Skip to content

Instantly share code, notes, and snippets.

@gourish13
Forked from psychon/selection-test.c
Last active December 11, 2022 07:53
Show Gist options
  • Select an option

  • Save gourish13/57ce532f91ad2d232cd2fa18d1d583c6 to your computer and use it in GitHub Desktop.

Select an option

Save gourish13/57ce532f91ad2d232cd2fa18d1d583c6 to your computer and use it in GitHub Desktop.
Some attempts at X11 selections

Compile

gcc selection-test.c -lxcb -lxcb-xfixes -lxcb-util
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include <xcb/xcb_aux.h>
static xcb_connection_t *c;
static xcb_screen_t *screen;
static xcb_window_t event_window;
static xcb_atom_t selection = XCB_ATOM_PRIMARY;
static xcb_atom_t UTF8_STRING;
static xcb_atom_t foo;
static xcb_atom_t foo2;
static xcb_atom_t TARGETS;
static xcb_atom_t intern_atom(const char *str)
{
xcb_intern_atom_reply_t *rep;
xcb_atom_t atom;
uint16_t name_len = strlen(str);
rep = xcb_intern_atom_reply(c, xcb_intern_atom(c, 0, name_len, str), NULL);
atom = rep->atom;
free(rep);
return atom;
}
static void print_selection(void)
{
/* We should not use CurrentTime here, as per ICCCM */
xcb_convert_selection(c, event_window, selection, UTF8_STRING, foo, XCB_CURRENT_TIME);
xcb_convert_selection(c, event_window, selection, TARGETS, foo2, XCB_CURRENT_TIME);
}
int main() {
xcb_generic_event_t *ev;
const xcb_query_extension_reply_t *query_ext;
c = xcb_connect(NULL, NULL);
if(xcb_connection_has_error(c)) {
printf("cannot open display (error %d)\n", xcb_connection_has_error(c));
return 0;
}
query_ext = xcb_get_extension_data(c, &xcb_xfixes_id);
if(!query_ext) {
puts("XFixes extension is not present!");
xcb_disconnect(c);
return 0;
}
UTF8_STRING = intern_atom("UTF8_STRING");
TARGETS = intern_atom("TARGETS");
foo = intern_atom("FOO");
foo2 = intern_atom("FOO2");
#if 0
selection = XCB_ATOM_PRIMARY;
#else
selection = intern_atom("CLIPBOARD");
#endif
screen = xcb_aux_get_screen(c, 0);
event_window = xcb_generate_id(c);
xcb_create_window(c, screen->root_depth, event_window, screen->root,
-1, -1, 1, 1, 0, XCB_COPY_FROM_PARENT,
screen->root_visual, XCB_CW_EVENT_MASK,
(uint32_t[]) { XCB_EVENT_MASK_PROPERTY_CHANGE });
xcb_discard_reply(c, xcb_xfixes_query_version(c, 1, 0).sequence);
xcb_xfixes_select_selection_input(c, event_window, selection,
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
print_selection();
xcb_flush(c);
while ((ev = xcb_wait_for_event(c)) != NULL) {
uint8_t type = ev->response_type & 0x7f;
if (query_ext != NULL && type == query_ext->first_event + XCB_XFIXES_SELECTION_NOTIFY) {
xcb_xfixes_selection_notify_event_t *event = (xcb_xfixes_selection_notify_event_t *) ev;
printf("Selection changed, new owner is 0x%x\n", event->owner);
print_selection();
} else {
switch(type) {
case 0:
{
xcb_generic_error_t *generr = (xcb_generic_error_t *) ev;
printf("Got error %d from request %d:%d\n",
generr->error_code, generr->major_code,
generr->minor_code);
}
break;
case XCB_PROPERTY_NOTIFY:
/* Ignore */
break;
case XCB_SELECTION_NOTIFY: {
xcb_get_property_reply_t* reply;
xcb_atom_t *atoms;
xcb_selection_notify_event_t *sel_event = (xcb_selection_notify_event_t *) ev;
/* Since we have only a single 'thing' we request, we do not
* have to inspect the values of the event.
*/
puts("Got SelectionNotify");
/* This needs delete = true, as per ICCCM */
if (sel_event->property == foo2) {
reply = xcb_get_property_reply(c, xcb_get_property(c, 1, event_window, foo2, XCB_ATOM_ATOM, 0, 300), NULL);
atoms = xcb_get_property_value(reply);
printf("have %d TARGETS (should be 0: %d)\n", xcb_get_property_value_length(reply)/4, xcb_get_property_value_length(reply)%4);
for (int i = 0; 4*i < xcb_get_property_value_length(reply); i++) {
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(c,
xcb_get_atom_name(c, atoms[i]), NULL);
printf("%d: %.*s (0x%x)\n", i,
xcb_get_atom_name_name_length(reply),
xcb_get_atom_name_name(reply),
atoms[i]);
free(reply);
}
free(reply);
}
if (sel_event->property == foo) {
reply = xcb_get_property_reply(c, xcb_get_property(c, 1, event_window, foo, UTF8_STRING, 0, 300), NULL);
printf("Value is '%.*s'\n",
xcb_get_property_value_length(reply),
(char *) xcb_get_property_value(reply));
free(reply);
}
}
break;
default:
printf("Got unexpected event %d\n", ev->response_type);
}
}
free(ev);
xcb_flush(c);
}
xcb_disconnect(c);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment