Thank you ebassi for showing me how to subclass a GObject. This is my updated example code that subclasses GtkApplicationWindow. It works, but example_transparent_window_snapshot
is not getting called. Do I have to call this function? I assumed it gets called when the window background is drawn.
I should also mention I’m new to using gtk. I’ve been reading the documentation for gtk4 but there is no description for the gtk_widget_snapshot
virtual method. Gtk.Widget.snapshot
If GtkWindow classes can’t be snapshotted, how could I change the background color of the window to be transparent? A transparent GtkDrawingArea doesn’t work, because it makes itself transparent but not the window background underneath. I want to be able to do this in C, not CSS or any external files. I want to make the window background color transparent, but keep the child widgets opaque (buttons, etc.) so gtk_widget_set_opacity
isn’t what im looking for.
/* Hello World application in gtk4, trying to set the background
* color of the
* main window to transparent.
*/
#include <gtk/gtk.h>
// new subclass
G_BEGIN_DECLS
#define EXAMPLE_TYPE_TRANSPARENT_WINDOW example_transparent_window_get_type ()
G_DECLARE_DERIVABLE_TYPE (ExampleTransparentWindow, example_transparent_window, EXAMPLE, TRANSPARENT_WINDOW, GtkApplicationWindow)
struct _ExampleTransparentWindowClass
{
GObject parent_instance;
void (*snapshot) (
GtkWidget *widget, GtkSnapshot *snapshot);
/* Other members, including private data. */
/* Padding to allow adding up to 12 new virtual functions without
* breaking ABI. */
gpointer padding[12];
};
GtkWidget *example_transparent_window_new (GtkApplication *application);
void example_transparent_window_snapshot (
GtkWidget *widget, GtkSnapshot *snapshot);
G_END_DECLS
/*
* forward definitions
*/
G_DEFINE_TYPE (ExampleTransparentWindow, example_transparent_window, GTK_TYPE_APPLICATION_WINDOW)
static void
example_transparent_window_real_snapshot (
GtkWidget *widget, GtkSnapshot *snapshot)
{
/* Default implementation for the virtual method. */
g_print ("snapshot\n");
}
void
example_transparent_window_snapshot (
GtkWidget *widget, GtkSnapshot *snapshot)
{
ExampleTransparentWindowClass *klass;
klass =
EXAMPLE_TRANSPARENT_WINDOW_GET_CLASS (EXAMPLE_TRANSPARENT_WINDOW (widget));
// not called
puts ("got here?");
/* if the method is purely virtual, then it is a good idea to
* check that it has been overridden before calling it, and,
* depending on the intent of the class, either ignore it silently
* or warn the user.
*/
g_return_if_fail (klass->snapshot != NULL);
klass->snapshot (widget, snapshot);
}
static void
example_transparent_window_class_init (
ExampleTransparentWindowClass *klass)
{
/* merely virtual method. */
klass->snapshot = example_transparent_window_real_snapshot;
}
static void
example_transparent_window_init (ExampleTransparentWindow *self)
{
// ViewerFilePrivate *priv = viewer_file_get_instance_private (self);
/* initialize all public and private members to reasonable default values.
* They are all automatically initialized to 0 to begin with. */
}
static void
example_transparent_window_dispose (GObject *gobject)
{
// ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject));
/* In dispose(), you are supposed to free all types referenced from this
* object which might themselves hold a reference to self. Generally,
* the most simple solution is to unref all members on which you own a
* reference.
*/
/* dispose() might be called multiple times, so we must guard against
* calling g_object_unref() on an invalid GObject by setting the member
* NULL; g_clear_object() does this for us.
*/
// g_clear_object (&priv->input_stream);
/* Always chain up to the parent class; there is no need to check if
* the parent class implements the dispose() virtual function: it is
* always guaranteed to do so
*/
G_OBJECT_CLASS (example_transparent_window_parent_class)->dispose (gobject);
}
static void
example_transparent_window_finalize (GObject *gobject)
{
// ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject));
/* Always chain up to the parent class; as with dispose(), finalize()
* is guaranteed to exist on the parent's class virtual function table
*/
G_OBJECT_CLASS (example_transparent_window_parent_class)->finalize (gobject);
}
// copied from gtk4 application window source code
GtkWidget *
example_transparent_window_new (GtkApplication *application)
{
g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
// using EXAMPLE_TYPE_TRANSPARENT_WINDOW throws critical runtime errors
return (GtkWidget *) g_object_new (GTK_TYPE_APPLICATION_WINDOW, "application",
application, NULL);
}
// end gtk4 source code
// end new subclass
static void
print_hello (GtkWidget *widget, gpointer data)
{
g_print ("Hello World\n");
// std::printf("Hello World\n");
}
static void
activate (GtkApplication *app, gpointer user_data)
{
#define WIDTH 800
#define HEIGHT 600
GtkWidget *window;
GtkWidget *button;
GtkWidget *fixed_container;
// works, but `example_transparent_window_snapshot` isn't getting called
window = example_transparent_window_new (app);
// window = gtk_application_window_new(app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
fixed_container = gtk_fixed_new ();
gtk_window_set_child (GTK_WINDOW (window), fixed_container);
gtk_fixed_put (GTK_FIXED (fixed_container), button, 20, 20);
gtk_widget_set_size_request (button, 400, 100);
gtk_window_present (GTK_WINDOW (window));
}
int
main (int argc, char *argv[])
{
GtkApplication *app;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return 0;
}
Thank you,
livphi