Mercurial > games > semicongine
comparison svk/api.nim @ 1489:e6bd1f553c1b
add: quite a bit more wrapper
| author | sam <sam@basx.dev> |
|---|---|
| date | Sun, 18 May 2025 23:47:16 +0700 |
| parents | 3ce7c132fdac |
| children | 81da4be50663 |
comparison
equal
deleted
inserted
replaced
| 1488:3ce7c132fdac | 1489:e6bd1f553c1b |
|---|---|
| 5 import std/logging | 5 import std/logging |
| 6 import std/os | 6 import std/os |
| 7 | 7 |
| 8 include ./vkapi | 8 include ./vkapi |
| 9 | 9 |
| 10 const VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 3, 0) | 10 # ============================================================================= |
| 11 # UTILS ======================================================================= | |
| 12 # ============================================================================= | |
| 13 | |
| 14 if not defined(release): | |
| 15 addHandler(newConsoleLogger()) | |
| 16 addHandler(newFileLogger("svk.log")) | |
| 17 | |
| 18 # log level | |
| 19 when defined(release): | |
| 20 const LOGLEVEL {.strdefine.}: string = "Warn" | |
| 21 else: | |
| 22 const LOGLEVEL {.strdefine.}: string = "Debug" | |
| 23 setLogFilter(parseEnum[Level]("lvl" & LOGLEVEL)) | |
| 24 | |
| 25 template debugAssert(arg: untyped): untyped = | |
| 26 when not defined(release): | |
| 27 assert arg | |
| 28 | |
| 29 # we will support vulkan 1.2 for maximum portability | |
| 30 const VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 2, 0) | |
| 11 | 31 |
| 12 iterator items*[T: HoleyEnum](E: typedesc[T]): T = | 32 iterator items*[T: HoleyEnum](E: typedesc[T]): T = |
| 13 for a in enumFullRange(E): | 33 for a in enumFullRange(E): |
| 14 yield a | 34 yield a |
| 15 | 35 |
| 27 error "Vulkan error: ", astToStr(call), " returned ", $value | 47 error "Vulkan error: ", astToStr(call), " returned ", $value |
| 28 raise newException( | 48 raise newException( |
| 29 Exception, "Vulkan error: " & astToStr(call) & " returned " & $value | 49 Exception, "Vulkan error: " & astToStr(call) & " returned " & $value |
| 30 ) | 50 ) |
| 31 | 51 |
| 52 # ============================================================================= | |
| 53 # PLATFORM TYPES ============================================================== | |
| 54 # ============================================================================= | |
| 55 | |
| 56 when defined(windows): | |
| 57 type NativeWindow* = object | |
| 58 hinstance*: HINSTANCE | |
| 59 hwnd*: HWND | |
| 60 g_wpPrev*: WINDOWPLACEMENT | |
| 61 else: | |
| 62 type NativeWindow* = object | |
| 63 display*: ptr Display | |
| 64 window*: Window | |
| 65 emptyCursor*: Cursor | |
| 66 ic*: XIC | |
| 67 | |
| 68 | |
| 69 | |
| 70 | |
| 71 # ============================================================================= | |
| 72 # VULKAN INSTANCE ============================================================= | |
| 73 # ============================================================================= | |
| 74 | |
| 32 type SVkInstance* = object | 75 type SVkInstance* = object |
| 33 vkInstance: VkInstance | 76 vkInstance: VkInstance |
| 34 debugMessenger: VkDebugUtilsMessengerEXT | 77 debugMessenger: VkDebugUtilsMessengerEXT |
| 78 window: NativeWindow | |
| 79 vkSurface*: VkSurfaceKHR | |
| 80 | |
| 81 proc createWindow(title: string): NativeWindow | |
| 35 | 82 |
| 36 proc `=copy`(a: var SVkInstance, b: SVkInstance) {.error.} | 83 proc `=copy`(a: var SVkInstance, b: SVkInstance) {.error.} |
| 37 | 84 |
| 38 proc `=destroy`(a: SVkInstance) = | 85 proc `=destroy`(a: SVkInstance) = |
| 86 debugAssert a.vkInstance.pointer == nil | |
| 87 debugAssert a.vkSurface.pointer == nil | |
| 88 debugAssert a.debugMessenger.pointer == nil | |
| 89 | |
| 90 proc destroy*(a: var SVkInstance) = | |
| 39 if a.vkInstance.pointer != nil: | 91 if a.vkInstance.pointer != nil: |
| 40 if a.debugMessenger.pointer != nil: | 92 if a.debugMessenger.pointer != nil: |
| 41 vkDestroyDebugUtilsMessengerEXT(a.vkInstance, a.debugMessenger, nil) | 93 vkDestroyDebugUtilsMessengerEXT(a.vkInstance, a.debugMessenger, nil) |
| 94 a.debugMessenger = VkDebugUtilsMessengerEXT(nil) | |
| 95 vkDestroySurfaceKHR(a.vkInstance, a.vkSurface, nil) | |
| 96 a.vkSurface = VkSurfaceKHR(nil) | |
| 42 a.vkInstance.vkDestroyInstance(nil) | 97 a.vkInstance.vkDestroyInstance(nil) |
| 98 a.vkInstance = VkInstance(nil) | |
| 43 | 99 |
| 44 proc debugCallback( | 100 proc debugCallback( |
| 45 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, | 101 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, |
| 46 messageTypes: VkDebugUtilsMessageTypeFlagsEXT, | 102 messageTypes: VkDebugUtilsMessageTypeFlagsEXT, |
| 47 pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, | 103 pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, |
| 51 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug, | 107 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug, |
| 52 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo, | 108 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo, |
| 53 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn, | 109 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn, |
| 54 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError, | 110 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError, |
| 55 }.toTable | 111 }.toTable |
| 56 log LOG_LEVEL_MAPPING[messageSeverity] | 112 log LOG_LEVEL_MAPPING[messageSeverity], "SVK-LOG: ", $pCallbackData.pMessage |
| 57 if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: | 113 if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: |
| 58 # stderr.write getStackTrace() | |
| 59 # stderr.writeLine LOG_LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}" | |
| 60 let errorMsg = $pCallbackData.pMessage & ": " & getStackTrace() | 114 let errorMsg = $pCallbackData.pMessage & ": " & getStackTrace() |
| 61 raise newException(Exception, errorMsg) | 115 raise newException(Exception, errorMsg) |
| 62 return VK_FALSE | 116 return VK_FALSE |
| 63 | 117 |
| 64 proc svkCreateInstance*( | 118 proc svkCreateInstance*( |
| 65 applicationName: string, | 119 applicationName: string, |
| 66 enabledLayers: openArray[string] = [], | 120 enabledLayers: openArray[string] = [], |
| 67 enabledExtensions: openArray[string] = | 121 enabledExtensions: openArray[string] = |
| 68 if defined(release): | 122 if defined(release): |
| 69 @["VK_KHR_surface"] | 123 if defined(windows): |
| 124 @["VK_KHR_surface", "VK_KHR_win32_surface"] | |
| 125 else: | |
| 126 @["VK_KHR_surface", "VK_KHR_xlib_surface"] | |
| 70 else: | 127 else: |
| 71 @["VK_KHR_surface", "VK_EXT_debug_utils"], | 128 if defined(windows): |
| 129 @["VK_KHR_surface", "VK_EXT_debug_utils", "VK_KHR_win32_surface"] | |
| 130 else: | |
| 131 @["VK_KHR_surface", "VK_EXT_debug_utils", "VK_KHR_xlib_surface"], | |
| 72 engineName = "semicongine", | 132 engineName = "semicongine", |
| 73 withSwapchain = true, | |
| 74 ): SVkInstance = | 133 ): SVkInstance = |
| 75 putEnv("VK_LOADER_LAYERS_ENABLE", "*validation") | 134 putEnv("VK_LOADER_LAYERS_ENABLE", "*validation") |
| 76 putEnv( | 135 putEnv( |
| 77 "VK_LAYER_ENABLES", | 136 "VK_LAYER_ENABLES", |
| 78 "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", | 137 "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", |
| 79 ) | 138 ) |
| 80 initVulkanLoader() | 139 initVulkanLoader() |
| 81 | 140 |
| 141 var allLayers = @enabledLayers | |
| 142 when not defined(release): | |
| 143 allLayers.add "VK_LAYER_KHRONOS_validation" | |
| 144 | |
| 82 let | 145 let |
| 83 appinfo = VkApplicationInfo( | 146 appinfo = VkApplicationInfo( |
| 84 pApplicationName: applicationName, | 147 pApplicationName: applicationName, |
| 85 pEngineName: engineName, | 148 pEngineName: engineName, |
| 86 apiVersion: VULKAN_VERSION, | 149 apiVersion: VULKAN_VERSION, |
| 87 ) | 150 ) |
| 88 enabledLayersC = allocCStringArray(enabledLayers) | 151 enabledLayersC = allocCStringArray(allLayers) |
| 89 enabledExtensionsC = allocCStringArray(enabledExtensions) | 152 enabledExtensionsC = allocCStringArray(enabledExtensions) |
| 90 createinfo = VkInstanceCreateInfo( | 153 createinfo = VkInstanceCreateInfo( |
| 91 pApplicationInfo: addr appinfo, | 154 pApplicationInfo: addr appinfo, |
| 92 enabledLayerCount: enabledLayers.len.uint32, | 155 enabledLayerCount: allLayers.len.uint32, |
| 93 ppEnabledLayerNames: enabledLayersC, | 156 ppEnabledLayerNames: enabledLayersC, |
| 94 enabledExtensionCount: enabledExtensions.len.uint32, | 157 enabledExtensionCount: enabledExtensions.len.uint32, |
| 95 ppEnabledExtensionNames: enabledExtensionsC, | 158 ppEnabledExtensionNames: enabledExtensionsC, |
| 96 ) | 159 ) |
| 97 checkVkResult vkCreateInstance(addr createinfo, nil, addr result.vkInstance) | 160 checkVkResult vkCreateInstance(addr createinfo, nil, addr result.vkInstance) |
| 98 | 161 |
| 99 enabledLayersC.deallocCStringArray() | 162 enabledLayersC.deallocCStringArray() |
| 100 enabledExtensionsC.deallocCStringArray() | 163 enabledExtensionsC.deallocCStringArray() |
| 101 | 164 |
| 165 # only support up to vulkan 1.2 for maximum portability | |
| 102 load_VK_VERSION_1_0(result.vkInstance) | 166 load_VK_VERSION_1_0(result.vkInstance) |
| 103 load_VK_VERSION_1_1(result.vkInstance) | 167 load_VK_VERSION_1_1(result.vkInstance) |
| 104 load_VK_VERSION_1_2(result.vkInstance) | 168 load_VK_VERSION_1_2(result.vkInstance) |
| 105 load_VK_VERSION_1_3(result.vkInstance) | |
| 106 | 169 |
| 107 for extension in enabledExtensions: | 170 for extension in enabledExtensions: |
| 108 loadExtension(result.vkInstance, extension) | 171 loadExtension(result.vkInstance, extension) |
| 109 if withSwapchain: | 172 load_VK_KHR_swapchain(result.vkInstance) |
| 110 load_VK_KHR_swapchain(result.vkInstance) | 173 |
| 111 | 174 var allTypes: VkDebugUtilsMessageTypeFlagsEXT |
| 175 for t in VkDebugUtilsMessageTypeFlagBitsEXT: | |
| 176 allTypes = allTypes or t | |
| 112 when not defined(release): | 177 when not defined(release): |
| 113 var debugMessengerCreateInfo = VkDebugUtilsMessengerCreateInfoEXT( | 178 var debugMessengerCreateInfo = VkDebugUtilsMessengerCreateInfoEXT( |
| 114 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT.items.toSeq, | 179 messageSeverity: VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, |
| 115 messageType: VkDebugUtilsMessageTypeFlagBitsEXT.items.toSeq, | 180 messageType: VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, |
| 116 pfnUserCallback: debugCallback, | 181 pfnUserCallback: debugCallback, |
| 117 ) | 182 ) |
| 118 checkVkResult vkCreateDebugUtilsMessengerEXT( | 183 checkVkResult vkCreateDebugUtilsMessengerEXT( |
| 119 result.vkInstance, addr debugMessengerCreateInfo, nil, addr result.debugMessenger | 184 result.vkInstance, addr debugMessengerCreateInfo, nil, addr result.debugMessenger |
| 120 ) | 185 ) |
| 186 | |
| 187 | |
| 188 result.window = createWindow(applicationName) | |
| 189 when defined(windows): | |
| 190 var surfaceCreateInfo = VkWin32SurfaceCreateInfoKHR(hinstance: window.hinstance, hwnd: window.hwnd) | |
| 191 checkVkResult vkCreateWin32SurfaceKHR(instance, addr surfaceCreateInfo, nil, addr result.vkSurface) | |
| 192 else: | |
| 193 var surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR(dpy: result.window.display, window: result.window.window) | |
| 194 checkVkResult result.vkInstance.vkCreateXlibSurfaceKHR(addr surfaceCreateInfo, nil, addr result.vkSurface) | |
| 195 | |
| 196 | |
| 197 | |
| 198 # ============================================================================= | |
| 199 # PHYSICAL DEVICES ============================================================ | |
| 200 # ============================================================================= | |
| 201 | |
| 202 type | |
| 203 SVkMemoryType* = object | |
| 204 size: uint64 | |
| 205 deviceLocal: bool # fast for gpu access | |
| 206 hostCached: bool # fast for host access | |
| 207 hostVisible: bool # can use vkMapMemory | |
| 208 hostCohorent: bool # does *not* require vkFlushMappedMemoryRanges and vkInvalidateMappedMemoryRanges | |
| 209 SVkQueueFamilies* = object | |
| 210 count: int | |
| 211 hasGraphics: bool # implies "hasTransfer" | |
| 212 hasCompute: bool # implies "hasTransfer" | |
| 213 | |
| 214 SVkPhysicalDevice* = object | |
| 215 name*: string | |
| 216 vkPhysicalDevice*: VkPhysicalDevice | |
| 217 vkPhysicalDeviceFeatures*: VkPhysicalDeviceFeatures | |
| 218 vkPhysicalDeviceProperties*: VkPhysicalDeviceProperties | |
| 219 memoryTypes*: seq[SVkMemoryType] | |
| 220 queueFamily*: uint32 | |
| 221 | |
| 222 proc getUsablePhysicalDevices*(instance: SVkInstance): seq[SVkPhysicalDevice] = | |
| 223 var nDevices: uint32 | |
| 224 checkVkResult instance.vkInstance.vkEnumeratePhysicalDevices(addr nDevices, nil) | |
| 225 var devices = newSeq[VkPhysicalDevice](nDevices) | |
| 226 checkVkResult instance.vkInstance.vkEnumeratePhysicalDevices(addr nDevices, addr devices[0]) | |
| 227 for d in devices: | |
| 228 var dev = SVkPhysicalDevice(vkPhysicalDevice: d) | |
| 229 d.vkGetPhysicalDeviceFeatures(addr dev.vkPhysicalDeviceFeatures) | |
| 230 d.vkGetPhysicalDeviceProperties(addr dev.vkPhysicalDeviceProperties) | |
| 231 | |
| 232 if dev.vkPhysicalDeviceProperties.deviceType notin [VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]: | |
| 233 continue | |
| 234 dev.name = $cast[cstring](addr dev.vkPhysicalDeviceProperties.deviceName[0]) | |
| 235 | |
| 236 var memoryProperties: VkPhysicalDeviceMemoryProperties | |
| 237 d.vkGetPhysicalDeviceMemoryProperties(addr memoryProperties) | |
| 238 for i in 0 ..< memoryProperties.memoryTypeCount: | |
| 239 let heapI = memoryProperties.memoryTypes[i].heapIndex | |
| 240 dev.memoryTypes.add SVkMemoryType( | |
| 241 size: memoryProperties.memoryHeaps[heapI].size.uint64, | |
| 242 deviceLocal: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
| 243 hostCached: VK_MEMORY_PROPERTY_HOST_CACHED_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
| 244 hostVisible: VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
| 245 hostCohorent: VK_MEMORY_PROPERTY_HOST_COHERENT_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
| 246 ) | |
| 247 | |
| 248 | |
| 249 var familyQueueCount: uint32 | |
| 250 var vkQueueFamilyProperties: seq[VkQueueFamilyProperties] | |
| 251 d.vkGetPhysicalDeviceQueueFamilyProperties(addr familyQueueCount, nil) | |
| 252 vkQueueFamilyProperties.setLen(familyQueueCount) | |
| 253 d.vkGetPhysicalDeviceQueueFamilyProperties(addr familyQueueCount, addr vkQueueFamilyProperties[0]) | |
| 254 dev.queueFamily = high(uint32) | |
| 255 for i in 0 ..< familyQueueCount: | |
| 256 let hasGraphics = VK_QUEUE_GRAPHICS_BIT in vkQueueFamilyProperties[i].queueFlags | |
| 257 let hasCompute = VK_QUEUE_COMPUTE_BIT in vkQueueFamilyProperties[i].queueFlags | |
| 258 let hasPresentation = VK_FALSE | |
| 259 checkVkResult dev.vkPhysicalDevice.vkGetPhysicalDeviceSurfaceSupportKHR(i, instance.vkSurface, addr hasPresentation) | |
| 260 | |
| 261 if hasGraphics and hasCompute and bool(hasPresentation): | |
| 262 dev.queueFamily = i | |
| 263 break | |
| 264 if dev.queueFamily == high(uint32): | |
| 265 raise newException(Exception, "Did not find queue family with graphics and compute support!") | |
| 266 | |
| 267 result.add dev | |
| 268 | |
| 269 when defined(windows): | |
| 270 proc createWindow(title: string): NativeWindow = | |
| 271 result.hInstance = HINSTANCE(GetModuleHandle(nil)) | |
| 272 var | |
| 273 windowClassName = T"EngineWindowClass" | |
| 274 windowName = T(title) | |
| 275 windowClass = WNDCLASSEX( | |
| 276 cbSize: UINT(WNDCLASSEX.sizeof), | |
| 277 lpfnWndProc: windowHandler, | |
| 278 hInstance: result.hInstance, | |
| 279 lpszClassName: windowClassName, | |
| 280 hcursor: currentCursor, | |
| 281 ) | |
| 282 | |
| 283 if (RegisterClassEx(addr(windowClass)) == 0): | |
| 284 raise newException(Exception, "Unable to register window class") | |
| 285 | |
| 286 result.hwnd = CreateWindowEx( | |
| 287 DWORD(0), | |
| 288 windowClassName, | |
| 289 windowName, | |
| 290 DWORD(WS_OVERLAPPEDWINDOW), | |
| 291 CW_USEDEFAULT, | |
| 292 CW_USEDEFAULT, | |
| 293 CW_USEDEFAULT, | |
| 294 CW_USEDEFAULT, | |
| 295 HMENU(0), | |
| 296 HINSTANCE(0), | |
| 297 result.hInstance, | |
| 298 nil, | |
| 299 ) | |
| 300 | |
| 301 result.g_wpPrev.length = UINT(sizeof(WINDOWPLACEMENT)) | |
| 302 discard result.hwnd.ShowWindow(SW_SHOW) | |
| 303 discard result.hwnd.SetForegroundWindow() | |
| 304 discard result.hwnd.SetFocus() | |
| 305 | |
| 306 proc destroyWindow*(window: NativeWindow) = | |
| 307 DestroyWindow(window.hwnd) | |
| 308 | |
| 309 else: | |
| 310 import ../semicongine/thirdparty/x11/xkblib | |
| 311 import ../semicongine/thirdparty/x11/xutil | |
| 312 | |
| 313 var deleteMessage* {.hint[GlobalVar]: off.}: x.Atom # one internal use, not serious | |
| 314 | |
| 315 proc XErrorLogger(display: PDisplay, event: PXErrorEvent): cint {.cdecl.} = | |
| 316 logging.error "Xlib: " & $event[] | |
| 317 | |
| 318 proc createWindow(title: string): NativeWindow = | |
| 319 doAssert XInitThreads() != 0 | |
| 320 let display = XOpenDisplay(nil) | |
| 321 if display == nil: | |
| 322 quit "Failed to open display" | |
| 323 discard XSetErrorHandler(XErrorLogger) | |
| 324 | |
| 325 let screen = display.XDefaultScreen() | |
| 326 let rootWindow = display.XRootWindow(screen) | |
| 327 let vis = display.XDefaultVisual(screen) | |
| 328 discard display.XkbSetDetectableAutoRepeat(true, nil) | |
| 329 var | |
| 330 attribs: XWindowAttributes | |
| 331 width = cuint(800) | |
| 332 height = cuint(600) | |
| 333 doAssert display.XGetWindowAttributes(rootWindow, addr(attribs)) != 0 | |
| 334 | |
| 335 var attrs = XSetWindowAttributes( | |
| 336 event_mask: | |
| 337 FocusChangeMask or KeyPressMask or KeyReleaseMask or ExposureMask or | |
| 338 VisibilityChangeMask or StructureNotifyMask or ButtonMotionMask or ButtonPressMask or | |
| 339 ButtonReleaseMask | |
| 340 ) | |
| 341 let window = display.XCreateWindow( | |
| 342 rootWindow, | |
| 343 (attribs.width - cint(width)) div 2, | |
| 344 (attribs.height - cint(height)) div 2, | |
| 345 width, | |
| 346 height, | |
| 347 0, | |
| 348 display.XDefaultDepth(screen), | |
| 349 InputOutput, | |
| 350 vis, | |
| 351 CWEventMask, | |
| 352 addr(attrs), | |
| 353 ) | |
| 354 doAssert display.XSetStandardProperties(window, title, "window", 0, nil, 0, nil) != 0 | |
| 355 # get an input context, to allow encoding of key-events to characters | |
| 356 | |
| 357 let im = XOpenIM(display, nil, nil, nil) | |
| 358 assert im != nil | |
| 359 let ic = im.XCreateIC(XNInputStyle, XIMPreeditNothing or XIMStatusNothing, nil) | |
| 360 assert ic != nil | |
| 361 | |
| 362 doAssert display.XMapWindow(window) != 0 | |
| 363 | |
| 364 deleteMessage = display.XInternAtom("WM_DELETE_WINDOW", XBool(false)) | |
| 365 doAssert display.XSetWMProtocols(window, addr(deleteMessage), 1) != 0 | |
| 366 | |
| 367 var data = "\0".cstring | |
| 368 var pixmap = display.XCreateBitmapFromData(window, data, 1, 1) | |
| 369 var color: XColor | |
| 370 var empty_cursor = | |
| 371 display.XCreatePixmapCursor(pixmap, pixmap, addr(color), addr(color), 0, 0) | |
| 372 doAssert display.XFreePixmap(pixmap) != 0 | |
| 373 | |
| 374 discard display.XSync(0) | |
| 375 | |
| 376 # wait until window is shown | |
| 377 var ev: XEvent | |
| 378 while ev.theType != MapNotify: | |
| 379 discard display.XNextEvent(addr(ev)) | |
| 380 | |
| 381 result = NativeWindow(display: display, window: window, emptyCursor: empty_cursor, ic: ic) | |
| 382 | |
| 383 proc destroyWindow*(window: NativeWindow) = | |
| 384 doAssert XDestroyWindow(window.display, window.window) != 0 | |
| 385 |
