How to store text on the system clipboard after application has quit using GTK3? - clipboard

I am trying to update the system clipboard from a GTK application. Here is a simplified program:
#include <gtk/gtk.h>
void callback(GtkClipboard *clipboard, const gchar *text, gpointer data) {
printf( "In callback: text = '%s'\n", text);
}
int main() {
gtk_init(NULL, NULL);
GdkScreen *screen = gdk_screen_get_default();
GdkDisplay *display = gdk_display_get_default();
GtkClipboard *clipboard = gtk_clipboard_get_for_display(
display, GDK_SELECTION_PRIMARY );
gtk_clipboard_set_text( clipboard, "Hello world", -1);
gtk_clipboard_request_text( clipboard, callback, NULL );
if( gdk_display_supports_clipboard_persistence(display) ) {
printf( "Supports clipboard persistence.\n");
gtk_clipboard_store(clipboard);
}
}
The output (after compiling the above program on my Ubuntu 19.10 laptop):
In callback: text = 'Hello world'
Note that the text: Supports clipboard persistence. is not shown, so apparently the display does not support updating the system clipboard (?). However, I can easily update it with the xclip command. Why is it not possible to do it from GTK?

GDK_SELECTION_PRIMARY -> is used to get the currently-selected object or text
GDK_SELECTION_CLIPBOARD -> is used perform operations like Cut/copy/paste
(https://developer.gnome.org/gtk3/stable/gtk3-Clipboards.html#gtk-clipboard-get-for-display)
and to store a text the application has to remain in the main loop long enough to let the clipboard manager copy the text.
#include <gtk/gtk.h>
void callback(GtkClipboard *clipboard, const gchar *text, gpointer data) {
printf("In callback: text = '%s'\n", text);
}
int main() {
gtk_init(NULL, NULL);
GdkScreen *screen = gdk_screen_get_default();
GdkDisplay *display = gdk_display_get_default();
GtkClipboard *clipboard =
gtk_clipboard_get_for_display(display, GDK_SELECTION_CLIPBOARD);
gtk_clipboard_set_text(clipboard, "Hello world", -1);
gtk_clipboard_request_text(clipboard, callback, NULL);
if (gdk_display_supports_clipboard_persistence(display)) {
printf("Supports clipboard persistence.\n");
gtk_clipboard_store(clipboard);
}
g_timeout_add(100, gtk_main_quit, NULL);
gtk_main();
}
according to the doc(https://developer.gnome.org/gdk3/stable/GdkDisplay.html#gdk-display-supports-clipboard-persistence) clipboard_persistance will only check for a running clipboard daemon. I am guessing that there are some changes made in this area as I was not able to find any running clipboard-daemon in me machine (they might have integrated it into the window manager)
(https://wiki.ubuntu.com/ClipboardPersistence) -> this doc explains the problems with clipboard persistence and ways to fix it.
if you install "clipit"(clipboard manager) and try to copy the text without waiting in the main loop for few milliseconds your output will be "Clipboard is null, recovering"
xclip would have mostly stayed online for a few milliseconds to allow coppying of the text.

Related

I want to copy, paste and cut content in my CEdit from my Clipboard

This is the event handlers i implemented to the copy, paste and Cut buttons in my MFCRibbonBar:
in the MyRibbonView.cpp:
void CMyRibbonView::OnEditCopy()
{
CWnd *wnd = GetFocus();
if (wnd == pEdit)
pEdit->Copy();
if (!OpenClipboard())
{
AfxMessageBox(_T("Cannot open the Clipboard"));
return;
}
if (!EmptyClipboard())
{
AfxMessageBox(_T("Cannot empty the Clipboard"));
return;
}
HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64);
strcpy_s((char*)hGlob, 64, "Current selection\r\n");
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
CString msg;
msg.Format(_T("Unable to set Clipboard data, error: %d"), GetLastError());
AfxMessageBox(msg);
CloseClipboard();
GlobalFree(hGlob);
return;
}
CloseClipboard();
}
void CMyRibbonView::OnEditPaste()
{
if (OpenClipboard())
{
HANDLE hClipboardData = GetClipboardData(CF_TEXT);
char *pchData = (char*)GlobalLock(hClipboardData);
CString strFromClipboard;
strFromClipboard = pchData;
pEdit->SetWindowText(strFromClipboard);
GlobalUnlock(hClipboardData);
CloseClipboard();
}
}
void CMyRibbonView::OnEditCut()
{
OnEditCopy();
pEdit->SetWindowText(L" ");
}
There is no errors, it's just not working. I tested it by adding the messages to check if it's actually the data or not but they're not popping up.
You need to GlobalLock your hGlob memory before copying your character string into it (this operation converts it into a usable pointer for your process - see here), and then call GlobalUnlock after you've done that (so that the clipboard can access hGlob):
HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64); // Maybe also need GMEM_MOVEABLE here instead?
char* cCopy = (char*)GlobalLock(hGlob);
strcpy_s(cGlob, 64, "Current selection\r\n");
GlobalUnlock(hGlob);
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
//...
And you'll need a similar arrangement for the paste operation.

Paste Certain Clipboard Text into TEdit in CBB 10

I wish that when the user clicks the button, ONLY TEXT THAT CONTAINS AN URL (beginning with http://) on the Clipboard is automatically pasted into the TEdit.
I've tried the following code but doesn't work at all.
#include <Clipbrd.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String Text = "http://";
if (Clipboard()->HasFormat(CF_TEXT))
{
Edit->Text = ContainsText(Clipboard()->AsText, Text);
// Clipboard()->Clear();
}
}
ContainsText() returns a bool indicating whether the subtext was found or not. You are assigning that result directly to your TEdit instead of using it to make a decision whether or not to assign the clipboard text to the TEdit.
Try this instead:
#include <Clipbrd.hpp>
#include <StrUtils.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (Clipboard()->HasFormat(CF_TEXT))
{
String CBText = Clipboard()->AsText;
if (ContainsText(CBText, "http://"))
{
Edit->Text = CBText;
// Clipboard()->Clear();
}
}
}
BTW, http:// is not the only URL scheme widely used. At a minimum, consider also looking for https:// as well.

firebreath plugin create a full screen window, but the window always under the browser window when it appers, how can I bring it to top

CaptureScreenApp app;
int MyPluginAPI::captureScreen(const FB::JSObjectPtr& callback)
{
boost::thread cs(boost::bind(&CaptureScreenApp ::captureScreen,
app, callback));
return 1;
}
class CaptureScreenApp {
public:
CaptureScreenApp() {
HRESULT hRes;
hRes = OleInitialize(NULL);
ATLASSERT(SUCCEEDED(hRes));
AtlInitCommonControls(ICC_WIN95_CLASSES);
g_Module.Init(NULL, NULL);
};
~CaptureScreenApp() {
g_Module.Term();
OleUninitialize();
};
bool captureScreen() {
CMessageLoop theLoop;
CMainDialog g_MainDlg;
g_Module.AddMessageLoop(&theLoop);
if (NULL == g_MainDlg.Create(NULL)){
DWORD ret = GetLastError();
return FALSE;
}
g_MainDlg.ShowWindow(SW_SHOW);
g_MainDlg.UpdateWindow();
int nRet = theLoop.Run();
g_Module.RemoveMessageLoop();
return TRUE;
};
};
class CMainDialog : public CDialogImpl<CMainDialog>
{
public:
enum {IDD = IDD_MAIN};
....
}
the window(the new window is a full screen window with a desktop pic as the background) I create in CaptureScreenApp::captureScreen always under the browser window when it appears(browser window always actived in other word), what ever how I set the HWND_TOPMOST for the new window. like this:
enter link description here
how can i bring the full screen window to top when it appers?
SetWindowPos API lets you change Z order (make sure to read Remarks there). You create your window with NULL parent, so your window is completely independent from browser window, so there is nothing to push it to the front: it would be either you or interactive user.

qDebug Qt console application to output to Qt Creator application output

How do I use qDebug in a Qt console application to output to the Qt Creator "application output" window? Currently qDebug writes to the console window which interferes with the non-debug output.
Using qDebug in a Qt GUI app outputs to application output window by default.
You can either output everything to console or everything to Qt Creator's Application Output panel.
For sake of completeness: If you want to have all the output in the panel instead of console you can uncheck "Run in terminal" in Project->Run settings.
To redirect QDebug to multiple places, you might have to write some code, maybe like this:
QList<QtMsgHandler> messageHandlers_;
static void messageDispatcher(QtMsgType type, const char *msg)
{
foreach (QtMsgHandler callback, ::messageHandlers_)
callback(type, msg);
}
static void messageLogger(QtMsgType type, const char *msg)
{
QString output;
switch (type) {
case QtDebugMsg: output = QString("mesage: %1\n").arg(msg); break;
case QtWarningMsg: output = QString("warning: %1\n").arg(msg); break;
case QtCriticalMsg: output = QString("critical: %1\n").arg(msg); break;
case QtFatalMsg: output = QString("fatal: %1\n").arg(msg); break;
default: return;
}
QFile file("log.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Append))
QTextStream(&file) << output;
}
int main()
{
...
::messageHandlers_.append(messageLogger)
qInstallMsgHandler(messageDispatcher);
...
}

Custom titles for Windows 7 Jump List Recent items

Quickie question: I'm toying with some of the new taskbar APIs in Windows 7 and have gotten Recent Items on my Apps jumplist to show up, but I would like to display them under a different title than the filename (most files my app will be opening will have very similar names). I don't see any way to do that with the IShellItem interface, though. Would I have to use custom categories and IShellLinks to accomplish this?
For reference, my current code looks like this:
void AddRecentApp(const wchar_t* path, const wchar_t* title /* Can I even use this? */ ) {
HRESULT hres;
hres = CoInitialize(NULL);
IShellItem* recentItem;
hres = SHCreateItemFromParsingName(path, NULL, IID_PPV_ARGS(&recentItem));
if(SUCCEEDED(hres)) {
SHARDAPPIDINFO recentItemInfo;
recentItemInfo.pszAppID = MY_APP_USER_MODEL_ID;
recentItemInfo.psi = recentItem;
SHAddToRecentDocs(SHARD_APPIDINFO, &recentItemInfo);
recentItem->Release();
}
}
Figured it out. IShellItems are just a representation of a file, so they only will provide that file's information (no custom title, etc.) An IShellLink is essentially a shortcut, and is much more flexible in terms of display and actions taken when launched, so are more appropriate in this situation. Here's my new code:
void AddRecentApp(const wchar_t* path, const wchar_t* title) {
HRESULT hres;
hres = CoInitialize(NULL);
// Shell links give us more control over how the item is displayed and run
IShellLink* shell_link;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shell_link));
if(SUCCEEDED(hres)) {
// Set up the basic link properties
shell_link->SetPath(path);
shell_link->SetArguments(L"--some-command-line-here"); // command line to execute when item is opened here!
shell_link->SetDescription(title); // This is what shows in the tooltip
shell_link->SetIconLocation(L"/path/to/desired/icon", 0); // can be an icon file or binary
// Open up the links property store and change the title
IPropertyStore* prop_store;
hres = shell_link->QueryInterface(IID_PPV_ARGS(&prop_store));
if(SUCCEEDED(hres)) {
PROPVARIANT pv;
InitPropVariantFromString(title, &pv);
// Set the title property.
prop_store->SetValue(PKEY_Title, pv); // THIS is where the displayed title is actually set
PropVariantClear(&pv);
// Save the changes we made to the property store
prop_store->Commit();
prop_store->Release();
}
// The link must persist in the file system somewhere, save it here.
IPersistFile* persist_file;
hres = shell_link->QueryInterface(IID_PPV_ARGS(&persist_file));
if(SUCCEEDED(hres)) {
hres = persist_file->Save(L"/link/save/directory", TRUE);
persist_file->Release();
}
// Add the link to the recent documents list
SHARDAPPIDINFOLINK app_id_info_link;
app_id_info_link.pszAppID = MY_APP_USER_MODEL_ID;
app_id_info_link.psl = shell_link;
SHAddToRecentDocs(SHARD_APPIDINFOLINK, &app_id_info_link);
shell_link->Release();
}
}

Resources