cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

gtk-clipboard.c (6312B)


      1/*
      2 * GTK UI -- clipboard support
      3 *
      4 * Copyright (C) 2021 Gerd Hoffmann <kraxel@redhat.com>
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
     18 *
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "qemu-common.h"
     23#include "qemu/main-loop.h"
     24
     25#include "ui/gtk.h"
     26
     27static QemuClipboardSelection gd_find_selection(GtkDisplayState *gd,
     28                                                GtkClipboard *clipboard)
     29{
     30    QemuClipboardSelection s;
     31
     32    for (s = 0; s < QEMU_CLIPBOARD_SELECTION__COUNT; s++) {
     33        if (gd->gtkcb[s] == clipboard) {
     34            return s;
     35        }
     36    }
     37    return QEMU_CLIPBOARD_SELECTION_CLIPBOARD;
     38}
     39
     40static void gd_clipboard_get_data(GtkClipboard     *clipboard,
     41                                  GtkSelectionData *selection_data,
     42                                  guint             selection_info,
     43                                  gpointer          data)
     44{
     45    GtkDisplayState *gd = data;
     46    QemuClipboardSelection s = gd_find_selection(gd, clipboard);
     47    QemuClipboardType type = QEMU_CLIPBOARD_TYPE_TEXT;
     48    g_autoptr(QemuClipboardInfo) info = NULL;
     49
     50    info = qemu_clipboard_info_ref(qemu_clipboard_info(s));
     51
     52    qemu_clipboard_request(info, type);
     53    while (info == qemu_clipboard_info(s) &&
     54           info->types[type].available &&
     55           info->types[type].data == NULL) {
     56        main_loop_wait(false);
     57    }
     58
     59    if (info == qemu_clipboard_info(s) && gd->cbowner[s]) {
     60        gtk_selection_data_set_text(selection_data,
     61                                    info->types[type].data,
     62                                    info->types[type].size);
     63    } else {
     64        /* clipboard owner changed while waiting for the data */
     65    }
     66}
     67
     68static void gd_clipboard_clear(GtkClipboard *clipboard,
     69                               gpointer data)
     70{
     71    GtkDisplayState *gd = data;
     72    QemuClipboardSelection s = gd_find_selection(gd, clipboard);
     73
     74    gd->cbowner[s] = false;
     75}
     76
     77static void gd_clipboard_notify(Notifier *notifier, void *data)
     78{
     79    GtkDisplayState *gd = container_of(notifier, GtkDisplayState, cbpeer.update);
     80    QemuClipboardInfo *info = data;
     81    QemuClipboardSelection s = info->selection;
     82    bool self_update = info->owner == &gd->cbpeer;
     83
     84    if (info != qemu_clipboard_info(s)) {
     85        gd->cbpending[s] = 0;
     86        if (!self_update) {
     87            GtkTargetList *list;
     88            GtkTargetEntry *targets;
     89            gint n_targets;
     90
     91            list = gtk_target_list_new(NULL, 0);
     92            if (info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) {
     93                gtk_target_list_add_text_targets(list, 0);
     94            }
     95            targets = gtk_target_table_new_from_list(list, &n_targets);
     96
     97            gtk_clipboard_clear(gd->gtkcb[s]);
     98            gd->cbowner[s] = true;
     99            gtk_clipboard_set_with_data(gd->gtkcb[s],
    100                                        targets, n_targets,
    101                                        gd_clipboard_get_data,
    102                                        gd_clipboard_clear,
    103                                        gd);
    104
    105            gtk_target_table_free(targets, n_targets);
    106            gtk_target_list_unref(list);
    107        }
    108        return;
    109    }
    110
    111    if (self_update) {
    112        return;
    113    }
    114
    115    /*
    116     * Clipboard got updated, with data probably.  No action here, we
    117     * are waiting for updates in gd_clipboard_get_data().
    118     */
    119}
    120
    121static void gd_clipboard_request(QemuClipboardInfo *info,
    122                                 QemuClipboardType type)
    123{
    124    GtkDisplayState *gd = container_of(info->owner, GtkDisplayState, cbpeer);
    125    char *text;
    126
    127    switch (type) {
    128    case QEMU_CLIPBOARD_TYPE_TEXT:
    129        text = gtk_clipboard_wait_for_text(gd->gtkcb[info->selection]);
    130        if (text) {
    131            qemu_clipboard_set_data(&gd->cbpeer, info, type,
    132                                    strlen(text), text, true);
    133            g_free(text);
    134        }
    135        break;
    136    default:
    137        break;
    138    }
    139}
    140
    141static void gd_owner_change(GtkClipboard *clipboard,
    142                            GdkEvent *event,
    143                            gpointer data)
    144{
    145    GtkDisplayState *gd = data;
    146    QemuClipboardSelection s = gd_find_selection(gd, clipboard);
    147    QemuClipboardInfo *info;
    148
    149    if (gd->cbowner[s]) {
    150        /* ignore notifications about our own grabs */
    151        return;
    152    }
    153
    154
    155    switch (event->owner_change.reason) {
    156    case GDK_OWNER_CHANGE_NEW_OWNER:
    157        info = qemu_clipboard_info_new(&gd->cbpeer, s);
    158        if (gtk_clipboard_wait_is_text_available(clipboard)) {
    159            info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
    160        }
    161
    162        qemu_clipboard_update(info);
    163        qemu_clipboard_info_unref(info);
    164        break;
    165    default:
    166        qemu_clipboard_peer_release(&gd->cbpeer, s);
    167        gd->cbowner[s] = false;
    168        break;
    169    }
    170}
    171
    172void gd_clipboard_init(GtkDisplayState *gd)
    173{
    174    gd->cbpeer.name = "gtk";
    175    gd->cbpeer.update.notify = gd_clipboard_notify;
    176    gd->cbpeer.request = gd_clipboard_request;
    177    qemu_clipboard_peer_register(&gd->cbpeer);
    178
    179    gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD] =
    180        gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
    181    gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMARY] =
    182        gtk_clipboard_get(GDK_SELECTION_PRIMARY);
    183    gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY] =
    184        gtk_clipboard_get(GDK_SELECTION_SECONDARY);
    185
    186    g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_CLIPBOARD],
    187                     "owner-change", G_CALLBACK(gd_owner_change), gd);
    188    g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_PRIMARY],
    189                     "owner-change", G_CALLBACK(gd_owner_change), gd);
    190    g_signal_connect(gd->gtkcb[QEMU_CLIPBOARD_SELECTION_SECONDARY],
    191                     "owner-change", G_CALLBACK(gd_owner_change), gd);
    192}