[gnome-panel/wip/muktupavels/add-to-panel: 1/2] add-applet-window: finish implementation



commit d21401984a6b7f1528e434e3d4917d63867ab090
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sat Apr 18 17:12:09 2020 +0300

    add-applet-window: finish implementation

 gnome-panel/Makefile.am            |   2 +
 gnome-panel/gp-add-applet-window.c | 338 ++++++++++++++++-------------
 gnome-panel/gp-add-applet-window.h |   6 +
 gnome-panel/gp-applet-row.c        | 430 +++++++++++++++++++++++++++++++++++++
 gnome-panel/gp-applet-row.h        |  38 ++++
 po/POTFILES.in                     |   1 +
 6 files changed, 664 insertions(+), 151 deletions(-)
---
diff --git a/gnome-panel/Makefile.am b/gnome-panel/Makefile.am
index ed699b279..5d3c0a63c 100644
--- a/gnome-panel/Makefile.am
+++ b/gnome-panel/Makefile.am
@@ -13,6 +13,8 @@ panel_sources =                       \
        gp-add-applet-window.h \
        gp-applet-manager.c \
        gp-applet-manager.h \
+       gp-applet-row.c \
+       gp-applet-row.h \
        gp-application.c \
        gp-application.h \
        gp-arrow-button.c \
diff --git a/gnome-panel/gp-add-applet-window.c b/gnome-panel/gp-add-applet-window.c
index e9320523a..982d6d113 100644
--- a/gnome-panel/gp-add-applet-window.c
+++ b/gnome-panel/gp-add-applet-window.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2018 Alberts Muktupāvels
+ * Copyright (C) 2004 Vincent Untz
+ * Copyright (C) 2018-2020 Alberts Muktupāvels
  *
  * 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
@@ -18,17 +19,21 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
-#include <libgnome-panel/gp-applet-info-private.h>
-#include <libgnome-panel/gp-module-private.h>
 
 #include "gp-add-applet-window.h"
+#include "gp-applet-row.h"
 #include "gp-module-manager.h"
+#include "libgnome-panel/gp-applet-info-private.h"
+#include "libgnome-panel/gp-module-private.h"
+#include "libpanel-util/panel-glib.h"
+#include "panel-applets-manager.h"
 
 struct _GpAddAppletWindow
 {
   GtkWindow        parent;
 
   GpModuleManager *module_manager;
+  PanelToplevel   *toplevel;
 
   GtkWidget       *header_bar;
   GtkWidget       *search_button;
@@ -45,6 +50,7 @@ enum
   PROP_0,
 
   PROP_MODULE_MANAGER,
+  PROP_TOPLEVEL,
 
   LAST_PROP
 };
@@ -75,145 +81,15 @@ label_make_bold (GtkWidget *label)
 }
 
 static void
-help_cb (GtkMenuItem       *menuitem,
-         GpAddAppletWindow *window)
-{
-  GpAppletInfo *info;
-  GError *error;
-
-  info = g_object_get_data (G_OBJECT (menuitem), "applet-info");
-
-  error = NULL;
-  gtk_show_uri_on_window (GTK_WINDOW (window), info->help_uri,
-                          GDK_CURRENT_TIME, &error);
-
-  if (error != NULL)
-    {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-    }
-}
-
-static void
-about_cb (GtkMenuItem       *menuitem,
-          GpAddAppletWindow *window)
-{
-  GtkWidget *dialog;
-  GpAppletInfo *info;
-
-  dialog = gtk_about_dialog_new ();
-  info = g_object_get_data (G_OBJECT (menuitem), "applet-info");
-
-  info->about_dialog_func (GTK_ABOUT_DIALOG (dialog));
-
-  gtk_window_present (GTK_WINDOW (dialog));
-}
-
-static void
-setup_view_more_button (GtkWidget         *button,
-                        GpAppletInfo      *info,
-                        GpAddAppletWindow *window)
+header_func_cb (GtkListBoxRow *row,
+                GtkListBoxRow *before,
+                gpointer       user_data)
 {
-  GtkWidget *image;
-  GtkWidget *menu;
-  gboolean sensitive;
-  GtkWidget *item;
-
-  image = gtk_image_new_from_icon_name ("view-more-symbolic",
-                                        GTK_ICON_SIZE_MENU);
-
-  gtk_button_set_image (GTK_BUTTON (button), image);
-  gtk_image_set_pixel_size (GTK_IMAGE (image), 16);
-
-  menu = gtk_menu_new ();
-  sensitive = FALSE;
-
-  gtk_menu_button_set_popup (GTK_MENU_BUTTON (button), menu);
-  gtk_widget_set_halign (menu, GTK_ALIGN_END);
-
-  if (info->help_uri && info->help_uri[0] != '\0')
-    {
-      sensitive = TRUE;
-      item = gtk_menu_item_new_with_label (_("Help"));
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-      gtk_widget_show (item);
-
-      g_object_set_data (G_OBJECT (item), "applet-info", info);
-      g_signal_connect (item, "activate", G_CALLBACK (help_cb), window);
-    }
-
-  if (info->about_dialog_func != NULL)
-    {
-      sensitive = TRUE;
-      item = gtk_menu_item_new_with_label (_("About"));
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-      gtk_widget_show (item);
-
-      g_object_set_data (G_OBJECT (item), "applet-info", info);
-      g_signal_connect (item, "activate", G_CALLBACK (about_cb), window);
-    }
+  GtkWidget *separator;
 
-  gtk_widget_set_sensitive (button, sensitive);
-}
+  separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
 
-static void
-add_applet (GpAddAppletWindow *window,
-            GtkListBox        *list_box,
-            GpAppletInfo      *info)
-{
-  GtkWidget *row;
-  GtkWidget *row_box;
-  GtkWidget *icon_image;
-  GtkWidget *info_box;
-  GtkWidget *add_button;
-  GtkWidget *menu_button;
-  GtkWidget *title_label;
-  GtkWidget *description_label;
-
-  row = gtk_list_box_row_new ();
-  g_object_set_data (G_OBJECT (row), "applet-info", info);
-  gtk_list_box_set_selection_mode (list_box, GTK_SELECTION_NONE);
-  gtk_list_box_prepend (list_box, row);
-  gtk_widget_show (row);
-
-  row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
-  gtk_container_add (GTK_CONTAINER (row), row_box);
-  g_object_set (row_box, "margin-start", 6, NULL);
-  g_object_set (row_box, "margin-end", 6, NULL);
-  gtk_widget_show (row_box);
-
-  icon_image = gtk_image_new_from_icon_name (info->icon_name, GTK_ICON_SIZE_DND);
-  gtk_image_set_pixel_size (GTK_IMAGE (icon_image), 32);
-  gtk_box_pack_start (GTK_BOX (row_box), icon_image, FALSE, FALSE, 0);
-  gtk_widget_show (icon_image);
-
-  info_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-  gtk_box_pack_start (GTK_BOX (row_box), info_box, TRUE, TRUE, 0);
-  gtk_widget_show (info_box);
-
-  add_button = gtk_button_new_with_label (_("Add"));
-  gtk_box_pack_start (GTK_BOX (row_box), add_button, FALSE, FALSE, 0);
-  gtk_widget_set_valign (add_button, GTK_ALIGN_CENTER);
-  gtk_widget_show (add_button);
-
-  menu_button = gtk_menu_button_new ();
-  gtk_box_pack_end (GTK_BOX (row_box), menu_button, FALSE, FALSE, 0);
-  gtk_widget_set_valign (menu_button, GTK_ALIGN_CENTER);
-  setup_view_more_button (menu_button, info, window);
-  gtk_widget_show (menu_button);
-
-  title_label = gtk_label_new (info->name);
-  gtk_box_pack_start (GTK_BOX (info_box), title_label, FALSE, FALSE, 0);
-  gtk_label_set_xalign (GTK_LABEL (title_label), 0);
-  label_make_bold (title_label);
-  gtk_widget_show (title_label);
-
-  description_label = gtk_label_new (info->description);
-  gtk_box_pack_start (GTK_BOX (info_box), description_label, FALSE, FALSE, 0);
-  gtk_label_set_max_width_chars (GTK_LABEL (description_label), 20);
-  gtk_label_set_line_wrap (GTK_LABEL (description_label), TRUE);
-  gtk_label_set_xalign (GTK_LABEL (description_label), 0);
-  gtk_widget_show (description_label);
+  gtk_list_box_row_set_header (row, separator);
 }
 
 static gboolean
@@ -231,7 +107,7 @@ filter_func_cb (GtkListBoxRow *row,
   if (!searching)
     return TRUE;
 
-  info = g_object_get_data (G_OBJECT (row), "applet-info");
+  info = gp_applet_row_get_info (GP_APPLET_ROW (row));
 
   if (!info)
     return FALSE;
@@ -239,10 +115,10 @@ filter_func_cb (GtkListBoxRow *row,
   retval = FALSE;
 
   if (info->name)
-    retval |= strstr (info->name, window->search_text) != NULL;
+    retval |= panel_g_utf8_strstrcase (info->name, window->search_text) != NULL;
 
   if (info->description)
-    retval |= strstr (info->description, window->search_text) != NULL;
+    retval |= panel_g_utf8_strstrcase (info->description, window->search_text) != NULL;
 
   return retval;
 }
@@ -255,13 +131,102 @@ sort_func_cb (GtkListBoxRow *row1,
   GpAppletInfo *info1;
   GpAppletInfo *info2;
 
-  info1 = g_object_get_data (G_OBJECT (row1), "applet-info");
-  info2 = g_object_get_data (G_OBJECT (row2), "applet-info");
+  info1 = gp_applet_row_get_info (GP_APPLET_ROW (row1));
+  info2 = gp_applet_row_get_info (GP_APPLET_ROW (row2));
+
+  return g_utf8_collate (info1->name, info2->name);
+}
+
+typedef struct
+{
+  PanelToplevel       *toplevel;
+  PanelObjectPackType  pack_type;
+  int                  pack_index;
+  char                *iid;
+} InitialSetupData;
+
+static InitialSetupData *
+initial_setup_data_new (PanelToplevel       *toplevel,
+                        PanelObjectPackType  pack_type,
+                        int                  pack_index,
+                        const char          *iid)
+{
+  InitialSetupData *data;
+
+  data = g_new0 (InitialSetupData, 1);
+
+  data->toplevel = toplevel;
+  data->pack_type = pack_type;
+  data->pack_index = pack_index;
+  data->iid = g_strdup (iid);
+
+  return data;
+}
+
+static void
+initial_setup_data_free (gpointer user_data)
+{
+  InitialSetupData *data;
 
-  if (!info1 || !info2)
-    return 1;
+  data = (InitialSetupData *) user_data;
 
-  return g_strcmp0 (info1->name, info2->name);
+  g_free (data->iid);
+  g_free (data);
+}
+
+static void
+initial_setup_dialog_cb (GpInitialSetupDialog *dialog,
+                         gboolean              canceled,
+                         gpointer              user_data)
+{
+  InitialSetupData *data;
+  GVariant *initial_settings;
+
+  if (canceled)
+    return;
+
+  data = (InitialSetupData *) user_data;
+
+  initial_settings = gp_initital_setup_dialog_get_settings (dialog);
+
+  panel_applet_frame_create (data->toplevel,
+                             data->pack_type,
+                             data->pack_index,
+                             data->iid,
+                             initial_settings);
+
+  g_variant_unref (initial_settings);
+}
+
+static void
+row_activated_cb (GtkListBox        *box,
+                  GtkListBoxRow     *row,
+                  GpAddAppletWindow *self)
+{
+  const char *iid;
+  PanelWidget *panel;
+  PanelObjectPackType pack_type;
+  int pack_index;
+  InitialSetupData *data;
+
+  iid = gp_applet_row_get_iid (GP_APPLET_ROW (row));
+
+  pack_type = PANEL_OBJECT_PACK_START;
+
+  panel = panel_toplevel_get_panel_widget (self->toplevel);
+  pack_index = panel_widget_get_new_pack_index (panel, pack_type);
+
+  data = initial_setup_data_new (self->toplevel, pack_type, pack_index, iid);
+
+  if (panel_applets_manager_open_initial_setup_dialog (iid,
+                                                       NULL,
+                                                       GTK_WINDOW (self),
+                                                       initial_setup_dialog_cb,
+                                                       data,
+                                                       initial_setup_data_free))
+    return;
+
+  panel_applet_frame_create (self->toplevel, pack_type, pack_index, iid, NULL);
 }
 
 static void
@@ -305,15 +270,23 @@ add_module (GpAddAppletWindow *window,
   gtk_widget_show (list_frame);
 
   list_box = gtk_list_box_new ();
+  gtk_list_box_set_selection_mode (GTK_LIST_BOX (list_box), GTK_SELECTION_NONE);
+  gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (list_box), FALSE);
   g_object_set_data (G_OBJECT (module_box), "list-box", list_box);
   gtk_container_add (GTK_CONTAINER (list_frame), list_box);
   gtk_widget_show (list_box);
 
+  g_signal_connect (list_box,
+                    "row-activated",
+                    G_CALLBACK (row_activated_cb),
+                    window);
+
   applets = gp_module_get_applets (module);
   for (i = 0; applets[i] != NULL; i++)
     {
       GError *error;
       GpAppletInfo *info;
+      GtkWidget *row;
 
       error = NULL;
       info = gp_module_get_applet_info (module, applets[i], &error);
@@ -326,9 +299,16 @@ add_module (GpAddAppletWindow *window,
           continue;
         }
 
-      add_applet (window, GTK_LIST_BOX (list_box), info);
+      row = gp_applet_row_new (module, applets[i]);
+      gtk_list_box_prepend (GTK_LIST_BOX (list_box), row);
+      gtk_widget_show (row);
     }
 
+  gtk_list_box_set_header_func (GTK_LIST_BOX (list_box),
+                                header_func_cb,
+                                window,
+                                NULL);
+
   gtk_list_box_set_filter_func (GTK_LIST_BOX (list_box),
                                 filter_func_cb, window,
                                 NULL);
@@ -564,16 +544,48 @@ setup_window_content (GpAddAppletWindow *window)
   gtk_widget_show (label);
 }
 
+static void
+update_subtitle (GpAddAppletWindow *self)
+{
+  const char *name;
+  char *title;
+
+  name = panel_toplevel_get_name (self->toplevel);
+
+  if (name != NULL && *name != '\0')
+    title = g_strdup_printf (_("Find an item to add to “%s”"), name);
+  else
+    title = g_strdup (_("Find an item to add to the panel"));
+
+  gtk_header_bar_set_subtitle (GTK_HEADER_BAR (self->header_bar), title);
+  g_free (title);
+}
+
+static void
+toplevel_name_changed_cb (GObject           *object,
+                          GParamSpec        *pspec,
+                          GpAddAppletWindow *self)
+{
+  update_subtitle (self);
+}
+
 static void
 gp_add_applet_window_constructed (GObject *object)
 {
-  GpAddAppletWindow *window;
+  GpAddAppletWindow *self;
 
-  window = GP_ADD_APPLET_WINDOW (object);
+  self = GP_ADD_APPLET_WINDOW (object);
 
   G_OBJECT_CLASS (gp_add_applet_window_parent_class)->constructed (object);
 
-  rebuild_modules_list (window);
+  g_signal_connect_object (self->toplevel,
+                           "notify::name",
+                           G_CALLBACK (toplevel_name_changed_cb),
+                           self,
+                           0);
+
+  rebuild_modules_list (self);
+  update_subtitle (self);
 }
 
 static void
@@ -604,6 +616,11 @@ gp_add_applet_window_set_property (GObject      *object,
         window->module_manager = g_value_get_object (value);
         break;
 
+      case PROP_TOPLEVEL:
+        g_assert (window->toplevel == NULL);
+        window->toplevel = g_value_get_object (value);
+        break;
+
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
         break;
@@ -622,6 +639,15 @@ install_properties (GObjectClass *object_class)
                          G_PARAM_CONSTRUCT_ONLY |
                          G_PARAM_STATIC_STRINGS);
 
+  window_properties[PROP_TOPLEVEL] =
+    g_param_spec_object ("toplevel",
+                         "toplevel",
+                         "toplevel",
+                         PANEL_TYPE_TOPLEVEL,
+                         G_PARAM_WRITABLE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (object_class, LAST_PROP,
                                      window_properties);
 }
@@ -649,3 +675,13 @@ gp_add_applet_window_init (GpAddAppletWindow *window)
   gtk_window_set_default_size (GTK_WINDOW (window), 600, 480);
   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
 }
+
+GtkWidget *
+gp_add_applet_window_new (GpModuleManager *manager,
+                          PanelToplevel   *toplevel)
+{
+  return g_object_new (GP_TYPE_ADD_APPLET_WINDOW,
+                       "module-manager", manager,
+                       "toplevel", toplevel,
+                       NULL);
+}
diff --git a/gnome-panel/gp-add-applet-window.h b/gnome-panel/gp-add-applet-window.h
index 9ac21e925..ca2b491ad 100644
--- a/gnome-panel/gp-add-applet-window.h
+++ b/gnome-panel/gp-add-applet-window.h
@@ -20,12 +20,18 @@
 
 #include <gtk/gtk.h>
 
+#include "gp-module-manager.h"
+#include "panel-toplevel.h"
+
 G_BEGIN_DECLS
 
 #define GP_TYPE_ADD_APPLET_WINDOW gp_add_applet_window_get_type ()
 G_DECLARE_FINAL_TYPE (GpAddAppletWindow, gp_add_applet_window,
                       GP, ADD_APPLET_WINDOW, GtkWindow)
 
+GtkWidget *gp_add_applet_window_new (GpModuleManager *manager,
+                                     PanelToplevel   *toplevel);
+
 G_END_DECLS
 
 #endif
diff --git a/gnome-panel/gp-applet-row.c b/gnome-panel/gp-applet-row.c
new file mode 100644
index 000000000..8a852cf8c
--- /dev/null
+++ b/gnome-panel/gp-applet-row.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "gp-applet-row.h"
+
+#include <glib/gi18n.h>
+
+#include "panel-applets-manager.h"
+#include "panel-layout.h"
+#include "panel-lockdown.h"
+
+struct _GpAppletRow
+{
+  GtkListBoxRow  parent;
+
+  GpModule      *module;
+  char          *applet_id;
+
+  char          *iid;
+
+  GtkWidget     *event_box;
+
+  GtkWidget     *about_dialog;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_MODULE,
+  PROP_APPLET_ID,
+
+  LAST_PROP
+};
+
+static GParamSpec *row_properties[LAST_PROP] = { NULL };
+
+G_DEFINE_TYPE (GpAppletRow, gp_applet_row, GTK_TYPE_LIST_BOX_ROW)
+
+static void
+help_cb (GtkMenuItem *menuitem,
+         GpAppletRow *self)
+{
+  gp_module_show_help (self->module, NULL, self->applet_id, NULL);
+}
+
+static void
+about_cb (GtkMenuItem *menuitem,
+          GpAppletRow *self)
+{
+  if (self->about_dialog != NULL)
+    {
+      gtk_window_present (GTK_WINDOW (self->about_dialog));
+      return;
+    }
+
+  self->about_dialog = gp_module_create_about_dialog (self->module,
+                                                      NULL,
+                                                      self->applet_id);
+
+  if (self->about_dialog == NULL)
+    return;
+
+  g_object_add_weak_pointer (G_OBJECT (self->about_dialog),
+                             (gpointer *) &self->about_dialog);
+
+  gtk_window_present (GTK_WINDOW (self->about_dialog));
+}
+
+static void
+setup_view_more_button (GpAppletRow  *self,
+                        GtkWidget    *button,
+                        GpAppletInfo *info)
+{
+  GtkWidget *image;
+  GtkWidget *menu;
+  gboolean sensitive;
+  GtkWidget *item;
+
+  image = gtk_image_new_from_icon_name ("view-more-symbolic",
+                                        GTK_ICON_SIZE_MENU);
+
+  gtk_button_set_image (GTK_BUTTON (button), image);
+  gtk_image_set_pixel_size (GTK_IMAGE (image), 16);
+
+  menu = gtk_menu_new ();
+  sensitive = FALSE;
+
+  gtk_menu_button_set_popup (GTK_MENU_BUTTON (button), menu);
+  gtk_widget_set_halign (menu, GTK_ALIGN_END);
+
+  if (info->help_uri && info->help_uri[0] != '\0')
+    {
+      sensitive = TRUE;
+      item = gtk_menu_item_new_with_label (_("Help"));
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      g_signal_connect (item, "activate", G_CALLBACK (help_cb), self);
+    }
+
+  if (info->about_dialog_func != NULL)
+    {
+      sensitive = TRUE;
+      item = gtk_menu_item_new_with_label (_("About"));
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      g_signal_connect (item, "activate", G_CALLBACK (about_cb), self);
+    }
+
+  gtk_widget_set_sensitive (button, sensitive);
+}
+
+static void
+label_make_bold (GtkWidget *label)
+{
+  PangoLayout *layout;
+  PangoAttrList *attrs;
+
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+
+  layout = gtk_label_get_layout (GTK_LABEL (label));
+  attrs = pango_layout_get_attributes (layout);
+
+  if (!attrs)
+    {
+      attrs = pango_attr_list_new ();
+      pango_layout_set_attributes (layout, attrs);
+      pango_attr_list_unref (attrs);
+    }
+
+  pango_attr_list_change (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+}
+
+static void
+drag_data_get_cb (GtkWidget        *widget,
+                  GdkDragContext   *context,
+                  GtkSelectionData *data,
+                  guint             info,
+                  guint             time,
+                  GpAppletRow      *self)
+{
+  gtk_selection_data_set (data,
+                          gtk_selection_data_get_target (data),
+                          8,
+                          (const guchar *) self->iid,
+                          strlen (self->iid));
+}
+
+static void
+setup_drag_source (GpAppletRow *self)
+{
+  GpAppletInfo *info;
+  GdkModifierType modifiers;
+  GdkDragAction actions;
+  GtkTargetList *target_list;
+  GdkAtom target;
+
+  info = gp_module_get_applet_info (self->module, self->applet_id, NULL);
+
+  modifiers = GDK_BUTTON1_MASK | GDK_BUTTON2_MASK;
+  actions = GDK_ACTION_COPY;
+
+  gtk_drag_source_set (self->event_box, modifiers, NULL, 0, actions);
+  gtk_drag_source_set_icon_name (self->event_box, info->icon_name);
+
+  target_list = gtk_target_list_new (NULL, 0);
+
+  target = gdk_atom_intern_static_string ("application/x-panel-applet-iid");
+  gtk_target_list_add (target_list, target, 0, 0);
+
+  gtk_drag_source_set_target_list (self->event_box, target_list);
+  gtk_target_list_unref (target_list);
+
+  g_signal_connect (self->event_box,
+                    "drag-data-get",
+                    G_CALLBACK (drag_data_get_cb),
+                    self);
+}
+
+static void
+lockdown_changed_cb (PanelLockdown *lockdown,
+                     gpointer       user_data)
+{
+  GpAppletRow *self;
+
+  self = GP_APPLET_ROW (user_data);
+
+  if (!panel_layout_is_writable () ||
+      panel_lockdown_get_panels_locked_down_s () ||
+      panel_applets_manager_is_applet_disabled (self->iid, NULL))
+    {
+      gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+      gtk_drag_source_unset (self->event_box);
+      return;
+    }
+
+  gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
+  setup_drag_source (self);
+}
+
+static void
+add_clicked_cb (GtkButton   *button,
+                GpAppletRow *self)
+{
+  GtkListBoxRow *row;
+
+  row = GTK_LIST_BOX_ROW (self);
+
+  GTK_LIST_BOX_ROW_GET_CLASS (row)->activate (row);
+}
+
+static void
+setup_row (GpAppletRow *self)
+{
+  GpAppletInfo *info;
+  GtkWidget *hbox;
+  GtkWidget *icon_image;
+  GtkWidget *vbox;
+  GtkWidget *add_button;
+  GtkWidget *menu_button;
+  GtkWidget *title_label;
+  GtkWidget *description_label;
+
+  info = gp_module_get_applet_info (self->module, self->applet_id, NULL);
+  g_assert (info != NULL);
+
+  self->iid = g_strdup_printf ("%s::%s",
+                               gp_module_get_id (self->module),
+                               self->applet_id);
+
+  self->event_box = gtk_event_box_new ();
+  gtk_container_add (GTK_CONTAINER (self), self->event_box);
+  gtk_widget_show (self->event_box);
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+  gtk_container_add (GTK_CONTAINER (self->event_box), hbox);
+  gtk_widget_show (hbox);
+
+  g_object_set (hbox,
+                "margin-start", 6,
+                "margin-end", 6,
+                NULL);
+
+  icon_image = gtk_image_new_from_icon_name (info->icon_name, GTK_ICON_SIZE_DND);
+  gtk_image_set_pixel_size (GTK_IMAGE (icon_image), 32);
+  gtk_box_pack_start (GTK_BOX (hbox), icon_image, FALSE, FALSE, 0);
+  gtk_widget_show (icon_image);
+
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+  gtk_widget_show (vbox);
+
+  add_button = gtk_button_new_with_label (_("Add"));
+  gtk_box_pack_start (GTK_BOX (hbox), add_button, FALSE, FALSE, 0);
+  gtk_widget_set_valign (add_button, GTK_ALIGN_CENTER);
+  gtk_widget_show (add_button);
+
+  g_signal_connect (add_button, "clicked", G_CALLBACK (add_clicked_cb), self);
+
+  menu_button = gtk_menu_button_new ();
+  gtk_box_pack_end (GTK_BOX (hbox), menu_button, FALSE, FALSE, 0);
+  gtk_widget_set_valign (menu_button, GTK_ALIGN_CENTER);
+  setup_view_more_button (self, menu_button, info);
+  gtk_widget_show (menu_button);
+
+  title_label = gtk_label_new (info->name);
+  gtk_box_pack_start (GTK_BOX (vbox), title_label, FALSE, FALSE, 0);
+  gtk_label_set_xalign (GTK_LABEL (title_label), 0);
+  label_make_bold (title_label);
+  gtk_widget_show (title_label);
+
+  description_label = gtk_label_new (info->description);
+  gtk_box_pack_start (GTK_BOX (vbox), description_label, FALSE, FALSE, 0);
+  gtk_label_set_max_width_chars (GTK_LABEL (description_label), 20);
+  gtk_label_set_line_wrap (GTK_LABEL (description_label), TRUE);
+  gtk_label_set_xalign (GTK_LABEL (description_label), 0);
+  gtk_widget_show (description_label);
+
+  panel_lockdown_on_notify (panel_lockdown_get (),
+                            NULL,
+                            G_OBJECT (self),
+                            lockdown_changed_cb,
+                            self);
+
+  lockdown_changed_cb (panel_lockdown_get (), self);
+}
+
+static void
+gp_applet_row_constructed (GObject *object)
+{
+  G_OBJECT_CLASS (gp_applet_row_parent_class)->constructed (object);
+  setup_row (GP_APPLET_ROW (object));
+}
+
+static void
+gp_applet_row_dispose (GObject *object)
+{
+  GpAppletRow *self;
+
+  self = GP_APPLET_ROW (object);
+
+  g_clear_object (&self->module);
+
+  g_clear_pointer (&self->about_dialog, gtk_widget_destroy);
+
+  G_OBJECT_CLASS (gp_applet_row_parent_class)->dispose (object);
+}
+
+static void
+gp_applet_row_finalize (GObject *object)
+{
+  GpAppletRow *self;
+
+  self = GP_APPLET_ROW (object);
+
+  g_clear_pointer (&self->applet_id, g_free);
+
+  G_OBJECT_CLASS (gp_applet_row_parent_class)->finalize (object);
+}
+
+static void
+gp_applet_row_set_property (GObject      *object,
+                            guint         property_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GpAppletRow *self;
+
+  self = GP_APPLET_ROW (object);
+
+  switch (property_id)
+    {
+      case PROP_MODULE:
+        g_assert (self->module == NULL);
+        self->module = g_value_dup_object (value);
+        break;
+
+      case PROP_APPLET_ID:
+        g_assert (self->applet_id == NULL);
+        self->applet_id = g_value_dup_string (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+install_properties (GObjectClass *object_class)
+{
+  row_properties[PROP_MODULE] =
+    g_param_spec_object ("module",
+                         "module",
+                         "module",
+                         GP_TYPE_MODULE,
+                         G_PARAM_WRITABLE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  row_properties[PROP_APPLET_ID] =
+    g_param_spec_string ("applet-id",
+                         "applet-id",
+                         "applet-id",
+                         NULL,
+                         G_PARAM_WRITABLE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, LAST_PROP, row_properties);
+}
+
+static void
+gp_applet_row_class_init (GpAppletRowClass *self_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (self_class);
+
+  object_class->constructed = gp_applet_row_constructed;
+  object_class->dispose = gp_applet_row_dispose;
+  object_class->finalize = gp_applet_row_finalize;
+  object_class->set_property = gp_applet_row_set_property;
+
+  install_properties (object_class);
+}
+
+static void
+gp_applet_row_init (GpAppletRow *self)
+{
+}
+
+GtkWidget *
+gp_applet_row_new (GpModule   *module,
+                   const char *applet_id)
+{
+  return g_object_new (GP_TYPE_APPLET_ROW,
+                       "module", module,
+                       "applet-id", applet_id,
+                       NULL);
+}
+
+GpAppletInfo *
+gp_applet_row_get_info (GpAppletRow *self)
+{
+  return gp_module_get_applet_info (self->module, self->applet_id, NULL);
+}
+
+const char *
+gp_applet_row_get_iid (GpAppletRow *self)
+{
+  return self->iid;
+}
diff --git a/gnome-panel/gp-applet-row.h b/gnome-panel/gp-applet-row.h
new file mode 100644
index 000000000..d860e4e02
--- /dev/null
+++ b/gnome-panel/gp-applet-row.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GP_APPLET_ROW_H
+#define GP_APPLET_ROW_H
+
+#include "libgnome-panel/gp-applet-info-private.h"
+#include "libgnome-panel/gp-module-private.h"
+
+G_BEGIN_DECLS
+
+#define GP_TYPE_APPLET_ROW (gp_applet_row_get_type ())
+G_DECLARE_FINAL_TYPE (GpAppletRow, gp_applet_row, GP, APPLET_ROW, GtkListBoxRow)
+
+GtkWidget    *gp_applet_row_new      (GpModule    *module,
+                                      const char  *applet_id);
+
+GpAppletInfo *gp_applet_row_get_info (GpAppletRow *self);
+
+const char   *gp_applet_row_get_iid  (GpAppletRow *self);
+
+G_END_DECLS
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8a245520c..1da75721f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,6 +10,7 @@ data/org.gnome.gnome-panel.toplevel.gschema.xml
 gnome-panel/gnome-panel.desktop.in
 gnome-panel/gp-add-applet-window.c
 gnome-panel/gp-applet-manager.c
+gnome-panel/gp-applet-row.c
 gnome-panel/gp-arrow-button.c
 gnome-panel/gp-main.c
 gnome-panel/gp-properties-dialog.c


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