C++ Get string from Clipboard on Linux - c++

Hello I'm writing a c++ program and I need to get what's on clipboard into a string variable. I found a lot of solutions but all of them were written for windows. Is there any method without using the QT libraries? I found something related to X11 but not very explicit aswell.
Thank you very much

X11 uses a flexible multi-buffer multi-format asynchronous application-side clipboard protocol.
Most toolkits have it implemented (GTK's gtk_clipboard_get(), Qt's QApplication::clipboard(), Tk's clipboard_get). But you can do it manually with X11 API, for example, if you're not using toolkits, or if you must pass large amount of data through clipboard buffer without keeping it all in memory at the same time.
Theory
There may be many buffers, but you only need to know about two:
CLIPBOARD is the usual explicit buffer: you copy things there with Edit/Copy menu, and paste it with Edit/Paste menu.
PRIMARY selection is an implicit mouse selection feature: text gets in it when selected with mouse cursor, and gets pasted from it on middle-click in text input fields.
Primary selection needs no keypresses, so it's useful for copying small fragments between windows that are next to each other. This feature is mostly unix-specific, but I've seen putty, trillian and some gtk apps emulating it on Windows OS. Also firefox has "Paste & Go" feature when middle-clicking empty non-interactive space of the page.
To optimize things those are application-side buffers: instead of pushing entire clipboard/selection to the server every time it changes, application just tells the server "I own it". To get the buffer you ask the owner to give you its content. This way even a large buffer takes no resources until its actually requested.
When requesting the buffer you ask the owner for a specific format you need. For example an image copied from seamonkey browser (right-click an image and press "Copy Image") can be represented in different formats. It would appear as image URL if you paste it in terminal. It would become a picture loaded from that URL if you paste it in libreoffice writer. And it'd be the image itself if pasted in gimp. That works because seamonkey is smart and provides each application with format it asks for: text string for terminal, html for libreoffice and image data for gimp. To request text format you'd ask for UTF8_STRING format with fallback to STRING.
As you ask another application to prepare the buffer, and that may take some time, the request is asynchronous: the owner prepares the buffer, saves it in a specified location (window property is used as a temporary storage) and notifies you with SelectionNotify event when it's done.
So to get the buffer:
choose buffer name (CLIPBOARD, PRIMARY), format
(UTF8_STRING, STRING) and a window property to store result to
call XConvertSelection() to request the buffer
wait for SelectionNotify event
read buffer content from window property
Naive implementation
// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>
Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
char *result;
unsigned long ressize, restail;
int resbits;
Atom bufid = XInternAtom(display, bufname, False),
fmtid = XInternAtom(display, fmtname, False),
propid = XInternAtom(display, "XSEL_DATA", False),
incrid = XInternAtom(display, "INCR", False);
XEvent event;
XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
do {
XNextEvent(display, &event);
} while (event.type != SelectionNotify || event.xselection.selection != bufid);
if (event.xselection.property)
{
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, False, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
if (fmtid == incrid)
printf("Buffer is too large and INCR reading is not implemented yet.\n");
else
printf("%.*s", (int)ressize, result);
XFree(result);
return True;
}
else // request failed, e.g. owner can't convert to the target format
return False;
}
int main()
{
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
PrintSelection(display, window, "CLIPBOARD", "STRING");
XDestroyWindow(display, window);
XCloseDisplay(display);
return !result;
}
This will work for many simple cases. One thing missing here is support for incremental reading of large buffers. Let's add it!
Large buffers
Some apps may want to copy/paste 100 gigabytes of text logs. And X11 allows that! But the data must be passed incrementally, split into chunks.
If the requested buffer is too large, instead of storing it into the window property, owner sets a property of format INCR. If you delete it, owner assumes you've read it, and puts next chunk in the same property. That continues until the last chunk is read and deleted. Finally owner sets property of size 0 to mark the end of data.
So to read large buffer you delete INCR property and wait for the property to appear again (PropertyNotify event, state == PropertyNewValue), read and delete it, wait for it to appear again, and so on until it appears with zero size.
// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>
Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
char *result;
unsigned long ressize, restail;
int resbits;
Atom bufid = XInternAtom(display, bufname, False),
fmtid = XInternAtom(display, fmtname, False),
propid = XInternAtom(display, "XSEL_DATA", False),
incrid = XInternAtom(display, "INCR", False);
XEvent event;
XSelectInput (display, window, PropertyChangeMask);
XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
do {
XNextEvent(display, &event);
} while (event.type != SelectionNotify || event.xselection.selection != bufid);
if (event.xselection.property)
{
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
if (fmtid != incrid)
printf("%.*s", (int)ressize, result);
XFree(result);
if (fmtid == incrid)
do {
do {
XNextEvent(display, &event);
} while (event.type != PropertyNotify || event.xproperty.atom != propid || event.xproperty.state != PropertyNewValue);
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
printf("%.*s", (int)ressize, result);
XFree(result);
} while (ressize > 0);
return True;
}
else // request failed, e.g. owner can't convert to the target format
return False;
}
int main()
{
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
PrintSelection(display, window, "CLIPBOARD", "STRING");
XDestroyWindow(display, window);
XCloseDisplay(display);
return !result;
}
For example xsel tool uses INCR transfer for buffers larger than 4000. According to ICCCM, it's up to the application to choose a reasonable size limit.
The same code works for PRIMARY selection. Replace "CLIPBOARD" with "PRIMARY" to print PRIMARY selection contents.
References
X Selections summary by Jamie Zawinski
Xlib Programming Manual - Selections
ICCCM - Large Data Transfers and INCR protocol
https://github.com/exebook/x11clipboard - minimal XCopy() and XPaste() implementations
xsel and xclip sources
The Secondary Selection - history and ideas by Charles Lindsey

Did you try to find not a code first but a program with an implementation ? I did it for you and found a lot of implementations which use direct X11 calls. I think the most valuable is this but also you may read this. Just find any program and look for the sources. Try to look on wikipedia what applications use x11 clipboard/selection system.
The following programs specifically operate on data transfer
mechanisms:
xcutsel transfers data from selections to cut buffers or vice versa
xclipboard, glipper (Gnome), parcellite (LXDE), and klipper (KDE) are
clipboard managers, maybe wmcliphist as well xcb shows the content of
the cut buffers and allows the user to manipulate them xselection,
xclip, xsel and xcopy are command line programs that copy data to or
from the X selection. xcopy has a verbosity option that helps debug X
selection issues. parcellite also has the ability to read from and
write to specific X selections from the command line.
synergy is a cross platform tool that allows you to share a clipboard across
multiple computers running multiple operating systems
xfce4-clipman-plugin is a "clipboard history plugin for the Xfce4
panel" and also a clipboard manager xtranslate looks up words in the
Xselection in a multi-lingual dictionary autocutsel syncs cut buffer
and selection buffer
Shortly, in theory, X11 has 2 "clipboards": actually a keyboard and for selections - the text you selected immediately can be pasted anywhere you want by pressing middle-mouse button while actual "keyboard" is made for main/default clipboard purposes as exchange by different kind of objects.
P.S. I'd not work with x11 anymore after my experience. Enjoy :)

Related

X11 DestroyNotify event returns wrong window parameter

I'm currently working on writing a reparenting window manager using C++ and the XCB library. I unmanage windows when I recieve an UnmapNotify event; in this case the code is very simple:
if (unmap_ignore > 0) {
unmap_ignore--;
return;
}
client *cl = nullptr;
size_t idx = 0;
for (client &c : clients) {
if (c.window == ev->window) {
cl = &c;
break;
}
idx++;
}
if (!cl)
return;
xcb_unmap_window(conn, cl->frame);
clients.erase(clients.begin() + idx);
However, this does not work for some clients that don't bother unmapping the window (usually happens when you force kill the process). Then instead a DestroyNotify is sent. However the ev->window field there (typeof ev = xcb_destroy_notify_event_t) is some value that isn't what I want... here are some example logs (also note each line is a new DestroyNotify event, I get it twice for some reason and each time the #window field is different but not correct):
Found a client window: 4194307 but this was destroyed: 4194305
Found a client window: 4194307 but this was destroyed: 4194313
I remember before I tried to write a window manager in Xlib and had this exact same issue. I must be missing something obvious though, but if I look at the code of other reparenting window managers like Awesome or Herbsluftwm they just use the window field and have no problems. What am I doing wrong?
(my full code is here: http://ix.io/3yDj)
One thing I suspect is that it is just giving me two children windows of the destroyed parent instead of sending the actual parent. no idea why, but it is the most logical thing I can come up with. I just want to be able to handle this so I can unmap the frame for things that don't send UnmapNotify events.
I also first thought that it may report DestroyNotify on the parent window instead of the client reparented one, so I tried checking the frame but to no avail:
Found a client window: 2097152 but this was destroyed: 4194305
Found a client window: 2097152 but this was destroyed: 4194313
I've been truly stumped on this so any help is appreciated, thanks!
Awesome for example does the exact same thing as I tried with ev->window:
static void
event_handle_destroynotify(xcb_destroy_notify_event_t *ev)
{
client_t *c;
if((c = client_getbywin(ev->window)))
client_unmanage(c, CLIENT_UNMANAGE_DESTROYED);
else
for(int i = 0; i < globalconf.embedded.len; i++)
if(globalconf.embedded.tab[i].win == ev->window)
{
xembed_window_array_take(&globalconf.embedded, i);
luaA_systray_invalidate();
}
}

Scanned image always is 96 DPI

I'm trying to use the Leadtools API version 21 for automatically scanning some documents while setting some properties from code (do not want to show the TWAIN dialog). for example I set the scan DPI to 300 using L_TwainSetResolution(), but the image I get inside the bitmap callback always has resolution of 96x96.Here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
L_INT EXT_CALLBACK GetBmpCB(HTWAINSESSION hS, pBITMAPHANDLE pBitmap, L_VOID* pUserData)
{
// in here pBitmap->XResolution and pBitmap->YResolution are always 96
// but I have clearly set them to 300
// process image here
L_FreeBitmap(pBitmap); // free the image
return SUCCESS;
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
TW_FIX32 XRes = L_TwainFloatToFix32(300.0);
TW_FIX32 YRes = L_TwainFloatToFix32(300.0);
BITMAPHANDLE tBmp;
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
tBmp.uStructSize = sizeof(BITMAPHANDLE);
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830");
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo));
CheckRetCode(L_TwainStartCapsNeg(hSession));
CheckRetCode(L_TwainSetImageUnit(hSession, TWUN_INCHES));
CheckRetCode(L_TwainEnableDuplex(hSession, FALSE));
CheckRetCode(L_TwainSetResolution(hSession, &XRes, &YRes)); // setting the res to 300 x 300
CheckRetCode(L_TwainEndCapsNeg(hSession));
L_TwainAcquire(hSession, &tBmp, sizeof(BITMAPHANDLE), GetBmpCB, 0, NULL, NULL);
if(tBmp.Flags.Allocated)
L_FreeBitmap(&tBmp);
}
By the way the scanned image has the correct number of pixels. If I scan a 8.5x11 page, I get an image that is 2550x3300 pixels, but XResolution and YResolution are set to 96 which causes the saved image to be 26.5"x34.375".
Thank you
Sam
I tested with 4 different Twain drivers and got the following results:
One of them did not support 300 DPI, so it returned error “Bad value” when calling L_TwainSetResolution(). However, it returned correct image size for the actual DPI it supported, which is 100.
The other 3 supported different DPI values, and returned correct image size and DPI values in the callback’s pBitmap.
The only major difference between my code and yours is that I called L_TwainEndSession(). If your code doesn’t include it, make sure to call it once for each call of L_TwainInitSession/L_TwainInitSession2.
If that’s not the cause of your problem, try to test with more than one Twain driver and see if the problem is specific to one driver. If it’s not, put your code in a small test program and email it to support#leadtools.com and we will check it for you.

How to get signal in Qt from a printer when it finishes printing?

I am trying to get notifications in Qt for a printer but unfortunately couldn't find any solution. I've already tried to check the state but it never changes, it is always 'PrinterState::Idle'.
void Functions::print(QString fileName)
{
printerTmr = new QTimer(this);
printerTmr->setInterval(2000);
connect(printerTmr, SIGNAL(timeout()), this, SLOT(printerStateCheck()));
printerTmr->start(); //start checking the state of the printer
printer.setPageSize(QPrinter::A6);
printer.setOrientation(QPrinter::Landscape);
QImage img(fileName);
QSize size;
QIcon icon;
QPainter painter( &printer );
int w = printer.pageRect().width();
int h = printer.pageRect().height();
QRect page( 0, 0, w, h );
QImage image(fileName);
if (!image.isNull())
icon.addPixmap(QPixmap::fromImage(image), QIcon::Normal, QIcon::On);
icon = icon;
size = QSize(w,h);
QPixmap pixmap = icon.pixmap(size, QIcon::Normal, QIcon::On);
........
//draw simulated landscape
page.adjust( w/20, h/20, -w/20, -h/20 );
painter.drawPixmap(QPoint(0,0),pixmap);
}
void Functions::printerStateCheck()
{
if(printer.printerState() == QPrinter::PrinterState::Idle){
qDebug()<<"PrinterState::Idle";
}else if(printer.printerState() == QPrinter::PrinterState::Error){
qDebug()<<"PrinterState::Error";
}else if(printer.printerState() == QPrinter::PrinterState::Active){
qDebug()<<"PrinterState::Active";
}else if(printer.printerState() == QPrinter::PrinterState::Aborted){
qDebug()<<"PrinterState::Aborted";
}
}
Printing possibility in Qt is hold very simple. QPrinter device represents a series of pages of printed output, and is used in almost exactly the same way as other paint devices such as QWidget and QPixmap.
When printing directly to a printer on Windows or macOS, QPrinter uses the built-in printer drivers. On X11, QPrinter uses the Common Unix Printing System (CUPS) to send PDF output to the printer.
As an alternative, the printProgram() function can be used to specify the command or utility to use instead of the system default. (P.S.: but only on X11 system for pdf printing)
QPrinter::printerState() Returns the current state of the printer. This may not always be accurate (for example if the printer doesn't have the capability of reporting its state to the operating system).
So like the Qt doc says it is on printer, printer drivers, printing subsystem and OS itself to provide the state. I think you have more luck with printing states under linux whith CUPS then in windows.
Try to use OS printing API directly.
Here is info with example code for WINAPI on How to get the status of a printer and a print job

Adjust video capture input port using C++ / python

I am having a video capture device (VCD) that acquires frames from a TV which have various output ports (VGA, HDMI, DVI). I read these frames using C++/OpenCV, process them and then show the output on a C++/Qt QLabel.
My problems show up when I change the input port (DVI to HDMI or HDMI to VGA,...), at then I need to manually open the crossbar dialog window for the VCD and switch the input port.
Shows command window with ffmpeg command line + crossbar window for the video capture device
Moreover, for each input port, I need to adjust some parameters relating to color range, scaling size and wire's length.
I need to automate this process of selecting the right input port with the corresponding right parameters using a C++ or python code.
I was searching for a way to read all the input pins of the crossbar dialog box for the video capture device and this set/unset the required pins.
Thanks in advance.
Here is the example in C++/WinAPI how you can set/unset the VIDEO INPUT pins on settings dialog. This code assumes, that checkboxes are children elements of the main dialog; there can be case, when they are nested inside the tab control "Custom settings", so in this case you need find the that tab at first.
#include <windows.h>
#include <string>
#include <vector>
#include <map>
#include <iostream>
int main(int, char **)
{
// Find the dialog
HWND hwnd = FindWindowA(NULL, "%Your settings dialog caption%");
if (hwnd == NULL)
{
std::cerr << "cannot find settings dialog" << std::endl;
return 1;
}
std::map<std::string, HWND> options;
// Get first dialog element
HWND h = GetWindow(hwnd, GW_CHILD);
char caption[250];
std::vector<std::string> inputs{
"1/HDMI",
"2/DVI-D",
"3/COMPONENT",
"DVI",
"4/VGA",
"SOG",
"5/SDI",
"6/COMPOSITE",
"7/S-VIDEO",
"8/AUTO"
};
while (h != NULL)
{
// Get element text
if (GetWindowTextA(h, caption, 250))
{
std::string scaption(caption);
// Check the text, if it's in the list of the option, put it into map.
if (std::find(inputs.begin(), inputs.end(), scaption) != inputs.end())
{
options[caption] = h;
}
}
h = GetWindow(h, GW_HWNDNEXT);
}
// Check the 4/VGA option.
SendMessageA(options["4/VGA"], BM_CLICK, 0, 0);
return 0;
}

C++ Finding Index for Font temporarily added to System Font Table with AddFontResource() to use in Console

I am trying to temporarily install a font to use in the win32 console with
int AddFontResource(LPCTSTR lpszFilename);
and
BOOL WINAPI SetConsoleFont(HANDLE hOutput, DWORD fontIndex)
I got hold of this function from this site.
Although both functions seem to work fine I have no idea how to find the added font index to use with SetConsoleFont.
AddFontResource returns no index value or key to the temporary font.
Here is my relevant code:
#include "Level.h"
#include "ConsoleFont.h" //acquired from above mentioned site
#include <Windows.h>
//-------------------------------------------------------------------------------
void init();
void cleanup();
int main()
{
FileManager *pFileManager = new FileManager(); //unrelated
Level *lvl1 = new Level("filename",pFileManager); //unrelated
///TEMPORARY PLANNING
// using add font resource. how can i get this fonts index value?
int err = AddFontResource(L"Files/gamefont.fnt");
if (err == 0)
{
MessageBox(NULL,L"loading font failed",L"Error",0);
}
else
{
wchar_t message[100];
swprintf_s(message,100,L"AddFontResource returned: %d",err);
MessageBox(NULL,LPTSTR(message),L"error",0);
}
SendMessage(HWND_BROADCAST, WM_FONTCHANGE,0,0);
//acquiring handle to current active screen buffer
HANDLE tempHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (tempHandle == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,L"Failed to aquire Screen Buffer handle",L"Error",0);
}
//I dont know what to set this to. this is the crux of the problem.
DWORD fontIndex = 1;
if (FALSE == SetConsoleFont(tempHandle,fontIndex))
{
MessageBox(NULL,L"loading console font failed",L"Error",0);
}
//draws a house when in correct font
std::cout<<"!!!!!!!!#\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !#\n"
<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<std::endl;
///PLANNING OVERS
bool quit = false;
while(!quit)
{
//still to be implemented
}
err = RemoveFontResource(L"Files/gamefont.fnt");
if (err==0)
{
MessageBox(NULL,L"removing font failed",L"Error",0);
}
return 0;
}
I don't know how to go about finding my new font's index value or even if this is possible using my current method.
If someone knows or has a better method please help me out.
any help or hints are appreciated. It must possible to use a custom font in the win32 Console without fiddling with the registry. I'm sure of it :)
Unfortunately you entered the dark world on Win APIs. There is no documentation (or atleast I could never find it) for a console font table lookup. You can try the method "GetNumberOfConsoleFonts()" to see what is returned. I think the font at index 10 is Lucida Console. You'll have to play around a little. Also, this may not work for the OS version you have. Worked for me on XP. Never had to try on anything else. And honestly, never got it fully working on XP too.
For the registry,
Fonts registries are here:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
Console registries are here:
HKEY_CURRENT_USER\Console
If you end up modifying the registry, the changes may not be reflected immediately. You need to either restart the console or send a special WM_* message (sorry don't remember the name).
Will be great if you can find a solution/workaround :)
int err = AddFontResource(L"Files/gamefont.fnt");
if (err == 0)
{
MessageBox(NULL,L"loading font failed",L"Error",0);
}
else
{
wchar_t message[100];
swprintf_s(message,100,L"AddFontResource returned: %d",err);
MessageBox(NULL,LPTSTR(message),L"error",0);
}
this is wrong AddFontResource returns the number of fonts loaded, so the code in the ELSE doesn't make sense.