Skip to content

Commit 8c0d76b

Browse files
committed
status icon: Add support for scroll events
ref: linuxmint/cinnamon#9152
1 parent 0eb8978 commit 8c0d76b

12 files changed

Lines changed: 248 additions & 4 deletions

libxapp/meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ libxapp_dep = declare_dependency(
137137
gir = gnome.generate_gir(libxapp,
138138
namespace: 'XApp',
139139
nsversion: '1.0',
140-
sources: xapp_headers + xapp_sources + dbus_headers,
140+
sources: xapp_headers + xapp_sources + dbus_headers + xapp_enums,
141141
identifier_prefix: 'XApp',
142142
symbol_prefix: 'xapp_',
143143
includes: ['GObject-2.0', 'Gtk-3.0'],

libxapp/org.x.StatusIcon.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
<arg name='time' direction='in' type='u'/>
1818
<arg name='panel_position' direction='in' type='i'/>
1919
</method>
20+
<method name='Scroll'>
21+
<arg name='delta' direction='in' type='i'/>
22+
<arg name='orientation' direction='in' type='i'/>
23+
<arg name='time' direction='in' type='u'/>
24+
</method>
2025
<property type='s' name='Name' access='read'/>
2126
<property type='s' name='IconName' access='read'/>
2227
<property type='s' name='TooltipText' access='read'/>

libxapp/xapp-status-icon.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum
3737
BUTTON_RELEASE,
3838
ACTIVATE,
3939
STATE_CHANGED,
40+
SCROLL,
4041
LAST_SIGNAL
4142
};
4243

@@ -163,6 +164,24 @@ state_to_str (XAppStatusIconState state)
163164
}
164165
}
165166

167+
static const gchar *
168+
direction_to_str (XAppScrollDirection direction)
169+
{
170+
switch (direction)
171+
{
172+
case XAPP_SCROLL_UP:
173+
return "Up";
174+
case XAPP_SCROLL_DOWN:
175+
return "Down";
176+
case XAPP_SCROLL_LEFT:
177+
return "Left";
178+
case XAPP_SCROLL_RIGHT:
179+
return "Right";
180+
default:
181+
return "Unknown";
182+
}
183+
}
184+
166185
static gint
167186
adjust_y_for_monitor_bounds (gint init_x,
168187
gint init_y,
@@ -438,6 +457,30 @@ handle_click_method (XAppStatusIconInterface *skeleton,
438457
return TRUE;
439458
}
440459

460+
static gboolean
461+
handle_scroll_method (XAppStatusIconInterface *skeleton,
462+
GDBusMethodInvocation *invocation,
463+
gint delta,
464+
XAppScrollDirection direction,
465+
guint _time,
466+
XAppStatusIcon *icon)
467+
{
468+
g_debug ("XAppStatusIcon: received Scroll from monitor %s: "
469+
"delta: %d , direction: %s , time: %u",
470+
g_dbus_method_invocation_get_sender (invocation),
471+
delta, direction_to_str (direction), _time);
472+
473+
g_signal_emit(icon, signals[SCROLL], 0,
474+
delta,
475+
direction,
476+
_time);
477+
478+
xapp_status_icon_interface_complete_scroll (skeleton,
479+
invocation);
480+
481+
return TRUE;
482+
}
483+
441484
static void
442485
popup_gtk_status_icon_with_menu (XAppStatusIcon *icon,
443486
GtkMenu *menu,
@@ -724,7 +767,8 @@ typedef struct
724767
static SkeletonSignal skeleton_signals[] = {
725768
// signal name callback
726769
{ "handle-button-press", handle_click_method },
727-
{ "handle-button-release", handle_click_method }
770+
{ "handle-button-release", handle_click_method },
771+
{ "handle-scroll", handle_scroll_method }
728772
};
729773

730774
static gboolean
@@ -1344,6 +1388,25 @@ xapp_status_icon_class_init (XAppStatusIconClass *klass)
13441388
0,
13451389
NULL, NULL, NULL,
13461390
G_TYPE_NONE, 1, XAPP_TYPE_STATUS_ICON_STATE);
1391+
1392+
/**
1393+
* XAppStatusIcon::scroll-event:
1394+
* @icon: The #XAppStatusIcon
1395+
* @amount: The amount of movement for the scroll event
1396+
* @direction: the #XAppScrollDirection of the scroll event
1397+
* @time: The time supplied by the event, or 0
1398+
*
1399+
* Gets emitted when the user uses the mouse scroll wheel over the status icon.
1400+
* For the most part, amounts will always be 1, unless an applet supports smooth
1401+
* scrolling. Generally the direction value is most important.
1402+
*/
1403+
signals [SCROLL] =
1404+
g_signal_new ("scroll-event",
1405+
XAPP_TYPE_STATUS_ICON,
1406+
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
1407+
0,
1408+
NULL, NULL, NULL,
1409+
G_TYPE_NONE, 3, G_TYPE_INT, XAPP_TYPE_SCROLL_DIRECTION, G_TYPE_UINT);
13471410
}
13481411

13491412
/**

libxapp/xapp-status-icon.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,24 @@ typedef enum
2828
XAPP_STATUS_ICON_STATE_NO_SUPPORT
2929
} XAppStatusIconState;
3030

31+
/**
32+
* XAppScrollDirection:
33+
* @XAPP_SCROLL_UP: Scroll theoretical content up.
34+
* @XAPP_SCROLL_DOWN: Scroll theoretical content down.
35+
* @XAPP_SCROLL_LEFT: Scroll theoretical content left.
36+
* @XAPP_SCROLL_RIGHT: Scroll theoretical content right.
37+
*
38+
* Represents the direction of icon scroll events.
39+
*/
40+
typedef enum
41+
{
42+
XAPP_SCROLL_UP,
43+
XAPP_SCROLL_DOWN,
44+
XAPP_SCROLL_LEFT,
45+
XAPP_SCROLL_RIGHT
46+
} XAppScrollDirection;
47+
48+
3149
XAppStatusIcon *xapp_status_icon_new (void);
3250
void xapp_status_icon_set_name (XAppStatusIcon *icon, const gchar *name);
3351
void xapp_status_icon_set_icon_name (XAppStatusIcon *icon, const gchar *icon_name);

status-applets/mate/mate-xapp-status-applet.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ def __init__(self, icon, orientation, size):
6767
# this is the bus owned name
6868
self.name = self.proxy.get_name()
6969

70+
self.add_events(Gdk.EventMask.SCROLL_MASK)
71+
7072
# this is (usually) the name of the remote process
7173
self.proc_name = self.proxy.props.name
7274

@@ -99,6 +101,7 @@ def __init__(self, icon, orientation, size):
99101

100102
self.connect("button-press-event", self.on_button_press)
101103
self.connect("button-release-event", self.on_button_release)
104+
self.connect("scroll-event", self.on_scroll)
102105
self.connect("enter-notify-event", self.on_enter_notify)
103106
self.connect("leave-notify-event", self.on_leave_notify)
104107

@@ -219,6 +222,26 @@ def on_button_release(self, widget, event):
219222

220223
return Gdk.EVENT_PROPAGATE
221224

225+
def on_scroll(self, widget, event):
226+
has, direction = event.get_scroll_direction()
227+
228+
x_dir = XApp.ScrollDirection.UP
229+
delta = 0
230+
231+
if direction != Gdk.ScrollDirection.SMOOTH:
232+
x_dir = XApp.ScrollDirection(int(direction))
233+
234+
if direction == Gdk.ScrollDirection.UP:
235+
delta = -1
236+
elif direction == Gdk.ScrollDirection.DOWN:
237+
delta = 1
238+
elif direction == Gdk.ScrollDirection.LEFT:
239+
delta = -1
240+
elif direction == Gdk.ScrollDirection.RIGHT:
241+
delta = 1
242+
243+
self.proxy.call_scroll_sync(delta, x_dir, event.time, None)
244+
222245
def calc_menu_origin(self, widget, orientation):
223246
alloc = widget.get_allocation()
224247
ignore, x, y = widget.get_window().get_origin()

test-scripts/xapp-status-applet

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import gi
33
gi.require_version('Gtk', '3.0')
44
gi.require_version('XApp', '1.0')
5-
from gi.repository import Gio, GLib, GObject, Gtk, XApp
5+
from gi.repository import Gio, GLib, GObject, Gtk, XApp, Gdk
66
import os
77
import sys
88

@@ -16,6 +16,7 @@ class StatusWidget(Gtk.Button):
1616

1717
self.proxy = icon
1818
self.name = self.proxy.get_name()
19+
self.add_events(Gdk.EventMask.SCROLL_MASK)
1920

2021
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
2122

@@ -40,6 +41,7 @@ class StatusWidget(Gtk.Button):
4041

4142
self.connect("button-press-event", self.on_button_press)
4243
self.connect("button-release-event", self.on_button_release)
44+
self.connect("scroll-event", self.on_scroll)
4345

4446
def on_icon_name_changed(self, proxy, gparamspec, data=None):
4547
string = self.proxy.props.icon_name
@@ -77,6 +79,27 @@ class StatusWidget(Gtk.Button):
7779
print ("Button release : %d:%d" % (x, y))
7880
self.proxy.call_button_release_sync(x, y, event.button, event.time, Gtk.PositionType.TOP, None)
7981

82+
def on_scroll(self, widget, event):
83+
has, direction = event.get_scroll_direction()
84+
85+
x_dir = XApp.ScrollDirection.UP
86+
delta = 0
87+
88+
if direction != Gdk.ScrollDirection.SMOOTH:
89+
x_dir = XApp.ScrollDirection(int(direction))
90+
91+
if direction == Gdk.ScrollDirection.UP:
92+
delta = -1
93+
elif direction == Gdk.ScrollDirection.DOWN:
94+
delta = 1
95+
elif direction == Gdk.ScrollDirection.LEFT:
96+
delta = -1
97+
elif direction == Gdk.ScrollDirection.RIGHT:
98+
delta = 1
99+
100+
print ("Scroll : delta: %d, orientation: %d" % (delta, x_dir))
101+
self.proxy.call_scroll_sync(delta, x_dir, event.time, None)
102+
80103
class StatusApplet(GObject.Object):
81104

82105
def __init__(self):

test-scripts/xapp-status-icon-variants/xapp-status-icon-activate-and-menu

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class App(GObject.Object):
2222
self.status_icon.set_tooltip_text("Testing primary activate and secondary menu")
2323
self.status_icon.set_label("label 1")
2424
self.status_icon.set_visible(True)
25+
self.status_icon.connect("scroll-event", self.handle_scroll_event)
26+
27+
self.label = None
28+
self.window = None
2529

2630
self.counter = 1
2731

@@ -48,6 +52,31 @@ class App(GObject.Object):
4852
print("Activated via button %d" % button)
4953
self.counter = 0
5054
self.status_icon.set_label("label %d" % self.counter)
55+
self.make_window()
56+
57+
def make_window(self):
58+
w = Gtk.Window(default_width=300, default_height=130)
59+
b = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
60+
w.add(b)
61+
self.label = Gtk.Label("How can I help you?")
62+
b.pack_start(self.label, True, True, 0)
63+
64+
self.window = w
65+
w.show_all()
66+
67+
def handle_scroll_event(self, icon, amount, orientation, time, data=None):
68+
if self.window == None:
69+
self.make_window()
70+
71+
if orientation == XApp.ScrollDirection.UP:
72+
self.label.set_text("Scrolled Up !")
73+
elif orientation == XApp.ScrollDirection.DOWN:
74+
self.label.set_text("Scrolled Down!")
75+
elif orientation == XApp.ScrollDirection.LEFT:
76+
self.label.set_text("Scrolled Left!")
77+
else:
78+
self.label.set_text("Scrolled Right!")
79+
5180

5281
if __name__ == '__main__':
5382
GLib.setenv ("G_MESSAGES_DEBUG", "all", True)

test-scripts/xapp-status-icon-variants/xapp-status-icon-ai

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ sets both primary and secondary menus on the XAppStatusIcon.
1717
class App(GObject.Object):
1818
def __init__(self):
1919
super(App, self).__init__()
20+
self.window = None
21+
2022
self.indicator = AppIndicator3.Indicator.new("xapp-status-icon-via-libappindicator",
2123
"info",
2224
AppIndicator3.IndicatorCategory.SYSTEM_SERVICES)
@@ -39,15 +41,32 @@ class App(GObject.Object):
3941

4042
self.indicator.set_menu(self.menu)
4143

44+
self.indicator.connect("scroll-event", self.handle_scroll_event)
4245
GLib.timeout_add_seconds(2, self.on_timeout_cb)
4346

4447
def activate_window(self, item, data=None):
4548
w = Gtk.Window(default_width=300, default_height=130)
4649
b = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
4750
w.add(b)
48-
b.pack_start(Gtk.Label("How can I help you?"), True, True, 0)
51+
self.label = Gtk.Label("How can I help you?")
52+
b.pack_start(self.label, True, True, 0)
53+
54+
self.window = w
4955
w.show_all()
5056

57+
def handle_scroll_event(self, icon, amount, direction, data=None):
58+
if self.window == None:
59+
self.activate_window(None)
60+
61+
if direction == Gdk.ScrollDirection.UP:
62+
self.label.set_text("Scrolled Up!")
63+
elif direction == Gdk.ScrollDirection.DOWN:
64+
self.label.set_text("Scrolled Down!")
65+
elif direction == Gdk.ScrollDirection.LEFT:
66+
self.label.set_text("Scrolled Left!")
67+
else:
68+
self.label.set_text("Scrolled Right!")
69+
5170
def on_timeout_cb(self):
5271
self.counter += 1
5372
self.indicator.set_label("AppIndicator3 %d" % self.counter, "AppIndicator3 1000")

test-scripts/xapp-status-icon-variants/xapp-status-icon-all-menus

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@ class App(GObject.Object):
2222
self.status_icon.set_tooltip_text("Testing primary and secondary menus")
2323
self.status_icon.set_label("label 1")
2424
self.status_icon.set_visible(True)
25+
self.status_icon.connect("scroll-event", self.handle_scroll_event)
2526

2627
self.counter = 1
2728

29+
self.label = None
30+
self.window = None
31+
2832
menu = Gtk.Menu()
2933
menu.append(Gtk.MenuItem.new_with_label("Engage the hyperdrive"))
3034
menu.append(Gtk.SeparatorMenuItem())
@@ -51,6 +55,29 @@ class App(GObject.Object):
5155
self.status_icon.set_label("label %d" % self.counter)
5256
return True
5357

58+
def make_window(self):
59+
w = Gtk.Window(default_width=300, default_height=130)
60+
b = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
61+
w.add(b)
62+
self.label = Gtk.Label("How can I help you?")
63+
b.pack_start(self.label, True, True, 0)
64+
65+
self.window = w
66+
w.show_all()
67+
68+
def handle_scroll_event(self, icon, amount, orientation, time, data=None):
69+
if self.window == None:
70+
self.make_window()
71+
72+
if orientation == XApp.ScrollDirection.UP:
73+
self.label.set_text("Scrolled Up !")
74+
elif orientation == XApp.ScrollDirection.DOWN:
75+
self.label.set_text("Scrolled Down!")
76+
elif orientation == XApp.ScrollDirection.LEFT:
77+
self.label.set_text("Scrolled Left!")
78+
else:
79+
self.label.set_text("Scrolled Right!")
80+
5481
if __name__ == '__main__':
5582
GLib.setenv ("G_MESSAGES_DEBUG", "all", True)
5683
app = App()

0 commit comments

Comments
 (0)