gtkmm entry missing keys on signal_key_press_event - c++

So I have been experimenting with the Gtkmm, as I want to migrate some of my code to C++ and I figured it would be easier.
I used to be able to use something that looks like so in C:
g_signal_connect(entry, "key-release-event", G_CALLBACK(receiveKeyPressed), NULL);
But it seems when I try to use the similar system in Gtkmm:
entry->signal_key_pressed().connect( sigc::ptr_fun(*receiveKeyPressed) );
It entirely misses all keyboard presses except for the shift keys and tab, etc.
Can anyone please explain why?

Connect your handler as first:
Flags: Run Last
#include <gtkmm.h>
#include <iostream>
int main()
{
auto app = Gtk::Application::create();
Gtk::Window window;
Gtk::Entry entry;
window.add(entry);
entry.signal_key_press_event().connect([&](GdkEventKey* event)->bool{
std::cout<<"pressed: "<<std::hex<<event->keyval<<" "<<std::hex<<event->state<<std::endl;
return false; //to propagate the event further
}, false); //run before other handlers (from entry)
window.show_all();
return app->run(window);
}

Related

Drag and drop of files from Qt application to MS Edge

I have a Qt application for Windows which contains a list of files in a widget. I want to be able to drag the files from this widget to another application. I am using Qt-base drag and drop mechanism and it works well in most cases. One case which does not work is to drag and drop it into MS Edge browser, for example when I open MS Edge and start writing an email with mail.google.com and I want to add the files as attachment by drag and drop from my Qt application. It is strange that this does work in Chrome, Firefox and also in ancient Internet Explorer. But not in Edge. Here is my minimalistic example. Try to drag files from the widget to a web page which accepts drag and drop of a file. On my computer this works for all browsers except Edge.
#include <QApplication>
#include <QDrag>
#include <QLabel>
#include <QMimeData>
#include <QMouseEvent>
class Window : public QLabel
{
public:
void mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
QList<QUrl> urls;
urls.append(QUrl::fromLocalFile("C:/test/test1"));
urls.append(QUrl::fromLocalFile("C:/test/test2"));
QMimeData* mimeData = new QMimeData();
mimeData->setUrls(urls);
QDrag* drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction);
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.setText("Drag from here...");
w.show();
return a.exec();
}
Note that I am passing data as text/uri-list MIME type. I was observing how other applications behave as drag source, and they seem to work fine - e.g. when dragging from File Explorer, Total Commander etc to MS Edge. When I look at the MIME types that they send, I can see also application/x-qt-windows-mime;value="Shell IDList Array" type, which I am missing in my example. So this is what I assume is the problem, Edge probably expects this MS-centric data type. I would also like to wrap data in this format but I do not know how to do it.
I assume I will have to use Win32 API. So I browsed around and got some snippets which should be able to create some useful data structures...
QVector<LPITEMIDLIST> idLists;
for (const QString &nativePath: qAsConst(nativePaths))
{
PCWSTR pszFile = PCWSTR(nativePath.utf16());
LPITEMIDLIST idl = ILCreateFromPathW(pszFile);
if (idl == nullptr)
{
for (LPITEMIDLIST pid : qAsConst(idLists))
ILFree(pid);
return nullptr;
}
idLists.append(idl);
}
IShellItemArray *iArray = nullptr;
HRESULT result = SHCreateShellItemArrayFromIDLists(UINT(idLists.size()), (LPCITEMIDLIST*)idLists.data(), &iArray);
for (LPITEMIDLIST pid : qAsConst(idLists))
ILFree(pid);
This seems to me as the way that could lead to the desired outcome but there are still some steps missing. I do not know how to wrap this data (are they of any use at all?) into QMimeData::setData(). Any ideas?

Check that the app runs for the first time

I'm new to qt mobile development and I have a rather dumb question.
How would I check whether a user runs the app for the first time (both Android and iOS)?
EDIT:
The reason I need this check is that I have an intro SwipeView for the first-timers and after it's read once it should always open the main app screen.
I've tried the way #TrebledJ suggested and it seems to work alright, Or is this stupid to do that in main.cpp?
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSettings>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QSettings settings;
QVariant firstRun = settings.value("first-run");
QQmlApplicationEngine engine;
QUrl startingScreen(QStringLiteral("qrc:/main.qml"));
if(!firstRun.isValid())
settings.setValue("first-run", true);
else
startingScreen.setUrl(QStringLiteral("qrc:/start.qml"));
engine.load(startingScreen);
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
Use QSettings to check for a set value.
QSettings settings;
QVariant val = settings.value("first-time");
if (!val.isValid()) {
// ... first run
settings.setValue("first-time", false); // set a value so that the value is valid on the next run
} else {
// ... not first run
}
In QML, there is the Settings QML Type.
import Qt.labs.settings 1.0
Settings {
id: settings
property bool isFirstTime: true
}
Component.onCompleted: {
if (settings.isFirstTime) {
// ... first run
settings.isFirstTime = false;
} else {
// ... not first run
}
}
However, according to documentation:
Note: This type is made available by importing the Qt.labs.settings module. Types in the Qt.labs module are not guaranteed to remain compatible in future versions.
In consideration of the non-guarantee, Felgo/V-Play's API has a Storage QML Type which can also perform the check in QML. (The first example in their documentation implements this.)

GTK3: Mouse vanishes when using drag and drop

Im trying to use the inter-widget drag-and-drop functionalities in GTK3 with gtkmm. Im using Windows 7 x64 (msys2) and gcc 5.3.0.
When i start dragging, the mouse cursor vanishes and the DnD icon is shown at the upper left corner of the screen. Is this a bug or is there something wrong in my code?
Here you can see a very small test application with Gtk::CheckButton as drag source and drag destination.
#include <iostream>
#include <gtkmm-3.0/gtkmm.h>
struct DragButton : Gtk::CheckButton{
DragButton(){
this->signal_drag_begin().connect([](const Glib::RefPtr<Gdk::DragContext>& ctx){
ctx->set_icon();
});
this->drag_source_set({Gtk::TargetEntry("testdata")});
this->drag_dest_set({Gtk::TargetEntry("testdata")});
this->signal_drag_data_get().connect(
[this](const Glib::RefPtr<Gdk::DragContext>&,Gtk::SelectionData& s,guint,guint ){
std::cout << "sending data." << std::endl;
}
);
this->signal_drag_data_received().connect(
[](const Glib::RefPtr<Gdk::DragContext>& c,int,int,const Gtk::SelectionData&,guint,guint time){
std::cout << "receiving data" << std::endl;
c->drop_finish(true,time);
}
);
}
};
int main(){
auto app = Gtk::Application::create("test");
auto settings = Gtk::Settings::get_default();
settings->set_property<Glib::ustring>("gtk-font-name","Sans 10");
Gtk::Window window;
window.set_default_size(100,50);
Gtk::Box box;
for(int i = 0; i < 3; i++){
box.pack_end(*Gtk::manage(new DragButton));
}
window.add(box);
window.show_all();
app->run(window);
}
This screenshot shows the output:
I noticed the same behaviour here. Even with "official" gnome/gtk applications. For example, let's try to drag&drop widgets in Glade: you will have the same "strange" effect.
I think it's a bug of gtk libraries in Windows, but I can't imagine why this isn't solved yet, considering drag&drop is a very useful and used operation.
I found the problem. I found out here that the adwait-icon-theme that is used as a default was not fully windows-compatible. The cursors .cur format were missing. This commit fixed the problem, I had to install the new version of the theme.

Using SDL2 with wxWidgets 3.0

My goal is to build a Game Boy emulator. In order to do this, I would like to embed an SDL2 surface into a wxWidgets window.
I found this tutorial: http://code.technoplaza.net/wx-sdl/part1/, but my program crashes as soon as I run it. However I suspect this was intended for SDL1.2. Part of the program is shown below.
It seems that if I call SDL_Init() and also attempt to show a wxFrame (which, in this case, is MainWindow), it shows the window for a second and then the program crashes. I commented all other calls to SDL in my program so far, so it seems the problem lies with calling Show() on a wxFrame and initing SDL2 in the same program.
So the question is: can SDL2 and wxWidgets 3 work together? If not, could you guys suggest to me good alternatives a GUI of a Game Boy emulator? Does wxWidgets have its own graphics frame like Qt does (I'd rather avoid Qt)?
Thanks very much!
#include "MainApp.h"
#include "MainWindow.h"
#include <stdexcept>
namespace GBEmu {
static void initSDL() {
//This and SDL_Quit() are the only calls to the SDL library in my code
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
throw std::runtime_error("Fatal Error: Could not init SDL");
}
}
bool MainApp::OnInit()
{
try {
//If I comment out this line, the MainWindow wxFrame shows up fine.
//If I leave both uncommented, the window shows up quickly and then
//crashes.
initSDL();
//If I comment out this line and leave initSDL() uncommented,
//the program will not crash, but just run forever.
(new MainWindow("GBEmu", {50,50}, {640,480}))->Show();
} catch(std::exception &e) {
wxLogMessage(_("Fatal Error: " + std::string(e.what())));
}
return true;
}
int MainApp::OnExit() {
SDL_Quit();
return wxApp::OnExit();
}
}
wxIMPLEMENT_APP(GBEmu::MainApp);
EDIT: Here is more information on how it crashes: It crashes with a Segfault in what seems to be the pthread_mutex_lock disassembly file. This is the output in the console with stack trace:
Starting /home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx...
The program has unexpectedly finished.
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx crashed
Stack trace:
Error: signal 11:
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx(_ZN5GBEmu7handlerEi+0x1c)[0x414805]
/lib/x86_64-linux-gnu/libc.so.6(+0x36ff0)[0x7fb88e136ff0]
/lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x30)[0x7fb88c12ffa0]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XrmQGetResource+0x3c)[0x7fb88d1ca15c]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XGetDefault+0xc2)[0x7fb88d1a7a92]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x94dcf)[0x7fb88af8edcf]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x97110)[0x7fb88af91110]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(cairo_surface_get_font_options+0x87)[0x7fb88af63e07]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2b61f)[0x7fb88af2561f]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2ef95)[0x7fb88af28f95]
This is a screenshot of where it seems to fail (line 7):
Update: In my MainWindow class, I attach a menu bar to the window. However, it seems when I comment out the setting of the menu bar, the window will show up fine even with initing of SDL. The menu bar will show up fine if I have initSDL() commented out but not the setting of the menu bar. Here is where I set the menu bar:
MainWindow::MainWindow(const wxString &title, const wxPoint &pos, const wxSize &size)
:wxFrame(nullptr, wxIDs::MainWindow, title, pos, size){
wxMenu *fileMenu = new wxMenu;
fileMenu->Append(wxID_EXIT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(fileMenu, "&File");
//commenting this line out will allow the window to showup
//and not crash the program
SetMenuBar(menuBar);
}
You are experiencing an old heisenbug.
The workaround is simple: you have to initialize SDL before wxWidgets (basically, before GTK). To achieve this, you have to change
wxIMPLEMENT_APP(GBEmu::MainApp);
to
wxIMPLEMENT_APP_NO_MAIN(GBEmu::MainApp);
so that wxWidgets doesn't hijack your main().
Then you have to create main() manually. In it, initialize SDL, then call wxEntry():
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cerr << "Could not initialize SDL.\n";
return 1;
}
return wxEntry(argc, argv);
}
More about the bug:
I have googled around a bit and found that this bug has come up in a few places over the years. There are open reports in many bug trackers that have stack traces very similar to the one you get here (with debug symbols).
The oldest report I could find is from 2005 (!!) from the cairo bug tracker (https://bugs.freedesktop.org/show_bug.cgi?id=4373).
My best guess is that the real hiding place of this bug in either in GTK, cairo, or X. Unfortunately I do not currently have the time to look into it more in depth.

Fltk Window wait

C++ fltk: I have a window with an in_box and an out_box, how do I make it so that the user can type into the in_box hit enter, then proceed with the rest of the event. Right now the window just shows up and goes away.
Window w(Point(100,100),200,200, "Category Sales");
In_box cat_in(Point(75,75),100,20,"Category:");
Out_box cat_out(Point(75,115),100,20,"Sales:");
w.attach(cat_in);
w.attach(enter);
category = cat_in.get_string();
I'm not sure exactly if this will fix your problem, but to keep the window open, return Fl::run().
I have never seen In_box and Out_box before, so I will assume those are your own classes or structures...
As pointed before - the easiest way to start the FLTK event loop is to use Fl::run() or (FLTK2) fltk::run().
So, here your code should look something like (FLTK2):
#include <fltk/Window.h>
#include <fltk/Widget.h>
#include <fltk/run.h>
using namespace fltk;
int main(int argc, char **argv) {
// your code begins
Window w(Point(100,100),200,200, "Category Sales");
In_box cat_in(Point(75,75),100,20,"Category:");
Out_box cat_out(Point(75,115),100,20,"Sales:");
w.attach(cat_in);
w.attach(enter);
category = cat_in.get_string();
// your code ends
w->end();
w->show(argc, argv);
return run(); // this line is the most important, here we start the FLTK event-loop
}