1. wxThread changes (detached/joinable) for MSW and docs updates

2. wxUSE_GUI=0 compilation for MSW (use vc6dll.t with tmake) and many small
   fixes related to this
3. an attempt to make wxLog more MT friendly
4. a small fix for wxRegConfig: it doesn't create empty unused keys any
   more (SetPath() would always create a key, now it's deleted if it was
   empty)


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4712 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1999-11-27 22:57:06 +00:00
parent aa9a4ae1a5
commit b568d04ffa
24 changed files with 1430 additions and 908 deletions

View File

@@ -239,7 +239,7 @@ iniconf.cpp M 16
joystick.cpp M joystick.cpp M
listbox.cpp M listbox.cpp M
listctrl.cpp M 32 listctrl.cpp M 32
main.cpp M main.cpp M B
mdi.cpp M mdi.cpp M
menu.cpp M menu.cpp M
menuitem.cpp M menuitem.cpp M
@@ -258,9 +258,9 @@ printdlg.cpp M
printwin.cpp M printwin.cpp M
radiobox.cpp M radiobox.cpp M
radiobut.cpp M radiobut.cpp M
regconf.cpp M 32 regconf.cpp M 32,B
region.cpp M region.cpp M
registry.cpp M 32 registry.cpp M 32,B
scrolbar.cpp M scrolbar.cpp M
settings.cpp M settings.cpp M
slider95.cpp M 32 slider95.cpp M 32
@@ -277,12 +277,12 @@ taskbar.cpp M 32
tbar95.cpp M 32 tbar95.cpp M 32
tbarmsw.cpp M 16 tbarmsw.cpp M 16
textctrl.cpp M textctrl.cpp M
thread.cpp M 32 thread.cpp M 32,B
timer.cpp M timer.cpp M
tooltip.cpp M 32 tooltip.cpp M 32
treectrl.cpp M 32 treectrl.cpp M 32
utils.cpp M utils.cpp M B
utilsexc.cpp M utilsexc.cpp M B
uuid.cpp M O uuid.cpp M O
wave.cpp M wave.cpp M
window.cpp M window.cpp M
@@ -292,7 +292,7 @@ gsocket.c M S
dialup.cpp U dialup.cpp U
fontenum.cpp U fontenum.cpp U
fontutil.cpp U fontutil.cpp U
threadpsx.cpp U threadpsx.cpp U B
utilsunx.cpp U B utilsunx.cpp U B
gsocket.c U gsocket.c U

View File

@@ -81,7 +81,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release" # PROP Intermediate_Dir "Release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W3 /Zi /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D WIN95=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WXMSW__" /D "__WIN32__" /Yu"wx/wxprec.h" /FD /c # ADD CPP /nologo /W3 /Zi /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D wxUSE_GUI=1 /D WIN95=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WXMSW__" /D "__WIN32__" /Yu"wx/wxprec.h" /FD /c
# ADD BASE RSC /l 0x409 # ADD BASE RSC /l 0x409
# ADD RSC /l 0x409 # ADD RSC /l 0x409
BSC32=bscmake.exe BSC32=bscmake.exe
@@ -104,7 +104,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug" # PROP Intermediate_Dir "Debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W4 /Zi /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D DEBUG=1 /D WXDEBUG=1 /D "__WXDEBUG__" /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WIN32__" /D "__WXMSW__" /Fr /Yu"wx/wxprec.h" /FD /c # ADD CPP /nologo /W4 /Zi /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D DEBUG=1 /D WXDEBUG=1 /D "__WXDEBUG__" /D wxUSE_GUI=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WIN32__" /D "__WXMSW__" /Fr /Yu"wx/wxprec.h" /FD /c
# ADD BASE RSC /l 0x409 # ADD BASE RSC /l 0x409
# ADD RSC /l 0x409 # ADD RSC /l 0x409
BSC32=bscmake.exe BSC32=bscmake.exe

145
distrib/msw/tmake/vc6base.t Normal file
View File

@@ -0,0 +1,145 @@
#!#############################################################################
#! File: vc6base.t
#! Purpose: tmake template file from which wxBase.dsp is generated by running
#! tmake -t vc6base wxwin.pro -o wxBase.dsp
#! Author: Vadim Zeitlin
#! Created: 27.11.99
#! Version: $Id$
#!#############################################################################
#${
#! include the code which parses filelist.txt file and initializes
#! %wxCommon, %wxGeneric and %wxMSW hashes.
IncludeTemplate("filelist.t");
#! now transform these hashes into $project tags
foreach $file (sort keys %wxCommon) {
next if $wxCommon{$file} !~ /\bB\b/;
my $tag = $file =~ /\.c$/ ? "WXCSRCS" : "WXCOMMONSRCS";
$project{$tag} .= $file . " "
}
foreach $file (sort keys %wxMSW) {
next if $wxMSW{$file} !~ /\bB\b/;
my $tag = $file =~ /\.c$/ ? "WXMSWCSRCS" : "WXMSWSRCS";
$project{$tag} .= $file . " "
}
foreach $file (sort keys %wxBase) {
my $tag = $file =~ /\.c$/ ? "WXCSRCS" : "WXCOMMONSRCS";
$project{$tag} .= $file . " "
}
#$}
# Microsoft Developer Studio Project File - Name="wxBase" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=wxBase - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "wxBase.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "wxBase.mak" CFG="wxBase - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "wxBase - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "wxBase - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "wxBase - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W3 /Zi /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D wxUSE_GUI=0 /D WIN95=1 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WXMSW__" /D "__WIN32__" /Yu"wx/wxprec.h" /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "wxBase - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W4 /Zi /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D DEBUG=1 /D WXDEBUG=1 /D "__WXDEBUG__" /D wxUSE_GUI=0 /D "__WIN95__" /D "WIN32" /D "_WIN32" /D WINVER=0x400 /D "__WINDOWS__" /D "__WIN32__" /D "__WXMSW__" /Fr /Yu"wx/wxprec.h" /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo /o"lib/wxBase.bsc"
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "wxBase - Win32 Release"
# Name "wxBase - Win32 Debug"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\src\msw\dummy.cpp
# ADD CPP /Yc"wx/wxprec.h"
# End Source File
#$ ExpandGlue("WXCOMMONSRCS", "# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# End Source File\n");
#$ ExpandGlue("WXMSWSRCS", "# Begin Source File\n\nSOURCE=.\\src\\msw\\", "\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\msw\\", "\n# End Source File\n");
#$ ExpandGlue("WXCSRCS", "# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n");
#$ ExpandGlue("WXMSWCSRCS", "# Begin Source File\n\nSOURCE=.\\src\\msw\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n# Begin Source File\n\nSOURCE=.\\src\\common\\", "\n# SUBTRACT CPP /YX /Yc /Yu\n# End Source File\n");
# Begin Source File
SOURCE=.\src\common\y_tab.c
!IF "$(CFG)" == "wxBase - Win32 Release"
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "wxBase - Win32 Debug"
# ADD CPP /W1
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# End Target
# End Project

View File

@@ -83,7 +83,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /YX /FD /c # ADD BASE CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /c # ADD CPP /nologo /MT /W4 /GX /O2 /I "$(wx)\include" /I "$(wx)\src\zlib" /D "NDEBUG" /D wxUSE_GUI=1 /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -109,7 +109,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /YX /FD /GZ /c # ADD BASE CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /ZI /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D "__WXDEBUG__" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /GZ /c # ADD CPP /nologo /MTd /W4 /Gm /ZI /Od /I "$(wx)\include" /I "$(wx)\src\zlib" /D "_DEBUG" /D "__WXDEBUG__" /D wxUSE_GUI=1 /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "WXWINDLL_EXPORTS" /D "__WXMSW__" /D "__WIN95__" /D "__WINDOWS__" /D "__WIN32__" /D "WXMAKINGDLL" /Yu"wx/wxprec.h" /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"

View File

@@ -282,7 +282,10 @@ protected:
#include "wx/stubs/app.h" #include "wx/stubs/app.h"
#endif #endif
#else // !GUI #else // !GUI
typedef wxAppBase wxApp; // can't use typedef because wxApp forward declared as a class
class WXDLLEXPORT wxApp : public wxAppBase
{
};
#endif // GUI/!GUI #endif // GUI/!GUI
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -322,13 +325,13 @@ inline void WXDLLEXPORT wxPostEvent(wxEvtHandler *dest, wxEvent& event)
dest->AddPendingEvent(event); dest->AddPendingEvent(event);
} }
#endif // wxUSE_GUI/!wxUSE_GUI #endif // wxUSE_GUI
// console applications may avoid using DECLARE_APP and IMPLEMENT_APP macros // console applications may avoid using DECLARE_APP and IMPLEMENT_APP macros
// and call these functions instead at the program startup and termination // and call these functions instead at the program startup and termination
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
#if wxUSE_NOGUI #if !wxUSE_GUI
// initialize the library (may be called as many times as needed, but each // initialize the library (may be called as many times as needed, but each
// call to wxInitialize() must be matched by wxUninitialize()) // call to wxInitialize() must be matched by wxUninitialize())
@@ -338,7 +341,7 @@ extern bool WXDLLEXPORT wxInitialize();
// wxUninitialize() // wxUninitialize()
extern void WXDLLEXPORT wxUninitialize(); extern void WXDLLEXPORT wxUninitialize();
#endif // wxUSE_NOGUI #endif // !wxUSE_GUI
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// macros for dynamic creation of the application object // macros for dynamic creation of the application object

View File

@@ -43,6 +43,8 @@ static const double pt2mm = (1/(METRIC_CONVERSION_CONSTANT*72));
// standard icons from the resources // standard icons from the resources
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#if wxUSE_GUI
WXDLLEXPORT_DATA(extern HICON) wxSTD_FRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxSTD_FRAME_ICON;
WXDLLEXPORT_DATA(extern HICON) wxSTD_MDIPARENTFRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxSTD_MDIPARENTFRAME_ICON;
WXDLLEXPORT_DATA(extern HICON) wxSTD_MDICHILDFRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxSTD_MDICHILDFRAME_ICON;
@@ -51,6 +53,8 @@ WXDLLEXPORT_DATA(extern HICON) wxDEFAULT_MDIPARENTFRAME_ICON;
WXDLLEXPORT_DATA(extern HICON) wxDEFAULT_MDICHILDFRAME_ICON; WXDLLEXPORT_DATA(extern HICON) wxDEFAULT_MDICHILDFRAME_ICON;
WXDLLEXPORT_DATA(extern HFONT) wxSTATUS_LINE_FONT; WXDLLEXPORT_DATA(extern HFONT) wxSTATUS_LINE_FONT;
#endif // wxUSE_GUI
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// define things missing from some compilers' headers // define things missing from some compilers' headers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -268,9 +272,13 @@ private:
// global data // global data
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#if 0 // where is this??
// The MakeProcInstance version of the function wxSubclassedGenericControlProc // The MakeProcInstance version of the function wxSubclassedGenericControlProc
WXDLLEXPORT_DATA(extern FARPROC) wxGenericControlSubClassProc; WXDLLEXPORT_DATA(extern FARPROC) wxGenericControlSubClassProc;
#endif // 0
WXDLLEXPORT_DATA(extern wxChar*) wxBuffer; WXDLLEXPORT_DATA(extern wxChar*) wxBuffer;
WXDLLEXPORT_DATA(extern HINSTANCE) wxhInstance; WXDLLEXPORT_DATA(extern HINSTANCE) wxhInstance;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -279,11 +287,13 @@ WXDLLEXPORT_DATA(extern HINSTANCE) wxhInstance;
extern "C" extern "C"
{ {
WXDLLEXPORT HINSTANCE wxGetInstance(); WXDLLEXPORT HINSTANCE wxGetInstance();
} }
WXDLLEXPORT void wxSetInstance(HINSTANCE hInst); WXDLLEXPORT void wxSetInstance(HINSTANCE hInst);
#if wxUSE_GUI
WXDLLEXPORT wxWindow* wxFindWinFromHandle(WXHWND hWnd); WXDLLEXPORT wxWindow* wxFindWinFromHandle(WXHWND hWnd);
WXDLLEXPORT void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font); WXDLLEXPORT void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font);
@@ -316,5 +326,7 @@ inline bool wxStyleHasBorder(long style)
wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0; wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0;
} }
#endif // wxUSE_GUI
#endif #endif
// _WX_PRIVATE_H_ // _WX_PRIVATE_H_

View File

@@ -187,6 +187,19 @@
} }
#endif #endif
// FindResource
#ifdef FindResource
#undef FindResource
inline HRSRC FindResource(HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType)
{
#ifdef _UNICODE
return FindResourceW(hModule, lpName, lpType);
#else
return FindResourceA(hModule, lpName, lpType);
#endif
}
#endif
// IsMaximized // IsMaximized
#ifdef IsMaximized #ifdef IsMaximized

View File

@@ -53,9 +53,16 @@ enum wxThreadError
wxTHREAD_NO_RESOURCE, // No resource left to create a new thread wxTHREAD_NO_RESOURCE, // No resource left to create a new thread
wxTHREAD_RUNNING, // The thread is already running wxTHREAD_RUNNING, // The thread is already running
wxTHREAD_NOT_RUNNING, // The thread isn't running wxTHREAD_NOT_RUNNING, // The thread isn't running
wxTHREAD_KILLED, // Thread we waited for had to be killed
wxTHREAD_MISC_ERROR // Some other error wxTHREAD_MISC_ERROR // Some other error
}; };
enum wxThreadKind
{
wxTHREAD_DETACHED,
wxTHREAD_JOINABLE
};
// defines the interval of priority // defines the interval of priority
enum enum
{ {
@@ -231,15 +238,18 @@ private:
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Thread management class // Thread class
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// FIXME Thread termination model is still unclear. Delete() should probably // there are two different kinds of threads: joinable and detached (default)
// have a timeout after which the thread must be Kill()ed. // ones. Only joinable threads can return a return code and only detached
// threads auto-delete themselves - the user should delete the joinable
// threads manually.
// NB: in the function descriptions the words "this thread" mean the thread // NB: in the function descriptions the words "this thread" mean the thread
// created by the wxThread object while "main thread" is the thread created // created by the wxThread object while "main thread" is the thread created
// during the process initialization (a.k.a. the GUI thread) // during the process initialization (a.k.a. the GUI thread)
class wxThreadInternal; class wxThreadInternal;
class WXDLLEXPORT wxThread class WXDLLEXPORT wxThread
{ {
@@ -266,34 +276,52 @@ public:
// NB: at least under MSW worker threads can not call ::wxSleep()! // NB: at least under MSW worker threads can not call ::wxSleep()!
static void Sleep(unsigned long milliseconds); static void Sleep(unsigned long milliseconds);
// default constructor // constructor only creates the C++ thread object and doesn't create (or
wxThread(); // start) the real thread
wxThread(wxThreadKind kind = wxTHREAD_DETACHED);
// functions that change the thread state: all these can only be called
// from _another_ thread (typically the thread that created this one, e.g.
// the main thread), not from the thread itself
// function that change the thread state
// create a new thread - call Run() to start it // create a new thread - call Run() to start it
wxThreadError Create(); wxThreadError Create();
// starts execution of the thread - from the moment Run() is called the // starts execution of the thread - from the moment Run() is called
// execution of wxThread::Entry() may start at any moment, caller // the execution of wxThread::Entry() may start at any moment, caller
// shouldn't suppose that it starts after (or before) Run() returns. // shouldn't suppose that it starts after (or before) Run() returns.
wxThreadError Run(); wxThreadError Run();
// stops the thread if it's running and deletes the wxThread object // stops the thread if it's running and deletes the wxThread object if
// freeing its memory. This function should also be called if the // this is a detached thread freeing its memory - otherwise (for
// Create() or Run() fails to free memory (otherwise it will be done by // joinable threads) you still need to delete wxThread object
// the thread itself when it terminates). The return value is the // yourself.
// thread exit code if the thread was gracefully terminated, 0 if it //
// wasn't running and -1 if an error occured. // this function only works if the thread calls TestDestroy()
ExitCode Delete(); // periodically - the thread will only be deleted the next time it
// does it!
//
// will fill the rc pointer with the thread exit code if it's !NULL
wxThreadError Delete(ExitCode *rc = (ExitCode *)NULL);
// waits for a joinable thread to finish and returns its exit code
//
// Returns (ExitCode)-1 on error (for example, if the thread is not
// joinable)
ExitCode Wait();
// kills the thread without giving it any chance to clean up - should // kills the thread without giving it any chance to clean up - should
// not be used in normal circumstances, use Delete() instead. It is a // not be used in normal circumstances, use Delete() instead. It is a
// dangerous function that should only be used in the most extreme // dangerous function that should only be used in the most extreme
// cases! The wxThread object is deleted by Kill() if thread was // cases!
// killed (i.e. no errors occured). //
// The wxThread object is deleted by Kill() if the thread is
// detachable, but you still have to delete it manually for joinable
// threads.
wxThreadError Kill(); wxThreadError Kill();
// pause a running thread // pause a running thread: as Delete(), this only works if the thread
// calls TestDestroy() regularly
wxThreadError Pause(); wxThreadError Pause();
// resume a paused thread // resume a paused thread
@@ -308,10 +336,6 @@ public:
// Get the current priority. // Get the current priority.
unsigned int GetPriority() const; unsigned int GetPriority() const;
// Get the thread ID - a platform dependent number which uniquely
// identifies a thread inside a process
unsigned long GetID() const;
// thread status inquiries // thread status inquiries
// Returns true if the thread is alive: i.e. running or suspended // Returns true if the thread is alive: i.e. running or suspended
bool IsAlive() const; bool IsAlive() const;
@@ -320,11 +344,22 @@ public:
// Returns true if the thread is suspended // Returns true if the thread is suspended
bool IsPaused() const; bool IsPaused() const;
// is the thread of detached kind?
bool IsDetached() const { return m_isDetached; }
// Get the thread ID - a platform dependent number which uniquely
// identifies a thread inside a process
unsigned long GetId() const;
// called when the thread exits - in the context of this thread // called when the thread exits - in the context of this thread
// //
// NB: this function will not be called if the thread is Kill()ed // NB: this function will not be called if the thread is Kill()ed
virtual void OnExit() { } virtual void OnExit() { }
// dtor is public, but the detached threads should never be deleted - use
// Delete() instead (or leave the thread terminate by itself)
virtual ~wxThread();
protected: protected:
// Returns TRUE if the thread was asked to terminate: this function should // Returns TRUE if the thread was asked to terminate: this function should
// be called by the thread from time to time, otherwise the main thread // be called by the thread from time to time, otherwise the main thread
@@ -332,14 +367,7 @@ protected:
bool TestDestroy(); bool TestDestroy();
// exits from the current thread - can be called only from this thread // exits from the current thread - can be called only from this thread
void Exit(void *exitcode = 0); void Exit(ExitCode exitcode = 0);
// destructor is private - user code can't delete thread objects, they will
// auto-delete themselves (and thus must be always allocated on the heap).
// Use Delete() or Kill() instead.
//
// NB: derived classes dtors shouldn't be public neither!
virtual ~wxThread();
// entry point for the thread - called by Run() and executes in the context // entry point for the thread - called by Run() and executes in the context
// of this thread. // of this thread.
@@ -357,6 +385,9 @@ private:
// protects access to any methods of wxThreadInternal object // protects access to any methods of wxThreadInternal object
wxCriticalSection m_critsect; wxCriticalSection m_critsect;
// true if the thread is detached, false if it is joinable
bool m_isDetached;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -369,9 +400,9 @@ void WXDLLEXPORT wxMutexGuiLeave();
// macros for entering/leaving critical sections which may be used without // macros for entering/leaving critical sections which may be used without
// having to take them inside "#if wxUSE_THREADS" // having to take them inside "#if wxUSE_THREADS"
#define wxENTER_CRIT_SECT(cs) (cs)->Enter() #define wxENTER_CRIT_SECT(cs) (cs).Enter()
#define wxLEAVE_CRIT_SECT(cs) (cs)->Leave() #define wxLEAVE_CRIT_SECT(cs) (cs).Leave()
#define wxCRIT_SECT_LOCKER(name, cs) wxCriticalSectionLocker name(*cs) #define wxCRIT_SECT_LOCKER(name, cs) wxCriticalSectionLocker name(cs)
#else // !wxUSE_THREADS #else // !wxUSE_THREADS

View File

@@ -172,7 +172,7 @@ WXDLLEXPORT int wxKill(long pid, wxSignal sig = wxSIGTERM);
// If no command then just the shell // If no command then just the shell
WXDLLEXPORT bool wxShell(const wxString& command = wxEmptyString); WXDLLEXPORT bool wxShell(const wxString& command = wxEmptyString);
// Sleep for nSecs seconds under UNIX, do nothing under Windows // Sleep for nSecs seconds
WXDLLEXPORT void wxSleep(int nSecs); WXDLLEXPORT void wxSleep(int nSecs);
// Sleep for a given amount of milliseconds // Sleep for a given amount of milliseconds

View File

@@ -30,8 +30,8 @@
// what to test? // what to test?
//#define TEST_ARRAYS //#define TEST_ARRAYS
#define TEST_LOG //#define TEST_LOG
//#define TEST_THREADS #define TEST_THREADS
// ============================================================================ // ============================================================================
// implementation // implementation
@@ -47,30 +47,51 @@
static size_t gs_counter = (size_t)-1; static size_t gs_counter = (size_t)-1;
static wxCriticalSection gs_critsect; static wxCriticalSection gs_critsect;
static wxCondition gs_cond;
class MyThread : public wxThread class MyJoinableThread : public wxThread
{ {
public: public:
MyThread(char ch); MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE)
{ m_n = n; Create(); }
// thread execution starts here // thread execution starts here
virtual void *Entry(); virtual ExitCode Entry();
private:
size_t m_n;
};
wxThread::ExitCode MyJoinableThread::Entry()
{
unsigned long res = 1;
for ( size_t n = 1; n < m_n; n++ )
{
res *= n;
// it's a loooong calculation :-)
Sleep(100);
}
return (ExitCode)res;
}
class MyDetachedThread : public wxThread
{
public:
MyDetachedThread(char ch) { m_ch = ch; Create(); }
// thread execution starts here
virtual ExitCode Entry();
// and stops here // and stops here
virtual void OnExit(); virtual void OnExit();
public: private:
char m_ch; char m_ch;
}; };
MyThread::MyThread(char ch) wxThread::ExitCode MyDetachedThread::Entry()
{
m_ch = ch;
Create();
}
void *MyThread::Entry()
{ {
{ {
wxCriticalSectionLocker lock(gs_critsect); wxCriticalSectionLocker lock(gs_critsect);
@@ -80,7 +101,8 @@ void *MyThread::Entry()
gs_counter++; gs_counter++;
} }
for ( size_t n = 0; n < 10; n++ ) static const size_t nIter = 10;
for ( size_t n = 0; n < nIter; n++ )
{ {
if ( TestDestroy() ) if ( TestDestroy() )
break; break;
@@ -91,13 +113,14 @@ void *MyThread::Entry()
wxThread::Sleep(100); wxThread::Sleep(100);
} }
return NULL; return 0;
} }
void MyThread::OnExit() void MyDetachedThread::OnExit()
{ {
wxCriticalSectionLocker lock(gs_critsect); wxCriticalSectionLocker lock(gs_critsect);
gs_counter--; if ( !--gs_counter )
gs_cond.Signal();
} }
#endif // TEST_THREADS #endif // TEST_THREADS
@@ -178,33 +201,44 @@ int main(int argc, char **argv)
printf(msg); printf(msg);
// but this one will because log functions use fixed size buffer // but this one will because log functions use fixed size buffer
wxLogMessage("A very very long message 2: '%s', the end!\n", s.c_str()); // (note that it doesn't need '\n' at the end neither - will be added
// by wxLog anyhow)
wxLogMessage("A very very long message 2: '%s', the end!", s.c_str());
#endif // TEST_LOG #endif // TEST_LOG
#ifdef TEST_THREADS #ifdef TEST_THREADS
puts("Testing detached threads...");
static const size_t nThreads = 3; static const size_t nThreads = 3;
MyThread *threads[nThreads]; MyDetachedThread *threads[nThreads];
size_t n; size_t n;
for ( n = 0; n < nThreads; n++ ) for ( n = 0; n < nThreads; n++ )
{ {
threads[n] = new MyThread('+' + n); threads[n] = new MyDetachedThread('A' + n);
}
threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
for ( n = 0; n < nThreads; n++ )
{
threads[n]->Run(); threads[n]->Run();
} }
// wait until all threads terminate // wait until all threads terminate
for ( ;; ) wxMutex mutex;
{ mutex.Lock();
wxCriticalSectionLocker lock(gs_critsect); gs_cond.Wait(mutex);
if ( !gs_counter ) mutex.Unlock();
break;
}
puts("\nThat's all, folks!"); puts("\n\nTesting a joinable thread used for a loooong calculation...");
for ( n = 0; n < nThreads; n++ ) // calc 10! in the background
{ MyJoinableThread thread(10);
threads[n]->Delete(); thread.Run();
}
printf("\nThread terminated with exit code %lu.\n",
(unsigned long)thread.Wait());
#endif // TEST_THREADS #endif // TEST_THREADS
wxUninitialize(); wxUninitialize();

View File

@@ -150,7 +150,7 @@ void *MyThread::Entry()
wxString text; wxString text;
text.Printf("Thread 0x%x started (priority = %d).\n", text.Printf("Thread 0x%x started (priority = %d).\n",
GetID(), GetPriority()); GetId(), GetPriority());
WriteText(text); WriteText(text);
for ( m_count = 0; m_count < 10; m_count++ ) for ( m_count = 0; m_count < 10; m_count++ )
@@ -159,14 +159,14 @@ void *MyThread::Entry()
if ( TestDestroy() ) if ( TestDestroy() )
break; break;
text.Printf("[%u] Thread 0x%x here.\n", m_count, GetID()); text.Printf("[%u] Thread 0x%x here.\n", m_count, GetId());
WriteText(text); WriteText(text);
// wxSleep() can't be called from non-GUI thread! // wxSleep() can't be called from non-GUI thread!
wxThread::Sleep(1000); wxThread::Sleep(1000);
} }
text.Printf("Thread 0x%x finished.\n", GetID()); text.Printf("Thread 0x%x finished.\n", GetId());
WriteText(text); WriteText(text);
return NULL; return NULL;
@@ -266,17 +266,18 @@ MyThread *MyFrame::CreateThread()
void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
{ {
static wxString s_str; static long s_num = 10;
s_str = wxGetTextFromUser("How many threads to start: ",
"wxThread sample", s_num = wxGetNumberFromUser("How many threads to start: ", "",
s_str, this); "wxThread sample", s_num, 1, 10000, this);
if ( s_str.IsEmpty() ) if ( s_num == -1 )
return; {
s_num = 10;
size_t count, n;
sscanf(s_str, "%u", &count);
if ( count == 0 )
return; return;
}
size_t count = (size_t)s_num, n;
wxArrayThread threads; wxArrayThread threads;

View File

@@ -47,7 +47,7 @@
void wxAppBase::ProcessPendingEvents() void wxAppBase::ProcessPendingEvents()
{ {
// ensure that we're the only thread to modify the pending events list // ensure that we're the only thread to modify the pending events list
wxCRIT_SECT_LOCKER(locker, wxPendingEventsLocker); wxCRIT_SECT_LOCKER(locker, *wxPendingEventsLocker);
if ( !wxPendingEvents ) if ( !wxPendingEvents )
return; return;

View File

@@ -609,13 +609,13 @@ void wxEvtHandler::AddPendingEvent(wxEvent& event)
m_pendingEvents->Append(event2); m_pendingEvents->Append(event2);
wxENTER_CRIT_SECT(wxPendingEventsLocker); wxENTER_CRIT_SECT(*wxPendingEventsLocker);
if ( !wxPendingEvents ) if ( !wxPendingEvents )
wxPendingEvents = new wxList; wxPendingEvents = new wxList;
wxPendingEvents->Append(this); wxPendingEvents->Append(this);
wxLEAVE_CRIT_SECT(wxPendingEventsLocker); wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
wxWakeUpIdle(); wxWakeUpIdle();
} }
@@ -623,9 +623,9 @@ void wxEvtHandler::AddPendingEvent(wxEvent& event)
void wxEvtHandler::ProcessPendingEvents() void wxEvtHandler::ProcessPendingEvents()
{ {
#if defined(__VISAGECPP__) #if defined(__VISAGECPP__)
wxCRIT_SECT_LOCKER(locker, &m_eventsLocker);
#else
wxCRIT_SECT_LOCKER(locker, m_eventsLocker); wxCRIT_SECT_LOCKER(locker, m_eventsLocker);
#else
wxCRIT_SECT_LOCKER(locker, *m_eventsLocker);
#endif #endif
wxNode *node = m_pendingEvents->First(); wxNode *node = m_pendingEvents->First();

View File

@@ -30,7 +30,6 @@
#include "wx/module.h" #include "wx/module.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// global vars // global vars
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -48,6 +48,7 @@
#include "wx/utils.h" #include "wx/utils.h"
#include "wx/wxchar.h" #include "wx/wxchar.h"
#include "wx/log.h" #include "wx/log.h"
#include "wx/thread.h"
// other standard headers // other standard headers
#include <errno.h> #include <errno.h>
@@ -55,9 +56,7 @@
#include <time.h> #include <time.h>
#ifdef __WXMSW__ #ifdef __WXMSW__
#include <windows.h> #include "wx/msw/private.h" // includes windows.h for OutputDebugString
// Redefines OutputDebugString if necessary
#include "wx/msw/private.h"
#else //Unix #else //Unix
#include <signal.h> #include <signal.h>
#endif //Win/Unix #endif //Win/Unix
@@ -78,23 +77,36 @@
// ============================================================================ // ============================================================================
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// implementation of Log functions // globals
//
// NB: unfortunately we need all these distinct functions, we can't make them
// macros and not all compilers inline vararg functions.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// log functions can't allocate memory (LogError("out of memory...") should // log functions can't allocate memory (LogError("out of memory...") should
// work!), so we use a static buffer for all log messages // work!), so we use a static buffer for all log messages
#define LOG_BUFFER_SIZE (4096) #define LOG_BUFFER_SIZE (4096)
// static buffer for error messages (FIXME MT-unsafe) // static buffer for error messages
static wxChar s_szBuf[LOG_BUFFER_SIZE]; static wxChar s_szBuf[LOG_BUFFER_SIZE];
#if wxUSE_THREADS
// the critical section protecting the static buffer
static wxCriticalSection gs_csLogBuf;
#endif // wxUSE_THREADS
// ----------------------------------------------------------------------------
// implementation of Log functions
//
// NB: unfortunately we need all these distinct functions, we can't make them
// macros and not all compilers inline vararg functions.
// ----------------------------------------------------------------------------
// generic log function // generic log function
void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
{ {
if ( wxLog::GetActiveTarget() != NULL ) { if ( wxLog::GetActiveTarget() != NULL ) {
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
va_list argptr; va_list argptr;
va_start(argptr, szFormat); va_start(argptr, szFormat);
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
@@ -108,6 +120,8 @@ void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
void wxLog##level(const wxChar *szFormat, ...) \ void wxLog##level(const wxChar *szFormat, ...) \
{ \ { \
if ( wxLog::GetActiveTarget() != NULL ) { \ if ( wxLog::GetActiveTarget() != NULL ) { \
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \
\
va_list argptr; \ va_list argptr; \
va_start(argptr, szFormat); \ va_start(argptr, szFormat); \
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \
@@ -129,6 +143,8 @@ void wxLogVerbose(const wxChar *szFormat, ...)
{ {
wxLog *pLog = wxLog::GetActiveTarget(); wxLog *pLog = wxLog::GetActiveTarget();
if ( pLog != NULL && pLog->GetVerbose() ) { if ( pLog != NULL && pLog->GetVerbose() ) {
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
va_list argptr; va_list argptr;
va_start(argptr, szFormat); va_start(argptr, szFormat);
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
@@ -144,6 +160,8 @@ void wxLogVerbose(const wxChar *szFormat, ...)
void wxLog##level(const wxChar *szFormat, ...) \ void wxLog##level(const wxChar *szFormat, ...) \
{ \ { \
if ( wxLog::GetActiveTarget() != NULL ) { \ if ( wxLog::GetActiveTarget() != NULL ) { \
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); \
\
va_list argptr; \ va_list argptr; \
va_start(argptr, szFormat); \ va_start(argptr, szFormat); \
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \ wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); \
@@ -158,6 +176,8 @@ void wxLogVerbose(const wxChar *szFormat, ...)
wxLog *pLog = wxLog::GetActiveTarget(); wxLog *pLog = wxLog::GetActiveTarget();
if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) { if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) {
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
va_list argptr; va_list argptr;
va_start(argptr, szFormat); va_start(argptr, szFormat);
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
@@ -175,6 +195,8 @@ void wxLogVerbose(const wxChar *szFormat, ...)
// that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
// if both bits are set. // if both bits are set.
if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) { if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) {
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
va_list argptr; va_list argptr;
va_start(argptr, szFormat); va_start(argptr, szFormat);
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
@@ -207,6 +229,8 @@ void wxLogSysErrorHelper(long lErrCode)
void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
{ {
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
va_list argptr; va_list argptr;
va_start(argptr, szFormat); va_start(argptr, szFormat);
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
@@ -217,6 +241,8 @@ void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
{ {
wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
va_list argptr; va_list argptr;
va_start(argptr, szFormat); va_start(argptr, szFormat);
wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
@@ -361,15 +387,16 @@ void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t))
{ {
wxString str; wxString str;
TimeStamp(&str); TimeStamp(&str);
str << szString << wxT('\n'); str << szString;
fputs(str.mb_str(), m_fp); fputs(str.mb_str(), m_fp);
fputc(_T('\n'), m_fp);
fflush(m_fp); fflush(m_fp);
// under Windows, programs usually don't have stderr at all, so show the // under Windows, programs usually don't have stderr at all, so show the
// messages also under debugger // messages also under debugger - unless it's a console program
#ifdef __WXMSW__ #if defined(__WXMSW__) && wxUSE_GUI
OutputDebugString(str + wxT('\r')); OutputDebugString(str + wxT("\r\n"));
#endif // MSW #endif // MSW
} }

View File

@@ -771,6 +771,7 @@ bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
bool wxFileTypeImpl::GetIcon(wxIcon *icon) const bool wxFileTypeImpl::GetIcon(wxIcon *icon) const
{ {
#if wxUSE_GUI
if ( m_info ) { if ( m_info ) {
// we don't have icons in the fallback resources // we don't have icons in the fallback resources
return FALSE; return FALSE;
@@ -819,6 +820,8 @@ bool wxFileTypeImpl::GetIcon(wxIcon *icon) const
} }
// no such file type or no value or incorrect icon entry // no such file type or no value or incorrect icon entry
#endif // wxUSE_GUI
return FALSE; return FALSE;
} }

View File

@@ -200,7 +200,12 @@ extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len,
return iLen; return iLen;
#else // ANSI #else // ANSI
return wxVsnprintfA(buf, len, format, argptr); // vsnprintf() will not terminate the string with '\0' if there is not
// enough place, but we want the string to always be NUL terminated
int rc = wxVsnprintfA(buf, len - 1, format, argptr);
buf[len] = 0;
return rc;
#endif // Unicode/ANSI #endif // Unicode/ANSI
} }

View File

@@ -100,7 +100,6 @@ extern wxList WXDLLEXPORT wxPendingDelete;
extern void wxSetKeyboardHook(bool doIt); extern void wxSetKeyboardHook(bool doIt);
extern wxCursor *g_globalCursor; extern wxCursor *g_globalCursor;
HINSTANCE wxhInstance = 0;
MSG s_currentMsg; MSG s_currentMsg;
wxApp *wxTheApp = NULL; wxApp *wxTheApp = NULL;
@@ -1217,11 +1216,16 @@ void wxWakeUpIdle()
{ {
// Send the top window a dummy message so idle handler processing will // Send the top window a dummy message so idle handler processing will
// start up again. Doing it this way ensures that the idle handler // start up again. Doing it this way ensures that the idle handler
// wakes up in the right thread. // wakes up in the right thread (see also wxWakeUpMainThread() which does
// the same for the main app thread only)
wxWindow *topWindow = wxTheApp->GetTopWindow(); wxWindow *topWindow = wxTheApp->GetTopWindow();
if ( topWindow ) { if ( topWindow )
HWND hWnd = (HWND)topWindow->GetHWND(); {
::PostMessage(hWnd, WM_NULL, 0, 0); if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
{
// should never happen
wxLogLastError("PostMessage(WM_NULL)");
}
} }
} }
@@ -1250,17 +1254,6 @@ wxApp::GetStdIcon(int which) const
} }
} }
HINSTANCE wxGetInstance()
{
return wxhInstance;
}
void wxSetInstance(HINSTANCE hInst)
{
wxhInstance = hInst;
}
// For some reason, with MSVC++ 1.5, WinMain isn't linked in properly // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
// if in a separate file. So include it here to ensure it's linked. // if in a separate file. So include it here to ensure it's linked.
#if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__TWIN32__)) #if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__TWIN32__))

View File

@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: main.cpp // Name: msw/main.cpp
// Purpose: Main/DllMain // Purpose: Main/DllMain
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by:
@@ -9,28 +9,51 @@
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__ #ifdef __GNUG__
#pragma implementation #pragma implementation
#endif #endif
// For compilers that support precompilation, includes "wx.h". // For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h" #include "wx/wxprec.h"
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#pragma hdrstop #pragma hdrstop
#endif #endif
#include "wx/event.h" #include "wx/event.h"
#include "wx/app.h" #include "wx/app.h"
#include <windows.h>
#include "wx/msw/private.h"
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
HINSTANCE wxhInstance = 0;
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// various entry points
// ----------------------------------------------------------------------------
// May wish not to have a DllMain or WinMain, e.g. if we're programming // May wish not to have a DllMain or WinMain, e.g. if we're programming
// a Netscape plugin. // a Netscape plugin or if we're writing a console application
#ifndef NOMAIN #if wxUSE_GUI && !defined(NOMAIN)
// NT defines APIENTRY, 3.x not // NT defines APIENTRY, 3.x not
#if !defined(APIENTRY) #if !defined(APIENTRY)
#define APIENTRY FAR PASCAL #define APIENTRY FAR PASCAL
#endif #endif
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
@@ -96,7 +119,21 @@ BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
return TRUE; return TRUE;
} }
#endif #endif // _WINDLL
#endif #endif // !NOMAIN
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
HINSTANCE wxGetInstance()
{
return wxhInstance;
}
void wxSetInstance(HINSTANCE hInst)
{
wxhInstance = hInst;
}

View File

@@ -160,13 +160,25 @@ void wxRegConfig::SetPath(const wxString& strPath)
} }
// recombine path parts in one variable // recombine path parts in one variable
wxString strRegPath; wxString strOldPath = m_strPath, strRegPath;
m_strPath.Empty(); m_strPath.Empty();
for ( size_t n = 0; n < aParts.Count(); n++ ) { for ( size_t n = 0; n < aParts.Count(); n++ ) {
strRegPath << '\\' << aParts[n]; strRegPath << '\\' << aParts[n];
m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
} }
if ( m_strPath == strOldPath )
return;
// as we create the registry key when SetPath(key) is done, we can be left
// with plenty of empty keys if this was only done to try to read some value
// which, in fact, doesn't exist - to prevent this from happening we
// automatically delete the old key if it was empty
if ( m_keyLocal.IsEmpty() )
{
m_keyLocal.DeleteSelf();
}
// change current key(s) // change current key(s)
m_keyLocal.SetName(m_keyLocalRoot, strRegPath); m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath); m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);

View File

@@ -36,6 +36,19 @@
#include "wx/module.h" #include "wx/module.h"
#include "wx/thread.h" #include "wx/thread.h"
// must have this symbol defined to get _beginthread/_endthread declarations
#ifndef _MT
#define _MT
#endif
#ifdef __VISUALC__
#include <process.h>
#endif
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// the possible states of the thread ("=>" shows all possible transitions from // the possible states of the thread ("=>" shows all possible transitions from
// this state) // this state)
enum wxThreadState enum wxThreadState
@@ -48,32 +61,32 @@ enum wxThreadState
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// static variables // this module globals
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// TLS index of the slot where we store the pointer to the current thread // TLS index of the slot where we store the pointer to the current thread
static DWORD s_tlsThisThread = 0xFFFFFFFF; static DWORD gs_tlsThisThread = 0xFFFFFFFF;
// id of the main thread - the one which can call GUI functions without first // id of the main thread - the one which can call GUI functions without first
// calling wxMutexGuiEnter() // calling wxMutexGuiEnter()
static DWORD s_idMainThread = 0; static DWORD gs_idMainThread = 0;
// if it's FALSE, some secondary thread is holding the GUI lock // if it's FALSE, some secondary thread is holding the GUI lock
static bool s_bGuiOwnedByMainThread = TRUE; static bool gs_bGuiOwnedByMainThread = TRUE;
// critical section which controls access to all GUI functions: any secondary // critical section which controls access to all GUI functions: any secondary
// thread (i.e. except the main one) must enter this crit section before doing // thread (i.e. except the main one) must enter this crit section before doing
// any GUI calls // any GUI calls
static wxCriticalSection *s_critsectGui = NULL; static wxCriticalSection *gs_critsectGui = NULL;
// critical section which protects s_nWaitingForGui variable // critical section which protects gs_nWaitingForGui variable
static wxCriticalSection *s_critsectWaitingForGui = NULL; static wxCriticalSection *gs_critsectWaitingForGui = NULL;
// number of threads waiting for GUI in wxMutexGuiEnter() // number of threads waiting for GUI in wxMutexGuiEnter()
static size_t s_nWaitingForGui = 0; static size_t gs_nWaitingForGui = 0;
// are we waiting for a thread termination? // are we waiting for a thread termination?
static bool s_waitingForThread = FALSE; static bool gs_waitingForThread = FALSE;
// ============================================================================ // ============================================================================
// Windows implementation of thread classes // Windows implementation of thread classes
@@ -169,6 +182,46 @@ wxMutexError wxMutex::Unlock()
class wxConditionInternal class wxConditionInternal
{ {
public: public:
wxConditionInternal()
{
event = ::CreateEvent(
NULL, // default secutiry
FALSE, // not manual reset
FALSE, // nonsignaled initially
NULL // nameless event
);
if ( !event )
{
wxLogSysError(_("Can not create event object."));
}
waiters = 0;
}
bool Wait(wxMutex& mutex, DWORD timeout)
{
mutex.Unlock();
waiters++;
// FIXME this should be MsgWaitForMultipleObjects() as well probably
DWORD rc = ::WaitForSingleObject(event, timeout);
waiters--;
mutex.Lock();
return rc != WAIT_TIMEOUT;
}
~wxConditionInternal()
{
if ( event )
{
if ( !::CloseHandle(event) )
{
wxLogLastError("CloseHandle(event)");
}
}
}
HANDLE event; HANDLE event;
int waiters; int waiters;
}; };
@@ -176,59 +229,46 @@ public:
wxCondition::wxCondition() wxCondition::wxCondition()
{ {
p_internal = new wxConditionInternal; p_internal = new wxConditionInternal;
p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( !p_internal->event )
{
wxLogSysError(_("Can not create event object."));
}
p_internal->waiters = 0;
} }
wxCondition::~wxCondition() wxCondition::~wxCondition()
{ {
CloseHandle(p_internal->event); delete p_internal;
} }
void wxCondition::Wait(wxMutex& mutex) void wxCondition::Wait(wxMutex& mutex)
{ {
mutex.Unlock(); (void)p_internal->Wait(mutex, INFINITE);
p_internal->waiters++;
WaitForSingleObject(p_internal->event, INFINITE);
p_internal->waiters--;
mutex.Lock();
} }
bool wxCondition::Wait(wxMutex& mutex, bool wxCondition::Wait(wxMutex& mutex,
unsigned long sec, unsigned long sec,
unsigned long nsec) unsigned long nsec)
{ {
DWORD ret; return p_internal->Wait(mutex, sec*1000 + nsec/1000000);
mutex.Unlock();
p_internal->waiters++;
ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
p_internal->waiters--;
mutex.Lock();
return (ret != WAIT_TIMEOUT);
} }
void wxCondition::Signal() void wxCondition::Signal()
{ {
SetEvent(p_internal->event); // set the event to signaled: if a thread is already waiting on it, it will
// be woken up, otherwise the event will remain in the signaled state until
// someone waits on it. In any case, the system will return it to a non
// signalled state afterwards. If multiple threads are waiting, only one
// will be woken up.
if ( !::SetEvent(p_internal->event) )
{
wxLogLastError("SetEvent");
}
} }
void wxCondition::Broadcast() void wxCondition::Broadcast()
{ {
int i; // this works because all these threads are already waiting and so each
// SetEvent() inside Signal() is really a PulseEvent() because the event
for (i=0;i<p_internal->waiters;i++) // state is immediately returned to non-signaled
for ( int i = 0; i < p_internal->waiters; i++ )
{ {
if ( SetEvent(p_internal->event) == 0 ) Signal();
{
wxLogSysError(_("Couldn't change the state of event object."));
}
} }
} }
@@ -238,7 +278,7 @@ void wxCondition::Broadcast()
wxCriticalSection::wxCriticalSection() wxCriticalSection::wxCriticalSection()
{ {
wxASSERT_MSG( sizeof(CRITICAL_SECTION) == sizeof(m_buffer), wxASSERT_MSG( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer),
_T("must increase buffer size in wx/thread.h") ); _T("must increase buffer size in wx/thread.h") );
::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer); ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
@@ -276,6 +316,24 @@ public:
m_priority = WXTHREAD_DEFAULT_PRIORITY; m_priority = WXTHREAD_DEFAULT_PRIORITY;
} }
~wxThreadInternal()
{
Free();
}
void Free()
{
if ( m_hThread )
{
if ( !::CloseHandle(m_hThread) )
{
wxLogLastError("CloseHandle(thread)");
}
m_hThread = 0;
}
}
// create a new (suspended) thread (for the given thread object) // create a new (suspended) thread (for the given thread object)
bool Create(wxThread *thread); bool Create(wxThread *thread);
@@ -289,7 +347,7 @@ public:
wxThreadState GetState() const { return m_state; } wxThreadState GetState() const { return m_state; }
// thread priority // thread priority
void SetPriority(unsigned int priority) { m_priority = priority; } void SetPriority(unsigned int priority);
unsigned int GetPriority() const { return m_priority; } unsigned int GetPriority() const { return m_priority; }
// thread handle and id // thread handle and id
@@ -309,41 +367,38 @@ private:
DWORD wxThreadInternal::WinThreadStart(wxThread *thread) DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
{ {
// store the thread object in the TLS // store the thread object in the TLS
if ( !::TlsSetValue(s_tlsThisThread, thread) ) if ( !::TlsSetValue(gs_tlsThisThread, thread) )
{ {
wxLogSysError(_("Can not start thread: error writing TLS.")); wxLogSysError(_("Can not start thread: error writing TLS."));
return (DWORD)-1; return (DWORD)-1;
} }
DWORD ret = (DWORD)thread->Entry(); DWORD rc = (DWORD)thread->Entry();
// enter m_critsect before changing the thread state
thread->m_critsect.Enter();
bool wasCancelled = thread->p_internal->GetState() == STATE_CANCELED;
thread->p_internal->SetState(STATE_EXITED); thread->p_internal->SetState(STATE_EXITED);
thread->m_critsect.Leave();
thread->OnExit(); thread->OnExit();
// if the thread was cancelled (from Delete()), then it the handle is still
// needed there
if ( thread->IsDetached() && !wasCancelled )
{
// auto delete
delete thread; delete thread;
}
//else: the joinable threads handle will be closed when Wait() is done
return ret; return rc;
} }
bool wxThreadInternal::Create(wxThread *thread) void wxThreadInternal::SetPriority(unsigned int priority)
{ {
m_hThread = ::CreateThread m_priority = priority;
(
NULL, // default security
0, // default stack size
(LPTHREAD_START_ROUTINE) // thread entry point
wxThreadInternal::WinThreadStart, //
(LPVOID)thread, // parameter
CREATE_SUSPENDED, // flags
&m_tid // [out] thread id
);
if ( m_hThread == NULL )
{
wxLogSysError(_("Can't create thread"));
return FALSE;
}
// translate wxWindows priority to the Windows one // translate wxWindows priority to the Windows one
int win_priority; int win_priority;
@@ -363,10 +418,49 @@ bool wxThreadInternal::Create(wxThread *thread)
win_priority = THREAD_PRIORITY_NORMAL; win_priority = THREAD_PRIORITY_NORMAL;
} }
if ( ::SetThreadPriority(m_hThread, win_priority) == 0 ) if ( !::SetThreadPriority(m_hThread, win_priority) )
{ {
wxLogSysError(_("Can't set thread priority")); wxLogSysError(_("Can't set thread priority"));
} }
}
bool wxThreadInternal::Create(wxThread *thread)
{
// for compilers which have it, we should use C RTL function for thread
// creation instead of Win32 API one because otherwise we will have memory
// leaks if the thread uses C RTL (and most threads do)
#ifdef __VISUALC__
typedef unsigned (__stdcall *RtlThreadStart)(void *);
m_hThread = (HANDLE)_beginthreadex(NULL, 0,
(RtlThreadStart)
wxThreadInternal::WinThreadStart,
thread, CREATE_SUSPENDED,
(unsigned int *)&m_tid);
#else // !VC++
m_hThread = ::CreateThread
(
NULL, // default security
0, // default stack size
(LPTHREAD_START_ROUTINE) // thread entry point
wxThreadInternal::WinThreadStart, //
(LPVOID)thread, // parameter
CREATE_SUSPENDED, // flags
&m_tid // [out] thread id
);
#endif // VC++/!VC++
if ( m_hThread == NULL )
{
wxLogSysError(_("Can't create thread"));
return FALSE;
}
if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
{
SetPriority(m_priority);
}
return TRUE; return TRUE;
} }
@@ -406,7 +500,7 @@ bool wxThreadInternal::Resume()
wxThread *wxThread::This() wxThread *wxThread::This()
{ {
wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread); wxThread *thread = (wxThread *)::TlsGetValue(gs_tlsThisThread);
// be careful, 0 may be a valid return value as well // be careful, 0 may be a valid return value as well
if ( !thread && (::GetLastError() != NO_ERROR) ) if ( !thread && (::GetLastError() != NO_ERROR) )
@@ -421,16 +515,13 @@ wxThread *wxThread::This()
bool wxThread::IsMain() bool wxThread::IsMain()
{ {
return ::GetCurrentThreadId() == s_idMainThread; return ::GetCurrentThreadId() == gs_idMainThread;
} }
#ifdef Yield
#undef Yield
#endif
void wxThread::Yield() void wxThread::Yield()
{ {
// 0 argument to Sleep() is special // 0 argument to Sleep() is special and means to just give away the rest of
// our timeslice
::Sleep(0); ::Sleep(0);
} }
@@ -439,11 +530,28 @@ void wxThread::Sleep(unsigned long milliseconds)
::Sleep(milliseconds); ::Sleep(milliseconds);
} }
// ctor and dtor
// -------------
wxThread::wxThread(wxThreadKind kind)
{
p_internal = new wxThreadInternal();
m_isDetached = kind == wxTHREAD_DETACHED;
}
wxThread::~wxThread()
{
delete p_internal;
}
// create/start thread // create/start thread
// ------------------- // -------------------
wxThreadError wxThread::Create() wxThreadError wxThread::Create()
{ {
wxCriticalSectionLocker lock(m_critsect);
if ( !p_internal->Create(this) ) if ( !p_internal->Create(this) )
return wxTHREAD_NO_RESOURCE; return wxTHREAD_NO_RESOURCE;
@@ -460,6 +568,7 @@ wxThreadError wxThread::Run()
return wxTHREAD_RUNNING; return wxTHREAD_RUNNING;
} }
// the thread has just been created and is still suspended - let it run
return Resume(); return Resume();
} }
@@ -483,7 +592,23 @@ wxThreadError wxThread::Resume()
// stopping thread // stopping thread
// --------------- // ---------------
wxThread::ExitCode wxThread::Delete() wxThread::ExitCode wxThread::Wait()
{
// although under Windows we can wait for any thread, it's an error to
// wait for a detached one in wxWin API
wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
_T("can't wait for detached thread") );
ExitCode rc = (ExitCode)-1;
(void)Delete(&rc);
p_internal->Free();
return rc;
}
wxThreadError wxThread::Delete(ExitCode *pRc)
{ {
ExitCode rc = 0; ExitCode rc = 0;
@@ -491,24 +616,28 @@ wxThread::ExitCode wxThread::Delete()
if ( IsPaused() ) if ( IsPaused() )
Resume(); Resume();
HANDLE hThread = p_internal->GetHandle();
if ( IsRunning() ) if ( IsRunning() )
{ {
if ( IsMain() ) if ( IsMain() )
{ {
// set flag for wxIsWaitingForThread() // set flag for wxIsWaitingForThread()
s_waitingForThread = TRUE; gs_waitingForThread = TRUE;
#if wxUSE_GUI
wxBeginBusyCursor(); wxBeginBusyCursor();
#endif // wxUSE_GUI
} }
HANDLE hThread; // ask the thread to terminate
{ {
wxCriticalSectionLocker lock(m_critsect); wxCriticalSectionLocker lock(m_critsect);
p_internal->Cancel(); p_internal->Cancel();
hThread = p_internal->GetHandle();
} }
#if wxUSE_GUI
// we can't just wait for the thread to terminate because it might be // we can't just wait for the thread to terminate because it might be
// calling some GUI functions and so it will never terminate before we // calling some GUI functions and so it will never terminate before we
// process the Windows messages that result from these functions // process the Windows messages that result from these functions
@@ -530,7 +659,7 @@ wxThread::ExitCode wxThread::Delete()
// error // error
wxLogSysError(_("Can not wait for thread termination")); wxLogSysError(_("Can not wait for thread termination"));
Kill(); Kill();
return (ExitCode)-1; return wxTHREAD_KILLED;
case WAIT_OBJECT_0: case WAIT_OBJECT_0:
// thread we're waiting for terminated // thread we're waiting for terminated
@@ -543,14 +672,14 @@ wxThread::ExitCode wxThread::Delete()
// WM_QUIT received: kill the thread // WM_QUIT received: kill the thread
Kill(); Kill();
return (ExitCode)-1; return wxTHREAD_KILLED;
} }
if ( IsMain() ) if ( IsMain() )
{ {
// give the thread we're waiting for chance to exit // give the thread we're waiting for chance to exit
// from the GUI call it might have been in // from the GUI call it might have been in
if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() ) if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
{ {
wxMutexGuiLeave(); wxMutexGuiLeave();
} }
@@ -562,12 +691,25 @@ wxThread::ExitCode wxThread::Delete()
wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject")); wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
} }
} while ( result != WAIT_OBJECT_0 ); } while ( result != WAIT_OBJECT_0 );
#else // !wxUSE_GUI
// simply wait for the thread to terminate
//
// OTOH, even console apps create windows (in wxExecute, for WinSock
// &c), so may be use MsgWaitForMultipleObject() too here?
if ( WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0 )
{
wxFAIL_MSG(wxT("unexpected result of WaitForSingleObject"));
}
#endif // wxUSE_GUI/!wxUSE_GUI
if ( IsMain() ) if ( IsMain() )
{ {
s_waitingForThread = FALSE; gs_waitingForThread = FALSE;
#if wxUSE_GUI
wxEndBusyCursor(); wxEndBusyCursor();
#endif // wxUSE_GUI
}
} }
if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
@@ -577,13 +719,22 @@ wxThread::ExitCode wxThread::Delete()
rc = (ExitCode)-1; rc = (ExitCode)-1;
} }
wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE, if ( IsDetached() )
wxT("thread must be already terminated.") ); {
// if the thread exits normally, this is done in WinThreadStart, but in
::CloseHandle(hThread); // this case it would have been too early because
// MsgWaitForMultipleObject() would fail if the therad handle was
// closed while we were waiting on it, so we must do it here
delete this;
} }
return rc; wxASSERT_MSG( (DWORD)rc != STILL_ACTIVE,
wxT("thread must be already terminated.") );
if ( pRc )
*pRc = rc;
return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
} }
wxThreadError wxThread::Kill() wxThreadError wxThread::Kill()
@@ -598,20 +749,37 @@ wxThreadError wxThread::Kill()
return wxTHREAD_MISC_ERROR; return wxTHREAD_MISC_ERROR;
} }
p_internal->Free();
if ( IsDetached() )
{
delete this; delete this;
}
return wxTHREAD_NO_ERROR; return wxTHREAD_NO_ERROR;
} }
void wxThread::Exit(void *status) void wxThread::Exit(ExitCode status)
{ {
delete this; p_internal->Free();
if ( IsDetached() )
{
delete this;
}
#ifdef __VISUALC__
_endthreadex((unsigned)status);
#else // !VC++
::ExitThread((DWORD)status); ::ExitThread((DWORD)status);
#endif // VC++/!VC++
wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
} }
// priority setting
// ----------------
void wxThread::SetPriority(unsigned int prio) void wxThread::SetPriority(unsigned int prio)
{ {
wxCriticalSectionLocker lock(m_critsect); wxCriticalSectionLocker lock(m_critsect);
@@ -621,28 +789,28 @@ void wxThread::SetPriority(unsigned int prio)
unsigned int wxThread::GetPriority() const unsigned int wxThread::GetPriority() const
{ {
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return p_internal->GetPriority(); return p_internal->GetPriority();
} }
unsigned long wxThread::GetID() const unsigned long wxThread::GetId() const
{ {
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return (unsigned long)p_internal->GetId(); return (unsigned long)p_internal->GetId();
} }
bool wxThread::IsRunning() const bool wxThread::IsRunning() const
{ {
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return p_internal->GetState() == STATE_RUNNING; return p_internal->GetState() == STATE_RUNNING;
} }
bool wxThread::IsAlive() const bool wxThread::IsAlive() const
{ {
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return (p_internal->GetState() == STATE_RUNNING) || return (p_internal->GetState() == STATE_RUNNING) ||
(p_internal->GetState() == STATE_PAUSED); (p_internal->GetState() == STATE_PAUSED);
@@ -650,28 +818,18 @@ bool wxThread::IsAlive() const
bool wxThread::IsPaused() const bool wxThread::IsPaused() const
{ {
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return (p_internal->GetState() == STATE_PAUSED); return p_internal->GetState() == STATE_PAUSED;
} }
bool wxThread::TestDestroy() bool wxThread::TestDestroy()
{ {
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return p_internal->GetState() == STATE_CANCELED; return p_internal->GetState() == STATE_CANCELED;
} }
wxThread::wxThread()
{
p_internal = new wxThreadInternal();
}
wxThread::~wxThread()
{
delete p_internal;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Automatic initialization for thread module // Automatic initialization for thread module
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -691,8 +849,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
bool wxThreadModule::OnInit() bool wxThreadModule::OnInit()
{ {
// allocate TLS index for storing the pointer to the current thread // allocate TLS index for storing the pointer to the current thread
s_tlsThisThread = ::TlsAlloc(); gs_tlsThisThread = ::TlsAlloc();
if ( s_tlsThisThread == 0xFFFFFFFF ) if ( gs_tlsThisThread == 0xFFFFFFFF )
{ {
// in normal circumstances it will only happen if all other // in normal circumstances it will only happen if all other
// TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
@@ -706,10 +864,10 @@ bool wxThreadModule::OnInit()
// main thread doesn't have associated wxThread object, so store 0 in the // main thread doesn't have associated wxThread object, so store 0 in the
// TLS instead // TLS instead
if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) ) if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
{ {
::TlsFree(s_tlsThisThread); ::TlsFree(gs_tlsThisThread);
s_tlsThisThread = 0xFFFFFFFF; gs_tlsThisThread = 0xFFFFFFFF;
wxLogSysError(_("Thread module initialization failed: " wxLogSysError(_("Thread module initialization failed: "
"can not store value in thread local storage")); "can not store value in thread local storage"));
@@ -717,36 +875,37 @@ bool wxThreadModule::OnInit()
return FALSE; return FALSE;
} }
s_critsectWaitingForGui = new wxCriticalSection(); gs_critsectWaitingForGui = new wxCriticalSection();
s_critsectGui = new wxCriticalSection(); gs_critsectGui = new wxCriticalSection();
s_critsectGui->Enter(); gs_critsectGui->Enter();
// no error return for GetCurrentThreadId() // no error return for GetCurrentThreadId()
s_idMainThread = ::GetCurrentThreadId(); gs_idMainThread = ::GetCurrentThreadId();
return TRUE; return TRUE;
} }
void wxThreadModule::OnExit() void wxThreadModule::OnExit()
{ {
if ( !::TlsFree(s_tlsThisThread) ) if ( !::TlsFree(gs_tlsThisThread) )
{ {
wxLogLastError("TlsFree failed."); wxLogLastError("TlsFree failed.");
} }
if ( s_critsectGui ) if ( gs_critsectGui )
{ {
s_critsectGui->Leave(); gs_critsectGui->Leave();
delete s_critsectGui; delete gs_critsectGui;
s_critsectGui = NULL; gs_critsectGui = NULL;
} }
wxDELETE(s_critsectWaitingForGui); delete gs_critsectWaitingForGui;
gs_critsectWaitingForGui = NULL;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// under Windows, these functions are implemented usign a critical section and // under Windows, these functions are implemented using a critical section and
// not a mutex, so the names are a bit confusing // not a mutex, so the names are a bit confusing
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -760,38 +919,38 @@ void WXDLLEXPORT wxMutexGuiEnter()
// set the flag telling to the main thread that we want to do some GUI // set the flag telling to the main thread that we want to do some GUI
{ {
wxCriticalSectionLocker enter(*s_critsectWaitingForGui); wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
s_nWaitingForGui++; gs_nWaitingForGui++;
} }
wxWakeUpMainThread(); wxWakeUpMainThread();
// now we may block here because the main thread will soon let us in // now we may block here because the main thread will soon let us in
// (during the next iteration of OnIdle()) // (during the next iteration of OnIdle())
s_critsectGui->Enter(); gs_critsectGui->Enter();
} }
void WXDLLEXPORT wxMutexGuiLeave() void WXDLLEXPORT wxMutexGuiLeave()
{ {
wxCriticalSectionLocker enter(*s_critsectWaitingForGui); wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
if ( wxThread::IsMain() ) if ( wxThread::IsMain() )
{ {
s_bGuiOwnedByMainThread = FALSE; gs_bGuiOwnedByMainThread = FALSE;
} }
else else
{ {
// decrement the number of waiters now // decrement the number of waiters now
wxASSERT_MSG( s_nWaitingForGui > 0, wxASSERT_MSG( gs_nWaitingForGui > 0,
wxT("calling wxMutexGuiLeave() without entering it first?") ); wxT("calling wxMutexGuiLeave() without entering it first?") );
s_nWaitingForGui--; gs_nWaitingForGui--;
wxWakeUpMainThread(); wxWakeUpMainThread();
} }
s_critsectGui->Leave(); gs_critsectGui->Leave();
} }
void WXDLLEXPORT wxMutexGuiLeaveOrEnter() void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
@@ -799,17 +958,17 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
wxASSERT_MSG( wxThread::IsMain(), wxASSERT_MSG( wxThread::IsMain(),
wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
wxCriticalSectionLocker enter(*s_critsectWaitingForGui); wxCriticalSectionLocker enter(*gs_critsectWaitingForGui);
if ( s_nWaitingForGui == 0 ) if ( gs_nWaitingForGui == 0 )
{ {
// no threads are waiting for GUI - so we may acquire the lock without // no threads are waiting for GUI - so we may acquire the lock without
// any danger (but only if we don't already have it) // any danger (but only if we don't already have it)
if ( !wxGuiOwnedByMainThread() ) if ( !wxGuiOwnedByMainThread() )
{ {
s_critsectGui->Enter(); gs_critsectGui->Enter();
s_bGuiOwnedByMainThread = TRUE; gs_bGuiOwnedByMainThread = TRUE;
} }
//else: already have it, nothing to do //else: already have it, nothing to do
} }
@@ -826,14 +985,14 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
bool WXDLLEXPORT wxGuiOwnedByMainThread() bool WXDLLEXPORT wxGuiOwnedByMainThread()
{ {
return s_bGuiOwnedByMainThread; return gs_bGuiOwnedByMainThread;
} }
// wake up the main thread if it's in ::GetMessage() // wake up the main thread if it's in ::GetMessage()
void WXDLLEXPORT wxWakeUpMainThread() void WXDLLEXPORT wxWakeUpMainThread()
{ {
// sending any message would do - hopefully WM_NULL is harmless enough // sending any message would do - hopefully WM_NULL is harmless enough
if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) ) if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
{ {
// should never happen // should never happen
wxLogLastError("PostThreadMessage(WM_NULL)"); wxLogLastError("PostThreadMessage(WM_NULL)");
@@ -842,7 +1001,7 @@ void WXDLLEXPORT wxWakeUpMainThread()
bool WXDLLEXPORT wxIsWaitingForThread() bool WXDLLEXPORT wxIsWaitingForThread()
{ {
return s_waitingForThread; return gs_waitingForThread;
} }
#endif // wxUSE_THREADS #endif // wxUSE_THREADS

View File

@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: utils.cpp // Name: mse/utils.cpp
// Purpose: Various utilities // Purpose: Various utilities
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by:
@@ -9,6 +9,14 @@
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__ #ifdef __GNUG__
// #pragma implementation "utils.h" // Note: this is done in utilscmn.cpp now. // #pragma implementation "utils.h" // Note: this is done in utilscmn.cpp now.
#endif #endif
@@ -21,18 +29,16 @@
#endif #endif
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/setup.h"
#include "wx/utils.h" #include "wx/utils.h"
#include "wx/app.h" #include "wx/app.h"
#include "wx/cursor.h" #include "wx/cursor.h"
#endif //WX_PRECOMP #endif //WX_PRECOMP
#include "wx/msw/private.h" #include "wx/msw/private.h" // includes <windows.h>
#include "wx/timer.h" #include "wx/timer.h"
#include "wx/intl.h" #include "wx/intl.h"
#include <windows.h>
#include <ctype.h> #include <ctype.h>
#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
@@ -118,23 +124,43 @@
// __VISUALC__ // __VISUALC__
/// END for console support /// END for console support
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// In the WIN.INI file // In the WIN.INI file
static const wxChar WX_SECTION[] = wxT("wxWindows"); static const wxChar WX_SECTION[] = wxT("wxWindows");
static const wxChar eHOSTNAME[] = wxT("HostName");
static const wxChar eUSERID[] = wxT("UserId");
static const wxChar eUSERNAME[] = wxT("UserName"); static const wxChar eUSERNAME[] = wxT("UserName");
// For the following functions we SHOULD fill in support // these are only used under Win16
// for Windows-NT (which I don't know) as I assume it begin #ifndef __WIN32__
// a POSIX Unix (so claims MS) that it has some special static const wxChar eHOSTNAME[] = wxT("HostName");
// functions beyond those provided by WinSock static const wxChar eUSERID[] = wxT("UserId");
#endif // !Win32
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// get host name and related
// ----------------------------------------------------------------------------
// Get full hostname (eg. DoDo.BSn-Germany.crg.de) // Get full hostname (eg. DoDo.BSn-Germany.crg.de)
bool wxGetHostName(wxChar *buf, int maxSize) bool wxGetHostName(wxChar *buf, int maxSize)
{ {
#if defined(__WIN32__) && !defined(__TWIN32__) #if defined(__WIN32__) && !defined(__TWIN32__)
// TODO should use GetComputerNameEx() when available
DWORD nSize = maxSize; DWORD nSize = maxSize;
return (::GetComputerName(buf, &nSize) != 0); if ( !::GetComputerName(buf, &nSize) )
{
wxLogLastError("GetComputerName");
return FALSE;
}
return TRUE;
#else #else
wxChar *sysname; wxChar *sysname;
const wxChar *default_host = wxT("noname"); const wxChar *default_host = wxT("noname");
@@ -148,6 +174,11 @@ bool wxGetHostName(wxChar *buf, int maxSize)
#endif #endif
} }
bool wxGetFullHostName(wxChar *buf, int maxSize)
{
return wxGetHostName(buf, maxSize);
}
// Get user ID e.g. jacs // Get user ID e.g. jacs
bool wxGetUserId(wxChar *buf, int maxSize) bool wxGetUserId(wxChar *buf, int maxSize)
{ {
@@ -286,30 +317,150 @@ error:
return TRUE; return TRUE;
} }
const wxChar* wxGetHomeDir(wxString *pstr)
{
wxString& strDir = *pstr;
#if defined(__UNIX__) && !defined(__TWIN32__)
const wxChar *szHome = wxGetenv("HOME");
if ( szHome == NULL ) {
// we're homeless...
wxLogWarning(_("can't find user's HOME, using current directory."));
strDir = wxT(".");
}
else
strDir = szHome;
// add a trailing slash if needed
if ( strDir.Last() != wxT('/') )
strDir << wxT('/');
#else // Windows
#ifdef __WIN32__
const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE"));
if ( szHome != NULL )
strDir << szHome;
szHome = wxGetenv(wxT("HOMEPATH"));
if ( szHome != NULL ) {
strDir << szHome;
// the idea is that under NT these variables have default values
// of "%systemdrive%:" and "\\". As we don't want to create our
// config files in the root directory of the system drive, we will
// create it in our program's dir. However, if the user took care
// to set HOMEPATH to something other than "\\", we suppose that he
// knows what he is doing and use the supplied value.
if ( wxStrcmp(szHome, wxT("\\")) != 0 )
return strDir.c_str();
}
#else // Win16
// Win16 has no idea about home, so use the working directory instead
#endif // WIN16/32
// 260 was taken from windef.h
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
wxString strPath;
::GetModuleFileName(::GetModuleHandle(NULL),
strPath.GetWriteBuf(MAX_PATH), MAX_PATH);
strPath.UngetWriteBuf();
// extract the dir name
wxSplitPath(strPath, &strDir, NULL, NULL);
#endif // UNIX/Win
return strDir.c_str();
}
wxChar *wxGetUserHome(const wxString& user)
{
// VZ: the old code here never worked for user != "" anyhow! Moreover, it
// returned sometimes a malloc()'d pointer, sometimes a pointer to a
// static buffer and sometimes I don't even know what.
static wxString s_home;
return (wxChar *)wxGetHomeDir(&s_home);
}
bool wxDirExists(const wxString& dir)
{
#if defined(__WIN32__)
WIN32_FIND_DATA fileInfo;
#else // Win16
#ifdef __BORLANDC__
struct ffblk fileInfo;
#else
struct find_t fileInfo;
#endif
#endif // Win32/16
#if defined(__WIN32__)
HANDLE h = ::FindFirstFile(dir, &fileInfo);
if ( h == INVALID_HANDLE_VALUE )
{
wxLogLastError("FindFirstFile");
return FALSE;
}
::FindClose(h);
return (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
#else // Win16
// In Borland findfirst has a different argument
// ordering from _dos_findfirst. But _dos_findfirst
// _should_ be ok in both MS and Borland... why not?
#ifdef __BORLANDC__
return (findfirst(dir, &fileInfo, _A_SUBDIR) == 0 &&
(fileInfo.ff_attrib & _A_SUBDIR) != 0);
#else
return (_dos_findfirst(dir, _A_SUBDIR, &fileInfo) == 0) &&
((fileInfo.attrib & _A_SUBDIR) != 0);
#endif
#endif // Win32/16
}
// ----------------------------------------------------------------------------
// process management
// ----------------------------------------------------------------------------
int wxKill(long pid, int sig) int wxKill(long pid, int sig)
{ {
// TODO use SendMessage(WM_QUIT) and TerminateProcess() if needed
return 0; return 0;
} }
//
// Execute a program in an Interactive Shell // Execute a program in an Interactive Shell
// bool wxShell(const wxString& command)
bool
wxShell(const wxString& command)
{ {
wxChar *shell; wxChar *shell = wxGetenv(wxT("COMSPEC"));
if ((shell = wxGetenv(wxT("COMSPEC"))) == NULL) if ( !shell )
shell = wxT("\\COMMAND.COM"); shell = wxT("\\COMMAND.COM");
wxChar tmp[255]; wxString cmd;
if (command != wxT("")) if ( !command )
wxSprintf(tmp, wxT("%s /c %s"), shell, WXSTRINGCAST command); {
// just the shell
cmd = shell;
}
else else
wxStrcpy(tmp, shell); {
// pass the command to execute to the command processor
cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
}
return (wxExecute((wxChar *)tmp, FALSE) != 0); return wxExecute(cmd, FALSE) != 0;
} }
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX) // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
long wxGetFreeMemory() long wxGetFreeMemory()
{ {
@@ -323,111 +474,10 @@ long wxGetFreeMemory()
#endif #endif
} }
// Sleep for nSecs seconds. Attempt a Windows implementation using timers.
static bool inTimer = FALSE;
class wxSleepTimer: public wxTimer
{
public:
inline void Notify()
{
inTimer = FALSE;
Stop();
}
};
static wxTimer *wxTheSleepTimer = NULL;
void wxUsleep(unsigned long milliseconds)
{
#ifdef __WIN32__
::Sleep(milliseconds);
#else
if (inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
inTimer = TRUE;
wxTheSleepTimer->Start(milliseconds);
while (inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
#endif
}
void wxSleep(int nSecs)
{
#if 0 // WIN32 hangs app
Sleep( 1000*nSecs );
#else
if (inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
inTimer = TRUE;
wxTheSleepTimer->Start(nSecs*1000);
while (inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
#endif
}
// Consume all events until no more left
void wxFlushEvents()
{
// wxYield();
}
// Output a debug mess., in a system dependent fashion.
void wxDebugMsg(const wxChar *fmt ...)
{
va_list ap;
static wxChar buffer[512];
if (!wxTheApp->GetWantDebugOutput())
return ;
va_start(ap, fmt);
wvsprintf(buffer,fmt,ap) ;
OutputDebugString((LPCTSTR)buffer) ;
va_end(ap);
}
// Non-fatal error: pop up message box and (possibly) continue
void wxError(const wxString& msg, const wxString& title)
{
wxSprintf(wxBuffer, wxT("%s\nContinue?"), WXSTRINGCAST msg);
if (MessageBox(NULL, (LPCTSTR)wxBuffer, (LPCTSTR)WXSTRINGCAST title,
MB_ICONSTOP | MB_YESNO) == IDNO)
wxExit();
}
// Fatal error: pop up message box and abort
void wxFatalError(const wxString& msg, const wxString& title)
{
wxSprintf(wxBuffer, wxT("%s: %s"), WXSTRINGCAST title, WXSTRINGCAST msg);
FatalAppExit(0, (LPCTSTR)wxBuffer);
}
// Emit a beeeeeep // Emit a beeeeeep
void wxBell() void wxBell()
{ {
// Removed by RD because IHMO syncronous sound is a Bad Thing. MessageBeep ::MessageBeep((UINT)-1); // default sound
// will do a similar thing anyway if there is no sound card...
//#ifdef __WIN32__
// Beep(1000,1000) ; // 1kHz during 1 sec.
//#else
MessageBeep((UINT)-1) ;
//#endif
} }
// Chris Breeze 27/5/98: revised WIN32 code to // Chris Breeze 27/5/98: revised WIN32 code to
@@ -477,6 +527,128 @@ int wxGetOsVersion(int *majorVsn, int *minorVsn)
#endif #endif
} }
// ----------------------------------------------------------------------------
// sleep functions
// ----------------------------------------------------------------------------
#if wxUSE_GUI
// Sleep for nSecs seconds. Attempt a Windows implementation using timers.
static bool gs_inTimer = FALSE;
class wxSleepTimer: public wxTimer
{
public:
virtual void Notify()
{
gs_inTimer = FALSE;
Stop();
}
};
static wxTimer *wxTheSleepTimer = NULL;
void wxUsleep(unsigned long milliseconds)
{
#ifdef __WIN32__
::Sleep(milliseconds);
#else
if (gs_inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
gs_inTimer = TRUE;
wxTheSleepTimer->Start(milliseconds);
while (gs_inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
#endif
}
void wxSleep(int nSecs)
{
if (gs_inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
gs_inTimer = TRUE;
wxTheSleepTimer->Start(nSecs*1000);
while (gs_inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
}
// Consume all events until no more left
void wxFlushEvents()
{
// wxYield();
}
#elif defined(__WIN32__) // wxUSE_GUI
void wxUsleep(unsigned long milliseconds)
{
::Sleep(milliseconds);
}
void wxSleep(int nSecs)
{
wxUsleep(1000*nSecs);
}
#endif // wxUSE_GUI/!wxUSE_GUI
// ----------------------------------------------------------------------------
// deprecated (in favour of wxLog) log functions
// ----------------------------------------------------------------------------
#if wxUSE_GUI
// Output a debug mess., in a system dependent fashion.
void wxDebugMsg(const wxChar *fmt ...)
{
va_list ap;
static wxChar buffer[512];
if (!wxTheApp->GetWantDebugOutput())
return ;
va_start(ap, fmt);
wvsprintf(buffer,fmt,ap) ;
OutputDebugString((LPCTSTR)buffer) ;
va_end(ap);
}
// Non-fatal error: pop up message box and (possibly) continue
void wxError(const wxString& msg, const wxString& title)
{
wxSprintf(wxBuffer, wxT("%s\nContinue?"), WXSTRINGCAST msg);
if (MessageBox(NULL, (LPCTSTR)wxBuffer, (LPCTSTR)WXSTRINGCAST title,
MB_ICONSTOP | MB_YESNO) == IDNO)
wxExit();
}
// Fatal error: pop up message box and abort
void wxFatalError(const wxString& msg, const wxString& title)
{
wxSprintf(wxBuffer, wxT("%s: %s"), WXSTRINGCAST title, WXSTRINGCAST msg);
FatalAppExit(0, (LPCTSTR)wxBuffer);
}
// ----------------------------------------------------------------------------
// functions to work with .INI files
// ----------------------------------------------------------------------------
// Reading and writing resources (eg WIN.INI, .Xdefaults) // Reading and writing resources (eg WIN.INI, .Xdefaults)
#if wxUSE_RESOURCES #if wxUSE_RESOURCES
bool wxWriteResource(const wxString& section, const wxString& entry, const wxString& value, const wxString& file) bool wxWriteResource(const wxString& section, const wxString& entry, const wxString& value, const wxString& file)
@@ -495,22 +667,25 @@ bool wxWriteResource(const wxString& section, const wxString& entry, const wxStr
bool wxWriteResource(const wxString& section, const wxString& entry, float value, const wxString& file) bool wxWriteResource(const wxString& section, const wxString& entry, float value, const wxString& file)
{ {
wxChar buf[50]; wxString buf;
wxSprintf(buf, wxT("%.4f"), value); buf.Printf(wxT("%.4f"), value);
return wxWriteResource(section, entry, buf, file); return wxWriteResource(section, entry, buf, file);
} }
bool wxWriteResource(const wxString& section, const wxString& entry, long value, const wxString& file) bool wxWriteResource(const wxString& section, const wxString& entry, long value, const wxString& file)
{ {
wxChar buf[50]; wxString buf;
wxSprintf(buf, wxT("%ld"), value); buf.Printf(wxT("%ld"), value);
return wxWriteResource(section, entry, buf, file); return wxWriteResource(section, entry, buf, file);
} }
bool wxWriteResource(const wxString& section, const wxString& entry, int value, const wxString& file) bool wxWriteResource(const wxString& section, const wxString& entry, int value, const wxString& file)
{ {
wxChar buf[50]; wxString buf;
wxSprintf(buf, wxT("%d"), value); buf.Printf(wxT("%d"), value);
return wxWriteResource(section, entry, buf, file); return wxWriteResource(section, entry, buf, file);
} }
@@ -534,7 +709,7 @@ bool wxGetResource(const wxString& section, const wxString& entry, wxChar **valu
if (*value) delete[] (*value); if (*value) delete[] (*value);
*value = copystring(wxBuffer); *value = copystring(wxBuffer);
return TRUE; return TRUE;
} }
bool wxGetResource(const wxString& section, const wxString& entry, float *value, const wxString& file) bool wxGetResource(const wxString& section, const wxString& entry, float *value, const wxString& file)
{ {
@@ -615,142 +790,42 @@ bool wxIsBusy()
return (gs_wxBusyCursorCount > 0); return (gs_wxBusyCursorCount > 0);
} }
// ---------------------------------------------------------------------------
const wxChar* wxGetHomeDir(wxString *pstr)
{
wxString& strDir = *pstr;
#if defined(__UNIX__) && !defined(__TWIN32__)
const wxChar *szHome = wxGetenv("HOME");
if ( szHome == NULL ) {
// we're homeless...
wxLogWarning(_("can't find user's HOME, using current directory."));
strDir = wxT(".");
}
else
strDir = szHome;
// add a trailing slash if needed
if ( strDir.Last() != wxT('/') )
strDir << wxT('/');
#else // Windows
#ifdef __WIN32__
const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE"));
if ( szHome != NULL )
strDir << szHome;
szHome = wxGetenv(wxT("HOMEPATH"));
if ( szHome != NULL ) {
strDir << szHome;
// the idea is that under NT these variables have default values
// of "%systemdrive%:" and "\\". As we don't want to create our
// config files in the root directory of the system drive, we will
// create it in our program's dir. However, if the user took care
// to set HOMEPATH to something other than "\\", we suppose that he
// knows what he is doing and use the supplied value.
if ( wxStrcmp(szHome, wxT("\\")) != 0 )
return strDir.c_str();
}
#else // Win16
// Win16 has no idea about home, so use the working directory instead
#endif // WIN16/32
// 260 was taken from windef.h
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
wxString strPath;
::GetModuleFileName(::GetModuleHandle(NULL),
strPath.GetWriteBuf(MAX_PATH), MAX_PATH);
strPath.UngetWriteBuf();
// extract the dir name
wxSplitPath(strPath, &strDir, NULL, NULL);
#endif // UNIX/Win
return strDir.c_str();
}
// Hack for MS-DOS
wxChar *wxGetUserHome (const wxString& user)
{
wxChar *home;
wxString user1(user);
if (user1 != wxT("")) {
wxChar tmp[64];
if (wxGetUserId(tmp, sizeof(tmp)/sizeof(char))) {
// Guests belong in the temp dir
if (wxStricmp(tmp, wxT("annonymous")) == 0) {
if ((home = wxGetenv(wxT("TMP"))) != NULL ||
(home = wxGetenv(wxT("TMPDIR"))) != NULL ||
(home = wxGetenv(wxT("TEMP"))) != NULL)
return *home ? home : (wxChar*)wxT("\\");
}
if (wxStricmp(tmp, WXSTRINGCAST user1) == 0)
user1 = wxT("");
}
}
if (user1 == wxT(""))
if ((home = wxGetenv(wxT("HOME"))) != NULL)
{
wxStrcpy(wxBuffer, home);
Unix2DosFilename(wxBuffer);
return wxBuffer;
}
return NULL; // No home known!
}
// Check whether this window wants to process messages, e.g. Stop button // Check whether this window wants to process messages, e.g. Stop button
// in long calculations. // in long calculations.
bool wxCheckForInterrupt(wxWindow *wnd) bool wxCheckForInterrupt(wxWindow *wnd)
{ {
if(wnd){ wxCHECK( wnd, FALSE );
MSG msg;
HWND win= (HWND) wnd->GetHWND();
while(PeekMessage(&msg,win,0,0,PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;//*** temporary?
}
else{
wxFAIL_MSG(wxT("wnd==NULL !!!"));
return FALSE;//*** temporary? MSG msg;
while ( ::PeekMessage(&msg, GetHwndOf(wnd), 0, 0, PM_REMOVE) )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
} }
return TRUE;
} }
#endif // wxUSE_GUI
// MSW only: get user-defined resource from the .res file. // MSW only: get user-defined resource from the .res file.
// Returns NULL or newly-allocated memory, so use delete[] to clean up. // Returns NULL or newly-allocated memory, so use delete[] to clean up.
#ifdef __WXMSW__
wxChar *wxLoadUserResource(const wxString& resourceName, const wxString& resourceType) wxChar *wxLoadUserResource(const wxString& resourceName, const wxString& resourceType)
{ {
wxChar *s = NULL; HRSRC hResource = ::FindResource(wxGetInstance(), resourceName, resourceType);
#if !defined(__WIN32__) || defined(__TWIN32__) if ( hResource == 0 )
HRSRC hResource = ::FindResource(wxGetInstance(), WXSTRINGCAST resourceName, WXSTRINGCAST resourceType);
#else
#ifdef UNICODE
HRSRC hResource = ::FindResourceW(wxGetInstance(), WXSTRINGCAST resourceName, WXSTRINGCAST resourceType);
#else
HRSRC hResource = ::FindResourceA(wxGetInstance(), WXSTRINGCAST resourceName, WXSTRINGCAST resourceType);
#endif
#endif
if (hResource == 0)
return NULL; return NULL;
HGLOBAL hData = ::LoadResource(wxGetInstance(), hResource); HGLOBAL hData = ::LoadResource(wxGetInstance(), hResource);
if (hData == 0) if ( hData == 0 )
return NULL;
wxChar *theText = (wxChar *)LockResource(hData);
if (!theText)
return NULL; return NULL;
s = copystring(theText); wxChar *theText = (wxChar *)::LockResource(hData);
if ( !theText )
return NULL;
wxChar *s = copystring(theText);
// Obsolete in WIN32 // Obsolete in WIN32
#ifndef __WIN32__ #ifndef __WIN32__
@@ -758,85 +833,46 @@ wxChar *wxLoadUserResource(const wxString& resourceName, const wxString& resourc
#endif #endif
// No need?? // No need??
// GlobalFree(hData); // GlobalFree(hData);
return s; return s;
} }
#endif
// ----------------------------------------------------------------------------
// get display info
// ----------------------------------------------------------------------------
void wxGetMousePosition( int* x, int* y ) void wxGetMousePosition( int* x, int* y )
{ {
POINT pt; POINT pt;
GetCursorPos( & pt ); GetCursorPos( & pt );
*x = pt.x; if ( x ) *x = pt.x;
*y = pt.y; if ( y ) *y = pt.y;
}; };
// Return TRUE if we have a colour display // Return TRUE if we have a colour display
bool wxColourDisplay() bool wxColourDisplay()
{ {
HDC dc = ::GetDC((HWND) NULL); ScreenHDC dc;
bool flag;
int noCols = GetDeviceCaps(dc, NUMCOLORS); int noCols = GetDeviceCaps(dc, NUMCOLORS);
if ((noCols == -1) || (noCols > 2))
flag = TRUE; return (noCols == -1) || (noCols > 2);
else
flag = FALSE;
ReleaseDC((HWND) NULL, dc);
return flag;
} }
// Returns depth of screen // Returns depth of screen
int wxDisplayDepth() int wxDisplayDepth()
{ {
HDC dc = ::GetDC((HWND) NULL); ScreenHDC dc;
int planes = GetDeviceCaps(dc, PLANES); return GetDeviceCaps(dc, PLANES) * GetDeviceCaps(dc, BITSPIXEL);
int bitsPerPixel = GetDeviceCaps(dc, BITSPIXEL);
int depth = planes*bitsPerPixel;
ReleaseDC((HWND) NULL, dc);
return depth;
} }
// Get size of display // Get size of display
void wxDisplaySize(int *width, int *height) void wxDisplaySize(int *width, int *height)
{ {
HDC dc = ::GetDC((HWND) NULL); ScreenHDC dc;
*width = GetDeviceCaps(dc, HORZRES); *height = GetDeviceCaps(dc, VERTRES);
ReleaseDC((HWND) NULL, dc);
}
bool wxDirExists(const wxString& dir) if ( width ) *width = GetDeviceCaps(dc, HORZRES);
{ if ( height ) *height = GetDeviceCaps(dc, VERTRES);
/* MATTHEW: [6] Always use same code for Win32, call FindClose */
#if defined(__WIN32__)
WIN32_FIND_DATA fileInfo;
#else
#ifdef __BORLANDC__
struct ffblk fileInfo;
#else
struct find_t fileInfo;
#endif
#endif
#if defined(__WIN32__)
HANDLE h = FindFirstFile((LPTSTR) WXSTRINGCAST dir,(LPWIN32_FIND_DATA)&fileInfo);
if (h==INVALID_HANDLE_VALUE)
return FALSE;
else {
FindClose(h);
return ((fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
}
#else
// In Borland findfirst has a different argument
// ordering from _dos_findfirst. But _dos_findfirst
// _should_ be ok in both MS and Borland... why not?
#ifdef __BORLANDC__
return ((findfirst(WXSTRINGCAST dir, &fileInfo, _A_SUBDIR) == 0 && (fileInfo.ff_attrib & _A_SUBDIR) != 0));
#else
return (((_dos_findfirst(WXSTRINGCAST dir, _A_SUBDIR, &fileInfo) == 0) && (fileInfo.attrib & _A_SUBDIR)) != 0);
#endif
#endif
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: utilsexec.cpp // Name: msw/utilsexec.cpp
// Purpose: Various utilities // Purpose: Various utilities
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by:
@@ -9,48 +9,51 @@
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__ #ifdef __GNUG__
#pragma implementation #pragma implementation
#endif #endif
// For compilers that support precompilation, includes "wx.h". // For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h" #include "wx/wxprec.h"
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#pragma hdrstop #pragma hdrstop
#endif #endif
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/setup.h" #include "wx/utils.h"
#include "wx/utils.h" #include "wx/app.h"
#include "wx/app.h" #include "wx/intl.h"
#include "wx/intl.h"
#endif #endif
#include "wx/log.h" #include "wx/log.h"
#ifdef __WIN32__ #ifdef __WIN32__
#include "wx/process.h" #include "wx/process.h"
#endif #endif
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include <windows.h>
#include <ctype.h> #include <ctype.h>
#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
#include <direct.h> #include <direct.h>
#ifndef __MWERKS__ #ifndef __MWERKS__
#include <dos.h> #include <dos.h>
#endif #endif
#endif #endif
#ifdef __GNUWIN32__ #if defined(__GNUWIN32__) && !defined(__TWIN32__)
#ifndef __TWIN32__ #include <sys/unistd.h>
#include <sys/unistd.h> #include <sys/stat.h>
#include <sys/stat.h>
#endif
#endif #endif
#if defined(__WIN32__) && !defined(__WXWINE__) #if defined(__WIN32__) && !defined(__WXWINE__)
@@ -71,9 +74,26 @@
#endif #endif
#include <stdarg.h> #include <stdarg.h>
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// this message is sent when the process we're waiting for terminates // this message is sent when the process we're waiting for terminates
#define wxWM_PROC_TERMINATED (WM_USER + 10000) #define wxWM_PROC_TERMINATED (WM_USER + 10000)
// ----------------------------------------------------------------------------
// this module globals
// ----------------------------------------------------------------------------
// we need to create a hidden window to receive the process termination
// notifications and for this we need a (Win) class name for it which we will
// register the first time it's needed
static const wxChar *gs_classForHiddenWindow = NULL;
// ----------------------------------------------------------------------------
// private types
// ----------------------------------------------------------------------------
// structure describing the process we're being waiting for // structure describing the process we're being waiting for
struct wxExecuteData struct wxExecuteData
{ {
@@ -96,6 +116,9 @@ public:
bool state; // set to FALSE when the process finishes bool state; // set to FALSE when the process finishes
}; };
// ============================================================================
// implementation
// ============================================================================
#ifdef __WIN32__ #ifdef __WIN32__
static DWORD wxExecuteThread(wxExecuteData *data) static DWORD wxExecuteThread(wxExecuteData *data)
@@ -150,8 +173,6 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
} }
#endif #endif
extern wxChar wxPanelClassName[];
long wxExecute(const wxString& command, bool sync, wxProcess *handler) long wxExecute(const wxString& command, bool sync, wxProcess *handler)
{ {
wxCHECK_MSG( !!command, 0, wxT("empty command in wxExecute") ); wxCHECK_MSG( !!command, 0, wxT("empty command in wxExecute") );
@@ -242,17 +263,31 @@ long wxExecute(const wxString& command, bool sync, wxProcess *handler)
if ( !::CloseHandle(pi.hThread) ) if ( !::CloseHandle(pi.hThread) )
wxLogLastError("CloseHandle(hThread)"); wxLogLastError("CloseHandle(hThread)");
if ( !gs_classForHiddenWindow )
{
gs_classForHiddenWindow = _T("wxHiddenWindow");
WNDCLASS wndclass;
wxZeroMemory(wndclass);
wndclass.lpfnWndProc = (WNDPROC)wxExecuteWindowCbk;
wndclass.hInstance = wxGetInstance();
wndclass.lpszClassName = gs_classForHiddenWindow;
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError("RegisterClass(hidden window)");
return FALSE;
}
}
// create a hidden window to receive notification about process // create a hidden window to receive notification about process
// termination // termination
HWND hwnd = ::CreateWindow(wxPanelClassName, NULL, 0, 0, 0, 0, 0, NULL, HWND hwnd = ::CreateWindow(gs_classForHiddenWindow, NULL,
0, 0, 0, 0, 0, NULL,
(HMENU)NULL, wxGetInstance(), 0); (HMENU)NULL, wxGetInstance(), 0);
wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") ); wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
FARPROC ExecuteWindowInstance = MakeProcInstance((FARPROC)wxExecuteWindowCbk,
wxGetInstance());
::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) ExecuteWindowInstance);
// Alloc data // Alloc data
wxExecuteData *data = new wxExecuteData; wxExecuteData *data = new wxExecuteData;
data->hProcess = pi.hProcess; data->hProcess = pi.hProcess;
@@ -338,33 +373,3 @@ long wxExecute(char **argv, bool sync, wxProcess *handler)
return wxExecute(command, sync, handler); return wxExecute(command, sync, handler);
} }
bool wxGetFullHostName(wxChar *buf, int maxSize)
{
#if defined(__WIN32__) && !defined(__TWIN32__)
DWORD nSize = maxSize ;
if ( !::GetComputerName(buf, &nSize) )
{
wxLogLastError("GetComputerName");
return FALSE;
}
#else
char *sysname;
const char *default_host = "noname";
static const char WX_SECTION[] = "wxWindows";
static const char eHOSTNAME[] = "HostName";
if ((sysname = getenv("SYSTEM_NAME")) == NULL) {
GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1);
} else
strncpy(buf, sysname, maxSize - 1);
buf[maxSize] = '\0';
if ( *buf == '\0' )
{
wxLogLastError("GetComputerName");
return FALSE;
}
#endif
return TRUE;
}

View File

@@ -685,7 +685,14 @@ wxThreadError wxThread::Resume()
// exiting thread // exiting thread
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
wxThread::ExitCode wxThread::Delete() wxThread::ExitCode Wait()
{
wxFAIL_MSG("TODO");
return 0;
}
wxThreadError wxThread::Delete(ExitCode *rc)
{ {
if (IsPaused()) if (IsPaused())
Resume(); Resume();
@@ -745,7 +752,7 @@ wxThreadError wxThread::Kill()
} }
} }
void wxThread::Exit(void *status) void wxThread::Exit(ExitCode status)
{ {
// first call user-level clean up code // first call user-level clean up code
OnExit(); OnExit();