* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#include <string.h>
#include "gfilemonitor.h"
-#include "gio-marshal.h"
#include "gioenumtypes.h"
#include "gfile.h"
#include "gvfs.h"
#include "glibintl.h"
-#include "gioalias.h"
struct _FileChange;
typedef struct _FileChange FileChange;
*
* To get informed about changes to the file or directory you are
* monitoring, connect to the #GFileMonitor::changed signal. The
- * signal will be emitted in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * context</link> of the thread that the monitor was created in
+ * signal will be emitted in the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread that the monitor was created in
* (though if the global default main context is blocked, this may
* cause notifications to be blocked even if the thread-default
* context is still running).
LAST_SIGNAL
};
-/* work around a limitation of the aliasing foo */
-#undef g_file_monitor
-
-G_DEFINE_ABSTRACT_TYPE (GFileMonitor, g_file_monitor, G_TYPE_OBJECT);
-
typedef struct {
GFile *file;
guint32 last_sent_change_time; /* 0 == not sent */
/* Rate limiting change events */
GHashTable *rate_limiter;
+ GMutex mutex;
GSource *pending_file_change_source;
GSList *pending_file_changes; /* FileChange */
enum {
PROP_0,
PROP_RATE_LIMIT,
- PROP_CANCELLED
+ PROP_CANCELLED,
+ PROP_CONTEXT
};
+/* work around a limitation of the aliasing foo */
+#undef g_file_monitor
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GFileMonitor, g_file_monitor, G_TYPE_OBJECT)
+
static void
g_file_monitor_set_property (GObject *object,
guint prop_id,
g_file_monitor_set_rate_limit (monitor, g_value_get_int (value));
break;
+ case PROP_CONTEXT:
+ monitor->priv->context = g_value_dup_boxed (value);
+ if (monitor->priv->context == NULL)
+ monitor->priv->context = g_main_context_ref_thread_default ();
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_hash_table_destroy (monitor->priv->rate_limiter);
- if (monitor->priv->context)
- g_main_context_unref (monitor->priv->context);
+ g_main_context_unref (monitor->priv->context);
+ g_mutex_clear (&monitor->priv->mutex);
G_OBJECT_CLASS (g_file_monitor_parent_class)->finalize (object);
}
g_source_unref (priv->pending_file_change_source);
priv->pending_file_change_source = NULL;
}
- g_slist_foreach (priv->pending_file_changes, (GFunc) file_change_free, NULL);
- g_slist_free (priv->pending_file_changes);
+ g_slist_free_full (priv->pending_file_changes, (GDestroyNotify) file_change_free);
priv->pending_file_changes = NULL;
/* Make sure we cancel on last unref */
g_file_monitor_class_init (GFileMonitorClass *klass)
{
GObjectClass *object_class;
-
- g_type_class_add_private (klass, sizeof (GFileMonitorPrivate));
-
+
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = g_file_monitor_finalize;
object_class->dispose = g_file_monitor_dispose;
* GFileMonitor::changed:
* @monitor: a #GFileMonitor.
* @file: a #GFile.
- * @other_file: a #GFile.
+ * @other_file: (allow-none): a #GFile or #NULL.
* @event_type: a #GFileMonitorEvent.
- *
- * Emitted when a file has been changed.
+ *
+ * Emitted when @file has been changed.
+ *
+ * If using #G_FILE_MONITOR_SEND_MOVED flag and @event_type is
+ * #G_FILE_MONITOR_EVENT_MOVED, @file will be set to a #GFile containing the
+ * old path, and @other_file will be set to a #GFile containing the new path.
+ *
+ * In all the other cases, @other_file will be set to #NULL.
**/
signals[CHANGED] =
g_signal_new (I_("changed"),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GFileMonitorClass, changed),
NULL, NULL,
- _gio_marshal_VOID__OBJECT_OBJECT_ENUM,
+ NULL,
G_TYPE_NONE, 3,
G_TYPE_FILE, G_TYPE_FILE, G_TYPE_FILE_MONITOR_EVENT);
FALSE,
G_PARAM_READABLE|
G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (object_class,
+ PROP_CONTEXT,
+ g_param_spec_boxed ("context",
+ P_("Context"),
+ P_("The main context to dispatch from"),
+ G_TYPE_MAIN_CONTEXT, G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static void
g_file_monitor_init (GFileMonitor *monitor)
{
- monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
- G_TYPE_FILE_MONITOR,
- GFileMonitorPrivate);
+ monitor->priv = g_file_monitor_get_instance_private (monitor);
monitor->priv->rate_limit_msec = DEFAULT_RATE_LIMIT_MSECS;
monitor->priv->rate_limiter = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal,
NULL, (GDestroyNotify) rate_limiter_free);
- monitor->priv->context = g_main_context_get_thread_default ();
+ g_mutex_init (&monitor->priv->mutex);
}
/**
/**
* g_file_monitor_set_rate_limit:
* @monitor: a #GFileMonitor.
- * @limit_msecs: a integer with the limit in milliseconds to
- * poll for changes.
+ * @limit_msecs: a non-negative integer with the limit in milliseconds
+ * to poll for changes
*
* Sets the rate limit to which the @monitor will report
- * consecutive change events to the same file.
- *
- **/
+ * consecutive change events to the same file.
+ */
void
g_file_monitor_set_rate_limit (GFileMonitor *monitor,
- int limit_msecs)
+ gint limit_msecs)
{
GFileMonitorPrivate *priv;
-
+
g_return_if_fail (G_IS_FILE_MONITOR (monitor));
-
+ g_return_if_fail (limit_msecs >= 0);
+
priv = monitor->priv;
if (priv->rate_limit_msec != limit_msecs)
{
{
GFileMonitor *monitor = G_FILE_MONITOR (data);
GSList *pending, *iter;
-
+
+ g_mutex_lock (&monitor->priv->mutex);
pending = g_slist_reverse (monitor->priv->pending_file_changes);
monitor->priv->pending_file_changes = NULL;
if (monitor->priv->pending_file_change_source)
g_source_unref (monitor->priv->pending_file_change_source);
monitor->priv->pending_file_change_source = NULL;
}
+ g_mutex_unlock (&monitor->priv->mutex);
g_object_ref (monitor);
for (iter = pending; iter; iter = iter->next)
{
FileChange *change = iter->data;
+
g_signal_emit (monitor, signals[CHANGED], 0,
change->child, change->other_file, change->event_type);
file_change_free (change);
change->other_file = NULL;
change->event_type = event_type;
+ g_mutex_lock (&monitor->priv->mutex);
if (!priv->pending_file_change_source)
{
source = g_idle_source_new ();
* pending idles.
*/
g_source_set_callback (source, emit_cb, monitor, NULL);
+ g_source_set_name (source, "[gio] emit_cb");
g_source_attach (source, monitor->priv->context);
}
/* We reverse this in the processor */
priv->pending_file_changes = g_slist_prepend (priv->pending_file_changes, change);
+ g_mutex_unlock (&monitor->priv->mutex);
}
static guint32
get_time_msecs (void)
{
- return g_thread_gettime() / (1000 * 1000);
+ return g_get_monotonic_time () / G_TIME_SPAN_MILLISECOND;
}
static guint32
if (limiter->last_sent_change_time != 0)
{
- /* Set a timeout at 2*rate limit so that we can clear out the change from the hash eventualy */
+ /* Set a timeout at 2*rate limit so that we can clear out the change from the hash eventually */
expire_at = limiter->last_sent_change_time + 2 * monitor->priv->rate_limit_msec;
if (time_difference (time_now, expire_at) > 0)
* has taken place. Should be called from file monitor
* implementations only.
*
- * The signal will be emitted from an idle handler (in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * context</link>).
+ * The signal will be emitted from an idle handler (in the
+ * [thread-default main context][g-main-context-push-thread-default]).
**/
void
g_file_monitor_emit_event (GFileMonitor *monitor,
limiter->last_sent_change_time = time_now;
limiter->send_delayed_change_at = 0;
- /* Set a timeout of 2*rate limit so that we can clear out the change from the hash eventualy */
+ /* Set a timeout of 2*rate limit so that we can clear out the change from the hash eventually */
update_rate_limiter_timeout (monitor, time_now + 2 * monitor->priv->rate_limit_msec);
}
update_rate_limiter_timeout (monitor, limiter->send_virtual_changes_done_at);
}
}
-
-#define __G_FILE_MONITOR_C__
-#include "gioaliasdef.c"