diff options
author | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2022-09-21 23:59:48 +0200 |
---|---|---|
committer | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2022-09-21 23:59:48 +0200 |
commit | ce5fa07af99ac9d53e38213fd286fe8ac208e789 (patch) | |
tree | 1b203e7b677d78fabf431ce986cc09ff0b0ecd5c | |
parent | 4e646dac54541c70532374463767428e3f22cbd2 (diff) | |
parent | 0c689d5662beef6b90a0104ab3933058f23ce7f9 (diff) | |
download | ayatana-indicator-printers-ce5fa07af99ac9d53e38213fd286fe8ac208e789.tar.gz ayatana-indicator-printers-ce5fa07af99ac9d53e38213fd286fe8ac208e789.tar.bz2 ayatana-indicator-printers-ce5fa07af99ac9d53e38213fd286fe8ac208e789.zip |
Merge branch 'tari01-pr/indicator-ng'
Attributes GH PR #18: https://github.com/AyatanaIndicators/ayatana-indicator-printers/pull/18
-rw-r--r-- | .build.yml | 36 | ||||
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | data/CMakeLists.txt | 3 | ||||
-rw-r--r-- | data/org.ayatana.indicator.printers | 11 | ||||
-rw-r--r-- | debian/control | 7 | ||||
-rw-r--r-- | src/CMakeLists.txt | 27 | ||||
-rw-r--r-- | src/indicator-menu-item.c | 395 | ||||
-rw-r--r-- | src/indicator-menu-item.h | 81 | ||||
-rw-r--r-- | src/indicator-printer-state-notifier.c | 36 | ||||
-rw-r--r-- | src/indicator-printers-menu.c | 334 | ||||
-rw-r--r-- | src/indicator-printers-menu.h | 76 | ||||
-rw-r--r-- | src/indicator-printers-service.c | 561 | ||||
-rw-r--r-- | src/indicator-printers-service.h | 52 | ||||
-rw-r--r-- | src/indicator-printers.c | 303 | ||||
-rw-r--r-- | src/indicator-printers.h | 70 | ||||
-rw-r--r-- | src/main.c | 47 |
16 files changed, 585 insertions, 1458 deletions
@@ -13,12 +13,8 @@ requires: - cmake - cmake-extras - intltool - - mate-common - glib2 - - gtk3 - - libdbusmenu-glib - - libdbusmenu-gtk3 - - libayatana-indicator + - libayatana-common - libcups - systemd - cups @@ -32,14 +28,11 @@ requires: - git - cmake - cmake-extras - - mate-common - intltool - libglib2.0-dev - - libgtk-3-dev - - libdbusmenu-glib-dev - - libdbusmenu-gtk3-dev - - libayatana-indicator3-dev - libcups2-dev +# - libayatana-common-dev + - liblomiri-url-dispatcher-dev - dbus ubuntu: @@ -49,14 +42,11 @@ requires: - git - cmake - cmake-extras - - mate-common - intltool - libglib2.0-dev - - libgtk-3-dev - - libdbusmenu-glib-dev - - libdbusmenu-gtk3-dev - - libayatana-indicator3-dev - libcups2-dev +# - libayatana-common-dev +# - liblomiri-url-dispatcher-dev variables: - 'CHECKERS=" @@ -76,6 +66,22 @@ variables: -enable-checker alpha.core.FixedAddr -enable-checker security.insecureAPI.strcpy"' +before_scripts: + - cd ${START_DIR} + - if [ ! -d libayatana-common-build ]; then + - git clone --depth 1 https://github.com/AyatanaIndicators/libayatana-common.git libayatana-common-build + - fi + - cd libayatana-common-build + - if [ ${DISTRO_NAME} == "debian" ]; then + - cmake . -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_LOMIRI_FEATURES=ON + - else + - cmake . -DCMAKE_INSTALL_PREFIX=/usr + - fi + - make + - make install + - cd - + - rm -Rf libayatana-common-build/ + build_scripts: - if [ ${DISTRO_NAME} == "debian" ];then - cppcheck --enable=warning,style,performance,portability,information,missingInclude . diff --git a/CMakeLists.txt b/CMakeLists.txt index 24451e4..892b0e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ endif () include (GNUInstallDirs) find_package (PkgConfig REQUIRED) include (FindPkgConfig) -pkg_check_modules (SERVICE REQUIRED gtk+-3.0>=3.0 ayatana-indicator3-0.4>=0.2 dbusmenu-glib-0.4>=0.2 dbusmenu-gtk3-0.4) +pkg_check_modules (SERVICE REQUIRED glib-2.0>=2.36 gio-2.0>=2.36 gio-unix-2.0>=2.36 libayatana-common) find_program (CUPS_CONFIG cups-config REQUIRED) execute_process (COMMAND ${CUPS_CONFIG} --cflags OUTPUT_VARIABLE CUPS_CFLAGS) execute_process (COMMAND ${CUPS_CONFIG} --libs OUTPUT_VARIABLE CUPS_LIBS) @@ -61,7 +61,7 @@ if (ENABLE_TESTS) add_subdirectory (test) if (ENABLE_COVERAGE) find_package (CoverageReport) - ENABLE_COVERAGE_REPORT (TARGETS "ayatana-printersmenu" "ayatana-indicator-printers-service" TESTS "mock-cups-notifier" FILTER /usr/include ${CMAKE_BINARY_DIR}/*) + ENABLE_COVERAGE_REPORT (TARGETS "ayatanaindicatorprintersservice" "ayatana-indicator-printers-service" TESTS "mock-cups-notifier" FILTER /usr/include ${CMAKE_BINARY_DIR}/*) endif () endif () diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 20245cd..ac6a6c6 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -10,3 +10,6 @@ endif () # ayatana-indicator-printers.desktop configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/ayatana-indicator-printers.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/ayatana-indicator-printers.desktop" @ONLY) install (FILES "${CMAKE_CURRENT_BINARY_DIR}/ayatana-indicator-printers.desktop" DESTINATION "/etc/xdg/autostart") + +# org.ayatana.indicator.printers +install (FILES "${CMAKE_CURRENT_SOURCE_DIR}/org.ayatana.indicator.printers" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/ayatana/indicators") diff --git a/data/org.ayatana.indicator.printers b/data/org.ayatana.indicator.printers new file mode 100644 index 0000000..d9fe355 --- /dev/null +++ b/data/org.ayatana.indicator.printers @@ -0,0 +1,11 @@ +[Indicator Service] +Name=ayatana-indicator-printers +ObjectPath=/org/ayatana/indicator/printers +Position=100 + +[phone] +ObjectPath=/org/ayatana/indicator/printers/phone +Position=25 + +[desktop] +ObjectPath=/org/ayatana/indicator/printers/desktop diff --git a/debian/control b/debian/control index a6fce8f..040ff2b 100644 --- a/debian/control +++ b/debian/control @@ -7,13 +7,10 @@ Build-Depends: debhelper (>= 10), cmake-extras, dh-systemd | debhelper (>= 10.2~), dpkg-dev (>= 1.16.1.1), - mate-common, + intltool, libglib2.0-dev (>= 2.43.2), - libgtk-3-dev, - libdbusmenu-glib-dev (>= 0.5.90), - libdbusmenu-gtk3-dev (>= 0.5.90), - libayatana-indicator3-dev (>= 0.3.91), libcups2-dev, + libayatana-common-dev, systemd [linux-any], Standards-Version: 4.1.1 Homepage: https://github.com/AyatanaIndicators/ayatana-indicator-printers diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 98af322..d0fdbd1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,31 +1,22 @@ -# libayatana-printersmenu.so -add_library (ayatana-printersmenu SHARED - indicator-printers.c - indicator-printers.h - indicator-menu-item.c - indicator-menu-item.h - dbus-names.h) -target_include_directories (ayatana-printersmenu PUBLIC ${SERVICE_INCLUDE_DIRS}) -target_compile_definitions (ayatana-printersmenu PUBLIC GETTEXT_PACKAGE="${GETTEXT_PACKAGE}" PACKAGE_NAME="${PACKAGE}") -install (TARGETS ayatana-printersmenu DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/ayatana-indicators3/7/") - # cups-notifier.h # cups-notifier.c include (GdbusCodegen) add_gdbus_codegen_with_namespace (CUPS_NOTIFIER cups-notifier org.cups.cupsd Cups "${CMAKE_CURRENT_SOURCE_DIR}/org.cups.cupsd.Notifier.xml") -# ayatana-indicator-printers-service -add_executable (ayatana-indicator-printers-service +# libayatanaindicatorprintersservice.a +add_library (ayatanaindicatorprintersservice STATIC + indicator-printers-service.h indicator-printers-service.c - indicator-printers-menu.c - indicator-printers-menu.h indicator-printer-state-notifier.c indicator-printer-state-notifier.h spawn-printer-settings.c spawn-printer-settings.h dbus-names.h ${CUPS_NOTIFIER}) -target_include_directories (ayatana-indicator-printers-service PUBLIC ${SERVICE_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries (ayatana-indicator-printers-service ${SERVICE_LIBRARIES}) -target_compile_definitions (ayatana-indicator-printers-service PUBLIC GETTEXT_PACKAGE="${GETTEXT_PACKAGE}" LOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}") +target_include_directories (ayatanaindicatorprintersservice PUBLIC ${SERVICE_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) +target_compile_definitions (ayatanaindicatorprintersservice PUBLIC GETTEXT_PACKAGE="${GETTEXT_PACKAGE}" LOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}") + +# ayatana-indicator-printers-service +add_executable (ayatana-indicator-printers-service main.c) +target_link_libraries (ayatana-indicator-printers-service ayatanaindicatorprintersservice ${SERVICE_LIBRARIES}) install (TARGETS ayatana-indicator-printers-service RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR}/${CMAKE_PROJECT_NAME}) diff --git a/src/indicator-menu-item.c b/src/indicator-menu-item.c deleted file mode 100644 index ed89a0f..0000000 --- a/src/indicator-menu-item.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 "indicator-menu-item.h" - -#include <math.h> - -struct _IndicatorMenuItemPrivate -{ - GtkImage *image; - GtkWidget *label; - GtkWidget *right_label; - gboolean right_is_lozenge; -}; - -G_DEFINE_TYPE_WITH_PRIVATE(IndicatorMenuItem, indicator_menu_item, GTK_TYPE_MENU_ITEM) - -enum { - PROP_0, - PROP_ICON, - PROP_ICON_NAME, - PROP_LABEL, - PROP_RIGHT, - PROP_RIGHT_IS_LOZENGE, - N_PROPERTIES -}; - -static GParamSpec *properties[N_PROPERTIES]; - - -static gint -gtk_widget_get_font_size (GtkWidget *widget) -{ - const PangoFontDescription *font; - - gtk_style_context_get(gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget), "font", &font, NULL); - - return pango_font_description_get_size (font) / PANGO_SCALE; -} - -static void -cairo_lozenge (cairo_t *cr, double x, double y, double w, double h) -{ - double radius = MIN (w / 2.0, h / 2.0); - double x1 = x + w - radius; - double x2 = x + radius; - double y1 = y + radius; - double y2 = y + h - radius; - - cairo_move_to (cr, x+radius, y); - cairo_arc (cr, x1, y1, radius, M_PI * 1.5, M_PI * 2); - cairo_arc (cr, x1, y2, radius, 0, M_PI * 0.5); - cairo_arc (cr, x2, y2, radius, M_PI * 0.5, M_PI); - cairo_arc (cr, x2, y1, radius, M_PI, M_PI * 1.5); -} - -static gboolean -detail_label_draw (GtkWidget *widget, - cairo_t *cr, - gpointer data) -{ - GtkAllocation allocation; - double x, y, w, h; - GdkRGBA color; - PangoLayout *layout; - PangoRectangle layout_extents; - gboolean is_lozenge = *(gboolean *)data; - gint font_size = gtk_widget_get_font_size (widget); - - /* let the label handle the drawing if it's not a lozenge */ - if (!is_lozenge) - return FALSE; - - layout = gtk_label_get_layout (GTK_LABEL(widget)); - pango_layout_get_extents (layout, NULL, &layout_extents); - pango_extents_to_pixels (&layout_extents, NULL); - - gtk_widget_get_allocation (widget, &allocation); - x = -font_size / 2.0; - y = 1; - w = allocation.width; - h = MIN (allocation.height, layout_extents.height + 4); - - if (layout_extents.width == 0) - return TRUE; - - gtk_style_context_get_color (gtk_widget_get_style_context (widget), - gtk_widget_get_state_flags (widget), - &color); - gdk_cairo_set_source_rgba (cr, &color); - - cairo_set_line_width (cr, 1.0); - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_lozenge (cr, x - font_size / 2.0, y, w + font_size, h); - - x += (w - layout_extents.width) / 2.0; - y += (h - layout_extents.height) / 2.0; - cairo_move_to (cr, floor (x), floor (y)); - pango_cairo_layout_path (cr, layout); - cairo_fill (cr); - - return TRUE; -} - - -static void -indicator_menu_item_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - IndicatorMenuItem *self = INDICATOR_MENU_ITEM (object); - - switch (property_id) - { - case PROP_ICON: - g_value_set_object (value, indicator_menu_item_get_icon (self)); - break; - - case PROP_ICON_NAME: - g_value_set_string (value, indicator_menu_item_get_icon_name (self)); - break; - - case PROP_LABEL: - g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->priv->label))); - break; - - case PROP_RIGHT: - g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->priv->right_label))); - break; - - case PROP_RIGHT_IS_LOZENGE: - g_value_set_boolean (value, self->priv->right_is_lozenge); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - - -static void -indicator_menu_item_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) - { - case PROP_ICON: - indicator_menu_item_set_icon (INDICATOR_MENU_ITEM (object), - g_value_get_object (value)); - break; - - case PROP_ICON_NAME: - indicator_menu_item_set_icon_name (INDICATOR_MENU_ITEM (object), - g_value_get_string (value)); - break; - - case PROP_LABEL: - indicator_menu_item_set_label (INDICATOR_MENU_ITEM (object), - g_value_get_string (value)); - break; - - case PROP_RIGHT: - indicator_menu_item_set_right (INDICATOR_MENU_ITEM (object), - g_value_get_string (value)); - break; - - case PROP_RIGHT_IS_LOZENGE: - indicator_menu_item_set_right_is_lozenge (INDICATOR_MENU_ITEM (object), - g_value_get_boolean (value)); - break; - - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - - -static void -indicator_menu_item_dispose (GObject *object) -{ - IndicatorMenuItem *self = INDICATOR_MENU_ITEM (object); - - g_clear_object (&self->priv->image); - g_clear_object (&self->priv->label); - g_clear_object (&self->priv->right_label); - - G_OBJECT_CLASS (indicator_menu_item_parent_class)->dispose (object); -} - - -static void -indicator_menu_item_class_init (IndicatorMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->get_property = indicator_menu_item_get_property; - object_class->set_property = indicator_menu_item_set_property; - object_class->dispose = indicator_menu_item_dispose; - - properties[PROP_ICON] = g_param_spec_object ("icon", - "Icon", - "Icon for this menu item", - GDK_TYPE_PIXBUF, - G_PARAM_READWRITE); - - properties[PROP_ICON_NAME] = g_param_spec_string ("icon-name", - "Icon name", - "Name of the themed icon", - "", - G_PARAM_READWRITE); - - properties[PROP_LABEL] = g_param_spec_string ("label", - "Label", - "The text for the main label", - "", - G_PARAM_READWRITE); - - properties[PROP_RIGHT] = g_param_spec_string ("right", - "Right", - "The text on the right side of the menu item", - "", - G_PARAM_READWRITE); - - properties[PROP_RIGHT_IS_LOZENGE] = g_param_spec_boolean ("right-is-lozenge", - "Right is a lozenge", - "Whether the right label is displayed as a lonzenge", - FALSE, - G_PARAM_READWRITE); - - g_object_class_install_properties (object_class, N_PROPERTIES, properties); -} - - -static void -indicator_menu_item_init (IndicatorMenuItem *self) -{ - IndicatorMenuItemPrivate *priv; - gint spacing; - GtkWidget *hbox; - - priv = indicator_menu_item_get_instance_private(self); - self->priv = priv; - - gtk_widget_style_get (GTK_WIDGET (self), - "toggle-spacing", &spacing, - NULL); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, spacing); - - priv->image = g_object_new (GTK_TYPE_IMAGE, NULL); - g_object_ref_sink (priv->image); - gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (priv->image), FALSE, FALSE, 0); - - priv->label = g_object_new (GTK_TYPE_LABEL, - "xalign", 0.0, - NULL); - g_object_ref_sink (priv->label); - gtk_box_pack_start (GTK_BOX (hbox), priv->label, TRUE, TRUE, 0); - - priv->right_label = g_object_new (GTK_TYPE_LABEL, - "xalign", 1.0, - "width-chars", 2, - NULL); - gtk_style_context_add_class (gtk_widget_get_style_context (priv->right_label), - "accelerator"); - g_signal_connect (priv->right_label, - "draw", - G_CALLBACK (detail_label_draw), - &priv->right_is_lozenge); - g_object_ref_sink (priv->right_label); - gtk_box_pack_start (GTK_BOX (hbox), - priv->right_label, - FALSE, - FALSE, - gtk_widget_get_font_size (priv->right_label) / 2.0 + 1); - - gtk_container_add (GTK_CONTAINER (self), hbox); - - priv->right_is_lozenge = FALSE; -} - - -IndicatorMenuItem * -indicator_menu_item_new (void) -{ - return g_object_new (INDICATOR_TYPE_MENU_ITEM, NULL); -} - - -const gchar * -indicator_menu_item_get_label (IndicatorMenuItem *self) -{ - return gtk_label_get_label (GTK_LABEL (self->priv->label)); -} - - -void -indicator_menu_item_set_label (IndicatorMenuItem *self, - const gchar *text) -{ - gtk_label_set_label (GTK_LABEL (self->priv->label), text); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]); -} - - -const gchar * -indicator_menu_item_get_right (IndicatorMenuItem *self) -{ - return gtk_label_get_label (GTK_LABEL (self->priv->right_label)); -} - - -void -indicator_menu_item_set_right (IndicatorMenuItem *self, - const gchar *text) -{ - gtk_label_set_label (GTK_LABEL (self->priv->right_label), text); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RIGHT]); -} - - -gboolean -indicator_menu_item_get_right_is_lozenge (IndicatorMenuItem *self) -{ - return self->priv->right_is_lozenge; -} - - -void -indicator_menu_item_set_right_is_lozenge (IndicatorMenuItem *self, - gboolean is_lozenge) -{ - self->priv->right_is_lozenge = is_lozenge; - gtk_widget_queue_draw (self->priv->right_label); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RIGHT_IS_LOZENGE]); -} - - -GdkPixbuf * -indicator_menu_item_get_icon (IndicatorMenuItem *self) -{ - if (gtk_image_get_storage_type (self->priv->image) == GTK_IMAGE_PIXBUF) - return gtk_image_get_pixbuf (self->priv->image); - else - return NULL; -} - - -void -indicator_menu_item_set_icon (IndicatorMenuItem *self, - GdkPixbuf *icon) -{ - gtk_image_set_from_pixbuf (self->priv->image, icon); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON]); -} - - -const gchar * -indicator_menu_item_get_icon_name (IndicatorMenuItem *self) -{ - const gchar *name = NULL; - - if (gtk_image_get_storage_type (self->priv->image) == GTK_IMAGE_ICON_NAME) - gtk_image_get_icon_name (self->priv->image, &name, NULL); - - return name; -} - - -void -indicator_menu_item_set_icon_name (IndicatorMenuItem *self, - const gchar *name) -{ - gtk_image_set_from_icon_name (self->priv->image, name, GTK_ICON_SIZE_MENU); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON_NAME]); -} diff --git a/src/indicator-menu-item.h b/src/indicator-menu-item.h deleted file mode 100644 index 84d6b74..0000000 --- a/src/indicator-menu-item.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 INDICATOR_MENU_ITEM_H -#define INDICATOR_MENU_ITEM_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define INDICATOR_TYPE_MENU_ITEM indicator_menu_item_get_type() - -#define INDICATOR_MENU_ITEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - INDICATOR_TYPE_MENU_ITEM, IndicatorMenuItem)) - -#define INDICATOR_MENU_ITEM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), \ - INDICATOR_TYPE_MENU_ITEM, IndicatorMenuItemClass)) - -#define INDICATOR_IS_MENU_ITEM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ - INDICATOR_TYPE_MENU_ITEM)) - -#define INDICATOR_IS_MENU_ITEM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), \ - INDICATOR_TYPE_MENU_ITEM)) - -#define INDICATOR_MENU_ITEM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - INDICATOR_TYPE_MENU_ITEM, IndicatorMenuItemClass)) - -typedef struct _IndicatorMenuItem IndicatorMenuItem; -typedef struct _IndicatorMenuItemClass IndicatorMenuItemClass; -typedef struct _IndicatorMenuItemPrivate IndicatorMenuItemPrivate; - -struct _IndicatorMenuItem -{ - GtkMenuItem parent; - IndicatorMenuItemPrivate *priv; -}; - -struct _IndicatorMenuItemClass -{ - GtkMenuItemClass parent_class; -}; - -GType indicator_menu_item_get_type (void) G_GNUC_CONST; - -IndicatorMenuItem *indicator_menu_item_new (void); - -const gchar * indicator_menu_item_get_label (IndicatorMenuItem *self); -void indicator_menu_item_set_label (IndicatorMenuItem *self, const gchar *text); -const gchar * indicator_menu_item_get_right (IndicatorMenuItem *self); -void indicator_menu_item_set_right (IndicatorMenuItem *self, const gchar *text); - -gboolean indicator_menu_item_get_right_is_lozenge (IndicatorMenuItem *self); -void indicator_menu_item_set_right_is_lozenge (IndicatorMenuItem *self, gboolean is_lozenge); -const gchar * indicator_menu_item_get_icon_name (IndicatorMenuItem *self); -void indicator_menu_item_set_icon (IndicatorMenuItem *self, GdkPixbuf *icon); -GdkPixbuf * indicator_menu_item_get_icon (IndicatorMenuItem *self); -void indicator_menu_item_set_icon_name (IndicatorMenuItem *self, const gchar *name); - -G_END_DECLS - -#endif diff --git a/src/indicator-printer-state-notifier.c b/src/indicator-printer-state-notifier.c index 7a587a0..12f77c6 100644 --- a/src/indicator-printer-state-notifier.c +++ b/src/indicator-printer-state-notifier.c @@ -1,7 +1,9 @@ /* * Copyright 2012 Canonical Ltd. + * Copyright 2022 Robert Tari * * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> + * Robert Tari <robert@tari.in> * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published @@ -17,9 +19,8 @@ */ #include "indicator-printer-state-notifier.h" - +#include <ayatana/common/utils.h> #include <glib/gi18n.h> -#include <gtk/gtk.h> #include <cups/cups.h> #include <string.h> #include <stdarg.h> @@ -27,9 +28,6 @@ #include "cups-notifier.h" #include "spawn-printer-settings.h" - -#define RESPONSE_SHOW_SYSTEM_SETTINGS 1 - struct _IndicatorPrinterStateNotifierPrivate { CupsNotifier *cups_notifier; @@ -95,12 +93,9 @@ show_alert_box (const gchar *printer, const gchar *reason, int njobs) { - GtkWidget *dialog; - GtkWidget *image; gchar *primary_text; gchar *secondary_text; - image = gtk_image_new_from_icon_name ("printer", GTK_ICON_SIZE_DIALOG); primary_text = g_strdup_printf (reason, printer); secondary_text = g_strdup_printf (ngettext( @@ -108,31 +103,14 @@ show_alert_box (const gchar *printer, "You have %d jobs queued to print on this printer.", njobs), njobs); - dialog = g_object_new (GTK_TYPE_MESSAGE_DIALOG, - "title", _("Printing Problem"), - "icon-name", "printer", - "image", image, - "text", primary_text, - "secondary-text", secondary_text, - "urgency-hint", TRUE, - "focus-on-map", FALSE, - "window-position", GTK_WIN_POS_CENTER, - "skip-taskbar-hint", FALSE, - "deletable", FALSE, - NULL); - + gchar *sText = g_strdup_printf("<b>%s</b>\n\n%s", primary_text, secondary_text); g_free (primary_text); g_free (secondary_text); - gtk_dialog_add_buttons(GTK_DIALOG (dialog), _("_Settingsā¦"), RESPONSE_SHOW_SYSTEM_SETTINGS, _("_OK"), GTK_RESPONSE_OK, NULL); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), - GTK_RESPONSE_OK); - gtk_widget_show_all (dialog); - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == RESPONSE_SHOW_SYSTEM_SETTINGS) - spawn_printer_settings (); + ayatana_common_utils_zenity_warning ("printer", _("Printing Problem"), sText); + g_free (sText); - gtk_widget_destroy (dialog); + spawn_printer_settings (); } diff --git a/src/indicator-printers-menu.c b/src/indicator-printers-menu.c deleted file mode 100644 index bf0bc07..0000000 --- a/src/indicator-printers-menu.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 "indicator-printers-menu.h" - -#include <glib/gi18n.h> - -#include <cups/cups.h> - -#include "spawn-printer-settings.h" - -struct _IndicatorPrintersMenuPrivate -{ - DbusmenuMenuitem *root; - GHashTable *printers; /* printer name -> dbusmenuitem */ - CupsNotifier *cups_notifier; -}; - -G_DEFINE_TYPE_WITH_PRIVATE(IndicatorPrintersMenu, indicator_printers_menu, G_TYPE_OBJECT) - -enum { - PROP_0, - PROP_CUPS_NOTIFIER, - NUM_PROPERTIES -}; - -static GParamSpec *properties[NUM_PROPERTIES]; - - -static void -dispose (GObject *object) -{ - IndicatorPrintersMenu *self = INDICATOR_PRINTERS_MENU (object); - - if (self->priv->printers) { - g_hash_table_unref (self->priv->printers); - self->priv->printers = NULL; - } - - g_clear_object (&self->priv->root); - g_clear_object (&self->priv->cups_notifier); - - G_OBJECT_CLASS (indicator_printers_menu_parent_class)->dispose (object); -} - - -void -set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - IndicatorPrintersMenu *self = INDICATOR_PRINTERS_MENU (object); - - switch (property_id) { - case PROP_CUPS_NOTIFIER: - indicator_printers_menu_set_cups_notifier (self, - g_value_get_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - - -void -get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - IndicatorPrintersMenu *self = INDICATOR_PRINTERS_MENU (object); - - switch (property_id) { - case PROP_CUPS_NOTIFIER: - g_value_set_object (value, - indicator_printers_menu_get_cups_notifier (self)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - - -static void -indicator_printers_menu_class_init (IndicatorPrintersMenuClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - properties[PROP_CUPS_NOTIFIER] = g_param_spec_object ("cups-notifier", - "Cups Notifier", - "A cups notifier object", - CUPS_TYPE_NOTIFIER, - G_PARAM_READWRITE); - - g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); -} - - -static void -on_printer_item_activated (DbusmenuMenuitem *menuitem, - guint timestamp, - gpointer user_data) -{ - const gchar *printer = user_data; - spawn_printer_settings_with_args ("--show-jobs %s", printer); -} - - -static void -update_indicator_visibility (IndicatorPrintersMenu *self) -{ - GList *it; - gboolean is_visible = FALSE; - - for (it = dbusmenu_menuitem_get_children (self->priv->root); - it; - it = g_list_next (it)) - { - DbusmenuMenuitem *child = it->data; - if ((is_visible = dbusmenu_menuitem_property_get_bool (child, "visible"))) - break; - } - - dbusmenu_menuitem_property_set_bool (self->priv->root, "visible", is_visible); -} - - -static void -update_printer_menuitem (IndicatorPrintersMenu *self, - const char *printer, - int state) -{ - DbusmenuMenuitem *item; - int njobs; - cups_job_t *jobs; - - njobs = cupsGetJobs (&jobs, printer, 1, CUPS_WHICHJOBS_ACTIVE); - cupsFreeJobs (njobs, jobs); - - if (njobs < 0) { - g_warning ("printer '%s' does not exist\n", printer); - return; - } - - item = g_hash_table_lookup (self->priv->printers, printer); - - if (!item) { - item = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (item, "type", "indicator-item"); - dbusmenu_menuitem_property_set (item, "indicator-icon-name", "printer"); - dbusmenu_menuitem_property_set (item, "indicator-label", printer); - g_signal_connect_data (item, "item-activated", - G_CALLBACK (on_printer_item_activated), - g_strdup (printer), (GClosureNotify) g_free, 0); - - dbusmenu_menuitem_child_append(self->priv->root, item); - g_hash_table_insert (self->priv->printers, g_strdup (printer), item); - } - - if (njobs == 0) { - dbusmenu_menuitem_property_set_bool (item, "visible", FALSE); - update_indicator_visibility (self); - return; - } - - /* there are jobs for this printer. Make sure the indicator and the menu - * item for that printer are shown */ - dbusmenu_menuitem_property_set_bool (self->priv->root, "visible", TRUE); - dbusmenu_menuitem_property_set_bool (item, "visible", TRUE); - - switch (state) { - case IPP_PRINTER_STOPPED: - dbusmenu_menuitem_property_set (item, "indicator-right", _("Paused")); - dbusmenu_menuitem_property_set_bool (item, "indicator-right-is-lozenge", FALSE); - break; - - case IPP_PRINTER_PROCESSING: { - gchar *jobstr = g_strdup_printf ("%d", njobs); - dbusmenu_menuitem_property_set (item, "indicator-right", jobstr); - dbusmenu_menuitem_property_set_bool (item, "indicator-right-is-lozenge", TRUE); - g_free (jobstr); - break; - } - } -} - - -static void -update_all_printer_menuitems (IndicatorPrintersMenu *self) -{ - int ndests, i; - cups_dest_t *dests; - - ndests = cupsGetDests (&dests); - for (i = 0; i < ndests; i++) { - const char *option = cupsGetOption ("printer-state", - dests[i].num_options, - dests[i].options); - if (option != NULL) { - int state = atoi (option); - update_printer_menuitem (self, dests[i].name, state); - } - } - cupsFreeDests (ndests, dests); -} - - -static void -update_job (CupsNotifier *cups_notifier, - const gchar *text, - const gchar *printer_uri, - const gchar *printer_name, - guint printer_state, - const gchar *printer_state_reasons, - gboolean printer_is_accepting_jobs, - guint job_id, - guint job_state, - const gchar *job_state_reasons, - const gchar *job_name, - guint job_impressions_completed, - gpointer user_data) -{ - IndicatorPrintersMenu *self = INDICATOR_PRINTERS_MENU (user_data); - - /* CUPS doesn't send the printer's name for these events. Update all menu - * items as a temporary workaround */ - if (job_state == IPP_JOB_CANCELLED || - job_state == IPP_JOB_ABORTED || - job_state == IPP_JOB_COMPLETED) - update_all_printer_menuitems (self); - else - update_printer_menuitem (self, printer_name, printer_state); -} - - -static void -on_printer_state_changed (CupsNotifier *object, - const gchar *text, - const gchar *printer_uri, - const gchar *printer_name, - guint printer_state, - const gchar *printer_state_reasons, - gboolean printer_is_accepting_jobs, - gpointer user_data) -{ - IndicatorPrintersMenu *self = INDICATOR_PRINTERS_MENU (user_data); - - update_printer_menuitem (self, printer_name, printer_state); -} - - -static void -indicator_printers_menu_init (IndicatorPrintersMenu *self) -{ - self->priv = indicator_printers_menu_get_instance_private(self); - - self->priv->root = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set_bool (self->priv->root, "visible", FALSE); - - self->priv->printers = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - - /* create initial menu items */ - update_all_printer_menuitems (self); -} - - -IndicatorPrintersMenu * -indicator_printers_menu_new (void) -{ - return g_object_new (INDICATOR_TYPE_PRINTERS_MENU, NULL); -} - - -DbusmenuMenuitem * -indicator_printers_menu_get_root (IndicatorPrintersMenu *self) -{ - return self->priv->root; -} - - -CupsNotifier * -indicator_printers_menu_get_cups_notifier (IndicatorPrintersMenu *self) -{ - return self->priv->cups_notifier; -} - - -void -indicator_printers_menu_set_cups_notifier (IndicatorPrintersMenu *self, - CupsNotifier *cups_notifier) -{ - if (self->priv->cups_notifier) { - g_object_disconnect (self->priv->cups_notifier, - "any-signal", update_job, self, - "any-signal", on_printer_state_changed, self, - NULL); - g_clear_object (&self->priv->cups_notifier); - } - - if (cups_notifier) { - self->priv->cups_notifier = g_object_ref (cups_notifier); - g_object_connect (self->priv->cups_notifier, - "signal::job-created", update_job, self, - "signal::job-state", update_job, self, - "signal::job-completed", update_job, self, - "signal::printer-state-changed", on_printer_state_changed, self, - NULL); - } -} diff --git a/src/indicator-printers-menu.h b/src/indicator-printers-menu.h deleted file mode 100644 index c10f221..0000000 --- a/src/indicator-printers-menu.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 INDICATOR_PRINTERS_MENU_H -#define INDICATOR_PRINTERS_MENU_H - -#include <glib-object.h> -#include <libdbusmenu-glib/dbusmenu-glib.h> - -#include "cups-notifier.h" - -G_BEGIN_DECLS - -#define INDICATOR_TYPE_PRINTERS_MENU indicator_printers_menu_get_type() - -#define INDICATOR_PRINTERS_MENU(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - INDICATOR_TYPE_PRINTERS_MENU, IndicatorPrintersMenu)) - -#define INDICATOR_PRINTERS_MENU_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), \ - INDICATOR_TYPE_PRINTERS_MENU, IndicatorPrintersMenuClass)) - -#define INDICATOR_IS_PRINTERS_MENU(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ - INDICATOR_TYPE_PRINTERS_MENU)) - -#define INDICATOR_IS_PRINTERS_MENU_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), \ - INDICATOR_TYPE_PRINTERS_MENU)) - -#define INDICATOR_PRINTERS_MENU_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - INDICATOR_TYPE_PRINTERS_MENU, IndicatorPrintersMenuClass)) - -typedef struct _IndicatorPrintersMenu IndicatorPrintersMenu; -typedef struct _IndicatorPrintersMenuClass IndicatorPrintersMenuClass; -typedef struct _IndicatorPrintersMenuPrivate IndicatorPrintersMenuPrivate; - -struct _IndicatorPrintersMenu -{ - GObject parent; - IndicatorPrintersMenuPrivate *priv; -}; - -struct _IndicatorPrintersMenuClass -{ - GObjectClass parent_class; -}; - -GType indicator_printers_menu_get_type (void) G_GNUC_CONST; - -IndicatorPrintersMenu *indicator_printers_menu_new (void); -DbusmenuMenuitem * indicator_printers_menu_get_root (IndicatorPrintersMenu *menu); -CupsNotifier * indicator_printers_menu_get_cups_notifier (IndicatorPrintersMenu *self); -void indicator_printers_menu_set_cups_notifier (IndicatorPrintersMenu *self, - CupsNotifier *cups_notifier); - -G_END_DECLS - -#endif diff --git a/src/indicator-printers-service.c b/src/indicator-printers-service.c index e2a32f7..042580f 100644 --- a/src/indicator-printers-service.c +++ b/src/indicator-printers-service.c @@ -18,189 +18,490 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <libayatana-indicator/indicator-service.h> -#include <libdbusmenu-glib/dbusmenu-glib.h> -#include <gtk/gtk.h> #include <cups/cups.h> #include "dbus-names.h" #include <glib/gi18n-lib.h> +#include <gio/gio.h> +#include "indicator-printers-service.h" #include "cups-notifier.h" -#include "indicator-printers-menu.h" #include "indicator-printer-state-notifier.h" +#include "spawn-printer-settings.h" #define NOTIFY_LEASE_DURATION (24 * 60 * 60) +static guint m_nSignal = 0; + +enum +{ + SECTION_HEADER = (1<<0), + SECTION_PRINTERS = (1<<2) +}; + +enum +{ + PROFILE_PHONE, + PROFILE_DESKTOP, + N_PROFILES +}; + +static const char *const lMenuNames[N_PROFILES] = +{ + "phone", + "desktop" +}; + +struct ProfileMenuInfo +{ + GMenu *pMenu; + GMenu *pSubmenu; + guint nExportId; +}; + +struct _IndicatorPrintersServicePrivate +{ + GCancellable *pCancellable; + IndicatorPrinterStateNotifier *pStateNotifier; + CupsNotifier *pCupsNotifier; + guint nOwnId; + guint nActionsId; + GDBusConnection *pConnection; + gboolean bMenusBuilt; + int nSubscriptionId; + struct ProfileMenuInfo lMenus[N_PROFILES]; + GSimpleActionGroup *pActionGroup; + GSimpleAction *pHeaderAction; + GSimpleAction *pPrinterAction; + GMenu *pPrintersSection; + gboolean bVisible; +}; + +typedef IndicatorPrintersServicePrivate priv_t; + +G_DEFINE_TYPE_WITH_PRIVATE (IndicatorPrintersService, indicator_printers_service, G_TYPE_OBJECT) + +static void rebuildNow (IndicatorPrintersService *self, guint nSections); + +static void unexport (IndicatorPrintersService *self) +{ + if (self->pPrivate->nSubscriptionId > 0) + { + ipp_t *pRequest = ippNewRequest (IPP_CANCEL_SUBSCRIPTION); + ippAddString (pRequest, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/"); + ippAddInteger (pRequest, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-id", self->pPrivate->nSubscriptionId); + ipp_t *pResponse = cupsDoRequest (CUPS_HTTP_DEFAULT, pRequest, "/"); + + if (!pResponse || cupsLastError () != IPP_OK) + { + g_warning ("Error subscribing to CUPS notifications: %s\n", cupsLastErrorString ()); + + return; + } + + ippDelete (pResponse); + } + + // Unexport the menus + for (int i = 0; i < N_PROFILES; ++i) + { + guint *pId = &self->pPrivate->lMenus[i].nExportId; + + if (*pId) + { + g_dbus_connection_unexport_menu_model (self->pPrivate->pConnection, *pId); + *pId = 0; + } + } + + // Unexport the actions + if (self->pPrivate->nActionsId) + { + g_dbus_connection_unexport_action_group (self->pPrivate->pConnection, self->pPrivate->nActionsId); + self->pPrivate->nActionsId = 0; + } +} + +static void onPrinterStateChanged (CupsNotifier *pNotifier, const gchar *sText, const gchar *sPrinterUri, const gchar *sPrinterName, guint nPrinterState, const gchar *sPrinterStateReasons, gboolean bPrinterIsAcceptingJobs, IndicatorPrintersService *self) +{ + rebuildNow(self, SECTION_PRINTERS | SECTION_HEADER); +} + +static void onJobChanged (CupsNotifier *pNotifier, const gchar *sText, const gchar *sPrinterUri, const gchar *sPrinterName, guint nPrinterState, const gchar *sPrinterStateReasons, gboolean bPrinterIsAcceptingJobs, guint nJobId, guint nJobState, const gchar *sJobStateReasons, const gchar *sJobName, guint nJobImpressionsCompleted, IndicatorPrintersService *self) +{ + rebuildNow(self, SECTION_PRINTERS | SECTION_HEADER); +} + +static void onDispose (GObject *pObject) +{ + IndicatorPrintersService *self = INDICATOR_PRINTERS_SERVICE (pObject); + + unexport (self); + + if (self->pPrivate->pCancellable != NULL) + { + g_cancellable_cancel (self->pPrivate->pCancellable); + g_clear_object (&self->pPrivate->pCancellable); + } + + if (self->pPrivate->pCupsNotifier) + { + g_object_disconnect (self->pPrivate->pCupsNotifier, "any-signal", onJobChanged, self, "any-signal", onPrinterStateChanged, self, NULL); + g_clear_object (&self->pPrivate->pCupsNotifier); + } + + g_object_unref (self->pPrivate->pStateNotifier); + g_clear_object (&self->pPrivate->pPrinterAction); + g_clear_object (&self->pPrivate->pHeaderAction); + g_clear_object (&self->pPrivate->pActionGroup); + g_clear_object (&self->pPrivate->pConnection); + + G_OBJECT_CLASS (indicator_printers_service_parent_class)->dispose (pObject); +} + +static void indicator_printers_service_class_init (IndicatorPrintersServiceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = onDispose; + m_nSignal = g_signal_new ("name-lost", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (IndicatorPrintersServiceClass, pNameLost), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static int createSubscription () +{ + int nId = 0; + + ipp_t *pRequest = ippNewRequest (IPP_CREATE_PRINTER_SUBSCRIPTION); + ippAddString (pRequest, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/"); + ippAddString (pRequest, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events", NULL, "all"); + ippAddString (pRequest, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-recipient-uri", NULL, "dbus://"); + ippAddInteger (pRequest, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-duration", NOTIFY_LEASE_DURATION); + ipp_t *pResponse = cupsDoRequest (CUPS_HTTP_DEFAULT, pRequest, "/"); + + if (!pResponse || cupsLastError () != IPP_OK) + { + g_warning ("Error subscribing to CUPS notifications: %s\n", cupsLastErrorString ()); -static int -create_subscription () -{ - ipp_t *req; - ipp_t *resp; - ipp_attribute_t *attr; - int id = 0; - - req = ippNewRequest (IPP_CREATE_PRINTER_SUBSCRIPTION); - ippAddString (req, IPP_TAG_OPERATION, IPP_TAG_URI, - "printer-uri", NULL, "/"); - ippAddString (req, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, - "notify-events", NULL, "all"); - ippAddString (req, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, - "notify-recipient-uri", NULL, "dbus://"); - ippAddInteger (req, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-lease-duration", NOTIFY_LEASE_DURATION); - - resp = cupsDoRequest (CUPS_HTTP_DEFAULT, req, "/"); - if (!resp || cupsLastError() != IPP_OK) { - g_warning ("Error subscribing to CUPS notifications: %s\n", - cupsLastErrorString ()); return 0; } - attr = ippFindAttribute (resp, "notify-subscription-id", IPP_TAG_INTEGER); - if (attr) - id = ippGetInteger (attr, 0); + ipp_attribute_t *pAttribute = ippFindAttribute (pResponse, "notify-subscription-id", IPP_TAG_INTEGER); + + if (pAttribute) + { + nId = ippGetInteger (pAttribute, 0); + } else - g_warning ("ipp-create-printer-subscription response doesn't contain " - "subscription id.\n"); + { + g_warning ("ipp-create-printer-subscription response doesn't contain subscription id.\n"); + } - ippDelete (resp); - return id; + ippDelete (pResponse); + + return nId; } +static gboolean renewSubscriptionTimeout (gpointer pData) +{ + int *nSubscriptionId = pData; + gboolean bRenewed = TRUE; + ipp_t *pRequest = ippNewRequest (IPP_RENEW_SUBSCRIPTION); + ippAddInteger (pRequest, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-id", *nSubscriptionId); + ippAddString (pRequest, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/"); + ippAddString (pRequest, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-recipient-uri", NULL, "dbus://"); + ippAddInteger (pRequest, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-duration", NOTIFY_LEASE_DURATION); + ipp_t *pResponse = cupsDoRequest (CUPS_HTTP_DEFAULT, pRequest, "/"); + + if (!pResponse || cupsLastError () != IPP_OK) + { + g_warning ("Error renewing CUPS subscription %d: %s\n", *nSubscriptionId, cupsLastErrorString ()); + bRenewed = FALSE; + } + else + { + ippDelete (pResponse); + } + + if (*nSubscriptionId <= 0 || !bRenewed) + { + *nSubscriptionId = createSubscription (); + } + + return TRUE; +} -static gboolean -renew_subscription (int id) +static GVariant *createHeaderState (IndicatorPrintersService *self) { - ipp_t *req; - ipp_t *resp; + GVariantBuilder b; - req = ippNewRequest (IPP_RENEW_SUBSCRIPTION); - ippAddInteger (req, IPP_TAG_OPERATION, IPP_TAG_INTEGER, - "notify-subscription-id", id); - ippAddString (req, IPP_TAG_OPERATION, IPP_TAG_URI, - "printer-uri", NULL, "/"); - ippAddString (req, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, - "notify-recipient-uri", NULL, "dbus://"); - ippAddInteger (req, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-lease-duration", NOTIFY_LEASE_DURATION); + g_variant_builder_init (&b, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&b, "{sv}", "title", g_variant_new_string (_("Printers"))); + g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (TRUE)); - resp = cupsDoRequest (CUPS_HTTP_DEFAULT, req, "/"); - if (!resp || cupsLastError() != IPP_OK) { - g_warning ("Error renewing CUPS subscription %d: %s\n", - id, cupsLastErrorString ()); - return FALSE; + if (self->pPrivate->bVisible) + { + GIcon *pIcon = g_themed_icon_new_with_default_fallbacks ("printer-symbolic"); + g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_string (_("Printers"))); + + if (pIcon) + { + GVariant *pSerialized = g_icon_serialize (pIcon); + + if (pSerialized != NULL) + { + g_variant_builder_add (&b, "{sv}", "icon", pSerialized); + g_variant_unref (pSerialized); + } + + g_object_unref (pIcon); + } } - ippDelete (resp); - return TRUE; + return g_variant_builder_end (&b); } +static void onPrinterItemActivated (GSimpleAction *pAction, GVariant *pVariant, gpointer pData) +{ + const gchar *sPrinter = g_variant_get_string(pVariant, NULL); + spawn_printer_settings_with_args ("--show-jobs %s", sPrinter); +} -static gboolean -renew_subscription_timeout (gpointer userdata) +static void initActions (IndicatorPrintersService *self) { - int *subscription_id = userdata; + self->pPrivate->pActionGroup = g_simple_action_group_new (); - if (*subscription_id <= 0 || !renew_subscription (*subscription_id)) - *subscription_id = create_subscription (); + GSimpleAction *pAction = g_simple_action_new_stateful ("_header", NULL, createHeaderState (self)); + g_action_map_add_action (G_ACTION_MAP (self->pPrivate->pActionGroup), G_ACTION (pAction)); + self->pPrivate->pHeaderAction = pAction; - return TRUE; + pAction = g_simple_action_new("printer", G_VARIANT_TYPE_STRING); + g_action_map_add_action (G_ACTION_MAP (self->pPrivate->pActionGroup), G_ACTION (pAction)); + self->pPrivate->pPrinterAction = pAction; + g_signal_connect(pAction, "activate", G_CALLBACK(onPrinterItemActivated), self); + + rebuildNow (self, SECTION_HEADER); } +static GMenuModel *createPrintersSection (IndicatorPrintersService *self) +{ + self->pPrivate->pPrintersSection = g_menu_new (); + self->pPrivate->bVisible = FALSE; + cups_dest_t *lDests; + gint nDests = cupsGetDests (&lDests); + + for (gint i = 0; i < nDests; i++) + { + const gchar *sOption = cupsGetOption ("printer-state", lDests[i].num_options, lDests[i].options); + + if (sOption != NULL) + { + cups_job_t *lJobs; + gint nJobs = cupsGetJobs (&lJobs, lDests[i].name, 1, CUPS_WHICHJOBS_ACTIVE); + cupsFreeJobs (nJobs, lJobs); + + if (nJobs < 0) + { + g_warning ("printer '%s' does not exist\n", lDests[i].name); + } + else if (nJobs != 0) + { + GMenuItem *pItem = g_menu_item_new (lDests[i].name, NULL); + g_menu_item_set_attribute (pItem, "x-ayatana-type", "s", "org.ayatana.indicator.basic"); + g_menu_item_set_action_and_target_value(pItem, "indicator.printer", g_variant_new_string (lDests[i].name)); + GIcon *pIcon = g_themed_icon_new_with_default_fallbacks ("printer"); + GVariant *pSerialized = g_icon_serialize(pIcon); + + if (pSerialized != NULL) + { + g_menu_item_set_attribute_value(pItem, G_MENU_ATTRIBUTE_ICON, pSerialized); + g_variant_unref(pSerialized); + } + + g_object_unref(pIcon); + + gint nState = atoi (sOption); + + switch (nState) + { + case IPP_PRINTER_STOPPED: + { + g_menu_item_set_attribute (pItem, "x-ayatana-secondary-text", "s", _("Paused")); + + break; + } + case IPP_PRINTER_PROCESSING: + { + g_menu_item_set_attribute (pItem, "x-ayatana-secondary-count", "i", nJobs); + + break; + } + } + + g_menu_append_item(self->pPrivate->pPrintersSection, pItem); + g_object_unref(pItem); + self->pPrivate->bVisible = TRUE; + } + } + } + + cupsFreeDests (nDests, lDests); + + return G_MENU_MODEL (self->pPrivate->pPrintersSection); +} -void -cancel_subscription (int id) +static void createMenu (IndicatorPrintersService *self, int nProfile) { - ipp_t *req; - ipp_t *resp; + g_assert (0 <= nProfile && nProfile < N_PROFILES); + g_assert (self->pPrivate->lMenus[nProfile].pMenu == NULL); - if (id <= 0) - return; + GMenuModel *lSections[16]; + guint nSection = 0; - req = ippNewRequest (IPP_CANCEL_SUBSCRIPTION); - ippAddString (req, IPP_TAG_OPERATION, IPP_TAG_URI, - "printer-uri", NULL, "/"); - ippAddInteger (req, IPP_TAG_OPERATION, IPP_TAG_INTEGER, - "notify-subscription-id", id); + // Build the sections + switch (nProfile) + { + case PROFILE_PHONE: + case PROFILE_DESKTOP: + { + lSections[nSection++] = createPrintersSection (self); - resp = cupsDoRequest (CUPS_HTTP_DEFAULT, req, "/"); - if (!resp || cupsLastError() != IPP_OK) { - g_warning ("Error subscribing to CUPS notifications: %s\n", - cupsLastErrorString ()); - return; + break; + } + + break; } - ippDelete (resp); + // Add sections to the submenu + GMenu *pSubmenu = g_menu_new (); + + for (guint i = 0; i < nSection; ++i) + { + g_menu_append_section (pSubmenu, NULL, lSections[i]); + g_object_unref (lSections[i]); + } + + // Add submenu to the header + GMenuItem *pHeader = g_menu_item_new (NULL, "indicator._header"); + g_menu_item_set_attribute (pHeader, "x-ayatana-type", "s", "org.ayatana.indicator.root"); + g_menu_item_set_submenu (pHeader, G_MENU_MODEL (pSubmenu)); + g_object_unref (pSubmenu); + + // Add header to the menu + GMenu *pMenu = g_menu_new (); + g_menu_append_item (pMenu, pHeader); + g_object_unref (pHeader); + + self->pPrivate->lMenus[nProfile].pMenu = pMenu; + self->pPrivate->lMenus[nProfile].pSubmenu = pSubmenu; } -static void -name_lost (GDBusConnection *connection, - const gchar *name, - gpointer user_data) +static void onBusAcquired (GDBusConnection *pConnection, const gchar *sName, gpointer pSelf) { - int subscription_id = GPOINTER_TO_INT (user_data); + g_debug ("bus acquired: %s", sName); + + IndicatorPrintersService *self = INDICATOR_PRINTERS_SERVICE (pSelf); + guint nId; + GError *pError = NULL; + GString *pPath = g_string_new (NULL); + self->pPrivate->pConnection = (GDBusConnection*)g_object_ref (G_OBJECT (pConnection)); + + // Export the actions + if ((nId = g_dbus_connection_export_action_group (pConnection, INDICATOR_PRINTERS_DBUS_OBJECT_PATH, G_ACTION_GROUP (self->pPrivate->pActionGroup), &pError))) + { + self->pPrivate->nActionsId = nId; + } + else + { + g_warning ("cannot export action group: %s", pError->message); + g_clear_error (&pError); + } - cancel_subscription (subscription_id); - gtk_main_quit (); + // Export the menus + for (gint nProfile = 0; nProfile < N_PROFILES; ++nProfile) + { + struct ProfileMenuInfo *pInfo = &self->pPrivate->lMenus[nProfile]; + + g_string_printf (pPath, "%s/%s", INDICATOR_PRINTERS_DBUS_OBJECT_PATH, lMenuNames[nProfile]); + + if ((nId = g_dbus_connection_export_menu_model (pConnection, pPath->str, G_MENU_MODEL (pInfo->pMenu), &pError))) + { + pInfo->nExportId = nId; + } + else + { + g_warning ("cannot export %s menu: %s", pPath->str, pError->message); + g_clear_error (&pError); + } + } + + g_string_free (pPath, TRUE); } -int main (int argc, char *argv[]) +static void onNameLost (GDBusConnection *pConnection, const gchar *sName, gpointer pSelf) { - /* Init i18n */ - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); + IndicatorPrintersService *self = INDICATOR_PRINTERS_SERVICE (pSelf); - DbusmenuServer *menuserver; - CupsNotifier *cups_notifier; - IndicatorPrintersMenu *menu; - IndicatorPrinterStateNotifier *state_notifier; - GError *error = NULL; - int subscription_id; + g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, sName); - gtk_init (&argc, &argv); + unexport (self); +} - subscription_id = create_subscription (); - g_timeout_add_seconds (NOTIFY_LEASE_DURATION - 60, - renew_subscription_timeout, - &subscription_id); +static void indicator_printers_service_init (IndicatorPrintersService *self) +{ + self->pPrivate = indicator_printers_service_get_instance_private (self); + self->pPrivate->pCancellable = g_cancellable_new (); + + GError *pError = NULL; + self->pPrivate->nSubscriptionId = createSubscription (); + g_timeout_add_seconds (NOTIFY_LEASE_DURATION - 60, renewSubscriptionTimeout, &self->pPrivate->nSubscriptionId); + self->pPrivate->pCupsNotifier = cups_notifier_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, CUPS_DBUS_PATH, NULL, &pError); + + if (pError) + { + g_error ("Error creating cups notify handler: %s", pError->message); + g_error_free (pError); + } - g_bus_own_name (G_BUS_TYPE_SESSION, - INDICATOR_PRINTERS_DBUS_NAME, - G_BUS_NAME_OWNER_FLAGS_NONE, - NULL, NULL, name_lost, - GINT_TO_POINTER (subscription_id), NULL); + g_object_connect (self->pPrivate->pCupsNotifier, "signal::job-created", onJobChanged, self, "signal::job-state", onJobChanged, self, "signal::job-completed", onJobChanged, self, "signal::printer-state-changed", onPrinterStateChanged, self, NULL); + self->pPrivate->pStateNotifier = g_object_new (INDICATOR_TYPE_PRINTER_STATE_NOTIFIER, "cups-notifier", self->pPrivate->pCupsNotifier, NULL); + initActions (self); - cups_notifier = cups_notifier_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - 0, - NULL, - CUPS_DBUS_PATH, - NULL, - &error); - if (error) { - g_warning ("Error creating cups notify handler: %s", error->message); - g_error_free (error); - return 1; + for (gint nProfile = 0; nProfile < N_PROFILES; ++nProfile) + { + createMenu (self, nProfile); } - menu = g_object_new (INDICATOR_TYPE_PRINTERS_MENU, - "cups-notifier", cups_notifier, - NULL); + self->pPrivate->bMenusBuilt = TRUE; + self->pPrivate->nOwnId = g_bus_own_name (G_BUS_TYPE_SESSION, INDICATOR_PRINTERS_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, onBusAcquired, NULL, onNameLost, self, NULL); +} + +IndicatorPrintersService *indicator_printers_service_new () +{ + GObject *pObject = g_object_new (INDICATOR_TYPE_PRINTERS_SERVICE, NULL); + + return INDICATOR_PRINTERS_SERVICE (pObject); +} + +static void rebuildSection (GMenu *pMenu, int nPos, GMenuModel *pSection) +{ + g_menu_remove (pMenu, nPos); + g_menu_insert_section (pMenu, nPos, NULL, pSection); + g_object_unref (pSection); +} - menuserver = dbusmenu_server_new (INDICATOR_PRINTERS_DBUS_OBJECT_PATH); - dbusmenu_server_set_root (menuserver, - indicator_printers_menu_get_root (menu)); +static void rebuildNow (IndicatorPrintersService *self, guint nSections) +{ + struct ProfileMenuInfo *pinfo = &self->pPrivate->lMenus[PROFILE_DESKTOP]; - state_notifier = g_object_new (INDICATOR_TYPE_PRINTER_STATE_NOTIFIER, - "cups-notifier", cups_notifier, - NULL); + if (nSections & SECTION_HEADER) + { + g_simple_action_set_state (self->pPrivate->pHeaderAction, createHeaderState (self)); + } - gtk_main (); + if (!self->pPrivate->bMenusBuilt) + { + return; + } - g_object_unref (menu); - g_object_unref (menuserver); - g_object_unref (state_notifier); - g_object_unref (cups_notifier); - return 0; + if (nSections & SECTION_PRINTERS) + { + rebuildSection (pinfo->pSubmenu, 0, createPrintersSection (self)); + } } diff --git a/src/indicator-printers-service.h b/src/indicator-printers-service.h new file mode 100644 index 0000000..0b093c1 --- /dev/null +++ b/src/indicator-printers-service.h @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Robert Tari + * + * Authors: Robert Tari <robert@tari.in> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 __INDICATOR_PRINTERS_SERVICE_H__ +#define __INDICATOR_PRINTERS_SERVICE_H__ + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define INDICATOR_PRINTERS_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_PRINTERS_SERVICE, IndicatorPrintersService)) +#define INDICATOR_TYPE_PRINTERS_SERVICE (indicator_printers_service_get_type ()) +#define INDICATOR_IS_PRINTERS_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_PRINTERS_SERVICE)) + +typedef struct _IndicatorPrintersService IndicatorPrintersService; +typedef struct _IndicatorPrintersServiceClass IndicatorPrintersServiceClass; +typedef struct _IndicatorPrintersServicePrivate IndicatorPrintersServicePrivate; + +struct _IndicatorPrintersService +{ + GObject parent; + IndicatorPrintersServicePrivate *pPrivate; +}; + +struct _IndicatorPrintersServiceClass +{ + GObjectClass parent_class; + void (*pNameLost) (IndicatorPrintersService *self); +}; + +GType indicator_printers_service_get_type (void); +IndicatorPrintersService *indicator_printers_service_new (); + +G_END_DECLS + +#endif diff --git a/src/indicator-printers.c b/src/indicator-printers.c deleted file mode 100644 index 2b7bb36..0000000 --- a/src/indicator-printers.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * Copyright 2022 Robert Tari - * - * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> - * Robert Tari <robert@tari.in> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 "indicator-printers.h" -#include "indicator-menu-item.h" -#include "dbus-names.h" - -#include <glib/gi18n-lib.h> -#include <gtk/gtk.h> -#include <gio/gio.h> - -#include <libayatana-indicator/indicator.h> -#include <libayatana-indicator/indicator-image-helper.h> - -#include <libdbusmenu-gtk/menu.h> -#include <libdbusmenu-gtk/menuitem.h> - - -INDICATOR_SET_VERSION -INDICATOR_SET_TYPE(INDICATOR_PRINTERS_TYPE) - -struct _IndicatorPrintersPrivate -{ - IndicatorObjectEntry entry; - guint name_watch; -}; - -G_DEFINE_TYPE_WITH_PRIVATE(IndicatorPrinters, indicator_printers, INDICATOR_OBJECT_TYPE) - -static void -dispose (GObject *object) -{ - IndicatorPrinters *self = INDICATOR_PRINTERS (object); - if (self->priv->name_watch != 0) { - g_bus_unwatch_name(self->priv->name_watch); - self->priv->name_watch = 0; - } - g_clear_object (&self->priv->entry.menu); - g_clear_object (&self->priv->entry.image); - G_OBJECT_CLASS (indicator_printers_parent_class)->dispose (object); -} - - -static GList * -get_entries (IndicatorObject *io) -{ - IndicatorPrinters *self = INDICATOR_PRINTERS (io); - return g_list_append (NULL, &self->priv->entry); -} - - -static void -indicator_printers_class_init (IndicatorPrintersClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - IndicatorObjectClass *io_class = INDICATOR_OBJECT_CLASS (klass); - - object_class->dispose = dispose; - - io_class->get_entries = get_entries; -} - - -static void -name_vanished (GDBusConnection * con, - const gchar * name, - gpointer user_data) -{ - IndicatorPrinters *self = INDICATOR_PRINTERS (user_data); - - indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE); -} - - -static GdkPixbuf * -gdk_pixbuf_new_from_encoded_data (guchar *data, - gsize length) -{ - GInputStream * input; - GError *err = NULL; - GdkPixbuf *img; - - input = g_memory_input_stream_new_from_data(data, length, NULL); - if (input == NULL) - return NULL; - - img = gdk_pixbuf_new_from_stream(input, NULL, &err); - if (err) { - g_warning("%s", err->message); - g_error_free(err); - } - - g_object_unref(input); - return img; -} - - -static GdkPixbuf * -g_variant_get_image (GVariant *value) -{ - const gchar *strvalue = NULL; - gsize length = 0; - guchar *icondata; - GdkPixbuf *img; - - if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) - strvalue = g_variant_get_string(value, NULL); - - if (!strvalue || !*strvalue) { - g_warning ("%s: value does not contain a base64 encoded image", - __func__); - return NULL; - } - - icondata = g_base64_decode(strvalue, &length); - img = gdk_pixbuf_new_from_encoded_data (icondata, length); - - g_free(icondata); - return img; -} - - -static gboolean -properties_match (const gchar *name, - const gchar *prop, - GVariant *value, - const GVariantType *type) -{ - return !g_strcmp0 (name, prop) && g_variant_is_of_type (value, type); -} - - -static void -indicator_prop_change_cb (DbusmenuMenuitem *mi, - gchar *prop, - GVariant *value, - gpointer user_data) -{ - IndicatorMenuItem *menuitem = user_data; - - if (properties_match (prop, "indicator-label", value, G_VARIANT_TYPE_STRING)) - indicator_menu_item_set_label (menuitem, g_variant_get_string (value, NULL)); - - else if (properties_match (prop, "indicator-right", value, G_VARIANT_TYPE_STRING)) - indicator_menu_item_set_right (menuitem, g_variant_get_string (value, NULL)); - - else if (properties_match (prop, "indicator-icon-name", value, G_VARIANT_TYPE_STRING)) - indicator_menu_item_set_icon_name (menuitem, g_variant_get_string (value, NULL)); - - else if (properties_match (prop, "indicator-icon", value, G_VARIANT_TYPE_STRING)) { - GdkPixbuf *pb = g_variant_get_image (value); - indicator_menu_item_set_icon (menuitem, pb); - g_object_unref (pb); - } - - else if (properties_match (prop, "visible", value, G_VARIANT_TYPE_BOOLEAN)) - gtk_widget_set_visible (GTK_WIDGET (menuitem), g_variant_get_boolean (value)); - - else if (properties_match (prop, "indicator-right-is-lozenge", value, G_VARIANT_TYPE_BOOLEAN)) - indicator_menu_item_set_right_is_lozenge (menuitem, g_variant_get_boolean (value)); -} - - -static void -root_property_changed (DbusmenuMenuitem *mi, - gchar *prop, - GVariant *value, - gpointer user_data) -{ - IndicatorObject *io = user_data; - - if (properties_match (prop, "visible", value, G_VARIANT_TYPE_BOOLEAN)) - indicator_object_set_visible (io, g_variant_get_boolean (value)); -} - - -static gboolean -new_indicator_item (DbusmenuMenuitem *newitem, - DbusmenuMenuitem *parent, - DbusmenuClient *client, - gpointer user_data) -{ - GtkWidget *menuitem; - const gchar *icon_name, *text, *right_text; - GVariant *icon; - gboolean is_lozenge, visible; - - icon_name = dbusmenu_menuitem_property_get (newitem, "indicator-icon-name"); - icon = dbusmenu_menuitem_property_get_variant (newitem, "indicator-icon"); - text = dbusmenu_menuitem_property_get (newitem, "indicator-label"); - right_text = dbusmenu_menuitem_property_get (newitem, "indicator-right"); - is_lozenge = dbusmenu_menuitem_property_get_bool (newitem, "indicator-right-is-lozenge"); - visible = dbusmenu_menuitem_property_get_bool (newitem, "visible"); - - menuitem = g_object_new (INDICATOR_TYPE_MENU_ITEM, - "icon-name", icon_name, - "label", text, - "right", right_text, - "right-is-lozenge", is_lozenge, - "visible", visible, - NULL); - if (icon) { - GdkPixbuf *pb = g_variant_get_image (icon); - indicator_menu_item_set_icon (INDICATOR_MENU_ITEM (menuitem), pb); - g_object_unref (pb); - } - gtk_widget_show_all (menuitem); - - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), - newitem, - GTK_MENU_ITEM (menuitem), - parent); - - g_signal_connect(G_OBJECT(newitem), - "property-changed", - G_CALLBACK(indicator_prop_change_cb), - menuitem); - - return TRUE; -} - - -static void -root_changed (DbusmenuClient *client, - DbusmenuMenuitem *newroot, - gpointer user_data) -{ - IndicatorPrinters *indicator = user_data; - gboolean is_visible; - - if (newroot) { - is_visible = dbusmenu_menuitem_property_get_bool (newroot, "visible"); - g_signal_connect (newroot, "property-changed", - G_CALLBACK (root_property_changed), indicator); - } - else - is_visible = FALSE; - - indicator_object_set_visible (INDICATOR_OBJECT (indicator), is_visible); -} - - -static void -indicator_printers_init (IndicatorPrinters *self) -{ - IndicatorPrintersPrivate *priv; - DbusmenuGtkMenu *menu; - DbusmenuClient *client; - GtkImage *image; - - priv = indicator_printers_get_instance_private(self); - self->priv = priv; - - priv->name_watch = g_bus_watch_name(G_BUS_TYPE_SESSION, - INDICATOR_PRINTERS_DBUS_NAME, - G_BUS_NAME_WATCHER_FLAGS_NONE, - NULL, /* appeared */ - name_vanished, - self, NULL); - - menu = dbusmenu_gtkmenu_new(INDICATOR_PRINTERS_DBUS_NAME, - INDICATOR_PRINTERS_DBUS_OBJECT_PATH); - - client = DBUSMENU_CLIENT (dbusmenu_gtkmenu_get_client (menu)); - dbusmenu_client_add_type_handler(client, - "indicator-item", - new_indicator_item); - g_signal_connect (client, "root-changed", G_CALLBACK (root_changed), self); - - image = indicator_image_helper ("printer-symbolic"); - gtk_widget_show (GTK_WIDGET (image)); - - priv->entry.name_hint = PACKAGE_NAME; - priv->entry.accessible_desc = _("Printers"); - priv->entry.menu = GTK_MENU (g_object_ref_sink (menu)); - priv->entry.image = g_object_ref_sink (image); - - indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE); -} - - -IndicatorPrinters * -indicator_printers_new (void) -{ - return g_object_new (INDICATOR_PRINTERS_TYPE, NULL); -} diff --git a/src/indicator-printers.h b/src/indicator-printers.h deleted file mode 100644 index 51b790c..0000000 --- a/src/indicator-printers.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * Authors: Lars Uebernickel <lars.uebernickel@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 INDICATOR_PRINTERS_H -#define INDICATOR_PRINTERS_H - -#include <libayatana-indicator/indicator-object.h> - -G_BEGIN_DECLS - -#define INDICATOR_PRINTERS_TYPE indicator_printers_get_type() - -#define INDICATOR_PRINTERS(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - INDICATOR_PRINTERS_TYPE, IndicatorPrinters)) - -#define INDICATOR_PRINTERS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), \ - INDICATOR_PRINTERS_TYPE, IndicatorPrintersClass)) - -#define INDICATOR_IS_PRINTERS(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ - INDICATOR_PRINTERS_TYPE)) - -#define INDICATOR_IS_PRINTERS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), \ - INDICATOR_PRINTERS_TYPE)) - -#define INDICATOR_PRINTERS_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - INDICATOR_PRINTERS_TYPE, IndicatorPrintersClass)) - -typedef struct _IndicatorPrinters IndicatorPrinters; -typedef struct _IndicatorPrintersClass IndicatorPrintersClass; -typedef struct _IndicatorPrintersPrivate IndicatorPrintersPrivate; - -struct _IndicatorPrinters -{ - IndicatorObject parent; - IndicatorPrintersPrivate *priv; -}; - -struct _IndicatorPrintersClass -{ - IndicatorObjectClass parent_class; -}; - -GType indicator_printers_get_type (void) G_GNUC_CONST; - -IndicatorPrinters *indicator_printers_new (void); - -G_END_DECLS - -#endif - diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6cc5103 --- /dev/null +++ b/src/main.c @@ -0,0 +1,47 @@ +/* + * Copyright 2022 Robert Tari + * + * Authors: + * Robert Tari <robert@tari.in> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 <locale.h> +#include <glib.h> +#include <glib/gi18n.h> +#include "indicator-printers-service.h" + +static void onNameLost (gpointer pInstance G_GNUC_UNUSED, gpointer pLoop) +{ + g_message("Exiting: service couldn't acquire or lost ownership of busname"); + g_main_loop_quit ((GMainLoop*) pLoop); +} + +int main (int argc G_GNUC_UNUSED, char **argv G_GNUC_UNUSED) +{ + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + IndicatorPrintersService *pService = indicator_printers_service_new (NULL); + GMainLoop *pLoop = g_main_loop_new (NULL, FALSE); + g_signal_connect (pService, "name-lost", G_CALLBACK (onNameLost), pLoop); + g_main_loop_run (pLoop); + + g_main_loop_unref (pLoop); + g_clear_object (&pService); + + return 0; +} |