diff --git a/lib/meson.build b/lib/meson.build index 273dc3f..70f861e 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -25,6 +25,7 @@ libmks_headers = [ libmks_private_sources = [ 'mks-cairo-framebuffer.c', + 'mks-css.c', 'mks-read-only-list-model.c', gnome.gdbus_codegen('mks-qemu', @@ -33,7 +34,13 @@ libmks_private_sources = [ namespace: 'MksQemu', sources: 'dbus-display1.xml', object_manager: true, - ) + ), + + gnome.compile_resources( + 'mks-resources', + 'mks.gresource.xml', + c_name: 'mks', + ), ] libmks_enums = gnome.mkenums_simple('mks-enums', diff --git a/lib/mks-css-private.h b/lib/mks-css-private.h new file mode 100644 index 0000000..37ad649 --- /dev/null +++ b/lib/mks-css-private.h @@ -0,0 +1,29 @@ +/* mks-css-private.h + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +void _mks_css_init (void); + +G_END_DECLS diff --git a/lib/mks-css.c b/lib/mks-css.c new file mode 100644 index 0000000..11bb4ed --- /dev/null +++ b/lib/mks-css.c @@ -0,0 +1,40 @@ +/* mks-css.c + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include + +#include "mks-css-private.h" + +void +_mks_css_init (void) +{ + static GtkCssProvider *provider; + + if G_UNLIKELY (provider == NULL) + { + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (provider, "/org/gnome/libmks/style.css"); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + } +} diff --git a/lib/mks-display.c b/lib/mks-display.c index 44e8286..bfa3cea 100644 --- a/lib/mks-display.c +++ b/lib/mks-display.c @@ -20,17 +20,26 @@ #include "config.h" +#include "mks-css-private.h" #include "mks-display.h" #include "mks-screen.h" typedef struct { - GdkPaintable *paintable; - MksScreen *screen; + /* The screen being displayed. We've gotten a GdkPaintable from it + * which is connected to @picture for display. + */ + MksScreen *screen; + + /* The picture widget in our template which is rendering the screens + * painable when available. + */ + GtkPicture *picture; } MksDisplayPrivate; enum { PROP_0, + PROP_CONTENT_FIT, PROP_SCREEN, N_PROPS }; @@ -39,34 +48,6 @@ G_DEFINE_TYPE_WITH_PRIVATE (MksDisplay, mks_display, GTK_TYPE_WIDGET) static GParamSpec *properties [N_PROPS]; -static void -mks_display_snapshot (GtkWidget *widget, - GtkSnapshot *snapshot) -{ - MksDisplay *self = (MksDisplay *)widget; - MksDisplayPrivate *priv = mks_display_get_instance_private (self); - GtkAllocation alloc; - double width; - double height; - - g_assert (MKS_IS_DISPLAY (self)); - g_assert (GTK_IS_SNAPSHOT (snapshot)); - - if (priv->paintable == NULL) - return; - - gtk_widget_get_allocation (widget, &alloc); - - width = gdk_paintable_get_intrinsic_width (priv->paintable); - height = gdk_paintable_get_intrinsic_height (priv->paintable); - - gtk_snapshot_scale (snapshot, - alloc.width / width, - alloc.height / height); - - gdk_paintable_snapshot (priv->paintable, snapshot, width, height); -} - static void mks_display_attach_cb (GObject *object, GAsyncResult *result, @@ -87,21 +68,7 @@ mks_display_attach_cb (GObject *object, if (priv->screen != screen) return; - if (g_set_object (&priv->paintable, paintable)) - { - g_signal_connect_object (priv->paintable, - "invalidate-size", - G_CALLBACK (gtk_widget_queue_resize), - self, - G_CONNECT_SWAPPED); - g_signal_connect_object (priv->paintable, - "invalidate-contents", - G_CALLBACK (gtk_widget_queue_draw), - self, - G_CONNECT_SWAPPED); - } - - gtk_widget_queue_resize (GTK_WIDGET (self)); + gtk_picture_set_paintable (priv->picture, paintable); } static void @@ -129,49 +96,8 @@ mks_display_disconnect (MksDisplay *self) g_assert (MKS_IS_DISPLAY (self)); g_assert (priv->screen != NULL); + gtk_picture_set_paintable (priv->picture, NULL); g_clear_object (&priv->screen); - g_clear_object (&priv->paintable); -} - -static void -mks_display_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - MksDisplay *self = (MksDisplay *)widget; - MksDisplayPrivate *priv = mks_display_get_instance_private (self); - - g_assert (MKS_IS_DISPLAY (self)); - - *minimum_baseline = -1; - *natural_baseline = -1; - *minimum = 0; - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - if (priv->paintable != NULL) - *natural = gdk_paintable_get_intrinsic_width (priv->paintable); - else - *natural = 0; - } - else - { - if (priv->paintable != NULL) - *natural = gdk_paintable_get_intrinsic_width (priv->paintable) - * gdk_paintable_get_intrinsic_aspect_ratio (priv->paintable); - else - *natural = 0; - } -} - -static GtkSizeRequestMode -mks_display_get_request_mode (GtkWidget *widget) -{ - return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; } static void @@ -183,8 +109,7 @@ mks_display_dispose (GObject *object) if (priv->screen != NULL) mks_display_disconnect (self); - g_clear_object (&priv->paintable); - g_clear_object (&priv->screen); + g_clear_pointer ((GtkWidget **)&priv->picture, gtk_widget_unparent); G_OBJECT_CLASS (mks_display_parent_class)->dispose (object); } @@ -199,6 +124,10 @@ mks_display_get_property (GObject *object, switch (prop_id) { + case PROP_CONTENT_FIT: + g_value_set_enum (value, mks_display_get_content_fit (self)); + break; + case PROP_SCREEN: g_value_set_object (value, mks_display_get_screen (self)); break; @@ -218,6 +147,10 @@ mks_display_set_property (GObject *object, switch (prop_id) { + case PROP_CONTENT_FIT: + mks_display_set_content_fit (self, g_value_get_enum (value)); + break; + case PROP_SCREEN: mks_display_set_screen (self, g_value_get_object (value)); break; @@ -237,9 +170,11 @@ mks_display_class_init (MksDisplayClass *klass) object_class->get_property = mks_display_get_property; object_class->set_property = mks_display_set_property; - widget_class->snapshot = mks_display_snapshot; - widget_class->measure = mks_display_measure; - widget_class->get_request_mode = mks_display_get_request_mode; + properties [PROP_CONTENT_FIT] = + g_param_spec_enum ("content-fit", NULL, NULL, + GTK_TYPE_CONTENT_FIT, + GTK_CONTENT_FIT_SCALE_DOWN, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); properties[PROP_SCREEN] = g_param_spec_object ("screen", NULL, NULL, @@ -247,11 +182,19 @@ mks_display_class_init (MksDisplayClass *klass) (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_css_name (widget_class, "MksDisplay"); + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libmks/mks-display.ui"); + gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, picture); + + _mks_css_init (); } static void mks_display_init (MksDisplay *self) { + gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * @@ -297,3 +240,24 @@ mks_display_set_screen (MksDisplay *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCREEN]); } + +GtkContentFit +mks_display_get_content_fit (MksDisplay *self) +{ + MksDisplayPrivate *priv = mks_display_get_instance_private (self); + + g_return_val_if_fail (MKS_IS_DISPLAY (self), 0); + + return gtk_picture_get_content_fit (priv->picture); +} + +void +mks_display_set_content_fit (MksDisplay *self, + GtkContentFit content_fit) +{ + MksDisplayPrivate *priv = mks_display_get_instance_private (self); + + g_return_if_fail (MKS_IS_DISPLAY (self)); + + gtk_picture_set_content_fit (priv->picture, content_fit); +} diff --git a/lib/mks-display.h b/lib/mks-display.h index 8271872..41c7173 100644 --- a/lib/mks-display.h +++ b/lib/mks-display.h @@ -41,11 +41,16 @@ struct _MksDisplayClass }; MKS_AVAILABLE_IN_ALL -GtkWidget *mks_display_new (void); +GtkWidget *mks_display_new (void); MKS_AVAILABLE_IN_ALL -MksScreen *mks_display_get_screen (MksDisplay *self); +MksScreen *mks_display_get_screen (MksDisplay *self); MKS_AVAILABLE_IN_ALL -void mks_display_set_screen (MksDisplay *self, - MksScreen *screen); +void mks_display_set_screen (MksDisplay *self, + MksScreen *screen); +MKS_AVAILABLE_IN_ALL +GtkContentFit mks_display_get_content_fit (MksDisplay *self); +MKS_AVAILABLE_IN_ALL +void mks_display_set_content_fit (MksDisplay *self, + GtkContentFit content_fit); G_END_DECLS diff --git a/lib/mks-display.ui b/lib/mks-display.ui new file mode 100644 index 0000000..234135f --- /dev/null +++ b/lib/mks-display.ui @@ -0,0 +1,10 @@ + + + + diff --git a/lib/mks-init.c b/lib/mks-init.c index 90ecc96..cabb3e4 100644 --- a/lib/mks-init.c +++ b/lib/mks-init.c @@ -30,6 +30,7 @@ #include "mks-paintable-private.h" #include "mks-qemu.h" #include "mks-read-only-list-model-private.h" +#include "mks-resources.h" #include "mks-screen.h" #include "mks-screen-attributes.h" #include "mks-session.h" @@ -38,6 +39,8 @@ static void mks_init_gtypes (void) { + g_resources_register (mks_get_resource ()); + /* First register GTypes for Qemu IPC */ g_type_ensure (MKS_QEMU_TYPE_AUDIO); g_type_ensure (MKS_QEMU_TYPE_AUDIO_IN_LISTENER); diff --git a/lib/mks-paintable.c b/lib/mks-paintable.c index 8053d5d..18cef9b 100644 --- a/lib/mks-paintable.c +++ b/lib/mks-paintable.c @@ -190,9 +190,6 @@ mks_paintable_set_framebuffer (MksPaintable *self, if (framebuffer != NULL) { - g_print ("Framebuffer set to %ux%u\n", - mks_cairo_framebuffer_get_width (framebuffer), - mks_cairo_framebuffer_get_height (framebuffer)); self->framebuffer = g_object_ref (framebuffer); g_signal_connect_object (self->framebuffer, "invalidate-size", diff --git a/lib/mks.gresource.xml b/lib/mks.gresource.xml new file mode 100644 index 0000000..92be702 --- /dev/null +++ b/lib/mks.gresource.xml @@ -0,0 +1,7 @@ + + + + mks-display.ui + style.css + + diff --git a/lib/style.css b/lib/style.css new file mode 100644 index 0000000..69ba225 --- /dev/null +++ b/lib/style.css @@ -0,0 +1,3 @@ +MksDisplay { + background: black; +}