<commit_before>/*  vdagent-x11.c vdagent x11 code

    Copyright 2010 Red Hat, Inc.

    Red Hat Authors:
    <NAME> <<EMAIL>>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or   
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* Note: Our event loop is only called when there is data to be read from the
   X11 socket. If events have arrived and have already been read by libX11 from
   the socket triggered by other libX11 calls from this file, the select for
   read in the main loop, won't see these and our event loop won't get called!
   
   Thus we must make sure that all queued events have been consumed, whenever
   we return to the main loop. IOW all (externally callable) functions in this
   file must end with calling XPending and consuming all queued events.
   
   Calling XPending when-ever we return to the mainloop also ensures any
   pending writes are flushed. */

#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <assert.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xfixes.h>
#include "vdagentd-proto.h"
#include "vdagent-x11.h"

enum { owner_none, owner_guest, owner_client };

struct vdagent_x11_selection_request {
    XEvent event;
    struct vdagent_x11_selection_request *next;
};

struct clipboard_format_tmpl {
    uint32_t type;
    const char *atom_names[16];
};

struct clipboard_format_info {
    uint32_t type;
    Atom atoms[16];
    int atom_count;
};

static const struct clipboard_format_tmpl clipboard_format_templates[] = {
    { VD_AGENT_CLIPBOARD_UTF8_TEXT, { "UTF8_STRING",
      "text/plain;charset=UTF-8", "text/plain;charset=utf-8", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_PNG, { "image/png", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_BMP, { "image/bmp", "image/x-bmp",
      "image/x-MS-bmp", "image/x-win-bitmap", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_TIFF, { "image/tiff", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_JPG, { "image/jpeg", NULL }, },
};

#define clipboard_format_count (sizeof(clipboard_format_templates)/sizeof(clipboard_format_templates[0]))

struct vdagent_x11 {
    struct clipboard_format_info clipboard_formats[clipboard_format_count];
    Display *display;
    Atom clipboard_atom;
    Atom targets_atom;
    Atom incr_atom;
    Atom multiple_atom;
    Window root_window;
    Window selection_window;
    struct udscs_connection *vdagentd;
    FILE *errfile;
    int verbose;
    int fd;
    int screen;
    int width;
    int height;
    int has_xrandr;
    int has_xfixes;
    int xfixes_event_base;
    int max_prop_size;
    int expected_targets_notifies;
    int expect_property_notify;
    int clipboard_owner;
    Atom clipboard_request_target;
    int clipboard_type_count;
    uint32_t clipboard_agent_types[256];
    Atom clipboard_x11_targets[256];
    uint8_t *clipboard_data;
    uint32_t clipboard_data_size;
    uint32_t clipboard_data_space;
    struct vdagent_x11_selection_request *selection_request;
    uint8_t *selection_req_data;
    uint32_t selection_req_data_pos;
    uint32_t selection_req_data_size;
    Atom selection_req_atom;
};

static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11);
static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11,
                                                XEvent *event, int incr);
static void vdagent_x11_handle_selection_request(struct vdagent_x11 *x11);
static void vdagent_x11_handle_targets_notify(struct vdagent_x11 *x11,
                                              XEvent *event, int incr);
static void vdagent_x11_handle_property_delete_notify(struct vdagent_x11 *x11,
                                                      XEvent *del_event);
static void vdagent_x11_send_selection_notify(struct vdagent_x11 *x11,
                                              Atom prop,
                                              int process_next_req);
static void vdagent_x11_set_clipboard_owner(struct vdagent_x11 *x11,
                                            int new_owner);

struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd,
    FILE *errfile, int verbose)
{
    struct vdagent_x11 *x11;
    XWindowAttributes attrib;
    int i, j, major, minor;

    x11 = calloc(1, sizeof(*x11));
    if (!x11) {
        fprintf(errfile, "out of memory allocating vdagent_x11 struct\n");
        return NULL;
    }

    x11->vdagentd = vdagentd;
    x11->errfile = errfile;
    x11->verbose = verbose;

    x11->display = XOpenDisplay(NULL);
    if (!x11->display) {
        fprintf(x11->errfile, "could not connect to X-server\n");
        free(x11);
        return NULL;
    }

    x11->screen = DefaultScreen(x11->display);
    x11->root_window = RootWindow(x11->display, x11->screen);
    x11->fd = ConnectionNumber(x11->display);
    x11->clipboard_atom = XInternAtom(x11->display, "CLIPBOARD", False);
    x11->targets_atom = XInternAtom(x11->display, "TARGETS", False);
    x11->incr_atom = XInternAtom(x11->display, "INCR", False);
    x11->multiple_atom = XInternAtom(x11->display, "MULTIPLE", False);
    for(i = 0; i < clipboard_format_count; i++) {
        x11->clipboard_formats[i].type = clipboard_format_templates[i].type;
        for(j = 0; clipboard_format_templates[i].atom_names[j]; j++) {
            x11->clipboard_formats[i].atoms[j] =
                XInternAtom(x11->display,
                            clipboard_format_templates[i].atom_names[j],
                            False);
        }
        x11->clipboard_formats[i].atom_count = j;
    }

    /* We should not store properties (for selections) on the root window */
    x11->selection_window = XCreateSimpleWindow(x11->display, x11->root_window,
                                                0, 0, 1, 1, 0, 0, 0);
    if (x11->verbose)
        fprintf(x11->errfile, "Selection window: %u\n",
                (unsigned int)x11->selection_window);

    if (XRRQueryExtension(x11->display, &i, &i))
        x11->has_xrandr = 1;
    else
        fprintf(x11->errfile, "no xrandr\n");

    if (XFixesQueryExtension(x11->display, &x11->xfixes_event_base, &i) &&
        XFixesQueryVersion(x11->display, &major, &minor) && major >= 1) {<commit_msg>x11: get PRIMARY clipboard atom<commit_after>/*  vdagent-x11.c vdagent x11 code

    Copyright 2010 Red Hat, Inc.

    Red Hat Authors:
    <NAME> <<EMAIL>>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* Note: Our event loop is only called when there is data to be read from the
   X11 socket. If events have arrived and have already been read by libX11 from
   the socket triggered by other libX11 calls from this file, the select for
   read in the main loop, won't see these and our event loop won't get called!
   
   Thus we must make sure that all queued events have been consumed, whenever
   we return to the main loop. IOW all (externally callable) functions in this
   file must end with calling XPending and consuming all queued events.
   
   Calling XPending when-ever we return to the mainloop also ensures any
   pending writes are flushed. */

#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <assert.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xfixes.h>
#include "vdagentd-proto.h"
#include "vdagent-x11.h"

enum { owner_none, owner_guest, owner_client };

struct vdagent_x11_selection_request {
    XEvent event;
    struct vdagent_x11_selection_request *next;
};

struct clipboard_format_tmpl {
    uint32_t type;
    const char *atom_names[16];
};

struct clipboard_format_info {
    uint32_t type;
    Atom atoms[16];
    int atom_count;
};

static const struct clipboard_format_tmpl clipboard_format_templates[] = {
    { VD_AGENT_CLIPBOARD_UTF8_TEXT, { "UTF8_STRING",
      "text/plain;charset=UTF-8", "text/plain;charset=utf-8", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_PNG, { "image/png", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_BMP, { "image/bmp", "image/x-bmp",
      "image/x-MS-bmp", "image/x-win-bitmap", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_TIFF, { "image/tiff", NULL }, },
    { VD_AGENT_CLIPBOARD_IMAGE_JPG, { "image/jpeg", NULL }, },
};

#define clipboard_format_count (sizeof(clipboard_format_templates)/sizeof(clipboard_format_templates[0]))

struct vdagent_x11 {
    struct clipboard_format_info clipboard_formats[clipboard_format_count];
    Display *display;
    Atom clipboard_atom;
    Atom clipboard_primary_atom;
    Atom targets_atom;
    Atom incr_atom;
    Atom multiple_atom;
    Window root_window;
    Window selection_window;
    struct udscs_connection *vdagentd;
    FILE *errfile;
    int verbose;
    int fd;
    int screen;
    int width;
    int height;
    int has_xrandr;
    int has_xfixes;
    int xfixes_event_base;
    int max_prop_size;
    int expected_targets_notifies;
    int expect_property_notify;
    int clipboard_owner;
    Atom clipboard_request_target;
    int clipboard_type_count;
    uint32_t clipboard_agent_types[256];
    Atom clipboard_x11_targets[256];
    uint8_t *clipboard_data;
    uint32_t clipboard_data_size;
    uint32_t clipboard_data_space;
    struct vdagent_x11_selection_request *selection_request;
    uint8_t *selection_req_data;
    uint32_t selection_req_data_pos;
    uint32_t selection_req_data_size;
    Atom selection_req_atom;
};

static void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11);
static void vdagent_x11_handle_selection_notify(struct vdagent_x11 *x11,
                                                XEvent *event, int incr);
static void vdagent_x11_handle_selection_request(struct vdagent_x11 *x11);
static void vdagent_x11_handle_targets_notify(struct vdagent_x11 *x11,
                                              XEvent *event, int incr);
static void vdagent_x11_handle_property_delete_notify(struct vdagent_x11 *x11,
                                                      XEvent *del_event);
static void vdagent_x11_send_selection_notify(struct vdagent_x11 *x11,
                                              Atom prop,
                                              int process_next_req);
static void vdagent_x11_set_clipboard_owner(struct vdagent_x11 *x11,
                                            int new_owner);

struct vdagent_x11 *vdagent_x11_create(struct udscs_connection *vdagentd,
    FILE *errfile, int verbose)
{
    struct vdagent_x11 *x11;
    XWindowAttributes attrib;
    int i, j, major, minor;

    x11 = calloc(1, sizeof(*x11));
    if (!x11) {
        fprintf(errfile, "out of memory allocating vdagent_x11 struct\n");
        return NULL;
    }

    x11->vdagentd = vdagentd;
    x11->errfile = errfile;
    x11->verbose = verbose;

    x11->display = XOpenDisplay(NULL);
    if (!x11->display) {
        fprintf(x11->errfile, "could not connect to X-server\n");
        free(x11);
        return NULL;
    }

    x11->screen = DefaultScreen(x11->display);
    x11->root_window = RootWindow(x11->display, x11->screen);
    x11->fd = ConnectionNumber(x11->display);
    x11->clipboard_atom = XInternAtom(x11->display, "CLIPBOARD", False);
    x11->clipboard_primary_atom = XInternAtom(x11->display, "PRIMARY", False);
    x11->targets_atom = XInternAtom(x11->display, "TARGETS", False);
    x11->incr_atom = XInternAtom(x11->display, "INCR", False);
    x11->multiple_atom = XInternAtom(x11->display, "MULTIPLE", False);
    for(i = 0; i < clipboard_format_count; i++) {
        x11->clipboard_formats[i].type = clipboard_format_templates[i].type;
        for(j = 0; clipboard_format_templates[i].atom_names[j]; j++) {
            x11->clipboard_formats[i].atoms[j] =
                XInternAtom(x11->display,
                            clipboard_format_templates[i].atom_names[j],
                            False);
        }
        x11->clipboard_formats[i].atom_count = j;
    }

    /* We should not store properties (for selections) on the root window */
    x11->selection_window = XCreateSimpleWindow(x11->display, x11->root_window,
                                                0, 0, 1, 1, 0, 0, 0);
    if (x11->verbose)
        fprintf(x11->errfile, "Selection window: %u\n",
                (unsigned int)x11->selection_window);

    if (XRRQueryExtension(x11->display, &i, &i))
        x11->has_xrandr = 1;
    else
        fprintf(x11->errfile, "no xrandr\n");

    if (XFixesQueryExtension(x11->display, &x11->xfixes_event_base, &i) &&
        XFixesQueryVersion(x11->display, &major, &minor) && major >= 1) {
{'fraction_non_alphanumeric': 0.09295857121944079, 'fraction_numerical': 0.03147416190894452, 'mean_word_length': 2.997366881217086, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 105, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1401617', 'n_tokens_mistral': 4706, 'n_tokens_neox': 4419, 'n_words': 1134}