Creating multiple windows in gtkmm - gtkmm

I started to learn gtkmm library and probably don't understand the way it works. Here's the problem: I've copied simple example from gtkmm tutorial, and want to modify it to create as many windows as I want by clicking the button.
Why can't I just write code like in function on_button_clicked() below?
class Hello : public Gtk::Window {
public:
Hello() :m_button("create copy") {
set_border_width(20);
m_button.signal_clicked().connect(sigc::mem_fun(*this, &Hello::on_button_clicked));
add(m_button);
show_all_children();
}
protected:
void on_button_clicked();
Gtk::Button m_button;
};
void Hello::on_button_clicked() {
Hello new_window;
new_window.show();
}
int main (int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
Hello hw;
return app->run(hw);
}

The reason a new window is not displayed is how C++ has been used in the method Hello::on_button_clicked().
The line :
Hello new_window;
creates a new window with local scope.
new_window.show();
This marks the window to be shown when GTK+ is back in control.
The line
}
exits the method and all local variables are destroyed. Which means that new_window is deleted before it can be seen.
To keep the window and have it shown the object must be stored so that it is not automatically destroyed. This could be allocated on the heap and a pointer kept to it in another class for easy access to the window.

Related

(C++/CLI) How to get callbacks from Native Code to Managed Code in C++ CLI?

RANT-BEGIN
Before jumping right into already answered band wagon, please read this paper about SE outdated answers https://ieeexplore.ieee.org/document/8669958
Things changes after a time, and I am afraid Computer science is one of the most if not the most field out there where APIs and Interfaces change radically very very fast. Needless to say that a solution that might worked last month might not after latest feature added to a platform/framework. I humbly request you to not mark this question as answered with decade old post when many mainstream things did not even existed. If you dont know latest solution dont bother about it and leave question for someone else who might.
For a community representative of Computer Science where innovations is everyday thing, it is very toxic, new comer unfriendly and conservative.
END-RANT
This question has already been answered by me and will be accepted tomorrow (SE policy). Thank you for your interest.
Many times you have function pointers in unmanaged context which are called by some kind of events, We will see how it can be achieved with Top-Level Functions and also with member functions of a managed class.
Again, Please dont mark it as answered by linking to a decade old posts.
PS:
So many edits due to unstable internet in third world country, yeah bite me!
unmanaged.cpp
#pragma unmanaged
// Declare an unmanaged function type that takes one int arguments and callbacks
// our function after incrementing it by 1
// Note the use of __stdcall for compatibility with managed code
// if your unmanaged callback uses any other calling convention you can
// UnmanagedFunctionPointerAttribute (check msdn for more info) on your delegate
typedef int(__stdcall* ANSWERCB)(int);//Signature of native callback
int TakesCallback(ANSWERCB fp, int a) {
if (fp) {
return fp(a+1);//Native Callback
}
// This code will be executed when passed without fp
return 0;
}
#pragma managed
managed.cpp
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Callbacks {
// Following delegate is for unmanaged code and must match its signature
public delegate void MyNativeDelegate(int i);
// This delegate is for managed/derived code and ideally should have only managed parameters
public delegate void MyManagedDelegate(int i);
public ref class TestCallback {// Our demo Managed class
private:
GCHandle gch;// kept reference so that it can be freed once we are done with it
void NativeCallbackListener(int i);//unmanaged code will call this function
public:
void TriggerCallback(int i); // Its here for demo purposes, usually unmanaged code will call automatically
event MyManagedDelegate^ SomethingHappened;//plain old event
~TestCallback();//free gch in destructor as its managed.
};
};
void Callbacks::TestCallback::NativeCallbackListener(int i) {
// Callback from Native code,
// If you need to transform your arguments do it here, like transforming void* to somekind of native structure.
// and then pass SomethingHappened::raise with Managed Class/Struct
return SomethingHappened::raise(i); // similar to SomethingHappened.Invoke() in c#
}
void Callbacks::TestCallback::TriggerCallback(int i)
{
MyNativeDelegate^ fp = gcnew MyNativeDelegate(this, &TestCallback::NativeCallbackListener);
// use this if your nativecallback function is not a member function MyNativeDelegate^ fp = gcnew MyNativeDelegate(&NativeCallbackListener);
gch = GCHandle::Alloc(fp);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer());// (ANSWERCB)ip.ToPointer(); works aswell
// Simulating native call, it should callback to our function ptr NativeCallbackListener with 2+1;
// Ideally Native code keeps function pointer and calls back without pointer being provided every time.
// Most likely with a dedicated function for that.
TakesCallback(cb, i);
}
void Callbacks::TestCallback::~TestCallBack() {
gch.Free();//Free GCHandle so GC can collect
}
implementation.cpp
using namespace System;
void OnSomethingHappened(int i);
int main(array<System::String^>^ args)
{
auto cb = gcnew Callbacks::TestCallback();
cb->SomethingHappened += gcnew Callbacks::MyManagedDelegate(&OnSomethingHappened);
cb->TriggerCallback(1);
return 0;
}
void OnSomethingHappened(int i)
{
Console::WriteLine("Got call back with " + i);
}

Constructing Xaml controls on C++/WinRT UI thread

I'm not sure what I'm doing wrong, but even though I'm definitely on the UI thread, I'm consistently getting the error " 'The application called an interface that was marshalled for a different thread.'" when constructing Xaml controls in C++.
See the following basic example, which uses a stripped down version of the default C++/WinRT CoreApplication template:
#include "pch.h"
using namespace winrt;
using namespace Windows;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::Composition;
using namespace Windows::ApplicationModel::Activation;
struct App : implements<App, IFrameworkViewSource, IFrameworkView> {
CompositionTarget m_target{nullptr};
IFrameworkView CreateView() { return *this; }
void Initialize(CoreApplicationView const &) {}
void Load(hstring const &) {}
void Uninitialize() {}
void Run() {
CoreWindow window = CoreWindow::GetForCurrentThread();
winrt::Windows::UI::Xaml::Controls::TextBox textbox; // Crashes here
CoreDispatcher dispatcher = window.Dispatcher();
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
}
void SetWindow(CoreWindow const &) {
Compositor compositor;
ContainerVisual root = compositor.CreateContainerVisual();
m_target = compositor.CreateTargetForCurrentView();
m_target.Root(root);
}
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { CoreApplication::Run(make<App>()); }
I've tried using window.Dispatcher().HasThreadAccess() to verify that I'm on the correct thread to be making UI calls, and it always returns true.
I've also tried calling RunAsync() from the window's Dispatcher and constructing a Xaml object in a lambda passed to this method, and it still has exactly the same result. HasThreadAccess returns true here too.
Can anyone explain to me where I'm going wrong here? Is constructing Xaml objects not supported in C++?
[edit]
Here's a sample project that reproduces the issue, again based on the default CoreWindow C++/WinRT template:
https://github.com/lyptt/CoreApp1
Turns out the CoreApplication-based template does not support anything from the Xaml namespace, as it's intended more towards providing a thin UWP layer for games, etc.
To get Xaml support you need to use the full template instead, then things magically start to work.

QObject::findChildren() for QML object finding

I have an QML form with QQuickApplicationWindow. I need to get QQuickItem pointers on BaseKey elements of QtVirtualKeyboard (it's implementation is placed in separate QML file and loads with Loader of layout when program executes), but it has dynamical (runtime) type like this BaseKey_QMLTYPE_XX, where "XX" is a changeable number.
I found QObject::findChildren() function http://doc.qt.io/qt-4.8/qobject.html#findChild, but i cant find out number "XX" in typename.
How can i find QQuickItem pointer on BaseKey from C++ code?
BaseKey_QMLTYPE_XX looks like what you'd get if you printed the object (print(myObject)). I think that comes from QMetaObject::className().
If the object doesn't have an objectName set, you won't be able to find it using findChild() (unless you have access to the C++ type and there's only one object of that type).
I have a hacky test helper function that does something similar to what you're after:
QObject *TestHelper::findPopupFromTypeName(const QString &typeName) const
{
QObject *popup = nullptr;
foreach (QQuickItem *child, overlay->childItems()) {
if (QString::fromLatin1(child->metaObject()->className()) == "QQuickPopupItem") {
if (QString::fromLatin1(child->parent()->metaObject()->className()).contains(typeName)) {
popup = child->parent();
break;
}
}
}
return popup;
}
You could adapt this to iterate over the children of an object that you pass in. There are a couple more changes than that to get it to work, but the general idea is there.

Accessing a C/C++ structure of callbacks through a DLL's exported function using JNA

I have a vendor supplied .DLL and an online API that I am using to interact with a piece of radio hardware; I am using JNA to access the exported functions through Java (because I don't know C/C++). I can call basic methods and use some API structures successfully, but I am having trouble with the callback structure. I've followed the TutorTutor guide here and also tried Mr. Wall's authoritative guide here, but I haven't been able to formulate the Java side syntax for callbacks set in a structure correctly.
I need to use this exported function:
BOOL __stdcall SetCallbacks(INT32 hDevice,
CONST G39DDC_CALLBACKS *Callbacks, DWORD_PTR UserData);
This function references the C/C++ Structure:
typedef struct{
G39DDC_IF_CALLBACK IFCallback;
//more omitted
} G39DDC_CALLBACKS;
...which according to the API has these Members (Note this is not an exported function):
VOID __stdcall IFCallback(CONST SHORT *Buffer, UINT32 NumberOfSamples,
UINT32 CenterFrequency, WORD Amplitude,
UINT32 ADCSampleRate, DWORD_PTR UserData);
//more omitted
I have a G39DDCAPI.java where I have loaded the DLL library and reproduced the API exported functions in Java, with the help of JNA. Simple calls to that work well.
I also have a G39DDC_CALLBACKS.java where I have implemented the above C/C++ structure in a format works for other API structures. This callback structure is where I am unsure of the syntax:
import java.util.Arrays;
import java.util.List;
import java.nio.ShortBuffer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.BaseTSD.DWORD_PTR;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
public class G39DDC_CALLBACKS extends Structure {
public G39DDC_IF_CALLBACK IFCallback;
//more omitted
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"IFCallback","DDC1StreamCallback" //more omitted
});
}
public static interface G39DDC_IF_CALLBACK extends StdCallCallback{
public void invoke(ShortBuffer _Buffer,int NumberOfSamples,
int CenterFrequency, short Amplitude,
int ADCSampleRate, DWORD_PTR UserData);
}
}
Edit: I made my arguments more type safe as Technomage suggested. I am still getting a null pointer exception with several attempts to call the callback. Since I'm not sure of my syntax regarding the callback structure above, I can't pinpoint my problem in the main below. Right now the relevant section looks like this:
int NumberOfSamples=65536;//This is usually 65536.
ShortBuffer _Buffer = ShortBuffer.allocate(NumberOfSamples);
int CenterFrequency=10000000;//Specifies center frequency (in Hz) of the useful band
//in received 50 MHz wide snapshot.
short Amplitude=0;//The possible value is 0 to 32767.
int ADCSampleRate=100;//Specifies sample rate of the ADC in Hz.
DWORD_PTR UserData = null;
G39DDC_CALLBACKS callbackStruct= new G39DDC_CALLBACKS();
lib.SetCallbacks(hDevice,callbackStruct,UserData);
//hDevice is a handle for the hardware device used-- works in other uses
//lib is a reference to the library in G39DDCAPI.java-- works in other uses
//The UserData is a big unknown-- I don't know what to do with this variable
//as a DWORD_PTR
callbackStruct.IFCallback.invoke(_Buffer, NumberOfSamples, CenterFrequency,
Amplitude, ADCSampleRate, UserData);
EDIT NO 2:
I have one callback working somewhat, but I don't have control over the buffers. More frustratingly, a single call to invoke the method will result in several runs of the custom callback, usually with multiple output files (results vary drastically from run to run). I don't know if it is because I am not allocating memory correctly on the Java side, because I cannot free the memory on the C/C++ side, or because I have no cue on which to tell Java to access the buffer, etc. Relevant code looks like:
//before this, main method sets library, starts DDCs, initializes some variables...
//API call to start IF
System.out.print("Starting IF... "+lib.StartIF(hDevice, Period)+"\n")
G39DDC_CALLBACKS callbackStructure = new G39DDC_CALLBACKS();
callbackStructure.IFCallback = new G39DDC_IF_CALLBACK(){
#Override
public void invoke(Pointer _Buffer, int NumberOfSamples, int CenterFrequency,
short Amplitude, int ADCSampleRate, DWORD_PTR UserData ) {
//notification
System.out.println("Invoked IFCallback!!");
try {
//ready file and writers
File filePath = new File("/users/user/G39DDC_Scans/");
if (!filePath.exists()){
System.out.println("Making new directory...");
filePath.mkdir();
}
String filename="Scan_"+System.currentTimeMillis();
File fille= new File("/users/user/G39DDC_Scans/"+filename+".txt");
if (!fille.exists()) {
System.out.println("Making new file...");
fille.createNewFile();
}
FileWriter fw = new FileWriter(fille.getAbsoluteFile());
//callback body
short[] deBuff=new short[NumberOfSamples];
int offset=0;
int arraySize=NumberOfSamples;
deBuff=_Buffer.getShortArray(offset,arraySize);
for (int i=0; i<NumberOfSamples; i++){
String str=deBuff[i]+",";
fw.write(str);
}
fw.close();
} catch (IOException e1) {
System.out.println("IOException: "+e1);
}
}
};
lib.SetCallbacks(hDevice, callbackStructure,UserData);
System.out.println("Main, before callback invocation");
callbackStructure.IFCallback.invoke(s_Pointer, NumberOfSamples, CenterFrequency, Amplitude, ADCSampleRate, UserData);
System.out.println("Main, after callback invocation");
//suddenly having trouble stopping DDCs or powering off device; assume it has to do with dll using the functions above
//System.out.println("StopIF: " + lib.StopIF(hDevice));//API function returns boolean value
//System.out.println("StopDDC2: " + lib.StopDDC2( hDevice, Channel));
//System.out.println("StopDDC1: " + lib.StopDDC1( hDevice, Channel ));
//System.out.println("test_finishDevice: " + test_finishDevice( hDevice, lib));
System.out.println("Program Exit");
//END MAIN METHOD
You need to extend StdCallCallback, for one, otherwise you'll likely crash when the native code tries to call the Java code.
Any place you see a Windows type with _PTR, you should use a PointerType - the platform package with JNA includes definitions for DWORD_PTR and friends.
Finally, you can't have a primitive array argument in your G39DDC_IF_CALLBACK. You'll need to use Pointer or an NIO buffer; Pointer.getShortArray() may then be used to extract the short[] by providing the desired length of the array.
EDIT
Yes, you need to initialize your callback field in the callbacks structure before passing it into your native function, otherwise you're just passing a NULL pointer, which will cause complaints on the Java or native side or both.
This is what it takes to create a callback, using an anonymous instance of the declared callback function interface:
myStruct.callbackField = new MyCallback() {
public void invoke(int arg) {
// do your stuff here
}
};

MFC state invalid when DLL called through LoadLibrary

i'm fighting with MFC and dynamicly linking DLLs with LoadLibrary. It seems that I cannot get the MFC state right when the app calls DLL, and the DLL calls back in the same call. Ultimately, it leads to tons of asserts.
Here is code mock-up of what i'm doing.
The application is just normal, straight from the wizard MFC app. I've got button somewhere and this is the button's handler:
void callback()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
CDialog1 dlg;
dlg.DoModal();
}
typedef void (*TPluginMainFunc)(void*);
void CTheApp1View::OnTestRun1()
{
static HMODULE hPluginMFCShared = LoadLibrary( _T("PluginMFCShared") );
if ( hPluginMFCShared )
{
TPluginMainFunc func = (TPluginMainFunc) GetProcAddress( hPluginMFCShared, "plugin_main" );
if ( func )
{
func(callback);
}
}
}
Then the 'PluginMFCShared' looks like this:
typedef void (*TFunc)();
extern "C" void GS_EXTERNAL_ENTRY plugin_main(TFunc func)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
func();
CDialog1 dlg;
dlg.DoModal();
}
So, the idea is that the app (CTheApp1View::OnTestRun1) loads a library and calls a function directly passing in a callback pointer. The library would use that callback to execute something from the app before continuing.
I thought AFX_MANAGE_STATE will take care of the MFC state, but there seem to be something more that needs to be done.
A test project could be found at (make sure TheApp1 project is set to be the start-up project):
SystemOfPlugins.zip
Any ideas?
Thanks for any suggestions.
Here's another suggestion. In your App variable, add an AFX_MODULE_STATE* variable named m_pModuleState, and initialize it at the end of the InitInstance funciton,
m_pModuleState = AfxGetModuleState();
Modify your callback function to set the application state before opening the dialog, and then set back the original state before exiting the function
void callback()
{
//Get the original state
AFX_MODULE_STATE* pOriginalState = AfxGetModuleState();
//Set the mfc state
AfxSetModuleState(((CTheApp1App*)&theApp)->m_pModuleState);
//Do stuff here
CDialog1 dlg;
dlg.DoModal();
//Set the mfc state back to its original state
AfxSetModuleState(pOriginalState);
}
And keep your plugin as it was in your example
extern "C" void GS_EXTERNAL_ENTRY plugin_main(TFunc func)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
func();
CDialog1 dlg;
dlg.DoModal();
}
This way, you would call AFX_MANAGE_STATE in your plugins, but when some of the plugin make a call to the callback function, you make sure to set the app's state so it can find the good dialog resources and execute state-specific functions
I looked at your code, and I got it working by modifiying 2 functions :
in pluginMFCShared.cpp, I called AFX_MANAGE_STATE after the call to func()
extern "C" void GS_EXTERNAL_ENTRY plugin_main(TFunc func)
{
func();
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
CDialog1 dlg;
dlg.DoModal();
}
In theapp1view.cpp, I removed the AFX_MANAGE_STATE
void callback()
{
CDialog1 dlg;
dlg.DoModal();
}
Now, the two dialogs pops one after another
Are you building the dll with the _LIB preprocessor flag? If so, check if you really should - the whole 'MFC dll' concept is antiquated, there is no reason to use it anymore. Then, forget about all the AFX_MANAGE_STATE stuff. In your dll, store the HMODULE of the dll that is passed to DllMain, and use ::AfxSetResourceHandle() to the correct value before each use of a CDialog or similar. Wrap it in a smart pointer-like class that sets the correct resource handle and resets it to the old one (= the main app's one, usually 0x4000...) when the object goes out of scope.
For all purposes where you can pass a resource handle directly (LoadString etc), you don't even have to touch the global handle.
Much easier to work, and much more transparent. The resource handle is the only one that is relevant for MFC state in MFC versions since VS6 anyway.