-
deuce authored
stuff at the same time. Remove the timer idea (Not multithread happy on Win32) and use deferred events with mutexes and semaphores galore. Whee.
deuce authoredstuff at the same time. Remove the timer idea (Not multithread happy on Win32) and use deferred events with mutexes and semaphores galore. Whee.
htmlwin.cpp 8.23 KiB
//
// file name: hworld.cpp
//
// purpose: wxWidgets "Hello world"
//
// For compilers that support precompilation, includes "wx/wx.h".
#undef _DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <wx/wx.h>
#include <wx/app.h>
#include <wx/html/htmlwin.h>
#include <wx/fs_inet.h>
#include <threadwrap.h>
#include <semwrap.h>
#include "htmlwin.h"
static sem_t appstarted;
static sem_t shown;
static sem_t state_changed;
static pthread_mutex_t update_mutex;
static wxString update_str;
enum update_type {
HTML_WIN_UPDATE_NONE
,HTML_WIN_UPDATE_ADD
,HTML_WIN_UPDATE_REPLACE
};
static enum update_type update_type=HTML_WIN_UPDATE_NONE;
static wxFrame *frame;
static wxHtmlWindow *htmlWindow;
static int window_width=640;
static int window_height=400;
static int window_xpos=50;
static int window_ypos=50;
static void(*output_callback)(const char *);
static int(*url_callback)(const char *, char *, size_t, char *, size_t);
static bool html_thread_running=false;
enum html_window_state {
HTML_WIN_STATE_RAISED
,HTML_WIN_STATE_ICONIZED
,HTML_WIN_STATE_HIDDEN
};
static enum html_window_state html_window_requested_state=HTML_WIN_STATE_RAISED;
class MyHTML: public wxHtmlWindow
{
public:
MyHTML(wxFrame *parent, int id);
void Clicked(wxHtmlLinkEvent &ev);
protected:
wxHtmlOpeningStatus OnOpeningURL(wxHtmlURLType type,const wxString& url, wxString *redirect) const;
void MyHTML::OnKeyDown(wxKeyEvent& event);
void MyHTML::OnUpdate(wxCommandEvent &event);
void MyHTML::OnState(wxCommandEvent &event);
DECLARE_EVENT_TABLE()
};
MyHTML::MyHTML(wxFrame *parent, int id) : wxHtmlWindow(parent, id)
{
}
wxHtmlOpeningStatus MyHTML::OnOpeningURL(wxHtmlURLType type,const wxString& url, wxString *redirect) const
{
char cache[4096];
char orig[4096];
char buf[1024];
FILE *outfile;
int ret;
ret=url_callback(url.mb_str(), cache, sizeof(cache), orig, sizeof(orig));
wxString cstr(cache,wxConvUTF8);
wxString remotefile(orig,wxConvUTF8);
redirect->Empty();
redirect->Append(cstr);
switch(ret) {
case URL_ACTION_DOWNLOAD:
outfile=fopen(cache+5 /* file:// */,"wb");
if(outfile) {
wxFileSystem *fs=new wxFileSystem();
wxFSFile *infile=fs->OpenFile(remotefile);
wxInputStream *in=infile->GetStream();
while(!in->Eof())
fwrite(buf, in->Read(buf,sizeof(buf)).LastRead(), 1, outfile);
fclose(outfile);
delete infile;
delete fs;
}
case URL_ACTION_REDIRECT:
return(wxHTML_REDIRECT);
}
return(wxHTML_OPEN);
}
void MyHTML::Clicked(wxHtmlLinkEvent &ev)
{
output_callback(ev.GetLinkInfo().GetHref().mb_str());
}
void MyHTML::OnKeyDown(wxKeyEvent& event)
{
int key=event.GetKeyCode();
char send[2]={0,0};
if(key >= ' ' && key <= '~')
send[0]=key;
else {
switch(key) {
case WXK_BACK:
case WXK_TAB:
case WXK_RETURN:
case WXK_ESCAPE:
case WXK_SPACE:
case WXK_DELETE:
send[0]=key;
}
}
if(send[0])
output_callback(send);
event.Skip();
}
void MyHTML::OnUpdate(wxCommandEvent &event)
{
int width,height,xpos,ypos;
pthread_mutex_lock(&update_mutex);
switch(update_type) {
case HTML_WIN_UPDATE_REPLACE:
frame->Show();
frame->Raise();
frame->GetPosition(&xpos, &ypos);
frame->GetSize(&width, &height);
if(xpos != window_xpos
|| ypos != window_ypos
|| width != window_width
|| height != window_height)
frame->SetSize(window_xpos, window_ypos, window_width, window_height, wxSIZE_AUTO);
htmlWindow->SetPage(update_str);
htmlWindow->Raise();
htmlWindow->SetFocus();
sem_post(&shown);
break;
case HTML_WIN_UPDATE_ADD:
htmlWindow->AppendToPage(update_str);
sem_post(&shown);
break;
}
update_str=wxT("");
update_type=HTML_WIN_UPDATE_NONE;
pthread_mutex_unlock(&update_mutex);
}
void MyHTML::OnState(wxCommandEvent &event)
{
if(wxTheApp) {
switch(html_window_requested_state) {
case HTML_WIN_STATE_RAISED:
if(!frame->IsShown())
frame->Show();
if(frame->IsIconized())
frame->Iconize(false);
frame->Raise();
htmlWindow->Raise();
htmlWindow->SetFocus();
break;
case HTML_WIN_STATE_ICONIZED:
if(!frame->IsShown())
frame->Show();
frame->Lower();
if(!frame->IsIconized())
frame->Iconize(true);
break;
case HTML_WIN_STATE_HIDDEN:
frame->Lower();
if(frame->IsShown())
frame->Show(false);
break;
}
}
sem_post(&state_changed);
}
#define HTML_ID wxID_HIGHEST
DECLARE_EVENT_TYPE(update_event, -1)
DECLARE_EVENT_TYPE(state_event, -1)
DEFINE_EVENT_TYPE(update_event)
DEFINE_EVENT_TYPE(state_event)
BEGIN_EVENT_TABLE(MyHTML, wxHtmlWindow)
EVT_KEY_DOWN(MyHTML::OnKeyDown)
EVT_HTML_LINK_CLICKED(HTML_ID, MyHTML::Clicked)
EVT_COMMAND(HTML_ID, update_event, MyHTML::OnUpdate)
EVT_COMMAND(HTML_ID, state_event, MyHTML::OnState)
END_EVENT_TABLE()
void send_html_event(int evt)
{
wxCommandEvent event( evt, HTML_ID );
htmlWindow->GetEventHandler()->AddPendingEvent( event );
}
class MyFrame: public wxFrame
{
public:
MyFrame(wxWindow * parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style);
private:
void MyFrame::OnCloseWindow(wxCloseEvent& event);
DECLARE_EVENT_TABLE()
};
MyFrame::MyFrame(wxWindow * parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style)
: wxFrame(parent, id, title, pos, size, style)
{
}
void MyFrame::OnCloseWindow(wxCloseEvent& event)
{
if(frame->IsShown())
Show(false);
}
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_CLOSE(MyFrame::OnCloseWindow)
END_EVENT_TABLE()
class MyApp: public wxApp
{
virtual bool OnInit();
};
bool MyApp::OnInit()
{
frame = new MyFrame((wxFrame *)NULL
, -1
, wxT("SyncTERM HTML")
, wxPoint(window_xpos,window_ypos)
, wxSize(window_width,window_height)
, wxCLOSE_BOX | wxMINIMIZE_BOX | wxCAPTION | wxCLIP_CHILDREN
);
htmlWindow = new MyHTML(frame, HTML_ID);
htmlWindow->SetRelatedFrame(frame,wxT("SyncTERM HTML : %s"));
wxFileSystem::AddHandler(new wxInternetFSHandler);
wxInitAllImageHandlers();
frame->Show();
SetTopWindow( frame );
while(wxTheApp->Pending())
wxTheApp->Dispatch();
sem_post(&appstarted);
return true;
}
IMPLEMENT_APP_NO_MAIN(MyApp)
void html_thread(void *args)
{
int argc=1;
char *argv[2];
html_thread_running=true;
argv[0]="wxHTML";
argv[1]="--sync";
wxEntry(argc, argv);
if(wxTheApp) {
wxTheApp->OnExit();
wxTheApp->CleanUp();
}
else
sem_post(&appstarted);
html_thread_running=false;
}
extern "C" {
int run_html(int width, int height, int xpos, int ypos, void(*callback)(const char *), int(*ucallback)(const char *, char *, size_t, char *, size_t))
{
output_callback=callback;
url_callback=ucallback;
window_xpos=xpos==-1?wxDefaultCoord:xpos;
window_ypos=ypos==-1?wxDefaultCoord:ypos;
window_width=width==-1?640:width;
window_height=height==-1?200:height;
if(!html_thread_running) {
sem_init(&appstarted, 0, 0);
sem_init(&state_changed, 0, 0);
sem_init(&shown, 0, 0);
pthread_mutex_init(&update_mutex, NULL);
_beginthread(html_thread, 0, NULL);
sem_wait(&appstarted);
sem_destroy(&appstarted);
}
return(!wxTheApp);
}
void hide_html(void)
{
html_window_requested_state=HTML_WIN_STATE_HIDDEN;
send_html_event(state_event);
sem_wait(&state_changed);
}
void iconize_html(void)
{
html_window_requested_state=HTML_WIN_STATE_ICONIZED;
send_html_event(state_event);
sem_wait(&state_changed);
}
void raise_html(void)
{
html_window_requested_state=HTML_WIN_STATE_RAISED;
send_html_event(state_event);
sem_wait(&state_changed);
}
void html_commit(void)
{
pthread_mutex_lock(&update_mutex);
if(update_type!=HTML_WIN_UPDATE_NONE) {
send_html_event(update_event);
pthread_mutex_unlock(&update_mutex);
sem_wait(&shown);
}
else
pthread_mutex_unlock(&update_mutex);
}
void add_html(const char *buf)
{
wxString wx_page(buf,wxConvUTF8);
pthread_mutex_lock(&update_mutex);
update_str+=wx_page;
update_type=HTML_WIN_UPDATE_ADD;
pthread_mutex_unlock(&update_mutex);
}
void add_html_char(char ch)
{
char str[2];
str[0]=ch;
str[1]=0;
add_html(str);
}
void show_html(const char *page)
{
if(wxTheApp) {
pthread_mutex_lock(&update_mutex);
wxString wx_page(page, wxConvUTF8);
update_str=wx_page;
update_type=HTML_WIN_UPDATE_REPLACE;
pthread_mutex_unlock(&update_mutex);
html_commit();
}
}
}