Init wxApp from Linux daemon

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
rudolfninja
Experienced Solver
Experienced Solver
Posts: 85
Joined: Tue Aug 28, 2018 1:02 pm
Location: Belarus

Re: Init wxApp from Linux daemon

Post by rudolfninja » Thu Jun 06, 2019 6:07 pm

The main purpose of my daemon is provide remote access to the system. It is used to accept client's connection to share application. When the application is shared I want to draw border around it. When user connects to view application's share daemon created separate thread which monitors application's windows state (size, position, overlapped or not, minimized or not, visible or not) and draws border around the app. Currently I use gtk to draw border, but there some problems with gtk, so I decided to draw border using wxWidgets. That why I need GUI-part in my daemon.
I'll try wxIMPLEMENT_APP_NO_MAIN. Are there some examples how to use it correctly?

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Thu Jun 06, 2019 7:32 pm

but wxWidgets itself uses gtk to make controls and drawings.
i also don't understand why you need to pull wxWidgets with your code. Less dependencies - better to maintain.
wxWidgets it's not for border drawings. it's for rich user applications.
also better to split daemon and interface to separate apps and let them conversate via sockets.
ubuntu 16.04, wxWidgets 3.0.4

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Thu Jun 06, 2019 7:53 pm

http://bighow.org/questions/24837572/us ... idgets-3-0

see my comments inside, after '///'
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) { ///This is a main function of your app
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { ///here they are calling some code they need
std::cerr << "Could not initialize SDL."; ///but wxWIdgets still not started
return 1;
}

return wxEntry(argc, argv); ///here they are starting wxWidgets and your wxWidgets code, and sit in there till exit
}
but here everything works in main thread.
so you must write body of secondary thread kinda

Code: Select all


wxDECLARE_APP(MyGUI);
wxIMPLEMENT_APP_NO_MAIN(MyGUI);

//wxWidgets main thread body
int wxStart(){
	return wxEntry(...); //starts wxWIdgets
}

//then in your daemon main(...)
int main(...){
	....
	std::thread(wxStart,...); //creates and starts wxWidgets in secondary thread 
}
imho.

here are some words about it
https://docs.wxwidgets.org/3.0/group__ ... 6d57389af
ubuntu 16.04, wxWidgets 3.0.4

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Thu Jun 06, 2019 10:05 pm

now i m testing this code, it normally starts wxWidgets if wxStart(..) runs in main thread, but hangs being run from secondary thread.

Code: Select all

#include <thread>
DECLARE_APP(MyApp)
wxIMPLEMENT_APP_NO_MAIN(MyApp);

int wxStart(int argc, char** argv){
	int dummy=0;
	return wxEntry(dummy, static_cast<wxChar**>(nullptr)); //starts wxWIdgets
}

//then in your daemon main(...)
int main(int argc, char** argv) {
	//wxDISABLE_DEBUG_SUPPORT();
	//std::thread(wxStart, argc, argv); //here it hangs
	wxStart(argc,argv); //here works normally
}

ubuntu 16.04, wxWidgets 3.0.4

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Thu Jun 06, 2019 10:33 pm

this code normally starts wxWIdgets in secondary thread

Code: Select all

#include <thread>
DECLARE_APP(MyApp)
wxIMPLEMENT_APP_NO_MAIN(MyApp);

int wxStart(int argc, char** argv){
	return wxEntry(argc, argv); //starts wxWIdgets
}

int main(int argc, char** argv) {
    //wxDISABLE_DEBUG_SUPPORT();
	std::thread lt(wxStart, argc, argv); //creates and starts wxWidgets in secondary thread
	lt.join();
	return 0;
}

ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 85
Joined: Tue Aug 28, 2018 1:02 pm
Location: Belarus

Re: Init wxApp from Linux daemon

Post by rudolfninja » Fri Jun 07, 2019 8:16 am

Thanks for the snippet.
As I understand, MyApp is a class derived from wxApp? Can I use wxApp instead if I haven't got such class (MyApp)?
What I have now:
In .cpp file of my class that starts from main function of main thread:

Code: Select all

int wxStart(int argc, char** argv)
{
    return wxEntry(argc, argv);
}

DECLARE_APP(wxApp)
wxIMPLEMENT_APP_NO_MAIN(wxApp);

bool LinuxSessionHelperModule::BeforeMainProc(int argc, char* argv[])
{
    atexit(ExitHandler);
    XInitThreads();
    CXErrorHandlerUtils::InstallErrorHandler();
    // some unrelated init code here
    
    std::thread(wxStart, argc, argv).detach();
    return true;
}
In .cpp file of my class, which run in secondary thread and tries to create border instance:

Code: Select all

wxDECLARE_APP(wxApp);
LinuxDisplayHelperMaster::LinuxDisplayHelperMaster(const TDisplayId& displayId, bool showFrame, int borderThickness)
{
    // some unrelated init code here
    wxGetApp().CallAfter(
                [this, borderThickness]
    {
        m_borderWindow = new LinuxBorderWindow(borderThickness);
        m_borderWindow->Show(true);
    }
    );
}
However I see and error about undefined reference to wxGetApp().

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Fri Jun 07, 2019 8:36 am

1. MyApp is an arbitrary name of your class derived from wxApp.
you must declare it, not wxApp!!! else you have created instance of base class. not yours.
so this code is wrong.

Code: Select all

DECLARE_APP(wxApp)
wxIMPLEMENT_APP_NO_MAIN(wxApp);
2. You cannot directly call anything from your daemon(main thread code) in your MyApp instance!
you can only send messages to it.

If you guarantee that this piece is working in secondary thread, where we started wxWidgets, then it's ok. so - where do you create an instance of this LinuxDisplayHelperMaster?

Code: Select all

wxDECLARE_APP(wxApp);
LinuxDisplayHelperMaster::LinuxDisplayHelperMaster(const TDisplayId& displayId, bool showFrame, int borderThickness)
{
    // some unrelated init code here
    wxGetApp().CallAfter(
                [this, borderThickness]
    {
        m_borderWindow = new LinuxBorderWindow(borderThickness);
        m_borderWindow->Show(true);
    }
    );
}
ubuntu 16.04, wxWidgets 3.0.4

rudolfninja
Experienced Solver
Experienced Solver
Posts: 85
Joined: Tue Aug 28, 2018 1:02 pm
Location: Belarus

Re: Init wxApp from Linux daemon

Post by rudolfninja » Fri Jun 07, 2019 9:19 am

So can I just create wxApp instance in LinuxSessionHelperModule and use it somehow in LinuxDisplayHelperMaster? Don't know actually how to access this instance from LinuxDisplayHelperMaster, but still...will it work?
I mean something like this:

Code: Select all

bool LinuxSessionHelperModule::BeforeMainProc(int argc, char* argv[])
{
    g_wxApp = new wxApp();
    wxApp::SetInstance(g_wxApp);
    return true;
}
May be I need call g_wxApp->OnInit() or something like that in separate thread?
And then in LinuxDisplayHelperMaster:

Code: Select all

LinuxDisplayHelperMaster::LinuxDisplayHelperMaster(const TDisplayId& displayId, bool showFrame, int borderThickness)
{
    // some unrelated init code here
    g_wxApp->CallAfter(
                [this, borderThickness]
    {
        m_borderWindow = new LinuxBorderWindow(borderThickness);
        m_borderWindow->Show(true);
    }
    );
}
Code from LinuxDisplayHelperMaster is executed in secondary thread.

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Fri Jun 07, 2019 9:36 am

do not create anything by hands.
just correct your
DECLARE_APP(wxApp)
wxIMPLEMENT_APP_NO_MAIN(wxApp);
to your wxWdgets app name.
what is the current problem?
you do not see wxGetApp()? compiler or linker cannot see this reference?
if compiler -
put DECLARE_APP(wxApp) in some common header(how i know your file structure?).
if linker cannot see - than file where wxIMPLEMENT_APP_NO_MAIN(...) is written is not linked.
ubuntu 16.04, wxWidgets 3.0.4

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Sat Jun 08, 2019 9:50 pm

by the way, my attempt to replant wxWidgets to secondary thread has problems. sometimes strange errors occur, not existing with regular wxWidgets start. errors i see were issued by std:: vector instances, and may be defined as static. i have quite big multithreading application.
Do not know what exactly happens, but it could be somehow connected with static initialization of objects, which c++ runtime is douing before main(..) call.
Without further digging i just returned things back. :)
ubuntu 16.04, wxWidgets 3.0.4

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3366
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Init wxApp from Linux daemon

Post by ONEEYEMAN » Sun Jun 09, 2019 2:50 am

Hi,
This type of problem are usually shown when you trying to access the GUI in the secondary thread (where by secondary thread I mean the thread where no wxApp-derived class was created).

You need to create wxApp and all GUI in one thread.

Thank you.

alys666
I live to help wx-kind
I live to help wx-kind
Posts: 186
Joined: Tue Oct 18, 2016 2:31 pm

Re: Init wxApp from Linux daemon

Post by alys666 » Sun Jun 09, 2019 5:43 pm

ONEEYEMAN wrote:
Sun Jun 09, 2019 2:50 am
Hi,
This type of problem are usually shown when you trying to access the GUI in the secondary thread (where by secondary thread I mean the thread where no wxApp-derived class was created).
You need to create wxApp and all GUI in one thread.
Thank you.
DECLARE_APP(wxApp)
wxIMPLEMENT_APP_NO_MAIN(wxApp);
are declarations.
I cannot "execute" them in any thread, except of main thread of application or thread which loads dll(if declare it in dll).
DECLARE_APP(..) is pure declation
wxIMPLEMENT_APP_NO_MAIN(...) - defines some variable and if it has constructor - application thread executes it before entering applicaion main(...).
ubuntu 16.04, wxWidgets 3.0.4

Post Reply