v0.9.5
This commit is contained in:
parent
a76af47d73
commit
1f92260cdf
18
ChangeLog
18
ChangeLog
@ -1,6 +1,14 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
0.9.4 -> 0.9.5
|
||||
--------------
|
||||
* Windows fixes and improvements:
|
||||
- system-tray + dialog-box user interface
|
||||
- fix for dropped connections
|
||||
- fix for content file deletion
|
||||
- fix for directory iterator
|
||||
|
||||
0.9.3 -> 0.9.4
|
||||
--------------
|
||||
* Fixed memory leak when no "--log" switch.
|
||||
@ -10,11 +18,11 @@ Change Log
|
||||
|
||||
0.9.2 -> 0.9.3
|
||||
--------------
|
||||
* Proxy mode (--immediate and --as-proxy)
|
||||
* Message preprocessing (--filter)
|
||||
* Message store classes better separated using abstract interfaces
|
||||
* Improved notification script, with MIME encoding
|
||||
* Builds with old 2.91 version of gcc
|
||||
* Proxy mode (--immediate and --as-proxy).
|
||||
* Message preprocessing (--filter).
|
||||
* Message store classes better separated using abstract interfaces.
|
||||
* Improved notification script, with MIME encoding.
|
||||
* Builds with old 2.91 version of gcc.
|
||||
|
||||
0.9.1 -> 0.9.2
|
||||
--------------
|
||||
|
8
README
8
README
@ -4,11 +4,11 @@ E-MailRelay Readme
|
||||
Abstract
|
||||
--------
|
||||
E-MailRelay is a simple SMTP store-and-forward message transfer agent (MTA).
|
||||
It runs as an SMTP server, storing incoming e-mail in a local spool directory,
|
||||
and then forwarding the stored messages to a downstream SMTP server on request.
|
||||
It runs as an SMTP server, storing e-mail in a local spool directory, and
|
||||
then forwarding the stored messages to a downstream SMTP server on request.
|
||||
It can also run as a proxy server, forwarding (and optionally pre-processing)
|
||||
incoming e-mail as soon as it is received. It does not do any message routing,
|
||||
other than to a local postmaster. Because of this functional simplicity it is
|
||||
e-mail as soon as it is received. It does not do any message routing, other
|
||||
than to a local postmaster. Because of this functional simplicity it is
|
||||
extremely easy to configure, typically only requiring the address of the
|
||||
downstream SMTP server to be put on the command line.
|
||||
|
||||
|
2
configure
vendored
2
configure
vendored
@ -691,7 +691,7 @@ fi
|
||||
|
||||
PACKAGE=emailrelay
|
||||
|
||||
VERSION=0.9.4
|
||||
VERSION=0.9.5
|
||||
|
||||
if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
|
||||
{ echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
|
||||
|
@ -39,7 +39,7 @@ dnl ===
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(src/main/gsmtp.h)
|
||||
AM_INIT_AUTOMAKE(emailrelay,0.9.4)
|
||||
AM_INIT_AUTOMAKE(emailrelay,0.9.5)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl ===
|
||||
|
@ -4,22 +4,22 @@ E-MailRelay User Guide
|
||||
What is it?
|
||||
-----------
|
||||
E-MailRelay is a simple store-and-forward e-mail transfer agent. It's a program
|
||||
which runs in the background and accepts e-mail front-ends (KMail, Outlook,
|
||||
which runs in the background and accepts e-mail from front-ends (KMail, Outlook,
|
||||
Netscape etc.), stores the messages on the hard disk, and when next connected
|
||||
to the Internet forwards them to a downstream SMTP server for onward delivery.
|
||||
|
||||
The E-MailRelay program ("emailrelay") can run in two main modes: a storage daemon,
|
||||
or a forwarding agent. As a storage daemon it waits for connections from your
|
||||
e-mail front-end and stores the mail which it receives in a spool directory.
|
||||
As a forwarding agent it pulls messages out of the spool directory and passes
|
||||
them on to a remote server -- typically an ISP mail server.
|
||||
The E-MailRelay program ("emailrelay") can run in two main modes: a storage
|
||||
daemon, or a forwarding agent. As a storage daemon it waits for connections
|
||||
from your e-mail front-end and stores the mail which it receives in a spool
|
||||
directory. As a forwarding agent it pulls messages out of the spool directory
|
||||
and passes them on to a remote server -- typically an ISP mail server.
|
||||
|
||||
E-MailRelay uses the Simple Message Transfer Protocol (SMTP). When running as a
|
||||
storage daemon it acts as an SMTP server, and when running as a forwarding
|
||||
agent it acts as an SMTP client.
|
||||
|
||||
The program can also run as a proxy server. In this mode e-mails submitted at the
|
||||
server interface are passed on to the dowstream server immediately, without
|
||||
The program can also run as a proxy server. In this mode e-mails submitted at
|
||||
the server interface are passed on to the dowstream server immediately, without
|
||||
spooling. This can be useful when combined with mail pre-processing to do things
|
||||
like encryption, message archiving, addition of digital signatures, etc.
|
||||
|
||||
|
@ -1,19 +1,19 @@
|
||||
Summary: Simple e-mail message transfer agent using SMTP
|
||||
Name: emailrelay
|
||||
Version: 0.9.4
|
||||
Version: 0.9.5
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
Source: http://emailrelay.sourceforge.net/.../emailrelay-src-0.9.4.tar.gz
|
||||
Source: http://emailrelay.sourceforge.net/.../emailrelay-src-0.9.5.tar.gz
|
||||
BuildRoot: /tmp/emailrelay-install
|
||||
|
||||
%description
|
||||
E-MailRelay is a simple SMTP store-and-forward message transfer agent (MTA).
|
||||
It runs as an SMTP server, storing incoming e-mail in a local spool directory,
|
||||
and then forwarding the stored messages to a downstream SMTP server on request.
|
||||
It runs as an SMTP server, storing e-mail in a local spool directory, and
|
||||
then forwarding the stored messages to a downstream SMTP server on request.
|
||||
It can also run as a proxy server, forwarding (and optionally pre-processing)
|
||||
incoming e-mail as soon as it is received. It does not do any message routing,
|
||||
other than to a local postmaster. Because of this functional simplicity it is
|
||||
e-mail as soon as it is received. It does not do any message routing, other
|
||||
than to a local postmaster. Because of this functional simplicity it is
|
||||
extremely easy to configure, typically only requiring the address of the
|
||||
downstream SMTP server to be put on the command line.
|
||||
|
||||
|
@ -34,6 +34,7 @@ namespace std
|
||||
using ::strrchr ;
|
||||
using ::strdup ;
|
||||
using ::strcpy ;
|
||||
using ::strncpy ;
|
||||
using ::strstr ;
|
||||
using ::strspn ;
|
||||
using ::strcspn ;
|
||||
|
@ -34,6 +34,7 @@ libglib_a_SOURCES = \
|
||||
gassert.h \
|
||||
gconvert.h \
|
||||
gdaemon.h \
|
||||
gdaemon.cpp \
|
||||
gdaemon_unix.cpp \
|
||||
gdate.cpp \
|
||||
gdate.h \
|
||||
|
@ -93,7 +93,7 @@ EXTRA_DIST = garg_win32.cpp gdaemon_win32.cpp gdatetime_win32.cpp gdirectory_
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/lib/gcc2.95
|
||||
noinst_LIBRARIES = libglib.a
|
||||
libglib_a_SOURCES = garg.cpp garg.h garg_unix.cpp gassert.h gconvert.h gdaemon.h gdaemon_unix.cpp gdate.cpp gdate.h gdatetime.cpp gdatetime.h gdatetime_unix.cpp gdebug.h gdef.h gdirectory.cpp gdirectory.h gdirectory_unix.cpp gexception.cpp gexception.h gfile.cpp gfile.h gfile_unix.cpp gfs.h gfs_unix.cpp ggetopt.cpp ggetopt.h glog.cpp glog.h glogoutput.cpp glogoutput.h glogoutput_unix.cpp gmemory.h gpath.cpp gpath.h gprocess.h gprocess_unix.cpp gstr.cpp gstr.h gstrings.h gtime.cpp gtime.h
|
||||
libglib_a_SOURCES = garg.cpp garg.h garg_unix.cpp gassert.h gconvert.h gdaemon.h gdaemon.cpp gdaemon_unix.cpp gdate.cpp gdate.h gdatetime.cpp gdatetime.h gdatetime_unix.cpp gdebug.h gdef.h gdirectory.cpp gdirectory.h gdirectory_unix.cpp gexception.cpp gexception.h gfile.cpp gfile.h gfile_unix.cpp gfs.h gfs_unix.cpp ggetopt.cpp ggetopt.h glog.cpp glog.h glogoutput.cpp glogoutput.h glogoutput_unix.cpp gmemory.h gpath.cpp gpath.h gprocess.h gprocess_unix.cpp gstr.cpp gstr.h gstrings.h gtime.cpp gtime.h
|
||||
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = ../../config.h
|
||||
@ -106,7 +106,7 @@ CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
libglib_a_LIBADD =
|
||||
libglib_a_OBJECTS = garg.o garg_unix.o gdaemon_unix.o gdate.o \
|
||||
libglib_a_OBJECTS = garg.o garg_unix.o gdaemon.o gdaemon_unix.o gdate.o \
|
||||
gdatetime.o gdatetime_unix.o gdirectory.o gdirectory_unix.o \
|
||||
gexception.o gfile.o gfile_unix.o gfs_unix.o ggetopt.o glog.o \
|
||||
glogoutput.o glogoutput_unix.o gpath.o gprocess_unix.o gstr.o gtime.o
|
||||
@ -226,6 +226,10 @@ garg_unix.o: garg_unix.cpp gdef.h ../../config.h \
|
||||
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
|
||||
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits garg.h \
|
||||
gdebug.h glogoutput.h glog.h gassert.h
|
||||
gdaemon.o: gdaemon.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \
|
||||
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
|
||||
../../lib/gcc2.95/limits gdaemon.h gexception.h gpath.h \
|
||||
gstrings.h gprocess.h
|
||||
gdaemon_unix.o: gdaemon_unix.cpp gdef.h ../../config.h \
|
||||
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
|
||||
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gdaemon.h \
|
||||
|
75
src/glib/gdaemon.cpp
Normal file
75
src/glib/gdaemon.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gdaemon.cpp
|
||||
//
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gdaemon.h"
|
||||
#include "gprocess.h"
|
||||
|
||||
//static
|
||||
void G::Daemon::PidFile::check( const G::Path & pid_file )
|
||||
{
|
||||
if( pid_file != G::Path() && !pid_file.isAbsolute() )
|
||||
throw G::Daemon::BadPidFile(std::string("must be an absolute path: ")+pid_file.str()) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void G::Daemon::PidFile::test( const G::Path & pid_file )
|
||||
{
|
||||
if( pid_file != G::Path() )
|
||||
{
|
||||
std::ofstream tester( pid_file.str().c_str() ) ;
|
||||
if( !tester.good() )
|
||||
throw G::Daemon::BadPidFile(std::string("cannot create file: ")+pid_file.str()) ;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void G::Daemon::PidFile::create( const G::Path & pid_file )
|
||||
{
|
||||
if( pid_file != G::Path() )
|
||||
{
|
||||
std::ofstream file( pid_file.str().c_str() ) ;
|
||||
file << G::Process::Id() << std::endl ;
|
||||
if( !file.good() )
|
||||
throw G::Daemon::BadPidFile(std::string("cannot create file: ")+pid_file.str()) ;
|
||||
}
|
||||
}
|
||||
|
||||
G::Daemon::PidFile::PidFile() :
|
||||
m_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
G::Daemon::PidFile::PidFile( const G::Path & path ) :
|
||||
m_path(path) ,
|
||||
m_valid(true)
|
||||
{
|
||||
}
|
||||
|
||||
void G::Daemon::PidFile::commit()
|
||||
{
|
||||
if( m_valid )
|
||||
create( m_path ) ;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,9 @@ public:
|
||||
private: Path m_path ;
|
||||
private: bool m_valid ;
|
||||
friend class Daemon ;
|
||||
private: static void check( const Path & ) ;
|
||||
private: static void test( const Path & ) ;
|
||||
private: static void create( const Path & ) ;
|
||||
} ;
|
||||
|
||||
static void detach() ;
|
||||
|
@ -25,51 +25,21 @@
|
||||
#include "gdaemon.h"
|
||||
#include "gprocess.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
void PidFile__testSyntax( const G::Path & pid_file )
|
||||
{
|
||||
if( pid_file != G::Path() && !pid_file.isAbsolute() )
|
||||
throw G::Daemon::BadPidFile(std::string("must be an absolute path: ")+pid_file.str()) ;
|
||||
}
|
||||
|
||||
void PidFile__testCreation( const G::Path & pid_file )
|
||||
{
|
||||
if( pid_file != G::Path() )
|
||||
{
|
||||
std::ofstream tester( pid_file.str().c_str() ) ;
|
||||
if( !tester.good() )
|
||||
throw G::Daemon::BadPidFile(std::string("cannot create file: ")+pid_file.str()) ;
|
||||
}
|
||||
}
|
||||
|
||||
void PidFile__create( const G::Path & pid_file )
|
||||
{
|
||||
if( pid_file != G::Path() )
|
||||
{
|
||||
std::ofstream file( pid_file.str().c_str() ) ;
|
||||
file << G::Process::Id() << std::endl ;
|
||||
if( !file.good() )
|
||||
throw G::Daemon::BadPidFile(std::string("cannot create file: ")+pid_file.str()) ;
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
//static
|
||||
void G::Daemon::detach( const Path & pid_file )
|
||||
{
|
||||
PidFile__testSyntax( pid_file ) ;
|
||||
PidFile__testCreation( pid_file ) ;
|
||||
PidFile::check( pid_file ) ;
|
||||
PidFile::test( pid_file ) ;
|
||||
|
||||
detach() ;
|
||||
|
||||
PidFile__create( pid_file ) ;
|
||||
PidFile::create( pid_file ) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void G::Daemon::detach( PidFile & pid_file )
|
||||
{
|
||||
PidFile__testSyntax( pid_file.m_path ) ;
|
||||
PidFile::check( pid_file.m_path ) ;
|
||||
detach() ;
|
||||
}
|
||||
|
||||
@ -95,23 +65,3 @@ void G::Daemon::setsid()
|
||||
; // no-op
|
||||
}
|
||||
|
||||
// ===
|
||||
|
||||
G::Daemon::PidFile::PidFile() :
|
||||
m_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
G::Daemon::PidFile::PidFile( const G::Path & path ) :
|
||||
m_path(path) ,
|
||||
m_valid(true)
|
||||
{
|
||||
}
|
||||
|
||||
void G::Daemon::PidFile::commit()
|
||||
{
|
||||
if( m_valid )
|
||||
PidFile__create( m_path ) ;
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,22 +40,6 @@ void G::Daemon::detach( PidFile & )
|
||||
//static
|
||||
void G::Daemon::detach()
|
||||
{
|
||||
(void) ::FreeConsole() ;
|
||||
}
|
||||
|
||||
// ===
|
||||
|
||||
G::Daemon::PidFile::PidFile() :
|
||||
m_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
G::Daemon::PidFile::PidFile( const Path & ) :
|
||||
m_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
void G::Daemon::PidFile::commit()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
|
@ -186,8 +186,8 @@ bool G::DirectoryIteratorImp::more()
|
||||
if( m_first )
|
||||
{
|
||||
m_first = false ;
|
||||
if( std::string(m_context.cFileName) == "." ||
|
||||
std::string(m_context.cFileName) == ".." )
|
||||
if( std::string(m_context.cFileName) != "." &&
|
||||
std::string(m_context.cFileName) != ".." )
|
||||
return true ;
|
||||
|
||||
G_DEBUG( "G::DirectoryIteratorImp::more: ignoring " << m_context.cFileName);
|
||||
|
@ -48,14 +48,13 @@ void G::GetOpt::parseSpec( const std::string & spec , char sep_major , char sep_
|
||||
|
||||
void G::GetOpt::parseOldSpec( const std::string & spec )
|
||||
{
|
||||
unsigned int ordinal = 1U ;
|
||||
for( size_t i = 0U ; i < spec.length() ; i++ )
|
||||
{
|
||||
char c = spec.at(i) ;
|
||||
if( c != ':' )
|
||||
{
|
||||
bool valued = (i+1U) < spec.length() && spec.at(i+1U) == ':' ;
|
||||
addSpec( ordinal++ , c , valued ) ;
|
||||
addSpec( std::string(1U,c) , c , valued ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,7 +66,6 @@ void G::GetOpt::parseNewSpec( const std::string & spec , char sep_major ,
|
||||
std::string ws_major( 1U , sep_major ) ;
|
||||
G::Str::splitIntoFields( spec , outer , ws_major , escape , false ) ;
|
||||
|
||||
unsigned int ordinal = 1U ;
|
||||
for( Strings::iterator p = outer.begin() ; p != outer.end() ; ++p )
|
||||
{
|
||||
StringArray inner ;
|
||||
@ -76,16 +74,16 @@ void G::GetOpt::parseNewSpec( const std::string & spec , char sep_major ,
|
||||
if( inner.size() != 5U )
|
||||
throw InvalidSpecification(std::stringstream() << "\"" << *p << "\" (" << ws_minor << ")") ;
|
||||
bool valued = G::Str::toUInt( inner[3U] ) != 0U ;
|
||||
addSpec( ordinal++ , inner[0U].at(0U) , inner[1U] , inner[2U] , valued , inner[4U] ) ;
|
||||
addSpec( inner[1U] , inner[0U].at(0U) , inner[1U] , inner[2U] , valued , inner[4U] ) ;
|
||||
}
|
||||
}
|
||||
|
||||
void G::GetOpt::addSpec( unsigned int ordinal , char c , bool valued )
|
||||
void G::GetOpt::addSpec( const std::string & sort_key , char c , bool valued )
|
||||
{
|
||||
addSpec( ordinal , c , std::string() , std::string() , valued , std::string() ) ;
|
||||
addSpec( sort_key , c , std::string() , std::string() , valued , std::string() ) ;
|
||||
}
|
||||
|
||||
void G::GetOpt::addSpec( unsigned int ordinal , char c , const std::string & name , const std::string & description ,
|
||||
void G::GetOpt::addSpec( const std::string & sort_key , char c , const std::string & name , const std::string & description ,
|
||||
bool valued , const std::string & value_description )
|
||||
{
|
||||
if( c == '\0' )
|
||||
@ -94,7 +92,8 @@ void G::GetOpt::addSpec( unsigned int ordinal , char c , const std::string & nam
|
||||
const bool debug = true ;
|
||||
if( debug )
|
||||
{
|
||||
G_DEBUG( "G::GetOpt::addSpec: #" << ordinal << ": "
|
||||
G_DEBUG( "G::GetOpt::addSpec: "
|
||||
<< "sort-key=" << sort_key << ": "
|
||||
<< "char=" << c << ": "
|
||||
<< "name=" << name << ": "
|
||||
<< "description=" << description << ": "
|
||||
@ -103,7 +102,7 @@ void G::GetOpt::addSpec( unsigned int ordinal , char c , const std::string & nam
|
||||
}
|
||||
|
||||
std::pair<SwitchSpecMap::iterator,bool> rc =
|
||||
m_spec_map.insert( std::make_pair(ordinal,SwitchSpec(c,name,description,valued,value_description)) ) ;
|
||||
m_spec_map.insert( std::make_pair(sort_key,SwitchSpec(c,name,description,valued,value_description)) ) ;
|
||||
|
||||
if( ! rc.second )
|
||||
throw InvalidSpecification("duplication") ;
|
||||
|
@ -137,7 +137,7 @@ private:
|
||||
hidden(description_.empty()) ,
|
||||
valued(v_) , value_description(vd_) {}
|
||||
} ;
|
||||
typedef std::map<unsigned int,SwitchSpec GLessAllocator(char,SwitchSpec) > SwitchSpecMap ;
|
||||
typedef std::map<std::string,SwitchSpec GLessAllocator(char,SwitchSpec) > SwitchSpecMap ;
|
||||
typedef std::pair<bool,std::string> Value ;
|
||||
typedef std::map<char,Value GLessAllocator(char,Value) > SwitchMap ;
|
||||
|
||||
@ -146,8 +146,8 @@ private:
|
||||
void parseSpec( const std::string & spec , char , char , char ) ;
|
||||
void parseOldSpec( const std::string & spec ) ;
|
||||
void parseNewSpec( const std::string & spec , char , char , char ) ;
|
||||
void addSpec( unsigned int ordinal , char c , bool valued ) ;
|
||||
void addSpec( unsigned int ordinal , char c , const std::string & name , const std::string & , bool valued , const std::string & ) ;
|
||||
void addSpec( const std::string & sort_key , char c , bool valued ) ;
|
||||
void addSpec( const std::string & sort_key , char c , const std::string & name , const std::string & , bool valued , const std::string & ) ;
|
||||
size_t parseArgs( const Arg & args_in ) ;
|
||||
bool isOldSwitch( const std::string & arg ) const ;
|
||||
bool isNewSwitch( const std::string & arg ) const ;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <cstdlib> // getenv
|
||||
#include <cstring> // strlen
|
||||
|
||||
|
||||
void G::LogOutput::rawOutput( G::Log::Severity severity , const char *message )
|
||||
{
|
||||
std::cerr << message ;
|
||||
@ -54,5 +55,7 @@ void G::LogOutput::rawOutput( G::Log::Severity severity , const char *message )
|
||||
|
||||
void G::LogOutput::syslog()
|
||||
{
|
||||
// no-op
|
||||
// see also ::RegisterEventSource() and ::ReportEvent() for NT
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ void operator<<=( std::auto_ptr<T> & ap , T * p )
|
||||
}
|
||||
|
||||
// Template function: operator<<=
|
||||
// Description: A version for null pointers.
|
||||
// Description: A version for null-pointer constants.
|
||||
//
|
||||
template <class T>
|
||||
void operator<<=( std::auto_ptr<T> & ap , int null_pointer )
|
||||
|
@ -414,6 +414,11 @@ bool G::Path::operator==( const Path & other ) const
|
||||
return m_str == other.m_str ;
|
||||
}
|
||||
|
||||
bool G::Path::operator!=( const Path & other ) const
|
||||
{
|
||||
return m_str != other.m_str ;
|
||||
}
|
||||
|
||||
G::Path &G::Path::operator=( const Path & other )
|
||||
{
|
||||
if( &other != this )
|
||||
|
@ -143,6 +143,9 @@ public:
|
||||
bool operator==( const Path & path ) const ;
|
||||
// Comparison operator.
|
||||
|
||||
bool operator!=( const Path & path ) const ;
|
||||
// Comparison operator.
|
||||
|
||||
void streamOut( std::ostream & stream ) const ;
|
||||
// Streams out the path.
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace G
|
||||
class G::Process::IdImp
|
||||
{
|
||||
public:
|
||||
int m_pid ;
|
||||
unsigned int m_pid ;
|
||||
} ;
|
||||
|
||||
// ===
|
||||
@ -49,7 +49,7 @@ public:
|
||||
G::Process::Id::Id() : m_imp(NULL)
|
||||
{
|
||||
m_imp = new IdImp ;
|
||||
m_imp->m_pid = ::_getpid() ;
|
||||
m_imp->m_pid = static_cast<unsigned int>(::_getpid()) ; // or ::GetCurrentProcessId()
|
||||
}
|
||||
|
||||
G::Process::Id::~Id()
|
||||
|
@ -214,6 +214,13 @@ unsigned short G::Str::toUShort( const std::string &s , bool limited )
|
||||
return ushort_val ;
|
||||
}
|
||||
|
||||
std::string G::Str::fromUInt( unsigned int n )
|
||||
{
|
||||
std::stringstream ss ;
|
||||
ss << n ;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
void G::Str::toLower( std::string &s )
|
||||
{
|
||||
for( std::string::iterator p = s.begin() ; p != s.end() ; ++p )
|
||||
|
@ -119,6 +119,9 @@ public:
|
||||
// Exception: Overflow
|
||||
// Exception: InvalidFormat
|
||||
|
||||
static std::string fromUInt( unsigned int ) ;
|
||||
// Converts from unsigned int to a decimal string.
|
||||
|
||||
static void toUpper( std::string &s ) ;
|
||||
// Replaces all lowercase characters in string 's' by
|
||||
// uppercase characters.
|
||||
|
@ -435,20 +435,22 @@ void GNet::ClientImp::readEvent()
|
||||
char buffer[200U] ;
|
||||
ssize_t n = s().read( buffer , sizeof(buffer) ) ;
|
||||
|
||||
if( n <= 0 )
|
||||
if( n == 0 || ( n == -1 && !s().eWouldBlock() ) )
|
||||
{
|
||||
if( s().eWouldBlock() ) return ; // for windows
|
||||
|
||||
close() ;
|
||||
setState( Disconnected ) ;
|
||||
m_interface.onDisconnect() ;
|
||||
}
|
||||
else
|
||||
else if( n != -1 )
|
||||
{
|
||||
G_ASSERT( n <= sizeof(buffer) ) ;
|
||||
G_DEBUG( "GNet::ClientImp::readEvent: " << n << " byte(s)" ) ;
|
||||
m_interface.onData( buffer , n ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
; // no-op (windows)
|
||||
}
|
||||
}
|
||||
|
||||
void GNet::ClientImp::exceptionEvent()
|
||||
|
@ -97,32 +97,32 @@ void GNet::Monitor::remove( const ServerPeer & peer )
|
||||
m_imp->m_server_peers.erase( & peer ) ;
|
||||
}
|
||||
|
||||
void GNet::Monitor::report( std::ostream & stream )
|
||||
void GNet::Monitor::report( std::ostream & s , const std::string & px , const std::string & eol )
|
||||
{
|
||||
stream << "clients created: " << m_imp->m_client_adds << std::endl ;
|
||||
stream << "client destroyed: " << m_imp->m_client_removes << std::endl ;
|
||||
s << px << "clients created: " << m_imp->m_client_adds << eol ;
|
||||
s << px << "clients destroyed: " << m_imp->m_client_removes << eol ;
|
||||
{
|
||||
for( MonitorImp::Clients::const_iterator p = m_imp->m_clients.begin() ;
|
||||
p != m_imp->m_clients.end() ; ++p )
|
||||
{
|
||||
stream
|
||||
s << px
|
||||
<< " client " << (const void *)(*p) << ": "
|
||||
<< (*p)->localAddress().second.displayString() << " -> "
|
||||
<< (*p)->peerAddress().second.displayString() << std::endl ;
|
||||
<< (*p)->peerAddress().second.displayString() << eol ;
|
||||
}
|
||||
}
|
||||
|
||||
stream << "servers created: " << m_imp->m_server_peer_adds << std::endl ;
|
||||
stream << "servers destroyed: " << m_imp->m_server_peer_removes << std::endl ;
|
||||
s << px << "servers created: " << m_imp->m_server_peer_adds << eol ;
|
||||
s << px << "servers destroyed: " << m_imp->m_server_peer_removes << eol ;
|
||||
|
||||
{
|
||||
for( MonitorImp::ServerPeers::const_iterator p = m_imp->m_server_peers.begin() ;
|
||||
p != m_imp->m_server_peers.end() ; ++p )
|
||||
{
|
||||
stream
|
||||
s << px
|
||||
<< " server " << (const void *)(*p) << ": "
|
||||
<< (*p)->localAddress().second.displayString() << " -> "
|
||||
<< (*p)->peerAddress().second.displayString() << std::endl ;
|
||||
<< (*p)->peerAddress().second.displayString() << eol ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +64,10 @@ public:
|
||||
void remove( const ServerPeer & peer ) ;
|
||||
// Removes a server peer.
|
||||
|
||||
void report( std::ostream & stream ) ;
|
||||
// Reports itself onto a stream.
|
||||
void report( std::ostream & stream ,
|
||||
const std::string & line_prefix = std::string() ,
|
||||
const std::string & eol = std::string("\n") ) ;
|
||||
// Reports itself onto a stream.
|
||||
|
||||
private:
|
||||
Monitor( const Monitor & ) ; // not implemented
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include <arpa/inet.h> // for inet_ntoa()
|
||||
typedef int SOCKET ; // used in gdescriptor.h
|
||||
#else
|
||||
#include <winsock.h>
|
||||
//#include <winsock.h> // winsock.h comes via windows.h
|
||||
typedef int socklen_t ;
|
||||
#endif
|
||||
|
||||
|
@ -37,6 +37,7 @@ GNet::ServerPeer::ServerPeer( StreamSocket * s , Address a ) :
|
||||
G_DEBUG( "GNet::ServerPeer::ctor: fd " << m_socket->asString() << ": " << m_address.displayString() ) ;
|
||||
if( Monitor::instance() ) Monitor::instance()->add(*this) ;
|
||||
m_socket->addReadHandler( *this ) ;
|
||||
m_socket->addExceptionHandler( *this ) ;
|
||||
}
|
||||
|
||||
GNet::ServerPeer::~ServerPeer()
|
||||
@ -68,15 +69,25 @@ void GNet::ServerPeer::readEvent()
|
||||
size_t buffer_size = sizeof(buffer) ;
|
||||
ssize_t rc = m_socket->read( buffer , buffer_size ) ;
|
||||
|
||||
if( rc <= 0 )
|
||||
if( rc == 0 || (rc == -1 && !m_socket->eWouldBlock()) )
|
||||
{
|
||||
doDelete() ;
|
||||
}
|
||||
else
|
||||
else if( rc != -1 )
|
||||
{
|
||||
size_t n = rc ;
|
||||
onData( buffer , n ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
; // no-op (windows)
|
||||
}
|
||||
}
|
||||
|
||||
void GNet::ServerPeer::exceptionEvent()
|
||||
{
|
||||
G_DEBUG( "GNet::Server::exceptionEvent: " << (void*)this ) ;
|
||||
doDelete() ;
|
||||
}
|
||||
|
||||
void GNet::ServerPeer::doDelete()
|
||||
|
@ -85,9 +85,9 @@ protected:
|
||||
private:
|
||||
Server( const Server & ) ; // not implemented
|
||||
void operator=( const Server & ) ; // not implemented
|
||||
virtual void readEvent() ; // see EventHandler
|
||||
virtual void writeEvent() ; // see EventHandler
|
||||
virtual void exceptionEvent() ; // see EventHandler
|
||||
virtual void readEvent() ; // from EventHandler
|
||||
virtual void writeEvent() ; // from EventHandler
|
||||
virtual void exceptionEvent() ; // from EventHandler
|
||||
|
||||
private:
|
||||
StreamSocket * m_socket ;
|
||||
@ -156,7 +156,8 @@ protected:
|
||||
// connection socket.
|
||||
|
||||
private:
|
||||
void readEvent() ;
|
||||
virtual void readEvent() ; // from EventHandler
|
||||
virtual void exceptionEvent() ; // from EventHandler
|
||||
ServerPeer( const ServerPeer & ) ; // not implemented
|
||||
void operator=( const ServerPeer & ) ; // not implemented
|
||||
|
||||
|
@ -168,9 +168,10 @@ ssize_t GNet::Socket::write( const char *buf, size_t len )
|
||||
G_DEBUG( "GNet::Socket::write: write error " << m_reason ) ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
if( nsent < len )
|
||||
else if( nsent < len )
|
||||
{
|
||||
m_reason = reason() ;
|
||||
}
|
||||
|
||||
G_DEBUG( "GNet::Socket::write: wrote " << nsent << "/" << len << " byte(s)" ) ;
|
||||
return nsent;
|
||||
@ -292,6 +293,13 @@ std::string GNet::Socket::asString() const
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
std::string GNet::Socket::reasonString() const
|
||||
{
|
||||
std::stringstream ss ;
|
||||
ss << m_reason ;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
GNet::StreamSocket::StreamSocket() :
|
||||
@ -326,7 +334,7 @@ ssize_t GNet::StreamSocket::read( char *buf , size_t len )
|
||||
if( sizeError(nread) )
|
||||
{
|
||||
m_reason = reason() ;
|
||||
G_DEBUG( "GNet::StreamSocket::read: read error " << m_reason ) ;
|
||||
G_DEBUG( "GNet::StreamSocket::read: fd " << m_socket << ": read error " << m_reason ) ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
|
@ -188,6 +188,10 @@ public:
|
||||
// Returns the socket handle as a string.
|
||||
// Only used in debugging.
|
||||
|
||||
std::string reasonString() const ;
|
||||
// Returns the failure reason as a string.
|
||||
// Only used in debugging.
|
||||
|
||||
protected:
|
||||
Socket( int domain, int type, int protocol = 0 ) ;
|
||||
// Constructor used by derived classes.
|
||||
@ -275,7 +279,11 @@ public:
|
||||
ssize_t read( char *buffer , size_t buffer_length ) ;
|
||||
// Reads from the TCP stream. Returns
|
||||
// 0 if the connection has been lost.
|
||||
// Returns -1 on error.
|
||||
// Returns -1 on error, or if there is
|
||||
// nothing to read (eWouldBlock() true).
|
||||
// Note that under Windows there can
|
||||
// be nothing to read even after receiving
|
||||
// a read event.
|
||||
|
||||
AcceptPair accept() ;
|
||||
// Accepts an incoming connection, returning
|
||||
|
@ -55,6 +55,7 @@ GNet::WinsockWindow::WinsockWindow( Winsock & ws , HINSTANCE hinstance ) :
|
||||
{
|
||||
}
|
||||
|
||||
// (wm_winsock is WM_USER -- should be called onWinsock())
|
||||
LRESULT GNet::WinsockWindow::onUser( WPARAM w , LPARAM l )
|
||||
{
|
||||
m_ws.onMessage( w , l ) ;
|
||||
@ -94,7 +95,7 @@ bool GNet::Winsock::init()
|
||||
G_WARNING( "GNet::Winsock::init: cannot create hidden window" ) ;
|
||||
return false ;
|
||||
}
|
||||
return attach( m_window->handle() , WM_USER ) ;
|
||||
return attach( m_window->handle() , GGui::Cracker::wm_winsock() ) ;
|
||||
}
|
||||
|
||||
bool GNet::Winsock::attach( HWND hwnd , unsigned msg )
|
||||
@ -176,7 +177,7 @@ void GNet::Winsock::dropException( Descriptor fd )
|
||||
namespace
|
||||
{
|
||||
const long READ_EVENTS = (FD_READ | FD_ACCEPT | FD_OOB) ;
|
||||
const long WRITE_EVENTS = (FD_WRITE | FD_CONNECT) ;
|
||||
const long WRITE_EVENTS = (FD_WRITE) ; // no need for "FD_CONNECT"
|
||||
const long EXCEPTION_EVENTS = (FD_CLOSE) ;
|
||||
} ;
|
||||
|
||||
@ -193,13 +194,13 @@ long GNet::Winsock::desiredEvents( Descriptor fd )
|
||||
long mask = 0 ;
|
||||
|
||||
if( m_read_list.contains(fd) )
|
||||
mask |= FD_READ | FD_ACCEPT | FD_OOB ;
|
||||
mask |= READ_EVENTS ;
|
||||
|
||||
if( m_write_list.contains(fd) )
|
||||
mask |= FD_WRITE | FD_CONNECT ;
|
||||
mask |= WRITE_EVENTS ;
|
||||
|
||||
if( m_exception_list.contains(fd) )
|
||||
mask |= FD_CLOSE ;
|
||||
mask |= EXCEPTION_EVENTS ;
|
||||
|
||||
return mask ;
|
||||
}
|
||||
@ -257,4 +258,3 @@ void GNet::Winsock::quit()
|
||||
GGui::Pump::quit() ;
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@ AM_INSTALL_PROGRAM_FLAGS=-s
|
||||
# change the local-state directory from .../var to .../var/spool/emailrelay
|
||||
localstatedir = ${prefix}/var/spool/emailrelay
|
||||
|
||||
EXTRA_DIST=commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico empty_file doxygen.cfg emailrelay.rc resource.h
|
||||
EXTRA_DIST=commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico icon2.ico icon3.ico empty_file doxygen.cfg emailrelay.rc resource.h
|
||||
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib -I$(top_srcdir)/src/gnet
|
||||
sbin_PROGRAMS = emailrelay
|
||||
libexec_PROGRAMS = emailrelay-poke
|
||||
|
@ -95,7 +95,7 @@ AM_INSTALL_PROGRAM_FLAGS = -s
|
||||
# change the local-state directory from .../var to .../var/spool/emailrelay
|
||||
localstatedir = ${prefix}/var/spool/emailrelay
|
||||
|
||||
EXTRA_DIST = commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico empty_file doxygen.cfg emailrelay.rc resource.h
|
||||
EXTRA_DIST = commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico icon2.ico icon3.ico empty_file doxygen.cfg emailrelay.rc resource.h
|
||||
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib -I$(top_srcdir)/src/gnet
|
||||
sbin_PROGRAMS = emailrelay
|
||||
libexec_PROGRAMS = emailrelay-poke
|
||||
@ -358,11 +358,11 @@ gfilestore.o: gfilestore.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../src/gnet/gnet.h ../../src/glib/glog.h gfilestore.h \
|
||||
gmessagestore.h gnewmessage.h gstoredmessage.h \
|
||||
../../src/glib/gstrings.h ../../src/glib/gpath.h \
|
||||
../../src/glib/gexception.h gnewfile.h gstoredfile.h \
|
||||
../../src/glib/gprocess.h ../../src/glib/gdirectory.h \
|
||||
../../src/glib/gmemory.h ../../src/glib/gfile.h \
|
||||
../../src/glib/gstr.h ../../src/glib/gassert.h \
|
||||
../../src/glib/glogoutput.h
|
||||
../../src/glib/gexception.h ../../src/glib/gdatetime.h \
|
||||
gnewfile.h gstoredfile.h ../../src/glib/gprocess.h \
|
||||
../../src/glib/gdirectory.h ../../src/glib/gmemory.h \
|
||||
../../src/glib/gfile.h ../../src/glib/gstr.h \
|
||||
../../src/glib/gassert.h ../../src/glib/glogoutput.h
|
||||
gmessagestore.o: gmessagestore.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
|
||||
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
|
||||
@ -383,7 +383,8 @@ gnewfile.o: gnewfile.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../src/gnet/gnet.h ../../src/glib/glog.h gmessagestore.h \
|
||||
gnewmessage.h gstoredmessage.h ../../src/glib/gstrings.h \
|
||||
../../src/glib/gpath.h ../../src/glib/gexception.h gnewfile.h \
|
||||
gfilestore.h ../../src/glib/gmemory.h ../../src/glib/gprocess.h \
|
||||
gfilestore.h ../../src/glib/gdatetime.h \
|
||||
../../src/glib/gmemory.h ../../src/glib/gprocess.h \
|
||||
../../src/glib/gfile.h ../../src/glib/gassert.h \
|
||||
../../src/glib/glogoutput.h
|
||||
gnewmessage.o: gnewmessage.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
@ -469,8 +470,8 @@ gstoredfile.o: gstoredfile.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../src/gnet/gnet.h ../../src/glib/glog.h gfilestore.h \
|
||||
gmessagestore.h gnewmessage.h gstoredmessage.h \
|
||||
../../src/glib/gstrings.h ../../src/glib/gpath.h \
|
||||
../../src/glib/gexception.h gstoredfile.h \
|
||||
../../src/glib/gmemory.h ../../src/glib/gfile.h \
|
||||
../../src/glib/gexception.h ../../src/glib/gdatetime.h \
|
||||
gstoredfile.h ../../src/glib/gmemory.h ../../src/glib/gfile.h \
|
||||
../../src/glib/gstr.h ../../src/glib/gassert.h \
|
||||
../../src/glib/glogoutput.h
|
||||
gstoredmessage.o: gstoredmessage.cpp ../../src/glib/gdef.h \
|
||||
@ -495,7 +496,10 @@ main_unix.o: main_unix.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../src/glib/ggetopt.h ../../src/glib/gexception.h \
|
||||
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \
|
||||
../../src/glib/gdaemon.h gmessagestore.h gnewmessage.h \
|
||||
gstoredmessage.h
|
||||
gstoredmessage.h gsmtpclient.h ../../src/gnet/glinebuffer.h \
|
||||
../../src/gnet/gclient.h ../../src/gnet/gaddress.h \
|
||||
../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \
|
||||
gclientprotocol.h
|
||||
poke.o: poke.c
|
||||
run.o: run.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
|
||||
@ -506,15 +510,16 @@ run.o: run.cpp ../../src/glib/gdef.h ../../config.h \
|
||||
../../src/glib/ggetopt.h ../../src/glib/gexception.h \
|
||||
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \
|
||||
../../src/glib/gdaemon.h gmessagestore.h gnewmessage.h \
|
||||
gstoredmessage.h gsmtpserver.h ../../src/gnet/gserver.h \
|
||||
../../src/gnet/gsocket.h ../../src/gnet/gaddress.h \
|
||||
../../src/gnet/gconnection.h ../../src/gnet/gselect.h \
|
||||
../../src/gnet/glinebuffer.h gverifier.h gserverprotocol.h \
|
||||
gprotocolmessage.h gsmtpclient.h ../../src/gnet/gclient.h \
|
||||
gclientprotocol.h gfilestore.h gnewfile.h gadminserver.h \
|
||||
../../src/gnet/gmonitor.h ../../src/glib/gprocess.h \
|
||||
../../src/glib/gmemory.h ../../src/glib/gdebug.h \
|
||||
../../src/glib/glogoutput.h ../../src/glib/gassert.h
|
||||
gstoredmessage.h gsmtpclient.h ../../src/gnet/glinebuffer.h \
|
||||
../../src/gnet/gclient.h ../../src/gnet/gaddress.h \
|
||||
../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \
|
||||
gclientprotocol.h gsmtpserver.h ../../src/gnet/gserver.h \
|
||||
../../src/gnet/gselect.h gverifier.h gserverprotocol.h \
|
||||
gprotocolmessage.h gfilestore.h ../../src/glib/gdatetime.h \
|
||||
gnewfile.h gadminserver.h ../../src/gnet/gmonitor.h \
|
||||
../../src/glib/gprocess.h ../../src/glib/gmemory.h \
|
||||
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
|
||||
../../src/glib/gassert.h
|
||||
|
||||
info-am:
|
||||
info: info-am
|
||||
|
@ -35,20 +35,16 @@ std::string Main::CommandLine::switchSpec()
|
||||
std::string dir = GSmtp::MessageStore::defaultDirectory().str() ;
|
||||
std::stringstream ss ;
|
||||
ss
|
||||
<< osSwitchSpec() << "|"
|
||||
<< "y!as-proxy!equivalent to \"--log --close-stderr --immediate --forward-to\"!1!host:port|"
|
||||
<< "e!close-stderr!closes the standard error stream after start-up!0!|"
|
||||
<< "a!admin!enables the administration interface and specifies its listening port number!1!admin-port|"
|
||||
<< "q!as-client!equivalent to \"--no-syslog --no-daemon --log --dont-serve --forward --forward-to\"!" << "1!host:port|"
|
||||
<< "y!as-proxy!equivalent to \"--close-stderr --log --immediate --forward-to\"!1!host:port|"
|
||||
<< "d!as-server!equivalent to \"--close-stderr --log\"!0!|"
|
||||
<< "e!close-stderr!closes the standard error stream when daemonising!0!|"
|
||||
<< "x!dont-serve!stops the process acting as a server (usually used with --forward)!0!|"
|
||||
<< "z!filter!defines a mail pre-processor (disallowed if running as root)!1!program|"
|
||||
<< "f!forward!forwards stored mail on startup (requires --forward-to)!0!|"
|
||||
<< "o!forward-to!specifies the remote smtp server (required by --forward and --admin)!1!host:port|"
|
||||
<< "h!help!displays help text and exits!0!|"
|
||||
<< "m!immediate!forwards each message as soon as it is received (requires --forward-to)!0!|"
|
||||
<< "l!log!writes log information on standard error (if open) and syslog (if not disabled)!0!|"
|
||||
<< "t!no-daemon!does not detach from the terminal!0!|"
|
||||
<< "n!no-syslog!disables syslog output!0!|"
|
||||
<< "i!pid-file!records the daemon process-id in the given file!1!pid-file|"
|
||||
<< "p!port!specifies the smtp listening port number!1!port|"
|
||||
<< "r!remote-clients!allows remote clients to connect!0!|"
|
||||
@ -109,7 +105,7 @@ std::string Main::CommandLine::semanticError() const
|
||||
if( cfg().daemon() && cfg().spoolDir().isRelative() )
|
||||
{
|
||||
return "in daemon mode the spool-dir must "
|
||||
"be an absolute path (starting with /)" ;
|
||||
"be an absolute path" ;
|
||||
}
|
||||
|
||||
if( !m_getopt.contains("forward-to") && (
|
||||
@ -207,17 +203,31 @@ void Main::CommandLine::showBanner( bool e ) const
|
||||
void Main::CommandLine::showCopyright( bool e ) const
|
||||
{
|
||||
Show show( e ) ;
|
||||
show.s() << "Copyright (C) 2001 Graeme Walker" << std::endl ;
|
||||
show.s() << copyright() << std::endl ;
|
||||
}
|
||||
|
||||
//static
|
||||
std::string Main::CommandLine::copyright()
|
||||
{
|
||||
return "Copyright (C) 2001 Graeme Walker" ;
|
||||
}
|
||||
|
||||
void Main::CommandLine::showWarranty( bool e ) const
|
||||
{
|
||||
Show show( e ) ;
|
||||
show.s()
|
||||
<< "This software is provided without warranty of any kind." << std::endl
|
||||
<< "You may redistribure copies of this program under " << std::endl
|
||||
<< "the terms of the GNU General Public License." << std::endl
|
||||
<< "For more information refer to the file named COPYING." << std::endl ;
|
||||
show.s() << warranty() ;
|
||||
}
|
||||
|
||||
//static
|
||||
std::string Main::CommandLine::warranty( const std::string & eol )
|
||||
{
|
||||
std::stringstream ss ;
|
||||
ss
|
||||
<< "This software is provided without warranty of any kind." << eol
|
||||
<< "You may redistribure copies of this program under " << eol
|
||||
<< "the terms of the GNU General Public License." << eol
|
||||
<< "For more information refer to the file named COPYING." << eol ;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
void Main::CommandLine::showVersion( bool e ) const
|
||||
|
@ -92,11 +92,18 @@ public:
|
||||
void showCopyright( bool error_stream = false ) const ;
|
||||
// Writes a copyright message.
|
||||
|
||||
static std::string warranty( const std::string & eol = std::string("\n") ) ;
|
||||
// Returns the warranty text.
|
||||
|
||||
static std::string copyright() ;
|
||||
// Returns the copyright text.
|
||||
|
||||
private:
|
||||
void showWarranty( bool error_stream ) const ;
|
||||
void showShortHelp( bool error_stream ) const ;
|
||||
std::string semanticError() const ;
|
||||
static std::string switchSpec() ;
|
||||
static std::string osSwitchSpec() ; // o/s-specific
|
||||
unsigned int ttyColumns() const ; // o/s-specific
|
||||
void showExtraHelp( bool error_stream ) const ;
|
||||
|
||||
|
33
src/main/commandline_unix.cpp
Executable file → Normal file
33
src/main/commandline_unix.cpp
Executable file → Normal file
@ -1,4 +1,23 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// commandline_unix.cpp
|
||||
//
|
||||
|
||||
@ -10,6 +29,20 @@
|
||||
|
||||
Main::CommandLine::Show * Main::CommandLine::Show::m_this = NULL ;
|
||||
|
||||
//static
|
||||
std::string Main::CommandLine::osSwitchSpec()
|
||||
{
|
||||
std::stringstream ss ;
|
||||
ss
|
||||
<< "l!log!writes log information on standard error (if open) and syslog (if not disabled)!0!|"
|
||||
<< "t!no-daemon!does not detach from the terminal!0!|"
|
||||
<< "n!no-syslog!disables syslog output!0!|"
|
||||
<< "q!as-client!equivalent to \"--log --no-syslog --no-daemon --dont-serve --forward --forward-to\"!" << "1!host:port|"
|
||||
<< "d!as-server!equivalent to \"--log --close-stderr\"!0!"
|
||||
;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
Main::CommandLine::Show::Show( bool e ) :
|
||||
m_e(e)
|
||||
{
|
||||
|
@ -27,6 +27,25 @@
|
||||
|
||||
Main::CommandLine::Show * Main::CommandLine::Show::m_this = NULL ;
|
||||
|
||||
//static
|
||||
std::string Main::CommandLine::osSwitchSpec()
|
||||
{
|
||||
// (could use empty descriptions here so that G::GetOpt does
|
||||
// not put them in the --help listing)
|
||||
|
||||
std::stringstream ss ;
|
||||
ss
|
||||
<< "l!log!writes log information on standard error (if open)!0!|"
|
||||
<< "t!no-daemon!use an ordinary window, not the system tray!0!|"
|
||||
<< "n!no-syslog!has no effect on windows!0!|"
|
||||
<< "q!as-client!equivalent to \"--log --no-daemon --dont-serve --forward --forward-to\"!" << "1!host:port|"
|
||||
<< "d!as-server!equivalent to \"--log --close-stderr\" (has little effect on windows)!0!|"
|
||||
<< "I!icon!chooses the application icon!1!icon index {0,1,2}"
|
||||
|
||||
;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
Main::CommandLine::Show::Show( bool )
|
||||
{
|
||||
if( m_this == NULL )
|
||||
@ -54,3 +73,4 @@ unsigned int Main::CommandLine::ttyColumns() const
|
||||
return 120U ;
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,12 +28,41 @@
|
||||
#include "gmessagestore.h"
|
||||
#include "gstr.h"
|
||||
#include "gdebug.h"
|
||||
#include <sstream>
|
||||
|
||||
Main::Configuration::Configuration( const CommandLine & cl ) :
|
||||
m_cl(cl)
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
std::string Main::Configuration::yn( bool b )
|
||||
{
|
||||
return b ? std::string("yes") : std::string("no") ;
|
||||
}
|
||||
|
||||
std::string Main::Configuration::str( const std::string & p , const std::string & eol ) const
|
||||
{
|
||||
const std::string na( "n/a" ) ;
|
||||
std::stringstream ss ;
|
||||
ss
|
||||
<< p << "listening port: " << (doServing()?G::Str::fromUInt(port()):na) << eol
|
||||
<< p << "downstream server address: " << (doForwarding()?serverAddress():na) << eol
|
||||
<< p << "spool directory: " << spoolDir() << eol
|
||||
<< p << "immediate forwarding? " << yn(immediate()) << eol
|
||||
<< p << "pre-processor: " << (useFilter()?filter():na) << eol
|
||||
<< p << "admin port: " << (doAdmin()?G::Str::fromUInt(adminPort()):na) << eol
|
||||
<< p << "run as daemon? " << yn(daemon()) << eol
|
||||
<< p << "log to stderr/syslog? " << yn(log()) << eol
|
||||
<< p << "verbose logging? " << yn(verbose()) << eol
|
||||
//<< p << "use syslog? " << yn(syslog()) << eol
|
||||
<< p << "close stderr? " << yn(closeStderr()) << eol
|
||||
<< p << "allow remote clients? " << yn(allowRemoteClients()) << eol
|
||||
<< p << "pid file: " << (usePidFile()?pidFile():na) << eol
|
||||
;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
bool Main::Configuration::log() const
|
||||
{
|
||||
return
|
||||
@ -142,3 +171,8 @@ std::string Main::Configuration::filter() const
|
||||
return m_cl.value("filter") ;
|
||||
}
|
||||
|
||||
unsigned int Main::Configuration::icon() const
|
||||
{
|
||||
return m_cl.contains("icon") ? G::Str::toUInt(m_cl.value("icon")) : 0U ;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,10 @@ public:
|
||||
explicit Configuration( const CommandLine & cl ) ;
|
||||
// Constructor. The reference is kept.
|
||||
|
||||
std::string str( const std::string & line_prefix = std::string() , const std::string & eol = std::string("\n") ) const ;
|
||||
// Reports the configuration in a multi-line
|
||||
// string.
|
||||
|
||||
unsigned int port() const ;
|
||||
// Returns the main port number.
|
||||
|
||||
@ -102,8 +106,14 @@ public:
|
||||
std::string filter() const ;
|
||||
// Returns the pre-processor's path.
|
||||
|
||||
unsigned int icon() const ;
|
||||
// Returns the icon selector.
|
||||
|
||||
private:
|
||||
const CommandLine & m_cl ;
|
||||
|
||||
private:
|
||||
static std::string yn( bool ) ;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -3,7 +3,7 @@
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = E-MailRelay
|
||||
PROJECT_NUMBER = 0.9.4
|
||||
PROJECT_NUMBER = 0.9.5
|
||||
OUTPUT_DIRECTORY =
|
||||
OUTPUT_LANGUAGE = English
|
||||
EXTRACT_ALL = YES
|
||||
|
@ -143,10 +143,18 @@ SOURCE=..\..\src\gnet\gconnection.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\win32\gcontrol.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\win32\gcracker.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\glib\gdaemon.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\glib\gdaemon_win32.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -167,6 +175,10 @@ SOURCE=..\..\src\gnet\gdescriptor_win32.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\win32\gdialog.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\glib\gdirectory.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -275,7 +287,7 @@ SOURCE=..\win32\gpump.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\win32\gpump_nodialog.cpp
|
||||
SOURCE=..\win32\gpump_dialog.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -295,6 +307,10 @@ SOURCE=..\..\src\gnet\gresolve_win32.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\win32\gscmap.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\gnet\gserver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -335,6 +351,10 @@ SOURCE=..\..\src\glib\gtime.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\win32\gtray.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gverifier.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -1,6 +1,16 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include <windows.h>
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.K.) resources
|
||||
|
||||
@ -18,6 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON DISCARDABLE "icon-32.ico"
|
||||
IDI_ICON2 ICON DISCARDABLE "icon2.ico"
|
||||
IDI_ICON3 ICON DISCARDABLE "icon3.ico"
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -32,7 +44,7 @@ END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\0"
|
||||
"#include <windows.h>\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
@ -44,17 +56,34 @@ END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
|
||||
IDR_MENU1 MENU DISCARDABLE
|
||||
BEGIN
|
||||
POPUP "popup"
|
||||
BEGIN
|
||||
MENUITEM "&Open", IDM_OPEN
|
||||
MENUITEM "&Close", IDM_CLOSE
|
||||
MENUITEM "&Quit", IDM_QUIT
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 72, 62
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Dialog"
|
||||
IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 259, 190
|
||||
STYLE WS_CHILD
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
ICON "",IDC_STATIC,24,19,21,20
|
||||
DEFPUSHBUTTON "OK",IDOK,105,169,50,14
|
||||
EDITTEXT IDC_EDIT1,7,7,245,153,ES_MULTILINE | ES_READONLY |
|
||||
WS_VSCROLL
|
||||
END
|
||||
|
||||
|
||||
@ -69,9 +98,9 @@ BEGIN
|
||||
IDD_DIALOG1, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 65
|
||||
RIGHTMARGIN, 252
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 55
|
||||
BOTTOMMARGIN, 183
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
@ -163,7 +163,7 @@ void GSmtp::AdminPeer::info()
|
||||
std::stringstream ss ;
|
||||
if( GNet::Monitor::instance() )
|
||||
{
|
||||
GNet::Monitor::instance()->report( ss ) ;
|
||||
GNet::Monitor::instance()->report( ss , "" , crlf() ) ;
|
||||
send( ss.str() ) ;
|
||||
}
|
||||
else
|
||||
|
@ -237,6 +237,7 @@ void GSmtp::ClientProtocol::applyEvent( const Reply & reply )
|
||||
|
||||
void GSmtp::ClientProtocol::doCallback( bool ok , const std::string & reason )
|
||||
{
|
||||
m_content <<= 0 ;
|
||||
if( m_callback )
|
||||
{
|
||||
Callback * cb = m_callback ;
|
||||
|
@ -96,6 +96,7 @@ GSmtp::FileStore::FileStore( const G::Path & dir , bool optimise ) :
|
||||
m_optimise(optimise) ,
|
||||
m_empty(false)
|
||||
{
|
||||
m_pid_modifier = static_cast<unsigned long>(G::DateTime::now()) % 1000000UL ;
|
||||
checkPath( dir ) ;
|
||||
}
|
||||
|
||||
@ -154,7 +155,7 @@ G::Path GSmtp::FileStore::envelopeWorkingPath( unsigned long seq ) const
|
||||
std::string GSmtp::FileStore::filePrefix( unsigned long seq ) const
|
||||
{
|
||||
std::stringstream ss ;
|
||||
ss << "emailrelay." << G::Process::Id() << "." << seq ;
|
||||
ss << "emailrelay." << G::Process::Id() << "." << m_pid_modifier << "." << seq ;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "gdef.h"
|
||||
#include "gsmtp.h"
|
||||
#include "gmessagestore.h"
|
||||
#include "gdatetime.h"
|
||||
#include "gexception.h"
|
||||
#include "gpath.h"
|
||||
#include <memory>
|
||||
@ -110,6 +111,7 @@ private:
|
||||
G::Path m_dir ;
|
||||
bool m_optimise ;
|
||||
bool m_empty ; // mutable
|
||||
unsigned long m_pid_modifier ;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -196,8 +196,8 @@ void GSmtp::StoredFile::fail( const std::string & reason )
|
||||
// write the reason into the file
|
||||
{
|
||||
std::ofstream file( m_envelope_path.str().c_str() ,
|
||||
std::ios_base::binary | std::ios_base::ate ) ;
|
||||
file << FileStore::x() << "Reason: " << reason ;
|
||||
std::ios_base::binary | std::ios_base::app ) ; // app not ate for win32
|
||||
file << FileStore::x() << "Reason: " << reason << crlf() ;
|
||||
}
|
||||
|
||||
G::Path env_temp( m_envelope_path ) ; // "foo.envelope.busy"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
BIN
src/main/icon2.ico
Normal file
BIN
src/main/icon2.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 766 B |
BIN
src/main/icon3.ico
Normal file
BIN
src/main/icon3.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 766 B |
@ -24,74 +24,323 @@
|
||||
#include "gdef.h"
|
||||
#include "gsmtp.h"
|
||||
#include "run.h"
|
||||
#include "gappbase.h"
|
||||
#include "gexception.h"
|
||||
#include "configuration.h"
|
||||
#include "commandline.h"
|
||||
#include "resource.h"
|
||||
#include "gtray.h"
|
||||
#include "gappbase.h"
|
||||
#include "gdialog.h"
|
||||
#include "gcontrol.h"
|
||||
#include "gmonitor.h"
|
||||
#include "gpump.h"
|
||||
#include "gstr.h"
|
||||
#include "gexception.h"
|
||||
#include "gmemory.h"
|
||||
#include "glog.h"
|
||||
#include "glogoutput.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
class App : public GGui::ApplicationBase
|
||||
class Callback
|
||||
{
|
||||
public: virtual void callback() = 0 ;
|
||||
} ;
|
||||
class Form : public GGui::Dialog
|
||||
{
|
||||
public:
|
||||
Form( GGui::ApplicationBase & , Callback & , const Main::Configuration & cfg ) ;
|
||||
void close() ;
|
||||
void set( const std::string & text ) ;
|
||||
private:
|
||||
virtual bool onInit() ;
|
||||
virtual void onNcDestroy() ;
|
||||
virtual void onClose() ;
|
||||
private:
|
||||
Callback & m_callback ;
|
||||
GGui::EditBox m_edit_box ;
|
||||
Main::Configuration m_cfg ;
|
||||
} ;
|
||||
class App : public GGui::ApplicationBase , public Callback
|
||||
{
|
||||
public:
|
||||
G_EXCEPTION( Error , "application error" ) ;
|
||||
App( HINSTANCE h , HINSTANCE p , const char * name ) ;
|
||||
void onPaint( HDC hdc ) ;
|
||||
bool onCreate() ;
|
||||
DWORD windowStyle() const ;
|
||||
void init( const Main::Configuration & cfg ) ;
|
||||
private:
|
||||
void doOpen() ;
|
||||
void doClose() ;
|
||||
void doQuit() ;
|
||||
void hide() ;
|
||||
virtual UINT resource() const ;
|
||||
virtual DWORD windowStyle() const ;
|
||||
virtual bool onCreate() ;
|
||||
virtual bool onClose() ;
|
||||
virtual void onTrayDoubleClick() ;
|
||||
virtual void onTrayRightMouseButtonDown() ;
|
||||
virtual void callback() ;
|
||||
virtual void onDimension( int & , int & ) ;
|
||||
virtual bool onSysCommand( SysCommand ) ;
|
||||
private:
|
||||
std::auto_ptr<GGui::Tray> m_tray ;
|
||||
std::auto_ptr<Form> m_form ;
|
||||
std::auto_ptr<Main::Configuration> m_cfg ;
|
||||
bool m_quit ;
|
||||
bool m_use_tray ;
|
||||
unsigned int m_icon ;
|
||||
} ;
|
||||
class Menu
|
||||
{
|
||||
G_EXCEPTION( Error , "menu error" ) ;
|
||||
public: explicit Menu( unsigned int resource_id ) ;
|
||||
public: ~Menu() ;
|
||||
public: int popup( const GGui::WindowBase & w , int sub_pos = 0 ) ;
|
||||
private: HMENU m_hmenu ;
|
||||
private: HMENU m_hmenu_popup ;
|
||||
private: Menu( const Menu & ) ;
|
||||
private: void operator=( const Menu & ) ;
|
||||
} ;
|
||||
} ;
|
||||
|
||||
App::App( HINSTANCE h , HINSTANCE p , const char * name ) :
|
||||
GGui::ApplicationBase( h , p , name )
|
||||
// ===
|
||||
|
||||
Form::Form( GGui::ApplicationBase & app , Callback & cb , const Main::Configuration & cfg ) :
|
||||
m_callback(cb) ,
|
||||
m_cfg(cfg) ,
|
||||
GGui::Dialog(app) ,
|
||||
m_edit_box(*this,IDC_EDIT1)
|
||||
{
|
||||
}
|
||||
|
||||
bool Form::onInit()
|
||||
{
|
||||
const std::string crlf( "\r\n" ) ;
|
||||
|
||||
std::stringstream ss ;
|
||||
ss
|
||||
<< "E-MailRelay V" << Main::Run::versionNumber() << crlf << crlf
|
||||
<< "Configuration..." << crlf
|
||||
<< m_cfg.str("* ",crlf)
|
||||
;
|
||||
|
||||
if( GNet::Monitor::instance() )
|
||||
{
|
||||
ss << crlf << "Network connections..." << crlf ;
|
||||
GNet::Monitor::instance()->report( ss , "* " , crlf ) ;
|
||||
}
|
||||
|
||||
ss << crlf << Main::CommandLine::warranty(crlf) << crlf << Main::CommandLine::copyright() ;
|
||||
|
||||
m_edit_box.set( ss.str() ) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
void Form::set( const std::string & text )
|
||||
{
|
||||
m_edit_box.set( text ) ;
|
||||
}
|
||||
|
||||
void Form::onClose()
|
||||
{
|
||||
end() ;
|
||||
}
|
||||
|
||||
void Form::close()
|
||||
{
|
||||
end() ;
|
||||
}
|
||||
|
||||
void Form::onNcDestroy()
|
||||
{
|
||||
m_callback.callback() ;
|
||||
}
|
||||
|
||||
// ===
|
||||
|
||||
App::App( HINSTANCE h , HINSTANCE p , const char * name ) :
|
||||
GGui::ApplicationBase( h , p , name ) ,
|
||||
m_use_tray(false) ,
|
||||
m_quit(false) ,
|
||||
m_icon(0U)
|
||||
{
|
||||
}
|
||||
|
||||
void App::init( const Main::Configuration & cfg )
|
||||
{
|
||||
m_use_tray = cfg.daemon() ;
|
||||
m_cfg <<= new Main::Configuration(cfg) ;
|
||||
m_icon = m_cfg->icon() ;
|
||||
}
|
||||
|
||||
void App::callback()
|
||||
{
|
||||
m_form <<= 0 ;
|
||||
if( m_use_tray )
|
||||
hide() ;
|
||||
else
|
||||
close() ;
|
||||
}
|
||||
|
||||
void App::onDimension( int & dx , int & dy )
|
||||
{
|
||||
if( m_form.get() )
|
||||
{
|
||||
const bool has_menu = false ;
|
||||
GGui::Size size = m_form->externalSize() ;
|
||||
GGui::Size border = GGui::Window::borderSize(has_menu) ;
|
||||
dx = size.dx + border.dx ;
|
||||
dy = size.dy + border.dy ;
|
||||
}
|
||||
}
|
||||
|
||||
void App::hide()
|
||||
{
|
||||
show( SW_HIDE ) ;
|
||||
}
|
||||
|
||||
DWORD App::windowStyle() const
|
||||
{
|
||||
return
|
||||
( GGui::Window::windowStylePopup() & ~WS_THICKFRAME ) |
|
||||
WS_MINIMIZEBOX ;
|
||||
return GGui::Window::windowStyleMain() ;
|
||||
}
|
||||
|
||||
UINT App::resource() const
|
||||
{
|
||||
// (menu and icon resource id, but we have no menus)
|
||||
return m_icon == 1U ? IDI_ICON2 : (m_icon == 2U ? IDI_ICON3 : IDI_ICON1) ;
|
||||
}
|
||||
|
||||
bool App::onCreate()
|
||||
{
|
||||
GGui::Size size ;
|
||||
size.dx = size.dy = 100 ;
|
||||
resize( size ) ;
|
||||
if( m_use_tray )
|
||||
m_tray <<= new GGui::Tray(resource(),*this,"E-MailRelay") ;
|
||||
else
|
||||
doOpen() ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
void App::onPaint( HDC hdc )
|
||||
void App::onTrayDoubleClick()
|
||||
{
|
||||
int dx_window = internalSize().dx ;
|
||||
int dy_window = internalSize().dy ;
|
||||
int dx_icon = 32 ;
|
||||
int dy_icon = 32 ;
|
||||
|
||||
int x = dx_window > dx_icon ? ((dx_window-dx_icon)/2) : 0 ;
|
||||
int y = dy_window > dy_icon ? ((dy_window-dy_icon)/2) : 0 ;
|
||||
|
||||
::DrawIcon( hdc , x , y ,
|
||||
::LoadIcon(hinstance(),MAKEINTRESOURCE(IDI_ICON1)) ) ;
|
||||
doOpen() ;
|
||||
}
|
||||
|
||||
void App::doOpen()
|
||||
{
|
||||
if( m_form.get() == NULL )
|
||||
{
|
||||
m_form <<= new Form( *this , *this , *m_cfg.get() ) ;
|
||||
if( ! m_form->runModeless(IDD_DIALOG1) )
|
||||
throw Error( "cannot run dialog box" ) ;
|
||||
}
|
||||
resize( externalSize() ) ; // no-op in itself, but uses onDimension()
|
||||
show() ;
|
||||
}
|
||||
|
||||
void App::onTrayRightMouseButtonDown()
|
||||
{
|
||||
Menu menu( IDR_MENU1 ) ;
|
||||
int id = menu.popup( *this ) ;
|
||||
if( id == IDM_OPEN )
|
||||
doOpen() ;
|
||||
else if( id == IDM_CLOSE )
|
||||
doClose() ;
|
||||
else
|
||||
doQuit() ;
|
||||
}
|
||||
|
||||
void App::doQuit()
|
||||
{
|
||||
m_quit = true ;
|
||||
close() ;
|
||||
}
|
||||
|
||||
void App::doClose()
|
||||
{
|
||||
if( m_form.get() )
|
||||
{
|
||||
m_form->close() ;
|
||||
hide() ;
|
||||
}
|
||||
}
|
||||
|
||||
bool App::onClose()
|
||||
{
|
||||
if( m_use_tray )
|
||||
{
|
||||
if( m_quit )
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
doClose() ;
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
|
||||
bool App::onSysCommand( SysCommand sc )
|
||||
{
|
||||
if( sc == scMaximise || sc == scSize )
|
||||
return true ; // true <= processed as no-op
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
|
||||
// ===
|
||||
|
||||
Menu::Menu( unsigned int id )
|
||||
{
|
||||
HINSTANCE hinstance = GGui::ApplicationInstance::hinstance() ;
|
||||
m_hmenu = ::LoadMenu( hinstance , MAKEINTRESOURCE(id) ) ;
|
||||
if( m_hmenu == NULL )
|
||||
throw Error() ;
|
||||
}
|
||||
|
||||
int Menu::popup( const GGui::WindowBase & w , int sub_pos )
|
||||
{
|
||||
POINT p ;
|
||||
::GetCursorPos( &p ) ;
|
||||
::SetForegroundWindow( w.handle() ) ;
|
||||
m_hmenu_popup = ::GetSubMenu( m_hmenu , sub_pos ) ;
|
||||
|
||||
const int default_pos = 0 ;
|
||||
::SetMenuDefaultItem( m_hmenu_popup , default_pos , TRUE ) ;
|
||||
|
||||
BOOL rc = ::TrackPopupMenuEx( m_hmenu_popup ,
|
||||
TPM_RETURNCMD , p.x , p.y , w.handle() , NULL ) ;
|
||||
return static_cast<int>(rc) ; // !!
|
||||
}
|
||||
|
||||
Menu::~Menu()
|
||||
{
|
||||
if( m_hmenu != NULL )
|
||||
::DestroyMenu( m_hmenu ) ;
|
||||
}
|
||||
|
||||
// ===
|
||||
|
||||
int WINAPI WinMain( HINSTANCE hinstance , HINSTANCE previous ,
|
||||
LPSTR command_line , int show )
|
||||
{
|
||||
try
|
||||
{
|
||||
show = SW_MINIMIZE ;
|
||||
|
||||
G::Arg arg ;
|
||||
arg.parse( hinstance , command_line ) ;
|
||||
|
||||
App app( hinstance , previous , "E-MailRelay" ) ;
|
||||
|
||||
try
|
||||
{
|
||||
Main::Run run( arg ) ;
|
||||
G::LogOutput log( run.cfg().log() , run.cfg().verbose() ) ;
|
||||
if( run.prepare() )
|
||||
{
|
||||
app.createWindow( show ) ;
|
||||
const bool visible = ! run.cfg().daemon() ;
|
||||
app.init( run.cfg() ) ;
|
||||
app.createWindow( show , visible ) ;
|
||||
run.run() ;
|
||||
}
|
||||
}
|
||||
@ -104,6 +353,7 @@ int WINAPI WinMain( HINSTANCE hinstance , HINSTANCE previous ,
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
::MessageBeep( MB_ICONHAND ) ;
|
||||
}
|
||||
return 1 ;
|
||||
}
|
||||
|
@ -21,18 +21,26 @@
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by emailrelay.rc
|
||||
//
|
||||
#include <windows.h>
|
||||
#define IDI_ICON1 101
|
||||
#define IDD_DIALOG1 101
|
||||
#define IDR_MENU1 102
|
||||
#define IDD_DIALOG2 103
|
||||
#define IDI_ICON2 105
|
||||
#define IDI_ICON3 106
|
||||
#define IDC_EDIT1 1000
|
||||
#define IDM_OPEN 40001
|
||||
#define IDM_QUIT 40002
|
||||
#define IDM_CLOSE 40005
|
||||
#define IDC_STATIC -1
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NO_MFC 1
|
||||
#define _APS_NEXT_RESOURCE_VALUE 107
|
||||
#define _APS_NEXT_COMMAND_VALUE 40006
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "gnewfile.h"
|
||||
#include "gadminserver.h"
|
||||
#include "gmonitor.h"
|
||||
#include "gexception.h"
|
||||
#include "gprocess.h"
|
||||
#include "gmemory.h"
|
||||
#include "gdebug.h"
|
||||
@ -42,17 +43,17 @@
|
||||
//static
|
||||
std::string Main::Run::versionNumber()
|
||||
{
|
||||
return "0.9.4" ;
|
||||
return "0.9.5" ;
|
||||
}
|
||||
|
||||
Main::Run::Run( G::Arg & arg ) :
|
||||
m_cl(arg,versionNumber())
|
||||
Main::Run::Run( const G::Arg & arg ) :
|
||||
m_arg(arg)
|
||||
{
|
||||
}
|
||||
|
||||
Main::Configuration Main::Run::cfg() const
|
||||
{
|
||||
return m_cl.cfg() ;
|
||||
return cl().cfg() ;
|
||||
}
|
||||
|
||||
std::string Main::Run::smtpIdent() const
|
||||
@ -71,7 +72,7 @@ void Main::Run::closeFiles()
|
||||
|
||||
void Main::Run::closeMoreFiles()
|
||||
{
|
||||
if( cfg().daemon() && cfg().closeStderr() )
|
||||
if( cfg().closeStderr() ) // was "daemon && close-stderr", but too confusing
|
||||
G::Process::closeStderr() ;
|
||||
}
|
||||
|
||||
@ -79,25 +80,25 @@ bool Main::Run::prepare()
|
||||
{
|
||||
bool do_run = false ;
|
||||
|
||||
if( m_cl.contains("help") )
|
||||
if( cl().contains("help") )
|
||||
{
|
||||
m_cl.showHelp( false ) ;
|
||||
cl().showHelp( false ) ;
|
||||
}
|
||||
else if( m_cl.hasUsageErrors() )
|
||||
else if( cl().hasUsageErrors() )
|
||||
{
|
||||
m_cl.showUsageErrors( true ) ;
|
||||
cl().showUsageErrors( true ) ;
|
||||
}
|
||||
else if( m_cl.contains("version") )
|
||||
else if( cl().contains("version") )
|
||||
{
|
||||
m_cl.showVersion( false ) ;
|
||||
cl().showVersion( false ) ;
|
||||
}
|
||||
else if( m_cl.argc() > 1U )
|
||||
else if( cl().argc() > 1U )
|
||||
{
|
||||
m_cl.showArgcError( true ) ;
|
||||
cl().showArgcError( true ) ;
|
||||
}
|
||||
else if( m_cl.hasSemanticError() )
|
||||
else if( cl().hasSemanticError() )
|
||||
{
|
||||
m_cl.showSemanticError( true ) ;
|
||||
cl().showSemanticError( true ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -148,7 +149,7 @@ void Main::Run::run()
|
||||
if( cfg().doForwarding() )
|
||||
{
|
||||
if( store.empty() )
|
||||
m_cl.showNoop( true ) ;
|
||||
cl().showNoop( true ) ;
|
||||
else
|
||||
doForwarding( store , *event_loop.get() ) ;
|
||||
}
|
||||
@ -176,8 +177,8 @@ void Main::Run::doServing( G::Daemon::PidFile & pid_file ,
|
||||
}
|
||||
|
||||
pid_file.commit() ;
|
||||
closeMoreFiles() ;
|
||||
|
||||
closeMoreFiles() ;
|
||||
event_loop.run() ;
|
||||
}
|
||||
|
||||
@ -185,11 +186,29 @@ void Main::Run::doForwarding( GSmtp::MessageStore & store ,
|
||||
GNet::EventSources & event_loop )
|
||||
{
|
||||
const bool quit_on_disconnect = true ;
|
||||
GSmtp::Client client( store , quit_on_disconnect ) ;
|
||||
GSmtp::Client client( store , *this , quit_on_disconnect ) ;
|
||||
std::string error = client.init( cfg().serverAddress() ) ;
|
||||
if( error.length() )
|
||||
throw G::Exception( error + ": " + cfg().serverAddress() ) ;
|
||||
|
||||
closeMoreFiles() ;
|
||||
event_loop.run() ;
|
||||
}
|
||||
|
||||
const Main::CommandLine & Main::Run::cl() const
|
||||
{
|
||||
// lazy evaluation so that the constructor does not throw
|
||||
if( m_cl.get() == NULL )
|
||||
{
|
||||
const_cast<Run*>(this)->m_cl <<= new CommandLine( m_arg , versionNumber() ) ;
|
||||
}
|
||||
return *m_cl.get() ;
|
||||
}
|
||||
|
||||
void Main::Run::clientDone( std::string reason )
|
||||
{
|
||||
G_DEBUG( "Main::Run::clientDone: \"" << reason << "\"" ) ;
|
||||
if( ! reason.empty() )
|
||||
throw G::Exception( reason ) ;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,10 @@
|
||||
#include "gdaemon.h"
|
||||
#include "garg.h"
|
||||
#include "gmessagestore.h"
|
||||
#include "gsmtpclient.h"
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
|
||||
namespace Main
|
||||
{
|
||||
@ -52,10 +54,10 @@ namespace Main
|
||||
/// return 0 ;
|
||||
/// }
|
||||
//
|
||||
class Main::Run
|
||||
class Main::Run : private GSmtp::Client::ClientCallback
|
||||
{
|
||||
public:
|
||||
explicit Run( G::Arg & arg ) ;
|
||||
explicit Run( const G::Arg & arg ) ;
|
||||
// Constructor.
|
||||
|
||||
bool prepare() ;
|
||||
@ -66,8 +68,13 @@ public:
|
||||
// Runs the application.
|
||||
// Precondition: prepare() returned true
|
||||
|
||||
private:
|
||||
Configuration cfg() const ;
|
||||
// Returns a configuration object.
|
||||
|
||||
static std::string versionNumber() ;
|
||||
// Returns the application version number string.
|
||||
|
||||
private:
|
||||
void runCore() ;
|
||||
void doForwarding( GSmtp::MessageStore & , GNet::EventSources & ) ;
|
||||
void doServing( G::Daemon::PidFile & , GNet::EventSources & ) ;
|
||||
@ -75,10 +82,12 @@ private:
|
||||
void closeMoreFiles() ;
|
||||
std::string smtpIdent() const ;
|
||||
void recordPid() ;
|
||||
Configuration cfg() const ;
|
||||
const CommandLine & cl() const ;
|
||||
virtual void clientDone( std::string ) ;
|
||||
|
||||
private:
|
||||
CommandLine m_cl ;
|
||||
std::auto_ptr<CommandLine> m_cl ;
|
||||
G::Arg m_arg ;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -25,10 +25,18 @@ EXTRA_DIST = \
|
||||
gappbase.h \
|
||||
gcracker.cpp \
|
||||
gcracker.h \
|
||||
gdialog.cpp \
|
||||
gdialog.h \
|
||||
gcontrol.cpp \
|
||||
gcontrol.h \
|
||||
gpump.cpp \
|
||||
gpump.h \
|
||||
gpump_nodialog.cpp \
|
||||
gpump_dialog.cpp \
|
||||
gscmap.h \
|
||||
gscmap.cpp \
|
||||
gsize.h \
|
||||
gtray.h \
|
||||
gtray.cpp \
|
||||
gwinbase.cpp \
|
||||
gwinbase.h \
|
||||
gwindow.cpp \
|
||||
|
@ -89,7 +89,7 @@ PACKAGE = @PACKAGE@
|
||||
RANLIB = @RANLIB@
|
||||
VERSION = @VERSION@
|
||||
|
||||
EXTRA_DIST = gappinst.cpp gappinst.h gappbase.cpp gappbase.h gcracker.cpp gcracker.h gpump.cpp gpump.h gpump_nodialog.cpp gsize.h gwinbase.cpp gwinbase.h gwindow.cpp gwindow.h gwinhid.cpp gwinhid.h
|
||||
EXTRA_DIST = gappinst.cpp gappinst.h gappbase.cpp gappbase.h gcracker.cpp gcracker.h gdialog.cpp gdialog.h gcontrol.cpp gcontrol.h gpump.cpp gpump.h gpump_dialog.cpp gscmap.h gscmap.cpp gsize.h gtray.h gtray.cpp gwinbase.cpp gwinbase.h gwindow.cpp gwindow.h gwinhid.cpp gwinhid.h
|
||||
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = ../../config.h
|
||||
|
@ -83,22 +83,20 @@ bool GGui::ApplicationBase::firstInstance() const
|
||||
bool GGui::ApplicationBase::initFirst()
|
||||
{
|
||||
UINT id = resource() ;
|
||||
|
||||
G_DEBUG( "GGui::ApplicationBase::initFirst: loading main icon: id " << id ) ;
|
||||
|
||||
HICON icon = id ? ::LoadIcon(hinstance(),MAKEINTRESOURCE(resource())) : 0 ;
|
||||
HICON icon = id ? ::LoadIcon(hinstance(),MAKEINTRESOURCE(id)) : 0 ;
|
||||
|
||||
G_DEBUG( "GGui::ApplicationBase::initFirst: "
|
||||
<< "registering main window class \"" << className()
|
||||
<< "\", hinstance " << hinstance() ) ;
|
||||
|
||||
const char * menu = MAKEINTRESOURCE( id ) ;
|
||||
return registerWindowClass( className() ,
|
||||
hinstance() ,
|
||||
classStyle() ,
|
||||
icon ? icon : GGui::Window::classIcon() ,
|
||||
GGui::Window::classCursor() ,
|
||||
backgroundBrush() ,
|
||||
MAKEINTRESOURCE(resource()) ) ;
|
||||
menu ) ;
|
||||
}
|
||||
|
||||
void GGui::ApplicationBase::close() const
|
||||
@ -160,8 +158,11 @@ void GGui::ApplicationBase::messageBox( const std::string & message )
|
||||
if( box_parent == NULL )
|
||||
box_parent = handle() ;
|
||||
|
||||
::MessageBox( box_parent , message.c_str() , title() ,
|
||||
MB_OK | MB_ICONEXCLAMATION ) ;
|
||||
unsigned int type = MB_OK | MB_ICONEXCLAMATION ;
|
||||
if( box_parent == NULL )
|
||||
type |= ( MB_TASKMODAL | MB_SETFOREGROUND ) ;
|
||||
|
||||
::MessageBox( box_parent , message.c_str() , title() , type ) ;
|
||||
}
|
||||
|
||||
//static
|
||||
|
@ -38,16 +38,16 @@ namespace GGui
|
||||
// Description: A simple windows application class which
|
||||
// can be used for very-simple applications on its own,
|
||||
// or as a base class for the more fully-functional
|
||||
// GApplication class. It has no dependence on other
|
||||
// low-level classes such as GPath, GArg, and (depending
|
||||
// on the build) GDialog (see "gpump_nodialog.cpp").
|
||||
// GGui::Application class. It has no dependence on other
|
||||
// low-level classes such as G::Path, G::Arg, and (depending
|
||||
// on the build) GGui::Dialog (see "gpump_nodialog.cpp").
|
||||
//
|
||||
// The application object creates and manages the application's
|
||||
// main window and runs the ::GetMessage() event loop.
|
||||
//
|
||||
// GApplicationBase derives from GGui::Window allowing the user
|
||||
// to override the default message handing for the
|
||||
// main application window.
|
||||
// GGui::ApplicationBase derives from GGui::Window allowing the
|
||||
// user to override the default message handing for the main
|
||||
// application window.
|
||||
//
|
||||
// See also: Application, ApplicationInstance, Pump
|
||||
//
|
||||
@ -90,6 +90,10 @@ public:
|
||||
// Puts up a message box in the absence of a running application
|
||||
// object.
|
||||
|
||||
virtual UINT resource() const ;
|
||||
// Overridable. Defines the resource id
|
||||
// for the main window's icon and menu.
|
||||
|
||||
protected:
|
||||
bool firstInstance() const ;
|
||||
// Returns true if the constructor's 'previous'
|
||||
@ -118,10 +122,6 @@ protected:
|
||||
virtual DWORD classStyle() const ;
|
||||
// Overridable. Defines the main window class style.
|
||||
|
||||
virtual UINT resource() const ;
|
||||
// Overridable. Defines the resource id
|
||||
// for the main window's icon and menu.
|
||||
|
||||
virtual void onDestroy() ;
|
||||
// Inherited from GGui::Window. Calls PostQuitMessage()
|
||||
// so that the task terminates when its main
|
||||
|
424
src/win32/gcontrol.cpp
Normal file
424
src/win32/gcontrol.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gcontrol.cpp
|
||||
//
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gdialog.h"
|
||||
#include "gcontrol.h"
|
||||
#include "glog.h"
|
||||
#include "gassert.h"
|
||||
#include "gdebug.h"
|
||||
|
||||
#define G_DC 0 // 0 <= reduce dependencies for now
|
||||
#if G_DC
|
||||
#include "gdc.h"
|
||||
#endif
|
||||
|
||||
LRESULT CALLBACK gcontrol_wndproc_export( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam ) ;
|
||||
|
||||
GGui::Control::Control( Dialog &dialog , int id ) :
|
||||
m_dialog(dialog) ,
|
||||
m_id(id) ,
|
||||
m_valid(true) ,
|
||||
m_hwnd(0) ,
|
||||
m_no_redraw_count(0)
|
||||
{
|
||||
G_ASSERT( m_dialog.isValid() ) ;
|
||||
}
|
||||
|
||||
void GGui::Control::invalidate()
|
||||
{
|
||||
m_valid = false ;
|
||||
}
|
||||
|
||||
bool GGui::Control::valid() const
|
||||
{
|
||||
return m_valid ;
|
||||
}
|
||||
|
||||
GGui::Dialog & GGui::Control::dialog() const
|
||||
{
|
||||
G_ASSERT( m_valid ) ;
|
||||
return m_dialog ;
|
||||
}
|
||||
|
||||
int GGui::Control::id() const
|
||||
{
|
||||
return m_id ;
|
||||
}
|
||||
|
||||
LRESULT GGui::Control::sendMessage( unsigned message , WPARAM wparam , LPARAM lparam ) const
|
||||
{
|
||||
return m_dialog.sendMessage( m_id , message , wparam , lparam ) ;
|
||||
}
|
||||
|
||||
HWND GGui::Control::handle() const
|
||||
{
|
||||
if( m_hwnd == 0 )
|
||||
{
|
||||
G_ASSERT( m_dialog.isValid() ) ;
|
||||
const_cast<Control*>(this)->m_hwnd = ::GetDlgItem( m_dialog.handle() , m_id ) ;
|
||||
G_DEBUG( "GGui::Control::handle: GetDlgItem(" << m_id << ") -> " << m_hwnd ) ;
|
||||
G_ASSERT( m_hwnd != 0 ) ;
|
||||
}
|
||||
return m_hwnd ;
|
||||
}
|
||||
|
||||
GGui::Control::~Control()
|
||||
{
|
||||
G_ASSERT( m_no_redraw_count == 0 ) ;
|
||||
}
|
||||
|
||||
bool GGui::Control::subClass()
|
||||
{
|
||||
G_ASSERT( handle() != 0 ) ;
|
||||
|
||||
SubClassMap::Proc old = reinterpret_cast<SubClassMap::Proc>(
|
||||
::GetWindowLong( handle() , GWL_WNDPROC ) ) ;
|
||||
|
||||
m_dialog.map().add( handle() , old , (void*)this ) ;
|
||||
::SetWindowLong( handle() , GWL_WNDPROC,
|
||||
reinterpret_cast<DWORD>(gcontrol_wndproc_export) ) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK gcontrol_wndproc_export( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam )
|
||||
{
|
||||
// get the dialog box window handle
|
||||
HWND hwnd_dialog = ::GetParent(hwnd) ;
|
||||
if( hwnd_dialog == NULL )
|
||||
{
|
||||
G_ASSERT( false ) ;
|
||||
return ::DefWindowProc( hwnd , message , wparam , lparam ) ;
|
||||
}
|
||||
|
||||
// find the dialog box object
|
||||
GGui::Dialog *dialog = reinterpret_cast<GGui::Dialog*>( ::GetWindowLong( hwnd_dialog , DWL_USER ) ) ;
|
||||
if( dialog == NULL )
|
||||
{
|
||||
G_ASSERT( false ) ;
|
||||
return ::DefWindowProc( hwnd , message , wparam , lparam ) ;
|
||||
}
|
||||
G_ASSERT( dialog->isValid() ) ;
|
||||
|
||||
// find the control object and the super-class window procedure
|
||||
void *context = NULL ;
|
||||
GGui::SubClassMap::Proc super_class = reinterpret_cast<GGui::SubClassMap::Proc>(dialog->map().find(hwnd,&context)) ;
|
||||
GGui::Control *control = reinterpret_cast<GGui::Control*>(context) ;
|
||||
G_ASSERT( control != NULL ) ;
|
||||
G_ASSERT( control->handle() == hwnd ) ;
|
||||
G_ASSERT( control->id() == ::GetDlgCtrlID(hwnd) ) ;
|
||||
|
||||
// remove the control from the map if it is being destroyed
|
||||
if( message == WM_NCDESTROY )
|
||||
dialog->map().remove( hwnd ) ;
|
||||
|
||||
return control->wndProc( message , wparam , lparam , super_class ) ;
|
||||
}
|
||||
|
||||
LRESULT GGui::Control::wndProc( unsigned message , WPARAM wparam , LPARAM lparam , WNDPROC super_class )
|
||||
{
|
||||
bool forward = true ;
|
||||
LRESULT result = onMessage( message , wparam , lparam , super_class , forward ) ;
|
||||
|
||||
if( forward )
|
||||
return (*super_class)( handle() , message , wparam , lparam ) ;
|
||||
else
|
||||
return result ;
|
||||
}
|
||||
|
||||
LRESULT GGui::Control::onMessage( unsigned , WPARAM , LPARAM , WNDPROC , bool &forward )
|
||||
{
|
||||
forward = true ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// GGui::ListBox
|
||||
// -------------------------------------
|
||||
|
||||
GGui::ListBox::ListBox( Dialog &dialog , int id ) :
|
||||
Control(dialog,id)
|
||||
{
|
||||
}
|
||||
|
||||
GGui::ListBox::~ListBox()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::ListBox::set( const G::Strings &list ) // was putList()
|
||||
{
|
||||
if( list.size() == 0U )
|
||||
{
|
||||
sendMessage( LB_RESETCONTENT , 0 , 0 ) ;
|
||||
return ;
|
||||
}
|
||||
|
||||
// disable redrawing
|
||||
NoRedraw no_redraw( *this ) ;
|
||||
|
||||
// clear
|
||||
sendMessage( LB_RESETCONTENT , 0 , 0 ) ;
|
||||
|
||||
// add
|
||||
for( G::Strings::const_iterator string_p = list.begin() ;
|
||||
string_p != list.end() ; ++string_p )
|
||||
{
|
||||
sendMessage( LB_ADDSTRING , 0 , (LPARAM)(*string_p).c_str() ) ;
|
||||
}
|
||||
}
|
||||
|
||||
int GGui::ListBox::getSelection()
|
||||
{
|
||||
LRESULT rc = sendMessage( LB_GETCURSEL ) ;
|
||||
return rc == LB_ERR ? -1 : (int)rc ;
|
||||
}
|
||||
|
||||
void GGui::ListBox::setSelection( int index )
|
||||
{
|
||||
sendMessage( LB_SETCURSEL , (WPARAM)index ) ;
|
||||
}
|
||||
|
||||
std::string GGui::ListBox::getItem( int index ) const
|
||||
{
|
||||
G_ASSERT( index >= 0 ) ;
|
||||
|
||||
LRESULT rc = sendMessage( LB_GETTEXTLEN , (WPARAM)index ) ;
|
||||
if( rc == LB_ERR || rc > 0xfff0 )
|
||||
return std::string() ;
|
||||
|
||||
char *buffer = new char[rc+2] ;
|
||||
G_ASSERT( buffer != NULL ) ;
|
||||
if( buffer == NULL )
|
||||
return std::string() ;
|
||||
|
||||
buffer[0] = '\0' ;
|
||||
sendMessage( LB_GETTEXT , (WPARAM)index , (LPARAM)(LPCSTR)buffer ) ;
|
||||
std::string s( buffer ) ;
|
||||
delete [] buffer ;
|
||||
return s ;
|
||||
}
|
||||
|
||||
unsigned GGui::ListBox::entries() const
|
||||
{
|
||||
LRESULT entries = sendMessage( LB_GETCOUNT , 0 , 0 ) ;
|
||||
if( entries == LB_ERR )
|
||||
{
|
||||
G_DEBUG( "GGui::ListBox::entries: listbox getcount error" ) ;
|
||||
entries = 0 ;
|
||||
}
|
||||
return entries ;
|
||||
}
|
||||
|
||||
// =============
|
||||
// GGui::EditBox
|
||||
// -------------
|
||||
|
||||
GGui::EditBox::EditBox( Dialog &dialog , int id ) :
|
||||
Control( dialog , id ) ,
|
||||
m_character_height(0)
|
||||
{
|
||||
}
|
||||
|
||||
GGui::EditBox::~EditBox()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::EditBox::set( const std::string & text )
|
||||
{
|
||||
NoRedraw no_redraw( *this ) ;
|
||||
::SetWindowText( handle() , text.c_str() ) ;
|
||||
}
|
||||
|
||||
void GGui::EditBox::set( const G::Strings & list ) // was putList()
|
||||
{
|
||||
if( list.size() == 0U )
|
||||
{
|
||||
::SetWindowText( handle() , "" ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
NoRedraw no_redraw( *this ) ;
|
||||
|
||||
std::string total ;
|
||||
const char *sep = "" ;
|
||||
for( G::Strings::const_iterator iter = list.begin() ;
|
||||
iter != list.end() ; ++iter )
|
||||
{
|
||||
total.append( sep ) ;
|
||||
sep = "\x0D\x0A" ;
|
||||
total.append( *iter ) ;
|
||||
}
|
||||
|
||||
::SetWindowText( handle() , total.c_str() ) ;
|
||||
G_ASSERT( lines() >= list.size() ) ;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned GGui::EditBox::lines()
|
||||
{
|
||||
// handle an empty control since em_getlinecount returns one
|
||||
int length = ::GetWindowTextLength( handle() ) ;
|
||||
if( length == 0 )
|
||||
return 0 ;
|
||||
|
||||
LRESULT lines = sendMessage( EM_GETLINECOUNT ) ;
|
||||
G_ASSERT( lines == (LRESULT)(unsigned)lines ) ;
|
||||
G_DEBUG( "GGui::EditBox::lines: " << lines ) ;
|
||||
return lines ;
|
||||
}
|
||||
|
||||
#if G_DC
|
||||
unsigned GGui::EditBox::linesInWindow()
|
||||
{
|
||||
unsigned text_height = characterHeight() ;
|
||||
unsigned window_height = windowHeight() ;
|
||||
G_ASSERT( text_height != 0 ) ;
|
||||
unsigned result = window_height / text_height ;
|
||||
G_DEBUG( "GGui::EditBox::linesInWindow: " << result ) ;
|
||||
return result ;
|
||||
}
|
||||
#endif
|
||||
|
||||
void GGui::EditBox::scrollBack( int lines )
|
||||
{
|
||||
if( lines <= 0 )
|
||||
return ;
|
||||
|
||||
LONG dy = -lines ;
|
||||
sendMessage( EM_LINESCROLL , 0 , dy ) ;
|
||||
}
|
||||
|
||||
void GGui::EditBox::scrollToEnd()
|
||||
{
|
||||
// (add ten just to make sure)
|
||||
sendMessage( EM_LINESCROLL , 0 , lines() + 10 ) ;
|
||||
}
|
||||
|
||||
std::string GGui::EditBox::get() const
|
||||
{
|
||||
int length = ::GetWindowTextLength( handle() ) ;
|
||||
char *buffer = new char[length+2] ;
|
||||
G_ASSERT( buffer != NULL ) ;
|
||||
::GetWindowText( handle() , buffer , length+1 ) ;
|
||||
G_ASSERT( strlen(buffer) <= (unsigned)length ) ;
|
||||
std::string s( buffer ) ;
|
||||
delete [] buffer ;
|
||||
return s ;
|
||||
}
|
||||
|
||||
unsigned GGui::EditBox::scrollPosition()
|
||||
{
|
||||
unsigned position = sendMessage( EM_GETFIRSTVISIBLELINE ) ;
|
||||
G_DEBUG( "GGui::EditBox::scrollPosition: " << position ) ;
|
||||
return position ;
|
||||
}
|
||||
|
||||
unsigned GGui::EditBox::scrollRange()
|
||||
{
|
||||
unsigned range = lines() ;
|
||||
if( range <= 1 )
|
||||
range = 1 ;
|
||||
else
|
||||
range-- ;
|
||||
|
||||
//range += linesInWindow() ;
|
||||
G_DEBUG( "GGui::EditBox::scrollRange: " << range ) ;
|
||||
return range ;
|
||||
}
|
||||
|
||||
#if G_DC
|
||||
unsigned GGui::EditBox::characterHeight()
|
||||
{
|
||||
if( m_character_height == 0 )
|
||||
{
|
||||
DeviceContext dc( handle() ) ;
|
||||
TEXTMETRIC tm ;
|
||||
::GetTextMetrics( dc() , &tm ) ;
|
||||
m_character_height = (unsigned)( tm.tmHeight + tm.tmExternalLeading ) ;
|
||||
G_ASSERT( m_character_height != 0 ) ;
|
||||
}
|
||||
return m_character_height ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if G_DC
|
||||
unsigned GGui::EditBox::windowHeight()
|
||||
{
|
||||
RECT rect ;
|
||||
::GetWindowRect( handle() , &rect ) ;
|
||||
G_ASSERT( rect.bottom >= rect.top ) ;
|
||||
return (unsigned)( rect.bottom - rect.top ) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
// =====================================
|
||||
// GCheckBox
|
||||
// -------------------------------------
|
||||
|
||||
GGui::CheckBox::CheckBox( Dialog &dialog , int id ) :
|
||||
Control(dialog,id)
|
||||
{
|
||||
}
|
||||
|
||||
GGui::CheckBox::~CheckBox()
|
||||
{
|
||||
}
|
||||
|
||||
bool GGui::CheckBox::get() const
|
||||
{
|
||||
return !! ::IsDlgButtonChecked( dialog().handle() , id() ) ;
|
||||
}
|
||||
|
||||
void GGui::CheckBox::set( bool b )
|
||||
{
|
||||
::CheckDlgButton( dialog().handle() , id() , b ) ;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// GButton
|
||||
// -------------------------------------
|
||||
|
||||
GGui::Button::Button( Dialog &dialog , int id ) :
|
||||
Control(dialog,id)
|
||||
{
|
||||
}
|
||||
|
||||
GGui::Button::~Button()
|
||||
{
|
||||
}
|
||||
|
||||
bool GGui::Button::enabled() const
|
||||
{
|
||||
return !!::IsWindowEnabled( handle() ) ;
|
||||
}
|
||||
|
||||
void GGui::Button::enable( bool b )
|
||||
{
|
||||
::EnableWindow( handle() , !!b ) ;
|
||||
}
|
||||
|
||||
void GGui::Button::disable()
|
||||
{
|
||||
::EnableWindow( handle() , false ) ;
|
||||
}
|
||||
|
303
src/win32/gcontrol.h
Normal file
303
src/win32/gcontrol.h
Normal file
@ -0,0 +1,303 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gcontrol.h
|
||||
//
|
||||
|
||||
#ifndef G_CONTROL_H
|
||||
#define G_CONTROL_H
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gdialog.h"
|
||||
#include "gstrings.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace GGui
|
||||
{
|
||||
class Control ;
|
||||
class ListBox ;
|
||||
class EditBox ;
|
||||
class CheckBox ;
|
||||
class Button ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::Control
|
||||
// Description: A base class for dialog box control objects.
|
||||
// Normally a dialog box object (derived from Dialog) will
|
||||
// have Control-derived objects embedded within it to
|
||||
// represent some of the dialog box controls.
|
||||
// See also: EditBox, ListBox, CheckBox, Button
|
||||
//
|
||||
class GGui::Control
|
||||
{
|
||||
public:
|
||||
class NoRedraw
|
||||
{
|
||||
private: Control & m_control ;
|
||||
public: NoRedraw(Control&) ;
|
||||
public: ~NoRedraw() ;
|
||||
private: void operator=( const NoRedraw & ) ;
|
||||
private: NoRedraw( const NoRedraw & ) ;
|
||||
} ;
|
||||
|
||||
private:
|
||||
friend class Control::NoRedraw ;
|
||||
unsigned m_no_redraw_count ;
|
||||
bool m_valid ;
|
||||
Dialog & m_dialog ;
|
||||
int m_id ;
|
||||
HWND m_hwnd ;
|
||||
|
||||
public:
|
||||
|
||||
Control( Dialog &dialog , int id ) ;
|
||||
// Constructor. The lifetime of the Control
|
||||
// object should not exceed that of the given
|
||||
// dialog box; normally the control object
|
||||
// should be a member of the dialog object.
|
||||
|
||||
void invalidate() ;
|
||||
// Called by the Dialog class when this
|
||||
// control's dialog box object becomes invalid.
|
||||
|
||||
bool valid() const ;
|
||||
// Returns true if this control is usable.
|
||||
|
||||
Dialog & dialog() const ;
|
||||
// Returns a reference to the control's
|
||||
// dialog box.
|
||||
|
||||
int id() const ;
|
||||
// Returns the control's identifier.
|
||||
|
||||
HWND handle() const ;
|
||||
// Returns the control's window handle.
|
||||
|
||||
virtual ~Control() ;
|
||||
// Virtual destructor.
|
||||
|
||||
LRESULT sendMessage( unsigned message , WPARAM wparam = 0 , LPARAM lparam = 0 ) const ;
|
||||
// Sends a window message to this control.
|
||||
|
||||
bool subClass() ;
|
||||
// Subclasses the control so that all received messages
|
||||
// are passed to onMessage().
|
||||
|
||||
LRESULT wndProc( unsigned message , WPARAM wparam , LPARAM lparam , WNDPROC super_class ) ;
|
||||
// Not for general use. Called from the exported
|
||||
// window procedure.
|
||||
|
||||
protected:
|
||||
virtual LRESULT onMessage( unsigned message , WPARAM wparam ,
|
||||
LPARAM lparam , WNDPROC super_class , bool &forward ) ;
|
||||
// Overridable. Called on receipt of a window message
|
||||
// sent to a sub-classed control.
|
||||
//
|
||||
// If the implementation sets 'forward' true,
|
||||
// or leaves it alone, then the message is
|
||||
// passed on to the super-class handler and
|
||||
// the implementation's return value is ignored.
|
||||
// This means that an empty implementation
|
||||
// does not affect the control's behaviour.
|
||||
//
|
||||
// If the implementation handles the message
|
||||
// fully it should reset 'forward' and return
|
||||
// an appropriate value; if it does something
|
||||
// but still needs the super-class behaviour
|
||||
// then it should leave 'forward' alone.
|
||||
//
|
||||
// The 'super_class' parameter is normally only
|
||||
// needed if the super-class handler's
|
||||
// return value needs to be modified or if the
|
||||
// sub-class behaviour must be done after
|
||||
// the super-class behaviour.
|
||||
|
||||
private:
|
||||
Control( const Control & ) ;
|
||||
void operator=( const Control & ) ;
|
||||
} ;
|
||||
|
||||
inline GGui::Control::NoRedraw::NoRedraw( Control &control ) :
|
||||
m_control(control)
|
||||
{
|
||||
m_control.m_no_redraw_count++ ;
|
||||
if( m_control.m_no_redraw_count == 1 )
|
||||
m_control.sendMessage( WM_SETREDRAW , false ) ;
|
||||
}
|
||||
|
||||
inline GGui::Control::NoRedraw::~NoRedraw()
|
||||
{
|
||||
m_control.m_no_redraw_count-- ;
|
||||
if( m_control.m_no_redraw_count == 0 )
|
||||
m_control.sendMessage( WM_SETREDRAW , true ) ;
|
||||
}
|
||||
|
||||
// Class: GGui::ListBox
|
||||
// Description: A list box class.
|
||||
//
|
||||
class GGui::ListBox : public Control
|
||||
{
|
||||
public:
|
||||
ListBox( Dialog &dialog , int id ) ;
|
||||
// Constructor.
|
||||
|
||||
virtual ~ListBox() ;
|
||||
// Virtual destructor.
|
||||
|
||||
void set( const G::Strings & list ) ;
|
||||
// Puts a list of strings into the
|
||||
// given list box control.
|
||||
|
||||
int getSelection() ;
|
||||
// Returns the currently selected item
|
||||
// in a list box. Returns -1 if none.
|
||||
|
||||
void setSelection( int index ) ;
|
||||
// Sets the list box selection. For no
|
||||
// selection index should be -1.
|
||||
|
||||
std::string getItem( int index ) const ;
|
||||
// Returns the specified item in a
|
||||
// list box.
|
||||
|
||||
unsigned entries() const ;
|
||||
// Returns the number of list box entries.
|
||||
|
||||
private:
|
||||
void operator=( const ListBox & ) ;
|
||||
ListBox( const ListBox & ) ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::EditBox
|
||||
// Description: An edit box class.
|
||||
//
|
||||
class GGui::EditBox : public Control
|
||||
{
|
||||
private:
|
||||
unsigned m_character_height ;
|
||||
|
||||
public:
|
||||
EditBox( Dialog &dialog , int id ) ;
|
||||
// Constructor.
|
||||
|
||||
virtual ~EditBox() ;
|
||||
// Virtual destructor.
|
||||
|
||||
void set( const G::Strings &list ) ;
|
||||
// Puts a list of strings into the
|
||||
// given multi-line edit box control.
|
||||
// Does no scrolling.
|
||||
|
||||
void set( const std::string & string ) ;
|
||||
// Sets the text of the edit control.
|
||||
|
||||
std::string get() const ;
|
||||
// Gets the text of a single-line edit control.
|
||||
|
||||
unsigned lines() ;
|
||||
// Returns the number of lines. This will
|
||||
// in general be more than the number of
|
||||
// strings passed to set(G::Strings) because of
|
||||
// line wrapping.
|
||||
|
||||
void scrollToEnd() ;
|
||||
// Scrolls forward so that _no_ text is
|
||||
// visible. Normally used before scrollBack().
|
||||
|
||||
void scrollBack( int lines ) ;
|
||||
// Scrolls back 'lines' lines. Does nothing
|
||||
// if 'lines' is zero or negative.
|
||||
|
||||
unsigned linesInWindow() ;
|
||||
// Return the (approximate) number of lines
|
||||
// which will fit inside the edit box window.
|
||||
|
||||
unsigned scrollPosition() ;
|
||||
// Returns a value representing the vertical
|
||||
// scroll position.
|
||||
//
|
||||
// See also SBM_SETPOS.
|
||||
|
||||
unsigned scrollRange() ;
|
||||
// Returns a value representing the vertical
|
||||
// scroll range. This is similar to lines(),
|
||||
// but it is never zero.
|
||||
//
|
||||
// See also SBM_SETRANGE.
|
||||
|
||||
private:
|
||||
unsigned windowHeight() /*not const*/ ;
|
||||
unsigned characterHeight() /*not const*/ ;
|
||||
EditBox( const EditBox & ) ;
|
||||
void operator=( const EditBox & ) ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::CheckBox
|
||||
// Description: A check box class.
|
||||
//
|
||||
class GGui::CheckBox : public Control
|
||||
{
|
||||
public:
|
||||
CheckBox( Dialog &dialog , int id ) ;
|
||||
// Constructor.
|
||||
|
||||
virtual ~CheckBox() ;
|
||||
// Virtual destructor.
|
||||
|
||||
bool get() const ;
|
||||
// Returns the state of a boolean check box.
|
||||
|
||||
void set( bool b ) ;
|
||||
// Sets the state of a boolean check box.
|
||||
|
||||
private:
|
||||
void operator=( const CheckBox ) ;
|
||||
CheckBox( const CheckBox & ) ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::Button
|
||||
// Description: A button class.
|
||||
//
|
||||
class GGui::Button : public Control
|
||||
{
|
||||
public:
|
||||
Button( Dialog &dialog , int id ) ;
|
||||
// Constructor.
|
||||
|
||||
virtual ~Button() ;
|
||||
// Virtual destructor.
|
||||
|
||||
bool enabled() const ;
|
||||
// Returns true if the button is enabled.
|
||||
|
||||
void enable( bool b = true ) ;
|
||||
// Enables the button. Disables it if 'b'
|
||||
// is false.
|
||||
|
||||
void disable() ;
|
||||
// Disables the button, greying it.
|
||||
|
||||
private:
|
||||
void operator=( const Button & ) ;
|
||||
Button( const Button & ) ;
|
||||
} ;
|
||||
|
||||
#endif
|
@ -132,6 +132,23 @@ LRESULT GGui::Cracker::crack( UINT message , WPARAM wparam ,
|
||||
onSysColourChange() ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
{
|
||||
bool processed = false ;
|
||||
WPARAM cmd = wparam & 0xfff0 ;
|
||||
if( cmd == SC_MAXIMIZE )
|
||||
processed = onSysCommand( scMaximise ) ;
|
||||
else if( cmd == SC_MINIMIZE )
|
||||
processed = onSysCommand( scMinimise ) ;
|
||||
else if( cmd == SC_SIZE )
|
||||
processed = onSysCommand( scSize ) ;
|
||||
else if( cmd == SC_CLOSE )
|
||||
processed = onSysCommand( scClose ) ;
|
||||
if( !processed )
|
||||
defolt = true ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
{
|
||||
@ -296,11 +313,30 @@ LRESULT GGui::Cracker::crack( UINT message , WPARAM wparam ,
|
||||
return onUser( wparam , lparam ) ;
|
||||
}
|
||||
|
||||
case WM_USER+1: // see wm_idle()
|
||||
case WM_USER+1U: // see wm_idle()
|
||||
{
|
||||
return onIdle() ? 1 : 0 ;
|
||||
}
|
||||
|
||||
case WM_USER+2U: // see wm_tray()
|
||||
{
|
||||
if( lparam == WM_LBUTTONDBLCLK )
|
||||
onTrayDoubleClick() ;
|
||||
else if( lparam == WM_RBUTTONUP )
|
||||
onTrayRightMouseButtonUp() ;
|
||||
else if( lparam == WM_RBUTTONDOWN )
|
||||
onTrayRightMouseButtonDown() ;
|
||||
else if( lparam == WM_LBUTTONDOWN )
|
||||
onTrayLeftMouseButtonDown() ;
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
case WM_USER+3U: // see wm_quit()
|
||||
{
|
||||
// never gets here -- intercepted in GGui::Pump
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
{
|
||||
onTimer( wparam ) ;
|
||||
@ -333,10 +369,28 @@ LRESULT GGui::Cracker::crack( UINT message , WPARAM wparam ,
|
||||
return 0L ; // ignored
|
||||
}
|
||||
|
||||
//static
|
||||
unsigned int GGui::Cracker::wm_winsock()
|
||||
{
|
||||
return WM_USER ;
|
||||
}
|
||||
|
||||
//static
|
||||
unsigned int GGui::Cracker::wm_idle()
|
||||
{
|
||||
return WM_USER+1 ;
|
||||
return WM_USER+1U ;
|
||||
}
|
||||
|
||||
//static
|
||||
unsigned int GGui::Cracker::wm_tray()
|
||||
{
|
||||
return WM_USER+2U ;
|
||||
}
|
||||
|
||||
//static
|
||||
unsigned int GGui::Cracker::wm_quit()
|
||||
{
|
||||
return WM_USER+3U ;
|
||||
}
|
||||
|
||||
// trivial default implementations of virtual functions...
|
||||
@ -350,6 +404,11 @@ void GGui::Cracker::onSysColourChange()
|
||||
{
|
||||
}
|
||||
|
||||
bool GGui::Cracker::onSysCommand( SysCommand )
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
|
||||
bool GGui::Cracker::onCreate()
|
||||
{
|
||||
return true ;
|
||||
@ -418,6 +477,22 @@ void GGui::Cracker::onDoubleClick( unsigned , unsigned , unsigned )
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Cracker::onTrayDoubleClick()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Cracker::onTrayLeftMouseButtonDown()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Cracker::onTrayRightMouseButtonDown()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Cracker::onTrayRightMouseButtonUp()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Cracker::onTimer( unsigned )
|
||||
{
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
Cracker( const Cracker &other ) ;
|
||||
// Copy constructor.
|
||||
|
||||
Cracker &operator=( const Cracker &other ) ;
|
||||
Cracker & operator=( const Cracker & other ) ;
|
||||
// Assignment operator.
|
||||
|
||||
LRESULT crack( unsigned msg , WPARAM w , LPARAM l , bool &defolt ) ;
|
||||
@ -63,9 +63,22 @@ public:
|
||||
// user should then normally call
|
||||
// DefWindowProc().
|
||||
|
||||
static unsigned int wm_winsock() ;
|
||||
// Returns a message number which is recommended for
|
||||
// winsock messages.
|
||||
|
||||
static unsigned int wm_idle() ;
|
||||
// Returns a message number which should be used for
|
||||
// idle messages. See onIdle().
|
||||
// idle messages. See onIdle() and GGui::Pump.
|
||||
|
||||
static unsigned int wm_tray() ;
|
||||
// Returns a message number which should be used for
|
||||
// system-tray notification messages.
|
||||
// See GGui::Tray.
|
||||
|
||||
static unsigned int wm_quit() ;
|
||||
// Returns a message number which can be used
|
||||
// as an alternative to WM_QUIT. See also GGui::Pump.
|
||||
|
||||
protected:
|
||||
virtual bool onEraseBackground( HDC hdc ) ;
|
||||
@ -86,6 +99,12 @@ protected:
|
||||
// Overridable. Called when the window
|
||||
// receives a WM_SYSCOLORCHANGE message.
|
||||
|
||||
enum SysCommand { scMaximise , scMinimise , scClose , scSize /*etc*/ } ;
|
||||
virtual bool onSysCommand( SysCommand sys_command ) ;
|
||||
// Overridable. Called when the window
|
||||
// receives a WM_SYSCOMMAND message.
|
||||
// Returns true if processed.
|
||||
|
||||
virtual bool onCreate() ;
|
||||
// Overridable. Called when the window
|
||||
// receives a WM_CREATE message.
|
||||
@ -170,6 +189,30 @@ protected:
|
||||
// button is double clicked (but depending
|
||||
// on the window class-style).
|
||||
|
||||
virtual void onTrayDoubleClick() ;
|
||||
// Overridable. Called when the left mouse
|
||||
// button is double clicked on the window's
|
||||
// system-tray icon.
|
||||
// See also: GGui::Tray
|
||||
|
||||
virtual void onTrayLeftMouseButtonDown() ;
|
||||
// Overridable. Called when the left mouse
|
||||
// button is clicked on the window's
|
||||
// system-tray icon.
|
||||
// See also: GGui::Tray
|
||||
|
||||
virtual void onTrayRightMouseButtonDown() ;
|
||||
// Overridable. Called when the right mouse
|
||||
// button is clicked on the window's
|
||||
// system-tray icon.
|
||||
// See also: GGui::Tray
|
||||
|
||||
virtual void onTrayRightMouseButtonUp() ;
|
||||
// Overridable. Called when the right mouse
|
||||
// button is released on the window's
|
||||
// system-tray icon.
|
||||
// See also: GGui::Tray
|
||||
|
||||
virtual void onTimer( unsigned id ) ;
|
||||
// Overridable. Called on receipt of a WM_TIMER
|
||||
// message.
|
||||
@ -223,6 +266,7 @@ protected:
|
||||
// Called whenever the event loop becomes empty.
|
||||
// If true is returned then it is called again
|
||||
// (as long as the queue is still empty).
|
||||
// See also: GGui::Pump
|
||||
} ;
|
||||
|
||||
inline
|
||||
|
378
src/win32/gdialog.cpp
Normal file
378
src/win32/gdialog.cpp
Normal file
@ -0,0 +1,378 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gdialog.cpp
|
||||
//
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gdialog.h"
|
||||
#include "gdebug.h"
|
||||
#include "glog.h"
|
||||
#include <algorithm> // find
|
||||
|
||||
// static data
|
||||
GGui::DialogList GGui::Dialog::m_list ;
|
||||
|
||||
// local prototypes
|
||||
BOOL CALLBACK gdialog_dlgproc_export( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam ) ;
|
||||
|
||||
GGui::Dialog::Dialog( HINSTANCE hinstance , HWND hwnd_parent , const char *title ) :
|
||||
WindowBase(NULL) ,
|
||||
m_modal(false) ,
|
||||
m_focus_set(false) ,
|
||||
m_hinstance(hinstance) ,
|
||||
m_hwnd_parent(hwnd_parent)
|
||||
{
|
||||
m_magic = Magic ;
|
||||
if( title != NULL )
|
||||
m_title = title ;
|
||||
}
|
||||
|
||||
GGui::Dialog::Dialog( const ApplicationBase & app , bool top_level ) :
|
||||
WindowBase(NULL) ,
|
||||
m_modal(false) ,
|
||||
m_focus_set(false)
|
||||
{
|
||||
m_magic = Magic ;
|
||||
m_hinstance = app.hinstance() ;
|
||||
m_hwnd_parent = top_level ? NULL : app.handle() ;
|
||||
m_title = app.title() ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::privateInit( HWND hwnd )
|
||||
{
|
||||
setHandle( hwnd ) ;
|
||||
::SetWindowText( handle() , m_title.c_str() ) ;
|
||||
}
|
||||
|
||||
GGui::Dialog::~Dialog()
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::~Dialog" ) ;
|
||||
cleanup() ;
|
||||
m_magic = 0 ;
|
||||
}
|
||||
|
||||
GGui::DialogList::iterator GGui::Dialog::find( HWND h )
|
||||
{
|
||||
return std::find( m_list.begin() , m_list.end() , DialogHandle(h) ) ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::cleanup()
|
||||
{
|
||||
// if not already cleaned up
|
||||
if( handle() != NULL )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::cleanup" ) ;
|
||||
|
||||
// reset the object pointer
|
||||
::SetWindowLong( handle() , DWL_USER , (LPARAM)NULL ) ;
|
||||
|
||||
// remove from the modal list
|
||||
G_ASSERT( (find(handle())!=m_list.end()) == !m_modal ) ;
|
||||
if( !m_modal )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::dlgProc: removing modeless dialog box window " << handle() ) ;
|
||||
m_list.erase( find(handle()) ) ;
|
||||
G_ASSERT( find(handle()) == m_list.end() ) ; // assert one
|
||||
}
|
||||
}
|
||||
setHandle( NULL ) ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::setFocus( int control )
|
||||
{
|
||||
HWND hwnd_control = ::GetDlgItem( handle() , control ) ;
|
||||
if( hwnd_control != NULL )
|
||||
{
|
||||
m_focus_set = true ; // determines the WM_INITDIALOG return value
|
||||
::SetFocus( hwnd_control ) ;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT GGui::Dialog::sendMessage( int control , unsigned message , WPARAM wparam , LPARAM lparam ) const
|
||||
{
|
||||
HWND hwnd_control = ::GetDlgItem( handle() , control ) ;
|
||||
return ::SendMessage( hwnd_control , message , wparam , lparam ) ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::dlgProc( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam )
|
||||
{
|
||||
if( message == WM_INITDIALOG )
|
||||
{
|
||||
Dialog *dialog = (Dialog*)(void*)lparam ;
|
||||
::SetWindowLong( hwnd , DWL_USER , (LPARAM)(void *)dialog ) ;
|
||||
dialog->privateInit( hwnd ) ;
|
||||
G_DEBUG( "GGui::Dialog::dlgProc: WM_INITDIALOG" ) ;
|
||||
if( !dialog->onInit() )
|
||||
{
|
||||
dialog->privateEnd( 0 ) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
// add to the static list of modeless dialogs
|
||||
if( !dialog->m_modal )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::dlgProc: adding modeless dialog box window " << hwnd ) ;
|
||||
m_list.push_front( DialogHandle(hwnd) ) ;
|
||||
G_DEBUG( "GGui::Dialog::dlgProc: now " << m_list.size() << " modeless dialog box(es)" ) ;
|
||||
}
|
||||
|
||||
return !dialog->privateFocusSet() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
GGui::Dialog *dialog = (GGui::Dialog*)::GetWindowLong( hwnd , DWL_USER ) ;
|
||||
if( dialog != NULL )
|
||||
return dialog->dlgProc( message , wparam , lparam ) ;
|
||||
else
|
||||
return 0 ; // WM_SETFONT etc.
|
||||
}
|
||||
}
|
||||
|
||||
bool GGui::Dialog::dlgProc( UINT message , WPARAM wparam , LPARAM lparam )
|
||||
{
|
||||
switch( message )
|
||||
{
|
||||
case WM_VSCROLL:
|
||||
case WM_HSCROLL:
|
||||
{
|
||||
HWND hwnd_scrollbar = (HWND)(HIWORD(lparam)) ; // may be zero
|
||||
if( wparam == SB_THUMBPOSITION || wparam == SB_THUMBTRACK )
|
||||
{
|
||||
unsigned position = LOWORD(lparam) ;
|
||||
onScrollPosition( hwnd_scrollbar , position ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool vertical = message == WM_VSCROLL ;
|
||||
onScroll( hwnd_scrollbar , vertical ) ;
|
||||
}
|
||||
onScrollMessage( message , wparam , lparam ) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
onCommand( wparam ) ;
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
#ifdef G_WIN16
|
||||
case WM_CTLCOLOR:
|
||||
{
|
||||
return (bool)onControlColour( wparam , LOWORD(lparam) , HIWORD(lparam) ) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef G_WIN32
|
||||
case WM_CTLCOLORDLG:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_DLG ) ;
|
||||
case WM_CTLCOLORMSGBOX:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_MSGBOX ) ;
|
||||
case WM_CTLCOLOREDIT:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_EDIT ) ;
|
||||
case WM_CTLCOLORBTN:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_BTN ) ;
|
||||
case WM_CTLCOLORLISTBOX:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_LISTBOX ) ;
|
||||
case WM_CTLCOLORSCROLLBAR:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_SCROLLBAR ) ;
|
||||
case WM_CTLCOLORSTATIC:
|
||||
return !!onControlColour( (HDC)wparam , (HWND)lparam , CTLCOLOR_STATIC ) ;
|
||||
#endif
|
||||
|
||||
#if 0 // Windows bug -- WM_SETCURSOR is useless in a dialog box
|
||||
case WM_SETCURSOR:
|
||||
{
|
||||
onSetCursor( (HWND)wparam , LOWORD(lparam) , HIWORD(lparam) ) ;
|
||||
return 0 ;
|
||||
}
|
||||
#endif
|
||||
|
||||
case WM_CLOSE:
|
||||
{
|
||||
onClose() ;
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
case WM_DESTROY:
|
||||
{
|
||||
onDestroy() ;
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
case WM_NCDESTROY:
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::dlgProc: WM_NCDESTROY" ) ;
|
||||
cleanup() ;
|
||||
onNcDestroy() ; // override could do "delete this"
|
||||
return 1 ;
|
||||
}
|
||||
}
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
HBRUSH GGui::Dialog::onControlColour( HDC /*hDC*/ , HWND /*hwnd_control*/ , WORD /*type*/ )
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::onDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Dialog::onNcDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::Dialog::end()
|
||||
{
|
||||
privateEnd( 1 ) ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::privateEnd( int i )
|
||||
{
|
||||
if( handle() == NULL ) return ;
|
||||
G_DEBUG( "GGui::Dialog::privateEnd: " << i ) ;
|
||||
if( m_modal )
|
||||
::EndDialog( handle() , i ) ;
|
||||
else
|
||||
::DestroyWindow( handle() ) ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::onClose()
|
||||
{
|
||||
privateEnd(1) ;
|
||||
}
|
||||
|
||||
void GGui::Dialog::onCommand( UINT id )
|
||||
{
|
||||
if( id == IDOK )
|
||||
privateEnd(1) ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::run( int resource_id )
|
||||
{
|
||||
return run( MAKEINTRESOURCE(resource_id) ) ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::run( const char *f_name )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::run" ) ;
|
||||
|
||||
if( handle() != NULL )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::run: already running" ) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
m_modal = true ;
|
||||
int rc = ::DialogBoxParam( m_hinstance , f_name ,
|
||||
m_hwnd_parent , (DLGPROC)gdialog_dlgproc_export ,
|
||||
(LPARAM)(void *)this ) ;
|
||||
|
||||
if( rc == -1 )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::run: cannot create dialog box" ) ;
|
||||
return false ;
|
||||
}
|
||||
else if( rc == 0 )
|
||||
{
|
||||
// onInit() returned false
|
||||
G_DEBUG( "GGui::Dialog::run: dialog creation aborted" ) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::runModeless( int resource_id , bool visible )
|
||||
{
|
||||
return runModeless( MAKEINTRESOURCE(resource_id) , visible ) ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::runModeless( const char *f_name , bool visible )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::runModeless" ) ;
|
||||
|
||||
if( handle() != NULL )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::runModeless: already running" ) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
m_modal = false ;
|
||||
HWND hwnd = ::CreateDialogParam( m_hinstance , f_name ,
|
||||
m_hwnd_parent , (DLGPROC)gdialog_dlgproc_export ,
|
||||
(LPARAM)(void *)this ) ;
|
||||
|
||||
if( hwnd == NULL )
|
||||
{
|
||||
G_DEBUG( "GGui::Dialog::runModless: cannot create dialog box" ) ;
|
||||
return false ;
|
||||
}
|
||||
G_DEBUG( "GGui::Dialog::runModeless: hwnd " << hwnd ) ;
|
||||
G_ASSERT( hwnd == handle() ) ;
|
||||
|
||||
if( visible )
|
||||
::ShowWindow( hwnd , SW_SHOW ) ; // in case not WS_VISIBLE style
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::dialogMessage( MSG &msg )
|
||||
{
|
||||
for( GGui::DialogList::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
|
||||
{
|
||||
if( ::IsDialogMessage( (*p).h , &msg ) )
|
||||
return true ;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
BOOL CALLBACK gdialog_dlgproc_export( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam )
|
||||
{
|
||||
return GGui::Dialog::dlgProc( hwnd , message , wparam , lparam ) ;
|
||||
}
|
||||
|
||||
GGui::SubClassMap & GGui::Dialog::map()
|
||||
{
|
||||
return m_map ;
|
||||
}
|
||||
|
||||
bool GGui::Dialog::registerNewClass( HICON hicon , const std::string & new_class_name ) const
|
||||
{
|
||||
std::string old_class_name = windowClass() ;
|
||||
HINSTANCE hinstance = windowInstanceHandle() ;
|
||||
|
||||
// get our class info
|
||||
//
|
||||
WNDCLASS class_info ;
|
||||
::GetClassInfo( hinstance , old_class_name.c_str() , &class_info ) ;
|
||||
|
||||
// register a new class
|
||||
//
|
||||
class_info.hIcon = hicon ;
|
||||
class_info.lpszClassName = new_class_name.c_str() ;
|
||||
ATOM rc = ::RegisterClass( &class_info ) ;
|
||||
|
||||
return rc != 0 ;
|
||||
}
|
||||
|
239
src/win32/gdialog.h
Normal file
239
src/win32/gdialog.h
Normal file
@ -0,0 +1,239 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gdialog.h
|
||||
//
|
||||
|
||||
#ifndef G_DIALOG_H
|
||||
#define G_DIALOG_H
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gwinbase.h"
|
||||
#include "gappbase.h"
|
||||
#include "gscmap.h"
|
||||
|
||||
namespace GGui
|
||||
{
|
||||
class DialogHandle ;
|
||||
class Dialog ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::DialogHandle
|
||||
// Description: A private implementation class used by GGui::Dialog.
|
||||
//
|
||||
class GGui::DialogHandle
|
||||
{
|
||||
public:
|
||||
HWND h ;
|
||||
DialogHandle(HWND h_) : h(h_) {}
|
||||
bool operator==( const DialogHandle & rhs ) const
|
||||
{ return h == rhs.h ; }
|
||||
} ;
|
||||
|
||||
namespace GGui
|
||||
{
|
||||
typedef std::list< DialogHandle GAllocator(DialogHandle) > DialogList ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::Dialog
|
||||
// Description: A dialog box class for both modal and
|
||||
// modeless operation.
|
||||
// See also: GGui::Control
|
||||
//
|
||||
class GGui::Dialog : public WindowBase
|
||||
{
|
||||
public:
|
||||
Dialog( HINSTANCE hinstance , HWND hwnd_parent ,
|
||||
const char *title = NULL ) ;
|
||||
// Constructor. After contruction just call
|
||||
// run() or runModeless() with the appropriate
|
||||
// dialog resource id or name.
|
||||
|
||||
explicit Dialog( const GGui::ApplicationBase & app , bool top_level = false ) ;
|
||||
// Contructor for a dialog box which takes some
|
||||
// of its attributes (eg. its title) from the main
|
||||
// application window.
|
||||
//
|
||||
// Normally the dialog is a child of the application
|
||||
// window, but if the top-level parameter is set then
|
||||
// the dialog box is given no parent and therefore
|
||||
// appears on the task bar.
|
||||
|
||||
virtual ~Dialog() ;
|
||||
// Virtual destructor. If the dialog box
|
||||
// is running, it is left running, but
|
||||
// in headless chicken mode.
|
||||
|
||||
static bool dialogMessage( MSG &msg ) ;
|
||||
// Processes messages for all modeless dialog boxes.
|
||||
// This should be put in the application's main message
|
||||
// loop (as the GPump class does).
|
||||
// Returns true if the message was used up.
|
||||
|
||||
bool run( const char * resource_name ) ;
|
||||
// See run(int).
|
||||
|
||||
bool run( int resource_id ) ;
|
||||
// Runs the dialog modally. Returns false if the
|
||||
// dialog could not be created or if onInit()
|
||||
// returned false.
|
||||
|
||||
bool runModeless( const char * resource_name , bool visible = true ) ;
|
||||
// See runModeless(int).
|
||||
|
||||
bool runModeless( int resource_id , bool visible = true ) ;
|
||||
// Runs the dialog modelessly. Returns false if the
|
||||
// dialog could not be created or if onInit()
|
||||
// returned false.
|
||||
//
|
||||
// Normally modeless Dialog objects must be allocated
|
||||
// on the heap and deleted with "delete this" within
|
||||
// onNcDestroy().
|
||||
|
||||
static bool dlgProc( HWND hwnd , UINT message ,
|
||||
WPARAM wparam , LPARAM lparam ) ;
|
||||
// Called directly from the exported dialog procedure.
|
||||
|
||||
void setFocus( int control ) ;
|
||||
// Sets focus to the specified control.
|
||||
|
||||
LRESULT sendMessage( int control , unsigned message ,
|
||||
WPARAM wparam = 0 , LPARAM lparam = 0 ) const ;
|
||||
// Sends a message to the specified control.
|
||||
|
||||
SubClassMap & map() ;
|
||||
// Used by GGui::Control. (The sub-class map allows the Control
|
||||
// class to map from a sub-classed control's window handle to
|
||||
// the control object's address and the address of the super-
|
||||
// class window procedure.)
|
||||
|
||||
bool registerNewClass( HICON hicon , const std::string & class_name ) const;
|
||||
// Registers a new window-class based on this
|
||||
// dialog box's window-class, but with the specified
|
||||
// icon. (See "Custom Dialog Boxes" in MSDN.)
|
||||
// Use after runModeless() and before end().
|
||||
// Returns false on error.
|
||||
|
||||
void end() ;
|
||||
// Starts the dialog box termination sequence.
|
||||
// Usually called from the override of onClose() or
|
||||
// onCommand().
|
||||
|
||||
bool isValid() ;
|
||||
// Returns true if the object passes its internal
|
||||
// consistency checks. Used in debugging.
|
||||
|
||||
protected:
|
||||
virtual bool onInit() ;
|
||||
// Overridable. Called on receipt of a WM_INITDIALOG
|
||||
// message. Returns false to abort the dialog
|
||||
// box creation.
|
||||
|
||||
virtual void onCommand( UINT id ) ;
|
||||
// Overridable. Called on receipt of a WM_COMMAND
|
||||
// message.
|
||||
|
||||
virtual HBRUSH onControlColour( HDC hDC , HWND hwnd_control , WORD type ) ;
|
||||
// Overridable. Called on receipt of a WM_CTLCOLOR
|
||||
// message.
|
||||
|
||||
virtual void onClose() ;
|
||||
// Overridable. Called on receipt of a WM_CLOSE
|
||||
// message.
|
||||
|
||||
virtual void onScrollPosition( HWND hwnd_scrollbar , unsigned position ) ;
|
||||
// Overridable. Called on receipt of thumb-track and
|
||||
// thumb-position messages.
|
||||
|
||||
virtual void onScroll( HWND hwnd_scrollbar , bool vertical ) ;
|
||||
// Overridable. Called on receipt of scroll messages excluding
|
||||
// thumb-track and thumb-position messages.
|
||||
|
||||
virtual void onScrollMessage( unsigned message ,
|
||||
WPARAM wparam , LPARAM lparam ) ;
|
||||
// Overridable. Called on receipt of all scroll messages.
|
||||
// This combines onScroll() and onScrollPosition().
|
||||
|
||||
virtual void onDestroy() ;
|
||||
// Overridable. Called on receipt of a WM_DESTROY
|
||||
// message.
|
||||
|
||||
virtual void onNcDestroy() ;
|
||||
// Overridable. Called on receipt of a WM_NCDESTROY
|
||||
// message. The override may do a "delete this" if
|
||||
// necessary.
|
||||
|
||||
private:
|
||||
bool dlgProc( UINT message , WPARAM wparam , LPARAM lparam ) ;
|
||||
void privateInit( HWND hwnd ) ;
|
||||
void privateEnd( int n ) ;
|
||||
bool privateFocusSet() const ;
|
||||
void cleanup() ;
|
||||
DialogList::iterator find( HWND h ) ;
|
||||
Dialog( const Dialog &other ) ;
|
||||
void operator=( const Dialog &other ) ;
|
||||
|
||||
private:
|
||||
enum { Magic = 4567 } ;
|
||||
std::string m_name ;
|
||||
std::string m_title ;
|
||||
HINSTANCE m_hinstance ;
|
||||
HWND m_hwnd_parent ;
|
||||
bool m_focus_set ;
|
||||
bool m_modal ;
|
||||
int m_magic ;
|
||||
SubClassMap m_map ;
|
||||
static DialogList m_list ;
|
||||
} ;
|
||||
|
||||
inline
|
||||
bool GGui::Dialog::privateFocusSet() const
|
||||
{
|
||||
return m_focus_set ;
|
||||
}
|
||||
|
||||
inline
|
||||
bool GGui::Dialog::onInit()
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
|
||||
inline
|
||||
void GGui::Dialog::onScrollPosition( HWND , unsigned )
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
void GGui::Dialog::onScroll( HWND , bool )
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
void GGui::Dialog::onScrollMessage( unsigned , WPARAM , LPARAM )
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
bool GGui::Dialog::isValid()
|
||||
{
|
||||
return m_magic == Magic ;
|
||||
}
|
||||
|
||||
#endif
|
@ -34,7 +34,7 @@ void GGui::Pump::run()
|
||||
void GGui::Pump::run( HWND idle_window , unsigned int idle_message )
|
||||
{
|
||||
G_LOG( "GGui::Pump::run: " << idle_window << " " << idle_message ) ;
|
||||
::PostMessage( idle_window , GGui::Cracker::wm_idle() , 0 , 0 ) ; // pump priming
|
||||
::PostMessage( idle_window , idle_message , 0 , 0 ) ; // pump priming
|
||||
runCore( true , idle_window , idle_message ) ;
|
||||
}
|
||||
|
||||
@ -43,7 +43,16 @@ void GGui::Pump::runCore( bool idle , HWND hwnd_idle , unsigned int wm_idle )
|
||||
MSG msg ;
|
||||
while( ::GetMessage( &msg , NULL , 0 , 0 ) )
|
||||
{
|
||||
if( dialogMessage( msg ) ) // (may be stubbed out as a build option)
|
||||
// we use our own quit message rather than WM_QUIT because
|
||||
// WM_QUIT has some nasty undocumented side-effects such as
|
||||
// making message boxes invisible -- we need to quit event
|
||||
// loops (sometimes more than once) without side effects
|
||||
//
|
||||
if( msg.message == Cracker::wm_quit() )
|
||||
{
|
||||
break ;
|
||||
}
|
||||
else if( dialogMessage( msg ) ) // (may be stubbed out as a build option)
|
||||
{
|
||||
; // no-op
|
||||
}
|
||||
@ -75,6 +84,6 @@ bool GGui::Pump::sendIdle( HWND hwnd_idle , unsigned int wm_idle )
|
||||
|
||||
void GGui::Pump::quit()
|
||||
{
|
||||
::PostQuitMessage( 0 ) ;
|
||||
::PostMessage( 0 , Cracker::wm_quit() , 0 , 0 ) ; // not PostQuitMessage()
|
||||
}
|
||||
|
||||
|
@ -18,16 +18,17 @@
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gpump_nodialog.cpp
|
||||
// gpump_dialog.cpp
|
||||
//
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gpump.h"
|
||||
#include "gdialog.h"
|
||||
|
||||
//static
|
||||
bool GGui::Pump::dialogMessage( MSG & msg )
|
||||
{
|
||||
return false ;
|
||||
return Dialog::dialogMessage( msg ) ;
|
||||
}
|
||||
|
||||
|
93
src/win32/gscmap.cpp
Normal file
93
src/win32/gscmap.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gscmap.cpp
|
||||
//
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gscmap.h"
|
||||
#include "gdebug.h"
|
||||
#include "glog.h"
|
||||
|
||||
GGui::SubClassMap::~SubClassMap()
|
||||
{
|
||||
}
|
||||
|
||||
void GGui::SubClassMap::add( HWND hwnd , SubClassMap::Proc proc , void *context )
|
||||
{
|
||||
for( unsigned i = 0 ; i < SlotsLimit ; i++ )
|
||||
{
|
||||
if( m_list[i].hwnd == hwnd )
|
||||
{
|
||||
G_ASSERT( !"GGui::SubClassMap::add: duplicate window handle" ) ;
|
||||
}
|
||||
if( m_list[i].hwnd == 0 )
|
||||
{
|
||||
m_list[i].proc = proc ;
|
||||
m_list[i].hwnd = hwnd ;
|
||||
m_list[i].context = context ;
|
||||
if( i >= m_high_water )
|
||||
m_high_water = i+1 ;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
G_DEBUG( "GGui::SubClassMap::add: too many subclassed windows" ) ;
|
||||
G_ASSERT( !"GGui::SubClassMap::add: too many subclasses windows" ) ;
|
||||
}
|
||||
|
||||
GGui::SubClassMap::Proc GGui::SubClassMap::find( HWND hwnd , void **context_p )
|
||||
{
|
||||
if( context_p != NULL )
|
||||
*context_p = NULL ;
|
||||
|
||||
for( unsigned i = 0 ; i < m_high_water ; i++ )
|
||||
{
|
||||
if( m_list[i].hwnd == hwnd )
|
||||
{
|
||||
if( context_p != NULL )
|
||||
*context_p = m_list[i].context ;
|
||||
return m_list[i].proc ;
|
||||
}
|
||||
}
|
||||
G_DEBUG( "GGui::SubClassMap::find: cannot find window " << hwnd ) ;
|
||||
G_ASSERT( false ) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
void GGui::SubClassMap::remove( HWND hwnd )
|
||||
{
|
||||
unsigned int count = 0U ;
|
||||
for( unsigned int i = 0U ; i < m_high_water ; i++ )
|
||||
{
|
||||
if( m_list[i].hwnd == hwnd )
|
||||
{
|
||||
m_list[i].hwnd = 0 ;
|
||||
count++ ;
|
||||
if( count > 1U )
|
||||
G_ASSERT( !"GGui::SubClassMap::remove: duplicate" ) ;
|
||||
}
|
||||
}
|
||||
if( count == 0U )
|
||||
{
|
||||
G_DEBUG( "GGui::SubClassMap::remove: cannot find window " << hwnd ) ;
|
||||
G_ASSERT( false ) ;
|
||||
}
|
||||
}
|
||||
|
88
src/win32/gscmap.h
Normal file
88
src/win32/gscmap.h
Normal file
@ -0,0 +1,88 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gscmap.h
|
||||
//
|
||||
|
||||
#ifndef G_SCMAP_H
|
||||
#define G_SCMAP_H
|
||||
|
||||
#include "gdef.h"
|
||||
|
||||
namespace GGui
|
||||
{
|
||||
class SubClassMap ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::SubClassMap
|
||||
// Description: A class for mapping sub-classed window handles
|
||||
// to their old window procedures. Note that a sub-class
|
||||
// map is only required for standard windows such as
|
||||
// standard controls or standard dialog boxes; when subclassing
|
||||
// our own windows it is better to store the old window procedure
|
||||
// function pointer using SetWindowLong().
|
||||
//
|
||||
class GGui::SubClassMap
|
||||
{
|
||||
public:
|
||||
typedef WNDPROC Proc ; // could also be FARPROC -- see CallWindowProc
|
||||
|
||||
SubClassMap() ;
|
||||
// Default constructor.
|
||||
|
||||
~SubClassMap() ;
|
||||
// Destructor.
|
||||
|
||||
void add( HWND hwnd , Proc proc , void *context = NULL ) ;
|
||||
// Adds the given entry to the map.
|
||||
|
||||
Proc find( HWND hwnd , void **context_p = NULL ) ;
|
||||
// Finds the entry in the map whith the given
|
||||
// window handle. Optionally returns the context
|
||||
// pointer by reference.
|
||||
|
||||
void remove( HWND hwnd ) ;
|
||||
// Removes the given entry from the map. Typically
|
||||
// called when processing a WM_NCDESTROY message.
|
||||
|
||||
private:
|
||||
SubClassMap( const SubClassMap &other ) ;
|
||||
void operator=( const SubClassMap &other ) ;
|
||||
|
||||
private:
|
||||
enum { SlotsLimit = 80 } ;
|
||||
struct Slot
|
||||
{
|
||||
Proc proc ;
|
||||
HWND hwnd ;
|
||||
void *context ;
|
||||
Slot() : proc(0) , hwnd(0) , context(NULL) {} ;
|
||||
} ;
|
||||
Slot m_list[SlotsLimit] ;
|
||||
unsigned int m_high_water ;
|
||||
} ;
|
||||
|
||||
inline
|
||||
GGui::SubClassMap::SubClassMap() :
|
||||
m_high_water(0U)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
@ -42,6 +42,7 @@ public:
|
||||
unsigned long dx ;
|
||||
unsigned long dy ;
|
||||
Size() ;
|
||||
Size( unsigned long dx , unsigned long dy ) ;
|
||||
void streamOut( std::ostream & ) const ;
|
||||
} ;
|
||||
|
||||
@ -52,6 +53,13 @@ GGui::Size::Size() :
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
GGui::Size::Size( unsigned long dx_ , unsigned long dy_ ) :
|
||||
dx(dx_) ,
|
||||
dy(dy_)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
void GGui::Size::streamOut( std::ostream & s ) const
|
||||
{
|
||||
|
59
src/win32/gtray.cpp
Normal file
59
src/win32/gtray.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gtray.cpp
|
||||
//
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gtray.h"
|
||||
#include "gappinst.h"
|
||||
#include <cstring>
|
||||
|
||||
GGui::Tray::Tray( unsigned int icon_id , const WindowBase & window ,
|
||||
const std::string & tip , unsigned int message )
|
||||
{
|
||||
m_info.cbSize = sizeof(m_info) ;
|
||||
m_info.hWnd = window.handle() ;
|
||||
m_info.uID = message ;
|
||||
m_info.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP ;
|
||||
m_info.uCallbackMessage = message ;
|
||||
m_info.hIcon =
|
||||
::LoadIcon( ApplicationInstance::hinstance() ,
|
||||
MAKEINTRESOURCE(icon_id)) ;
|
||||
|
||||
char * p = m_info.szTip ;
|
||||
const size_t n = sizeof(m_info.szTip) ;
|
||||
|
||||
std::strncpy( p , tip.c_str() , n ) ;
|
||||
p[n-1U] = '\0' ;
|
||||
|
||||
bool ok = !! ::Shell_NotifyIcon( NIM_ADD , &m_info ) ;
|
||||
if( !ok )
|
||||
throw Error() ;
|
||||
}
|
||||
|
||||
GGui::Tray::~Tray()
|
||||
{
|
||||
m_info.uFlags = 0 ;
|
||||
m_info.uCallbackMessage = 0 ;
|
||||
m_info.hIcon = 0 ;
|
||||
bool ok = !! ::Shell_NotifyIcon( NIM_DELETE , &m_info ) ;
|
||||
}
|
||||
|
61
src/win32/gtray.h
Normal file
61
src/win32/gtray.h
Normal file
@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// ===
|
||||
//
|
||||
// gtray.h
|
||||
//
|
||||
|
||||
#ifndef G_GUI_TRAY_H
|
||||
#define G_GUI_TRAY_H
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gwinbase.h"
|
||||
#include "gcracker.h"
|
||||
#include "gexception.h"
|
||||
|
||||
namespace GGui
|
||||
{
|
||||
class Tray ;
|
||||
} ;
|
||||
|
||||
// Class: GGui::Tray
|
||||
// Description: Manages an icon within the system tray.
|
||||
//
|
||||
class GGui::Tray
|
||||
{
|
||||
public:
|
||||
G_EXCEPTION( Error , "system-tray error" ) ;
|
||||
|
||||
Tray( unsigned int icon_resource_id , const WindowBase & window ,
|
||||
const std::string & tip , unsigned int message = Cracker::wm_tray() ) ;
|
||||
// Constructor. Adds the icon to the system tray.
|
||||
|
||||
~Tray() ;
|
||||
// Destructor. Removes the icon from the system tray.
|
||||
|
||||
private:
|
||||
void operator=( const Tray & ) ; // not implemented
|
||||
Tray( const Tray & ) ; // not implemented
|
||||
|
||||
private:
|
||||
NOTIFYICONDATA m_info ;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "gwinbase.h"
|
||||
#include "gdebug.h"
|
||||
#include <windowsx.h>
|
||||
#include <cstring>
|
||||
|
||||
GGui::WindowBase::WindowBase( HWND hwnd ) :
|
||||
m_hwnd(hwnd)
|
||||
@ -58,29 +59,52 @@ void GGui::WindowBase::setHandle( HWND hwnd )
|
||||
|
||||
GGui::Size GGui::WindowBase::internalSize() const
|
||||
{
|
||||
Size size ;
|
||||
RECT rect ;
|
||||
if( ::GetClientRect( m_hwnd , &rect ) )
|
||||
{
|
||||
G_ASSERT( rect.right >= rect.left ) ;
|
||||
G_ASSERT( rect.bottom >= rect.top ) ;
|
||||
size.dx = rect.right - rect.left ;
|
||||
size.dy = rect.bottom - rect.top ;
|
||||
G_ASSERT( rect.left == 0 ) ;
|
||||
G_ASSERT( rect.top == 0 ) ;
|
||||
return Size( rect.right , rect.bottom ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size() ;
|
||||
}
|
||||
return size ;
|
||||
}
|
||||
|
||||
GGui::Size GGui::WindowBase::externalSize() const
|
||||
{
|
||||
GGui::Size size ;
|
||||
RECT rect ;
|
||||
if( ::GetWindowRect( m_hwnd , &rect ) )
|
||||
{
|
||||
G_ASSERT( rect.right >= rect.left ) ;
|
||||
G_ASSERT( rect.bottom >= rect.top ) ;
|
||||
size.dx = rect.right - rect.left ;
|
||||
size.dy = rect.bottom - rect.top ;
|
||||
return Size( rect.right - rect.left , rect.bottom - rect.top ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size() ;
|
||||
}
|
||||
return size ;
|
||||
}
|
||||
|
||||
std::string GGui::WindowBase::windowClass() const
|
||||
{
|
||||
char buffer[256U] ;
|
||||
buffer[0U] = '\0' ;
|
||||
::GetClassName( m_hwnd , buffer , sizeof(buffer)-1U ) ;
|
||||
buffer[sizeof(buffer)-1U] = '\0' ;
|
||||
|
||||
if( (std::strlen(buffer)+1U) == sizeof(buffer) )
|
||||
{
|
||||
G_WARNING( "GGui::WindowBase::windowClass: possible truncation: "
|
||||
<< "\"" << buffer << "\"" ) ;
|
||||
}
|
||||
|
||||
return std::string( buffer ) ;
|
||||
}
|
||||
|
||||
HINSTANCE GGui::WindowBase::windowInstanceHandle() const
|
||||
{
|
||||
return reinterpret_cast<HINSTANCE>(::GetWindowLong(m_hwnd,GWL_HINSTANCE)) ;
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,10 @@ namespace GGui
|
||||
|
||||
// Class: GGui::WindowBase
|
||||
// Description: A low-level window class which
|
||||
// encapsulates a window handle and methods
|
||||
// to retrieve basic window attributes.
|
||||
// encapsulates a window handle and provides methods
|
||||
// to retrieve basic window attributes. Knows
|
||||
// nothing about window messages.
|
||||
// See also: GGui::Cracker, GGui::Window, GGui::Dialog
|
||||
//
|
||||
class GGui::WindowBase
|
||||
{
|
||||
@ -63,6 +65,13 @@ public:
|
||||
// Returns the internal size of the window.
|
||||
// (ie. the size of the client area)
|
||||
|
||||
std::string windowClass() const ;
|
||||
// Returns the window's window-class name.
|
||||
|
||||
HINSTANCE windowInstanceHandle() const ;
|
||||
// Returns the window's application instance.
|
||||
// See also: GGui::ApplicationInstance
|
||||
|
||||
protected:
|
||||
void setHandle( HWND hwnd ) ;
|
||||
// Sets the window handle.
|
||||
|
@ -201,10 +201,8 @@ LRESULT GGui::Window::wndProcCore( unsigned msg , WPARAM wparam , LPARAM lparam
|
||||
}
|
||||
catch( std::exception & e )
|
||||
{
|
||||
// absorb the exception
|
||||
G_DEBUG( "GGui::Window::wndProcCore: exception: " << e.what() ) ;
|
||||
defolt = true ;
|
||||
return 0 ; // ignored
|
||||
onException( e ) ;
|
||||
return 0 ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,8 +214,7 @@ bool GGui::Window::onCreateCore()
|
||||
}
|
||||
catch( std::exception & e )
|
||||
{
|
||||
// absorb the exception
|
||||
G_DEBUG( "GGui::Window::onCreateCore: exception: " << e.what() ) ;
|
||||
onException( e ) ;
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
@ -288,19 +285,6 @@ GGui::Size GGui::Window::borderSize( bool has_menu )
|
||||
return size ;
|
||||
}
|
||||
|
||||
GGui::Size GGui::Window::clientSize() const
|
||||
{
|
||||
Size size ;
|
||||
RECT rect ;
|
||||
BOOL success = ::GetClientRect( handle() , &rect ) ;
|
||||
// if( success )
|
||||
{
|
||||
size.dx = rect.right ;
|
||||
size.dy = rect.bottom ;
|
||||
}
|
||||
return size ;
|
||||
}
|
||||
|
||||
void GGui::Window::resize( Size new_size , bool repaint )
|
||||
{
|
||||
// note that GetWindowRect() returns coordinates
|
||||
@ -329,3 +313,11 @@ void GGui::Window::resize( Size new_size , bool repaint )
|
||||
}
|
||||
}
|
||||
|
||||
void GGui::Window::onException( std::exception & e )
|
||||
{
|
||||
// it is not clear that it is safe to throw out of a
|
||||
// window procedure, but it seems to work okay
|
||||
//
|
||||
throw ;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ namespace GGui
|
||||
// Class: GGui::Window
|
||||
// Description: A window class. Window messages
|
||||
// should be processed by overriding the on*()
|
||||
// virtual functions inherited from GCracker.
|
||||
// virtual functions inherited from GGui::Cracker.
|
||||
// See also: WindowBase
|
||||
//
|
||||
class GGui::Window : public Cracker
|
||||
{
|
||||
@ -114,18 +115,13 @@ public:
|
||||
void invalidate( bool erase = true ) ;
|
||||
// Invalidates the window so that it redraws.
|
||||
|
||||
static Size borderSize( bool has_menu = true ) ;
|
||||
static Size borderSize( bool has_menu ) ;
|
||||
// Returns the size of the border of a _typical_
|
||||
// main window. The actual border size will
|
||||
// depend on the window style and its size
|
||||
// (since the menu bar changes height at
|
||||
// run-time).
|
||||
|
||||
Size clientSize() const ;
|
||||
// Returns the size of the window's client area.
|
||||
// (The client size is also available in WM_MOVE
|
||||
// messages and from onSize().)
|
||||
|
||||
void resize( Size new_size , bool repaint = true ) ;
|
||||
// Resizes the window. The top-left corner stays put.
|
||||
|
||||
@ -189,7 +185,12 @@ protected:
|
||||
// Returns the address of the exported 'C' window
|
||||
// procedure. This is not for general use -- see
|
||||
// WindowHidden.
|
||||
|
||||
|
||||
virtual void onException( std::exception & e ) ;
|
||||
// Called if an exception is being thrown out of the
|
||||
// window procedure. The default implementation
|
||||
// does "throw;" to continue throwing the exception.
|
||||
|
||||
public:
|
||||
static LRESULT wndProc( HWND hwnd , UINT message , WPARAM wparam , LPARAM lparam ) ;
|
||||
// Called directly from the global, exported
|
||||
|
@ -47,7 +47,7 @@ GGui::WindowHidden::WindowHidden( HINSTANCE hinstance ) :
|
||||
{
|
||||
bool success = create( window_class_name.c_str() ,
|
||||
"" , // title
|
||||
0 , // window style
|
||||
WS_POPUP , // window style
|
||||
0 , 0 , 10 , 10 , // x,y,dx,dy
|
||||
0 , // parent
|
||||
0 , // menu
|
||||
|
@ -47,10 +47,9 @@ public:
|
||||
virtual ~WindowHidden() ;
|
||||
// Virtual destructor.
|
||||
|
||||
protected:
|
||||
void onNcDestroy() ;
|
||||
|
||||
private:
|
||||
virtual void onNcDestroy() ;
|
||||
WindowHidden( const WindowHidden & ) ;
|
||||
void operator=( const WindowHidden & ) ;
|
||||
std::string windowClassName() ;
|
||||
|
Loading…
x
Reference in New Issue
Block a user