"Fossies" - the Fresh Open Source Software Archive

Member "cb2bib-2.0.1/src/clipboardPoll.cpp" (12 Feb 2021, 7629 Bytes) of package /linux/privat/cb2bib-2.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "clipboardPoll.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0.0_vs_2.0.1.

    1 /***************************************************************************
    2  *   clipboardPoll, modified by Pere Constans for cb2Bib, 2005
    3  *   constans@molspaces.com
    4  *   cb2Bib version 2.0.1. Licensed under the GNU GPL version 3.
    5  *
    6  *
    7  *   Author and Copyright (C) 2003 by Lubos Lunak <l.lunak@kde.org>
    8  *   Distributed under the GNU General Public License
    9  *
   10  *
   11  *   This file is part of the KDE project
   12  *   Copyright (C) 2003 by Lubos Lunak <l.lunak@kde.org>
   13  *
   14  *   This program is free software; you can redistribute it and/or
   15  *   modify it under the terms of the GNU General Public
   16  *   License as published by the Free Software Foundation; either
   17  *   version 2 of the License, or (at your option) any later version.
   18  *
   19  *   This program is distributed in the hope that it will be useful,
   20  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   21  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   22  *   General Public License for more details.
   23  *
   24  *   You should have received a copy of the GNU General Public License
   25  *   along with this program; see the file COPYING.  If not, write to
   26  *   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   27  *   Boston, MA 02111-1307, USA.
   28  ***************************************************************************/
   29 #include "clipboardPoll.h"
   30 
   31 
   32 #include <QClipboard>
   33 #include <QX11Info>
   34 #include <X11/Xatom.h>
   35 
   36 
   37 /*
   38 
   39  The polling magic:
   40 
   41  There's no way with X11 how to find out if the selection has changed (unless
   42 its ownership is taken away from the current client). In the future, there will
   43 be hopefully such notification, which will make this whole file more or less
   44 obsolete. But for now, Klipper has to poll. In order to avoid transferring all
   45 the data on every time pulse, this file implements two optimizations: The first
   46 one is checking whether the selection owner is Qt application (using the
   47 _QT_SELECTION/CLIPBOARD_SENTINEL atoms on the root window of screen 0), and if
   48 yes, Klipper can rely on QClipboard's signals. If the owner is not Qt app, and
   49 the ownership has changed, it means the selection has changed as well.
   50 Otherwise, first only the timestamp of the last selection change is requested
   51 using the TIMESTAMP selection target, and if it's the same, it's assumed the
   52 contents haven't changed. Note that some applications (like XEmacs) does not
   53 provide this information, so Klipper has to assume that the clipboard might have
   54 changed in this case --- this is what is meant by REFUSED below.
   55 
   56 */
   57 
   58 clipboardPoll::clipboardPoll(QWidget* parentw) : QWidget(parentw)
   59 {
   60     //     kapp->installX11EventFilter( this );
   61     timer = new QTimer(this);
   62     connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
   63 
   64     const char* names[6] = { "_QT_SELECTION_SENTINEL",      "_QT_CLIPBOARD_SENTINEL",     "CLIPBOARD", "TIMESTAMP",
   65                              "KLIPPER_SELECTION_TIMESTAMP", "KLIPPER_CLIPBOARD_TIMESTAMP"
   66                            };
   67     Atom atoms[6];
   68     XInternAtoms(QX11Info::display(), const_cast<char**>(names), 6, False, atoms);
   69     selection.sentinel_atom = atoms[0];
   70     clipboard.sentinel_atom = atoms[1];
   71     xa_clipboard = atoms[2];
   72     xa_timestamp = atoms[3];
   73     selection.timestamp_atom = atoms[4];
   74     clipboard.timestamp_atom = atoms[5];
   75     selection.atom = XA_PRIMARY;
   76     clipboard.atom = xa_clipboard;
   77     selection.last_change = clipboard.last_change = QX11Info::appTime(); // don't trigger right after startup
   78     selection.last_owner = XGetSelectionOwner(QX11Info::display(), XA_PRIMARY);
   79     clipboard.last_owner = XGetSelectionOwner(QX11Info::display(), xa_clipboard);
   80     selection.waiting_for_timestamp = false;
   81     clipboard.waiting_for_timestamp = false;
   82     updateQtOwnership(selection);
   83     updateQtOwnership(clipboard);
   84 }
   85 
   86 clipboardPoll::~clipboardPoll()
   87 {
   88     delete timer;
   89 }
   90 
   91 
   92 bool clipboardPoll::x11Event(XEvent* e)
   93 {
   94     // note that this is also installed as app-wide filter
   95     if (e->type == SelectionNotify && e->xselection.requestor == winId())
   96     {
   97         if (changedTimestamp(selection, *e))
   98         {
   99             emit clipboardChanged(true);
  100         }
  101 
  102         if (changedTimestamp(clipboard, *e))
  103         {
  104             emit clipboardChanged(false);
  105         }
  106         return true; // filter out
  107     }
  108     return false;
  109 }
  110 
  111 void clipboardPoll::updateQtOwnership(SelectionData& sData)
  112 {
  113     Atom type;
  114     int format;
  115     unsigned long nitems;
  116     unsigned long after;
  117     unsigned char* prop = NULL;
  118     if (XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(0), sData.sentinel_atom, 0, 2, False, XA_WINDOW,
  119                            &type, &format, &nitems, &after, &prop) != Success ||
  120         type != XA_WINDOW || format != 32 || nitems != 2 || prop == NULL)
  121     {
  122         sData.owner_is_qt = false;
  123         if (prop != NULL)
  124             XFree(prop);
  125         return;
  126     }
  127     Window owner = reinterpret_cast<long*>(prop)[0]; // [0] is new owner, [1] is previous
  128     XFree(prop);
  129     Window current_owner = XGetSelectionOwner(QX11Info::display(), sData.atom);
  130     sData.owner_is_qt = (owner == current_owner);
  131 }
  132 
  133 void clipboardPoll::timeout()
  134 {
  135     //     KlipperWidget::updateTimestamp();
  136     if (!qApp->clipboard()->ownsSelection() && checkTimestamp(selection))
  137     {
  138         emit clipboardChanged(true);
  139     }
  140     if (!qApp->clipboard()->ownsClipboard() && checkTimestamp(clipboard))
  141     {
  142         emit clipboardChanged(false);
  143     }
  144 }
  145 
  146 bool clipboardPoll::checkTimestamp(SelectionData& sData)
  147 {
  148     Window current_owner = XGetSelectionOwner(QX11Info::display(), sData.atom);
  149     updateQtOwnership(sData);
  150     if (sData.owner_is_qt)
  151     {
  152         sData.last_change = CurrentTime;
  153         sData.last_owner = current_owner;
  154         sData.waiting_for_timestamp = false;
  155         return false;
  156     }
  157     if (current_owner != sData.last_owner) // owner has changed
  158     {
  159         sData.last_owner = current_owner;
  160         sData.waiting_for_timestamp = false;
  161         sData.last_change = CurrentTime;
  162         return true;
  163     }
  164     if (current_owner == None)
  165     {
  166         return false; // None also last_owner...
  167     }
  168     if (sData.waiting_for_timestamp)
  169     {
  170         // We're already waiting for the timestamp of the last check
  171         return false;
  172     }
  173     XDeleteProperty(QX11Info::display(), winId(), sData.timestamp_atom);
  174     XConvertSelection(QX11Info::display(), sData.atom, xa_timestamp, sData.timestamp_atom, winId(),
  175                       QX11Info::appTime());
  176     sData.waiting_for_timestamp = true;
  177     sData.waiting_x_time = QX11Info::appTime();
  178     return false;
  179 }
  180 
  181 bool clipboardPoll::changedTimestamp(SelectionData& sData, const XEvent& ev)
  182 {
  183     if (ev.xselection.requestor != winId() || ev.xselection.selection != sData.atom ||
  184         ev.xselection.time != sData.waiting_x_time)
  185     {
  186         return false;
  187     }
  188     sData.waiting_for_timestamp = false;
  189     if (ev.xselection.property == None)
  190     {
  191         return true;
  192     }
  193     Atom type;
  194     int format;
  195     unsigned long nitems;
  196     unsigned long after;
  197     unsigned char* prop = NULL;
  198     if (XGetWindowProperty(QX11Info::display(), winId(), ev.xselection.property, 0, 1, False, AnyPropertyType, &type,
  199                            &format, &nitems, &after, &prop) != Success ||
  200         format != 32 || nitems != 1 || prop == NULL)
  201     {
  202         if (prop != NULL)
  203             XFree(prop);
  204         return true;
  205     }
  206     Time timestamp = reinterpret_cast<long*>(prop)[0];
  207     XFree(prop);
  208     if (timestamp != sData.last_change || timestamp == CurrentTime)
  209     {
  210         sData.last_change = timestamp;
  211         return true;
  212     }
  213     return false; // ok, same timestamp
  214 }