Пример #1
0
/**
 * inf_chat_buffer_get_message:
 * @buffer: A #InfChatBuffer.
 * @n: The index of the message to obtain.
 *
 * Returns the message with the given index from the buffer. The oldest
 * message in the buffer has index 0, and the most recent one has index
 * inf_chat_buffer_get_n_messages() - 1.
 *
 * Returns: The #InfChatBufferMessage with the given index.
 */
const InfChatBufferMessage*
inf_chat_buffer_get_message(InfChatBuffer* buffer,
                            guint n)
{
  InfChatBufferPrivate* priv;

  g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), NULL);
  g_return_val_if_fail(n < inf_chat_buffer_get_n_messages(buffer), NULL);

  priv = INF_CHAT_BUFFER_PRIVATE(buffer);
  return &priv->messages[
    (priv->first_message + n) % priv->size
  ];
}
Пример #2
0
static void
inf_chat_buffer_buffer_set_modified(InfBuffer* buffer,
                                    gboolean modified)
{
  InfChatBuffer* chat_buffer;
  InfChatBufferPrivate* priv;

  chat_buffer = INF_CHAT_BUFFER(buffer);
  priv = INF_CHAT_BUFFER_PRIVATE(chat_buffer);

  if(priv->modified != modified)
  {
    priv->modified = modified;
    g_object_notify(G_OBJECT(buffer), "modified");
  }
}
Пример #3
0
static void
inf_chat_buffer_init(GTypeInstance* instance,
                     gpointer g_class)
{
  InfChatBuffer* buffer;
  InfChatBufferPrivate* priv;

  buffer = INF_CHAT_BUFFER(instance);
  priv = INF_CHAT_BUFFER_PRIVATE(buffer);

  priv->messages = NULL;
  priv->alloc_messages = 0;
  priv->num_messages = 0;
  priv->first_message = 0;
  priv->size = 256;
  priv->modified = FALSE;
}
Пример #4
0
static void
inf_chat_buffer_finalize(GObject* object)
{
  InfChatBuffer* buffer;
  InfChatBufferPrivate* priv;
  guint i;

  buffer = INF_CHAT_BUFFER(object);
  priv = INF_CHAT_BUFFER_PRIVATE(buffer);

  /* Note that the messages array is not necessarily filled from its
   * beginning - we might have preallocated some space for prepending
   * entries. */
  for(i = 0; i < priv->num_messages; ++i)
    g_free(priv->messages[(priv->first_message + i) % priv->size].text);
  g_free(priv->messages);

  G_OBJECT_CLASS(parent_class)->finalize(object);
}
Пример #5
0
static void
inf_chat_buffer_add_message_handler(InfChatBuffer* buffer,
                                    const InfChatBufferMessage* message)
{
  InfChatBufferPrivate* priv;
  InfChatBufferMessage* new_message;

  priv = INF_CHAT_BUFFER_PRIVATE(buffer);

  new_message = inf_chat_buffer_reserve_message(buffer, message->time);

  /* new_message can be NULL if the buffer is already full, and the new
   * message is older than all existing messages. */
  if(new_message != NULL)
  {
    new_message->type = message->type;
    new_message->user = message->user;
    new_message->text = g_strndup(message->text, message->length);
    new_message->length = message->length;
    new_message->time = message->time;
    new_message->flags = message->flags;
  }
}
Пример #6
0
/**
 * inf_chat_buffer_get_size:
 * @buffer: A #InfChatBuffer.
 *
 * Returns the size of the chat buffer, which is the maximum number of
 * messages that can be stored in the buffer.
 *
 * Returns: The number of messages in the chat buffer.
 */
guint
inf_chat_buffer_get_size(InfChatBuffer* buffer)
{
  g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), 0);
  return INF_CHAT_BUFFER_PRIVATE(buffer)->size;
}
Пример #7
0
/**
 * inf_chat_buffer_get_n_messages:
 * @buffer: A #InfChatBuffer.
 *
 * Returns the number of messages in the buffer.
 *
 * Returns: The number of messages in the buffer.
 */
guint
inf_chat_buffer_get_n_messages(InfChatBuffer* buffer)
{
  g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), 0);
  return INF_CHAT_BUFFER_PRIVATE(buffer)->num_messages;
}
Пример #8
0
/* The function returns NULL if the new message is older than all other
 * messages in the buffer. Make sure to initalize all fields of the new
 * message to sensible values after having called this function. */
static InfChatBufferMessage*
inf_chat_buffer_reserve_message(InfChatBuffer* buffer,
                                time_t time)
{
  InfChatBufferPrivate* priv;
  InfChatBufferMessage* message;
  guint begin;
  guint end;
  guint n;

  priv = INF_CHAT_BUFFER_PRIVATE(buffer);

  begin = 0;
  end = priv->num_messages;

  /* Find the place at which to insert the new message */
  while(begin != end)
  {
    n = (begin + end) / 2;
    message = &priv->messages[(priv->first_message + n) % priv->size];
    if(message->time <= time)
      begin = (begin + end + 1)/2;
    else
      end = (begin + end)/2;
  } while(begin != end);

  n = begin;

  /* Can't insert at the beginning if there is no more space in the buffer */
  if(n == 0 && priv->num_messages == priv->size)
    return NULL;

  if(priv->num_messages < priv->size)
  {
    /* We have buffer space available, so we don't need to drop an existing
     * message. */
 
    /* We rely on the messages not wrapping around yet when the buffer is
     * not yet full. */
    g_assert(priv->first_message + priv->num_messages <= priv->alloc_messages);

    if(priv->num_messages == priv->alloc_messages)
    {
      /* We need to allocate more space */
      priv->alloc_messages = MAX(priv->alloc_messages * 2, 16);
      priv->alloc_messages = MIN(priv->alloc_messages, priv->size);

      g_assert(priv->alloc_messages > priv->num_messages);

      priv->messages = g_realloc(
        priv->messages,
        priv->alloc_messages * sizeof(InfChatBufferMessage)
      );
    }

    if(n == 0 && priv->first_message == 0)
    {
      /* The new message is the first one, but there is no space at the
       * beginning of the array, so we need to shift the other messages */
      end = (priv->alloc_messages - priv->num_messages + 1) / 2;
      g_assert(end > 0);

      memmove(
        priv->messages + end,
        priv->messages /* + priv->first_message */,
        priv->num_messages * sizeof(InfChatBufferMessage)
      );

      priv->first_message = end - 1;
    }
    else if(n == priv->num_messages &&
            priv->first_message + priv->num_messages == priv->alloc_messages)
    {
      /* The new message is the last one, but there is no space at the end of
       * the array, so we need to shift the other messages */
      end = (priv->alloc_messages - priv->num_messages) / 2;
      g_assert(end + priv->num_messages < priv->alloc_messages);

      memmove(
        priv->messages + end,
        priv->messages + priv->first_message,
        priv->num_messages * sizeof(InfChatBufferMessage)
      );

      priv->first_message = end;
    }
    else if(n > 0 && n < priv->num_messages)
    {
      /* The new message is inserted in the middle, so we need to shift either
       * the messages before or the ones after, depending on where we have
       * space available. */
      if((n < priv->num_messages / 2 &&
          priv->first_message > 0) ||
         (n > priv->num_messages / 2 &&
          priv->first_message + priv->num_messages == priv->alloc_messages))
      {
        begin = priv->first_message;

        memmove(
          priv->messages + begin - 1,
          priv->messages + begin,
          (n + 1) * sizeof(InfChatBufferMessage)
        );

        --priv->first_message;
      }
      else
      {
        memmove(
          priv->messages + n + 1,
          priv->messages + n,
          (priv->num_messages - n) * sizeof(InfChatBufferMessage)
        );
      }
    }

    ++ priv->num_messages;
  }
  else
  {
    /* The buffer is full. This means we need to remove the oldest message */
    g_assert(n > 0); /* we have catched this before */

    begin = priv->first_message;
    end = (priv->first_message + n) % priv->size;

    if(n == priv->num_messages)
    {
      /* We insert at the end, so the first message is going to be freed */
      g_free(priv->messages[priv->first_message].text);
      priv->first_message = (priv->first_message + 1) % priv->size;
    }
    else
    {
      /* Clear the oldest message */
      g_free(priv->messages[end].text);

      if(begin < end)
      {
        memmove(
          priv->messages + begin + 1,
          priv->messages + begin,
          (end - begin) * sizeof(InfChatBufferMessage)
        );
      }
      else
      {
        memmove(
          priv->messages + end + 1,
          priv->messages + end,
          (begin - end) * sizeof(InfChatBufferMessage)
        );

        priv->first_message = (priv->first_message + 1) % priv->size;
      }
    }

    /* We increased first_message, so adapt the new message's number */
    --n;
  }

  return &priv->messages[(priv->first_message + n) % priv->size];
}
Пример #9
0
static gboolean
inf_chat_buffer_buffer_get_modified(InfBuffer* buffer)
{
  return INF_CHAT_BUFFER_PRIVATE(buffer)->modified;
}