diff --git a/Makefile.am b/Makefile.am index 4d6f5ec..009109b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,7 @@ SUBDIRS = libxapp po schemas files docs +if ENABLE_PYTHON +SUBDIRS += pygobject +endif ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} diff --git a/configure.ac b/configure.ac index f642342..a726d10 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT(xapp, 1.0.3) +AC_INIT(xapp, 1.0.4) AC_CONFIG_SRCDIR(libxapp) m4_ifdef([AX_IS_RELEASE], [AX_IS_RELEASE([always])]) @@ -97,10 +97,26 @@ GOBJECT_INTROSPECTION_CHECK([0.9.7]) +CFLAGS="$CFLAGS -Wno-declaration-after-statement" + +# Python support + +PYGOBJECT_REQUIRED=2.90 + +PKG_CHECK_EXISTS([pygobject-3.0 >= $PYGOBJECT_REQUIRED], + [have_python=yes], [have_python=no]) + +AS_IF([test "x$have_python" = "xyes"], + [AM_PATH_PYTHON + AC_SUBST([pyoverridesdir], [`$PYTHON -c "import gi;print (gi._overridesdir)" 2>/dev/null`])]) + +AM_CONDITIONAL([ENABLE_PYTHON], [test "x$have_python" = "xyes"]) + AC_CONFIG_FILES([ Makefile docs/Makefile docs/reference/Makefile +pygobject/Makefile libxapp/Makefile libxapp/xapp.pc libxapp/xapp-uninstalled.pc diff --git a/docs/reference/xapp-docs.xml b/docs/reference/xapp-docs.xml index 32b0171..daa1627 100644 --- a/docs/reference/xapp-docs.xml +++ b/docs/reference/xapp-docs.xml @@ -8,7 +8,7 @@ ]> - Xapp Reference Manual + XApp Reference Manual for &package_string;. @@ -16,8 +16,9 @@ API reference - + + diff --git a/files/usr/share/vala/vapi/xapp.vapi b/files/usr/share/vala/vapi/xapp.vapi new file mode 100644 index 0000000..893be7c --- /dev/null +++ b/files/usr/share/vala/vapi/xapp.vapi @@ -0,0 +1,90 @@ +/* xapp.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "XApp", gir_namespace = "XApp", gir_version = "1.0", lower_case_cprefix = "xapp__")] +namespace XApp { + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", type_id = "xapp_gtk_window_get_type ()")] + public class GtkWindow : Gtk.Window, Atk.Implementor, Gtk.Buildable { + [CCode (cname = "xapp_gtk_window_new", has_construct_function = false, type = "GtkWidget*")] + public GtkWindow (Gtk.WindowType type); + [CCode (cname = "xapp_gtk_window_set_icon_from_file")] + public void set_icon_from_file (string? file_name) throws GLib.Error; + [CCode (cname = "xapp_gtk_window_set_icon_name")] + public void set_icon_name (string? icon_name); + [CCode (cname = "xapp_gtk_window_set_progress")] + public void set_progress (int progress); + [CCode (cname = "xapp_gtk_window_set_progress_pulse")] + public void set_progress_pulse (bool pulse); + } + [CCode (cheader_filename = "libxapp/xapp-kbd-layout-controller.h", type_id = "xapp_kbd_layout_controller_get_type ()")] + public class KbdLayoutController : GLib.Object { + [CCode (cname = "xapp_kbd_layout_controller_new", has_construct_function = false)] + public KbdLayoutController (); + [CCode (array_length = false, array_null_terminated = true, cname = "xapp_kbd_layout_controller_get_all_names")] + public unowned string[] get_all_names (); + [CCode (cname = "xapp_kbd_layout_controller_get_current_flag_id")] + public int get_current_flag_id (); + [CCode (cname = "xapp_kbd_layout_controller_get_current_group")] + public uint get_current_group (); + [CCode (cname = "xapp_kbd_layout_controller_get_current_icon_name")] + public string get_current_icon_name (); + [CCode (cname = "xapp_kbd_layout_controller_get_current_name")] + public string get_current_name (); + [CCode (cname = "xapp_kbd_layout_controller_get_current_short_group_label")] + public string get_current_short_group_label (); + [CCode (cname = "xapp_kbd_layout_controller_get_current_variant_label")] + public string get_current_variant_label (); + [CCode (cname = "xapp_kbd_layout_controller_get_enabled")] + public bool get_enabled (); + [CCode (cname = "xapp_kbd_layout_controller_get_flag_id_for_group")] + public int get_flag_id_for_group (uint group); + [CCode (cname = "xapp_kbd_layout_controller_get_icon_name_for_group")] + public string get_icon_name_for_group (uint group); + [CCode (cname = "xapp_kbd_layout_controller_get_short_group_label_for_group")] + public string get_short_group_label_for_group (uint group); + [CCode (cname = "xapp_kbd_layout_controller_get_variant_label_for_group")] + public string get_variant_label_for_group (uint group); + [CCode (cname = "xapp_kbd_layout_controller_next_group")] + public void next_group (); + [CCode (cname = "xapp_kbd_layout_controller_previous_group")] + public void previous_group (); + [CCode (cname = "xapp_kbd_layout_controller_render_cairo_subscript")] + public static void render_cairo_subscript (Cairo.Context cr, double x, double y, double width, double height, int subscript); + [CCode (cname = "xapp_kbd_layout_controller_set_current_group")] + public void set_current_group (uint group); + [NoAccessorMethod] + public bool enabled { get; } + public signal void config_changed (); + public signal void layout_changed (uint object); + } + [CCode (cheader_filename = "libxapp/xapp-monitor-blanker.h", type_id = "xapp_monitor_blanker_get_type ()")] + public class MonitorBlanker : GLib.Object { + [CCode (cname = "xapp_monitor_blanker_new", has_construct_function = false)] + public MonitorBlanker (); + [CCode (cname = "xapp_monitor_blanker_are_monitors_blanked")] + public bool are_monitors_blanked (); + [CCode (cname = "xapp_monitor_blanker_blank_other_monitors")] + public void blank_other_monitors (Gtk.Window window); + [CCode (cname = "xapp_monitor_blanker_unblank_monitors")] + public void unblank_monitors (); + } + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h")] + [SimpleType] + public struct GtkWindow_autoptr { + } + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_window_icon_from_file")] + public static void set_window_icon_from_file (Gtk.Window window, string? file_name) throws GLib.Error; + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_window_icon_name")] + public static void set_window_icon_name (Gtk.Window window, string? icon_name); + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_window_progress")] + public static void set_window_progress (Gtk.Window window, int progress); + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_window_progress_pulse")] + public static void set_window_progress_pulse (Gtk.Window window, bool pulse); + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_xid_icon_from_file")] + public static void set_xid_icon_from_file (ulong xid, string? file_name); + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_xid_icon_name")] + public static void set_xid_icon_name (ulong xid, string? icon_name); + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_xid_progress")] + public static void set_xid_progress (ulong xid, int progress); + [CCode (cheader_filename = "libxapp/xapp-gtk-window.h", cname = "xapp_set_xid_progress_pulse")] + public static void set_xid_progress_pulse (ulong xid, bool pulse); +} diff --git a/libxapp/Makefile.am b/libxapp/Makefile.am index aeafbad..f2bd420 100644 --- a/libxapp/Makefile.am +++ b/libxapp/Makefile.am @@ -16,7 +16,9 @@ introspection_sources = \ xapp-monitor-blanker.c \ - xapp-kbd-layout-controller.c + xapp-kbd-layout-controller.c \ + xapp-gtk-window.c \ + xapp-glade-catalog.c libxapp_la_SOURCES = \ $(introspection_sources) @@ -35,10 +37,14 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = xapp.pc +catalogdir = $(prefix)/share/glade/catalogs/ +catalog_DATA = xapp-glade-catalog.xml + libxappdir = $(includedir)/xapp/libxapp libxapp_HEADERS = \ xapp-monitor-blanker.h \ - xapp-kbd-layout-controller.h + xapp-kbd-layout-controller.h \ + xapp-gtk-window.h -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = diff --git a/libxapp/xapp-glade-catalog.c b/libxapp/xapp-glade-catalog.c new file mode 100644 index 0000000..813ca48 --- /dev/null +++ b/libxapp/xapp-glade-catalog.c @@ -0,0 +1,13 @@ +#include "config.h" +#include + +#include "xapp-gtk-window.h" + +void +xapp_glade_catalog_init (const gchar *catalog_name); + +void +xapp_glade_catalog_init (const gchar *catalog_name) +{ + g_type_ensure (XAPP_TYPE_GTK_WINDOW); +} diff --git a/libxapp/xapp-glade-catalog.xml b/libxapp/xapp-glade-catalog.xml new file mode 100644 index 0000000..18f46c3 --- /dev/null +++ b/libxapp/xapp-glade-catalog.xml @@ -0,0 +1,12 @@ + + + xapp_glade_catalog_init + + + + + + + + diff --git a/libxapp/xapp-gtk-window.c b/libxapp/xapp-gtk-window.c new file mode 100644 index 0000000..800bd38 --- /dev/null +++ b/libxapp/xapp-gtk-window.c @@ -0,0 +1,755 @@ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "xapp-gtk-window.h" + +#define ICON_NAME_HINT "_NET_WM_XAPP_ICON_NAME" +#define PROGRESS_HINT "_NET_WM_XAPP_PROGRESS" +#define PROGRESS_PULSE_HINT "_NET_WM_XAPP_PROGRESS_PULSE" + +/** + * SECTION:xapp-gtk-window + * @Short_description: A subclass of %GtkWindow that allows additional + communication with the window manager. + * @Title: XAppGtkWindow + * + * This widget is a simple subclass of GtkWindow that provides the following + * additional capabilities: + * + * - Ability to set an icon name or icon file path for the window manager to + * make use of, rather than relying on a desktop file or fixed-size window- + * backed icon that Gtk normally generates. The window manager must support + * the NET_WM_XAPP_ICON_NAME hint. + * + * - Ability to send progress info to the window manager, in the form of an integer, + * 0-100, which can then be used to display this progress in some manner in a task + * manager or window list. The window manager must support the NET_WM_XAPP_PROGRESS + * hint. + * + * - Ability to signal a 'pulsing' progress state, of potentially indeterminate value, + * in the form of a boolean, which can be passed on to a window list. The window + * manager must support the NET_WM_XAPP_PROGRESS_PULSE hint + * + * Wrappers: + * + * Also provided are corresponding wrapper functions for normal GtkWindows. + * They are not class methods - they are called with the target widget as their first + * argument. + * + * For example: + * + * win = Gtk.Window() + * XApp.set_window_icon_name(win, "foobar") + * + * These functions mirror those of the #XAppGtkWindow class, but allow the properties + * to work with normal GtkWindows and descendants of GtkWindow. + */ + +typedef struct +{ + gchar *icon_name; + gchar *icon_path; + guint progress; + gboolean progress_pulse; +} XAppGtkWindowPrivate; + +struct _XAppGtkWindow +{ + GtkWindow parent_object; + + XAppGtkWindowPrivate *priv; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (XAppGtkWindow, xapp_gtk_window, GTK_TYPE_WINDOW) + +static void +clear_icon_strings (XAppGtkWindowPrivate *priv) +{ + g_clear_pointer (&priv->icon_name, g_free); + g_clear_pointer (&priv->icon_path, g_free); +} + +static void +set_window_hint_utf8 (Window xid, + const gchar *atom_name, + const gchar *str) +{ + GdkDisplay *display; + + display = gdk_display_get_default (); + + if (str != NULL) + { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + xid, + gdk_x11_get_xatom_by_name_for_display (display, atom_name), + gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8, + PropModeReplace, (guchar *) str, strlen (str)); + } + else + { + XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), + xid, + gdk_x11_get_xatom_by_name_for_display (display, atom_name)); + } +} + +static void +set_window_hint_cardinal (Window xid, + const gchar *atom_name, + gulong cardinal) +{ + GdkDisplay *display; + + display = gdk_display_get_default (); + + gdk_error_trap_push (); + + if (cardinal > 0) + { + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + xid, + gdk_x11_get_xatom_by_name_for_display (display, atom_name), + XA_CARDINAL, 32, + PropModeReplace, + (guchar *) &cardinal, 1); + } + else + { + XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), + xid, + gdk_x11_get_xatom_by_name_for_display (display, atom_name)); + } + + gdk_error_trap_pop (); +} + +static Window +get_window_xid (GtkWindow *window) +{ + GdkWindow *gdk_window; + + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + + if (gdk_window_get_effective_toplevel (gdk_window) != gdk_window) + { + g_warning ("Window is not toplevel"); + return 0; + } + + return GDK_WINDOW_XID (gdk_window); +} + +static void +update_window_icon (GtkWindow *window, + XAppGtkWindowPrivate *priv) +{ + /* Icon name/path */ + if (priv->icon_name != NULL) + { + set_window_hint_utf8 (get_window_xid (window), + ICON_NAME_HINT, + priv->icon_name); + } + else if (priv->icon_path != NULL) + { + set_window_hint_utf8 (get_window_xid (window), + ICON_NAME_HINT, + priv->icon_path); + } + else + { + set_window_hint_utf8 (get_window_xid (window), + ICON_NAME_HINT, + NULL); + } +} + +static void +update_window_progress (GtkWindow *window, + XAppGtkWindowPrivate *priv) +{ + /* Progress: 0 - 100 */ + set_window_hint_cardinal (get_window_xid (window), + PROGRESS_HINT, + (gulong) priv->progress); + + set_window_hint_cardinal (get_window_xid (window), + PROGRESS_PULSE_HINT, + (gulong) (priv->progress_pulse ? 1 : 0)); +} + +static void +set_icon_name_internal (GtkWindow *window, + XAppGtkWindowPrivate *priv, + const gchar *icon_name) +{ + if (g_strcmp0 (icon_name, priv->icon_name) == 0) + { + gtk_window_set_icon_name (window, icon_name); + return; + } + + /* Clear both strings when either is set - this ensures the + * correct value is set during update_window() */ + clear_icon_strings (priv); + + if (icon_name != NULL) + { + priv->icon_name = g_strdup (icon_name); + } + + /* If the window is realized, set the icon name immediately. + * If it's not, it will be set by xapp_gtk_window_realize(). */ + if (gtk_widget_get_realized (GTK_WIDGET (window))) + { + update_window_icon (window, priv); + } + + /* Call the GtkWindow method for compatibility */ + gtk_window_set_icon_name (GTK_WINDOW (window), icon_name); +} + +static void +set_icon_from_file_internal (GtkWindow *window, + XAppGtkWindowPrivate *priv, + const gchar *file_name, + GError **error) +{ + if (g_strcmp0 (file_name, priv->icon_path) == 0) + { + gtk_window_set_icon_from_file (window, file_name, error); + return; + } + + /* Clear both strings when either is set - this ensures the correct + * value is set during update_window() */ + clear_icon_strings (priv); + + if (file_name != NULL) + { + priv->icon_path = g_strdup (file_name); + } + + /* If the window is realized, set the icon path immediately. + * If it's not, it will be set by xapp_gtk_window_realize(). */ + if (gtk_widget_get_realized (GTK_WIDGET (window))) + { + update_window_icon (window, priv); + } + + gtk_window_set_icon_from_file (GTK_WINDOW (window), file_name, error); +} + +static void +set_progress_internal (GtkWindow *window, + XAppGtkWindowPrivate *priv, + gint progress) +{ + gboolean update; + guint clamped_progress; + + update = FALSE; + + if (priv->progress_pulse) + { + priv->progress_pulse = FALSE; + update = TRUE; + } + + clamped_progress = CLAMP (progress, 0, 100); + + if (clamped_progress != priv->progress) + { + priv->progress = clamped_progress; + update = TRUE; + } + + /* If the window is realized, set the progress immediately. + * If it's not, it will be set by xapp_gtk_window_realize(). */ + if (gtk_widget_get_realized (GTK_WIDGET (window))) + { + if (update) + { + update_window_progress (window, priv); + } + } +} + +static void +set_progress_pulse_internal (GtkWindow *window, + XAppGtkWindowPrivate *priv, + gboolean pulse) +{ + gboolean update; + + update = FALSE; + + if (priv->progress_pulse != pulse) + { + priv->progress_pulse = pulse; + + update = TRUE; + } + + /* If the window is realized, set the progress immediately. + * If it's not, it will be set by xapp_gtk_window_realize(). */ + if (gtk_widget_get_realized (GTK_WIDGET (window))) + { + if (update) + { + update_window_progress (window, priv); + } + } +} + +static void +xapp_gtk_window_realize (GtkWidget *widget) +{ + XAppGtkWindow *window = XAPP_GTK_WINDOW (widget); + XAppGtkWindowPrivate *priv = window->priv; + + GTK_WIDGET_CLASS (xapp_gtk_window_parent_class)->realize (widget); + + update_window_icon (GTK_WINDOW (window), priv); + update_window_progress (GTK_WINDOW (window), priv); +} + +static void +xapp_gtk_window_unrealize (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (xapp_gtk_window_parent_class)->unrealize (widget); +} + +static void +xapp_gtk_window_finalize (GObject *object) +{ + XAppGtkWindow *window = XAPP_GTK_WINDOW (object); + XAppGtkWindowPrivate *priv = window->priv; + + clear_icon_strings (priv); + + G_OBJECT_CLASS (xapp_gtk_window_parent_class)->finalize (object); +} + +static void +xapp_gtk_window_init (XAppGtkWindow *window) +{ + XAppGtkWindowPrivate *priv; + + window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window, XAPP_TYPE_GTK_WINDOW, XAppGtkWindowPrivate); + + priv = window->priv; + + priv->icon_name = NULL; + priv->icon_path = NULL; +} + +static void +xapp_gtk_window_class_init (XAppGtkWindowClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + + gobject_class->finalize = xapp_gtk_window_finalize; + wclass->realize = xapp_gtk_window_realize; + wclass->unrealize = xapp_gtk_window_unrealize; +} + +/** + * xapp_gtk_window_new: + * @type: The #GtkWindowType to use + * + * Creates a new #XAppGtkWindow of type @type. See gtk_window_new() + * for more details. + * + * Returns: A new #XAppGtkWindow (transfer: full) + */ +GtkWidget * +xapp_gtk_window_new (GtkWindowType type) +{ + return g_object_new (XAPP_TYPE_GTK_WINDOW, "type", type, NULL); +} + +/** + * xapp_gtk_window_set_icon_name: + * @window: The #XAppGtkWindow to set the icon name for + * @icon_name: (nullable): The icon name or path to set, or %NULL to unset. + * + * Sets the icon name hint for a window manager (like muffin) to make + * available when applications want to change their icons during runtime + * without having to resort to the internal low-res pixbufs that GdkWindow + * sets on the client side. This also chains up and calls GtkWindow.set_icon_name + * for convenience and compatibility. Set to %NULL to unset. + */ +void +xapp_gtk_window_set_icon_name (XAppGtkWindow *window, + const gchar *icon_name) +{ + g_return_if_fail (XAPP_IS_GTK_WINDOW (window)); + + set_icon_name_internal (GTK_WINDOW (window), window->priv, icon_name); +} + +/** + * xapp_gtk_window_set_icon_from_file: + * @window: The #XAppGtkWindow to set the icon name for + * @file_name: (nullable): The icon path to set, or %NULL to unset. + * @error: (nullable): An error to set if something goes wrong. + * + * Sets the icon name hint for a window manager (like muffin) to make + * available when applications want to change their icons during runtime + * without having to resort to the internal low-res pixbufs that GdkWindow + * sets on the client side. This also chains up and calls GtkWindow.set_icon_from_file + * for convenience and compatibility. Set to %NULL to unset. + */ +void +xapp_gtk_window_set_icon_from_file (XAppGtkWindow *window, + const gchar *file_name, + GError **error) +{ + g_return_if_fail (XAPP_IS_GTK_WINDOW (window)); + + set_icon_from_file_internal (GTK_WINDOW (window), window->priv, file_name, error); +} + +/** + * xapp_gtk_window_set_progress: + * @window: The #XAppGtkWindow to set the progress for + * @progress: The value to set for progress. + * + * Sets the progress hint for a window manager (like muffin) to make + * available when applications want to display the application's progress + * in some operation. The value sent to the WM will be clamped to + * between 0 and 100. + * + * Note: If a window will stick around after progress is complete, you will + * probaby need to set progress to 0 to remove any progress effects on taskbars + * and window lists. + * + * Setting progress will also cancel the 'pulsing' flag on the window as + * well, if it has been set. + */ +void +xapp_gtk_window_set_progress (XAppGtkWindow *window, + gint progress) +{ + g_return_if_fail (XAPP_IS_GTK_WINDOW (window)); + + set_progress_internal (GTK_WINDOW (window), window->priv, progress); +} + +/** + * xapp_gtk_window_set_progress_pulse: + * @window: The #XAppGtkWindow to set the progress for + * @pulse: Whether to have pulsing set or not. + * + * Sets the progress pulse hint hint for a window manager (like muffin) + * to make available when applications want to display indeterminate or + * ongoing progress in a task manager. + * + * Note: If a window will stick around after progress is complete, you will + * probaby need to set progress to 0 to remove any progress effects on taskbars + * and window lists. This will also remove the pulse state, if it is set. + * + * Setting an explicit progress value will unset this flag. + */ +void +xapp_gtk_window_set_progress_pulse (XAppGtkWindow *window, + gboolean pulse) +{ + g_return_if_fail (XAPP_IS_GTK_WINDOW (window)); + g_return_if_fail (XAPP_IS_GTK_WINDOW (window)); + + set_progress_pulse_internal (GTK_WINDOW (window), window->priv, pulse); +} + + +/* Wrappers (for GtkWindow subclasses like GtkDialog) + * window must be a GtkWindow or descendant */ +static void +on_gtk_window_realized (GtkWidget *widget, + gpointer user_data) +{ + XAppGtkWindowPrivate *priv; + + priv = (XAppGtkWindowPrivate *) user_data; + + update_window_icon (GTK_WINDOW (widget), priv); + update_window_progress (GTK_WINDOW (widget), priv); +} + +static void +destroy_xapp_struct (gpointer user_data) +{ + XAppGtkWindowPrivate *priv = (XAppGtkWindowPrivate *) user_data; + + g_clear_pointer (&priv->icon_name, g_free); + g_clear_pointer (&priv->icon_path, g_free); + + g_slice_free (XAppGtkWindowPrivate, priv); +} + +static XAppGtkWindowPrivate * +get_xapp_struct (GtkWindow *window) +{ + XAppGtkWindowPrivate *priv; + + priv = g_object_get_data (G_OBJECT (window), + "xapp-window-struct"); + + if (priv) + { + return priv; + } + + priv = g_slice_new0 (XAppGtkWindowPrivate); + + g_object_set_data_full (G_OBJECT (window), + "xapp-window-struct", + priv, + (GDestroyNotify) destroy_xapp_struct); + + g_signal_connect_after (GTK_WIDGET (window), + "realize", + G_CALLBACK (on_gtk_window_realized), + priv); + + return priv; +} + +/** + * xapp_set_window_icon_name: + * @window: The #GtkWindow to set the icon name for + * @icon_name: (nullable): The icon name to set, or %NULL to unset. + * + * Sets the icon name hint for a window manager (like muffin) to make + * available when applications want to change their icons during runtime + * without having to resort to the internal low-res pixbufs that GdkWindow + * sets on the client side. This is a function, not a method, for taking + * advantage of this feature with descendants of GtkWindows, such as + * GtkDialogs. Sets gtk_window_set_icon_name as well, to avoid needing + * to have two calls each time. Set to %NULL to unset. + */ +void +xapp_set_window_icon_name (GtkWindow *window, + const gchar *icon_name) +{ + XAppGtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = get_xapp_struct (window); + + if (XAPP_IS_GTK_WINDOW (window)) + { + g_warning("Window is an instance of XAppGtkWindow. Use the instance set_icon_name method instead."); + } + + set_icon_name_internal (window, priv, icon_name); +} + + +/** + * xapp_set_window_icon_from_file: + * @window: The #GtkWindow to set the icon name for + * @file_name: (nullable): The icon path to set, or %NULL to unset. + * @error: (nullable): An error to set if something goes wrong. + * + * Sets the icon name hint for a window manager (like muffin) to make + * available when applications want to change their icons during runtime + * without having to resort to the internal low-res pixbufs that GdkWindow + * sets on the client side. This also chains up and calls GtkWindow.set_icon_from_file + * for convenience and compatibility. Set to %NULL to unset. + */ +void +xapp_set_window_icon_from_file (GtkWindow *window, + const gchar *file_name, + GError **error) +{ + XAppGtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = get_xapp_struct (window); + + if (XAPP_IS_GTK_WINDOW (window)) + { + g_warning("Window is an instance of XAppGtkWindow. Use the instance set_icon_from_file method instead."); + } + + set_icon_from_file_internal (window, priv, file_name, error); +} + +/** + * xapp_set_window_progress: + * @window: The #GtkWindow to set the progress for + * @progress: The value to set for progress. + * + * Sets the progress hint for a window manager (like muffin) to make + * available when applications want to display the application's progress + * in some operation. The value sent to the WM will be clamped to + * between 0 and 100. + * + * Note: If a window will stick around after progress is complete, you will + * probaby need to set progress to 0 to remove any progress effects on taskbars + * and window lists. + * + * Setting progress will also cancel the 'pulsing' flag on the window as + * well, if it has been set. + */ +void +xapp_set_window_progress (GtkWindow *window, + gint progress) +{ + XAppGtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = get_xapp_struct (window); + + if (XAPP_IS_GTK_WINDOW (window)) + { + g_warning("Window is an instance of XAppGtkWindow. Use the instance set_progress method instead."); + } + + set_progress_internal (window, priv, progress); +} + +/** + * xapp_set_window_progress_pulse: + * @window: The #GtkWindow to set the progress for + * @pulse: Whether to have pulsing set or not. + * + * Sets the progress pulse hint hint for a window manager (like muffin) + * to make available when applications want to display indeterminate or + * ongoing progress in a task manager. + * + * Note: If a window will stick around after progress is complete, you will + * probaby need to set progress to 0 to remove any progress effects on taskbars + * and window lists. This will also remove the pulse state, if it is set. + * + * Setting an explicit progress value will unset this flag. + */ +void +xapp_set_window_progress_pulse (GtkWindow *window, + gboolean pulse) +{ + XAppGtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = get_xapp_struct (window); + + if (XAPP_IS_GTK_WINDOW (window)) + { + g_warning("Window is an instance of XAppGtkWindow. Use the instance set_progress_pulse method instead."); + } + + set_progress_pulse_internal (GTK_WINDOW (window), priv, pulse); +} + +/** + * xapp_set_xid_icon_name: + * @xid: The Window to set the icon name for + * @icon_name: (nullable): The icon name to set, or %NULL to unset. + * + * Sets the icon name hint for a window manager (like muffin) to make + * available when applications want to change their icons during runtime + * without having to resort to the internal low-res pixbufs that GdkWindow + * sets on the client side. This is a function, not a method, for applying + * the icon name property for a given (possibly foreign) window, by passing + * the window's XID. Set to %NULL to unset. + */ +void +xapp_set_xid_icon_name (gulong xid, + const gchar *icon_name) +{ + g_return_if_fail (xid > 0); + + set_window_hint_utf8 (xid, ICON_NAME_HINT, icon_name); +} + +/** + * xapp_set_xid_icon_from_file: + * @xid: The Window to set the icon name for + * @file_name: (nullable): The icon path to set, or %NULL to unset. + * + * Sets the icon name hint for a window manager (like muffin) to make + * available when applications want to change their icons during runtime + * without having to resort to the internal low-res pixbufs that GdkWindow + * sets on the client side. This is a function, not a method, for applying + * the icon name property for a given (possibly foreign) window, by passing + * the window's XID. Set to %NULL to unset. + */ +void +xapp_set_xid_icon_from_file (gulong xid, + const gchar *file_name) +{ + + g_return_if_fail (xid > 0); + + set_window_hint_utf8 (xid, ICON_NAME_HINT, file_name); +} + +/** + * xapp_set_xid_progress: + * @xid: The Window to set the progress for + * @progress: The value to set for progress. + * + * Sets the progress hint for a window manager (like muffin) to make + * available when applications want to display the application's progress + * in some operation. The value sent to the WM will be clamped to + * between 0 and 100. + * + * Setting progress will also cancel the 'pulsing' flag on the window as + * well, if it has been set. + * + * Note: If a window will stick around after progress is complete, you will + * probaby need to set progress to 0 to remove any progress effects on taskbars + * and window lists. + * + * This is a function, not a method, for applying the progress property for + * a given (possibly foreign) window, by passing the window's XID. + */ +void +xapp_set_xid_progress (gulong xid, + gint progress) +{ + g_return_if_fail (xid > 0); + + set_window_hint_cardinal (xid, PROGRESS_HINT, (gulong) (CLAMP (progress, 0, 100))); + set_window_hint_cardinal (xid, PROGRESS_PULSE_HINT, (gulong) 0); +} + +/** + * xapp_set_xid_progress_pulse: + * @xid: The Window to set the progress for + * @pulse: Whether to have pulsing set or not. + * + * Sets the progress pulse hint hint for a window manager (like muffin) + * to make available when applications want to display indeterminate or + * ongoing progress in a task manager. + * + * Note: If a window will stick around after progress is complete, you will + * probaby need to set progress to 0 to remove any progress effects on taskbars + * and window lists. + * + * Setting an explicit progress value will unset this flag. + */ +void +xapp_set_xid_progress_pulse (gulong xid, + gboolean pulse) +{ + g_return_if_fail (xid > 0); + + set_window_hint_cardinal (xid, PROGRESS_PULSE_HINT, (gulong) (pulse ? 1 : 0)); +} diff --git a/libxapp/xapp-gtk-window.h b/libxapp/xapp-gtk-window.h new file mode 100644 index 0000000..5df7e1a --- /dev/null +++ b/libxapp/xapp-gtk-window.h @@ -0,0 +1,52 @@ +#ifndef __XAPP_GTK_WINDOW_H__ +#define __XAPP_GTK_WINDOW_H__ + +#include + +#include +#include + +G_BEGIN_DECLS + +#define XAPP_TYPE_GTK_WINDOW (xapp_gtk_window_get_type ()) + +G_DECLARE_FINAL_TYPE (XAppGtkWindow, xapp_gtk_window, XAPP, GTK_WINDOW, GtkWindow) + +/* Class */ +GtkWidget *xapp_gtk_window_new (GtkWindowType type); + +void xapp_gtk_window_set_icon_name (XAppGtkWindow *window, + const gchar *icon_name); + +void xapp_gtk_window_set_icon_from_file (XAppGtkWindow *window, + const gchar *file_name, + GError **error); +void xapp_gtk_window_set_progress (XAppGtkWindow *window, + gint progress); +void xapp_gtk_window_set_progress_pulse (XAppGtkWindow *window, + gboolean pulse); +/* Wrappers (for GtkWindow subclasses like GtkDialog)*/ + +void xapp_set_window_icon_name (GtkWindow *window, + const gchar *icon_name); + +void xapp_set_window_icon_from_file (GtkWindow *window, + const gchar *file_name, + GError **error); +void xapp_set_window_progress (GtkWindow *window, + gint progress); +void xapp_set_window_progress_pulse (GtkWindow *window, + gboolean pulse); +/* Low level for X11 Window xid's */ +void xapp_set_xid_icon_name (gulong xid, + const gchar *icon_name); +void xapp_set_xid_icon_from_file (gulong xid, + const gchar *file_name); +void xapp_set_xid_progress (gulong xid, + gint progress); +void xapp_set_xid_progress_pulse (gulong xid, + gboolean pulse); + +G_END_DECLS + +#endif /* __XAPP_GTK_WINDOW_H__ */ diff --git a/libxapp/xapp-kbd-layout-controller.c b/libxapp/xapp-kbd-layout-controller.c index 6972d2f..03dc5bf 100644 --- a/libxapp/xapp-kbd-layout-controller.c +++ b/libxapp/xapp-kbd-layout-controller.c @@ -13,6 +13,17 @@ #include #include "xapp-kbd-layout-controller.h" + +/** + * SECTION:xapp-kbd-layout-controller + * @Short_description: Keyboard layout selection UI element provider. + * @Title: XAppKbdLayoutController + * + * A GObject wrapper for Gkbd that provides additional UI element + * support for keyboard layout flags and abbreviations, as well as + * Wfacilities to distinguish regional and hardware-based variants + * which might otherwise appear identical in a layout list. + */ enum { @@ -61,7 +72,7 @@ { GkbdConfiguration *config; - gint num_groups; + guint num_groups; GPtrArray *group_data; @@ -130,7 +141,9 @@ /* Populate the GroupData pointer array */ - gint i, j, group_dupe_id, variant_dupe_id; + gint group_dupe_id, variant_dupe_id; + guint i, j; + GPtrArray *list = g_ptr_array_new_with_free_func ((GDestroyNotify) group_data_free); for (i = 0; i < priv->num_groups; i++) @@ -386,18 +399,37 @@ 0, G_TYPE_NONE); } +/** + * xapp_kbd_layout_controller_new + * + * Creates a new XAppKbdLayoutController instance. + * + * Returns: (transfer full): a new #XAppKbdLayoutController instance + */ XAppKbdLayoutController * xapp_kbd_layout_controller_new (void) { return g_object_new (XAPP_TYPE_KBD_LAYOUT_CONTROLLER, NULL); } +/** + * xapp_kbd_layout_controller_get_enabled: + * @controller: the #XAppKbdLayoutController + * + * Returns whether or not the layout controller is enabled + */ gboolean xapp_kbd_layout_controller_get_enabled (XAppKbdLayoutController *controller) { return controller->priv->enabled; } +/** + * xapp_kbd_layout_controller_get_current_group: + * @controller: the #XAppKbdLayoutController + * + * Selects the previous group in the group list. + */ guint xapp_kbd_layout_controller_get_current_group (XAppKbdLayoutController *controller) { @@ -406,6 +438,13 @@ return gkbd_configuration_get_current_group (controller->priv->config); } +/** + * xapp_kbd_layout_controller_set_current_group + * @controller: the #XAppKbdLayoutController + * @group: the group number to make active + * + * Selects the given group number as active. + */ void xapp_kbd_layout_controller_set_current_group (XAppKbdLayoutController *controller, guint group) @@ -421,6 +460,12 @@ } } +/** + * xapp_kbd_layout_controller_next_group + * @controller: the #XAppKbdLayoutController + * + * Selects the next group in the group list. + */ void xapp_kbd_layout_controller_next_group (XAppKbdLayoutController *controller) { @@ -429,6 +474,12 @@ gkbd_configuration_lock_next_group (controller->priv->config); } +/** + * xapp_kbd_layout_controller_previous_group + * @controller: the #XAppKbdLayoutController + * + * Selects the previous group in the group list. + */ void xapp_kbd_layout_controller_previous_group (XAppKbdLayoutController *controller) { @@ -452,6 +503,7 @@ /** * xapp_kbd_layout_controller_get_current_name: + * @controller: the #XAppKbdLayoutController * * Returns the full name of the current keyboard layout. * @@ -468,6 +520,7 @@ /** * xapp_kbd_layout_controller_get_all_names: + * @controller: the #XAppKbdLayoutController * * Returns an array of all full layout names * @@ -483,6 +536,7 @@ /** * xapp_kbd_layout_controller_get_current_icon_name: + * @controller: the #XAppKbdLayoutController * * Returns the icon file name (no path or extension) to use for the current layout * @@ -502,6 +556,8 @@ /** * xapp_kbd_layout_controller_get_icon_name_for_group: + * @controller: the #XAppKbdLayoutController + * @group: a group number * * Returns the icon file name (no path or extension) to use for the specified layout. * @@ -521,6 +577,7 @@ /** * xapp_kbd_layout_controller_get_current_flag_id: + * @controller: the #XAppKbdLayoutController * * Returns the duplicate id for the current layout * @@ -541,6 +598,8 @@ /** * xapp_kbd_layout_controller_flag_id_for_group: + * @controller: the #XAppKbdLayoutController + * @group: a group number * * Returns the duplicate id for the specified layout * @@ -560,6 +619,7 @@ /** * xapp_kbd_layout_controller_get_current_short_group_label: + * @controller: the #XAppKbdLayoutController * * Returns the short group label (and subscript, if any) of the current layout * @@ -579,6 +639,8 @@ /** * xapp_kbd_layout_controller_get_short_group_label_for_group: + * @controller: the #XAppKbdLayoutController + * @group: a group number * * Returns the short group label and subscript of the specified layout. * @@ -599,6 +661,7 @@ /** * xapp_kbd_layout_controller_get_current_variant_label: + * @controller: the #XAppKbdLayoutController * * Returns the variant label (and subscript, if any) of the current layout * @@ -618,6 +681,8 @@ /** * xapp_kbd_layout_controller_get_variant_label_for_group: + * @controller: the #XAppKbdLayoutController + * @group: a group number * * Returns the variant label and subscript of the specified layout. * @@ -636,6 +701,19 @@ return g_strdup (GROUP_DATA (priv->group_data, group)->variant_label); } +/** + * xapp_kbd_layout_controller_render_cairo_subscript: + * @cr: a #cairo_t + * @x: the x position of the drawing area + * @y: the y position of the drawing area + * @width: the width of the drawing area + * @height: the height of the drawing area + * @subscript: the number to render + * + * Renders a subscript number in the given work area. This should + * be called from within a "draw" or "paint" widget/actor function, + * where a valid cairo_t is provided to draw with. + */ void xapp_kbd_layout_controller_render_cairo_subscript (cairo_t *cr, gdouble x, diff --git a/m4/gtk-doc.m4 b/m4/gtk-doc.m4 index 0ada151..3675543 100644 --- a/m4/gtk-doc.m4 +++ b/m4/gtk-doc.m4 @@ -1,6 +1,6 @@ dnl -*- mode: autoconf -*- -# serial 1 +# serial 2 dnl Usage: dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) @@ -10,8 +10,24 @@ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + ifelse([$1],[],[gtk_doc_requires="gtk-doc"],[gtk_doc_requires="gtk-doc >= $1"]) + AC_MSG_CHECKING([for gtk-doc]) + PKG_CHECK_EXISTS([$gtk_doc_requires],[have_gtk_doc=yes],[have_gtk_doc=no]) + AC_MSG_RESULT($have_gtk_doc) + + if test "$have_gtk_doc" = "no"; then + AC_MSG_WARN([ + You will not be able to create source packages with 'make dist' + because $gtk_doc_requires is not found.]) + fi + dnl check for tools we added during development - AC_PATH_PROG([GTKDOC_CHECK],[gtkdoc-check]) + dnl Use AC_CHECK_PROG to avoid the check target using an absolute path that + dnl may not be writable by the user. Currently, automake requires that the + dnl test name must end in '.test'. + dnl https://bugzilla.gnome.org/show_bug.cgi?id=701638 + AC_CHECK_PROG([GTKDOC_CHECK],[gtkdoc-check],[gtkdoc-check.test]) + AC_PATH_PROG([GTKDOC_CHECK_PATH],[gtkdoc-check]) AC_PATH_PROGS([GTKDOC_REBASE],[gtkdoc-rebase],[true]) AC_PATH_PROG([GTKDOC_MKPDF],[gtkdoc-mkpdf]) @@ -28,21 +44,21 @@ [use gtk-doc to build documentation [[default=no]]]),, [enable_gtk_doc=no]) - if test x$enable_gtk_doc = xyes; then - ifelse([$1],[], - [PKG_CHECK_EXISTS([gtk-doc],, - AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))], - [PKG_CHECK_EXISTS([gtk-doc >= $1],, - AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build $PACKAGE_NAME]))]) - dnl don't check for glib if we build glib - if test "x$PACKAGE_NAME" != "xglib"; then - dnl don't fail if someone does not have glib - PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,) - fi + AC_MSG_CHECKING([whether to build gtk-doc documentation]) + AC_MSG_RESULT($enable_gtk_doc) + + if test "x$enable_gtk_doc" = "xyes" && test "$have_gtk_doc" = "no"; then + AC_MSG_ERROR([ + You must have $gtk_doc_requires installed to build documentation for + $PACKAGE_NAME. Please install gtk-doc or disable building the + documentation by adding '--disable-gtk-doc' to '[$]0'.]) fi - AC_MSG_CHECKING([whether to build gtk-doc documentation]) - AC_MSG_RESULT($enable_gtk_doc) + dnl don't check for glib if we build glib + if test "x$PACKAGE_NAME" != "xglib"; then + dnl don't fail if someone does not have glib + PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,[:]) + fi dnl enable/disable output formats AC_ARG_ENABLE([gtk-doc-html], @@ -58,7 +74,12 @@ enable_gtk_doc_pdf=no fi + if test -z "$AM_DEFAULT_VERBOSITY"; then + AM_DEFAULT_VERBOSITY=1 + fi + AC_SUBST([AM_DEFAULT_VERBOSITY]) + AM_CONDITIONAL([HAVE_GTK_DOC], [test x$have_gtk_doc = xyes]) AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes]) AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [test x$enable_gtk_doc_html = xyes]) AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [test x$enable_gtk_doc_pdf = xyes]) diff --git a/m4/intltool.m4 b/m4/intltool.m4 index 33353ed..c25b7b1 100644 --- a/m4/intltool.m4 +++ b/m4/intltool.m4 @@ -154,31 +154,6 @@ # Substitute ALL_LINGUAS so we can use it in po/Makefile AC_SUBST(ALL_LINGUAS) - -# Set DATADIRNAME correctly if it is not set yet -# (copied from glib-gettext.m4) -if test -z "$DATADIRNAME"; then - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[]], - [[extern int _nl_msg_cat_cntr; - return _nl_msg_cat_cntr]])], - [DATADIRNAME=share], - [case $host in - *-*-solaris*) - dnl On Solaris, if bind_textdomain_codeset is in libc, - dnl GNU format message catalog is always supported, - dnl since both are added to the libc all together. - dnl Hence, we'd like to go with DATADIRNAME=share - dnl in this case. - AC_CHECK_FUNC(bind_textdomain_codeset, - [DATADIRNAME=share], [DATADIRNAME=lib]) - ;; - *) - [DATADIRNAME=lib] - ;; - esac]) -fi -AC_SUBST(DATADIRNAME) IT_PO_SUBDIR([po]) diff --git a/po/Makefile.in.in b/po/Makefile.in.in index 06a8cfe..fcd2c3b 100644 --- a/po/Makefile.in.in +++ b/po/Makefile.in.in @@ -33,8 +33,7 @@ datadir = @datadir@ datarootdir = @datarootdir@ libdir = @libdir@ -DATADIRNAME = @DATADIRNAME@ -itlocaledir = $(prefix)/$(DATADIRNAME)/locale +localedir = @localedir@ subdir = po install_sh = @install_sh@ # Automake >= 1.8 provides @mkdir_p@. @@ -80,7 +79,7 @@ .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot - $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox + $(MSGMERGE) $* $(GETTEXT_PACKAGE).pot -o $*.pox .po.mo: $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< @@ -108,7 +107,7 @@ install-data-yes: all linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ - dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ + dir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $$dir; \ if test -r $$lang.gmo; then \ $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ @@ -142,8 +141,8 @@ uninstall: linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ - rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ - rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ + rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ + rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ done check: all $(GETTEXT_PACKAGE).pot diff --git a/pygobject/Makefile.am b/pygobject/Makefile.am new file mode 100644 index 0000000..45c5f2e --- /dev/null +++ b/pygobject/Makefile.am @@ -0,0 +1,3 @@ +overridesdir = $(pyoverridesdir) +overrides_PYTHON = \ + XApp.py diff --git a/pygobject/XApp.py b/pygobject/XApp.py new file mode 100644 index 0000000..80eb278 --- /dev/null +++ b/pygobject/XApp.py @@ -0,0 +1,25 @@ +from gi.overrides import override +from gi.importer import modules + +""" +The only purpose of this file is to ensure the XApp widget GType is registered +at the time of import. Otherwise any user of XApp.GtkWindow would have to create +a dummy widget prior to using a GtkBuilder to parse a ui file containing an +XAppGtkWindow. + +The gi import machinery sweeps usr/lib/python*/dist-packages/gi/overrides for file +matching the module name at the time of execution. + +This file needs to be in both python2 and python3 overrides locations. + +""" + +XApp = modules['XApp']._introspection_module + +__all__ = [] + +class GtkWindow(XApp.GtkWindow): + pass + +GtkWindow = override(GtkWindow) +__all__.append('GtkWindow') diff --git a/test-scripts/xapp-gtk-window b/test-scripts/xapp-gtk-window new file mode 100755 index 0000000..bb83e87 --- /dev/null +++ b/test-scripts/xapp-gtk-window @@ -0,0 +1,138 @@ +#! /usr/bin/python3 + +""" +A demo/test script for the XAppAppGtkWindow class +""" +import sys, os +import signal +import gettext +import time + +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('XApp', '1.0') + +from gi.repository import GLib, Gtk, XApp, GObject + +signal.signal(signal.SIGINT, signal.SIG_DFL) + +class Main: + def __init__(self): + self.win = XApp.GtkWindow() + + self._animate_progress = 0 + + self.win.set_default_size(320, 200) + + frame = Gtk.Frame() + frame.set_margin_start(2) + frame.set_margin_end(2) + frame.set_margin_top(2) + frame.set_margin_bottom(2) + + self.win.add(frame) + + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + box.set_margin_start(2) + box.set_margin_end(2) + box.set_margin_top(2) + box.set_margin_bottom(2) + + frame.add(box) + + heading = Gtk.Label() + heading.set_markup("Use 'xprop -spy' to monitor changes") + box.pack_start(heading, True, True, 4) + + hbox = Gtk.HBox() + self.icon_name_entry = Gtk.Entry() + self.icon_name_setter = Gtk.Button("Set icon name") + self.icon_name_setter.connect("clicked", self.on_icon_name_setter_clicked) + hbox.pack_start(self.icon_name_entry, True, True, 4) + hbox.pack_start(self.icon_name_setter, False, False, 4) + box.pack_start(hbox, True, True, 4) + + hbox = Gtk.HBox() + self.icon_path_entry = Gtk.Entry() + self.icon_path_setter = Gtk.Button("Set icon path") + self.icon_path_setter.connect("clicked", self.on_icon_path_setter_clicked) + hbox.pack_start(self.icon_path_entry, True, True, 4) + hbox.pack_start(self.icon_path_setter, False, False, 4) + box.pack_start(hbox, True, True, 4) + + hbox = Gtk.HBox() + self.progress_label = Gtk.Label("Progress:") + self.progress = Gtk.Scale() + self.progress.connect("value-changed", self.on_progress_value_changed) + self.progress.set_draw_value(True) + self.progress.set_digits(0) + self.progress.set_range(0, 100) + + hbox.pack_start(self.progress_label, False, False, 4) + hbox.pack_start(self.progress, True, True, 4) + box.pack_start(hbox, True, True, 4) + + hbox = Gtk.HBox() + self.pulse_label = Gtk.Label("Progress pulse:") + self.pulse_switch = Gtk.Switch() + self.pulse_switch.set_halign(Gtk.Align.CENTER) + self.pulse_switch.connect("notify::active", self.on_pulse_switch_changed) + hbox.pack_start(self.pulse_label, False, False, 4) + hbox.pack_start(self.pulse_switch, True, True, 4) + box.pack_start(hbox, True, True, 4) + + hbox = Gtk.HBox() + self.animate_button = Gtk.Button("Simulate progress over time") + self.animate_button.connect("clicked", self.on_animate_progress_clicked) + hbox.pack_start(self.animate_button, True, True, 4) + + box.pack_start(hbox, True, True, 4) + + frame.show_all() + self.win.connect("delete-event", lambda w, e: Gtk.main_quit()) + self.win.present() + + Gtk.main() + + def on_animate_progress_clicked(self, button, data=None): + self.progress.set_sensitive(False) + self.pulse_switch.set_sensitive(False) + + self._animate_progress = 0 + self.win.set_progress(0) + + GObject.timeout_add(500, self.on_progress_tick) + + def on_progress_tick(self): + self.win.set_progress(self._animate_progress) + + if self._animate_progress == 100: + self.on_animate_complete() + return False + else: + self._animate_progress += 1 + return True + + def on_animate_complete(self): + self.progress.set_sensitive(True) + self.pulse_switch.set_sensitive(True) + self.progress.set_value(100) + + def on_icon_name_setter_clicked(self, button, data=None): + self.win.set_icon_name(self.icon_name_entry.get_text()) + + def on_icon_path_setter_clicked(self, button, data=None): + try: + self.win.set_icon_from_file(self.icon_path_entry.get_text()) + except GLib.Error as e: + print(e.message) + + def on_progress_value_changed(self, range, data=None): + self.win.set_progress(int(self.progress.get_value())) + self.pulse_switch.set_active(False) + + def on_pulse_switch_changed(self, switch, pspec, data=None): + self.win.set_progress_pulse(self.pulse_switch.get_active()) + +if __name__ == "__main__": + main = Main() diff --git a/vapi/XApp-1.0.metadata b/vapi/XApp-1.0.metadata new file mode 100644 index 0000000..3854317 --- /dev/null +++ b/vapi/XApp-1.0.metadata @@ -0,0 +1,4 @@ +GtkWindow cheader_filename="libxapp/xapp-gtk-window.h" +MonitorBlanker cheader_filename="libxapp/xapp-monitor-blanker.h" +KbdLayoutController cheader_filename="libxapp/xapp-kbd-layout-controller.h" +XApp cheader_filename="libxapp/xapp-gtk-window.h" \ No newline at end of file diff --git a/vapi/generate_vapi b/vapi/generate_vapi new file mode 100755 index 0000000..c24cebd --- /dev/null +++ b/vapi/generate_vapi @@ -0,0 +1,2 @@ +#!/bin/bash +vapigen --pkg glib-2.0 --pkg gio-unix-2.0 --pkg gtk+-3.0 --library xapp /usr/share/gir-1.0/XApp-1.0.gir --metadatadir . -d ../files/usr/share/vala/vapi/