gcc selection-test.c -lxcb -lxcb-xfixes -lxcb-util
-
-
Save gourish13/57ce532f91ad2d232cd2fa18d1d583c6 to your computer and use it in GitHub Desktop.
Some attempts at X11 selections
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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