OSDN Git Service

Add initial working GUI mode DMH class implementation.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 29 Sep 2012 21:46:44 +0000 (22:46 +0100)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Fri, 5 Oct 2012 10:38:19 +0000 (11:38 +0100)
ChangeLog
Makefile.in
src/dmh.cpp
src/dmh.h
src/dmhcore.h [new file with mode: 0644]
src/guidmh.cpp [new file with mode: 0644]
src/guimain.cpp
src/guimain.h
src/pkgview.cpp

index e7a7951..5f082a4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,46 @@
+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.
index ec9be79..1f41fca 100644 (file)
@@ -90,7 +90,8 @@ CLI_EXE_OBJECTS  =   \
    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
 
index dc67ce9..91bca19 100644 (file)
@@ -4,10 +4,11 @@
  * $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.
    */
@@ -58,49 +69,29 @@ class dmhTypeTTY : public dmhTypeGeneric
     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...
@@ -113,11 +104,15 @@ EXTERN_C void dmh_init( const dmh_class subsystem, const char *progname )
     /* 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.
@@ -141,34 +136,6 @@ int abort_if_fatal( const dmh_severity code, int status )
   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.
index 74c08cd..aa86696 100644 (file)
--- a/src/dmh.h
+++ b/src/dmh.h
@@ -5,7 +5,7 @@
  * $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
@@ -60,8 +60,14 @@ EXTERN_C void dmh_init( const dmh_class, const char* );
 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 );
 
diff --git a/src/dmhcore.h b/src/dmhcore.h
new file mode 100644 (file)
index 0000000..46b58f8
--- /dev/null
@@ -0,0 +1,47 @@
+#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 */
diff --git a/src/guidmh.cpp b/src/guidmh.cpp
new file mode 100644 (file)
index 0000000..32aed2d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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 */
index 7cfc4c2..24344b8 100644 (file)
@@ -27,6 +27,7 @@
  */
 #include "guimain.h"
 #include "pkglock.h"
+#include "dmh.h"
 
 using WTK::StringResource;
 using WTK::WindowClassMaker;
@@ -75,19 +76,10 @@ int APIENTRY WinMain
     {
       /* 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...
@@ -102,17 +94,25 @@ int APIENTRY WinMain
       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 );
index d6a4d11..b807959 100644 (file)
@@ -90,6 +90,7 @@ class AppWindowMaker: public WTK::MainWindowMaker
     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 ); }
 
 
index 3441fe9..a04bbb4 100644 (file)
@@ -4,7 +4,7 @@
  * $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
@@ -26,6 +26,7 @@
  *
  */
 #include "guimain.h"
+#include "dmh.h"
 
 using WTK::GenericDialogue;
 using WTK::HorizontalSashWindowMaker;
@@ -54,6 +55,18 @@ static const double VSASH_MIN_POS = 0.25;
 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;