From 6d8476d3df0efff98bb8aa5812d6d00576ebae5a Mon Sep 17 00:00:00 2001 From: Maarten Duijndam Date: Mon, 4 Nov 2024 13:04:40 +0100 Subject: [PATCH 1/5] Psy.Initializer, init everything by default --- psy/psy-init.c | 23 ++--------------------- tests/test-gtk-window.c | 4 ++-- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/psy/psy-init.c b/psy/psy-init.c index a16fa54..5a83ce8 100644 --- a/psy/psy-init.c +++ b/psy/psy-init.c @@ -15,7 +15,6 @@ static GMutex init_mutex; typedef struct _PsyInitializer { GObject parent; - guint all : 1; #ifdef HAVE_GSTREAMER guint gstreamer : 1; #endif @@ -29,7 +28,6 @@ G_DEFINE_TYPE(PsyInitializer, psy_initializer, G_TYPE_OBJECT) typedef enum { PROP_NULL, // GObject internal use - PROP_ALL, // Turn everything on. #ifdef HAVE_GSTREAMER PROP_GSTREAMER, #endif @@ -124,9 +122,6 @@ initializer_get_property(GObject *obj, PsyInitializer *self = PSY_INITIALIZER(obj); switch (id) { - case PROP_ALL: - g_value_set_boolean(value, self->all != 0); - break; case PROP_GSTREAMER: g_value_set_boolean(value, self->gstreamer != 0); break; @@ -147,13 +142,6 @@ initializer_set_property(GObject *obj, PsyInitializer *self = PSY_INITIALIZER(obj); switch (id) { - case PROP_ALL: - self->all = g_value_get_boolean(value); - if (self->all) { - self->gstreamer = TRUE; - self->portaudio = TRUE; - } - break; case PROP_GSTREAMER: self->gstreamer = g_value_get_boolean(value); break; @@ -174,19 +162,12 @@ psy_initializer_class_init(PsyInitializerClass *klass) obj_class->finalize = initializer_finalize; obj_class->constructed = initializer_constructed; - initializer_properties[PROP_ALL] - = g_param_spec_boolean("all", - "All", - "Initialize all libs psylib uses", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - #ifdef HAVE_GSTREAMER initializer_properties[PROP_GSTREAMER] = g_param_spec_boolean( "gstreamer", "GStreamer", "Initialize gstreamer along with the rest of psylib", - FALSE, + TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); #endif @@ -195,7 +176,7 @@ psy_initializer_class_init(PsyInitializerClass *klass) "portaudio", "PortAudio", "Initialize portaudio along with the rest of psylib", - FALSE, + TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); #endif diff --git a/tests/test-gtk-window.c b/tests/test-gtk-window.c index fd7073d..f0e4595 100644 --- a/tests/test-gtk-window.c +++ b/tests/test-gtk-window.c @@ -232,8 +232,8 @@ main(int argc, char **argv) gint window_style; const gchar *text_content = NULL; - PsyInitializer *initializer - = g_object_new(PSY_TYPE_INITIALIZER, "all", FALSE, NULL); + PsyInitializer *initializer = g_object_new( + PSY_TYPE_INITIALIZER, "gstreamer", FALSE, "portaudio", FALSE, NULL); PsyColor *circle_color = psy_color_new_rgb(1.0, 0, 0); PsyColor *cross_color = psy_color_new_rgb(1.0, 1.0, 0); From 111e3baa2422b929d7152d918779e3459e4d7925 Mon Sep 17 00:00:00 2001 From: Maarten Duijndam Date: Mon, 4 Nov 2024 15:28:37 +0100 Subject: [PATCH 2/5] Make Psy.Initializer init dep libs as opt out The Initializer:all property has been removed. All libraries are initialized by default and you can opt out specific libs fixes #130 --- examples/python/stepping.py | 2 +- examples/python/timers.py | 2 +- psy/psy-init.c | 19 +++++++ tests/meson.build | 10 ++++ tests/test-init.c | 107 ++++++++++++++++++++++++++++++++++++ tests/test-timer2.c | 2 +- 6 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 tests/test-init.c diff --git a/examples/python/stepping.py b/examples/python/stepping.py index d39663e..2fe5e08 100644 --- a/examples/python/stepping.py +++ b/examples/python/stepping.py @@ -11,7 +11,7 @@ from gi.repository import Psy, GLib import psy_operators -initializer = Psy.Initializer() # initialize psylib +initializer = Psy.Initializer(gstreamer=False, portaudio=False) # initialize psylib window: Psy.Canvas _NUM_ITERATIONS = 10 diff --git a/examples/python/timers.py b/examples/python/timers.py index 6700df5..24640dc 100644 --- a/examples/python/timers.py +++ b/examples/python/timers.py @@ -10,7 +10,7 @@ from gi.repository import Psy, GLib import psy_operators -psy_init = Psy.Initializer() +psy_init = Psy.Initializer(gstreamer=False, portaudio=False) cmd_parser = ap.ArgumentParser( "timers", description="An example using Psy.Timers with python" diff --git a/psy/psy-init.c b/psy/psy-init.c index 5a83ce8..49289f6 100644 --- a/psy/psy-init.c +++ b/psy/psy-init.c @@ -122,12 +122,16 @@ initializer_get_property(GObject *obj, PsyInitializer *self = PSY_INITIALIZER(obj); switch (id) { +#ifdef HAVE_GSTREAMER case PROP_GSTREAMER: g_value_set_boolean(value, self->gstreamer != 0); break; +#endif +#ifdef HAVE_PORTAUDIO case PROP_PORTAUDIO: g_value_set_boolean(value, self->portaudio != 0); break; +#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, pspec); } @@ -142,12 +146,16 @@ initializer_set_property(GObject *obj, PsyInitializer *self = PSY_INITIALIZER(obj); switch (id) { +#ifdef HAVE_GSTREAMER case PROP_GSTREAMER: self->gstreamer = g_value_get_boolean(value); break; +#endif +#ifdef HAVE_PORTAUDIO case PROP_PORTAUDIO: self->portaudio = g_value_get_boolean(value); break; +#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, pspec); } @@ -163,6 +171,11 @@ psy_initializer_class_init(PsyInitializerClass *klass) obj_class->constructed = initializer_constructed; #ifdef HAVE_GSTREAMER + /** + * Initializer:gstreamer + * + * If set to true psylib will init gstreamer on your behalf + */ initializer_properties[PROP_GSTREAMER] = g_param_spec_boolean( "gstreamer", "GStreamer", @@ -172,6 +185,12 @@ psy_initializer_class_init(PsyInitializerClass *klass) #endif #ifdef HAVE_PORTAUDIO + + /** + * Initializer:portaudio + * + * If set to true psylib will init portaudio on your behalf + */ initializer_properties[PROP_PORTAUDIO] = g_param_spec_boolean( "portaudio", "PortAudio", diff --git a/tests/meson.build b/tests/meson.build index a917b18..a6d2cb8 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -15,6 +15,16 @@ if buildtype != 'debug' and buildtype != 'debugoptimized' UNIT_PP_ARGS += '-DNDEBUG=1' endif +test_init = executable( + 'test_init', + files('test-init.c', 'munit.c', 'unit-test-utilities.c'), + dependencies: psy_dep, + c_args : UNIT_PP_ARGS, + cpp_args : UNIT_PP_ARGS, +) +test('test_init', test_init) + + test_gtk_window = executable( 'test_gtk_window', files('test-gtk-window.c'), diff --git a/tests/test-init.c b/tests/test-init.c new file mode 100644 index 0000000..07cbafa --- /dev/null +++ b/tests/test-init.c @@ -0,0 +1,107 @@ + +#include "unit-test-utilities.h" + +#include +#include +#include + +static int +initializer_setup(void) +{ + install_log_handler(); + set_log_handler_level(G_LOG_LEVEL_DEBUG); + set_log_handler_file("test-init.txt"); + return 0; +} + +static int +initializer_teardown(void) +{ + set_log_handler_file(NULL); + remove_log_handler(); + return 0; +} + +static MunitResult +test_initializer_default(const MunitParameter params[], void *user_data) +{ + (void) params; + (void) user_data; + gboolean gst, portaudio; + PsyInitializer *initialzer = g_object_new(PSY_TYPE_INITIALIZER, NULL); + + g_object_get(initialzer, "gstreamer", &gst, "portaudio", &portaudio, NULL); + + munit_assert_int(gst, ==, TRUE); + munit_assert_int(portaudio, ==, TRUE); + + g_object_unref(initialzer); + + return MUNIT_OK; +} + +static MunitResult +test_initializer_specific(const MunitParameter params[], void *user_data) +{ + (void) params; + (void) user_data; + gboolean gst, portaudio; + PsyInitializer *initialzer = g_object_new( + PSY_TYPE_INITIALIZER, "gstreamer", TRUE, "portaudio", FALSE, NULL); + + g_object_get(initialzer, "gstreamer", &gst, "portaudio", &portaudio, NULL); + + munit_assert_int(gst, ==, TRUE); + munit_assert_int(portaudio, ==, FALSE); + + g_object_unref(initialzer); + + return MUNIT_OK; +} + +// clang-format off +MunitTest tests[] = { + {"default",test_initializer_default, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + {"specific", test_initializer_specific, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + {0} +}; +// clang-format on + +MunitSuite suite = {"initializer/", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}; + +static void +signal_handler(int sig) +{ + switch (sig) { + case SIGINT: + case SIGABRT: + case SIGSEGV: + remove_log_handler(); + g_print("Received signal %d\nquitting\n", sig); + exit(sig); + } +} + +static void +setup_signal_handlers(void) +{ + if (signal(SIGINT, signal_handler) == SIG_ERR) { + g_printerr("Unable to catch SIGINT"); + } + if (signal(SIGABRT, signal_handler) == SIG_ERR) { + g_printerr("Unable to catch SIGABRT"); + } + if (signal(SIGSEGV, signal_handler) == SIG_ERR) { + g_printerr("Unable to catch SIGABRT"); + } +} + +int +main(int argc, char **argv) +{ + initializer_setup(); + setup_signal_handlers(); + int ret = munit_suite_main(&suite, NULL, argc, argv); + initializer_teardown(); + return ret; +} diff --git a/tests/test-timer2.c b/tests/test-timer2.c index ba3a680..2dee513 100644 --- a/tests/test-timer2.c +++ b/tests/test-timer2.c @@ -520,7 +520,7 @@ MunitTest tests[] = { }; // clang-format on -MunitSuite suite = {"psy-timer/", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}; +MunitSuite suite = {"timer/", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE}; static void signal_handler(int sig) From c03454f63cd0e897d3fd965cdd3a40af29d51ce8 Mon Sep 17 00:00:00 2001 From: Maarten Duijndam Date: Mon, 4 Nov 2024 15:51:23 +0100 Subject: [PATCH 3/5] log libs used --- psy/psy-init.c | 2 ++ tests/test-init.c | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/psy/psy-init.c b/psy/psy-init.c index 49289f6..f474a98 100644 --- a/psy/psy-init.c +++ b/psy/psy-init.c @@ -149,11 +149,13 @@ initializer_set_property(GObject *obj, #ifdef HAVE_GSTREAMER case PROP_GSTREAMER: self->gstreamer = g_value_get_boolean(value); + g_info("use gstreamer = %d", self->gstreamer == 1); break; #endif #ifdef HAVE_PORTAUDIO case PROP_PORTAUDIO: self->portaudio = g_value_get_boolean(value); + g_info("use portaudio = %d", self->portaudio == 1); break; #endif default: diff --git a/tests/test-init.c b/tests/test-init.c index 07cbafa..ea37d9a 100644 --- a/tests/test-init.c +++ b/tests/test-init.c @@ -45,9 +45,12 @@ test_initializer_specific(const MunitParameter params[], void *user_data) { (void) params; (void) user_data; - gboolean gst, portaudio; - PsyInitializer *initialzer = g_object_new( - PSY_TYPE_INITIALIZER, "gstreamer", TRUE, "portaudio", FALSE, NULL); + gboolean gst, portaudio; + + // No need to say we do "need" gstreamer. Initialization is everything + // unless explictly turned off as portaudio here below. + PsyInitializer *initialzer + = g_object_new(PSY_TYPE_INITIALIZER, "portaudio", FALSE, NULL); g_object_get(initialzer, "gstreamer", &gst, "portaudio", &portaudio, NULL); From bb2af299cdc496770cf6ee8832f91fb3939c31da Mon Sep 17 00:00:00 2001 From: Maarten Duijndam Date: Mon, 4 Nov 2024 16:38:36 +0100 Subject: [PATCH 4/5] Only deinit_gstreamer when you are sure Deinitializing gstreamer twice will crash your program. When your program finishes gstreamer stuff will be deinitialized. --- psy/psy-init.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/psy/psy-init.c b/psy/psy-init.c index f474a98..90d7021 100644 --- a/psy/psy-init.c +++ b/psy/psy-init.c @@ -16,7 +16,8 @@ static GMutex init_mutex; typedef struct _PsyInitializer { GObject parent; #ifdef HAVE_GSTREAMER - guint gstreamer : 1; + guint gstreamer : 1; + guint gstreamer_force_unload : 1; #endif #ifdef HAVE_PORTAUDIO guint portaudio : 1; @@ -30,6 +31,7 @@ typedef enum { PROP_NULL, // GObject internal use #ifdef HAVE_GSTREAMER PROP_GSTREAMER, + PROP_GSTREAMER_FORCE_UNLOAD, #endif #ifdef HAVE_PORTAUDIO PROP_PORTAUDIO, @@ -98,7 +100,10 @@ initializer_finalize(GObject *obj) // specific libs if (self->gstreamer) { - gst_deinit(); + // You are not allowed to deinit gstreamer twice. So only unload + // gstreamer when you are really sure. + if (self->gstreamer_force_unload) + gst_deinit(); } if (self->portaudio) { @@ -126,6 +131,9 @@ initializer_get_property(GObject *obj, case PROP_GSTREAMER: g_value_set_boolean(value, self->gstreamer != 0); break; + case PROP_GSTREAMER_FORCE_UNLOAD: + g_value_set_boolean(value, self->gstreamer != 0); + break; #endif #ifdef HAVE_PORTAUDIO case PROP_PORTAUDIO: @@ -151,6 +159,9 @@ initializer_set_property(GObject *obj, self->gstreamer = g_value_get_boolean(value); g_info("use gstreamer = %d", self->gstreamer == 1); break; + case PROP_GSTREAMER_FORCE_UNLOAD: + self->gstreamer = g_value_get_boolean(value); + break; #endif #ifdef HAVE_PORTAUDIO case PROP_PORTAUDIO: @@ -184,6 +195,20 @@ psy_initializer_class_init(PsyInitializerClass *klass) "Initialize gstreamer along with the rest of psylib", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + /** + * Initializer:gstreamer-force-unload + * + * If set to true psylib will deinit gstreamer on your behalf. You'll have + * to notice that doing this twice WILL crash your program, so you'll + * probably want to keep this off, as that doesn't hurt. + */ + initializer_properties[PROP_GSTREAMER_FORCE_UNLOAD] + = g_param_spec_boolean("gstreamer-force-unload", + "GStreamerForceUnload", + "deinit gstreamer when done. Keep it FALSE.", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); #endif #ifdef HAVE_PORTAUDIO From dae172a79c8afe42eba248e8e0ee8c32572650ef Mon Sep 17 00:00:00 2001 From: Maarten Duijndam Date: Mon, 4 Nov 2024 16:44:22 +0100 Subject: [PATCH 5/5] PsyInitialzizer set right property --- psy/psy-init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psy/psy-init.c b/psy/psy-init.c index 90d7021..e51021e 100644 --- a/psy/psy-init.c +++ b/psy/psy-init.c @@ -160,7 +160,7 @@ initializer_set_property(GObject *obj, g_info("use gstreamer = %d", self->gstreamer == 1); break; case PROP_GSTREAMER_FORCE_UNLOAD: - self->gstreamer = g_value_get_boolean(value); + self->gstreamer_force_unload = g_value_get_boolean(value); break; #endif #ifdef HAVE_PORTAUDIO