/* ScreencastIcon.c generated by valac 0.56.19, the Vala compiler
 * generated from ScreencastIcon.vala, do not modify */

/*
* Budgie Screencast
* Author: Sam Lane
* Copyright © 2026 Ubuntu Budgie Developers
* Website=https://ubuntubudgie.org
* 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 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
* <https://www.gnu.org/licenses/>.
*/
/*
 * ScreencastIcon — panel icon with a state-driven indicator overlay
 *
 * The base icon (budgie-screencast-symbolic) is always visible. Overlaid on
 * its bottom-right corner is a shared DrawingArea that renders differently
 * depending on the current state:
 *
 *   IDLE      → indicator hidden
 *   PENDING   → amber filled circle with a white countdown digit (14×14 px)
 *               shown during the final 5 seconds before recording starts or stops
 *   RECORDING → small red dot (10×10 px) that blinks at 0.5 Hz
 *
 * The indicator is sized differently in each state because the countdown badge
 * needs to accommodate a digit (14 px gives enough room for Cairo text layout),
 * while the recording dot is intentionally small and unobtrusive (10 px).
 *
 */

#include "budgie-screencast.h"
#include <gtk/gtk.h>
#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
#include <cairo-gobject.h>
#include <float.h>
#include <math.h>

#if !defined(VALA_STRICT_C)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
#elif defined(__clang__) && (__clang_major__ >= 16)
#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#endif
#endif

typedef enum  {
	SCREENCAST_ICON_STATE_IDLE,
	SCREENCAST_ICON_STATE_PENDING,
	SCREENCAST_ICON_STATE_RECORDING
} ScreencastIconState;

#define SCREENCAST_ICON_TYPE_STATE (screencast_icon_state_get_type ())
enum  {
	SCREENCAST_ICON_0_PROPERTY,
	SCREENCAST_ICON_NUM_PROPERTIES
};
static GParamSpec* screencast_icon_properties[SCREENCAST_ICON_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))

struct _ScreencastIconPrivate {
	GtkOverlay* overlay;
	GtkImage* base_icon;
	GtkDrawingArea* indicator;
	guint timeout_id;
	gboolean flash_state;
	ScreencastIconState state;
	gint countdown;
};

static gint ScreencastIcon_private_offset;
static gpointer screencast_icon_parent_class = NULL;
static GType screencast_icon_type_id = 0;

static GType screencast_icon_state_get_type (void) G_GNUC_CONST  G_GNUC_UNUSED ;
static gboolean screencast_icon_on_draw_indicator (ScreencastIcon* self,
                                            cairo_t* cr);
static gboolean _screencast_icon_on_draw_indicator_gtk_widget_draw (GtkWidget* _sender,
                                                             cairo_t* cr,
                                                             gpointer self);
static void screencast_icon_transition_to (ScreencastIcon* self,
                                    ScreencastIconState next,
                                    gint cd);
static void screencast_icon_stop_timer (ScreencastIcon* self);
static void screencast_icon_start_flash_timer (ScreencastIcon* self);
static void screencast_icon_draw_dot (ScreencastIcon* self,
                               cairo_t* cr);
static void screencast_icon_draw_countdown_badge (ScreencastIcon* self,
                                           cairo_t* cr);
static gboolean __lambda5_ (ScreencastIcon* self);
static gboolean ___lambda5__gsource_func (gpointer self);
static void screencast_icon_finalize (GObject * obj);

static inline gpointer
screencast_icon_get_instance_private (ScreencastIcon* self)
{
	return G_STRUCT_MEMBER_P (self, ScreencastIcon_private_offset);
}

static GType
screencast_icon_state_get_type_once (void)
{
	static const GEnumValue values[] = {{SCREENCAST_ICON_STATE_IDLE, "SCREENCAST_ICON_STATE_IDLE", "idle"}, {SCREENCAST_ICON_STATE_PENDING, "SCREENCAST_ICON_STATE_PENDING", "pending"}, {SCREENCAST_ICON_STATE_RECORDING, "SCREENCAST_ICON_STATE_RECORDING", "recording"}, {0, NULL, NULL}};
	GType screencast_icon_state_type_id;
	screencast_icon_state_type_id = g_enum_register_static ("ScreencastIconState", values);
	return screencast_icon_state_type_id;
}

static GType
screencast_icon_state_get_type (void)
{
	static volatile gsize screencast_icon_state_type_id__once = 0;
	if (g_once_init_enter (&screencast_icon_state_type_id__once)) {
		GType screencast_icon_state_type_id;
		screencast_icon_state_type_id = screencast_icon_state_get_type_once ();
		g_once_init_leave (&screencast_icon_state_type_id__once, screencast_icon_state_type_id);
	}
	return screencast_icon_state_type_id__once;
}

static gboolean
_screencast_icon_on_draw_indicator_gtk_widget_draw (GtkWidget* _sender,
                                                    cairo_t* cr,
                                                    gpointer self)
{
	gboolean result;
	result = screencast_icon_on_draw_indicator ((ScreencastIcon*) self, cr);
	return result;
}

ScreencastIcon*
screencast_icon_construct (GType object_type,
                           const gchar* icon_name)
{
	ScreencastIcon * self = NULL;
	GtkOverlay* _tmp0_;
	GtkOverlay* _tmp1_;
	GtkImage* _tmp2_;
	GtkOverlay* _tmp3_;
	GtkImage* _tmp4_;
	GtkDrawingArea* _tmp5_;
	GtkDrawingArea* _tmp6_;
	GtkDrawingArea* _tmp7_;
	GtkDrawingArea* _tmp8_;
	GtkDrawingArea* _tmp9_;
	GtkDrawingArea* _tmp10_;
	GtkDrawingArea* _tmp11_;
	GtkOverlay* _tmp12_;
	GtkDrawingArea* _tmp13_;
	GtkDrawingArea* _tmp14_;
	g_return_val_if_fail (icon_name != NULL, NULL);
	self = (ScreencastIcon*) g_object_new (object_type, NULL);
	gtk_event_box_set_visible_window ((GtkEventBox*) self, FALSE);
	_tmp0_ = (GtkOverlay*) gtk_overlay_new ();
	g_object_ref_sink (_tmp0_);
	_g_object_unref0 (self->priv->overlay);
	self->priv->overlay = _tmp0_;
	_tmp1_ = self->priv->overlay;
	gtk_container_add ((GtkContainer*) self, (GtkWidget*) _tmp1_);
	_tmp2_ = (GtkImage*) gtk_image_new_from_icon_name (icon_name, (GtkIconSize) GTK_ICON_SIZE_BUTTON);
	g_object_ref_sink (_tmp2_);
	_g_object_unref0 (self->priv->base_icon);
	self->priv->base_icon = _tmp2_;
	_tmp3_ = self->priv->overlay;
	_tmp4_ = self->priv->base_icon;
	gtk_container_add ((GtkContainer*) _tmp3_, (GtkWidget*) _tmp4_);
	_tmp5_ = (GtkDrawingArea*) gtk_drawing_area_new ();
	g_object_ref_sink (_tmp5_);
	_g_object_unref0 (self->priv->indicator);
	self->priv->indicator = _tmp5_;
	_tmp6_ = self->priv->indicator;
	gtk_widget_set_size_request ((GtkWidget*) _tmp6_, 10, 10);
	_tmp7_ = self->priv->indicator;
	gtk_widget_set_halign ((GtkWidget*) _tmp7_, GTK_ALIGN_END);
	_tmp8_ = self->priv->indicator;
	gtk_widget_set_valign ((GtkWidget*) _tmp8_, GTK_ALIGN_END);
	_tmp9_ = self->priv->indicator;
	gtk_widget_set_margin_bottom ((GtkWidget*) _tmp9_, 10);
	_tmp10_ = self->priv->indicator;
	gtk_widget_set_margin_end ((GtkWidget*) _tmp10_, 0);
	_tmp11_ = self->priv->indicator;
	g_signal_connect_object ((GtkWidget*) _tmp11_, "draw", (GCallback) _screencast_icon_on_draw_indicator_gtk_widget_draw, self, 0);
	_tmp12_ = self->priv->overlay;
	_tmp13_ = self->priv->indicator;
	gtk_overlay_add_overlay (_tmp12_, (GtkWidget*) _tmp13_);
	gtk_widget_show_all ((GtkWidget*) self);
	_tmp14_ = self->priv->indicator;
	gtk_widget_hide ((GtkWidget*) _tmp14_);
	return self;
}

ScreencastIcon*
screencast_icon_new (const gchar* icon_name)
{
	return screencast_icon_construct (TYPE_SCREENCAST_ICON, icon_name);
}

void
screencast_icon_set_recording (ScreencastIcon* self,
                               gboolean recording)
{
	g_return_if_fail (self != NULL);
	if (recording) {
		screencast_icon_transition_to (self, SCREENCAST_ICON_STATE_RECORDING, 0);
	} else {
		if (self->priv->state == SCREENCAST_ICON_STATE_RECORDING) {
			screencast_icon_transition_to (self, SCREENCAST_ICON_STATE_IDLE, 0);
		}
	}
}

void
screencast_icon_set_pending (ScreencastIcon* self,
                             gboolean pending,
                             gint seconds)
{
	g_return_if_fail (self != NULL);
	if (pending) {
		screencast_icon_transition_to (self, SCREENCAST_ICON_STATE_PENDING, seconds);
	} else {
		if (self->priv->state == SCREENCAST_ICON_STATE_PENDING) {
			screencast_icon_transition_to (self, SCREENCAST_ICON_STATE_IDLE, 0);
		}
	}
}

void
screencast_icon_update_countdown (ScreencastIcon* self,
                                  gint seconds)
{
	GtkDrawingArea* _tmp0_;
	g_return_if_fail (self != NULL);
	if (self->priv->state != SCREENCAST_ICON_STATE_PENDING) {
		return;
	}
	self->priv->countdown = seconds;
	_tmp0_ = self->priv->indicator;
	gtk_widget_queue_draw ((GtkWidget*) _tmp0_);
}

static void
screencast_icon_transition_to (ScreencastIcon* self,
                               ScreencastIconState next,
                               gint cd)
{
	g_return_if_fail (self != NULL);
	screencast_icon_stop_timer (self);
	self->priv->state = next;
	self->priv->countdown = cd;
	switch (self->priv->state) {
		case SCREENCAST_ICON_STATE_IDLE:
		{
			GtkDrawingArea* _tmp0_;
			_tmp0_ = self->priv->indicator;
			gtk_widget_hide ((GtkWidget*) _tmp0_);
			break;
		}
		case SCREENCAST_ICON_STATE_PENDING:
		{
			GtkDrawingArea* _tmp1_;
			GtkDrawingArea* _tmp2_;
			GtkDrawingArea* _tmp3_;
			_tmp1_ = self->priv->indicator;
			gtk_widget_set_size_request ((GtkWidget*) _tmp1_, 14, 14);
			_tmp2_ = self->priv->indicator;
			gtk_widget_show ((GtkWidget*) _tmp2_);
			_tmp3_ = self->priv->indicator;
			gtk_widget_queue_draw ((GtkWidget*) _tmp3_);
			break;
		}
		case SCREENCAST_ICON_STATE_RECORDING:
		{
			GtkDrawingArea* _tmp4_;
			GtkDrawingArea* _tmp5_;
			_tmp4_ = self->priv->indicator;
			gtk_widget_set_size_request ((GtkWidget*) _tmp4_, 10, 10);
			self->priv->flash_state = TRUE;
			_tmp5_ = self->priv->indicator;
			gtk_widget_show ((GtkWidget*) _tmp5_);
			screencast_icon_start_flash_timer (self);
			break;
		}
		default:
		break;
	}
}

static gboolean
screencast_icon_on_draw_indicator (ScreencastIcon* self,
                                   cairo_t* cr)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (cr != NULL, FALSE);
	switch (self->priv->state) {
		case SCREENCAST_ICON_STATE_RECORDING:
		{
			screencast_icon_draw_dot (self, cr);
			break;
		}
		case SCREENCAST_ICON_STATE_PENDING:
		{
			screencast_icon_draw_countdown_badge (self, cr);
			break;
		}
		default:
		{
			break;
		}
	}
	result = FALSE;
	return result;
}

static void
screencast_icon_draw_dot (ScreencastIcon* self,
                          cairo_t* cr)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (cr != NULL);
	cairo_arc (cr, (gdouble) 5, (gdouble) 5, (gdouble) 4, (gdouble) 0, 2 * G_PI);
	cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
	cairo_fill (cr);
}

static void
screencast_icon_draw_countdown_badge (ScreencastIcon* self,
                                      cairo_t* cr)
{
	gchar* text = NULL;
	gchar* _tmp0_;
	cairo_text_extents_t ext = {0};
	cairo_text_extents_t _tmp1_ = {0};
	cairo_text_extents_t _tmp2_;
	cairo_text_extents_t _tmp3_;
	cairo_text_extents_t _tmp4_;
	cairo_text_extents_t _tmp5_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (cr != NULL);
	cairo_arc (cr, (gdouble) 7, (gdouble) 7, 6.5, (gdouble) 0, 2 * G_PI);
	cairo_set_source_rgb (cr, 1.0, 0.65, 0.0);
	cairo_fill (cr);
	cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
	cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size (cr, 8.0);
	_tmp0_ = g_strdup_printf ("%i", self->priv->countdown);
	text = _tmp0_;
	cairo_text_extents (cr, text, &_tmp1_);
	ext = _tmp1_;
	_tmp2_ = ext;
	_tmp3_ = ext;
	_tmp4_ = ext;
	_tmp5_ = ext;
	cairo_move_to (cr, (7 - (_tmp2_.width / 2)) - _tmp3_.x_bearing, (7 - (_tmp4_.height / 2)) - _tmp5_.y_bearing);
	cairo_show_text (cr, text);
	_g_free0 (text);
}

static gboolean
__lambda5_ (ScreencastIcon* self)
{
	GtkDrawingArea* _tmp0_;
	gboolean result;
	self->priv->flash_state = !self->priv->flash_state;
	_tmp0_ = self->priv->indicator;
	gtk_widget_set_visible ((GtkWidget*) _tmp0_, self->priv->flash_state);
	result = TRUE;
	return result;
}

static gboolean
___lambda5__gsource_func (gpointer self)
{
	gboolean result;
	result = __lambda5_ ((ScreencastIcon*) self);
	return result;
}

static void
screencast_icon_start_flash_timer (ScreencastIcon* self)
{
	g_return_if_fail (self != NULL);
	if (self->priv->timeout_id != ((guint) 0)) {
		return;
	}
	self->priv->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT, (guint) 500, ___lambda5__gsource_func, g_object_ref (self), g_object_unref);
}

static void
screencast_icon_stop_timer (ScreencastIcon* self)
{
	g_return_if_fail (self != NULL);
	if (self->priv->timeout_id != ((guint) 0)) {
		g_source_remove (self->priv->timeout_id);
		self->priv->timeout_id = (guint) 0;
	}
	self->priv->flash_state = TRUE;
}

static void
screencast_icon_class_init (ScreencastIconClass * klass,
                            gpointer klass_data)
{
	screencast_icon_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &ScreencastIcon_private_offset);
	G_OBJECT_CLASS (klass)->finalize = screencast_icon_finalize;
}

static void
screencast_icon_instance_init (ScreencastIcon * self,
                               gpointer klass)
{
	self->priv = screencast_icon_get_instance_private (self);
	self->priv->timeout_id = (guint) 0;
	self->priv->flash_state = TRUE;
	self->priv->state = SCREENCAST_ICON_STATE_IDLE;
	self->priv->countdown = 0;
}

static void
screencast_icon_finalize (GObject * obj)
{
	ScreencastIcon * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_SCREENCAST_ICON, ScreencastIcon);
	_g_object_unref0 (self->priv->overlay);
	_g_object_unref0 (self->priv->base_icon);
	_g_object_unref0 (self->priv->indicator);
	G_OBJECT_CLASS (screencast_icon_parent_class)->finalize (obj);
}

GType
screencast_icon_get_type (void)
{
	return screencast_icon_type_id;
}

GType
screencast_icon_register_type (GTypeModule * module)
{
	static const GTypeInfo g_define_type_info = { sizeof (ScreencastIconClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) screencast_icon_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ScreencastIcon), 0, (GInstanceInitFunc) screencast_icon_instance_init, NULL };
	screencast_icon_type_id = g_type_module_register_type (module, gtk_event_box_get_type (), "ScreencastIcon", &g_define_type_info, 0);
	ScreencastIcon_private_offset = sizeof (ScreencastIconPrivate);
	return screencast_icon_type_id;
}

