Skip to content

Commit

Permalink
Merge pull request #583 from daschuer/win_console
Browse files Browse the repository at this point in the history
Console fixes for Windows.
  • Loading branch information
rryan committed May 13, 2015
2 parents a93d9b0 + 448eb28 commit 999b7c8
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 96 deletions.
3 changes: 1 addition & 2 deletions build/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ def sources(self, build):
"util/xml.cpp",
"util/tapfilter.cpp",
"util/movinginterquartilemean.cpp",
"util/console.cpp",

'#res/mixxx.qrc'
]
Expand Down Expand Up @@ -1061,8 +1062,6 @@ def configure(self, build, conf):
# runtime because Mixxx loads DLLs at runtime. Since this is a
# debug build, use the debug version of the MD runtime.
build.env.Append(CCFLAGS='/MDd')
# Enable the Mixxx debug console (see main.cpp).
build.env.Append(CPPDEFINES='DEBUGCONSOLE')
else:
# Important: We always build Mixxx with the Multi-Threaded DLL
# runtime because Mixxx loads DLLs at runtime.
Expand Down
11 changes: 2 additions & 9 deletions src/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,12 @@ def build_tests():
env.Append(LIBS = 'gmock')

if build.platform_is_windows:
# Subsystem change temporarily disabled due to LP #1453782.
# TODO(rryan): Build Mixxx core as a shared object and link it
# into mixxx and mixxx-test. We could build both in different
# environments right now but then automoc and protoc get run in
# both environments which makes SCons unhappy.
# # We want a terminal for tests.
# if build.machine_is_64bit:
# test_env['LINKFLAGS'].remove('/subsystem:windows,5.02')
# test_env['LINKFLAGS'].append('/subsystem:console,5.02')
# else:
# test_env['LINKFLAGS'].remove('/subsystem:windows,5.01')
# test_env['LINKFLAGS'].append('/subsystem:console,5.01')

# Currently both executables are built with /subsystem:windows
# and the console is attached manually
test_bin = env.Program(
'mixxx-test', [test_sources, env.RES('#src/mixxx.rc')],
LINKCOM = [env['LINKCOM'], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1'])
Expand Down
87 changes: 2 additions & 85 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "errordialoghandler.h"
#include "util/cmdlineargs.h"
#include "util/version.h"
#include "util/console.h"

#include <QFile>
#include <QFileInfo>
Expand All @@ -48,11 +49,6 @@ extern "C" {
#include <X11/Xlib.h>
#endif

#ifdef __WINDOWS__
#include <windows.h>
typedef BOOL(WINAPI* pfSetCurrentConsoleFontEx)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
#endif // __WINDOWS__

QStringList plugin_paths; //yes this is global. sometimes global is good.

//void qInitImages_mixxx();
Expand Down Expand Up @@ -252,73 +248,7 @@ int main(int argc, char * argv[])
return(0);
}

//it seems like this code should be inline in MessageHandler() but for some reason having it there corrupts the messages sometimes -kousu 2/2009

#ifdef __WINDOWS__
// Setup Windows console encoding
// toLocal8Bit() returns the ANSI file encoding format
// this does not necessarily match the OEM console encoding
// https://www.microsoft.com/resources/msdn/goglobal/default.mspx
// In case of a German Windows XP to 10 console encoding is cp850
// where files encoding is cp1252
// Qt has no solution for it https://bugreports.qt.io/browse/QTBUG-13303
// http://stackoverflow.com/questions/1259084/what-encoding-code-page-is-cmd-exe-using
// We try to change the console encoding to file encoding
// For a German windows we expect
// LOCALE_IDEFAULTANSICODEPAGE "1252" // ANSI Codepage used by Qt toLocal8Bit
// LOCALE_IDEFAULTCODEPAGE "850" // OEM Codepage Console

// TODO() Verify it the folowing:
// it turns out that SetConsoleOutputCP() shows the invisible console that is
// created on startup by Qt using the CREATE_NO_WINDOW flag
// http://stackoverflow.com/questions/447352/how-to-know-whether-we-are-in-a-console-or-a-windowed-app
// This means, we must not call any console related commands, if we are not
// called from a console or will initialize one anyway.

#ifdef DEBUGCONSOLE
if (GetConsoleWindow() != NULL) {
// This should create the window for the hidden console
// initalized by Qt
SetConsoleTitleA("Mixxx Debug Messages");
}
#endif
UINT oldCodePage;
bool shouldResetCodePage = false;
if (GetConsoleWindow() != NULL) {
// Save current code page
oldCodePage = GetConsoleOutputCP();
shouldResetCodePage = true;

HMODULE kernel32_dll = LoadLibraryW(L"kernel32.dll");
if (kernel32_dll) {
pfSetCurrentConsoleFontEx pfSCCFX = (pfSetCurrentConsoleFontEx)GetProcAddress(kernel32_dll, "SetCurrentConsoleFontEx");
if (pfSCCFX) {
// Use a unicode font
CONSOLE_FONT_INFOEX newFont;
newFont.cbSize = sizeof newFont;
newFont.nFont = 0;
newFont.dwFontSize.X = 0;
newFont.dwFontSize.Y = 14;
newFont.FontFamily = FF_DONTCARE;
newFont.FontWeight = FW_NORMAL;
wcscpy_s(newFont.FaceName, L"Consolas");
pfSCCFX(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &newFont);
} else {
// This happens on Windows XP
qWarning() << "The console font may not support non ANSI characters." <<
"In case of character issues switch to font \"Consolas\"";
}
}

// set console to the default ANSI Code Page
UINT defaultCodePage;
GetLocaleInfo(LOCALE_USER_DEFAULT,
LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE,
reinterpret_cast<LPWSTR>(&defaultCodePage),
sizeof(defaultCodePage));
SetConsoleOutputCP(defaultCodePage);
}
#endif
Console console();

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
qInstallMsgHandler(MessageHandler);
Expand Down Expand Up @@ -353,10 +283,6 @@ int main(int argc, char * argv[])
// if(QString("--no-visuals")==argv[i])
// bVisuals = false;

#ifdef __WINDOWS__
qDebug() << "using CP" << LOCALE_IDEFAULTANSICODEPAGE << "for console";
#endif


#ifdef __APPLE__
QDir dir(QApplication::applicationDirPath());
Expand Down Expand Up @@ -409,15 +335,6 @@ int main(int argc, char * argv[])
}
}

#ifdef __WINDOWS__
// Reset Windows console to old code page
// We need to stick with the unicode font since
// changing back will destroy the console history
if (shouldResetCodePage && GetConsoleWindow() != NULL) {
SetConsoleOutputCP(oldCodePage);
}
#endif

//delete plugin_paths;
return result;
}
3 changes: 3 additions & 0 deletions src/test/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <gtest/gtest.h>
#include "util/console.h"


int main(int argc, char **argv) {
Console console();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
100 changes: 100 additions & 0 deletions src/util/console.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@

#include "console.h"

#include <stdio.h>
#include <QtDebug>

#ifdef __WINDOWS__
#include <windows.h>
#include <io.h> // Debug Console
typedef BOOL(WINAPI* pfSetCurrentConsoleFontEx)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX);


Console::Console() {

// Setup Windows console encoding
// toLocal8Bit() returns the ANSI file encoding format
// this does not necessarily match the OEM console encoding
// https://www.microsoft.com/resources/msdn/goglobal/default.mspx
// In case of a German Windows XP to 10 console encoding is cp850
// where files encoding is cp1252
// Qt has no solution for it https://bugreports.qt.io/browse/QTBUG-13303
// http://stackoverflow.com/questions/1259084/what-encoding-code-page-is-cmd-exe-using
// We try to change the console encoding to file encoding
// For a German windows we expect
// LOCALE_IDEFAULTANSICODEPAGE "1252" // ANSI Codepage used by Qt toLocal8Bit
// LOCALE_IDEFAULTCODEPAGE "850" // OEM Codepage Console

m_shouldResetCodePage = false;
if(AttachConsole(ATTACH_PARENT_PROCESS)) {
// we are started from a console porcess
int fd;
FILE *fp;

fd = _open_osfhandle((long) GetStdHandle(STD_OUTPUT_HANDLE), 0);
fp = _fdopen(fd, "w");
*stdout = *fp;
setvbuf(stdout, NULL, _IONBF, 0);

fd = _open_osfhandle((long) GetStdHandle(STD_ERROR_HANDLE), 0);
fp = _fdopen(fd, "w");
*stderr = *fp;
setvbuf(stderr, NULL, _IONBF, 0);

// Save current code page
m_oldCodePage = GetConsoleOutputCP();
m_shouldResetCodePage = true;

HMODULE kernel32_dll = LoadLibraryW(L"kernel32.dll");
if (kernel32_dll) {
pfSetCurrentConsoleFontEx pfSCCFX = (pfSetCurrentConsoleFontEx)GetProcAddress(kernel32_dll, "SetCurrentConsoleFontEx");
if (pfSCCFX) {
// Use a unicode font
CONSOLE_FONT_INFOEX newFont;
newFont.cbSize = sizeof newFont;
newFont.nFont = 0;
newFont.dwFontSize.X = 0;
newFont.dwFontSize.Y = 14;
newFont.FontFamily = FF_DONTCARE;
newFont.FontWeight = FW_NORMAL;
wcscpy_s(newFont.FaceName, L"Consolas");
pfSCCFX(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &newFont);
} else {
// This happens on Windows XP
qWarning() << "The console font may not support non ANSI characters." <<
"In case of character issues switch to font \"Lucida Console\"";
}
}

// set console to the default ANSI Code Page
UINT defaultCodePage;
GetLocaleInfo(LOCALE_USER_DEFAULT,
LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE,
reinterpret_cast<LPWSTR>(&defaultCodePage),
sizeof(defaultCodePage));
SetConsoleOutputCP(defaultCodePage);
} else {
// started by double click
// no need to deal with a console
}
}

Console::~Console() {
// Reset Windows console to old code page
// We need to stick with the unicode font since
// changing back will destroy the console history
if (m_shouldResetCodePage) {
SetConsoleOutputCP(m_oldCodePage);
}
}

#else // __WINDOWS__

// Nothing to do on non Windows targets
Console::Console() {
}

Console::~Console() {
}

#endif // __WINDOWS__
17 changes: 17 additions & 0 deletions src/util/console.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

#ifndef CONSOLE_H_
#define CONSOLE_H_

class Console {
public:
Console();
~Console();

private:
#ifdef __WINDOWS__
unsigned int m_oldCodePage;
bool m_shouldResetCodePage;
#endif
};

#endif /* CONSOLE_H_ */

0 comments on commit 999b7c8

Please sign in to comment.