static void
g_file_monitor_source_dispose (GFileMonitorSource *fms)
{
  g_mutex_lock (&fms->lock);

  if (fms->instance)
    {
      GHashTableIter iter;
      gpointer seqiter;
      QueuedEvent *event;

      g_hash_table_iter_init (&iter, fms->pending_changes_table);
      while (g_hash_table_iter_next (&iter, NULL, &seqiter))
        {
          g_hash_table_iter_remove (&iter);
          g_sequence_remove (seqiter);
        }

      while ((event = g_queue_pop_head (&fms->event_queue)))
        queued_event_free (event);

      g_assert (g_sequence_is_empty (fms->pending_changes));
      g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
      g_assert (fms->event_queue.length == 0);
      fms->instance = NULL;

      g_file_monitor_source_update_ready_time (fms);
    }

  g_mutex_unlock (&fms->lock);

  g_source_destroy ((GSource *) fms);
}
Beispiel #2
0
static void
g_menu_exporter_group_subscribe (GMenuExporterGroup *group,
                                 GVariantBuilder    *builder)
{
  GHashTableIter iter;
  gpointer key, val;

  if (!group->prepared)
    {
      GMenuExporterMenu *menu;

      /* set this first, so that any menus created during the
       * preparation of the first menu also end up in the prepared
       * state.
       * */
      group->prepared = TRUE;

      menu = g_hash_table_lookup (group->menus, 0);

      /* If the group was created by a subscription and does not yet
       * exist, it won't have a root menu...
       *
       * That menu will be prepared if it is ever added (due to
       * group->prepared == TRUE).
       */
      if (menu)
        g_menu_exporter_menu_prepare (menu);
    }

  group->subscribed++;

  g_hash_table_iter_init (&iter, group->menus);
  while (g_hash_table_iter_next (&iter, &key, &val))
    {
      guint id = GPOINTER_TO_INT (key);
      GMenuExporterMenu *menu = val;

      if (!g_sequence_is_empty (menu->item_links))
        {
          g_variant_builder_open (builder, G_VARIANT_TYPE ("(uuaa{sv})"));
          g_variant_builder_add (builder, "u", group->id);
          g_variant_builder_add (builder, "u", id);
          g_variant_builder_add_value (builder, g_menu_exporter_menu_list (menu));
          g_variant_builder_close (builder);
        }
    }
}
static void
g_file_monitor_source_finalize (GSource *source)
{
  GFileMonitorSource *fms = (GFileMonitorSource *) source;

  /* should already have been cleared in dispose of the monitor */
  g_assert (fms->instance == NULL);
  g_assert (g_sequence_is_empty (fms->pending_changes));
  g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
  g_assert (fms->event_queue.length == 0);

  g_hash_table_unref (fms->pending_changes_table);
  g_sequence_free (fms->pending_changes);

  g_free (fms->dirname);
  g_free (fms->basename);
  g_free (fms->filename);

  g_mutex_clear (&fms->lock);
}
static gboolean
g_file_monitor_source_dispatch (GSource     *source,
                                GSourceFunc  callback,
                                gpointer     user_data)
{
  GFileMonitorSource *fms = (GFileMonitorSource *) source;
  QueuedEvent *event;
  GQueue event_queue;
  gint64 now;

  /* make sure the monitor still exists */
  if (!fms->instance)
    return FALSE;

  now = g_source_get_time (source);

  /* Acquire the lock once and grab all events in one go, handling the
   * queued events first.  This avoids strange possibilities in cases of
   * long delays, such as CHANGED events coming before CREATED events.
   *
   * We do this by converting the applicable pending changes into queued
   * events (after the ones already queued) and then stealing the entire
   * event queue in one go.
   */
  g_mutex_lock (&fms->lock);

  /* Create events for any pending changes that are due to fire */
  while (!g_sequence_is_empty (fms->pending_changes))
    {
      GSequenceIter *iter = g_sequence_get_begin_iter (fms->pending_changes);
      PendingChange *pending = g_sequence_get (iter);

      /* We've gotten to a pending change that's not ready.  Stop. */
      if (pending_change_get_ready_time (pending, fms) > now)
        break;

      if (pending->dirty)
        {
          /* It's time to send another CHANGED and update the record */
          g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, pending->child, NULL);
          pending->last_emission = now;
          pending->dirty = FALSE;

          g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
        }
      else
        {
          /* It's time to send CHANGES_DONE and remove the pending record */
          g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, pending->child, NULL);
          g_file_monitor_source_remove_pending_change (fms, iter, pending->child);
        }
    }

  /* Steal the queue */
  memcpy (&event_queue, &fms->event_queue, sizeof event_queue);
  memset (&fms->event_queue, 0, sizeof fms->event_queue);

  g_file_monitor_source_update_ready_time (fms);

  g_mutex_unlock (&fms->lock);

  /* We now have our list of events to deliver */
  while ((event = g_queue_pop_head (&event_queue)))
    {
      /* an event handler could destroy 'instance', so check each time */
      if (fms->instance)
        g_file_monitor_emit_event (fms->instance, event->child, event->other, event->event_type);

      queued_event_free (event);
    }

  return TRUE;
}