Example A-2. The text_seln.c program (continued)
lines_selected = *(long *)(ptr += sizeof(SELN_REQ_LAST_UNIT));
ptr += sizeof(long);
/* hack to workaround bug with SELN_REQ_LAST_UNIT always
* returning -1. Count the lines explicitly in the selection.
*/
if (lines_selected < 0) {
register char *p;
lines_selected++;
for (p = selection_buf; *p; p++)
if (*p == ’\n’)
lines_selected++;
}
printf("index in textsw: %d–%d, line number(s) = %d–%d\n",
first+1, last+1, sel_lin_num+1,
sel_lin_num + lines_selected + 1);
} else {
/* the selection does not lie in our text subwindow */
response = selection_ask(server, &holder,
SELN_REQ_CONTENTS_ASCII, NULL,
NULL);
if (response->status != SELN_SUCCESS) {
printf("selection_ask() returns %d\n", response–>status);
return NULL;
}
(void) strcpy(selection_buf,
response->data + sizeof(SELN_REQ_CONTENTS_ASCII));
}
return selection_buf;
}
There are several points of interest here. In the function get_selection(), once the
holder of the client has been obtained, it is tested to see if the holder is the text subwindow
using seln_holder_same_client(). If so, selection_ask() is called requesting
information specific to the text subwindow. If the text subwindow is not the holder of the
selection, then selection_ask() is called requesting only the ASCII contents. If there is
no selection, then the status field of the structure is set to SELN_FAILED.
In the case where the holder is the text subwindow, we ask it for the first and last indices of
the selection relative to the beginning of the text stream. Note that we might not be able to
request this information from any object. For example, if the selection were inside an xterm,
then this information would not be available and the xterm’s selection client would not
respond to such requests.
The next attribute (
SELN_REQ_CONTENTS_ASCII) requests the ASCII contents of the
selection actually made. Following that, the attribute-value pair:
SELN_REQ_FAKE_LEVEL, SELN_LEVEL_LINE
fools the text subwindow into thinking that the user selected an entire line of text (in
OPEN LOOK, this would have meant a triple-click with the SELECT mouse button). Had this
attribute-value pair been listed before the request for ASCII contents, the text returned by the
request would have contained the entire line of text on which the selection occurred regard-
less of whether the selection began at the beginning of the line.
The Selection
Service
The Selection Service 645
The reason we fake the text window into thinking the entire line has been selected is: the
attributes SELN_REQ_FIRST_UNIT and SELN_REQ_LAST_UNIT request the line numbers that
the selection spans. As the names of the attributes imply, the request is for the first and last
units selected. Setting the SELN_REQ_FAKE_LEVEL attribute to SELN_LEVEL_LINE indicates
that the unit type should be line. Note that we fake the fact that the selection unit is set to
line just to get the start and end line numbers of the selection. If we wanted to actually set
the level, we would have used SELN_REQ_SET_LEVEL.
After selection_ask() returns a pointer to a Seln_request structure, the values of
the requested attributes are found in data, the byte stream. As demonstrated in Example
A-2 above, the way to retrieve these values is by moving a pointer along the array:
Seln_request *response;
char *ptr;
long value;
...
response = selection_ask(server, &holder,
ATTR1, NULL,
ATTR2, NULL,
...
NULL);
...
/* set the ptr to beginning of data response -- first attribute */
ptr = response->data;
/* value is data succeeding first attribute -- skip over attr */
value = *(long *)(ptr += sizeof(Seln_attribute));
ptr += sizeof(long); /* skip over the size of the type of value */
There is no need to test the attributes as you scan data; they are the same attributes that you
used in selection_ask() and they remain in the same order. The values you get back
are almost always long.* The exception to this is the text string returned when
SELN_REQ_CONTENTS_ASCII is specified. However, the text string is padded to a 4-byte
boundary to make sure that the alignment is correct. text_seln.c demonstrates how this is
done.
A.4 Using selection_query()
One problem with using selection_ask() is handling large selections. In this context,
“large” means a text string that is long enough so that it, along with all its attributes and val-
ues, does not fit in the data byte-stream. Of course, the fewer attributes that are requested,
the more text is returned from the selection.
In this case, the problem is that there is an upper limit to the number of bytes that can be
retrieved from the selection. There is no guarantee that the user is not going to select a large
number of bytes from some arbitrary application on the screen. However, there is another
way to get the selection, regardless of how large it is, by using selection_query():
*Architectures whose int type does not equal its long type must be sure to compensate for this.
646 XView Programming Manual
Seln_result
selection_query(server, holder, reader, context,
attrs
)
Xv_Server server;
Seln_holder *holder;
Seln_result (*reader)();
char *context;
<attribute-value list>
attrs
The primary feature of this routine is that you provide it with a pointer to a function that does
the scanning of the data array in the Seln_request structure, as demonstrated earlier.
Your reader function is called by selection_query(), and it gets the
Seln_request structure as the sole parameter to your function. Your function takes the
form of:
Seln_result
reader(request)
Seln_request *request;
Your function should return SELN_SUCCESS provided that you encountered no problems with
scanning request->data. selection_query() returns the same Seln_result
that your reader function returns. Your reader function is called by
selection_query() for each chunk of data in the selection.* The flowchart in Figure
A-2 shows the sequence of operations.
The program in Example A-3 demonstrates the use of selection_query(). It is similar
to text_seln.c, but this new program also provides for selections from one of three selection
ranks. The user chooses the selection rank from the panel choice item. When the Get
Selection button is pressed, the current selection from that selection rank is displayed.
The point of the program is to demonstrate the flow of control between
selection_query() and the client-installed reader procedure. The text subwindow in
the application loads the file /etc/termcap. When a selection is made,
selection_query() is called, which in turn calls the reader procedure. You can make
an arbitrarily large selection to show how read_proc is called many times. Start by ini-
tializing the selection and then scrolling the window and extending the selection by using the
ADJUST mouse button on later text. Select the Get Selection panel button and the output is
directed to stdout. Because the selection size can be large, the output text is truncated to
the first 20 characters of the selection.
Example A-3. The long_seln.c program
/*
* long_seln.c shows how to get an arbitrarily large selection by
* providing a reading procedure to selection_query(). The panel
* items allow the user to choose between 3 selection ranks.
*/
#include <xview/xview.h>
#include <xview/textsw.h>
#include <xview/panel.h>
#include <xview/seln.h>
*A chunk is the largest text string that will fit in the data field of the Seln_request structure.
The Selection
Service
The Selection Service 647
return-value
(Seln-result)
Yes
reader(Seln_request)
SELN_SUCCESS
SELN_???? (error)
No
(return-value)
More
selection
to read?
Error
reading
request?
No
Yes
selection_query()
Figure A-2. How selection_query() is used
Example A-3. The long_seln.c program (continued)
extern char *malloc();
Seln_rank seln_type = SELN_PRIMARY;
#define FIRST_BUFFER 0
#define NOT_FIRST_BUFFER !FIRST_BUFFER
char *seln_bufs[3 ]; /* contents of each of the three selections */
Seln_result read_proc(); /* supplied to selection_query() as reader */
Textsw textsw; /* select from this textsw */
Xv_Server server;
char *get_selection();
void
change_selection(item, value)
648 XView Programming Manual
Example A-3. The long_seln.c program (continued)
Panel_item item;
int value;
{
if (value == 0)
seln_type = SELN_PRIMARY;
else if (value == 1)
seln_type = SELN_SECONDARY;
else
seln_type = SELN_SHELF;
}
main(argc, argv)
char *argv[ ];
{
Frame frame;
Panel panel;
void print_seln(), exit();
xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
frame = (Frame) xv_create(NULL, FRAME,
FRAME_LABEL, argv[0 ],
NULL);
panel = (Panel)xv_create(frame, PANEL,
WIN_WIDTH, WIN_EXTEND_TO_EDGE,
NULL);
(void) xv_create(panel, PANEL_BUTTON,
PANEL_LABEL_STRING, "Quit",
PANEL_NOTIFY_PROC, exit,
NULL);
(void) xv_create(panel, PANEL_BUTTON,
PANEL_LABEL_STRING, "Get Selection",
PANEL_NOTIFY_PROC, print_seln,
NULL);
(void) xv_create(panel, PANEL_CHOICE,
PANEL_LABEL_STRING, "Selection Type",
PANEL_CHOICE_STRINGS, "Primary", "Secondary", "Shelf", NULL,
PANEL_NOTIFY_PROC, change_selection,
NULL);
window_fit(panel);
textsw = (Textsw)xv_create(frame, TEXTSW,
WIN_X, 0,
WIN_BELOW, panel,
WIN_ROWS, 10,
WIN_COLUMNS, 80,
TEXTSW_FILE_CONTENTS, "/etc/termcap",
NULL);
window_fit(frame);
server = (Xv_Server)xv_get(xv_get(frame, XV_SCREEN), SCREEN_SERVER);
xv_main_loop(frame);
}
void
print_seln()
The Selection
Service
The Selection Service 649
Get Volume 7A: XView Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.