0011 최대화한 창이 원래 크기로 돌아오지 않음

From 카카오톡 on Wine
Jump to navigationJump to search

Super + 위로 최대화한 다음 Super + 아래를 눌러도 창이 꿈쩍도 하지 않습니다. GNOME 쪽은 최대화를 푼 것으로 알고 있고, 창만 큰 채로 남습니다.

추적을 켜고 두 번 눌러보면 이렇게 나옵니다.

xdg_toplevel_handle_configure hwnd=0x10078 1920x1048,0x5   ← 최대화
wayland_configure_window processing=1920x1048,0x5
wayland_surface_update_state_toplevel window_state=0x1

xdg_toplevel_handle_configure hwnd=0x10078 960x1048,0      ← 최대화 해제
wayland_configure_window processing=0x0,0
wayland_surface_update_state_toplevel window_state=0

컴포지터는 960x1048을 또박또박 보내주는데 드라이버 쪽에서는 0x0이 됩니다. 일부러 그렇게 합니다. 최대화나 전체화면처럼 크기를 꼭 지켜야 하는 상태가 아니면 configure에 실린 크기는 권고일 뿐이라, wayland_configure_window가 버립니다.

if (state)
{
    width = surface->processing.rect.right - surface->processing.rect.left;
    height = surface->processing.rect.bottom - surface->processing.rect.top;
}
else
{
    width = height = 0;
}

여기까지는 맞습니다. 문제는 그 다음입니다. 상태가 바뀐 것은 반영해야 하니 WS_MAXIMIZE를 손으로 떼는데, 크기는 0이라 같이 붙는 SetWindowPos는 SWP_NOSIZE로 아무것도 안 합니다.

NtUserSetWindowLong(hwnd, GWL_STYLE, style ^ WS_MAXIMIZE, FALSE);

그래서 스타일 비트만 떨어지고 창은 최대화된 크기 그대로입니다. 게다가 이제 원래 크기를 기억하는 곳이 아무 데도 없습니다. 컴포지터는 자기가 보낸 크기가 반영되지 않으니 같은 configure를 계속 다시 보내고, 로그가 몇 초에 한 번씩 같은 줄로 채워집니다.

원래 크기는 Win32가 압니다. 창을 최대화할 때 normal placement를 저장해 두니까요. 그래서 비트를 손으로 떼는 대신 SC_RESTORE를 보내 Win32에게 복원을 맡겼습니다. 바로 위에 있는 최소화 복원이 이미 같은 방식입니다.

TRACE("hwnd=%p restoring from maximize\n", hwnd);
surface->current = surface->processing;
memset(&surface->processing, 0, sizeof(surface->processing));
xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial);
wayland_win_data_release(data);
send_message(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);

configure를 먼저 ack하는 것은 프로토콜 위반을 피하려는 것이고, SC_RESTORE가 창을 줄이면 그때 configure 주기가 새로 돕니다.

최소화된 창은 건드리지 않습니다. 최소화하기 전에 최대화돼 있던 창은 WS_MAXIMIZE와 WS_MINIMIZE를 함께 가지고 있어서, 여기서 복원을 보내면 사용자가 내려둔 창이 혼자 올라옵니다.