I’m happily using msys2 in combination with the pacman package manager to create a library. The library has a concept of windows, that is wrapped around HWND’s and winuser.h’s functions to create the window and window class. The windows are intended as a toplevel window. Normally I would suspect that a window, when opened for the first time, meets a Number of conditions:
- They are on top of the other (toplevel) windows. (this is – I think – what you get when you open e.g. chrome, word etc. via e.g. the windows taskbar or start menu.
- They are the ones that receive input from the keyboard.
No matter what I try, not one of the conditions above is met. The window is behind the msys2 terminal, but also all other opened windows. The icon of my program flickers with an orange color on the task bar at the bottom.
The class for my window is created as follows and is destroyed when the last of my windows is also destroyed.
static void
create_window_class(void)
{
g_module_handle = GetModuleHandle(NULL);
WNDCLASSEX win_class = {
.cbSize = sizeof(win_class),
.style = CS_OWNDC,
.lpfnWndProc = startup_winproc,
.hCursor = LoadCursor(NULL, IDC_ARROW),
.lpszClassName = g_win_class_name,
};
g_win_class = g_malloc0(sizeof(WNDCLASSEX));
*g_win_class = win_class;
g_win_class_atom = RegisterClassEx(g_win_class);
if (g_win_class_atom == 0) {
char error_buf[1024];
psy_strerr(GetLastError(), error_buf, sizeof(error_buf));
g_critical("Unable to create WindowClass '%s': %s",
g_win_class_name,
error_buf);
}
}
And then the window is created like this:
static void
win_window_constructed(GObject *object)
{
PsyWinWindow *self = PSY_WIN_WINDOW(object);
G_OBJECT_CLASS(psy_win_window_parent_class)->constructed(object);
DWORD win_style = WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU | WS_CAPTION;
DWORD win_style_ex = WS_EX_OVERLAPPEDWINDOW;
gint nth_mon = psy_window_get_monitor(PSY_WINDOW(self));
g_assert(nth_mon >= 0 && (guint) nth_mon < self->display_info->len);
PsyDisplayInfo *desired_monitor = self->display_info->pdata[nth_mon];
PsySize *size = desired_monitor->rect->size;
PsyPos *pos = desired_monitor->rect->pos;
RECT r = {
.bottom = 480, // pos->y + size->height,
.top = pos->x, // pos->y,
.right = 640, // pos->x + size->width,
.left = pos->y, // pos->x,
};
// We could use AdjustWindowRectEx to set the client size to the desired
// size however, we try just to create a window at fullscreen size
// AdjustWindowRectEx(&r, win_style, FALSE, win_style_ex);
self->window = CreateWindowEx(win_style_ex,
g_win_class_name,
"psy_window",
win_style,
r.left,
r.top,
r.right - r.left,
r.bottom - r.top,
NULL,
NULL,
g_module_handle,
self);
if (!self->window) {
char error_buff[1024];
psy_strerr(GetLastError(), error_buff, sizeof(error_buff));
g_critical("Unable to create window: %s", error_buff);
return;
}
BOOL success;
ShowWindow(self->window, SW_SHOWMAXIMIZED);
// Try to set it to the top in the Z-order, this functions
// succeeds, however, the windows Z-order policy doesn't
// allow the monitor to go to the top. Only once the user
// clicks it, it will go to the top. Currently, the window
// will flicker it's icon on the task bar.
//
// Also show the window.
success = SetWindowPos(self->window,
HWND_TOP,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
if (!success) {
char error_buf[1024];
psy_strerr(GetLastError(), error_buf, sizeof(error_buf));
g_critical("Unable to set window pos: %s", error_buf);
}
success = SetForegroundWindow(self->window);
if (!success) {
char error[1024];
psy_strerr(GetLastError(), error, sizeof(error));
g_critical(
"%s: Unable to set window to foreground: %s", __func__, error);
}
PsyD3dContext *context
= psy_d3d_context_new_full(self, 1, self->enable_debug);
psy_canvas_set_context(PSY_CANVAS(self), PSY_DRAWING_CONTEXT(context));
}
I run my programs using the msys2 terminal.
./some/path/myprogram.exe
I can see the window popping up, eh under that is. I see my program on the taskbar and if I use SetForegroundWindow(self->window)
, I can see the icon flickering in orange on the taskbar. I get messages such as WM_CREATE
, WM_ACTIVATE
(although I do get the message the keyboard remains with msys2 e.g pressing alt + f4 would close the msys2 terminal and not my window).
There are some corner cases, where the 2 points above are met.
- I run the command through gdb e.g.
gdb ./some/path/myprogram.exe
- I run cmd and start the program from there, it works only the first time.
- I can use HWND_TOPMOST with SetWindowPosition, but that only makes the window appear above the others, even when I switch to another window with alt+tab or mouse click and even then the keyboard input isn’t focused on my program. Besides, after the window is visible, I want users to be able to switch to a window of their choice. I have no intention of fighting the z-order of the windows.
Now it might have something to do with staring programs from the msys2 terminal.
If I run chrome via the msys2 terminal it also seems to pop under the other windows.
So my question boils down to: why do programs run via msys2 rather pop under in stead of pop up, and why isn’t the keyboard focus directed to the newly opened windows?
7