/*
 * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#ifndef HEADLESS

#include <X11/IntrinsicP.h>
#include "VDrawingAreaP.h"

#endif /* !HEADLESS */

#include <stdio.h>
#include <malloc.h>

#ifdef __linux__
/* XXX: Shouldn't be necessary. */
#include "awt_p.h"
#endif /* __linux__ */


/******************************************************************
 *
 * Provides Canvas widget which allows the X11 visual to be
 * changed (the Motif DrawingArea restricts the visual to that
 * of the parent widget).
 *
 ******************************************************************/


/******************************************************************
 *
 * VDrawingArea Widget Resources
 *
 ******************************************************************/

#ifndef HEADLESS
#define Offset(x)       (XtOffsetOf(VDrawingAreaRec, x))
static XtResource resources[]=
{
        { XtNvisual, XtCVisual, XtRVisual, sizeof(Visual*),
          Offset(vdrawing_area.visual), XtRImmediate, CopyFromParent}
};


static void Realize();
static Boolean SetValues();
static void Destroy ();

static XmBaseClassExtRec baseClassExtRec = {
    NULL,
    NULLQUARK,
    XmBaseClassExtVersion,
    sizeof(XmBaseClassExtRec),
    NULL,                               /* InitializePrehook    */
    NULL,                               /* SetValuesPrehook     */
    NULL,                               /* InitializePosthook   */
    NULL,                               /* SetValuesPosthook    */
    NULL,                               /* secondaryObjectClass */
    NULL,                               /* secondaryCreate      */
    NULL,                               /* getSecRes data       */
    { 0 },                              /* fastSubclass flags   */
    NULL,                               /* getValuesPrehook     */
    NULL,                               /* getValuesPosthook    */
    NULL,                               /* classPartInitPrehook */
    NULL,                               /* classPartInitPosthook*/
    NULL,                               /* ext_resources        */
    NULL,                               /* compiled_ext_resources*/
    0,                                  /* num_ext_resources    */
    FALSE,                              /* use_sub_resources    */
    NULL,                               /* widgetNavigable      */
    NULL,                               /* focusChange          */
    NULL                                /* wrapper_data         */
};

VDrawingAreaClassRec vDrawingAreaClassRec = {
{
    /* Core class part */

    /* superclass         */    (WidgetClass)&xmDrawingAreaClassRec,
    /* class_name         */    "VDrawingArea",
    /* widget_size        */    sizeof(VDrawingAreaRec),
    /* class_initialize   */    NULL,
    /* class_part_initialize*/  NULL,
    /* class_inited       */    FALSE,
    /* initialize         */    NULL,
    /* initialize_hook    */    NULL,
    /* realize            */    Realize,
    /* actions            */    NULL,
    /* num_actions        */    0,
    /* resources          */    resources,
    /* num_resources      */    XtNumber(resources),
    /* xrm_class          */    NULLQUARK,
    /* compress_motion    */    FALSE,
    /* compress_exposure  */    FALSE,
    /* compress_enterleave*/    FALSE,
    /* visible_interest   */    FALSE,
    /* destroy            */    Destroy,
    /* resize             */    XtInheritResize,
    /* expose             */    XtInheritExpose,
    /* set_values         */    SetValues,
    /* set_values_hook    */    NULL,
    /* set_values_almost  */    XtInheritSetValuesAlmost,
    /* get_values_hook    */    NULL,
    /* accept_focus       */    NULL,
    /* version            */    XtVersion,
    /* callback_offsets   */    NULL,
    /* tm_table           */    NULL,
    /* query_geometry       */  NULL,
    /* display_accelerator  */  NULL,
    /* extension            */  NULL
  },

   {            /* composite_class fields */
      XtInheritGeometryManager,                 /* geometry_manager   */
      XtInheritChangeManaged,                   /* change_managed     */
      XtInheritInsertChild,                     /* insert_child       */
      XtInheritDeleteChild,                     /* delete_child       */
      NULL,                                     /* extension          */
   },

   {            /* constraint_class fields */
      NULL,                                     /* resource list        */
      0,                                        /* num resources        */
      0,                                        /* constraint size      */
      NULL,                                     /* init proc            */
      NULL,                                     /* destroy proc         */
      NULL,                                     /* set values proc      */
      NULL,                                     /* extension            */
   },

   {            /* manager_class fields */
      XtInheritTranslations,                    /* translations           */
      NULL,                                     /* syn_resources          */
      0,                                        /* num_get_resources      */
      NULL,                                     /* syn_cont_resources     */
      0,                                        /* num_get_cont_resources */
      XmInheritParentProcess,                   /* parent_process         */
      NULL,                                     /* extension           */
   },

   {            /* drawingArea class */
           /* extension */      NULL
   },

   /* VDrawingArea class part */
   {
        /* extension    */      NULL
   }
};

WidgetClass vDrawingAreaClass = (WidgetClass)&vDrawingAreaClassRec;

static Boolean
SetValues(cw, rw, nw, args, num_args)
    Widget cw;
    Widget rw;
    Widget nw;
    ArgList args;
    Cardinal *num_args;
{
    VDrawingAreaWidget current = (VDrawingAreaWidget)cw;
    VDrawingAreaWidget new_w = (VDrawingAreaWidget)nw;

    if (new_w->vdrawing_area.visual != current->vdrawing_area.visual) {
        new_w->vdrawing_area.visual = current->vdrawing_area.visual;
#ifdef DEBUG
        fprintf(stdout, "VDrawingArea.SetValues: can't change visual from: visualID=%ld to visualID=%ld\n",
                     current->vdrawing_area.visual->visualid,
                     new_w->vdrawing_area.visual->visualid);
#endif

    }

    return (False);
}

int
FindWindowInList (Window parentWindow, Window *colormap_windows, int count)
{
    int i;

    for (i = 0; i < count; i++)
        if (colormap_windows [i] == parentWindow)
           return i;
    return -1;
}

static void
Realize(w, value_mask, attributes)
    Widget               w;
    XtValueMask          *value_mask;
    XSetWindowAttributes *attributes;
{
    Widget parent;
    Status status;
    Window *colormap_windows;
    Window *new_colormap_windows;
    int count;
    int i;
    VDrawingAreaWidget vd = (VDrawingAreaWidget)w;

#ifdef DEBUG
    fprintf(stdout, "VDrawingArea.Realize: visualID=%ld, depth=%d\n",
                        vd->vdrawing_area.visual->visualid, w->core.depth);
#endif

    /* 4328588:
     * Since we have our own Realize() function, we don't execute the one for
     * our super-super class, XmManager, and miss the code which checks that
     * height and width != 0.  I've added that here.  -bchristi
     */
    if (!XtWidth(w)) XtWidth(w) = 1 ;
    if (!XtHeight(w)) XtHeight(w) = 1 ;

    w->core.window = XCreateWindow (XtDisplay (w), XtWindow (w->core.parent),
                        w->core.x, w->core.y, w->core.width, w->core.height,
                        0, w->core.depth, InputOutput,
                        vd->vdrawing_area.visual,
                        *value_mask, attributes );

    /* Need to add this window to the list of Colormap windows */
    parent = XtParent (w);
    while ((parent != NULL) && (!(XtIsShell (parent))))
        parent = XtParent (parent);
    if (parent == NULL) {
        fprintf (stderr, "NO TopLevel widget?!\n");
        return;
    }

    status = XGetWMColormapWindows (XtDisplay (w), XtWindow (parent),
                                    &colormap_windows, &count);

    /* If status is zero, add this window and shell to the list
       of colormap Windows */
    if (status == 0) {
        new_colormap_windows = (Window *) calloc (2, sizeof (Window));
        new_colormap_windows [0] = XtWindow (w);
        new_colormap_windows [1] = XtWindow (parent);
        XSetWMColormapWindows (XtDisplay (w), XtWindow (parent),
                               new_colormap_windows, 2);
        free (new_colormap_windows);
    } else {
        /* Check if parent is already in the list */
        int parent_entry = -1;

        if (count > 0)
            parent_entry = FindWindowInList (XtWindow (parent),
                                        colormap_windows, count);
        if (parent_entry == -1) {  /*  Parent not in list  */
            new_colormap_windows = (Window *) calloc (count + 2,
                                                sizeof (Window));
            new_colormap_windows [0] = XtWindow (w);
            new_colormap_windows [1] = XtWindow (parent);
            for (i = 0; i < count; i++)
                new_colormap_windows [i + 2] = colormap_windows [i];
            XSetWMColormapWindows (XtDisplay (w), XtWindow (parent),
                                   new_colormap_windows, count + 2);

        } else {        /* parent already in list, just add new window */
            new_colormap_windows = (Window *) calloc (count + 1,
                                                sizeof (Window));
            new_colormap_windows [0] = XtWindow (w);
            for (i = 0; i < count; i++)
                new_colormap_windows [i + 1] = colormap_windows [i];
            XSetWMColormapWindows (XtDisplay (w), XtWindow (parent),
                                   new_colormap_windows, count + 1);
        }
        free (new_colormap_windows);
        XFree (colormap_windows);
    }


}

static void
Destroy(Widget widget)
{
    Status status;
    Widget parent;
    Window *colormap_windows;
    Window *new_colormap_windows;
    int count;
    int listEntry;
    int i;
    int j;

    /* Need to get this window's parent shell first */
    parent = XtParent (widget);
    while ((parent != NULL) && (!(XtIsShell (parent))))
        parent = XtParent (parent);
    if (parent == NULL) {
        fprintf (stderr, "NO TopLevel widget?!\n");
        return;
    }

    status = XGetWMColormapWindows (XtDisplay (widget), XtWindow (parent),
                                    &colormap_windows, &count);

    /* If status is zero, then there were no colormap windows for
       the parent ?? */

    if (status == 0)
        return;

    /* Remove this window from the list of colormap windows */
    listEntry = FindWindowInList (XtWindow (widget), colormap_windows,
                                  count);

    new_colormap_windows = (Window *) calloc (count - 1, sizeof (Window));
    j = 0;
    for (i = 0; i < count; i++) {
        if (i == listEntry)
           continue;
        new_colormap_windows [j] = colormap_windows [i];
        j++;
    }
    XSetWMColormapWindows (XtDisplay (widget), XtWindow (parent),
                           new_colormap_windows, count - 1);
    free (new_colormap_windows);
    XFree (colormap_windows);

}
#endif /* !HEADLESS */
