/*
 * sel_req.c: Example of how to make requests to a selection owner for
 *        the selection contents.
 */
#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;
Textsw      textsw;
Xv_Server   server;
Panel       panel;
Panel_item  p_selection,
            p_target,
            p_request;

Selection_requestor  sel;

#define TARGETS     1<<0
#define TIMESTAMP   1<<1
#define LENGTH      1<<2
#define STRING      1<<3
#define DELETE      1<<4
#define LINE        "------------------------------------------------------"

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

main(argc, argv)
int    argc;
char **argv;
{
    void    MakeRequest(),
            SelectionReplyProc(),
            RequestChoice();
    Xv_Font font;

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

    frame = xv_create((Window)NULL, FRAME,
                      XV_X,       10,
                      XV_Y,       10,
                      XV_LABEL,   "Selection Requestor Example",
                      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,
                      PANEL_LAYOUT,   PANEL_VERTICAL,
                      XV_FONT,    font,
                      NULL);

    p_selection = xv_create(panel, PANEL_TEXT,
                            PANEL_LABEL_STRING,         "Selection:",
                            PANEL_VALUE_DISPLAY_LENGTH,     40,
                            PANEL_NOTIFY_PROC,      MakeRequest,
                            NULL);
    p_target = xv_create(panel, PANEL_TOGGLE,
                         PANEL_LABEL_STRING,         "Request:",
                         PANEL_NOTIFY_PROC,      RequestChoice,
                         PANEL_CHOICE_STRINGS,       "TARGETS",
                         "TIMESTAMP",
                         "LENGTH",
                         "STRING",
                         "DELETE",
                         NULL,
                         NULL);
    p_request = xv_create(panel, PANEL_BUTTON,
                          PANEL_LABEL_STRING,     "Make Request",
                          PANEL_NOTIFY_PROC,  MakeRequest,
                          PANEL_ITEM_X,       xv_cols(panel, 20),
                          0);

    window_fit(panel);

    textsw = xv_create(frame, TEXTSW,
                       XV_X,       0,
                       XV_FONT,    font,
                       WIN_BELOW,  panel,
                       NULL);

    /* Create a selection requestor object. */
    sel = xv_create(panel, SELECTION_REQUESTOR,
                    SEL_REPLY_PROC, SelectionReplyProc,
                    NULL);

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

void
RequestChoice(item, value, event)
Panel_item       item;
unsigned int     value;
Event           *event;
{
    int   set = False;

    /* Build the request based on the toggle items the user has selected. */

    if(value & TARGETS)
    {
        if(set)
            xv_set(sel, SEL_APPEND_TYPE_NAMES, "TARGETS", NULL, NULL);
        else
            xv_set(sel, SEL_TYPE_NAME, "TARGETS", NULL);

        set = True;
    }

    if(value & TIMESTAMP)
    {
        if(set)
            xv_set(sel, SEL_APPEND_TYPE_NAMES, "TIMESTAMP", NULL, NULL);
        else
            xv_set(sel, SEL_TYPE_NAME, "TIMESTAMP", NULL);

        set = True;
    }

    if(value & LENGTH)
    {
        if(set)
            xv_set(sel, SEL_APPEND_TYPE_NAMES, "LENGTH", NULL, NULL);
        else
            xv_set(sel, SEL_TYPE_NAME, "LENGTH", NULL);

        set = True;
    }

    if(value & STRING)
    {
        if(set)
            xv_set(sel, SEL_APPEND_TYPE_NAMES, "STRING", NULL, NULL);
        else
            xv_set(sel, SEL_TYPE_NAME, "STRING", NULL);

        set = True;
    }

    if(value & DELETE)
    {
        if(set)
            xv_set(sel, SEL_APPEND_TYPE_NAMES, "DELETE", NULL, NULL);
        else
            xv_set(sel, SEL_TYPE_NAME, "DELETE", NULL);

        set = True;
    }
}

void
MakeRequest(item, event)
Panel_item       item;
Event           *event;
{
    if(item == p_selection)
    {
        char *rank = NULL;

        /* Set the rank of the selection we are going to make requests to. */
        rank = (char *)xv_get(item, PANEL_VALUE);
        xv_set(sel, SEL_RANK_NAME,  rank,
               NULL);
    }
    else
    {
        /* Post a non-blocking request to the selection holder. */
        sel_post_req(sel);
        textsw_erase(textsw, 0, TEXTSW_INFINITY);
    }
}

/* When the selection holder replies to our request(s), the
 * Selection reply procedure is called with the information we
 * requested.
 */
void
SelectionReplyProc(sel, target, type, value, length, format)
Selection_requestor sel;
Xv_opaque       value;
Atom        target;
Atom        type;
unsigned long   length;
int         format;
{
    if(length == SEL_ERROR)
    {
        SelectionError(sel, target, *(int *)value);
        return;
    }

    if(target == ATOM(server, "TARGETS"))
    {
        textsw_insert(textsw, "Holder will convert the following targets:\n",
                      43);

        do
        {
            Atom *targets = (Atom *)value;
            char *target_name;

            if(targets[--length])
            {
                target_name = (char *)xv_get(server, SERVER_ATOM_NAME,
                                             targets[length]);

                textsw_insert(textsw, "\t", 1);
                textsw_insert(textsw, target_name, strlen(target_name));
                textsw_insert(textsw, "\n", 1);
            }
        }
        while(length);
    }
    else if(target == ATOM(server, "TIMESTAMP"))
    {
        char buf[10];

        textsw_insert(textsw, "TIMESTAMP of acquisition: ", 26);
        sprintf(buf, "%lu\n", *(unsigned long *)value);
        textsw_insert(textsw, buf, strlen(buf));
    }
    else if(target == ATOM(server, "LENGTH"))
    {
        char buf[10];

        textsw_insert(textsw, "Length of selection: ", 21);
        sprintf(buf, "%d\n", *(int *)value);
        textsw_insert(textsw, buf, strlen(buf));
    }
    else if(target == ATOM(server, "STRING"))
    {
        static int  incr = False;

        if(type == ATOM(server, "INCR"))
        {
            textsw_insert(textsw, "Contents of the selection:\n", 27);
            incr = True;
        }
        else if(length)
        {
            if(!incr)
                textsw_insert(textsw, "Contents of the selection:\n", 27);

            textsw_insert(textsw, (char *)value, length);
            textsw_insert(textsw, "\n", 1);
        }
        else
            incr = False;
    }
    else if(target == ATOM(server, "DELETE"))
    {
        textsw_insert(textsw, "The Selection has been deleted\n", 31);
    }

    textsw_insert(textsw, LINE, strlen(LINE));
}

SelectionError(sel, target, errorCode)
Selection_requestor  sel;
Atom         target;
int          errorCode;
{
    Atom     rank;
    char    *rank_string;
    char    *target_string = (char *)xv_get(server, SERVER_ATOM_NAME, target);
    char     msg[100];

    rank = (Atom)xv_get(sel, SEL_RANK);
    rank_string = (char *)xv_get(server, SERVER_ATOM_NAME, rank);

    sprintf(msg, "Selection failed for rank ``%s'' on target ``%s'': ",
            rank_string, target_string);
    textsw_insert(textsw, msg, strlen(msg));

    switch(errorCode)
    {
    case SEL_BAD_PROPERTY :
        textsw_insert(textsw, "Bad Property", strlen("Bad Property"));
        break;

    case SEL_BAD_CONVERSION :
        textsw_insert(textsw, "Conversion Rejected",
                      strlen("Conversion Rejected"));
        break;

    case SEL_BAD_TIME:
        textsw_insert(textsw, "Bad Time Match", strlen("Bad Time Match"));
        break;

    case SEL_BAD_WIN_ID:
        textsw_insert(textsw, "Bad Window Match", strlen("Bad Window Match"));
        break;

    case SEL_TIMEDOUT:
        textsw_insert(textsw, "Timeout", strlen("Timeout"));
        break;
    }
}
