diff options
| author | Kane Scipioni <[email protected]> | 2025-08-23 07:54:58 -0500 |
|---|---|---|
| committer | Victor Kareh <[email protected]> | 2025-10-09 17:27:39 +0000 |
| commit | e89ae9d58dc08737a1eb12d0853ac09709db88e3 (patch) | |
| tree | 7179e2d9b1b69e8cbbadab61bbd41abfb0f616be | |
| parent | 9af00887ad2abd8f4b9e64e1a41e1e4907bebb43 (diff) | |
| download | mate-screensaver-e89ae9d58dc08737a1eb12d0853ac09709db88e3.tar.bz2 mate-screensaver-e89ae9d58dc08737a1eb12d0853ac09709db88e3.tar.xz | |
Added starfield screensaver
| -rw-r--r-- | savers/Makefile.am | 19 | ||||
| -rw-r--r-- | savers/gste-starfield.c | 424 | ||||
| -rw-r--r-- | savers/gste-starfield.h | 57 | ||||
| -rw-r--r-- | savers/starfield.c | 135 | ||||
| -rw-r--r-- | savers/starfield.desktop.in.in | 12 |
5 files changed, 647 insertions, 0 deletions
diff --git a/savers/Makefile.am b/savers/Makefile.am index c81eab7..4b5b089 100644 --- a/savers/Makefile.am +++ b/savers/Makefile.am @@ -20,6 +20,7 @@ DESKTOP_IN_IN_FILES = \ gnomelogo-floaters.desktop.in.in \ personal-slideshow.desktop.in.in \ popsquares.desktop.in.in \ + starfield.desktop.in.in \ $(NULL) cosmos-slideshow.desktop.in: cosmos-slideshow.desktop.in.in Makefile @@ -32,6 +33,8 @@ personal-slideshow.desktop.in: personal-slideshow.desktop.in.in Makefile @$(edit) $< >$@ popsquares.desktop.in: popsquares.desktop.in.in Makefile @$(edit) $< >$@ +starfield.desktop.in: starfield.desktop.in.in Makefile + @$(edit) $< >$@ edit = sed \ -e 's|@SLIDESHOW_COSMOS_DIR[@]|$(SLIDESHOW_COSMOS_DIR)|g' \ @@ -49,6 +52,7 @@ themes_in_files = \ gnomelogo-floaters.desktop.in \ personal-slideshow.desktop.in \ popsquares.desktop.in \ + starfield.desktop.in \ $(NULL) themes_DATA = $(themes_in_files:.desktop.in=.desktop) @@ -85,6 +89,7 @@ saver_PROGRAMS = \ floaters \ popsquares \ slideshow \ + starfield \ $(NULL) floaters_SOURCES = \ @@ -121,6 +126,18 @@ slideshow_LDADD = \ $(MATE_SCREENSAVER_SAVER_LIBS) \ $(NULL) +starfield_SOURCES = \ + gste-starfield.c \ + gste-starfield.h \ + starfield.c \ + $(NULL) + +starfield_LDADD = \ + libgs-theme-engine.a \ + $(MATE_SCREENSAVER_SAVER_LIBS) \ + -lm \ + $(NULL) + EXTRA_DIST = \ gs-theme-engine-marshal.list \ $(DESKTOP_IN_IN_FILES) \ @@ -134,6 +151,7 @@ CLEANFILES = \ gnomelogo-floaters.desktop.in \ popsquares.desktop.in \ personal-slideshow.desktop.in \ + starfield.desktop.in \ $(NULL) DISTCLEANFILES = \ @@ -148,6 +166,7 @@ MAINTAINERCLEANFILES = \ gnomelogo-floaters.desktop \ personal-slideshow.desktop \ popsquares.desktop \ + starfield.desktop \ $(NULL) -include $(top_srcdir)/git.mk diff --git a/savers/gste-starfield.c b/savers/gste-starfield.c new file mode 100644 index 0000000..691f28b --- /dev/null +++ b/savers/gste-starfield.c @@ -0,0 +1,424 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- + * + * Copyright (C) 2025 Kane Scipioni <[email protected]> + * Copyright (C) 2012-2025 MATE Developers + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include "config.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <glib.h> +#include <gtk/gtk.h> + +#include "gs-theme-engine.h" +#include "gste-starfield.h" + +static void gste_starfield_finalize (GObject *object); +static void draw_frame (GSTEStarfield *sf, + cairo_t *cr); + +typedef struct _point +{ + gdouble x, y, z; +} point; + +struct GSTEStarfieldPrivate +{ + guint timeout_id; + int64_t timestamp; + unsigned int count; + double speed; + double current_speed; + double acceleration; + guint delay; + double size; + point *stars; +}; + +enum +{ + PROP_0, + PROP_COUNT, + PROP_SPEED, + PROP_ACCEL, + PROP_DELAY, + PROP_SIZE +}; + +static GObjectClass *parent_class = NULL; + +G_DEFINE_TYPE_WITH_PRIVATE (GSTEStarfield, gste_starfield, GS_TYPE_THEME_ENGINE) + +#define Z_NEAR 0.0 +#define Z_FAR 1.0 +#define XY_CLIP_LIMIT 0.5 + +#define DEFAULT_ACCELERATION 1.0 +#define MAX_ACCELERATION 10.0 +#define MIN_ACCELERATION 0.1 + +#define DEFAULT_SPEED 3.0 +#define MAX_SPEED 10.0 +#define MIN_SPEED 1.0 +#define SPEED_FACTOR 0.25 + +#define DEFAULT_COUNT 200 +#define MAX_COUNT 500 +#define MIN_COUNT 1 + +#define DEFAULT_DELAY 15 +#define MAX_DELAY 33 +#define MIN_DELAY 5 + +#define DEFAULT_SIZE 8 +#define MAX_SIZE 20 +#define MIN_SIZE 1 +#define SIZE_RATIO 0.001 + +static void +gste_starfield_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GSTEStarfield *self; + + self = GSTE_STARFIELD (object); + + switch (prop_id) + { + case PROP_COUNT: + self->priv->count = g_value_get_int (value); + break; + case PROP_SPEED: + self->priv->speed = g_value_get_double (value); + break; + case PROP_ACCEL: + self->priv->acceleration = g_value_get_double (value); + break; + case PROP_DELAY: + self->priv->delay = g_value_get_int (value); + break; + case PROP_SIZE: + self->priv->size = g_value_get_double (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gste_starfield_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GSTEStarfield *self; + + self = GSTE_STARFIELD (object); + + switch (prop_id) + { + case PROP_COUNT: + g_value_set_int (value, self->priv->count); + break; + case PROP_SPEED: + g_value_set_double (value, self->priv->speed); + break; + case PROP_ACCEL: + g_value_set_double (value, self->priv->acceleration); + break; + case PROP_DELAY: + g_value_set_int (value, self->priv->delay); + break; + case PROP_SIZE: + g_value_set_double (value, self->priv->size); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +setup_stars (GSTEStarfield *sf) +{ + int i; + + if (sf->priv->stars) + { + g_free (sf->priv->stars); + } + sf->priv->stars = g_new(point, sf->priv->count); + + for (i = 0; i < sf->priv->count; ++i) + { + point *s = &sf->priv->stars[i]; + s->z = -cbrt(g_random_double() - 1); /* icdf for beta(1, 3) distribution */ + s->x = s->z * g_random_double_range(-XY_CLIP_LIMIT, XY_CLIP_LIMIT); + s->y = s->z * g_random_double_range(-XY_CLIP_LIMIT, XY_CLIP_LIMIT); + } + sf->priv->timestamp = g_get_monotonic_time (); + sf->priv->current_speed = 0.0; +} + +static double +get_elapsed_time (GSTEStarfield *sf) +{ + int64_t prev_timestamp = sf->priv->timestamp; + + sf->priv->timestamp = g_get_monotonic_time (); + + int64_t elapsed = sf->priv->timestamp - prev_timestamp; + + return (double)elapsed / 1e6; +} + +static gboolean +draw_iter (GSTEStarfield *sf) +{ + gtk_widget_queue_draw (GTK_WIDGET (sf)); + return TRUE; +} + +static void +gste_starfield_real_show (GtkWidget *widget) +{ + GSTEStarfield *sf = GSTE_STARFIELD (widget); + + /* start */ + setup_stars (sf); + + if (sf->priv->timeout_id > 0) + { + g_source_remove (sf->priv->timeout_id); + } + sf->priv->timeout_id = g_timeout_add (sf->priv->delay, + (GSourceFunc)draw_iter, + sf); + + if (GTK_WIDGET_CLASS (parent_class)->show) + { + GTK_WIDGET_CLASS (parent_class)->show (widget); + } +} + +static gboolean +gste_starfield_real_draw (GtkWidget *widget, + cairo_t *cr) +{ + if (GTK_WIDGET_CLASS (parent_class)->draw) { + GTK_WIDGET_CLASS (parent_class)->draw (widget, cr); + } + + draw_frame (GSTE_STARFIELD (widget), cr); + + return TRUE; +} + +static gboolean +gste_starfield_real_configure (GtkWidget *widget, + GdkEventConfigure *event) +{ + GSTEStarfield *sf = GSTE_STARFIELD (widget); + gboolean handled = FALSE; + + /* resize */ + + /* just reset everything */ + setup_stars (sf); + + /* schedule a redraw */ + gtk_widget_queue_draw (widget); + + if (GTK_WIDGET_CLASS (parent_class)->configure_event) + { + handled = GTK_WIDGET_CLASS (parent_class)->configure_event (widget, event); + } + + return handled; +} + +static void +gste_starfield_class_init (GSTEStarfieldClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gste_starfield_finalize; + object_class->get_property = gste_starfield_get_property; + object_class->set_property = gste_starfield_set_property; + + widget_class->show = gste_starfield_real_show; + widget_class->draw = gste_starfield_real_draw; + widget_class->configure_event = gste_starfield_real_configure; + + g_object_class_install_property (object_class, + PROP_COUNT, + g_param_spec_int ("count", + NULL, + NULL, + MIN_COUNT, + MAX_COUNT, + DEFAULT_COUNT, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SPEED, + g_param_spec_double ("speed", + NULL, + NULL, + MIN_SPEED, + MAX_SPEED, + DEFAULT_SPEED, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ACCEL, + g_param_spec_double ("acceleration", + NULL, + NULL, + MIN_ACCELERATION, + MAX_ACCELERATION, + DEFAULT_ACCELERATION, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_DELAY, + g_param_spec_int ("delay", + NULL, + NULL, + MIN_DELAY, + MAX_DELAY, + DEFAULT_DELAY, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SIZE, + g_param_spec_double ("size", + NULL, + NULL, + MIN_SIZE, + MAX_SIZE, + DEFAULT_SIZE, + G_PARAM_READWRITE)); +} + +static void +draw_frame (GSTEStarfield *sf, + cairo_t *cr) +{ + int i; + int window_width; + int window_height; + GdkWindow *window; + + window = gs_theme_engine_get_window (GS_THEME_ENGINE (sf)); + + if (window == NULL) + { + return; + } + + gs_theme_engine_get_window_size (GS_THEME_ENGINE (sf), + &window_width, + &window_height); + + double elapsed = get_elapsed_time(sf); + double speed = sf->priv->current_speed; + double step = SPEED_FACTOR * speed * elapsed; + double max_radius = fmax(sf->priv->size * SIZE_RATIO * window_height, 1); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_FAST); + + for (i = 0; i < sf->priv->count; ++i) + { + point *s = &sf->priv->stars[i]; + + s->z -= step; + + if (s->z <= Z_NEAR || + s->x > s->z * XY_CLIP_LIMIT || + s->x < s->z * -XY_CLIP_LIMIT || + s->y > s->z * XY_CLIP_LIMIT || + s->y < s->z * -XY_CLIP_LIMIT) + { + s->z = Z_FAR - g_random_double_range(0, fmin(step, Z_FAR - Z_NEAR)); + s->x = s->z * g_random_double_range(-XY_CLIP_LIMIT, XY_CLIP_LIMIT); + s->y = s->z * g_random_double_range(-XY_CLIP_LIMIT, XY_CLIP_LIMIT); + } + + double x = (s->x / s->z + XY_CLIP_LIMIT) * window_width; + double y = (s->y / s->z + XY_CLIP_LIMIT) * window_height; + double illum = 1.0 / (1.0 + s->z); + illum *= illum; + double radius = max_radius * (1.0 - s->z); + + cairo_set_source_rgb (cr, illum, illum, illum); + cairo_set_line_width (cr, radius); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y); + cairo_stroke (cr); + } + if (speed != sf->priv->speed) + { + speed += sf->priv->acceleration * elapsed; + sf->priv->current_speed = fmin(speed, sf->priv->speed); + } +} + +static void +gste_starfield_init (GSTEStarfield *sf) +{ + sf->priv = gste_starfield_get_instance_private (sf); + + sf->priv->count = DEFAULT_COUNT; + sf->priv->speed = DEFAULT_SPEED; + sf->priv->acceleration = DEFAULT_ACCELERATION; + sf->priv->delay = DEFAULT_DELAY; + sf->priv->size = DEFAULT_SIZE; +} + +static void +gste_starfield_finalize (GObject *object) +{ + GSTEStarfield *sf; + + g_return_if_fail (object != NULL); + g_return_if_fail (GSTE_IS_STARFIELD (object)); + + sf = GSTE_STARFIELD (object); + + g_return_if_fail (sf->priv != NULL); + + if (sf->priv->timeout_id > 0) + { + g_source_remove (sf->priv->timeout_id); + sf->priv->timeout_id = 0; + } + + g_free (sf->priv->stars); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} diff --git a/savers/gste-starfield.h b/savers/gste-starfield.h new file mode 100644 index 0000000..a459d8d --- /dev/null +++ b/savers/gste-starfield.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2025 Kane Scipioni <[email protected]> + * Copyright (C) 2012-2025 MATE Developers + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + */ + +#ifndef __GSTE_STARFIELD_H +#define __GSTE_STARFIELD_H + +#include <glib.h> +#include <gdk/gdk.h> +#include "gs-theme-engine.h" + +G_BEGIN_DECLS + +#define GSTE_TYPE_STARFIELD (gste_starfield_get_type ()) +#define GSTE_STARFIELD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSTE_TYPE_STARFIELD, GSTEStarfield)) +#define GSTE_STARFIELD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSTE_TYPE_STARFIELD, GSTEStarfieldClass)) +#define GSTE_IS_STARFIELD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSTE_TYPE_STARFIELD)) +#define GSTE_IS_STARFIELD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSTE_TYPE_STARFIELD)) +#define GSTE_STARFIELD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSTE_TYPE_STARFIELD, GSTEStarfieldClass)) + +typedef struct GSTEStarfieldPrivate GSTEStarfieldPrivate; + +typedef struct +{ + GSThemeEngine parent; + GSTEStarfieldPrivate *priv; +} GSTEStarfield; + +typedef struct +{ + GSThemeEngineClass parent_class; +} GSTEStarfieldClass; + +GType gste_starfield_get_type (void); +GSThemeEngine *gste_starfield_new (void); + +G_END_DECLS + +#endif /* __GSTE_STARFIELD_H */ diff --git a/savers/starfield.c b/savers/starfield.c new file mode 100644 index 0000000..ce8bdbc --- /dev/null +++ b/savers/starfield.c @@ -0,0 +1,135 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- + * + * Copyright (C) 2025 Kane Scipioni <[email protected]> + * Copyright (C) 2012-2025 MATE Developers + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <gtk/gtk.h> + +#include <glib/gi18n.h> + +#include "gs-theme-window.h" +#include "gs-theme-engine.h" +#include "gste-starfield.h" + +int +main (int argc, char **argv) +{ + GSThemeEngine *engine; + GtkWidget *window; + GError *error; + gboolean ret; + gint count = 0; + gdouble speed = 0.0; + gdouble acceleration = 0.0; + gint delay = 0; + gdouble size = 0.0; + GOptionEntry entries [] = + { + { + "count", 'c', 0, G_OPTION_ARG_INT, &count, + N_("Number of stars [1-500]"), N_("NUM") + }, + { + "speed", 's', 0, G_OPTION_ARG_DOUBLE, &speed, + N_("Speed of camera [1.0-10.0]"), N_("RATE") + }, + { + "acceleration", 'a', 0, G_OPTION_ARG_DOUBLE, &acceleration, + N_("Acceleration of camera [0.1-10.0]"), N_("ACCEL") + }, + { + "delay", 'd', 0, G_OPTION_ARG_INT, &delay, + N_("Time between frames [5-33]"), N_("MSEC") + }, + { + "size", 'r', 0, G_OPTION_ARG_DOUBLE, &size, + N_("Max radius of stars [1-20]"), N_("RADIUS") + }, + { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } + }; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + error = NULL; + + ret = gtk_init_with_args (&argc, &argv, + NULL, + entries, + NULL, + &error); + if (!ret) + { + g_printerr (_("%s. See --help for usage information.\n"), + error->message); + g_error_free (error); + exit (1); + } + + window = gs_theme_window_new (); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), + NULL); + + g_set_prgname ("starfield"); + + engine = g_object_new (GSTE_TYPE_STARFIELD, NULL); + + if (count) + { + g_object_set (engine, "count", count, NULL); + } + + if (speed) + { + g_object_set (engine, "speed", speed, NULL); + } + + if (acceleration) + { + g_object_set (engine, "acceleration", acceleration, NULL); + } + + if (delay) + { + g_object_set (engine, "delay", delay, NULL); + } + + if (size) + { + g_object_set (engine, "size", size, NULL); + } + + gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (engine)); + + gtk_widget_show (GTK_WIDGET (engine)); + + gtk_window_set_default_size (GTK_WINDOW (window), 640, 480); + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/savers/starfield.desktop.in.in b/savers/starfield.desktop.in.in new file mode 100644 index 0000000..44b92df --- /dev/null +++ b/savers/starfield.desktop.in.in @@ -0,0 +1,12 @@ +[Desktop Entry] +Name=Starfield +Comment=Fly through space. +Exec=@SAVERDIR@/starfield +TryExec=@SAVERDIR@/starfield +StartupNotify=false +Terminal=false +Type=Application +Categories=Screensaver; +# Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! +Keywords=MATE;screensaver;space;stars; +OnlyShowIn=MATE; |
