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

/**/
/*  Copyright 2020 elementary, Inc. (https://elementary.io)*/
/**/
/*  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 <http://www.gnu.org/licenses/>.*/
/**/

#include "gala.h"
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <gio/gdesktopappinfo.h>
#include <gio/gio.h>
#include <glib-object.h>

#define GALA_APP_CACHE_DEFAULT_TIMEOUT_SECONDS 3

enum  {
	GALA_APP_CACHE_0_PROPERTY,
	GALA_APP_CACHE_NUM_PROPERTIES
};
static GParamSpec* gala_app_cache_properties[GALA_APP_CACHE_NUM_PROPERTIES];
#define _g_hash_table_unref0(var) ((var == NULL) ? NULL : (var = (g_hash_table_unref (var), NULL)))
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
typedef struct _Block1Data Block1Data;
#define _g_thread_unref0(var) ((var == NULL) ? NULL : (var = (g_thread_unref (var), NULL)))
typedef struct _GalaAppCacheRebuildCacheData GalaAppCacheRebuildCacheData;
enum  {
	GALA_APP_CACHE_CHANGED_SIGNAL,
	GALA_APP_CACHE_NUM_SIGNALS
};
static guint gala_app_cache_signals[GALA_APP_CACHE_NUM_SIGNALS] = {0};

struct _GalaAppCachePrivate {
	GHashTable* startup_wm_class_to_id;
	GRecMutex __lock_startup_wm_class_to_id;
	GHashTable* id_to_app;
	GAppInfoMonitor* app_info_monitor;
	guint queued_update_id;
};

struct _Block1Data {
	int _ref_count_;
	GalaAppCache* self;
	GSourceFunc callback;
	gpointer callback_target;
	GDestroyNotify callback_target_destroy_notify;
	gpointer _async_data_;
};

struct _GalaAppCacheRebuildCacheData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	GalaAppCache* self;
	Block1Data* _data1_;
	GThread* _tmp0_;
	GThread* _tmp1_;
};

static gint GalaAppCache_private_offset;
static gpointer gala_app_cache_parent_class = NULL;

static void gala_app_cache_queue_cache_update (GalaAppCache* self);
static gboolean __lambda4_ (GalaAppCache* self);
static void gala_app_cache_rebuild_cache (GalaAppCache* self,
                                   GAsyncReadyCallback _callback_,
                                   gpointer _user_data_);
static void gala_app_cache_rebuild_cache_finish (GalaAppCache* self,
                                          GAsyncResult* _res_);
static void __lambda6_ (GalaAppCache* self,
                 GObject* obj,
                 GAsyncResult* res);
static void ___lambda6__gasync_ready_callback (GObject* source_object,
                                        GAsyncResult* res,
                                        gpointer self);
static gboolean ___lambda4__gsource_func (gpointer self);
static void gala_app_cache_rebuild_cache_data_free (gpointer _data);
static gboolean gala_app_cache_rebuild_cache_co (GalaAppCacheRebuildCacheData* _data_);
static Block1Data* block1_data_ref (Block1Data* _data1_);
static void block1_data_unref (void * _userdata_);
static gboolean _gala_app_cache_rebuild_cache_co_gsource_func (gpointer self);
static void __lambda5_ (Block1Data* _data1_);
static void _g_object_unref0_ (gpointer var);
static inline void _g_list_free__g_object_unref0_ (GList* self);
static gpointer ___lambda5__gthread_func (gpointer self);
static GObject * gala_app_cache_constructor (GType type,
                                      guint n_construct_properties,
                                      GObjectConstructParam * construct_properties);
static void _gala_app_cache_queue_cache_update_g_app_info_monitor_changed (GAppInfoMonitor* _sender,
                                                                    gpointer self);
static void gala_app_cache_finalize (GObject * obj);
static GType gala_app_cache_get_type_once (void);

static inline gpointer
gala_app_cache_get_instance_private (GalaAppCache* self)
{
	return G_STRUCT_MEMBER_P (self, GalaAppCache_private_offset);
}

static void
__lambda6_ (GalaAppCache* self,
            GObject* obj,
            GAsyncResult* res)
{
	g_return_if_fail (res != NULL);
	gala_app_cache_rebuild_cache_finish (self, res);
	g_signal_emit (self, gala_app_cache_signals[GALA_APP_CACHE_CHANGED_SIGNAL], 0);
	self->priv->queued_update_id = (guint) 0;
}

static void
___lambda6__gasync_ready_callback (GObject* source_object,
                                   GAsyncResult* res,
                                   gpointer self)
{
	__lambda6_ ((GalaAppCache*) self, source_object, res);
	g_object_unref (self);
}

static gboolean
__lambda4_ (GalaAppCache* self)
{
	gboolean result;
	gala_app_cache_rebuild_cache (self, ___lambda6__gasync_ready_callback, g_object_ref (self));
	result = G_SOURCE_REMOVE;
	return result;
}

static gboolean
___lambda4__gsource_func (gpointer self)
{
	gboolean result;
	result = __lambda4_ ((GalaAppCache*) self);
	return result;
}

static void
gala_app_cache_queue_cache_update (GalaAppCache* self)
{
	g_return_if_fail (self != NULL);
	if (self->priv->queued_update_id != ((guint) 0)) {
		g_source_remove (self->priv->queued_update_id);
	}
	self->priv->queued_update_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, (guint) GALA_APP_CACHE_DEFAULT_TIMEOUT_SECONDS, ___lambda4__gsource_func, g_object_ref (self), g_object_unref);
}

static void
gala_app_cache_rebuild_cache_data_free (gpointer _data)
{
	GalaAppCacheRebuildCacheData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->self);
	g_slice_free (GalaAppCacheRebuildCacheData, _data_);
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static void
gala_app_cache_rebuild_cache (GalaAppCache* self,
                              GAsyncReadyCallback _callback_,
                              gpointer _user_data_)
{
	GalaAppCacheRebuildCacheData* _data_;
	GalaAppCache* _tmp0_;
	g_return_if_fail (self != NULL);
	_data_ = g_slice_new0 (GalaAppCacheRebuildCacheData);
	_data_->_async_result = g_task_new (G_OBJECT (self), NULL, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, gala_app_cache_rebuild_cache_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	gala_app_cache_rebuild_cache_co (_data_);
}

static void
gala_app_cache_rebuild_cache_finish (GalaAppCache* self,
                                     GAsyncResult* _res_)
{
	GalaAppCacheRebuildCacheData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), NULL);
}

static Block1Data*
block1_data_ref (Block1Data* _data1_)
{
	g_atomic_int_inc (&_data1_->_ref_count_);
	return _data1_;
}

static void
block1_data_unref (void * _userdata_)
{
	Block1Data* _data1_;
	_data1_ = (Block1Data*) _userdata_;
	if (g_atomic_int_dec_and_test (&_data1_->_ref_count_)) {
		GalaAppCache* self;
		self = _data1_->self;
		(_data1_->callback_target_destroy_notify == NULL) ? NULL : (_data1_->callback_target_destroy_notify (_data1_->callback_target), NULL);
		_data1_->callback = NULL;
		_data1_->callback_target = NULL;
		_data1_->callback_target_destroy_notify = NULL;
		_g_object_unref0 (self);
		g_slice_free (Block1Data, _data1_);
	}
}

static gboolean
_gala_app_cache_rebuild_cache_co_gsource_func (gpointer self)
{
	gboolean result;
	result = gala_app_cache_rebuild_cache_co (self);
	return result;
}

static void
_g_object_unref0_ (gpointer var)
{
	(var == NULL) ? NULL : (var = (g_object_unref (var), NULL));
}

static inline void
_g_list_free__g_object_unref0_ (GList* self)
{
	g_list_free_full (self, (GDestroyNotify) _g_object_unref0_);
}

static void
__lambda5_ (Block1Data* _data1_)
{
	GalaAppCache* self;
	GSourceFunc _tmp25_;
	gpointer _tmp25__target;
	GDestroyNotify _tmp25__target_destroy_notify;
	GError* _inner_error0_ = NULL;
	self = _data1_->self;
	{
		GHashTable* _tmp0_;
		_tmp0_ = self->priv->startup_wm_class_to_id;
		g_rec_mutex_lock (&self->priv->__lock_startup_wm_class_to_id);
		{
			GHashTable* _tmp1_;
			GHashTable* _tmp2_;
			GList* app_infos = NULL;
			GList* _tmp3_;
			GList* _tmp4_;
			_tmp1_ = self->priv->startup_wm_class_to_id;
			g_hash_table_remove_all (_tmp1_);
			_tmp2_ = self->priv->id_to_app;
			g_hash_table_remove_all (_tmp2_);
			_tmp3_ = g_app_info_get_all ();
			app_infos = _tmp3_;
			_tmp4_ = app_infos;
			{
				GList* app_collection = NULL;
				GList* app_it = NULL;
				app_collection = _tmp4_;
				for (app_it = app_collection; app_it != NULL; app_it = app_it->next) {
					GAppInfo* app = NULL;
					app = (GAppInfo*) app_it->data;
					{
						const gchar* id = NULL;
						GAppInfo* _tmp5_;
						const gchar* _tmp6_;
						const gchar* startup_wm_class = NULL;
						GAppInfo* _tmp7_;
						const gchar* _tmp8_;
						GHashTable* _tmp9_;
						const gchar* _tmp10_;
						GAppInfo* _tmp11_;
						GDesktopAppInfo* _tmp12_;
						const gchar* _tmp13_;
						const gchar* old_id = NULL;
						GHashTable* _tmp14_;
						const gchar* _tmp15_;
						gconstpointer _tmp16_;
						gboolean _tmp17_ = FALSE;
						const gchar* _tmp18_;
						_tmp5_ = app;
						_tmp6_ = g_app_info_get_id (_tmp5_);
						id = _tmp6_;
						_tmp7_ = app;
						_tmp8_ = g_desktop_app_info_get_startup_wm_class (G_TYPE_CHECK_INSTANCE_CAST (_tmp7_, G_TYPE_DESKTOP_APP_INFO, GDesktopAppInfo));
						startup_wm_class = _tmp8_;
						_tmp9_ = self->priv->id_to_app;
						_tmp10_ = id;
						_tmp11_ = app;
						_tmp12_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (_tmp11_, G_TYPE_DESKTOP_APP_INFO, GDesktopAppInfo));
						g_hash_table_insert (_tmp9_, _tmp10_, _tmp12_);
						_tmp13_ = startup_wm_class;
						if (_tmp13_ == NULL) {
							continue;
						}
						_tmp14_ = self->priv->startup_wm_class_to_id;
						_tmp15_ = startup_wm_class;
						_tmp16_ = g_hash_table_lookup (_tmp14_, _tmp15_);
						old_id = (const gchar*) _tmp16_;
						_tmp18_ = old_id;
						if (_tmp18_ == NULL) {
							_tmp17_ = TRUE;
						} else {
							const gchar* _tmp19_;
							const gchar* _tmp20_;
							_tmp19_ = id;
							_tmp20_ = startup_wm_class;
							_tmp17_ = g_strcmp0 (_tmp19_, _tmp20_) == 0;
						}
						if (_tmp17_) {
							GHashTable* _tmp21_;
							const gchar* _tmp22_;
							const gchar* _tmp23_;
							_tmp21_ = self->priv->startup_wm_class_to_id;
							_tmp22_ = startup_wm_class;
							_tmp23_ = id;
							g_hash_table_insert (_tmp21_, _tmp22_, _tmp23_);
						}
					}
				}
			}
			(app_infos == NULL) ? NULL : (app_infos = (_g_list_free__g_object_unref0_ (app_infos), NULL));
		}
		__finally0:
		{
			GHashTable* _tmp24_;
			_tmp24_ = self->priv->startup_wm_class_to_id;
			g_rec_mutex_unlock (&self->priv->__lock_startup_wm_class_to_id);
		}
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return;
		}
	}
	_tmp25_ = _data1_->callback;
	_tmp25__target = _data1_->callback_target;
	_tmp25__target_destroy_notify = _data1_->callback_target_destroy_notify;
	_data1_->callback = NULL;
	_data1_->callback_target = NULL;
	_data1_->callback_target_destroy_notify = NULL;
	g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, _tmp25_, _tmp25__target, _tmp25__target_destroy_notify);
}

static gpointer
___lambda5__gthread_func (gpointer self)
{
	gpointer result;
	__lambda5_ (self);
	result = NULL;
	block1_data_unref (self);
	return result;
}

static gboolean
gala_app_cache_rebuild_cache_co (GalaAppCacheRebuildCacheData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		case 1:
		goto _state_1;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	_data_->_data1_ = g_slice_new0 (Block1Data);
	_data_->_data1_->_ref_count_ = 1;
	_data_->_data1_->self = g_object_ref (_data_->self);
	_data_->_data1_->_async_data_ = _data_;
	_data_->_data1_->callback = _gala_app_cache_rebuild_cache_co_gsource_func;
	_data_->_data1_->callback_target = _data_;
	_data_->_data1_->callback_target_destroy_notify = NULL;
	_data_->_tmp0_ = g_thread_new ("rebuild_cache", ___lambda5__gthread_func, block1_data_ref (_data_->_data1_));
	_data_->_tmp1_ = _data_->_tmp0_;
	_g_thread_unref0 (_data_->_tmp1_);
	_data_->_state_ = 1;
	return FALSE;
	_state_1:
	;
	block1_data_unref (_data_->_data1_);
	_data_->_data1_ = NULL;
	g_task_return_pointer (_data_->_async_result, _data_, NULL);
	if (_data_->_state_ != 0) {
		while (!g_task_get_completed (_data_->_async_result)) {
			g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
		}
	}
	g_object_unref (_data_->_async_result);
	return FALSE;
}

GDesktopAppInfo*
gala_app_cache_lookup_id (GalaAppCache* self,
                          const gchar* id)
{
	GHashTable* _tmp0_;
	gconstpointer _tmp1_;
	GDesktopAppInfo* result;
	g_return_val_if_fail (self != NULL, NULL);
	if (id == NULL) {
		result = NULL;
		return result;
	}
	_tmp0_ = self->priv->id_to_app;
	_tmp1_ = g_hash_table_lookup (_tmp0_, id);
	result = (GDesktopAppInfo*) _tmp1_;
	return result;
}

GDesktopAppInfo*
gala_app_cache_lookup_startup_wmclass (GalaAppCache* self,
                                       const gchar* wm_class)
{
	const gchar* id = NULL;
	GHashTable* _tmp0_;
	gconstpointer _tmp1_;
	const gchar* _tmp2_;
	GHashTable* _tmp3_;
	const gchar* _tmp4_;
	gconstpointer _tmp5_;
	GDesktopAppInfo* _tmp6_;
	GDesktopAppInfo* result;
	g_return_val_if_fail (self != NULL, NULL);
	if (wm_class == NULL) {
		result = NULL;
		return result;
	}
	_tmp0_ = self->priv->startup_wm_class_to_id;
	_tmp1_ = g_hash_table_lookup (_tmp0_, wm_class);
	id = (const gchar*) _tmp1_;
	_tmp2_ = id;
	if (_tmp2_ == NULL) {
		result = NULL;
		return result;
	}
	_tmp3_ = self->priv->id_to_app;
	_tmp4_ = id;
	_tmp5_ = g_hash_table_lookup (_tmp3_, _tmp4_);
	_tmp6_ = _g_object_ref0 ((GDesktopAppInfo*) _tmp5_);
	result = _tmp6_;
	return result;
}

GalaAppCache*
gala_app_cache_construct (GType object_type)
{
	GalaAppCache * self = NULL;
	self = (GalaAppCache*) g_object_new (object_type, NULL);
	return self;
}

GalaAppCache*
gala_app_cache_new (void)
{
	return gala_app_cache_construct (GALA_TYPE_APP_CACHE);
}

static void
_gala_app_cache_queue_cache_update_g_app_info_monitor_changed (GAppInfoMonitor* _sender,
                                                               gpointer self)
{
	gala_app_cache_queue_cache_update ((GalaAppCache*) self);
}

static GObject *
gala_app_cache_constructor (GType type,
                            guint n_construct_properties,
                            GObjectConstructParam * construct_properties)
{
	GObject * obj;
	GObjectClass * parent_class;
	GalaAppCache * self;
	GHashFunc _tmp0_;
	GEqualFunc _tmp1_;
	GHashTable* _tmp2_;
	GHashFunc _tmp3_;
	GEqualFunc _tmp4_;
	GHashTable* _tmp5_;
	GAppInfoMonitor* _tmp6_;
	GAppInfoMonitor* _tmp7_;
	parent_class = G_OBJECT_CLASS (gala_app_cache_parent_class);
	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_APP_CACHE, GalaAppCache);
	_tmp0_ = g_str_hash;
	_tmp1_ = g_str_equal;
	_tmp2_ = g_hash_table_new_full (_tmp0_, _tmp1_, NULL, NULL);
	_g_hash_table_unref0 (self->priv->startup_wm_class_to_id);
	self->priv->startup_wm_class_to_id = _tmp2_;
	_tmp3_ = g_str_hash;
	_tmp4_ = g_str_equal;
	_tmp5_ = g_hash_table_new_full (_tmp3_, _tmp4_, NULL, _g_object_unref0_);
	_g_hash_table_unref0 (self->priv->id_to_app);
	self->priv->id_to_app = _tmp5_;
	_tmp6_ = g_app_info_monitor_get ();
	_g_object_unref0 (self->priv->app_info_monitor);
	self->priv->app_info_monitor = _tmp6_;
	_tmp7_ = self->priv->app_info_monitor;
	g_signal_connect_object (_tmp7_, "changed", (GCallback) _gala_app_cache_queue_cache_update_g_app_info_monitor_changed, self, 0);
	gala_app_cache_rebuild_cache (self, NULL, NULL);
	return obj;
}

static void
gala_app_cache_class_init (GalaAppCacheClass * klass,
                           gpointer klass_data)
{
	gala_app_cache_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GalaAppCache_private_offset);
	G_OBJECT_CLASS (klass)->constructor = gala_app_cache_constructor;
	G_OBJECT_CLASS (klass)->finalize = gala_app_cache_finalize;
	gala_app_cache_signals[GALA_APP_CACHE_CHANGED_SIGNAL] = g_signal_new ("changed", GALA_TYPE_APP_CACHE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static void
gala_app_cache_instance_init (GalaAppCache * self,
                              gpointer klass)
{
	self->priv = gala_app_cache_get_instance_private (self);
	g_rec_mutex_init (&self->priv->__lock_startup_wm_class_to_id);
	self->priv->queued_update_id = (guint) 0;
}

static void
gala_app_cache_finalize (GObject * obj)
{
	GalaAppCache * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_APP_CACHE, GalaAppCache);
	g_rec_mutex_clear (&self->priv->__lock_startup_wm_class_to_id);
	_g_hash_table_unref0 (self->priv->startup_wm_class_to_id);
	_g_hash_table_unref0 (self->priv->id_to_app);
	_g_object_unref0 (self->priv->app_info_monitor);
	G_OBJECT_CLASS (gala_app_cache_parent_class)->finalize (obj);
}

static GType
gala_app_cache_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GalaAppCacheClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gala_app_cache_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GalaAppCache), 0, (GInstanceInitFunc) gala_app_cache_instance_init, NULL };
	GType gala_app_cache_type_id;
	gala_app_cache_type_id = g_type_register_static (G_TYPE_OBJECT, "GalaAppCache", &g_define_type_info, 0);
	GalaAppCache_private_offset = g_type_add_instance_private (gala_app_cache_type_id, sizeof (GalaAppCachePrivate));
	return gala_app_cache_type_id;
}

GType
gala_app_cache_get_type (void)
{
	static volatile gsize gala_app_cache_type_id__once = 0;
	if (g_once_init_enter (&gala_app_cache_type_id__once)) {
		GType gala_app_cache_type_id;
		gala_app_cache_type_id = gala_app_cache_get_type_once ();
		g_once_init_leave (&gala_app_cache_type_id__once, gala_app_cache_type_id);
	}
	return gala_app_cache_type_id__once;
}

