/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*-
 *
 * Pigment media rendering library
 *
 * Copyright © 2006, 2007, 2008 Fluendo Embedded S.L.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author(s): Loïc Molinari <loic@fluendo.com>
 *            Julien Moutte <julien@fluendo.com>
 */

#ifndef __PGM_VIEWPORT_H__
#define __PGM_VIEWPORT_H__

/* pgmviewport.h and pgmviewportfactory.h include each other */
typedef struct _PgmViewport      PgmViewport;
typedef struct _PgmViewportClass PgmViewportClass;

#include <gdk-pixbuf/gdk-pixbuf.h>
#include "pgmcanvas.h"
#include "pgmviewportfactory.h"
#include "pgmlinearalgebra.h"
#include "pgmevents.h"
#ifdef WIN32
#include <Windows.h>
#endif /* WIN32 */

G_BEGIN_DECLS

#define PGM_TYPE_VIEWPORT  (pgm_viewport_get_type ())
#define PGM_VIEWPORT(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj), PGM_TYPE_VIEWPORT, PgmViewport))
#define PGM_VIEWPORT_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass), PGM_TYPE_VIEWPORT, PgmViewportClass))
#define PGM_IS_VIEWPORT(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj), PGM_TYPE_VIEWPORT))
#define PGM_IS_VIEWPORT_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE((klass), PGM_TYPE_VIEWPORT))
#define PGM_VIEWPORT_GET_CLASS(obj) \
  (G_TYPE_INSTANCE_GET_CLASS((obj), PGM_TYPE_VIEWPORT, PgmViewportClass))
#define PGM_VIEWPORT_CAST(obj) ((PgmViewport *) (obj))

/**
 * PgmViewportCursor:
 * @PGM_VIEWPORT_LEFT_ARROW: Standard left arrow system cursor.
 * @PGM_VIEWPORT_INHERIT: Inherited cursor from the environment.
 * @PGM_VIEWPORT_NONE: Hidden cursor.
 *
 * Pigment system cursor type.
 */
typedef enum {
  PGM_VIEWPORT_LEFT_ARROW = 0,
  PGM_VIEWPORT_INHERIT    = 1,
  PGM_VIEWPORT_NONE       = 2
} PgmViewportCursor;

/**
 * PgmViewportCapacity:
 * @PGM_VIEWPORT_HARDWARE_ACCELERATION: Supports accelerated rendering thanks
 * to dedicated hardware.
 * @PGM_VIEWPORT_APPLICATION_EMBEDDING: Supports embedding into another
 * application.
 * @PGM_VIEWPORT_OPACITY: Supports opacity so that compositing managers can
 * blend the viewport with other applications.
 * @PGM_VIEWPORT_TOUCHPAD: Supports touchpad so that application can use the
 * pressure events and parameters.
 * @PGM_VIEWPORT_X11_SYSTEM_BUFFER: Supports X11 system buffer as image content.
 * Actually, X11 system buffers are Pixmaps.
 *
 * Capacities supported by the viewport.
 */
typedef enum {
  PGM_VIEWPORT_HARDWARE_ACCELERATION = (1 << 0),
  PGM_VIEWPORT_APPLICATION_EMBEDDING = (1 << 1),
  PGM_VIEWPORT_OPACITY               = (1 << 2),
  PGM_VIEWPORT_TOUCHPAD              = (1 << 3),
  PGM_VIEWPORT_X11_SYSTEM_BUFFER     = (1 << 4)
} PgmViewportCapacity;

/**
 * PgmViewportRotation:
 * @PGM_VIEWPORT_ROTATION_NONE: Do not rotate to the canvas.
 * @PGM_VIEWPORT_ROTATION_90: Rotate the canvas 90° counter-clockwise.
 * @PGM_VIEWPORT_ROTATION_180: Rotate the canvas 180° counter-clockwise.
 * @PGM_VIEWPORT_ROTATION_270: Rotate the canvas 270° counter-clockwise.
 *
 * The rotation types of the canvas projection.
 */
typedef enum {
  PGM_VIEWPORT_ROTATION_NONE = 0,
  PGM_VIEWPORT_ROTATION_90   = 1,
  PGM_VIEWPORT_ROTATION_180  = 2,
  PGM_VIEWPORT_ROTATION_270  = 3
} PgmViewportRotation;

/**
 * PgmViewportReflection:
 * @PGM_VIEWPORT_REFLECTION_NONE: Do not reflect to the canvas.
 * @PGM_VIEWPORT_REFLECTION_HORIZONTAL_FLIP: Reflect the canvas horizontally.
 * @PGM_VIEWPORT_REFLECTION_VERTICAL_FLIP: Reflect the canvas vertically.
 *
 * The reflection types of the canvas projection.
 */
typedef enum {
  PGM_VIEWPORT_REFLECTION_NONE            = 0,
  PGM_VIEWPORT_REFLECTION_HORIZONTAL_FLIP = 1,
  PGM_VIEWPORT_REFLECTION_VERTICAL_FLIP   = 2
} PgmViewportReflection;

/* FIXME: Should not be exported in this header since it's only used
 *        internally. That could be fixed separating public and private
 *        GObject fields (see #183) */
typedef struct __PgmIOWatch _PgmIOWatch;
struct __PgmIOWatch {
  GIOChannel *out;
  GIOChannel *in;
  gint        fd[2];
  gint        tag;
};

/**
 * PgmViewport:
 * @factory: the factory used to instantiate the #PgmViewport.
 * @canvas: the attached canvas.
 * @message_filter: the filter of message events.
 * @title: the viewport title.
 * @icon: the current icon.
 * @cursor: the current cursor.
 * @fullscreen: the fullscreen state.
 * @visible: the visible state.
 * @decorated: the decorated state.
 * @iconified: the iconified state.
 * @opacity: the opacity.
 * @alpha_blending: the alpha blending state.
 * @width: the viewport width.
 * @height: the viewport height.
 * @width_mm: the viewport screen width in millimeters.
 * @height_mm: the viewport screen height in millimeters.
 * @projection: the 4x4 projection matrix.
 * @inv_projection: the 4x4 inverse projection matrix.
 * @projected_x: the attached canvas projected x position.
 * @projected_y: the attached canvas projected y position.
 * @projected_width: the attached canvas projected width.
 * @projected_height: the attached canvas projected height.
 * @rotation: the rotation of the projected canvas.
 * @reflection: the reflection of the projected canvas.
 * @pixel_aspect_ratio: the pixel-aspect-ratio.
 * @viewport_ratio: the viewport ratio.
 * @canvas_ratio: the attached canvas ratio with pixel-aspect-ratio correction
 * applied.
 * @caps_mask: the viewport mask of supported capacities.
 *
 * The #PgmViewport structure.
 */
struct _PgmViewport {
  GstObject parent;

  /*< public >*/ /* with LOCK */
  PgmViewportFactory *factory;
  PgmCanvas          *canvas;

  GList *message_filter;

  gchar             *title;
  GdkPixbuf         *icon;
  PgmViewportCursor  cursor;
  gboolean           fullscreen;
  gboolean           visible;
  gboolean           decorated;
  gboolean           iconified;
  gboolean           alpha_blending;

  gint width, height;
  gint width_mm, height_mm;

  PgmMat4x4 *projection, *inv_projection;
  gint       projected_x, projected_y;
  gint       projected_width, projected_height;

  PgmViewportRotation   rotation;
  PgmViewportReflection reflection;

  gfloat pixel_aspect_ratio;
  gfloat viewport_ratio;
  gfloat canvas_ratio;

  gulong caps_mask;

  guchar opacity;

  /*< private >*/
  /* Watch sources */
  _PgmIOWatch *event_watch;
  GMutex      *event_lock;
  GList       *event_list;
  _PgmIOWatch *pixel_watch;
  GMutex      *pixel_lock;
  GList       *pixel_list;
  gboolean     pixel_watch_up;
  gboolean     event_watch_up;

  /* Canvas rotation/reflection */
  gfloat projection_hflip, projection_vflip;
  gfloat projection_rotation;

  /* Signal handler id */
  gulong canvas_size_handler;
};

/**
 * PgmViewportClass:
 * @parent_class: the parent class structure.
 * @button_press_event: the "button-press-event" signal.
 * @button_pressure_event: the "button-pressure-event" signal.
 * @button_release_event: the "button-release-event" signal.
 * @key_press_event: the "key-press-event" signal.
 * @key_release_event: the "key-release-event" signal.
 * @configure_event: the "configure-event" signal.
 * @delete_event: the "delete-event" signal.
 * @scroll_event: the "scroll-event" signal.
 * @motion_notify_event: the "motion-notify-event" signal.
 * @expose_event: the "expose-event" signal.
 * @drag_motion_event: the "drag-motion-event" signal.
 * @drag_drop_event: the "drag-drop-event" signal.
 * @drag_leave_event: the "drag-leave-event" signal.
 * @state_event: the "state-event" signal.
 * @win32_message_event: the "win32-message-event" signal.
 * @pixels_read: the "pixels-read" signal.
 * @update_pass: the "update-pass" signal.
 * @set_title: the set_title virtual method.
 * @show: the show virtual method.
 * @hide: the hide virtual method.
 * @set_decorated: the set_decorated virtual method.
 * @set_cursor: the set_cursor virtual method.
 * @set_icon: the set_icon virtual method.
 * @set_size: the set_size virtual method.
 * @get_size: the get_size virtual method.
 * @set_alpha_blending: the set_alpha_blending virtual method.
 * @set_opacity: the set_opacity virtual method.
 * @set_fullscreen: the set_fullscreen virtual method.
 * @set_iconified: the set_iconified virtual method.
 * @focus: the focus virtual method.
 * @set_screen_resolution: the set_screen_resolution virtual method.
 * @get_screen_resolution: the get_screen_resolution virtual method.
 * @set_screen_size_mm: the set_screen_size_mm virtual method.
 * @get_screen_size_mm: the get_screen_size_mm virtual method.
 * @set_canvas: the set_canvas virtual method.
 * @update_projection: the update_projection virtual method.
 * @get_embedding_id: the get_embedding_id virtual method.
 * @get_pixel_formats: the get_pixel_formats virtual method.
 * @get_caps_mask: the get_caps_mask virtual method.
 * @get_max_texture_size: the get_max_texture_size virtual method.
 * @get_frame_rate: the get_frame_rate virtual method.
 * @set_message_filter: the set_message_filter virtual method.
 * @read_pixels: the read_pixels virtual method.
 * @set_drag_status: the set_drag_status virtual method.
 *
 * Pigment drawable class.
 */
struct _PgmViewportClass {
  GstObjectClass parent_class;

  /*< public >*/

  /* signals */

  void     (*button_press_event)    (PgmViewport *viewport,
                                     PgmEventButton *event);

  void     (*button_pressure_event) (PgmViewport *viewport,
                                     PgmEventButton *event);

  void     (*button_release_event)  (PgmViewport *viewport,
                                     PgmEventButton *event);

  void     (*key_press_event)       (PgmViewport *viewport,
                                     PgmEventKey *event);

  void     (*key_release_event)     (PgmViewport *viewport,
                                     PgmEventKey *event);

  void     (*configure_event)       (PgmViewport *viewport,
                                     PgmEventConfigure *event);

  void     (*delete_event)          (PgmViewport *viewport,
                                     PgmEvent *event);

  void     (*scroll_event)          (PgmViewport *viewport,
                                     PgmEventScroll *event);

  void     (*motion_notify_event)   (PgmViewport *viewport,
                                     PgmEventMotion *event);

  void     (*expose_event)          (PgmViewport *viewport,
                                     PgmEventExpose *event);

  gboolean (*drag_motion_event)     (PgmViewport *viewport,
                                     PgmEventDnd *event);

  void     (*drag_drop_event)       (PgmViewport *viewport,
                                     PgmEventDnd *event);

  void     (*drag_leave_event)      (PgmViewport *viewport,
                                     PgmEventDnd *event);

  void     (*state_event)           (PgmViewport *viewport,
                                     PgmEventState *event);

#ifdef WIN32
  LRESULT  (*win32_message_event)   (PgmViewport *viewport,
                                     PgmEventWin32Message *event);
#endif /* WIN32 */

  void     (*pixels_read)           (PgmViewport *viewport,
                                     guint width,
                                     guint height,
                                     gpointer pixels);

  void     (*update_pass)           (PgmViewport *viewport);

  /* virtual methods for subclasses */

  PgmError (*set_title)             (PgmViewport *viewport,
                                     const gchar *title);

  PgmError (*show)                  (PgmViewport *viewport);
  PgmError (*hide)                  (PgmViewport *viewport);

  PgmError (*set_decorated)         (PgmViewport *viewport,
                                     gboolean decorated);

  PgmError (*set_cursor)            (PgmViewport *viewport,
                                     PgmViewportCursor cursor);

  PgmError (*set_icon)              (PgmViewport *viewport,
                                     GdkPixbuf *icon);

  PgmError (*set_size)              (PgmViewport *viewport,
                                     gint width,
                                     gint height);
  PgmError (*get_size)              (PgmViewport *viewport,
                                     gint *width,
                                     gint *height);

  PgmError (*set_alpha_blending)    (PgmViewport *viewport,
                                     gboolean alpha_blending);

  PgmError (*set_opacity)           (PgmViewport *viewport,
                                     guchar opacity);

  PgmError (*set_fullscreen)        (PgmViewport *viewport,
                                     gboolean fullscreen);

  PgmError (*set_iconified)         (PgmViewport *viewport,
                                     gboolean iconified);

  PgmError (*focus)                 (PgmViewport *viewport);

  PgmError (*set_screen_resolution) (PgmViewport *viewport,
                                     gint width,
                                     gint height);
  PgmError (*get_screen_resolution) (PgmViewport *viewport,
                                     gint *width,
                                     gint *height);

  PgmError (*set_screen_size_mm)    (PgmViewport *viewport,
                                     gint width,
                                     gint height);
  PgmError (*get_screen_size_mm)    (PgmViewport *viewport,
                                     gint *width,
                                     gint *height);

  PgmError (*set_canvas)            (PgmViewport *viewport,
                                     PgmCanvas *canvas);

  PgmError (*update_projection)     (PgmViewport *viewport);

  PgmError (*get_embedding_id)      (PgmViewport *viewport,
                                     gulong *embedding_id);

  PgmError (*get_pixel_formats)     (PgmViewport *viewport,
                                     gulong *formats_mask);

  PgmError (*get_caps_mask)         (PgmViewport *viewport,
                                     gulong *caps_mask);

  PgmError (*get_max_texture_size)  (PgmViewport *viewport,
                                     guint32 *max_texture_size);

  PgmError (*get_frame_rate)        (PgmViewport *viewport,
                                     guint *frame_rate);

  PgmError (*set_message_filter)    (PgmViewport *viewport,
                                     GList *filter);

  PgmError (*read_pixels)           (PgmViewport *viewport,
                                     guint x,
                                     guint y,
                                     guint width,
                                     guint height,
                                     guint8 *pixels);

  PgmError (*set_drag_status)       (PgmViewport *viewport,
                                     gboolean accept);
};

GType        pgm_viewport_get_type              (void);

PgmError     pgm_viewport_set_title             (PgmViewport *viewport,
                                                 const gchar *title);
PgmError     pgm_viewport_get_title             (PgmViewport *viewport,
                                                 gchar **title);

PgmError     pgm_viewport_show                  (PgmViewport *viewport);
PgmError     pgm_viewport_hide                  (PgmViewport *viewport);
PgmError     pgm_viewport_is_visible            (PgmViewport *viewport,
                                                 gboolean *visible);

PgmError     pgm_viewport_set_decorated         (PgmViewport *viewport,
                                                 gboolean decorated);
PgmError     pgm_viewport_get_decorated         (PgmViewport *viewport,
                                                 gboolean *decorated);

PgmError     pgm_viewport_set_cursor            (PgmViewport *viewport,
                                                 PgmViewportCursor cursor);
PgmError     pgm_viewport_get_cursor            (PgmViewport *viewport,
                                                 PgmViewportCursor *cursor);

PgmError     pgm_viewport_set_icon              (PgmViewport *viewport,
                                                 GdkPixbuf *icon);
PgmError     pgm_viewport_get_icon              (PgmViewport *viewport,
                                                 GdkPixbuf **icon);

PgmError     pgm_viewport_set_size              (PgmViewport *viewport,
                                                 gint width,
                                                 gint height);
PgmError     pgm_viewport_get_size              (PgmViewport *viewport,
                                                 gint *width,
                                                 gint *height);

PgmError     pgm_viewport_set_alpha_blending    (PgmViewport *viewport,
                                                 gboolean alpha_blending);
PgmError     pgm_viewport_get_alpha_blending    (PgmViewport *viewport,
                                                 gboolean *alpha_blending);

PgmError     pgm_viewport_set_opacity           (PgmViewport *viewport,
                                                 guchar opacity);
PgmError     pgm_viewport_get_opacity           (PgmViewport *viewport,
                                                 guchar *opacity);

PgmError     pgm_viewport_set_fullscreen        (PgmViewport *viewport,
                                                 gboolean fullscreen);
PgmError     pgm_viewport_get_fullscreen        (PgmViewport *viewport,
                                                 gboolean *fullscreen);

PgmError     pgm_viewport_set_iconified         (PgmViewport *viewport,
                                                 gboolean iconified);
PgmError     pgm_viewport_get_iconified         (PgmViewport *viewport,
                                                 gboolean *iconified);

PgmError     pgm_viewport_focus                 (PgmViewport *viewport);

PgmError     pgm_viewport_set_screen_resolution (PgmViewport *viewport,
                                                 gint width,
                                                 gint height);
PgmError     pgm_viewport_get_screen_resolution (PgmViewport *viewport,
                                                 gint *width,
                                                 gint *height);

PgmError     pgm_viewport_set_screen_size_mm    (PgmViewport *viewport,
                                                 gint width,
                                                 gint height);
PgmError     pgm_viewport_get_screen_size_mm    (PgmViewport *viewport,
                                                 gint *width,
                                                 gint *height);

PgmError     pgm_viewport_push_event            (PgmViewport *viewport,
                                                 PgmEvent *event);

PgmError     pgm_viewport_get_canvas            (PgmViewport *viewport,
                                                 PgmCanvas **canvas);
PgmError     pgm_viewport_set_canvas            (PgmViewport *viewport,
                                                 PgmCanvas *canvas);

PgmError     pgm_viewport_set_canvas_rotation   (PgmViewport *viewport,
                                                 PgmViewportRotation rotation);
PgmError     pgm_viewport_get_canvas_rotation   (PgmViewport *viewport,
                                                 PgmViewportRotation *rotation);

PgmError     pgm_viewport_set_canvas_reflection (PgmViewport *viewport,
                                                 PgmViewportReflection reflection);
PgmError     pgm_viewport_get_canvas_reflection (PgmViewport *viewport,
                                                 PgmViewportReflection *reflection);

PgmError     pgm_viewport_set_message_filter    (PgmViewport *viewport,
                                                 GList *filter);
PgmError     pgm_viewport_get_message_filter    (PgmViewport *viewport,
                                                 GList **filter);

PgmError     pgm_viewport_update_projection     (PgmViewport *viewport);

PgmError     pgm_viewport_to_canvas             (PgmViewport *viewport,
                                                 gfloat *canvas_x,
                                                 gfloat *canvas_y,
                                                 gfloat *canvas_z,
                                                 gfloat viewport_x,
                                                 gfloat viewport_y,
                                                 gfloat viewport_z);

PgmError     pgm_viewport_from_canvas           (PgmViewport *viewport,
                                                 gfloat *viewport_x,
                                                 gfloat *viewport_y,
                                                 gfloat *viewport_z,
                                                 gfloat canvas_x,
                                                 gfloat canvas_y,
                                                 gfloat canvas_z);

PgmError     pgm_viewport_get_embedding_id      (PgmViewport *viewport,
                                                 gulong *embedding_id);

PgmError     pgm_viewport_get_pixel_formats     (PgmViewport *viewport,
                                                 gulong *formats_mask);

PgmError     pgm_viewport_get_caps_mask         (PgmViewport *viewport,
                                                 gulong *caps_mask);

PgmError     pgm_viewport_get_max_texture_size  (PgmViewport *viewport,
                                                 guint32 *max_texture_size);

PgmError     pgm_viewport_get_frame_rate        (PgmViewport *viewport,
                                                 guint *frame_rate);

PgmError     pgm_viewport_read_pixels           (PgmViewport *viewport,
                                                 guint x,
                                                 guint y,
                                                 guint width,
                                                 guint height,
                                                 guint8 *pixels);

PgmError     pgm_viewport_push_pixels           (PgmViewport *viewport,
                                                 guint width,
                                                 guint height,
                                                 guint8 *pixels);

PgmError     pgm_viewport_emit_update_pass      (PgmViewport *viewport);


/* Protected methods */

#ifdef WIN32
PgmError _pgm_viewport_push_win32_message (PgmViewport *viewport,
                                           PgmEvent *event,
                                           gint32 *message_processed,
                                           LRESULT *result);
#endif /* WIN32 */

G_END_DECLS

#endif /* __PGM_VIEWPORT_H__ */
