/*
 * linc-source.c: This file is part of the linc library.
 *
 * Authors:
 *    Owen Taylor   (owen@redhat.com)
 *    Michael Meeks (michael@ximian.com)
 *
 * Copyright 1998, 2001, Red Hat, Inc., Ximian, Inc.,
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#include <glib.h>
#include "linc-debug.h"
#include "linc-private.h"

static gboolean 
linc_source_prepare (GSource *source,
		     gint    *timeout)
{
	*timeout = -1;

	return FALSE;
}

static gboolean 
linc_source_check (GSource *source)
{
	LincUnixWatch *watch = (LincUnixWatch *)source;

	return watch->pollfd.revents & watch->condition;
}

static gboolean
linc_source_dispatch (GSource    *source,
		      GSourceFunc callback,
		      gpointer    user_data)

{
	GIOFunc    func;
	LincUnixWatch *watch = (LincUnixWatch *) source;

	if (!callback)
		g_error ("No callback");
  
	func = (GIOFunc) callback;

	return (*func) (watch->channel,
			watch->pollfd.revents & watch->condition,
			user_data);
}

static void
linc_source_finalize (GSource *source)
{
	d_printf ("Finalize source %p", source);
}

GSourceFuncs linc_source_watch_funcs = {
	linc_source_prepare,
	linc_source_check,
	linc_source_dispatch,
	linc_source_finalize
};

static void
linc_source_set_condition (LincUnixWatch *watch,
			   GIOCondition  condition)
{
	if (watch) {
		watch->pollfd.events = condition;
		watch->condition     = condition;
	}
}

static GSource *
linc_source_create_watch (GMainContext *context,
			  int           fd,
			  GIOChannel   *channel,
			  GIOCondition  condition,
			  GIOFunc       func,
			  gpointer      user_data)
{
	GSource       *source;
	LincUnixWatch *watch;

	source = g_source_new (&linc_source_watch_funcs,
			       sizeof (LincUnixWatch));
	watch = (LincUnixWatch *) source;

	watch->pollfd.fd = fd;
	watch->channel   = channel;

	linc_source_set_condition (watch, condition);

	g_source_set_can_recurse (source, TRUE);
	g_source_add_poll (source, &watch->pollfd);

	g_source_set_callback (source, (GSourceFunc) func,
			       user_data, NULL);
	g_source_attach (source, context);

	return source;
}

/*
 * Wrappers to make listening on two mainloops simpler
 */

LincWatch *
linc_io_add_watch_fd (int          fd,
		      GIOCondition condition,
		      GIOFunc      func,
		      gpointer     user_data)
{
	LincWatch *w;
  
	w = g_new (LincWatch, 1);

	/* Linc loop */
	w->linc_source = linc_source_create_watch (
		linc_main_get_context (), fd, NULL,
		condition, func, user_data);

	/* Main loop */
	w->main_source = linc_source_create_watch (
		NULL, fd, NULL, condition, func, user_data);

	return w;
}

/**
 * linc_io_add_watch:
 * @channel: the GIOChannel to watch
 * @condition: the condition mask to watch for
 * @func: the function to invoke when a condition is met
 * @user_data: a user data closure
 * 
 * This routine creates a watch on an IO channel that operates both in
 * the standard glib mainloop, but also in the 'linc' mainloop so we
 * can iterate that without causing re-enterancy.
 *
 * This method is deprecated.
 * 
 * Return value: a pointer identifying the watch.
 **/
LincWatch *
linc_io_add_watch (GIOChannel    *channel,
		   GIOCondition   condition,
		   GIOFunc        func,
		   gpointer       user_data)
{
	LincWatch *w;
	int       fd = g_io_channel_unix_get_fd(channel);

	w = g_new (LincWatch, 1);

	/* Linc loop */
	w->linc_source = linc_source_create_watch (
		linc_main_get_context (), fd, channel,
		condition, func, user_data);

	/* Main loop */
	w->main_source = linc_source_create_watch (
		NULL, fd, channel, condition, func, user_data);

	return w;
}

/**
 * linc_io_remove_watch:
 * @watch: the handle of a watch on a GIOChannel
 * 
 * This removes a watch by it's handle in @w
 **/
void
linc_io_remove_watch (LincWatch *w)
{
	if (w) {
		linc_source_set_condition ((LincUnixWatch *) w->main_source, 0);
		linc_source_set_condition ((LincUnixWatch *) w->linc_source, 0);

		g_source_destroy (w->main_source);
		g_source_unref   (w->main_source);

		g_source_destroy (w->linc_source);
		g_source_unref   (w->linc_source);

		g_free (w);
	}
}

void
linc_watch_set_condition (LincWatch   *w,
			  GIOCondition condition)
{
	if (w) {
		linc_source_set_condition (
			(LincUnixWatch *) w->linc_source,
			condition);

		linc_source_set_condition (
			(LincUnixWatch *) w->main_source,
			condition);
	}
}


syntax highlighted by Code2HTML, v. 0.9.1