Commit 55434cdb authored by Ernestas Kulik's avatar Ernestas Kulik 🦑

Yay for reinventing wheels

parent b6e3579f
......@@ -99,5 +99,7 @@ if get_option('nst_extension')
subdir('nautilus-sendto-extension')
endif
subdir ('src-ng')
# Compile GSettings schemas when installing from source.
meson.add_install_script('build-aux/meson/postinstall.py')
#include <stdlib.h>
#include <glib.h>
#include "nautilus-file.h"
#include "nautilus-task-manager.h"
static void
got_info (NautilusFile *file,
GFileInfo *info,
GError *error,
gpointer user_data)
{
g_message ("Got info for %p\n\tDisplay name: %s",
(gpointer) file,
g_file_info_get_display_name (info));
g_object_unref (info);
g_main_loop_quit ((GMainLoop *) user_data);
}
int
main (int argc,
char **argv)
{
g_autoptr (NautilusTaskManager) manager = NULL;
g_autoptr (GFile) location = NULL;
g_autoptr (NautilusFile) file = NULL;
g_autoptr (NautilusFile) duplicate_file = NULL;
GMainLoop *loop;
if (!(argc > 1))
{
g_message ("No file provided, exiting");
return EXIT_SUCCESS;
}
manager = nautilus_task_manager_dup_singleton ();
location = g_file_new_for_commandline_arg (argv[1]);
g_message ("Creating NautilusFile");
file = nautilus_file_new (location);
g_message ("Got %p\n", (gpointer) file);
g_message ("Creating another NautilusFile for the same location");
duplicate_file = nautilus_file_new (location);
g_message ("Got %p, which is %s\n",
(gpointer) duplicate_file,
file == duplicate_file? "the same" : "not the same");
loop = g_main_loop_new (NULL, TRUE);
nautilus_file_query_info (file, NULL, got_info, loop);
g_main_loop_run (loop);
return EXIT_SUCCESS;
}
nautilus_ng_sources = ['nautilus-task.c',
'nautilus-task.h',
'nautilus-task-manager.c',
'nautilus-task-manager.h',
'nautilus-file.c',
'nautilus-file.h',
'tasks/nautilus-attribute-task.c',
'tasks/nautilus-attribute-task.h',
'main.c']
nautilus_ng_dependencies = [gio, glib]
nautilus_marshallers = gnome.genmarshal ('nautilus-marshallers',
sources: 'nautilus-marshallers.list',
prefix: 'nautilus_cclosure_marshal')
nautilus_ng_sources += nautilus_marshallers
nautilus_ng = executable ('nautilus-ng', nautilus_ng_sources,
dependencies: nautilus_ng_dependencies,
install: true)
/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
*
* This file is part of Nautilus.
*
* Nautilus 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.
*
* Nautilus 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 Nautilus. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nautilus-file.h"
#include "nautilus-task-manager.h"
#include "tasks/nautilus-attribute-task.h"
typedef enum
{
INVALID,
PENDING,
VALID
} CacheState;
typedef struct
{
GFile *location;
GFileInfo *info;
CacheState info_state;
GMutex cache_mutex;
} NautilusFilePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (NautilusFile, nautilus_file, G_TYPE_OBJECT)
enum
{
PROP_LOCATION = 1,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES] = { NULL };
static GHashTable *files = NULL;
static GMutex files_mutex;
static void
set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusFilePrivate *priv;
priv = nautilus_file_get_instance_private (NAUTILUS_FILE (object));
switch (property_id)
{
case PROP_LOCATION:
{
priv->location = g_value_dup_object (value);
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
}
static void
finalize (GObject *object)
{
NautilusFilePrivate *priv;
priv = nautilus_file_get_instance_private (NAUTILUS_FILE (object));
g_mutex_lock (&files_mutex);
g_hash_table_remove (files, priv->location);
g_mutex_unlock (&files_mutex);
g_mutex_clear (&priv->cache_mutex);
G_OBJECT_CLASS (nautilus_file_parent_class)->finalize (object);
}
static void
nautilus_file_class_init (NautilusFileClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = set_property;
object_class->finalize = finalize;
properties[PROP_LOCATION] =
g_param_spec_object ("location", "Location", "Location",
G_TYPE_FILE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
}
static void
nautilus_file_init (NautilusFile *self)
{
NautilusFilePrivate *priv;
priv = nautilus_file_get_instance_private (self);
priv->info = g_file_info_new ();
g_mutex_init (&priv->cache_mutex);
}
typedef struct
{
NautilusFile *file;
NautilusFileInfoCallback callback;
gpointer callback_data;
} QueryInfoDetails;
static void
on_query_info_finished (NautilusAttributeTask *task,
GFile *file,
GFileInfo *info,
GError *error,
gpointer data)
{
QueryInfoDetails *details;
NautilusFilePrivate *priv;
details = data;
priv = nautilus_file_get_instance_private (details->file);
g_mutex_lock (&priv->cache_mutex);
g_file_info_copy_into (info, priv->info);
priv->info_state = VALID;
g_mutex_unlock (&priv->cache_mutex);
details->callback (details->file, g_file_info_dup (info), error,
details->callback_data);
g_free (details);
}
void
nautilus_file_query_info (NautilusFile *file,
GCancellable *cancellable,
NautilusFileInfoCallback callback,
gpointer user_data)
{
NautilusFilePrivate *priv;
g_autoptr (NautilusTask) task = NULL;
QueryInfoDetails *details;
g_autoptr (NautilusTaskManager) manager = NULL;
priv = nautilus_file_get_instance_private (file);
g_mutex_lock (&priv->cache_mutex);
/* This is not the right thing to do if a cache update is pending.
* A task reference could be stored and we could connect to the signal,
* but there might be a better way.
*/
if (priv->info_state == PENDING || priv->info_state == VALID)
{
g_mutex_unlock (&priv->cache_mutex);
callback (file, g_file_info_dup (priv->info), NULL, user_data);
}
g_mutex_unlock (&priv->cache_mutex);
task = nautilus_attribute_task_new (priv->location,
"standard::*,"
"access::*,"
"mountable::*,"
"time::*,"
"unix::*,"
"owner::*,"
"selinux::*,"
"thumbnail::*,"
"id::filesystem,"
"trash::orig-path,"
"trash::deletion-date,"
"metadata::*,"
"recent::*",
G_FILE_QUERY_INFO_NONE,
cancellable);
details = g_new0 (QueryInfoDetails, 1);
manager = nautilus_task_manager_dup_singleton ();
details->file = file;
details->callback = callback;
details->callback_data = user_data;
g_signal_connect (task, "finished",
G_CALLBACK (on_query_info_finished), details);
nautilus_task_manager_queue_task (manager, task);
}
NautilusFile *
nautilus_file_new (GFile *location)
{
NautilusFile *file;
g_return_val_if_fail (G_IS_FILE (location), NULL);
g_mutex_lock (&files_mutex);
if (files == NULL)
{
files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
g_object_unref, NULL);
}
file = g_hash_table_lookup (files, location);
if (file != NULL)
{
file = g_object_ref (file);
}
else
{
file = g_object_new (NAUTILUS_TYPE_FILE, "location", location, NULL);
g_assert (g_hash_table_insert (files, location, file));
}
g_mutex_unlock (&files_mutex);
return file;
}
/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
*
* This file is part of Nautilus.
*
* Nautilus 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.
*
* Nautilus 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 Nautilus. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NAUTILUS_FILE_H_INCLUDED
#define NAUTILUS_FILE_H_INCLUDED
#include <glib-object.h>
#include <gio/gio.h>
#define NAUTILUS_TYPE_FILE (nautilus_file_get_type ())
G_DECLARE_DERIVABLE_TYPE (NautilusFile, nautilus_file, NAUTILUS, FILE, GObject)
typedef void (*NautilusFileInfoCallback) (NautilusFile *file,
GFileInfo *info,
GError *error,
gpointer user_data);
struct _NautilusFileClass
{
GObjectClass parent_class;
};
void nautilus_file_query_info (NautilusFile *file,
GCancellable *cancellable,
NautilusFileInfoCallback callback,
gpointer user_data);
NautilusFile *nautilus_file_new (GFile *location);
#endif
VOID:OBJECT,OBJECT,BOXED
/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
*
* This file is part of Nautilus.
*
* Nautilus 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.
*
* Nautilus 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 Nautilus. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nautilus-task-manager.h"
struct _NautilusTaskManager
{
GObject parent_instance;
GThreadPool *thread_pool;
};
G_DEFINE_TYPE (NautilusTaskManager, nautilus_task_manager, G_TYPE_OBJECT)
static NautilusTaskManager *instance = NULL;
static GObject *
constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
static GMutex mutex;
GObjectClass *parent_class;
g_mutex_lock (&mutex);
if (instance != NULL)
{
g_mutex_unlock (&mutex);
return g_object_ref (instance);
}
parent_class = G_OBJECT_CLASS (nautilus_task_manager_parent_class);
instance = NAUTILUS_TASK_MANAGER (parent_class->constructor (type,
n_construct_properties,
construct_properties));
g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *) &instance);
g_mutex_unlock (&mutex);
return G_OBJECT (instance);
}
static void
finalize (GObject *object)
{
NautilusTaskManager *self;
self = NAUTILUS_TASK_MANAGER (object);
g_thread_pool_free (self->thread_pool, TRUE, TRUE);
}
static void
nautilus_task_manager_class_init (NautilusTaskManagerClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->constructor = constructor;
object_class->finalize = finalize;
}
static void
execute_task (gpointer data,
gpointer user_data)
{
g_autoptr (NautilusTask) task = NULL;
task = NAUTILUS_TASK (data);
nautilus_task_execute (task);
}
static void
nautilus_task_manager_init (NautilusTaskManager *self)
{
self->thread_pool = g_thread_pool_new (execute_task, self,
16, FALSE,
NULL);
}
void
nautilus_task_manager_queue_task (NautilusTaskManager *self,
NautilusTask *task)
{
g_return_if_fail (NAUTILUS_IS_TASK_MANAGER (self));
g_return_if_fail (NAUTILUS_IS_TASK (task));
g_thread_pool_push (self->thread_pool, g_object_ref (task), NULL);
}
NautilusTaskManager *
nautilus_task_manager_dup_singleton (void)
{
return g_object_new (NAUTILUS_TYPE_TASK_MANAGER, NULL);
}
/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
*
* This file is part of Nautilus.
*
* Nautilus 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.
*
* Nautilus 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 Nautilus. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NAUTILUS_TASK_MANAGER_H_INCLUDED
#define NAUTILUS_TASK_MANAGER_H_INCLUDED
#include "nautilus-task.h"
#include <glib-object.h>
#define NAUTILUS_TYPE_TASK_MANAGER (nautilus_task_manager_get_type ())
G_DECLARE_FINAL_TYPE (NautilusTaskManager, nautilus_task_manager,
NAUTILUS, TASK_MANAGER,
GObject)
void nautilus_task_manager_queue_task (NautilusTaskManager *self,
NautilusTask *task);
NautilusTaskManager *nautilus_task_manager_dup_singleton (void);
#endif
/* Copyright (C) 2017 Ernestas Kulik <ernestask@gnome.org>
*
* This file is part of Nautilus.
*
* Nautilus 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.
*
* Nautilus 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 Nautilus. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nautilus-task.h"
#include <gobject/gvaluecollector.h>
typedef struct
{
GCancellable *cancellable;
GMainContext *context;
} NautilusTaskPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (NautilusTask, nautilus_task,
G_TYPE_OBJECT)
typedef struct
{
GValue instance_and_params[4];
guint signal_id;
int n_values;
} EmissionData;
enum
{
PROP_CANCELLABLE = 1,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES] = { NULL };
static void
set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
case PROP_CANCELLABLE:
{
NautilusTask *self;
NautilusTaskPrivate *priv;
self = NAUTILUS_TASK (object);
priv = nautilus_task_get_instance_private (self);
if (G_UNLIKELY (priv->cancellable) != NULL)
{
g_clear_object (&priv->cancellable);
}
priv->cancellable = g_value_dup_object (value);
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
}
static void
finalize (GObject *object)
{
NautilusTask *self;
NautilusTaskPrivate *priv;
self = NAUTILUS_TASK (object);
priv = nautilus_task_get_instance_private (self);
g_clear_object (&priv->cancellable);
g_clear_pointer (&priv->context, g_main_context_unref);
G_OBJECT_CLASS (nautilus_task_parent_class)->finalize (object);
}
static void
emission_data_free (EmissionData *data)
{
for (int i = 0; i < data->n_values; i++)
{
g_value_unset (&data->instance_and_params[i]);
}
g_free (data);
}
static gboolean
emit_signal (gpointer data)
{
EmissionData *emission_data;
emission_data = data;
g_signal_emitv (emission_data->instance_and_params,
emission_data->signal_id,
0, NULL);
g_clear_pointer (&emission_data, emission_data_free);
return FALSE;
}
static void
emit_signal_in_main_context (NautilusTask *instance,
guint signal_id,
...)
{
va_list ap;
EmissionData *emission_data;
GSignalQuery query;
g_autofree gchar *error = NULL;
NautilusTaskPrivate *priv;
emission_data = g_new0 (EmissionData, 1);
priv = nautilus_task_get_instance_private (instance);
va_start (ap, signal_id);
g_value_init (&emission_data->instance_and_params[0],
G_TYPE_FROM_INSTANCE (instance));
g_value_set_instance (&emission_data->instance_and_params[0], instance);
emission_data->signal_id = signal_id;
g_signal_query (signal_id, &query);
if (query.signal_id == 0)
{
g_clear_pointer (&emission_data, emission_data_free);
va_end (ap);
return;
}
for (int i = 0; i < query.n_params; i++)
{
G_VALUE_COLLECT_INIT (&emission_data->instance_and_params[i + 1],
query.param_types[i],
ap, 0, &error);
if (error != NULL)
{
break;
}
emission_data->n_values++;
}
if (error != NULL)
{
g_clear_pointer (&emission_data, emission_data_free);
va_end (ap);
return;
}
g_main_context_invoke (priv->context, emit_signal, emission_data);
va_end (ap);
}
static void
nautilus_task_class_init (NautilusTaskClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = set_property;
object_class->finalize = finalize;
klass->emit_signal_in_main_context = emit_signal_in_main_context;
properties[PROP_CANCELLABLE] =
g_param_spec_object ("cancellable", "Cancellable", "Cancellable",
G_TYPE_CANCELLABLE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
}
static void
nautilus_task_init (NautilusTask *self)
{
NautilusTaskPrivate *priv;
priv = nautilus_task_get_instance_private (self);
priv->context = g_main_context_ref_thread_default ();
}