diff --git a/debian/changelog b/debian/changelog index 312b59d..25c3840 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,19 @@ +xapp (1.8.7) ulyana; urgency=medium + + [ Clement Lefebvre ] + * Update docs + + [ Michael Webster ] + * xapp-status-icon.c: Get rid of the dead 'shadow' region around menus, as they can interfere with clicking on the icon to close the menu. + * xapp-status-icon: Add new properties for menu/button state handling and one for metadata (miscellaneous info to help define behavior in the status applets). + * xapp-sn-watcher: Set status icon metadata for appindicator icons, to inform the applet to highlight/toggle the panel icon with either button click when opening the menu. + * mate-xapp-status-applet.py: Use new properties to sync button toggle state with the menu state. + * test-scripts: Update some scripts to demonstrate new property use. + * sn-item: Remove support for XAyatanaLabel. + * xapp-sn-watcher: Update clear the registration list before freeing the table of registered items. + + -- Clement Lefebvre Sat, 06 Jun 2020 14:29:58 +0100 + xapp (1.8.6) ulyana; urgency=medium [ Clement Lefebvre ] diff --git a/docs/reference/XAppStatusIcon.html b/docs/reference/XAppStatusIcon.html index 07a229e..5e2f91b 100644 --- a/docs/reference/XAppStatusIcon.html +++ b/docs/reference/XAppStatusIcon.html @@ -111,6 +111,14 @@ void +xapp_status_icon_popup_menu () + + + + +void + + xapp_status_icon_set_primary_menu () @@ -490,6 +498,69 @@

the current visibility state.

Since: 1.8.5

+ +
+
+

xapp_status_icon_popup_menu ()

+
void
+xapp_status_icon_popup_menu (XAppStatusIcon *icon,
+                             GtkMenu *menu,
+                             gint x,
+                             gint y,
+                             guint button,
+                             guint _time,
+                             gint panel_position);
+

Pop up menu + using the positioning arguments. These arguments should be +those provided by a “button-release-event”.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

icon

an XAppStatusIcon

 

menu

A GtkMenu to display when the primary mouse button is released.

[nullable]

x

The x anchor position for the menu.

 

y

The y anchor position for the menu.

 

button

The button used to initiate this action (or 0)

 

_time

The event time (or 0)

 

panel_position

The GtkPositionType for the position of the icon.

 
+
+

Since: 1.8.6


diff --git a/docs/reference/api-index-full.html b/docs/reference/api-index-full.html index 40e2e51..29856ea 100644 --- a/docs/reference/api-index-full.html +++ b/docs/reference/api-index-full.html @@ -631,6 +631,10 @@
+xapp_status_icon_popup_menu, function in XAppStatusIcon +
+
+
xapp_status_icon_set_icon_name, function in XAppStatusIcon
diff --git a/docs/reference/index.html b/docs/reference/index.html index 752ff39..d972c85 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -15,7 +15,7 @@

- xapp 1.8.5 + xapp 1.8.6


diff --git a/docs/reference/libxapp.devhelp2 b/docs/reference/libxapp.devhelp2 index a5f93b6..804f1a3 100644 --- a/docs/reference/libxapp.devhelp2 +++ b/docs/reference/libxapp.devhelp2 @@ -112,6 +112,7 @@ + diff --git a/libxapp/org.x.StatusIcon.xml b/libxapp/org.x.StatusIcon.xml index 6bf2f16..c8b9634 100644 --- a/libxapp/org.x.StatusIcon.xml +++ b/libxapp/org.x.StatusIcon.xml @@ -28,5 +28,8 @@ + + + diff --git a/libxapp/xapp-status-icon.c b/libxapp/xapp-status-icon.c index 9c7d333..0c8a935 100644 --- a/libxapp/xapp-status-icon.c +++ b/libxapp/xapp-status-icon.c @@ -84,6 +84,7 @@ gchar *label; gboolean visible; gint icon_size; + gchar *metadata; guint owner_id; guint listener_id; @@ -255,6 +256,40 @@ } static void +primary_menu_unmapped (GtkWidget *widget, + gpointer user_data) +{ + g_return_if_fail (XAPP_IS_STATUS_ICON (user_data)); + XAppStatusIcon *icon = XAPP_STATUS_ICON (user_data); + + g_debug ("XAppStatusIcon: Primary menu unmapped"); + + if (icon->priv->state == XAPP_STATUS_ICON_STATE_NATIVE) + { + xapp_status_icon_interface_set_primary_menu_is_open (icon->priv->skeleton, FALSE); + } + + g_signal_handlers_disconnect_by_func (widget, primary_menu_unmapped, icon); +} + +static void +secondary_menu_unmapped (GtkWidget *widget, + gpointer user_data) +{ + g_return_if_fail (XAPP_IS_STATUS_ICON (user_data)); + XAppStatusIcon *icon = XAPP_STATUS_ICON (user_data); + + g_debug ("XAppStatusIcon: Secondary menu unmapped"); + + if (icon->priv->state == XAPP_STATUS_ICON_STATE_NATIVE) + { + xapp_status_icon_interface_set_secondary_menu_is_open (icon->priv->skeleton, FALSE); + } + + g_signal_handlers_disconnect_by_func (widget, secondary_menu_unmapped, icon); +} + +static void popup_menu (XAppStatusIcon *self, GtkMenu *menu, gint x, @@ -269,6 +304,51 @@ GdkGravity rect_anchor, menu_anchor; g_debug ("XAppStatusIcon: Popup menu on behalf of application"); + + if (!gtk_widget_get_realized (GTK_WIDGET (menu))) + { + GtkWidget *toplevel; + GtkStyleContext *context; + + gtk_widget_realize (GTK_WIDGET (menu)); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu)); + context = gtk_widget_get_style_context (toplevel); + + /* GtkMenu uses a GtkWindow as its toplevel that is explicitly set to + * be client-decorated, and applies shadows outside the visible part of + * the menu. They interfere with clicks on the icon while the menu is open, + * as the invisible part takes the events instead (and this ends up doing + * nothing). It makes the menu a littly ugly, so here's a new class name we + * can use for themes to restore things bit if we want. Just avoid shadows. */ + gtk_style_context_remove_class (context, "csd"); + gtk_style_context_add_class (context, "xapp-status-icon-menu-window"); + } + + if (button == GDK_BUTTON_PRIMARY) + { + if (self->priv->state == XAPP_STATUS_ICON_STATE_NATIVE) + { + xapp_status_icon_interface_set_primary_menu_is_open (self->priv->skeleton, TRUE); + } + + g_signal_connect (gtk_widget_get_toplevel (GTK_WIDGET (menu)), + "unmap", + G_CALLBACK (primary_menu_unmapped), + self); + } + else + if (button == GDK_BUTTON_SECONDARY) + { + if (self->priv->state == XAPP_STATUS_ICON_STATE_NATIVE) + { + xapp_status_icon_interface_set_secondary_menu_is_open (self->priv->skeleton, TRUE); + } + + g_signal_connect (gtk_widget_get_toplevel (GTK_WIDGET (menu)), + "unmap", + G_CALLBACK (secondary_menu_unmapped), + self); + } event = synthesize_event (self, x, y, button, _time, panel_position, @@ -655,6 +735,7 @@ "icon-name", priv->icon_name, "tooltip-text", priv->tooltip_text, "visible", priv->visible, + "metadata", priv->metadata, NULL); g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (priv->skeleton)); @@ -1724,6 +1805,41 @@ } /** + * xapp_status_icon_set_metadata: + * @icon: an #XAppStatusIcon + * @metadata: (nullable): A json-formatted string of key:values. + * + * Sets metadata to pass to the icon proxy for an applet's use. Right now this is only so + * xapp-sn-watcher can tell the applets when the icon is originating from appindicator so panel + * button 'highlighting' can behave correctly. + * + * Since: 1.8.7 + */ +void +xapp_status_icon_set_metadata (XAppStatusIcon *icon, + const gchar *metadata) +{ + g_return_if_fail (XAPP_IS_STATUS_ICON (icon)); + gchar *old_meta; + + g_debug ("XAppStatusIcon set_metadata: '%s'", metadata); + + if (g_strcmp0 (metadata, icon->priv->metadata) == 0) + { + return; + } + + old_meta = icon->priv->metadata; + icon->priv->metadata = g_strdup (metadata); + g_free (old_meta); + + if (icon->priv->skeleton) + { + xapp_status_icon_interface_set_metadata (icon->priv->skeleton, metadata); + } +} + +/** * xapp_status_icon_any_monitors: * * Looks for the existence of any active #XAppStatusIconMonitors on the bus. diff --git a/libxapp/xapp-status-icon.h b/libxapp/xapp-status-icon.h index a848af7..d76125a 100644 --- a/libxapp/xapp-status-icon.h +++ b/libxapp/xapp-status-icon.h @@ -66,6 +66,8 @@ void xapp_status_icon_set_secondary_menu (XAppStatusIcon *icon, GtkMenu *menu); GtkWidget *xapp_status_icon_get_secondary_menu (XAppStatusIcon *icon); XAppStatusIconState xapp_status_icon_get_state (XAppStatusIcon *icon); +void xapp_status_icon_set_metadata (XAppStatusIcon *icon, + const gchar *metadata); /* static */ gboolean xapp_status_icon_any_monitors (void); diff --git a/meson.build b/meson.build index 1c962a7..88d1beb 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('xapp', 'c', - version : '1.8.6' + version : '1.8.7' ) gnome = import('gnome') diff --git a/status-applets/mate/mate-xapp-status-applet.py b/status-applets/mate/mate-xapp-status-applet.py index ff847b6..32cbb88 100755 --- a/status-applets/mate/mate-xapp-status-applet.py +++ b/status-applets/mate/mate-xapp-status-applet.py @@ -2,6 +2,7 @@ import locale import gettext +import json import os import sys import setproctitle @@ -56,7 +57,7 @@ class StatusWidget(Gtk.ToggleButton): def __init__(self, icon, orientation, size): - super(Gtk.Button, self).__init__() + super(Gtk.ToggleButton, self).__init__() self.theme = Gtk.IconTheme.get_default() self.orientation = orientation self.size = size @@ -93,11 +94,26 @@ self.proxy.bind_property("tooltip-text", self, "tooltip-markup", flags) self.proxy.bind_property("visible", self, "visible", flags) + self.proxy.connect("notify::primary-menu-is-open", self.menu_state_changed) + self.proxy.connect("notify::secondary-menu-is-open", self.menu_state_changed) + + self.highlight_both_menus = False + + if self.proxy.props.metadata not in ("", None): + try: + meta = json.loads(self.proxy.props.metadata) + if meta["highlight-both-menus"]: + self.highlight_both_menus = True + except json.JSONDecodeError as e: + print("Could not read metadata: %s" % e) + self.proxy.connect("notify::icon-name", self._on_icon_name_changed) self.in_widget = False self.plain_surface = None self.saturated_surface = None + + self.menu_opened = False self.connect("button-press-event", self.on_button_press) self.connect("button-release-event", self.on_button_release) @@ -175,6 +191,19 @@ self.image.set_pixel_size(self.size - ICON_SIZE_REDUCTION) self.image.set_from_icon_name("image-missing", Gtk.IconSize.MENU) + def menu_state_changed(self, proxy, pspec, data=None): + if pspec.name == "primary-menu-is-open": + prop = proxy.props.primary_menu_is_open + else: + prop = proxy.props.secondary_menu_is_open + + if not self.menu_opened or prop == False: + self.set_active(False) + return + + self.set_active(prop) + self.menu_opened = False + # TODO? def on_enter_notify(self, widget, event): self.in_widget = True @@ -187,12 +216,9 @@ return Gdk.EVENT_PROPAGATE # /TODO - def after_release_idle(self, data=None): - self.set_active(False) - - return GLib.SOURCE_REMOVE - def on_button_press(self, widget, event): + self.menu_opened = False + # If the user does ctrl->right-click, open the applet's about menu # instead of sending to the app. if event.state & Gdk.ModifierType.CONTROL_MASK and event.button == Gdk.BUTTON_SECONDARY: @@ -203,23 +229,23 @@ x, y = self.calc_menu_origin(widget, orientation) self.proxy.call_button_press(x, y, event.button, event.time, orientation, None, None) - if event.button != Gdk.BUTTON_PRIMARY: - self.set_active(True) - if event.button in (Gdk.BUTTON_MIDDLE, Gdk.BUTTON_SECONDARY): # Block the 'remove from panel' menu, and the middle-click drag. # They can still accomplish these things along the edges of the applet return Gdk.EVENT_STOP - return Gdk.EVENT_PROPAGATE + return Gdk.EVENT_STOP def on_button_release(self, widget, event): orientation = translate_applet_orientation_to_xapp(self.orientation) + if event.button == Gdk.BUTTON_PRIMARY: + self.menu_opened = True + elif event.button == Gdk.BUTTON_SECONDARY and self.highlight_both_menus: + self.menu_opened = True + x, y = self.calc_menu_origin(widget, orientation) self.proxy.call_button_release(x, y, event.button, event.time, orientation, None, None) - - GObject.timeout_add(200, self.after_release_idle) return Gdk.EVENT_PROPAGATE diff --git a/test-scripts/xapp-status-applet b/test-scripts/xapp-status-applet index 76133c5..975b0e8 100755 --- a/test-scripts/xapp-status-applet +++ b/test-scripts/xapp-status-applet @@ -5,14 +5,15 @@ from gi.repository import Gio, GLib, GObject, Gtk, XApp, Gdk import os import sys +import json DBUS_NAME = "org.x.StatusIcon" DBUS_PATH = "/org/x/StatusIcon" -class StatusWidget(Gtk.Button): +class StatusWidget(Gtk.ToggleButton): def __init__(self, icon): - super(Gtk.Button, self).__init__() + super(Gtk.ToggleButton, self).__init__() self.proxy = icon self.name = self.proxy.get_name() @@ -36,6 +37,9 @@ self.proxy.bind_property("label", self.label, "label", flags) self.proxy.bind_property("tooltip-text", self, "tooltip-markup", flags) self.proxy.bind_property("visible", self, "visible", flags) + + self.proxy.bind_property("primary-menu-is-open", self, "active", flags) + self.proxy.bind_property("secondary-menu-is-open", self, "active", flags) self.proxy.connect("notify::icon-name", self.on_icon_name_changed) diff --git a/test-scripts/xapp-status-icon-variants/xapp-status-icon-all-menus b/test-scripts/xapp-status-icon-variants/xapp-status-icon-all-menus index a1aa183..5202827 100755 --- a/test-scripts/xapp-status-icon-variants/xapp-status-icon-all-menus +++ b/test-scripts/xapp-status-icon-variants/xapp-status-icon-all-menus @@ -22,6 +22,8 @@ self.status_icon.set_tooltip_text("Testing primary and secondary menus") self.status_icon.set_label("label 1") self.status_icon.set_visible(True) + self.status_icon.set_metadata(' { "highlight-both-menus": true } ') + self.status_icon.connect("scroll-event", self.handle_scroll_event) self.counter = 1 diff --git a/xapp-sn-watcher/sn-item.c b/xapp-sn-watcher/sn-item.c index fc6033b..bf6b227 100644 --- a/xapp-sn-watcher/sn-item.c +++ b/xapp-sn-watcher/sn-item.c @@ -588,22 +588,6 @@ { g_autoptr(GVariant) tt_var; - if (item->is_ai) - { - gchar *text; - - text = get_string_property (item, "XAyatanaLabel"); - - if (text) - { - xapp_status_icon_set_tooltip_text (item->status_icon, text); - g_debug ("Tooltip text from XAyatanaLabel: %s", text); - - g_free (text); - return; - } - } - tt_var = get_property (item, "ToolTip"); if (tt_var) @@ -725,8 +709,7 @@ update_menu (item); } else - if (g_strcmp0 (signal_name, "XAyatanaNewLabel") || - g_strcmp0 (signal_name, "NewToolTip") || + if (g_strcmp0 (signal_name, "NewToolTip") || g_strcmp0 (signal_name, "NewTitle")) { update_tooltip (item); @@ -856,6 +839,7 @@ { SnItem *item = SN_ITEM (user_data); GError *error = NULL; + gchar *json = NULL; item->prop_proxy = g_dbus_proxy_new_finish (res, &error); @@ -872,6 +856,10 @@ item); item->status_icon = xapp_status_icon_new (); + + json = g_strdup_printf ("{ 'highlight-both-menus': %s }", item->is_ai ? "true" : "false"); + xapp_status_icon_set_metadata (item->status_icon, json); + g_free (json); g_signal_connect (item->status_icon, "activate", G_CALLBACK (xapp_icon_activated), item); g_signal_connect (item->status_icon, "button-press-event", G_CALLBACK (xapp_icon_button_press), item); diff --git a/xapp-sn-watcher/sn-item.xml b/xapp-sn-watcher/sn-item.xml index 4749320..1aaa609 100644 --- a/xapp-sn-watcher/sn-item.xml +++ b/xapp-sn-watcher/sn-item.xml @@ -71,13 +71,13 @@ - + diff --git a/xapp-sn-watcher/xapp-sn-watcher.c b/xapp-sn-watcher/xapp-sn-watcher.c index 167d86c..2c21eed 100644 --- a/xapp-sn-watcher/xapp-sn-watcher.c +++ b/xapp-sn-watcher/xapp-sn-watcher.c @@ -507,14 +507,13 @@ watcher->name_listener_id = 0; } + update_published_items (watcher); g_clear_pointer (&watcher->items, g_hash_table_unref); sn_watcher_interface_set_is_status_notifier_host_registered (watcher->skeleton, FALSE); g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (watcher->skeleton)); sn_watcher_interface_emit_status_notifier_host_registered (watcher->skeleton); - - update_published_items (watcher); if (watcher->owner_id > 0) {