aboutsummaryrefslogtreecommitdiff
path: root/src/mingwMain/kotlin/moe/yuuta/aero/Aero.kt
blob: 44c184e99561694b306b7566456ab5657bafa3f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package moe.yuuta.aero

import kotlinx.cinterop.*
import platform.windows.*

fun main() {
    SetProcessDPIAware()
    val className = "Main Window Class"

    memScoped {
        val wc = cValue<WNDCLASSA> {
            lpfnWndProc = staticCFunction(::windowProc)
            this.hInstance = hInstance
            lpszClassName = className.cstr.ptr
        }
        RegisterClassA(wc.ptr)
        return@memScoped wc
    }

    val hwnd = CreateWindowExA(
        0.convert(),
        className,
        "", // Filling texts will get the white background of the label
        WS_OVERLAPPEDWINDOW.convert(),
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        null,
        null,
        WinCompat.hInstance,
        null
    )

    val forceDialogEnv = WinApi.getenv("AERO_DEMO_FORCE_DIALOG")

    if (hwnd == null || (forceDialogEnv == "true")) {
        if (hwnd == null) {
            MessageBoxA(null,
                "The system returns an empty dialog (${GetLastError()})",
                "Aero",
                (MB_OK or MB_ICONERROR).convert())
        }
        memScoped {
            // Fallback
            val dlgImpl = cValue<DLGTEMPLATE> {
                style = (WS_OVERLAPPEDWINDOW or
                        DS_CENTER or
                        DS_MODALFRAME).convert()
                dwExtendedStyle = 0.convert()
                cdit = 0.convert()
                x = 0
                y = 0
                cx = 400
                cy = 200
            }
            return@memScoped DialogBoxIndirectParamW(WinCompat.hInstance,
                dlgImpl.ptr,
                null,
                staticCFunction(::dlgProc),
                0)
        }
    } else {
        ShowWindow(hwnd, WinCompat.nCmdShow)
        WinApi.msgLoop()
    }
}

fun windowProc(hwnd: HWND?,
               uMsg: UINT,
               wParam: WPARAM,
               lParam: LPARAM): LRESULT {
    return when (uMsg.convert<Int>()) {
        WM_CREATE -> {
            WinApi.setAero(hwnd)
            1
        }
        WM_DESTROY -> {
            PostQuitMessage(0)
            1
        }
        WM_PAINT -> {
            val ps = nativeHeap.alloc<PAINTSTRUCT>()
            val hdc = BeginPaint(hwnd, ps.ptr)
            FillRect(hdc,
                ps.rcPaint.ptr,
                GetStockObject(BLACK_BRUSH) as HBRUSH)
            EndPaint(hwnd, ps.ptr)
            nativeHeap.free(ps)
            1
        }
        else -> {
            DefWindowProcA(hwnd, uMsg, wParam, lParam)
        }
    }
}

fun dlgProc(hDlg: HWND?,
            message: UINT,
            wParam: WPARAM,
            lParam: LPARAM): INT_PTR {
    when (message.convert<Int>()) {
        WM_INITDIALOG -> {
            WinApi.setAero(hDlg)
            return true.toByte().toLong()
        }
        WM_COMMAND -> {
            EndDialog(hDlg, wParam.convert())
            return true.toByte().toLong()
        }
        WM_CTLCOLORDLG -> {
            return GetStockObject(BLACK_BRUSH).rawValue.toLong()
        }
        else -> {
            return false.toByte().toLong()
        }
    }
}