/*
 * Copyright © 2008 Kristian Høgsberg
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef WAYLAND_CLIENT_CORE_H
#define WAYLAND_CLIENT_CORE_H

#include <stdint.h>
#include "wayland-util.h"
#include "wayland-version.h"

#ifdef  __cplusplus
extern "C" {
#endif

/** \class wl_proxy
 *
 * \brief Represents a protocol object on the client side.
 *
 * A wl_proxy acts as a client side proxy to an object existing in the
 * compositor. The proxy is responsible for converting requests made by the
 * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events
 * coming from the compositor are also handled by the proxy, which will in
 * turn call the handler set with \ref wl_proxy_add_listener().
 *
 * \note With the exception of function \ref wl_proxy_set_queue(), functions
 * accessing a wl_proxy are not normally used by client code. Clients
 * should normally use the higher level interface generated by the scanner to
 * interact with compositor objects.
 *
 */
struct wl_proxy;

/** \class wl_display
 *
 * \brief Represents a connection to the compositor and acts as a proxy to
 * the wl_display singleton object.
 *
 * A wl_display object represents a client connection to a Wayland
 * compositor. It is created with either \ref wl_display_connect() or
 * \ref wl_display_connect_to_fd(). A connection is terminated using
 * \ref wl_display_disconnect().
 *
 * A wl_display is also used as the \ref wl_proxy for the wl_display
 * singleton object on the compositor side.
 *
 * A wl_display object handles all the data sent from and to the
 * compositor. When a \ref wl_proxy marshals a request, it will write its wire
 * representation to the display's write buffer. The data is sent to the
 * compositor when the client calls \ref wl_display_flush().
 *
 * Incoming data is handled in two steps: queueing and dispatching. In the
 * queue step, the data coming from the display fd is interpreted and
 * added to a queue. On the dispatch step, the handler for the incoming
 * event set by the client on the corresponding \ref wl_proxy is called.
 *
 * A wl_display has at least one event queue, called the <em>default
 * queue</em>. Clients can create additional event queues with \ref
 * wl_display_create_queue() and assign \ref wl_proxy's to it. Events
 * occurring in a particular proxy are always queued in its assigned queue.
 * A client can ensure that a certain assumption, such as holding a lock
 * or running from a given thread, is true when a proxy event handler is
 * called by assigning that proxy to an event queue and making sure that
 * this queue is only dispatched when the assumption holds.
 *
 * The default queue is dispatched by calling \ref wl_display_dispatch().
 * This will dispatch any events queued on the default queue and attempt
 * to read from the display fd if it's empty. Events read are then queued
 * on the appropriate queues according to the proxy assignment.
 *
 * A user created queue is dispatched with \ref wl_display_dispatch_queue().
 * This function behaves exactly the same as wl_display_dispatch()
 * but it dispatches given queue instead of the default queue.
 *
 * A real world example of event queue usage is Mesa's implementation of
 * eglSwapBuffers() for the Wayland platform. This function might need
 * to block until a frame callback is received, but dispatching the default
 * queue could cause an event handler on the client to start drawing
 * again. This problem is solved using another event queue, so that only
 * the events handled by the EGL code are dispatched during the block.
 *
 * This creates a problem where a thread dispatches a non-default
 * queue, reading all the data from the display fd. If the application
 * would call \em poll(2) after that it would block, even though there
 * might be events queued on the default queue. Those events should be
 * dispatched with \ref wl_display_dispatch_pending() or \ref
 * wl_display_dispatch_queue_pending() before flushing and blocking.
 */
struct wl_display;

/** \class wl_event_queue
 *
 * \brief A queue for \ref wl_proxy object events.
 *
 * Event queues allows the events on a display to be handled in a thread-safe
 * manner. See \ref wl_display for details.
 *
 */
struct wl_event_queue;

/** Destroy proxy after marshalling
 * @ingroup wl_proxy
 */
#define WL_MARSHAL_FLAG_DESTROY (1 << 0)

void
wl_event_queue_destroy(struct wl_event_queue *queue);

struct wl_proxy *
wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode,
		       const struct wl_interface *interface,
		       uint32_t version,
		       uint32_t flags, ...);

struct wl_proxy *
wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
			     const struct wl_interface *interface,
			     uint32_t version,
			     uint32_t flags,
			     union wl_argument *args);

void
wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);

void
wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode,
		       union wl_argument *args);

struct wl_proxy *
wl_proxy_create(struct wl_proxy *factory,
		const struct wl_interface *interface);

void *
wl_proxy_create_wrapper(void *proxy);

void
wl_proxy_wrapper_destroy(void *proxy_wrapper);

struct wl_proxy *
wl_proxy_marshal_constructor(struct wl_proxy *proxy,
			     uint32_t opcode,
			     const struct wl_interface *interface,
			     ...);

struct wl_proxy *
wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy,
				       uint32_t opcode,
				       const struct wl_interface *interface,
				       uint32_t version,
				       ...);

struct wl_proxy *
wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
				   uint32_t opcode, union wl_argument *args,
				   const struct wl_interface *interface);

struct wl_proxy *
wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
					     uint32_t opcode,
					     union wl_argument *args,
					     const struct wl_interface *interface,
					     uint32_t version);

void
wl_proxy_destroy(struct wl_proxy *proxy);

int
wl_proxy_add_listener(struct wl_proxy *proxy,
		      void (**implementation)(void), void *data);

const void *
wl_proxy_get_listener(struct wl_proxy *proxy);

int
wl_proxy_add_dispatcher(struct wl_proxy *proxy,
			wl_dispatcher_func_t dispatcher_func,
			const void * dispatcher_data, void *data);

void
wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);

void *
wl_proxy_get_user_data(struct wl_proxy *proxy);

uint32_t
wl_proxy_get_version(struct wl_proxy *proxy);

uint32_t
wl_proxy_get_id(struct wl_proxy *proxy);

void
wl_proxy_set_tag(struct wl_proxy *proxy,
		 const char * const *tag);

const char * const *
wl_proxy_get_tag(struct wl_proxy *proxy);

const char *
wl_proxy_get_class(struct wl_proxy *proxy);

void
wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);

struct wl_proxy *
wl_proxy_from_object(struct wl_object *object);

struct wl_display *
wl_display_connect(const char *name);

struct wl_display *
wl_display_connect_to_fd(int fd);

void
wl_display_disconnect(struct wl_display *display);

int
wl_display_get_fd(struct wl_display *display);

int
wl_display_dispatch(struct wl_display *display);

int
wl_display_dispatch_queue(struct wl_display *display,
			  struct wl_event_queue *queue);

int
wl_display_dispatch_queue_pending(struct wl_display *display,
				  struct wl_event_queue *queue);

int
wl_display_dispatch_pending(struct wl_display *display);

int
wl_display_get_error(struct wl_display *display);

uint32_t
wl_display_get_protocol_error(struct wl_display *display,
			      const struct wl_interface **interface,
			      uint32_t *id);

int
wl_display_flush(struct wl_display *display);

int
wl_display_roundtrip_queue(struct wl_display *display,
			   struct wl_event_queue *queue);

int
wl_display_roundtrip(struct wl_display *display);

struct wl_event_queue *
wl_display_create_queue(struct wl_display *display);

int
wl_display_prepare_read_queue(struct wl_display *display,
			      struct wl_event_queue *queue);

int
wl_display_prepare_read(struct wl_display *display);

void
wl_display_cancel_read(struct wl_display *display);

int
wl_display_read_events(struct wl_display *display);

void
wl_log_set_handler_client(wl_log_func_t handler);

/**
 * The message type.
 */
enum wl_client_message_type {
	/** The message is a request */
	WL_CLIENT_MESSAGE_REQUEST,

	/** The message is an event */
	WL_CLIENT_MESSAGE_EVENT,
};

/**
 * The message discard reason codes.
 */
enum wl_client_message_discarded_reason {
	/** The message was handled normally, and not discarded. */
	WL_CLIENT_MESSAGE_NOT_DISCARDED = 0,

	/** The target was not alive at dispatch time */
	WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH,

	/** The target had no listener or dispatcher */
	WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,

	/** The target was not valid when the event was demarshalled */
	WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
};

/**
 * The structure used to communicate details about an observed message to the
 * registered observers.
 */
struct wl_client_observed_message {
	/** The target for the message */
	struct wl_proxy *proxy;

	/** The message opcode */
	int message_opcode;

	/** The protocol message structure */
	const struct wl_message *message;

	/** The count of arguments to the message */
	int arguments_count;

	/** The argument array for the messagge */
	const union wl_argument *arguments;

	/** The discard reason code */
	enum wl_client_message_discarded_reason discarded_reason;

	/**
	 * The discard reason string, or NULL if the event was not discarded.
	 *
	 * This string is only for convenience for a observer that does
	 * logging. The string values should not be considered stable, and
	 * are not localized.
	 */
	const char *discarded_reason_str;
};

/**
 * The signature for a client message observer function, as registered with
 * wl_display_add_client_observer().
 *
 * \param user_data \c user_data pointer given when the observer was
 *                  registered with \c wl_display_create_client_observer
 * \param type      type of message
 * \param message   details for the message
 */
typedef void (*wl_client_message_observer_func_t)(
	void *user_data, enum wl_client_message_type type,
	const struct wl_client_observed_message *message);

/** \class wl_client_observer
 *
 * \brief Represents a client message observer
 *
 * A client observer allows the client to observe all request and event
 * message traffic to and from the client. For events, the observer is
 * also given a discard reason if the event wasn't handled.
 *
 * The typical use for the observer is to allow the client implementation to
 * do its own debug logging, as the default when setting WAYLAND_DEBUG is to
 * log to stderr.
 *
 * With this runtime call, the client can also enable and disable the observer
 * at any time.
 *
 * The protocol-logger-test.c file has an example of a logger implementation.
 */
struct wl_client_observer;

struct wl_client_observer *
wl_display_create_client_observer(struct wl_display *display,
				  wl_client_message_observer_func_t observer,
				  void *user_data);

void
wl_client_observer_destroy(struct wl_client_observer *observer);

#ifdef  __cplusplus
}
#endif

#endif
