Codebase list xapp / 768bdfd
xapp-status-icon: When a menu is provided to XAppStatusIcon, handle positioning and showing it internally instead of requiring the application to do it. - Set up the popup-menu and activate signals as well. Michael Webster 4 years ago
2 changed file(s) with 231 addition(s) and 55 deletion(s). Raw diff Collapse all Expand all
3636
3737 static guint signals[LAST_SIGNAL] = {0, };
3838
39 enum
40 {
41 PROP_0,
42 PROP_MENU,
43 N_PROPERTIES
44 };
45
3946 /**
4047 * SECTION:xapp-status-icon
4148 * @Short_description: Broadcasts status information over DBUS
4653 * Gtk.StatusIcon widget.
4754 *
4855 * If used in an environment where no applet is handling XAppStatusIcons,
49 * The XAppStatusIcon delegates its calls to a Gtk.StatusIcon.
56 * the XAppStatusIcon delegates its calls to a Gtk.StatusIcon.
5057 */
5158 struct _XAppStatusIconPrivate
5259 {
102109 }
103110 }
104111
112 typedef struct {
113 gint x;
114 gint y;
115 gint position;
116 guint32 t;
117 } PositionData;
118
119 static void
120 position_menu_cb (GtkMenu *menu,
121 gint *x,
122 gint *y,
123 gboolean *push_in,
124 gpointer user_data)
125 {
126 GtkAllocation alloc;
127 PositionData *position_data = (PositionData *) user_data;
128
129 *x = position_data->x;
130 *y = position_data->y;
131
132 gtk_widget_get_allocation (GTK_WIDGET (menu), &alloc);
133
134 switch (position_data->position) {
135 case GTK_POS_BOTTOM:
136 *y = *y - alloc.height;
137 break;
138 case GTK_POS_RIGHT:
139 *x = *x - alloc.width;
140 break;
141 }
142
143 *push_in = TRUE;
144 }
145
146 static void
147 popup_native_icon_menu (XAppStatusIcon *self,
148 gint x,
149 gint y,
150 guint button,
151 guint _time,
152 gint panel_position)
153 {
154 GdkDisplay *display;
155 GdkDevice *pointer;
156
157 g_debug ("XAppStatusIcon: Popup menu on behalf of application");
158
159 PositionData position_data = {
160 x, y, panel_position, _time
161 };
162
163 display = gdk_display_get_default ();
164 pointer = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
165
166 gtk_menu_popup_for_device (GTK_MENU (self->priv->menu),
167 pointer,
168 NULL,
169 NULL,
170 position_menu_cb,
171 &position_data,
172 NULL,
173 button,
174 _time);
175 }
176
105177 static gboolean
106178 handle_click_method (XAppStatusIconInterface *skeleton,
107179 GDBusMethodInvocation *invocation,
123195
124196 g_signal_emit (icon, signals[BUTTON_PRESS], 0, x, y, button, _time, panel_position);
125197
198 if (button == GDK_BUTTON_PRIMARY)
199 {
200 g_signal_emit (icon, signals[ACTIVATE], 0);
201 }
202
126203 xapp_status_icon_interface_complete_button_press (skeleton,
127204 invocation);
128205 }
135212 x, y, button, _time, panel_position_to_str (panel_position));
136213
137214 g_signal_emit (icon, signals[BUTTON_RELEASE], 0, x, y, button, _time, panel_position);
215
216 if (button == GDK_BUTTON_SECONDARY)
217 {
218 if (icon->priv->menu)
219 {
220 popup_native_icon_menu (icon, x, y, button, _time, panel_position);
221 }
222 else
223 {
224 g_signal_emit (icon, signals[POPUP_MENU], 0, x, y, button, _time, panel_position);
225 }
226 }
138227
139228 xapp_status_icon_interface_complete_button_release (skeleton,
140229 invocation);
199288 {
200289 g_debug ("XAppStatusIcon: GtkStatusIcon popup menu with NO menu provided");
201290
202 /* No menu provided, do our best to pass along good position info the app or appindicator
203 * (if they're not using patched appindicator) */
291 /* No menu provided, do our best to pass along good position info to the app
292 * or appindicator (if they're not using patched appindicator). */
204293 GdkScreen *screen;
205294 GdkRectangle irect;
206295 GtkOrientation orientation;
609698 }
610699
611700 static void
701 xapp_status_icon_set_property (GObject *object,
702 guint prop_id,
703 const GValue *value,
704 GParamSpec *pspec)
705 {
706 switch (prop_id)
707 {
708 case PROP_MENU:
709 xapp_status_icon_set_menu (XAPP_STATUS_ICON (object), g_value_get_object (value));
710 break;
711 default:
712 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
713 break;
714 }
715 }
716
717 static void
718 xapp_status_icon_get_property (GObject *object,
719 guint prop_id,
720 GValue *value,
721 GParamSpec *pspec)
722 {
723 XAppStatusIcon *icon = XAPP_STATUS_ICON (object);
724
725 switch (prop_id)
726 {
727 case PROP_MENU:
728 g_value_set_object (value, icon->priv->menu);
729 break;
730 default:
731 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
732 break;
733 }
734 }
735
736 static void
612737 xapp_status_icon_init (XAppStatusIcon *self)
613738 {
614739 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, XAPP_TYPE_STATUS_ICON, XAppStatusIconPrivate);
693818
694819 gobject_class->dispose = xapp_status_icon_dispose;
695820 gobject_class->finalize = xapp_status_icon_finalize;
821 gobject_class->set_property = xapp_status_icon_set_property;
822 gobject_class->get_property = xapp_status_icon_get_property;
696823
697824 g_type_class_add_private (gobject_class, sizeof (XAppStatusIconPrivate));
698825
699 /**
700 * XAppStatusIcon::button-press-event:
701 * @icon: The #XAppStatusIcon
702 * @x: The absolute x position to use for menu positioning
703 * @y: The absolute y position to use for menu positioning
704 * @button: The button that was pressed
705 * @time: The time supplied by the event, or 0
706 * @panel_position: The #GtkPositionType to use for menu positioning
707 *
708 * Gets emitted when there is a button press received from an applet
709 */
826 /**
827 * XAppStatusIcon:menu:
828 *
829 * A #GtkMenu to use when requested by the remote monitor.
830 *
831 * When this property is not %NULL, it is not necessary for the application
832 * to connect to the #XAppStatusIcon::button-release-event signal, and the
833 * #XAppStatusIcon::popup-menu signal will not be emitted. All menu positioning
834 * will be handled internally by #XAppStatusIcon.
835 *
836 * Setting this will remove any floating reference to the menu and assume ownership.
837 * As a result, it is not necessary to maintain a reference to it in the parent
838 * application (or unref it when finished with it - if you wish to replace the menu,
839 * simply call this method again with a new menu.
840 */
841 g_object_class_install_property (gobject_class, PROP_MENU,
842 g_param_spec_object ("menu",
843 "Status icon menu",
844 "The menu to use when the status icon is remotely requested",
845 GTK_TYPE_WIDGET,
846 G_PARAM_READWRITE));
847
848 /**
849 * XAppStatusIcon::button-press-event:
850 * @icon: The #XAppStatusIcon
851 * @x: The absolute x position to use for menu positioning
852 * @y: The absolute y position to use for menu positioning
853 * @button: The button that was pressed
854 * @time: The time supplied by the event, or 0
855 * @panel_position: The #GtkPositionType to use for menu positioning
856 *
857 * Gets emitted when there is a button press received from an applet
858 */
710859 signals[BUTTON_PRESS] =
711860 g_signal_new ("button-press-event",
712861 XAPP_TYPE_STATUS_ICON,
715864 NULL, NULL, NULL,
716865 G_TYPE_NONE, 5, G_TYPE_INT, G_TYPE_INT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT);
717866
718 /**
719 * XAppStatusIcon::button-release-event:
720 * @icon: The #XAppStatusIcon
721 * @x: The absolute x position to use for menu positioning
722 * @y: The absolute y position to use for menu positioning
723 * @button: The button that was released
724 * @time: The time supplied by the event, or 0
725 * @panel_position: The #GtkPositionType to use for menu positioning
726 *
727 * Gets emitted when there is a button release received from an applet
728 */
867 /**
868 * XAppStatusIcon::button-release-event:
869 * @icon: The #XAppStatusIcon
870 * @x: The absolute x position to use for menu positioning
871 * @y: The absolute y position to use for menu positioning
872 * @button: The button that was released
873 * @time: The time supplied by the event, or 0
874 * @panel_position: The #GtkPositionType to use for menu positioning
875 *
876 * Gets emitted when there is a button release received from an applet
877 */
729878 signals[BUTTON_RELEASE] =
730879 g_signal_new ("button-release-event",
731880 XAPP_TYPE_STATUS_ICON,
734883 NULL, NULL, NULL,
735884 G_TYPE_NONE, 5, G_TYPE_INT, G_TYPE_INT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT);
736885
737 /**
738 * XAppStatusIcon::activate:
739 * @icon: The #XAppStatusIcon
740 *
741 * Gets emitted when the user activates the status icon.
742 */
886 /**
887 * XAppStatusIcon::activate:
888 * @icon: The #XAppStatusIcon
889 *
890 * Gets emitted when the user activates (left-click) the status icon.
891 */
743892 signals [ACTIVATE] =
744893 g_signal_new ("activate",
745894 XAPP_TYPE_STATUS_ICON,
749898 G_TYPE_NONE,
750899 0);
751900
752 /**
753 * XAppStatusIcon::popup-menu:
754 * @icon: the #XAppStatusIcon
755 * @button: the button that was pressed, or 0 if the
756 * signal is not emitted in response to a button press event
757 * @activate_time: the timestamp of the event that
758 * triggered the signal emission
759 *
760 * Gets emitted when the user brings up the context menu
761 * of the status icon.
762 *
763 */
901 /**
902 * XAppStatusIcon::popup-menu:
903 * @icon: the #XAppStatusIcon
904 * @x: The absolute x position to use for menu positioning
905 * @y: The absolute y position to use for menu positioning
906 * @button: The button that was released
907 * @time: The time supplied by the event, or 0
908 * @panel_position: The #GtkPositionType to use for menu positioning
909 *
910 * Gets emitted when a right-click is performed on a button-release-
911 * event.
912 *
913 */
764914 signals [POPUP_MENU] =
765915 g_signal_new ("popup-menu",
766916 XAPP_TYPE_STATUS_ICON,
767917 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
768918 0,
769919 NULL, NULL, NULL,
770 G_TYPE_NONE,
771 2,
772 G_TYPE_UINT,
773 G_TYPE_UINT);
920 G_TYPE_NONE, 5, G_TYPE_INT, G_TYPE_INT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT);
774921 }
775922
776923 /**
778925 * @icon: a #XAppStatusIcon
779926 * @name: a name (this defaults to the name of the application, if not set)
780927 *
781 * Sets the status icon name. This is now shown to users.
928 * Sets the status icon name. This is not shown to users.
782929 *
783930 * Since: 1.6
784931 */
807954 * @icon: a #XAppStatusIcon
808955 * @icon_name: An icon name or absolute path to an icon.
809956 *
810 * Sets the icon name or icon filename to use.
957 * Sets the icon name or local path to use.
811958 *
812959 * Since: 1.6
813960 */
9151062 /**
9161063 * xapp_status_icon_set_menu:
9171064 * @icon: a #XAppStatusIcon
918 * @menu: A #GtkMenu to display when requested
919 *
920 * Sets a menu that will be used when requested.
1065 * @menu: (nullable): A #GtkMenu to display when requested
1066 *
1067 * See the #XAppStatusIcon:menu property for details
9211068 *
9221069 * Since: 1.6
9231070 */
9281075 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
9291076
9301077 g_clear_object (&icon->priv->menu);
931 icon->priv->menu = GTK_WIDGET (g_object_ref (menu));
1078
1079 if (menu)
1080 {
1081 icon->priv->menu = GTK_WIDGET (g_object_ref_sink (menu));
1082 }
1083 }
1084
1085 /**
1086 * xapp_status_icon_get_menu:
1087 * @icon: a #XAppStatusIcon
1088 *
1089 * Returns a pointer to a #GtkMenu that was set previously. If
1090 * no menu was set, this returns %NULL.
1091 *
1092 * Returns: (transfer none): the #GtkMenu or %NULL if none was set.
1093
1094 * Since: 1.6
1095 */
1096 void
1097 xapp_status_icon_get_menu (XAppStatusIcon *icon,
1098 GtkMenu *menu)
1099 {
1100 g_return_if_fail (XAPP_IS_STATUS_ICON (icon));
1101
1102 g_clear_object (&icon->priv->menu);
1103 icon->priv->menu = GTK_WIDGET (g_object_ref_sink (menu));
9321104 }
9331105
9341106 /**
1717 self.status_icon.set_visible(True)
1818
1919 self.counter = 1
20 self.status_icon.connect("button-press-event", self.on_button_press)
21 self.status_icon.connect("button-release-event", self.on_button_release)
2220
2321 self.menu = Gtk.Menu()
2422 self.menu.append(Gtk.MenuItem.new_with_label("Engage the hyperdrive"))
2624 self.menu.append(Gtk.MenuItem.new_with_label("It's a trap!"))
2725 self.menu.show_all()
2826
27 self.status_icon.connect("button-press-event", self.on_button_press)
28
29 # button-release is not needed when using set_menu. Comment one and uncomment
30 # the other if you want to test the other behavior.
31
32 # self.status_icon.connect("button-release-event", self.on_button_release)
2933 self.status_icon.set_menu(self.menu)
3034
3135 GLib.timeout_add_seconds(2, self.on_timeout_cb)