opennx/tracelogApp.cpp
2025-08-08 20:34:09 +02:00

350 lines
9.4 KiB
C++

// $Id: tracelogApp.cpp 702 2012-02-24 11:41:12Z felfert $
//
// Copyright (C) 2006 The OpenNX Team
// Author: Fritz Elfert
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
////@begin includes
#include "wx/fs_zip.h"
////@end includes
#include <wx/sysopt.h>
#include "wx/fs_mem.h"
#include <wx/taskbar.h>
#include <wx/dynarray.h>
#include <wx/mimetype.h>
#include <wx/sckstrm.h>
#include <wx/txtstrm.h>
#include "tracelogApp.h"
#include "Icon.h"
#include "TraceLogFrame.h"
#include "TraceLogRemote.h"
#include "DebugStringGrabber.h"
#include "memres.h"
#include <algorithm>
////@begin XPM images
////@end XPM images
static int TB_SHOWTRACE = ::wxNewId();
static int TB_REMOTE = ::wxNewId();
static int SERVER_ID = ::wxNewId();
static int SOCKET_ID = ::wxNewId();
class DebugEntry {
public:
pid_t pid;
wxDateTime stamp;
wxString msg;
};
WX_DECLARE_OBJARRAY(DebugEntry, DebugEntryArray);
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(DebugEntryArray);
class MyTaskBarIcon : public wxTaskBarIcon {
public:
virtual wxMenu *CreatePopupMenu() {
wxMenu *menu = new wxMenu;
menu->Append(TB_SHOWTRACE, _("Show Trace Log"));
menu->AppendCheckItem(TB_REMOTE, _("Enable remote debug"));
menu->Append(wxID_EXIT, _("E&xit"));
menu->Check(TB_REMOTE, ::wxGetApp().ServerEnabled());
return menu;
}
void OnMenuShowTrace(wxCommandEvent &evt) {
::wxGetApp().GetTopWindow()->Show(true);
evt.Skip();
}
void OnMenuRemote(wxCommandEvent &evt) {
if (evt.IsChecked()) {
::wxGetApp().StartSocketServer();
} else {
::wxGetApp().StopSocketServer();
}
evt.Skip();
}
void OnShowTrace(wxTaskBarIconEvent &evt) {
::wxGetApp().GetTopWindow()->Show(true);
evt.Skip();
}
void OnMenuExit(wxCommandEvent &evt) {
::wxGetApp().Terminate();
evt.Skip();
}
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MyTaskBarIcon, wxTaskBarIcon)
EVT_MENU(TB_SHOWTRACE, MyTaskBarIcon::OnMenuShowTrace)
EVT_MENU(TB_REMOTE, MyTaskBarIcon::OnMenuRemote)
EVT_MENU(wxID_EXIT, MyTaskBarIcon::OnMenuExit)
EVT_TASKBAR_LEFT_DCLICK(MyTaskBarIcon::OnShowTrace)
END_EVENT_TABLE();
/*!
* Application instance implementation
*/
////@begin implement app
IMPLEMENT_APP( tracelogApp )
////@end implement app
/*!
* tracelogApp type definition
*/
IMPLEMENT_CLASS( tracelogApp, wxApp )
/*!
* tracelogApp event table definition
*/
BEGIN_EVENT_TABLE(tracelogApp, wxApp)
////@begin tracelogApp event table entries
////@end tracelogApp event table entries
EVT_SOCKET(SERVER_ID, tracelogApp::OnServerEvent)
EVT_SOCKET(SOCKET_ID, tracelogApp::OnSocketEvent)
END_EVENT_TABLE()
/*!
* Constructor for tracelogApp
*/
tracelogApp::tracelogApp()
{
Init();
}
/*!
* Member initialisation
*/
void tracelogApp::Init()
{
m_pTaskBarIcon = NULL;
m_pGrabber = NULL;
m_pSocketServer = NULL;
m_sAllowedPeers = wxT("^\\d+\\.\\d+\\.\\d+\\.\\d+$");
m_nPort = 2020;
m_cAllowedPeers.Compile(m_sAllowedPeers, wxRE_ADVANCED);
////@begin tracelogApp member initialisation
////@end tracelogApp member initialisation
}
void tracelogApp::OnDebugString(wxCommandEvent &event)
{
m_pLogFrame->AddEntry(wxDateTime::UNow(), event.GetInt(), event.GetString());
std::map<wxSocketBase *, wxSocketOutputStream *>::iterator it;
for (it = m_mClients.begin() ; it != m_mClients.end(); it++) {
wxTextOutputStream s(*(it->second));
s << event.GetInt() << wxT("\t") << event.GetString() << endl;
}
event.Skip();
}
void tracelogApp::Terminate()
{
StopSocketServer();
if (m_pTaskBarIcon)
m_pTaskBarIcon->RemoveIcon();
if (m_pGrabber)
delete m_pGrabber;
m_pGrabber = NULL;
if (m_pLogFrame) {
m_pLogFrame->Close(true);
delete m_pLogFrame;
}
m_pLogFrame = NULL;
ExitMainLoop();
}
/*!
* Initialisation for tracelogApp
*/
bool tracelogApp::OnInit()
{
// Win: Don't remap bitmaps to system colors
wxSystemOptions::SetOption(wxT("msw.remap"), 0);
// WinXP: Don't draw themed gradients on notebook pages
wxSystemOptions::SetOption(wxT("msw.notebook.themed-background"), 0);
// Call to base class needed for initializing command line processing
if (!wxApp::OnInit())
return false;
wxFileSystem::AddHandler(new wxZipFSHandler);
wxFileSystem::AddHandler(new wxMemoryFSHandler);
wxInitAllImageHandlers();
wxBitmap::InitStandardHandlers();
wxXmlResource::Get()->InitAllHandlers();
const unsigned char *resptr = get_mem_res();
wxMemoryFSHandler::AddFileWithMimeType(wxT("memrsc"), resptr, cnt_mem_res, wxT("application/zip"));
{
// The following code eliminates a stupid error dialog which shows up
// if some .desktop entires (in KDE or GNOME applink dirs) are dangling symlinks.
wxLogNull lognull;
wxTheMimeTypesManager->GetFileTypeFromExtension(wxT("zip"));
}
free_mem_res(resptr);
m_sResourcePrefix = wxT("memory:memrsc#zip:");
if (!wxXmlResource::Get()->Load(m_sResourcePrefix + wxT("res/tracelog.xrc")))
return false;
m_pGrabber = new DebugStringGrabber();
if (!m_pGrabber->IsOk())
return false;
m_pLogFrame = new TraceLogFrame(NULL);
SetTopWindow(m_pLogFrame);
Connect(wxEVT_DEBUGSTRING, wxCommandEventHandler(tracelogApp::OnDebugString));
m_pGrabber->SetHandler(this);
m_pTaskBarIcon = new MyTaskBarIcon();
m_pTaskBarIcon->SetIcon(CreateIconFromFile(wxT("res/nx.png")), _("OpenNX"));
SetExitOnFrameDelete(true);
return true;
}
/*!
* Cleanup for tracelogApp
*/
int tracelogApp::OnExit()
{
StopSocketServer();
if (m_pTaskBarIcon)
m_pTaskBarIcon->RemoveIcon();
if (m_pGrabber)
delete m_pGrabber;
if (m_pLogFrame)
delete m_pLogFrame;
////@begin tracelogApp cleanup
return wxApp::OnExit();
////@end tracelogApp cleanup
}
void tracelogApp::StartSocketServer()
{
if (NULL == m_pSocketServer) {
TraceLogRemote d(NULL);
d.SetPort(m_nPort);
d.SetCregex(m_sAllowedPeers);
if (wxID_OK == d.ShowModal()) {
m_nPort = d.GetPort();
wxString tmp = d.GetCregex();
if (!tmp.IsEmpty()) {
wxRegEx testRE;
if (testRE.Compile(tmp, wxRE_ADVANCED)) {
m_sAllowedPeers = tmp;
}
}
m_cAllowedPeers.Compile(m_sAllowedPeers, wxRE_ADVANCED);
wxIPV4address addr;
addr.Service(m_nPort);
m_pSocketServer = new wxSocketServer(addr, wxSOCKET_REUSEADDR);
if (m_pSocketServer->Ok()) {
m_pSocketServer->SetEventHandler(*this, SERVER_ID);
m_pSocketServer->SetNotify(wxSOCKET_CONNECTION_FLAG);
m_pSocketServer->Notify(true);
} else {
m_pSocketServer->Destroy();
m_pSocketServer = NULL;
}
}
}
}
void tracelogApp::StopSocketServer()
{
if (NULL != m_pSocketServer) {
m_pSocketServer->Destroy();
m_pSocketServer = NULL;
}
}
void tracelogApp::OnServerEvent(wxSocketEvent& event)
{
// Accept new connection if there is one in the pending
// connections queue, else exit. We use Accept(false) for
// non-blocking accept (although if we got here, there
// should ALWAYS be a pending connection).
wxSocketBase *sock = m_pSocketServer->Accept(false);
if (sock) {
wxIPV4address peer;
if (sock->GetPeer(peer)) {
if (m_cAllowedPeers.Matches(peer.IPAddress())) {
sock->SetEventHandler(*this, SOCKET_ID);
sock->SetNotify(wxSOCKET_LOST_FLAG);
sock->SetFlags(wxSOCKET_WAITALL);
sock->SetTimeout(10);
m_mClients[sock] = new wxSocketOutputStream(*sock);
sock->Notify(true);
return;
}
}
sock->Destroy();
}
}
void tracelogApp::OnSocketEvent(wxSocketEvent& event)
{
wxSocketBase *sock = event.GetSocket();
if (wxSOCKET_LOST == event.GetSocketEvent()) {
sock->Notify(false);
std::map<wxSocketBase *, wxSocketOutputStream *>::iterator it = m_mClients.find(sock);
if (m_mClients.end() != it) {
delete it->second;
m_mClients.erase(it);
}
sock->Destroy();
}
}