2 Commits

Author SHA1 Message Date
Liam Bowen
a858280c5d Add .editorconfig to use tabs 2016-03-19 17:38:55 +01:00
David Macek
8ea0ca32a3 Adapted to Msys 2015-12-31 21:28:31 +01:00
16 changed files with 280 additions and 102 deletions

4
.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
root = true
[*.{c,h}]
indent_style = tab

12
.gitignore vendored
View File

@@ -1,6 +1,6 @@
/mingw32.exe /msys.exe
/mingw32.res /msys.res
/mingw64.exe /msys.ini
/mingw64.res /mingw.exe
/msys2.exe /mingw.res
/msys2.res /mingw.ini

View File

@@ -1,19 +1,22 @@
all: msys2.exe mingw32.exe mingw64.exe PREFIX=
msys2.res: launcher.rc msys2.ico msys: msys.exe msys.ini mingw.exe mingw.ini
windres -O COFF -o $@ $< -DMSYSTEM=MSYS -DICONFILE=msys2.ico all: msys
msys2.exe: launcher.c msys2.res
gcc -Wall -Wextra -static -mwindows -o $@ $^ -luuid -lshlwapi -lpsapi -DMSYSTEM=MSYS
strip $@
mingw32.res: launcher.rc mingw32.ico .PHONY: all msys
windres -O COFF -o $@ $< -DMSYSTEM=MINGW32 -DICONFILE=mingw32.ico
mingw32.exe: launcher.c mingw32.res
gcc -Wall -Wextra -static -mwindows -o $@ $^ -luuid -lshlwapi -lpsapi -DMSYSTEM=MINGW32
strip $@
mingw64.res: launcher.rc mingw64.ico msys.ini: launcher.ini
windres -O COFF -o $@ $< -DMSYSTEM=MINGW64 -DICONFILE=mingw64.ico cp -f $^ $@
mingw64.exe: launcher.c mingw64.res echo MSYSTEM=MSYS>> $@
gcc -Wall -Wextra -static -mwindows -o $@ $^ -luuid -lshlwapi -lpsapi -DMSYSTEM=MINGW64 msys.res: launcher.rc msys.ico
strip $@ $(PREFIX)windres -O COFF -o $@ $< -DMSYSTEM=MSYS -DICONFILE=msys.ico
msys.exe: launcher.c msys.res
$(PREFIX)gcc -std=c11 -Wall -Wextra -Werror -municode -mwindows -o $@ $^ -luuid -lshlwapi -lpsapi
mingw.ini: launcher.ini
cp -f $^ $@
echo MSYSTEM=MINGW32>> $@
mingw.res: launcher.rc mingw.ico
$(PREFIX)windres -O COFF -o $@ $< -DMSYSTEM=MINGW32 -DICONFILE=mingw.ico
mingw.exe: launcher.c mingw.res
$(PREFIX)gcc -std=c11 -Wall -Wextra -Werror -municode -mwindows -o $@ $^ -luuid -lshlwapi -lpsapi

View File

@@ -1,9 +1,9 @@
MSYS2 launcher Msys launcher
============== ==============
A helper for launching MSYS2 shells. Features blink-less launching and correct taskbar/start pinning. A helper for launching Msys shells, adapted from the MSYS2 launcher. Features almost blink-less launching and correct taskbar/start pinning.
Installation Installation
------------ ------------
Just `make` and put the executables inside your MSYS2 root. Just `make` and put the executables inside your Msys root.

View File

@@ -1,3 +1,4 @@
#define _UNICODE
#define _WIN32_WINNT 0x0601 #define _WIN32_WINNT 0x0601
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define PSAPI_VERSION 1 #define PSAPI_VERSION 1
@@ -17,25 +18,39 @@
#include "macros.h" #include "macros.h"
static void ShowError(const char* desc, const char* err, const long code) { // if any of the properties change, it's best to use a brand new AppID
char msg[1024]; #define APPID_REVISION 9
sprintf(msg, "%s. Reason: %s (0x%lx)", desc, err, code); struct MainWindow {
MessageBox(NULL, msg, "Launcher error", MB_ICONEXCLAMATION | MB_OK); DWORD pid;
HWND handle;
};
static void ShowError(const wchar_t* desc, const wchar_t* err, const long code) {
wchar_t msg[1024];
swprintf(msg, 1024, L"%s. Reason: %s (0x%lx)", desc, err, code);
MessageBox(NULL, msg, L"Launcher error", MB_ICONEXCLAMATION | MB_OK);
} }
static void ShowLastError(const char* desc) { static void ShowLastError(const wchar_t* desc) {
DWORD code; DWORD code;
char* err; wchar_t* err;
code = GetLastError(); code = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&err, 0, NULL); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&err, 0, NULL);
ShowError(desc, err, code); ShowError(desc, err, code);
LocalFree(err); LocalFree(err);
} }
static void ShowErrno(const wchar_t* desc) {
wchar_t* err;
PROCESS_INFORMATION StartChild(const wchar_t* cmdline) { err = _wcserror(errno);
ShowError(desc, err, errno);
}
static PROCESS_INFORMATION StartChild(wchar_t* cmdline) {
STARTUPINFOW si; STARTUPINFOW si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
DWORD code; DWORD code;
@@ -44,69 +59,124 @@ PROCESS_INFORMATION StartChild(const wchar_t* cmdline) {
si.cb = sizeof(si); si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi)); ZeroMemory(&pi, sizeof(pi));
SetLastError(0); SetLastError(0);
code = CreateProcessW(NULL, (wchar_t*)cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); code = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (code == 0) { if (code == 0) {
ShowLastError("Could not start the shell"); ShowLastError(L"Could not start the shell");
ShowError(L"The command was", cmdline, 0);
return pi; return pi;
} }
return pi; return pi;
} }
static int SetEnv(const char* msystem) { static wchar_t* SetEnv(wchar_t* conffile) {
int code; int code;
char* env; size_t buflen;
const char* err; size_t expandedlen;
const char prefix[] = "MSYSTEM="; wchar_t* tmp;
wchar_t* buf;
wchar_t* expanded;
wchar_t* msystem;
FILE* handle;
env = (char*)alloca(strlen(prefix) + strlen(msystem) + 1); msystem = NULL;
strcpy(env, prefix);
strcat(env, msystem); handle = _wfopen(conffile, L"rt");
code = putenv(env); if (handle == NULL) {
if (code != 0) { ShowErrno(L"Could not open configuration file");
err = strerror(errno); return msystem;
ShowError("Could not set MSYSTEM", err, errno);
return 0;
} }
return 1; buflen = 512;
buf = (wchar_t*)malloc(buflen * sizeof(wchar_t));
*buf = L'\0';
expandedlen = 2 * buflen;
expanded = (wchar_t*)malloc(expandedlen * sizeof(wchar_t));
while (true) {
tmp = fgetws(buf + wcslen(buf), buflen - wcslen(buf), handle);
if (tmp == NULL && !feof(handle)) {
ShowErrno(L"Could not read from configuration file");
return NULL;
}
tmp = buf + wcslen(buf) - 1;
if (!feof(handle) && *tmp != L'\n') {
buflen *= 2;
buf = (wchar_t*)realloc(buf, buflen * sizeof(wchar_t));
continue;
}
if (!feof(handle)) {
*tmp = L'\0';
}
if (*buf != L'\0' && *buf != L'#') {
tmp = wcschr(buf, L'=');
if (tmp != NULL) {
*tmp++ = L'\0';
while (expandedlen < 32768) {
code = ExpandEnvironmentStrings(tmp, expanded, expandedlen);
if ((size_t)code <= expandedlen) {
break;
}
expandedlen *= 2;
expanded = (wchar_t*)realloc(expanded, expandedlen * sizeof(wchar_t));
}
if ((*tmp != L'\0' && code == 0) || (size_t)code > expandedlen) {
ShowLastError(L"Could not expand string");
}
if (0 == wcscmp(L"MSYSTEM", buf)) {
msystem = _wcsdup(expanded);
if (msystem == NULL) {
ShowError(L"Could not duplicate string", expanded, 0);
return NULL;
}
}
code = SetEnvironmentVariable(buf, expanded);
if (code == 0) {
ShowLastError(L"Could not set environment variable");
}
} else {
ShowError(L"Could not parse environment line", buf, 0);
}
}
*buf = L'\0';
if (feof(handle)) {
break;
}
}
code = fclose(handle);
if (code != 0) {
ShowErrno(L"Could not close configuration file");
}
return msystem;
} }
struct handle_data { static bool IsMainWindow(HWND handle) {
unsigned long process_id;
HWND best_handle;
};
BOOL is_main_window(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle); return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
} }
static BOOL CALLBACK CheckWindow(HWND handle, LPARAM lParam) {
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam) struct MainWindow* data = (struct MainWindow*)lParam;
{ DWORD pid = 0;
struct handle_data* data = (struct handle_data*)lParam; GetWindowThreadProcessId(handle, &pid);
unsigned long process_id = 0; if (data->pid != pid || !IsMainWindow(handle)) {
GetWindowThreadProcessId(handle, &process_id);
if (data->process_id != process_id || !is_main_window(handle)) {
return TRUE; return TRUE;
} }
data->best_handle = handle; data->handle = handle;
return FALSE; return FALSE;
} }
HWND find_main_window(unsigned long process_id) static HWND FindMainWindow(DWORD pid) {
{ struct MainWindow data;
struct handle_data data; data.pid = pid;
data.process_id = process_id; data.handle = 0;
data.best_handle = 0; EnumWindows(CheckWindow, (LPARAM)&data);
EnumWindows(enum_windows_callback, (LPARAM)&data); return data.handle;
return data.best_handle;
} }
HRESULT SetAppUserModelProperty(IPropertyStore* store, const PROPERTYKEY* key, LPCWSTR value) { HRESULT SetAppUserModelProperty(IPropertyStore* store, const PROPERTYKEY* key, LPCWSTR value) {
PROPVARIANT propVariant; PROPVARIANT propVariant;
HRESULT hr; HRESULT hr;
@@ -125,45 +195,116 @@ HRESULT SetAppUserModelProperty(IPropertyStore* store, const PROPERTYKEY* key, L
return 0; return 0;
} }
int wmain(int argc, wchar_t* argv[]) {
int main(int argc, char* argv[]) {
PROCESS_INFORMATION child; PROCESS_INFORMATION child;
DWORD code; int code;
int res; int delay = 10;
HWND window; HWND window;
IPropertyStore* store; IPropertyStore* store;
HRESULT hr; HRESULT hr;
size_t buflen; size_t buflen;
wchar_t* buf; wchar_t* buf;
wchar_t msysdir[PATH_MAX], exepath[PATH_MAX]; wchar_t* tmp;
int delay = 10; wchar_t* args;
wchar_t* msystem;
wchar_t msysdir[PATH_MAX];
wchar_t exepath[PATH_MAX];
wchar_t confpath[PATH_MAX];
wchar_t wdpath[PATH_MAX];
const size_t proplen = 100;
wchar_t prop[proplen];
UNUSED(argc); code = GetCurrentDirectory(PATH_MAX, wdpath);
UNUSED(argv); if (code == 0 || code > PATH_MAX) {
ShowErrno(L"Could not determine working directory");
code = GetModuleFileNameW(NULL, exepath, sizeof(exepath) / sizeof(exepath[0]));
if (code == 0) {
ShowLastError("Could not determine executable path");
return __LINE__; return __LINE__;
} }
while (wcschr(exepath, L'\\') != NULL) { tmp = wdpath;
wcschr(exepath, L'\\')[0] = L'/'; while (true) {
tmp = wcschr(tmp, L'\\');
if (tmp == NULL) {
break;
}
*tmp = L'/';
} }
code = GetModuleFileName(NULL, exepath, sizeof(exepath) / sizeof(exepath[0]));
if (code == 0) {
ShowLastError(L"Could not determine executable path");
return __LINE__;
}
tmp = exepath;
while (true) {
tmp = wcschr(tmp, L'/');
if (tmp == NULL) {
break;
}
*tmp = L'\\';
}
wcscpy(msysdir, exepath); wcscpy(msysdir, exepath);
if (wcsrchr(msysdir, L'/') != NULL) { tmp = wcsrchr(msysdir, L'\\');
wcsrchr(msysdir, L'/')[0] = L'\0'; if (tmp == NULL) {
ShowError(L"Could not find root directory", msysdir, 0);
return __LINE__;
} }
buflen = wcslen(msysdir) + 1000; *tmp = L'\0';
buf = (wchar_t*)alloca(buflen * sizeof(wchar_t));
code = SetEnv(STRINGIFY_A(MSYSTEM)); wcscpy(confpath, exepath);
if (code == 0) { tmp = confpath + wcslen(confpath) - 4;
if (0 != wcsicmp(L".exe", tmp)) {
ShowError(L"Could not find configuration file", confpath, 0);
return __LINE__;
}
*tmp++ = L'.';
*tmp++ = L'i';
*tmp++ = L'n';
*tmp++ = L'i';
if (argc > 1) {
code = SetEnvironmentVariable(L"CHERE_INVOKING", L"1");
if (code == 0) {
ShowLastError(L"Could not set environment variable");
}
}
msystem = SetEnv(confpath);
if (msystem == NULL) {
ShowError(L"Did not find the MSYSTEM variable", confpath, 0);
return __LINE__; return __LINE__;
} }
res = swprintf(buf, buflen, L"%s/usr/bin/mintty.exe -i '%s' /usr/bin/bash --login -i", msysdir, exepath); code = SetEnvironmentVariable(L"MSYSCON", L"mintty.exe");
if (res < 0) { if (code == 0) {
ShowLastError(L"Could not set environment variable");
}
// can break, but hopefully won't for most use cases
args = GetCommandLine();
if (args[0] == L'"') {
args++;
}
args += wcslen(argv[0]);
if (args[0] == L'"') {
args++;
}
code = -1;
buf = NULL;
buflen = 1024;
while (code < 0 && buflen < 8192) {
buf = (wchar_t*)realloc(buf, buflen * sizeof(wchar_t));
if (buf == NULL) {
ShowError(L"Could not allocate memory", L"", 0);
return __LINE__;
}
code = swprintf(buf, buflen, L"%s\\bin\\mintty.exe -i '%s' -- /bin/bash --login -c 'cd \\'%s\\'; exec %s'", msysdir, exepath, wdpath, argc == 1 ? L"/bin/bash -i" : args);
buflen *= 2;
}
if (code < 0) {
ShowErrno(L"Could not write to buffer");
return __LINE__; return __LINE__;
} }
@@ -172,9 +313,12 @@ int main(int argc, char* argv[]) {
return __LINE__; return __LINE__;
} }
free(buf);
buf = NULL;
while (true) { while (true) {
Sleep(delay); Sleep(delay);
window = find_main_window(GetProcessId(child.hProcess)); window = FindMainWindow(GetProcessId(child.hProcess));
if (!window) { if (!window) {
delay *= 2; delay *= 2;
if (delay > 60000) { if (delay > 60000) {
@@ -188,12 +332,22 @@ int main(int argc, char* argv[]) {
return __LINE__; return __LINE__;
} }
hr = SetAppUserModelProperty(store, &PKEY_AppUserModel_ID, L"MSYS2.Shell." STRINGIFY_W(MSYSTEM) L".7"); code = swprintf(prop, proplen, L"Msys.Shell.%s.%d", msystem, APPID_REVISION);
if (code < 0) {
ShowErrno(L"Could not write to buffer");
return __LINE__;
}
hr = SetAppUserModelProperty(store, &PKEY_AppUserModel_ID, prop);
if (FAILED(hr)) { if (FAILED(hr)) {
return __LINE__; return __LINE__;
} }
hr = SetAppUserModelProperty(store, &PKEY_AppUserModel_RelaunchDisplayNameResource, L"MSYS2 " STRINGIFY_W(MSYSTEM) L" shell"); code = swprintf(prop, proplen, L"Msys %s Shell", msystem);
if (code < 0) {
ShowErrno(L"Could not write to buffer");
return __LINE__;
}
hr = SetAppUserModelProperty(store, &PKEY_AppUserModel_RelaunchDisplayNameResource, prop);
if (FAILED(hr)) { if (FAILED(hr)) {
return __LINE__; return __LINE__;
} }

4
launcher.ini Normal file
View File

@@ -0,0 +1,4 @@
#MSYS=winsymlinks:nativestrict
#MSYS=error_start:mingw64/bin/qtcreator.exe|-debug|<process-id>
#CHERE_INVOKING=1
#PATH=%SystemRoot%\System32;%SystemRoot%;%SystemRoot%\System32\Wbem

View File

@@ -1,15 +1,16 @@
#include "macros.h" #include "macros.h"
#include "version.h"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 0,1,0,0 FILEVERSION VER_MAJOR,VER_MINOR,0,0
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
BLOCK "040904E4" BLOCK "040904E4"
BEGIN BEGIN
VALUE "ProductName", "MSYS2" VALUE "ProductName", "Msys"
VALUE "FileDescription", "MSYS2/" STRINGIFY_A(MSYSTEM) " shell launcher" VALUE "FileDescription", "Msys " STRINGIFY_A(MSYSTEM) " shell launcher"
VALUE "FileVersion", "0.1" VALUE "FileVersion", STRINGIFY_A(VER_MAJOR) "." STRINGIFY_A(VER_MINOR)
END END
END END

View File

@@ -1,3 +1,6 @@
#ifndef M2L_MACROS_H
#define M2L_MACROS_H
#define UNUSED(x) ((void)(x)) #define UNUSED(x) ((void)(x))
#define STRINGIFY_A_(x) #x #define STRINGIFY_A_(x) #x
@@ -5,3 +8,5 @@
#define STRINGIFY_W_(x) L ## #x #define STRINGIFY_W_(x) L ## #x
#define STRINGIFY_W(x) STRINGIFY_W_(x) #define STRINGIFY_W(x) STRINGIFY_W_(x)
#endif

BIN
mingw.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

BIN
msys.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
msys2.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

7
version.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef M2L_VERSION_H
#define M2L_VERSION_H
#define VER_MAJOR 0
#define VER_MINOR 1
#endif