/* Definitions for use in *-xlike-inc.c files.
   Copyright (C) 2010 Ben Wing.

This file is part of XEmacs.

XEmacs is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

XEmacs 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 General Public License
for more details.

You should have received a copy of the GNU General Public License
along with XEmacs.  If not, see <http://www.gnu.org/licenses/>. */

/* Synched up with: Not in FSF. */

#ifndef INCLUDED_console_xlike_inc_h_
#define INCLUDED_console_xlike_inc_h_

/* X and GTK are quite similar, since GTK based its structure on Xlib.
   However, there are many small differences.  Creating two separate
   versions of the code, as Bill Perry did originally, is easier to code
   but hard to maintain and leads to bit rot.  On the other hand, trying to
   abstract out into device methods, as is done generally for different
   window systems, gets very hairy very quickly because the differences are
   on the level of individual library functions, constants and types, of
   which there are large number.  Abstracting them into device methods
   would lead to a large number of very small functions and very
   hard-to-read code.

   Instead, we handle the situation by the following:

   (1) In cases where there are lots of individual differences, we have
   only one copy, placed in a file called *-xlike-inc.c
   (e.g. redisplay-xlike-inc.c), and conditionalize using ifdefs.  Because
   we can compile with both X and GTK at once, we include this file inside
   of the appropriate device-specific file (e.g. redisplay-gtk.c or
   redisplay-x.c).  The `inc' in *-xlike-inc.c indicates that this is a
   file meant to be included in another file, despite the fact that it is a
   .c file.

   To signal which variety of "xlike" we are compiling for, either
   THIS_IS_X or THIS_IS_GTK needs to be defined, prior to including the
   *-xlike-inc.c file.

   (2) For code that is identical in both versions, or where it's possible
   to have only one copy at runtime through some other means, we name
   the file *-xlike.c.  This is a normal file, not included in some other
   file.  An example of "other means" is toolbar-xlike.c, where all
   functions are passed a frame or device, and it's possible to do run-time
   conditionalization based on the device type. (This isn't currently the
   case but will be soon once the related changes from my `hg-fixup'
   workspace are checked in. --ben) */


/* About the representation of color below:

   X has two ways of representing a color: (a) as an unsigned long
   representing a color pixel value, i.e. the actual value stored in memory
   or a file at a particular pixel location to indicate that the pixel
   takes on a specific color; and (b) an XColor structure, which
   encapsulates both the RGB components of a color and the associated color
   pixel value.

   We call the former type XLIKE_PIXEL and the latter XLIKE_COLOR, along
   with routines to convert from one to the other.  Differences between the
   two in specific functions and structures should be abstracted using the
   XLIKE_FOO() routines, e.g. XLIKE_SET_CLIP_RECTANGLE(). */

#if defined (THIS_IS_X) && defined (THIS_IS_GTK)
#error "Exactly one of THIS_IS_X and THIS_IS_GTK may be defined."
#endif

#if !defined (THIS_IS_X) && !defined (THIS_IS_GTK)
#error "Either THIS_IS_X or THIS_IS_GTK must be defined."
#endif

#ifdef THIS_IS_X
#  include "console-x-impl.h"
#  ifdef NEED_GCCACHE_H
#    include "gccache-x.h"
#  endif
#  ifdef NEED_GLYPHS_H
#    include "glyphs-x.h"
#  endif
#  ifdef NEED_OBJECTS_IMPL_H
#    include "fontcolor-x-impl.h"
#  endif
#else /* THIS_IS_GTK */
#  include "console-gtk-impl.h"
#  ifdef NEED_GLYPHS_H
#    include "glyphs-gtk.h"
#  endif
#  ifdef NEED_OBJECTS_IMPL_H
#    include "fontcolor-gtk-impl.h"
#  endif
#endif /* THIS_IS_GTK */

/* Just because we have XFT support doesn't mean we should use it.
   In particular, the xlike routines are used by both X and GTK code,
   but XFT stuff is X-specific.  HAVE_XFT will still be defined when
   the GTK flavor is active, but we don't want to trigger the XFT code
   in this case.  We could just undefine HAVE_XFT but I'd rather make
   it clearer that something else is going on. --ben */

#if defined (THIS_IS_X) && defined (HAVE_XFT)
#define XEMACS_USE_XFT
#define XEMACS_USE_XFT_MENUBARS
#define XEMACS_USE_XFT_TABS
#define XEMACS_USE_XFT_GAUGES
#endif

/***************************************************************************/
/*                           Common definitions                            */
/***************************************************************************/

#define XLIKE_PASTE_1(a,b) a##_##b
#define XLIKE_PASTE(a,b) XLIKE_PASTE_1(a,b)
#define XFUN(name) XLIKE_PASTE (XLIKE_NAME, name)

#define XLIKE_CONSOLE_HAS_METHOD_1(xlike, name) CONSOLE_HAS_METHOD (xlike, name)
#define XLIKE_CONSOLE_HAS_METHOD(name) \
  XLIKE_CONSOLE_HAS_METHOD_1 (XLIKE_NAME, name)

#define XCOLOR_INSTANCE_XLIKE_COLOR(x) \
  COLOR_INSTANCE_XLIKE_COLOR (XCOLOR_INSTANCE (x))

#ifdef THIS_IS_X

/***************************************************************************/
/*               Definitions implementing X flavor of XLIKE                */
/***************************************************************************/

#define XLIKE_NAME x
#define USED_IF_X(var) var
#define USED_IF_GTK(var) UNUSED (var)

/* types */
typedef Display * XLIKE_DISPLAY;
typedef Window XLIKE_WINDOW;
typedef XRectangle XLIKE_RECTANGLE;
typedef XColor XLIKE_COLOR;
typedef unsigned long XLIKE_PIXEL;

/* constants */
#define XLIKE_NONE None
#define XLIKE_FALSE False

#define XLIKE_GX_COPY GXcopy
#define XLIKE_GX_XOR GXxor

#define XLIKE_FILL_STIPPLED FillStippled
#define XLIKE_FILL_OPAQUE_STIPPLED FillOpaqueStippled
#define XLIKE_FILL_TILED FillTiled
#define XLIKE_FILL_SOLID FillSolid

/* functions */
#define GET_XLIKE_DISPLAY(d) DEVICE_X_DISPLAY (d)
#define GET_XLIKE_X_DISPLAY(d) DEVICE_X_DISPLAY (d)
#define GET_XLIKE_WINDOW(w) XtWindow (FRAME_X_TEXT_WIDGET (f))
#define XLIKE_FILL_RECTANGLE(dpy, x_win, gc, x, y, width, height) \
  XFillRectangle (dpy, x_win, gc, x, y, width, height)
#define XLIKE_DRAW_RECTANGLE(dpy, x_win, gc, x, y, width, height) \
  XDrawRectangle (dpy, x_win, gc, x, y, width, height)
#define XLIKE_DRAW_LINE(dpy, x_win, gc, x1, y1, x2, y2) \
  XDrawLine (dpy, x_win, gc, x1, y1, x2, y2)
#define XLIKE_TEXT_WIDTH(fi, ptr, len) XTextWidth (fi, (char *) ptr, len)
#define XLIKE_TEXT_WIDTH_WIDE(fi, ptr, len) XTextWidth16 (fi, (XChar2b *) ptr, len)

#define XLIKE_DISPLAY_LINE_HEIGHT(dl) DISPLAY_LINE_HEIGHT (dl)
#define XLIKE_DISPLAY_LINE_YPOS(dl) DISPLAY_LINE_YPOS (dl)
#define XLIKE_DISPLAY_LINE_TOP_CLIP(dl) ((dl)->top_clip)
#define XLIKE_SET_CLIP_RECTANGLE(dpy, gc, xorig, yorig, prect)		\
  /* #### why not Unsorted? */						\
  XSetClipRectangles (dpy, gc, xorig, yorig, prect, 1, YXBanded)
#define XLIKE_CLEAR_CLIP_MASK(dpy, gc)		\
do						\
  {						\
    XSetClipMask (dpy, gc, None);		\
    XSetClipOrigin (dpy, gc, 0, 0);		\
  }						\
while (0)
#define XLIKE_FLUSH(dpy) XSync (dpy, False)
#define XLIKE_CLEAR_AREA(dpy, win, x, y, width, height) \
  XClearArea (dpy, win, x, y, width, height, False)
 
#define IMAGE_INSTANCE_XLIKE_MASK IMAGE_INSTANCE_X_MASK
#define XIMAGE_INSTANCE_XLIKE_PIXMAP XIMAGE_INSTANCE_X_PIXMAP
#define COLOR_INSTANCE_XLIKE_COLOR COLOR_INSTANCE_X_COLOR
#define FONT_INSTANCE_XLIKE_FONT FONT_INSTANCE_X_FONT
#define XLIKE_FONT_NUM(val) ((val)->fid)
#define XLIKE_ICHAR_CHARSET(c) ichar_charset (c)

/************ End X flavor of XLIKE **********/


#else /* THIS_IS_GTK */

/***************************************************************************/
/*              Definitions implementing GTK flavor of XLIKE               */
/***************************************************************************/

#define XLIKE_NAME gtk
#define USED_IF_X(var) UNUSED (var)
#define USED_IF_GTK(var) var

/*types */
typedef void * XLIKE_DISPLAY;
typedef GdkWindow * XLIKE_WINDOW;
typedef GdkRectangle XLIKE_RECTANGLE;
#ifdef HAVE_GTK2
typedef GdkColor XLIKE_COLOR;
#else
typedef GdkRGBA XLIKE_COLOR;
#endif
typedef gulong   XLIKE_PIXEL;

/* constants */
#define XLIKE_NONE 0
#define XLIKE_FALSE FALSE

#define XLIKE_FILL_STIPPLED GDK_STIPPLED
#define XLIKE_FILL_OPAQUE_STIPPLED GDK_OPAQUE_STIPPLED
#define XLIKE_FILL_TILED GDK_TILED
#define XLIKE_FILL_SOLID GDK_SOLID

/* functions */

/* Avoid unused-variable warning involving D */
#define GET_XLIKE_DISPLAY(d) (d)
#define GET_XLIKE_X_DISPLAY(d) (USED (d), GDK_DISPLAY ())
#define GET_XLIKE_WINDOW(w) gtk_widget_get_window (FRAME_GTK_TEXT_WIDGET (w))
#define XLIKE_FILL_RECTANGLE(dpy, x_win, gc, x, y, width, height)	\
  (USED (dpy), gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE,	\
                                   x, y, width, height))
#define XLIKE_DRAW_RECTANGLE(dpy, x_win, gc, x, y, width, height)	\
  (USED (dpy), gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE,	\
                                   x, y, width, height))
#define XLIKE_DRAW_LINE(dpy, x_win, gc, x1, y1, x2, y2)			\
  (USED (dpy), gdk_draw_line (GDK_DRAWABLE (x_win), gc, x1, y1, x2, y2))
#define XLIKE_TEXT_WIDTH(fi, ptr, len) \
  gdk_text_width (fi, (char *) ptr, len)
#ifdef USE_PANGO
#define XLIKE_TEXT_WIDTH_WIDE(fi, ptr, len)             \
  pango_text_width_wc (fi, (GdkWChar *) ptr, len)
#else
#define XLIKE_TEXT_WIDTH_WIDE(fi, ptr, len)             \
  gdk_text_width_wc (fi, (GdkWChar *) ptr, len)
#endif

/* FIXME: This is totally bogus.  It removes dl->top_clip from the
   equations.  If there is a bug involving this, fix it properly!
   Or just ensure that top_clip is 0. */
#define XLIKE_DISPLAY_LINE_HEIGHT(dl) \
  ((dl)->ascent + (dl)->descent - (dl)->clip)
#define XLIKE_DISPLAY_LINE_YPOS(dl) ((dl)->ypos - (dl)->ascent)
#define XLIKE_DISPLAY_LINE_TOP_CLIP(dl) (0)
#define XLIKE_SET_CLIP_RECTANGLE(dpy, gc, xorig, yorig, prect)	\
do								\
  {								\
    USED (dpy);							\
    gdk_gc_set_clip_rectangle (gc, prect);			\
    gdk_gc_set_clip_origin (gc, xorig, yorig);			\
  }								\
while (0)
#define XLIKE_CLEAR_CLIP_MASK(dpy, gc)		\
do						\
  {						\
    USED (dpy);					\
    gdk_gc_set_clip_rectangle (gc, NULL);	\
    gdk_gc_set_clip_origin (gc, 0, 0);		\
  }						\
while (0)
#define XLIKE_FLUSH(dpy) gdk_flush ()
#define XLIKE_CLEAR_AREA(dpy, win, x, y, width, height) \
  (USED (dpy), gdk_window_clear_area (win, x, y, width, height))

#define IMAGE_INSTANCE_XLIKE_MASK IMAGE_INSTANCE_GTK_MASK
#define XIMAGE_INSTANCE_XLIKE_PIXMAP XIMAGE_INSTANCE_GTK_PIXMAP
#define COLOR_INSTANCE_XLIKE_COLOR(ci) (*COLOR_INSTANCE_GTK_COLOR (ci))
#define FONT_INSTANCE_XLIKE_FONT FONT_INSTANCE_GTK_FONT
#define XLIKE_FONT_NUM(val) (val)
#define XLIKE_ICHAR_CHARSET(c) Vcharset_ascii

/************ End GTK flavor of XLIKE **********/

#endif /* (not) THIS_IS_X */


#endif /* INCLUDED_console_xlike_inc_h_ */
