+2012-09-29 Keith Marshall <keithmarshall@users.sourceforge.net>
+
+ Add initial working GUI mode DMH class implementation.
+
+ * src/dmh.h (DMH_SEVERITY_MASK): New manifest constant; define it.
+ (DMH_DIGEST_MASK, DMH_COMPILE_DIGEST, DMH_DISPATCH_DIGEST): Likewise.
+ (DMH_BEGIN_DIGEST, DMH_END_DIGEST): Redefine in terms of above.
+
+ * src/dmhcore.h: New header file; it declares...
+ (dmhTypeGeneric): ...this abstract base class, factored from...
+
+ * src/dmh.cpp (dmhTypeGeneric): ...here, whence remove it; it is
+ still required, thus include dmhcore.h so that it remains visible.
+ (dmh_exception): Remove errant namespace qualifier from constructor.
+ (dmhTypeGUI): Delete class declaration and original constructor.
+ (dmh_init): Delete reference to dmhTypeGUI; replace by call to...
+ (dmh_init_gui): ...this new static function; it is a stub which
+ invokes a DLL import of the same name, to instantiate a dmhTypeGUI.
+ (dmhTypeGUI::control, dmhTypeGUI::notify, dmhTypeGUI::printf): Delete
+ original method stubs.
+
+ * src/guidmh.cpp: New file; it reimplements...
+ (dmhTypeGUI): ...this class; declare it and implement its constructor.
+ (dmh_init_gui): Provide its DLL exported implementation.
+ (dmhTypeGUI::dispatch_message): New private method; add it to the
+ class declaration and implement it; it is a helper method for...
+ (dmhTypeGUI::control, dmhTypeGUI::notify): ...these; implement them.
+ (dmhTypeGUI::printf): Provide a replacement stub.
+
+ * Makefile.in (GUIMAIN_OBJECTS): Add guidmh.OBJEXT
+
+ * src/guimain.h (AppWindowMaker::Create): New method; add it to the
+ class declaration; it overrides the default Create() method inherited
+ from WTK::MainWindowMaker
+
+ * src/pkgview.cpp (AppWindowMaker::Create): Implement it; it handles
+ window class registration and dmhTypeGUI initialisation, in addition
+ to the inherited CreateWindow() behaviour.
+
+ * src/guimain.cpp: Include dmh.h
+ (WinMain): Add catch block for dmh_exception. Remove window class
+ registration request; it is now delegated to AppWindowMaker::Create()
+
2012-09-26 Keith Marshall <keithmarshall@users.sourceforge.net>
Add .hgignore as tracked file.
clistub.$(OBJEXT) version.$(OBJEXT) approot.$(OBJEXT) getopt.$(OBJEXT)
GUIMAIN_OBJECTS = \
- guimain.$(OBJEXT) guidata.$(OBJEXT) approot.$(OBJEXT) pkgview.$(OBJEXT)
+ guimain.$(OBJEXT) guidata.$(OBJEXT) guidmh.$(OBJEXT) \
+ approot.$(OBJEXT) pkgview.$(OBJEXT)
GUIMAIN_LIBS = -lwtklite -lcomctl32
* $Id$
*
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
- * Copyright (C) 2009, 2010, 2011, MinGW Project
+ * Copyright (C) 2009, 2010, 2011, 2012, MinGW.org Project
*
*
- * Implementation of the diagnostic message handling subsystem.
+ * Implementation of the core components of, and the CLI specific
+ * API for, the diagnostic message handling subsystem.
*
*
* This is free software. Permission is granted to copy, modify and
#include <stdlib.h>
#include <stdarg.h>
-#include "dmh.h"
+#include "dmhcore.h"
-class dmhTypeGeneric
-{
- /* Abstract base class, from which message handlers are derived.
- */
- public:
- dmhTypeGeneric( const char* );
- virtual uint16_t control( const uint16_t, const uint16_t ) = 0;
- virtual int notify( const dmh_severity, const char*, va_list ) = 0;
- virtual int printf( const char*, va_list ) = 0;
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
- protected:
- const char *progname;
-};
+/* Implementation of the dmh_exception class.
+ */
+static const char *unspecified_error = "Unspecified error";
+
+dmh_exception::dmh_exception() throw():
+ message( unspecified_error ){}
+
+dmh_exception::dmh_exception( const char *msg ) throw():
+ message( unspecified_error )
+ {
+ if( msg && *msg )
+ message = msg;
+ }
+
+dmh_exception::~dmh_exception() throw(){}
+
+const char* dmh_exception::what() const throw()
+{
+ return message;
+}
-class dmhTypeTTY : public dmhTypeGeneric
+class dmhTypeTTY: public dmhTypeGeneric
{
/* Diagnostic message handler for use in console applications.
*/
inline int emit_and_flush( int );
};
-class dmhTypeGUI : public dmhTypeGeneric
-{
- /* Diagnostic message handler for use in window applications.
- */
- public:
- dmhTypeGUI( const char* );
- virtual uint16_t control( const uint16_t, const uint16_t );
- virtual int notify( const dmh_severity, const char*, va_list );
- virtual int printf( const char*, va_list );
-};
-
-dmh_exception::dmh_exception() throw()
-: message( "Unspecified error" )
-{}
-
-dmh_exception::dmh_exception::dmh_exception(const char * msg) throw()
-: message( "Unspecified error" )
-{
- if( msg && *msg )
- message = msg;
-}
-
-dmh_exception::~dmh_exception() throw()
-{}
-
-const char* dmh_exception::what() const throw()
-{
- return message;
-}
-
/* Constructors serve to initialise the message handler,
* simply creating the class instance, and storing the specified
* program name within it.
*/
dmhTypeGeneric::dmhTypeGeneric( const char* name ):progname( name ){}
dmhTypeTTY::dmhTypeTTY( const char* name ):dmhTypeGeneric( name ){}
-dmhTypeGUI::dmhTypeGUI( const char* name ):dmhTypeGeneric( name ){}
/* This pointer stores the address of the message handler
* class instance, after initialisation.
*/
static dmhTypeGeneric *dmh = NULL;
+#define client GetModuleHandle( NULL )
+static inline dmhTypeGeneric *dmh_init_gui( const char *progname )
+{
+ /* Stub function to support run-time binding of a client-provided
+ * implementation for the DMH_SUBSYSTEM_GUI class methods.
+ */
+ typedef dmhTypeGeneric *(*init_hook)( const char * );
+ init_hook do_init = (init_hook)(GetProcAddress( client, "dmh_init_gui" ));
+ return do_init ? do_init( progname ) : NULL;
+}
+
EXTERN_C void dmh_init( const dmh_class subsystem, const char *progname )
{
/* Public entry point for message handler initialisation...
/* No message handler has yet been initialised;
* passing the specified program name, select...
*/
- if( subsystem == DMH_SUBSYSTEM_GUI )
+ if( (subsystem == DMH_SUBSYSTEM_GUI)
/*
* ...a GUI class handler on demand...
*/
- dmh = new dmhTypeGUI( progname );
+ && ((dmh = dmh_init_gui( progname )) == NULL) )
+ /*
+ * ...but bail out, if this cannot be initialised...
+ */
+ throw dmh_exception( "DMH subsystem initialisation failed" );
else
/* ...otherwise, a console class handler by default.
return status;
}
-uint16_t dmhTypeGUI::control( const uint16_t request, const uint16_t mask )
-{
- /* Select optional features of the GUI class message handler.
- *
- * FIXME: this is a stub; implementation to be provided.
- */
- return 0;
-}
-
-int dmhTypeGUI::notify( const dmh_severity code, const char *fmt, va_list argv )
-{
- /* Message dispatcher for GUI applications.
- *
- * FIXME: this is a stub; implementation to be provided.
- */
- return
- fprintf( stderr, "%s: *** ERROR *** DMH_SUBSYSTEM_GUI not yet implemented\n", progname );
-}
-
-int dmhTypeGUI::printf( const char *fmt, va_list argv )
-{
- /* Display arbitrary text messages via the diagnostic message handler.
- *
- * FIXME: this is a stub; implementation to be provided.
- */
- return notify( DMH_ERROR, fmt, argv );
-}
-
uint16_t dmhTypeTTY::control( const uint16_t request, const uint16_t mask )
{
/* Select optional features of the console class message handler.
* $Id$
*
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
- * Copyright (C) 2009, 2010, 2011, MinGW Project
+ * Copyright (C) 2009, 2010, 2011, 2012 MinGW.org Project
*
*
* This header file provides the public API declarations for the
EXTERN_C int dmh_notify( const dmh_severity, const char *fmt, ... );
EXTERN_C int dmh_printf( const char *fmt, ... );
-#define DMH_BEGIN_DIGEST (uint16_t)(0x0001U), ~(uint16_t)(0x0001U)
-#define DMH_END_DIGEST (uint16_t)(0x0100U), (uint16_t)(0x0000U)
+#define DMH_COMPILE_DIGEST (uint16_t)(0x0100U)
+#define DMH_DISPATCH_DIGEST (uint16_t)(0x0200U)
+
+#define DMH_DIGEST_MASK (DMH_COMPILE_DIGEST | DMH_DISPATCH_DIGEST)
+#define DMH_BEGIN_DIGEST (DMH_COMPILE_DIGEST), ~(DMH_DIGEST_MASK)
+#define DMH_END_DIGEST (DMH_DISPATCH_DIGEST), ~(DMH_DIGEST_MASK)
+
+#define DMH_SEVERITY_MASK (DMH_INFO | DMH_WARNING | DMH_ERROR | DMH_FATAL)
EXTERN_C uint16_t dmh_control( const uint16_t, const uint16_t );
--- /dev/null
+#ifndef DMHCORE_H
+/*
+ * dmhcore.h
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2009, 2012, MinGW.org Project
+ *
+ *
+ * Declaration of the classes on which the implementation of the
+ * diagnostic message handling subsystem is based.
+ *
+ *
+ * This is free software. Permission is granted to copy, modify and
+ * redistribute this software, under the provisions of the GNU General
+ * Public License, Version 3, (or, at your option, any later version),
+ * as published by the Free Software Foundation; see the file COPYING
+ * for licensing details.
+ *
+ * Note, in particular, that this software is provided "as is", in the
+ * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
+ * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
+ * PARTICULAR PURPOSE. Under no circumstances will the author, or the
+ * MinGW Project, accept liability for any damages, however caused,
+ * arising from the use of this software.
+ *
+ */
+#define DMHCORE_H 1
+
+#include "dmh.h"
+
+class dmhTypeGeneric
+{
+ /* Abstract base class, from which message handlers are derived.
+ */
+ public:
+ dmhTypeGeneric( const char* );
+ virtual uint16_t control( const uint16_t, const uint16_t ) = 0;
+ virtual int notify( const dmh_severity, const char*, va_list ) = 0;
+ virtual int printf( const char*, va_list ) = 0;
+
+ protected:
+ const char *progname;
+};
+
+#endif /* DMHCORE_H: $RCSfile$: end of file */
--- /dev/null
+/*
+ * guidmh.cpp
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2009, 2010, 2011, 2012, MinGW.org Project
+ *
+ *
+ * Implementation of the GUI specific API for the DMH_SUBSYSTEM_GUI
+ * diagnostic message handling subsystem.
+ *
+ *
+ * This is free software. Permission is granted to copy, modify and
+ * redistribute this software, under the provisions of the GNU General
+ * Public License, Version 3, (or, at your option, any later version),
+ * as published by the Free Software Foundation; see the file COPYING
+ * for licensing details.
+ *
+ * Note, in particular, that this software is provided "as is", in the
+ * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
+ * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
+ * PARTICULAR PURPOSE. Under no circumstances will the author, or the
+ * MinGW Project, accept liability for any damages, however caused,
+ * arising from the use of this software.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "dmhcore.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+class dmhTypeGUI: public dmhTypeGeneric
+{
+ /* Diagnostic message handler for use in GUI applications.
+ */
+ public:
+ dmhTypeGUI( const char* );
+ virtual uint16_t control( const uint16_t, const uint16_t );
+ virtual int notify( const dmh_severity, const char*, va_list );
+ virtual int printf( const char*, va_list );
+
+ private:
+ HWND owner; uint16_t mode;
+ char *msgbuf; size_t msglen;
+ int dispatch_message( int );
+};
+
+EXTERN_C
+dmhTypeGeneric *dmh_init_gui( const char * ) __declspec(dllexport);
+dmhTypeGeneric *dmh_init_gui( const char *progname )
+{
+ /* Hook required by the dmh_init() function, to support run-time
+ * binding of this DMH_SUBSYSTEM_GUI implementation.
+ */
+ return new dmhTypeGUI( progname );
+}
+
+/* Constructor serves to initialise the message handler,
+ * creating the class instance, and storing the specified
+ * program name within it.
+ */
+dmhTypeGUI::dmhTypeGUI( const char* name ):dmhTypeGeneric( name ),
+ /*
+ * This handler also requires initialisation of the
+ * message box content collector.
+ */
+ owner( NULL ), mode( 0 ), msgbuf( NULL ), msglen( 0 ){}
+
+uint16_t dmhTypeGUI::control( const uint16_t request, const uint16_t mask )
+{
+ /* Select optional features of the GUI class message handler...
+ */
+ if( request & DMH_DISPATCH_DIGEST )
+ /*
+ * ...and dispatch "flush" requests for messages which have
+ * been collected, when operating in "digest mode".
+ */
+ dispatch_message( msglen );
+ return mode = request | (mode & mask);
+}
+
+int dmhTypeGUI::notify( const dmh_severity code, const char *fmt, va_list argv )
+{
+ /* Message dispatcher for GUI applications; this formats messages
+ * for display within a conventional MessageBox dialogue.
+ */
+ int newlen = 1 + vsnprintf( NULL, 0, fmt, argv );
+ if( mode & DMH_COMPILE_DIGEST )
+ {
+ /* The message handler is operating in "digest mode"; individual
+ * messages are collected into a dynamically extensible buffer,
+ * until a control request flushes the entire collection to a
+ * single MessageBox.
+ */
+ char *newbuf;
+ if( (newbuf = (char *)(realloc( msgbuf, newlen + msglen ))) != NULL )
+ {
+ /* The message buffer has been successfully extended
+ * to accommodate the incoming message...
+ */
+ if( (mode & DMH_SEVERITY_MASK) < code )
+ /*
+ * Adjust the severity code to match the maximum
+ * of all messages currently collected...
+ */
+ mode = code | (mode & ~DMH_SEVERITY_MASK);
+
+ /* ...and append the text of the incoming message
+ * to the buffered collection.
+ */
+ msglen += vsprintf( (msgbuf = newbuf) + msglen, fmt, argv );
+ }
+ }
+ else if( (msgbuf = (char *)(malloc( newlen ))) != NULL )
+ {
+ /* The handler is operating in "one shot" mode; record
+ * the severity of the incoming message and dispatch it
+ * immediately, in its own separate MessageBox.
+ */
+ mode = code | (mode & ~DMH_SEVERITY_MASK);
+ return dispatch_message( vsprintf( msgbuf, fmt, argv ) );
+ }
+}
+
+int dmhTypeGUI::dispatch_message( int len )
+{
+ /* Helper used by both the control() and notify() methods,
+ * for dispatching messages, either individually or as a
+ * "digest mode" collection, to a MessageBox.
+ */
+ if( msgbuf != NULL )
+ {
+ /* The MessageBox will exhibit only an "OK" button...
+ */
+ int status = MB_OK;
+ switch( mode & DMH_SEVERITY_MASK )
+ {
+ /* ...and will be adorned, as appropriate to the
+ * recorded message severity, with...
+ */
+ case DMH_INFO:
+ /* ...an icon which is indicative of an
+ * informational message...
+ */
+ status |= MB_ICONINFORMATION;
+ break;
+
+ case DMH_WARNING:
+ /* ...a warning message...
+ */
+ status |= MB_ICONWARNING;
+ break;
+
+ default:
+ /* ...or, if neither of the above is
+ * appropriate, an error message.
+ */
+ status |= MB_ICONERROR;
+ }
+ if( owner == NULL )
+ /*
+ * The owner window has yet to be identified; try to match
+ * it, on the basis of the window class name, to the top
+ * level application window.
+ */
+ owner = FindWindow( progname, NULL );
+
+ /* Dispatch the message...
+ */
+ MessageBox( owner, msgbuf, progname, status );
+
+ /* ...then release the heap memory used to format it.
+ */
+ free( (void *)(msgbuf) );
+ msgbuf = NULL; msglen = 0;
+ }
+ /* Always return the number of characters in the message,
+ * as notified by the calling method.
+ */
+ return len;
+}
+
+int dmhTypeGUI::printf( const char *fmt, va_list argv )
+{
+ /* Display arbitrary text messages via the diagnostic message handler.
+ *
+ * FIXME: this is a stub; ideally, we would like to emulate
+ * console behaviour for displaying the message stream, but
+ * until a formal implementation can be provided, we simply
+ * emit each message in its own informational MessageBox.
+ */
+ return notify( DMH_INFO, fmt, argv );
+}
+
+/* $RCSfile$: end of file */
*/
#include "guimain.h"
#include "pkglock.h"
+#include "dmh.h"
using WTK::StringResource;
using WTK::WindowClassMaker;
{
/* We've acquired the lock; we may now proceed to create an
* instance of the mingw-get GUI application window.
- *
- * First, register the window class name...
- */
- WindowClassMaker( Instance, ID_MAIN_WINDOW ).Register(
- StringResource( Instance, ID_MAIN_WINDOW_CLASS )
- );
-
- /* ...and then proceed to create the window itself.
*/
AppWindowMaker MainWindow( Instance );
AppWindow = MainWindow.Create(
- StringResource( Instance, ID_MAIN_WINDOW_CLASS ),
- MainWindowCaption
+ StringResource( Instance, ID_MAIN_WINDOW_CLASS ), MainWindowCaption
);
/* Show the window and paint its initial contents...
return pkgRelease( lock, MainWindowCaption, MainWindow.Invoked() );
}
}
+ catch( dmh_exception &e )
+ {
+ /* Here, we handle any fatal exception which has been raised
+ * and identified by the diagnostic message handler...
+ */
+ MessageBox( NULL, e.what(), "WinMain", MB_ICONERROR );
+ return EXIT_FAILURE;
+ }
catch( runtime_error &e )
{
- /* Here, we diagnose any error which was captured during the
- * creation of the application's window hierarchy, or processing
- * of its message loop...
+ /* ...while here, we diagnose any other error which was captured
+ * during the creation of the application's window hierarchy, or
+ * processing of its message loop...
*/
MessageBox( NULL, e.what(), "WinMain", MB_ICONERROR );
return EXIT_FAILURE;
}
catch(...)
- { /* ...while here, we diagnose any other error which we weren't
+ { /* ...and here, we diagnose any other error which we weren't
* able to explicitly identify.
*/
MessageBox( NULL, "Unknown exception", "WinMain", MB_ICONERROR );
pkgData( NULL ), DefaultFont( (HFONT)(GetStockObject( DEFAULT_GUI_FONT )) ){}
~AppWindowMaker(){ /* delete ChildWindows; */ DeleteObject( DefaultFont ); }
+ HWND Create( const char *, const char * );
inline long AdjustLayout(){ return OnSize( 0, 0, 0 ); }
* $Id$
*
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
- * Copyright (C) 2012, MinGW Project
+ * Copyright (C) 2012, MinGW.org Project
*
*
* Implementation of the layout controller for the main mingw-get
*
*/
#include "guimain.h"
+#include "dmh.h"
using WTK::GenericDialogue;
using WTK::HorizontalSashWindowMaker;
static const double VSASH_INIT_POS = 0.30;
static const double VSASH_MAX_POS = 0.60;
+HWND AppWindowMaker::Create( const char *class_name, const char *caption )
+{
+ /* A thin wrapper around the generic main window Create() function;
+ * it initialises the diagnostic message handler, and registers the
+ * requisite window class, before delegating creation of the main
+ * application window to the generic function.
+ */
+ dmh_init( DMH_SUBSYSTEM_GUI, class_name );
+ WTK::WindowClassMaker( AppInstance, ID_MAIN_WINDOW ).Register( class_name );
+ return WTK::MainWindowMaker::Create( class_name, caption );
+}
+
long AppWindowMaker::OnCreate()
{
/* Handler for creation of the top-level application window;