romegames 1
romegames
Krutzo 1
Krutzo
shrpnl 1
shrpnl
Best Studio 1
Best Studio
D 1
delimuratt
Aliyldrim 1
Aliyldrim
Mt2Hizmet 1
Mt2Hizmet
noisiv 1
noisiv
Manwe Work 1
Manwe Work
melankolıa18 1
melankolıa18
Agora Metin2 1
Agora Metin2
Cannn6161 1
Cannn6161
Hikaye Ekle
Reklam vermek için turkmmo@gmail.com

[FIX]Metin2 Client Window Centering Bug

GUNNERIUS

Level 20
TC Kimlik Numarası Doğrulanmış Üye
TM Üye
Katılım
10 Ocak 2009
Konular
3,748
Mesajlar
15,938
Çözüm
334
Online süresi
6mo 28d
Reaksiyon Skoru
8,027
Altın Konu
947
Başarım Puanı
474
Yaş
34
MmoLira
86,651
DevLira
-12
Ticaret - 100%
1   0   0

ROHAN2 WORLD 1-120 TR TİPİ OFFICIAL YOHARA, BALATHOR VE AMON! 80. GÜNÜNDE! +10.000 ONLİNE! HİLE VE BOT %100 ENGELLİ HEMEN TIKLA!

[C++] Metin2 Client Window Centering Bug (Win10 / Win11)
Gerçek Sebep ve Kalıcı Çözüm

Metin2 client’ında uzun zamandır var olan küçük ama fark edilen bir problem vardı.
Oyun penceresi açıldığında yatay eksende tam ortaya oturmuyordu.

Benim sistemimde bu fark yaklaşık 7 piksel civarındaydı.
Büyük bir şey değil ama “tam ortada değil” hissi net olarak vardı.

Before: pencere yatayda hafif sağa kayık

1768296062662.png

After: taskbar pozisyonu fark etmeksizin tam ortalanmış


before-png.XXXX


Bu sorun basit bir matematik hatası değil.

Win10 / Win11 üzerinde:
  • GetWindowRect() pencerenin gerçek görsel sınırlarını birebir yansıtmıyor
  • DWM (Desktop Window Manager) nedeniyle pencerenin sol ve sağ çerçeveleri simetrik değil

Bu yüzden klasik olarak kullanılan:
Kod:
(screenWidth - windowWidth) / 2
hesabı her zaman tam merkez vermiyor.

Bu çalışmayla birlikte birkaç küçük ama önemli temizlik de yapıldı.

  • Client penceresinin yatayda yaklaşık 7 piksel sağa kayık açılmasına sebep olan merkezleme mantığı düzeltildi
  • Pencere artık kullanıcının gerçekten gördüğü frame’e göre ortalanıyor (Win10 / Win11 DWM uyumlu)
  • GetWindowRect için yazılmış, WinAPI ismiyle çakışan gereksiz wrapper fonksiyon kaldırıldı
  • FindWindow ile pencere başlığına bakarak yapılan “another window” reposition mantığı tamamen kaldırıldı
  • Bu kod modern Windows sürümlerinde deterministik çalışmıyordu ve merkezlemeyi bozuyordu
  • Sabit offset, magic number veya “biraz sola kaydır” tarzı hack’ler kullanılmadı
  • Pencere artık her zaman work area içinde, taskbar’a taşmadan ve kayık olmadan açılıyor

Aşağıdaki video, yapılan değişiklikten sonraki sonucu gösteriyor:





Uygulama kısmı:

Client\\Source\\EterLib\\MSWindow.cpp dosyasında aşağıdaki wrapper fonksiyonu bulun ve silin:

Kod:
void CMSWindow::GetWindowRect(RECT* prc)
{
    ::GetWindowRect(m_hWnd, prc);
}

Ardından DWM uyumlu yeni yardımcı fonksiyonları ekleyin:

Kod:
static bool GetVisualWindowRect(HWND hwnd, RECT& outRect)
{
    if (!::GetWindowRect(hwnd, &outRect))
        return false;

    using DwmGetWindowAttributeFn = HRESULT(WINAPI*)(HWND, DWORD, PVOID, DWORD);
    constexpr DWORD ExtendedFrameBounds = 9;

    static HMODULE s_dwm = ::LoadLibraryA("dwmapi.dll");
    if (!s_dwm)
        return true;

    static auto s_getAttr =
        reinterpret_cast<DwmGetWindowAttributeFn>(
            ::GetProcAddress(s_dwm, "DwmGetWindowAttribute"));

    if (!s_getAttr)
        return true;

    RECT visual{};
    if (SUCCEEDED(s_getAttr(hwnd, ExtendedFrameBounds, &visual, sizeof(visual))))
    {
        outRect = visual;
    }

    return true;
}

static POINT GetCenteredPosition(const RECT& visualRect, const RECT& workArea, const RECT& windowRect)
{
    const int width = visualRect.right - visualRect.left;
    const int height = visualRect.bottom - visualRect.top;

    const int dx = visualRect.left - windowRect.left;
    const int dy = visualRect.top - windowRect.top;

    POINT pt{};
    pt.x = workArea.left + ((workArea.right - workArea.left) - width) / 2 - dx;
    pt.y = workArea.top + ((workArea.bottom - workArea.top) - height) / 2 - dy;
    return pt;
}

CMSWindow::SetCenterPosition() fonksiyonunu aşağıdaki şekilde değiştirin:

Kod:
void CMSWindow::SetCenterPosition()
{
    RECT window{};
    RECT visual{};
    RECT workArea{};

    if (!::GetWindowRect(m_hWnd, &window))
        return;

    visual = window;
    GetVisualWindowRect(m_hWnd, visual);

    ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);

    const POINT pos = GetCenteredPosition(visual, workArea, window);
    SetPosition(pos.x, pos.y);
}

Client\\Source\\EterLib\\MSWindow.h dosyasında aşağıdaki tanımı silin:

Kod:
void GetWindowRect(RECT* prc);

Client\\Source\\UserInterface\\PythonApplication.cpp içinde aşağıdaki kodu bulun ve kaldırın:

Kod:
bool bAnotherWindow = false;

if (FindWindow(NULL, c_szName))
{
    bAnotherWindow = true;
}

AdjustSize çağrısının hemen altına şunu ekleyin:

Kod:
CMSWindow::SetCenterPosition();

Ve aşağıdaki bloğu tamamen silin:

Kod:
if (bAnotherWindow)
{
    RECT rc;

    GetClientRect(&rc);

    int windowWidth = rc.right - rc.left;
    int windowHeight = rc.bottom - rc.top;

    CMSApplication::SetPosition(
        GetScreenWidth() - windowWidth,
        GetScreenHeight() - 60 - windowHeight);
}

Bu değişiklikten sonra pencere artık piksel şaşması olmadan, taskbar konumundan bağımsız şekilde tam ortaya oturur.
Herhangi bir sabit offset veya geçici çözüm kullanılmaz, davranış tamamen deterministiktir.

Kaptan Yosun'dan alıntıdır. İyi kullanımlar dilerim.​

 
PAYLAŞIM İÇİN TEŞEKKÜRLER, ELİNİZE SAĞLIK ADMİNİM.
 
Paylaşım için teşekkürler.
 
Eline sağlık, paylaşım için teşekkürler :)
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst