Logo Search packages:      
Sourcecode: netbook-launcher-efl version File versions  Download package

gstuff.c

/* netbook-launcher-efl: nice desktop launcher targeted at netbooks.
 *
 * Copyright (C) 2009  Canonical Ltd.
 * License: GNU GPLv3, see COPYING.
 *
 * Author: Gustavo Sverzut Barbieri <gustavo.barbieri@canonical.com>
 */

/**
 * This file takes care of gluing two main loops: Ecore and GLib.
 *
 * It does so by using one thread per loop and exchanging functions to
 * be called on the other thread. This is done asynchronously, so
 * either use locks around your data or copy it.
 *
 * Do not call GLib functions from the Ecore thread and vice-versa!
 *
 * The communication is LOCKLESS except by queues, that use locks
 * internally. Do not add useless locks around parts of the system,
 * try to use given primitives to avoid UI blocking on backend actions
 * and vice versa.
 *
 * Pipes are used to wakeup the other main loop, functions
 * gstuff_glib_run() and gstuff_ecore_run() will take care of internals to
 * add function context to queue and then wakeup the thread.
 */

#include "netbook-launcher.h"
#include <Ecore.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <pthread.h>

void
gstuff_shutdown(void)
{
}

Eina_Bool
gstuff_init(void)
{
  g_thread_init(NULL);
  g_set_application_name(PACKAGE);

  ecore_main_loop_glib_integrate();
 return 1;
}

static int
_dispatch(void *data)
{
  struct func_ctxt *ctxt = data;
  ctxt->func(ctxt->data);
  ctxt->free(ctxt);
  return 0;
}

static void
_add_dispatch(struct func_ctxt *ctxt)
{
   ecore_idler_add(_dispatch, ctxt);
}

/**
 * Have the given function context to run on GLib thread/main loop.
 *
 * @warning: just call this function from Ecore thread!
 *
 * @param ctxt: context to call function on GLib thread.
 * @return: 1 on success, 0 on error (ctxt->free(ctxt) is called on errors).
 */
Eina_Bool
gstuff_glib_run(struct func_ctxt *ctxt)
{
  if (!ctxt)
  {
    ERR("gstuff_glib_run(NULL)\n");
    return 0;
  }

  _add_dispatch(ctxt);
  return 1;
}

/**
 * Have the given function context to run on Ecore thread/main loop.
 *
 * @warning: just call this function from GLib thread!
 *
 * @param ctxt: context to call function on Ecore thread.
 * @return: 1 on success, 0 on error (ctxt->free(ctxt) is called on errors).
 */
Eina_Bool
gstuff_ecore_run(struct func_ctxt *ctxt)
{
  if (!ctxt)
  {
    g_warning("gstuff_ecore_run(NULL)");
    return 0;
  }

  _add_dispatch(ctxt);
  return 1;
}

static void
_gstuff_func_ctxt_dumb_free(void *data __UNUSED__)
{
}

static void
_gstuff_glib_exit(void *data __UNUSED__)
{
  g_debug("quit inexistent gtk main loop. ;)");
}

/**
 * Request glib main loop to exit.
 */
Eina_Bool
gstuff_glib_exit(void)
{
  return 1;
}

static void
_gstuff_ecore_exit(void *data __UNUSED__)
{
  ecore_main_loop_quit();
}

/**
 * Request ecore main loop to exit.
 */
Eina_Bool
gstuff_ecore_exit(void)
{
  static struct func_ctxt ctxt = {
    _gstuff_ecore_exit,
    _gstuff_func_ctxt_dumb_free,
    NULL
  };
  return gstuff_ecore_run(&ctxt);
}

struct func_ctxt_noargs
{
  struct func_ctxt base;
  void (*real_func)(void);
};

static void
_gstuff_noargs(void *data)
{
  struct func_ctxt_noargs *ctxt = data;
  ctxt->real_func();
}

static struct func_ctxt *
_gstuff_noargs_ctxt_new(void (*func)(void))
{
  struct func_ctxt_noargs *ctxt;

  if (!func)
    return NULL;

  ctxt = malloc(sizeof(*ctxt));
  if (!ctxt)
    return NULL;
  ctxt->base.func = _gstuff_noargs;
  ctxt->base.free = free;
  ctxt->base.data = ctxt;
  ctxt->real_func = func;
  return &ctxt->base;
}

/**
 * Request function to be called at GLib thread.
 */
Eina_Bool
gstuff_glib_run_noargs(void (*func)(void))
{
  return gstuff_glib_run(_gstuff_noargs_ctxt_new(func));
}

/**
 * Request function to be called at Ecore thread.
 */
Eina_Bool
gstuff_ecore_run_noargs(void (*func)(void))
{
  return gstuff_ecore_run(_gstuff_noargs_ctxt_new(func));
}

static struct func_ctxt *
_gstuff_simple_ctxt_new(void (*func)(void *data), const void *data)
{
  struct func_ctxt *ctxt;

  if (!func)
    return NULL;

  ctxt = malloc(sizeof(*ctxt));
  if (!ctxt)
    return NULL;
  ctxt->func = func;
  ctxt->free = free;
  ctxt->data = (void *)data;
  return ctxt;
}

/**
 * Request function to be called at GLib thread.
 *
 * @param data: any pointer to give to @a func, will not be copied.
 */
Eina_Bool
gstuff_glib_run_simple(void (*func)(void *data), const void *data)
{
  return gstuff_glib_run(_gstuff_simple_ctxt_new(func, data));
}

/**
 * Request function to be called at Ecore thread.
 *
 * @param data: any pointer to give to @a func, will not be copied.
 */
Eina_Bool
gstuff_ecore_run_simple(void (*func)(void *data), const void *data)
{
  return gstuff_ecore_run(_gstuff_simple_ctxt_new(func, data));
}

struct func_ctxt_string
{
  struct func_ctxt base;
  void (*real_func)(const char *);
  char str[];
};

static void
_gstuff_string(void *data)
{
  struct func_ctxt_string *ctxt = data;
  ctxt->real_func(ctxt->str);
}

static struct func_ctxt *
_gstuff_string_ctxt_new(void (*func)(const char *str), const char *str)
{
  struct func_ctxt_string *ctxt;
  size_t len;

  if (!func)
    return NULL;

  if (!str)
    return NULL;
  len = strlen(str);
  ctxt = malloc(sizeof(*ctxt) + len + 1);
  if (!ctxt)
    return NULL;

  ctxt->base.func = _gstuff_string;
  ctxt->base.free = free;
  ctxt->base.data = ctxt;
  ctxt->real_func = func;
  memcpy(ctxt->str, str, len + 1);
  return &ctxt->base;
}

/**
 * Request function to be called with a copy of str at GLib thread.
 *
 * @param str: string to be COPIED, no references will be kept after return.
 */
Eina_Bool
gstuff_glib_run_string(void (*func)(const char *str), const char *str)
{
  return gstuff_glib_run(_gstuff_string_ctxt_new(func, str));
}

/**
 * Request function to be called with a copy of str at Ecore thread.
 *
 * @param str: string to be COPIED, no references will be kept after return.
 */
Eina_Bool
gstuff_ecore_run_string(void (*func)(const char *str), const char *str)
{
  return gstuff_ecore_run(_gstuff_string_ctxt_new(func, str));
}

struct func_ctxt_ptr_string
{
  struct func_ctxt base;
  void (*real_func)(void *, const char *);
  const void *real_data;
  char str[];
};

static void
_gstuff_ptr_string(void *data)
{
  struct func_ctxt_ptr_string *ctxt = data;
  ctxt->real_func((void *)ctxt->real_data, ctxt->str);
}

static struct func_ctxt *
_gstuff_ptr_string_ctxt_new(void (*func)(void *data, const char *str), const void *data, const char *str)
{
  struct func_ctxt_ptr_string *ctxt;
  size_t len;

  if (!func)
    return NULL;

  if (!str)
    return NULL;
  len = strlen(str);
  ctxt = malloc(sizeof(*ctxt) + len + 1);
  if (!ctxt)
    return NULL;

  ctxt->base.func = _gstuff_ptr_string;
  ctxt->base.free = free;
  ctxt->base.data = ctxt;
  ctxt->real_func = func;
  ctxt->real_data = data;
  memcpy(ctxt->str, str, len + 1);
  return &ctxt->base;
}

/**
 * Request function to be called with a copy of str at GLib thread.
 *
 * @param data: extra pointer to give to function, not copied or touched.
 * @param str: string to be COPIED, no references will be kept after return.
 */
Eina_Bool
gstuff_glib_run_ptr_string(void (*func)(void *data, const char *str), const void *data, const char *str)
{
  return gstuff_glib_run(_gstuff_ptr_string_ctxt_new(func, data, str));
}

/**
 * Request function to be called with a copy of str at Ecore thread.
 *
 * @param data: extra pointer to give to function, not copied or touched.
 * @param str: string to be COPIED, no references will be kept after return.
 */
Eina_Bool
gstuff_ecore_run_ptr_string(void (*func)(void *data, const char *str), const void *data, const char *str)
{
  return gstuff_ecore_run(_gstuff_ptr_string_ctxt_new(func, data, str));
}

struct func_ctxt_string_array
{
  struct func_ctxt base;
  void (*real_func)(unsigned int, const char **);
  unsigned int count;
  char **array;
};

static void
_gstuff_string_array(void *data)
{
  struct func_ctxt_string_array *ctxt = data;
  ctxt->real_func(ctxt->count, (const char **)ctxt->array);
}

static struct func_ctxt *
_gstuff_string_array_ctxt_new(void (*func)(unsigned int count, const char **array), unsigned int count, const char **array)
{
  struct func_ctxt_string_array *ctxt;
  unsigned int i;
  size_t len;
  char *s;

  if (!func)
    return NULL;

  if (!array)
    return NULL;

  if (count == 0)
    while (array[count] != NULL)
      count++;

  len = 0;
  for (i = 0; i < count; i++)
    len += strlen(array[i]) + 1;

  ctxt = malloc(sizeof(*ctxt) + ((count + 1) * sizeof(char *)) + len);
  if (!ctxt)
    return NULL;

  ctxt->base.func = _gstuff_string_array;
  ctxt->base.free = free;
  ctxt->base.data = ctxt;
  ctxt->real_func = func;
  ctxt->count = count;

  ctxt->array = (char **)((char *)ctxt + sizeof(*ctxt));
  s = (char *)(ctxt->array + count + 1);
  for (i = 0; i < count;  i++)
  {
    len = strlen(array[i]) + 1;
    ctxt->array[i] = s;
    memcpy(s, array[i], len);
    s += len;
  }
  ctxt->array[i] = NULL;

  return &ctxt->base;
}

/**
 * Request function to run on GLib thread with an array of strings.
 *
 * @note: function will always receive the number of elements and the
 *        copied array will always be NULL terminated. Functions can
 *        always rely on such values even if they were not given as
 *        original parameter.
 *
 * @param func: function to call, first argument is the number of
 *        elements and second is the array, with a NULL terminator.
 * @param count: elements in array or 0 to count @a array until a NULL
 *        terminator is found.
 * @param array: elements to COPY. If @a count is 0, then it must be NULL
 *        terminated. Strings and array will be copied, no reference will
 *        be kept after function returns.
 */
Eina_Bool
gstuff_glib_run_string_array(void (*func)(unsigned int count, const char **array), unsigned int count, const char **array)
{
  return gstuff_glib_run(_gstuff_string_array_ctxt_new(func, count, array));
}

/**
 * Request function to run on Ecore thread with an array of strings.
 *
 * @note: function will always receive the number of elements and the
 *        copied array will always be NULL terminated. Functions can
 *        always rely on such values even if they were not given as
 *        original parameter.
 *
 * @param func: function to call, first argument is the number of
 *        elements and second is the array, with a NULL terminator.
 * @param count: elements in array or 0 to count @a array until a NULL
 *        terminator is found.
 * @param array: elements to COPY. If @a count is 0, then it must be NULL
 *        terminated. Strings and array will be copied, no reference will
 *        be kept after function returns.
 */
Eina_Bool
gstuff_ecore_run_string_array(void (*func)(unsigned int count, const char **array), unsigned int count, const char **array)
{
  return gstuff_ecore_run(_gstuff_string_array_ctxt_new(func, count, array));
}

struct func_ctxt_ptr_string_array
{
  struct func_ctxt base;
  void (*real_func)(void *, unsigned int, const char **);
  void *real_data;
  unsigned int count;
  char **array;
};

static void
_gstuff_ptr_string_array(void *data)
{
  struct func_ctxt_ptr_string_array *ctxt = data;
  ctxt->real_func(ctxt->real_data, ctxt->count, (const char **)ctxt->array);
}

static struct func_ctxt *
_gstuff_ptr_string_array_ctxt_new(void (*func)(void *data, unsigned int count, const char **array), const void *data, unsigned int count, const char **array)
{
  struct func_ctxt_ptr_string_array *ctxt;
  unsigned int i;
  size_t len;
  char *s;

  if (!func)
    return NULL;

  if (!array)
    return NULL;

  if (count == 0)
    while (array[count] != NULL)
      count++;

  len = 0;
  for (i = 0; i < count; i++)
    len += strlen(array[i]) + 1;

  ctxt = malloc(sizeof(*ctxt) + ((count + 1) * sizeof(char *)) + len);
  if (!ctxt)
    return NULL;

  ctxt->base.func = _gstuff_ptr_string_array;
  ctxt->base.free = free;
  ctxt->base.data = ctxt;
  ctxt->real_func = func;
  ctxt->real_data = (void *)data;
  ctxt->count = count;

  ctxt->array = (char **)((char *)ctxt + sizeof(*ctxt));
  s = (char *)(ctxt->array + count + 1);
  for (i = 0; i < count;  i++)
  {
    len = strlen(array[i]) + 1;
    ctxt->array[i] = s;
    memcpy(s, array[i], len);
    s += len;
  }
  ctxt->array[i] = NULL;

  return &ctxt->base;
}

/**
 * Request function to run on GLib thread with data and array of strings.
 *
 * @note: function will always receive the number of elements and the
 *        copied array will always be NULL terminated. Functions can
 *        always rely on such values even if they were not given as
 *        original parameter.
 *
 * @param func: function to call, first argument is the number of
 *        elements and second is the array, with a NULL terminator.
 * @param data: extra data to give to function.
 * @param count: elements in array or 0 to count @a array until a NULL
 *        terminator is found.
 * @param array: elements to COPY. If @a count is 0, then it must be NULL
 *        terminated. Strings and array will be copied, no reference will
 *        be kept after function returns.
 */
Eina_Bool
gstuff_glib_run_ptr_string_array(void (*func)(void *data, unsigned int count, const char **array), const void *data, unsigned int count, const char **array)
{
  return gstuff_glib_run(
    _gstuff_ptr_string_array_ctxt_new(func, data, count, array));
}

/**
 * Request function to run on Ecore thread with data and array of strings.
 *
 * @note: function will always receive the number of elements and the
 *        copied array will always be NULL terminated. Functions can
 *        always rely on such values even if they were not given as
 *        original parameter.
 *
 * @param func: function to call, first argument is the number of
 *        elements and second is the array, with a NULL terminator.
 * @param data: extra data to give to function.
 * @param count: elements in array or 0 to count @a array until a NULL
 *        terminator is found.
 * @param array: elements to COPY. If @a count is 0, then it must be NULL
 *        terminated. Strings and array will be copied, no reference will
 *        be kept after function returns.
 */
Eina_Bool
gstuff_ecore_run_ptr_string_array(void (*func)(void *data, unsigned int count, const char **array), const void *data, unsigned int count, const char **array)
{
  return gstuff_ecore_run
    (_gstuff_ptr_string_array_ctxt_new(func, data, count, array));
}

Generated by  Doxygen 1.6.0   Back to index