/*
 * sel_hold.c: Example of how to acquire and hold a selection.
 *
 */
#include <stdio.h>
#include <X11/Xlib.h>
#include <xview/xview.h>
#include <xview/frame.h>
#include <xview/panel.h>
#include <xview/textsw.h>
#include <xview/font.h>
#include <xview/sel_pkg.h>

Frame       frame;
Xv_Server   server;
Panel       panel;
Panel_item  p_selection,
            p_contents,
            p_own,
            p_lose;

Selection_owner sel;
Selection_item  sel_targets;

#define ATOM(server, name)  (Atom)xv_get(server, SERVER_ATOM, name)

main(argc, argv)
int    argc;
char **argv;
{
    Panel_setting   NotifyProc();
    int         SelectionConvertProc();
    void        SelectionDoneProc(),
                SelectionLoseProc();
    Xv_Font     font;
    Atom        targets[5];

    server = xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);

    frame = xv_create((Window)NULL, FRAME,
                      XV_X,       520,
                      XV_Y,       655,
                      XV_LABEL,   "Selection Holder Example",
                      FRAME_SHOW_FOOTER,  True,
                      NULL);

    font = (Xv_Font)xv_find(frame, FONT, FONT_NAME, "lucida-19", NULL);

    if(!font)
    {
        fprintf(stderr, "Cannot use font: lucida-19.\n");
        font = (Xv_Font)xv_get(frame, XV_FONT);
    }

    panel = xv_create(frame, PANEL,
                      XV_FONT,    font,
                      NULL);

    p_selection = xv_create(panel, PANEL_TEXT,
                            PANEL_LABEL_STRING,         "Selection:",
                            PANEL_VALUE_DISPLAY_LENGTH,     40,
                            PANEL_NOTIFY_PROC,      NotifyProc,
                            PANEL_ITEM_X,           xv_col(panel, 0),
                            PANEL_ITEM_Y,           xv_row(panel, 0),
                            NULL);
    p_contents = xv_create(panel, PANEL_TEXT,
                           PANEL_LABEL_STRING,         "Contents:",
                           PANEL_VALUE_DISPLAY_LENGTH,     40,
                           PANEL_ITEM_X,           xv_col(panel, 0),
                           PANEL_ITEM_Y,           xv_row(panel, 1),
                           NULL);
    p_own = xv_create(panel, PANEL_BUTTON,
                      PANEL_LABEL_STRING,     "Own Selection",
                      PANEL_NOTIFY_PROC,  NotifyProc,
                      PANEL_ITEM_X,       xv_col(panel, 5),
                      PANEL_ITEM_Y,       xv_row(panel, 2),
                      NULL);
    p_lose = xv_create(panel, PANEL_BUTTON,
                       PANEL_LABEL_STRING,     "Lose Selection",
                       PANEL_NOTIFY_PROC,  NotifyProc,
                       PANEL_ITEM_X,       xv_col(panel, 30),
                       PANEL_ITEM_Y,       xv_row(panel, 2),
                       NULL);

    /* Create a selection owner object */
    sel = xv_create(panel, SELECTION_OWNER,
                    SEL_CONVERT_PROC,   SelectionConvertProc,
                    SEL_DONE_PROC,      SelectionDoneProc,
                    SEL_LOSE_PROC,      SelectionLoseProc,
                    NULL);

    targets[0] = (Atom)xv_get(server, SERVER_ATOM, "TARGETS");
    targets[1] = (Atom)xv_get(server, SERVER_ATOM, "TIMESTAMP");
    targets[2] = (Atom)xv_get(server, SERVER_ATOM, "LENGTH");
    targets[3] = (Atom)xv_get(server, SERVER_ATOM, "STRING");
    targets[4] = (Atom)xv_get(server, SERVER_ATOM, "DELETE");

    /* Create a selection item, ownened by the selection owner we just
     * created.  This pre-registers a conversion, in this case a
     * conversion for ``TARGETS''.
     */
    sel_targets = xv_create(sel, SELECTION_ITEM,
                            SEL_TYPE_NAME,      "TARGETS",
                            SEL_FORMAT,     32,
                            SEL_LENGTH,     5,
                            SEL_DATA, (Xv_opaque)targets,
                            NULL);

    window_fit(panel);
    window_fit(frame);
    xv_main_loop(frame);
    exit(0);
}

Panel_setting
NotifyProc(item, event)
Panel_item       item;
Event           *event;
{
    if(item == p_selection)
    {
        char     *rank;

        /* Get the rank of the selection the user would like to use. */
        rank = (char *)xv_get(item, PANEL_VALUE);
        /* Set the rank to our selection owner object. */
        xv_set(sel, SEL_RANK_NAME, rank, NULL);

        return(PANEL_NEXT);
    }
    else if(item == p_own)
    {
        /* The user pressed the ``own'' button, so we acquire the
         * selection.
         */
        xv_set(sel, SEL_OWN, True,
               SEL_TIME, &event_time(event),
               NULL);
        xv_set(frame, FRAME_LEFT_FOOTER, "Acquired Selection...", NULL);
    }
    else if(item == p_lose)
    {
        /* The user pressed the ``lose'' button, so we lose ownership
         * of the selection.
         */
        xv_set(sel, SEL_OWN, False,
               SEL_TIME, &event_time(event),
               NULL);
        xv_set(frame, FRAME_LEFT_FOOTER, "Lost Selection...", NULL);
    }

    return(PANEL_DONE);
}

/* The conversion procedure is called whenever some client makes
 * a request to our selection.  Its purpose is to respond to the
 * request.
 */
int
SelectionConvertProc(sel, target, data, length, format)
Selection_owner  sel;
Atom        *target;    /* Input/Output */
Xv_opaque       *data;      /* Output */
unsigned long   *length;    /* Output */
int         *format;    /* Output */
{
    /* Request for the length of the selection. */
    if(*target == ATOM(server, "LENGTH"))
    {
        static unsigned long     len;
        char            *contents;

        contents = (char *)xv_get(p_contents, PANEL_VALUE);
        len = strlen(contents);

        *target = ATOM(server, "INTEGER");
        *format = 32;
        *length = 1;
        *data = (Xv_opaque)&len;
        return(True);
        /* Request for the string contents of the selection. */
    }
    else if(*target == ATOM(server, "STRING"))
    {
        char            *contents;

        contents = (char *)xv_get(p_contents, PANEL_VALUE);

        *target = ATOM(server, "STRING");
        *format = 8;
        *length = strlen(contents);
        *data = (Xv_opaque)strdup(contents);
        return(True);
        /* Request to delete the selection. */
    }
    else if(*target == ATOM(server, "DELETE"))
    {
        xv_set(p_contents, PANEL_VALUE, "", NULL);
        *target = ATOM(server, "NULL");
        *format = 32;
        *length = 0;
        *data = (Xv_opaque)NULL;
        return(True);
    }
    else
        /* Call the default selection conversion procedure.  Will handle
         * requests for any pre-registered conversions.
         */
        return(sel_convert_proc(sel, target, data, length, format));
}

/* The selection done procedure is called after each conversion has
 * happened.  This gives the application a chance to free up
 * memory.
 */
void
SelectionDoneProc(sel, data, target)
Selection_owner  sel;
Xv_opaque       *data;
Atom         target;
{
    if(target == ATOM(server, "STRING"))
        free((char *)data);
}

/* If some other client acquires the selection we hold, the
 * selection lose procedure is called.  This tells us that we
 * no longer hold that selection.
 */
void
SelectionLoseProc(sel)
Selection_owner sel;
{
    xv_set(frame, FRAME_LEFT_FOOTER, "Lost Selection...", NULL);
}
