Mercurial > games > semicongine
comparison semiconginev2/platform/linux/window.nim @ 1227:4d97cfc4888b
merge
| author | sam <sam@basx.dev> |
|---|---|
| date | Wed, 17 Jul 2024 23:45:43 +0700 |
| parents | 56781cc0fc7c |
| children |
comparison
equal
deleted
inserted
replaced
| 1170:2addc5f6804f | 1227:4d97cfc4888b |
|---|---|
| 1 import ../../thirdparty/x11/xlib | |
| 2 import ../../thirdparty/x11/xutil | |
| 3 import ../../thirdparty/x11/keysym | |
| 4 import ../../thirdparty/x11/x as x11 | |
| 5 import ../../thirdparty/x11/xkblib | |
| 6 | |
| 7 include ./symkey_map | |
| 8 | |
| 9 var deleteMessage*: Atom | |
| 10 | |
| 11 type | |
| 12 NativeWindow* = object | |
| 13 display*: ptr xlib.Display | |
| 14 window*: x11.Window | |
| 15 emptyCursor: Cursor | |
| 16 | |
| 17 template checkXlibResult(call: untyped) = | |
| 18 let value = call | |
| 19 if value == 0: | |
| 20 raise newException(Exception, "Xlib error: " & astToStr(call) & | |
| 21 " returned " & $value) | |
| 22 | |
| 23 proc XErrorLogger(display: PDisplay, event: PXErrorEvent): cint {.cdecl.} = | |
| 24 logging.error &"Xlib: {event[]}" | |
| 25 | |
| 26 proc CreateWindow*(title: string): NativeWindow = | |
| 27 checkXlibResult XInitThreads() | |
| 28 let display = XOpenDisplay(nil) | |
| 29 if display == nil: | |
| 30 quit "Failed to open display" | |
| 31 discard XSetErrorHandler(XErrorLogger) | |
| 32 | |
| 33 let rootWindow = display.XDefaultRootWindow() | |
| 34 discard display.XkbSetDetectableAutoRepeat(true, nil) | |
| 35 var | |
| 36 attribs: XWindowAttributes | |
| 37 width = cuint(800) | |
| 38 height = cuint(600) | |
| 39 checkXlibResult display.XGetWindowAttributes(rootWindow, addr(attribs)) | |
| 40 | |
| 41 var attrs = XSetWindowAttributes() | |
| 42 let window = XCreateWindow( | |
| 43 display, | |
| 44 rootWindow, | |
| 45 (attribs.width - cint(width)) div 2, (attribs.height - cint(height)) div 2, | |
| 46 width, height, | |
| 47 0, | |
| 48 CopyFromParent, | |
| 49 InputOutput, | |
| 50 cast[PVisual](CopyFromParent), | |
| 51 0, # CWOverrideRedirect, | |
| 52 addr attrs, | |
| 53 # foregroundColor, backgroundColor | |
| 54 ) | |
| 55 checkXlibResult XSetStandardProperties(display, window, title, "window", 0, nil, 0, nil) | |
| 56 checkXlibResult XSelectInput(display, window, PointerMotionMask or ButtonPressMask or ButtonReleaseMask or KeyPressMask or KeyReleaseMask or ExposureMask) | |
| 57 checkXlibResult XMapWindow(display, window) | |
| 58 | |
| 59 deleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", XBool(false)) | |
| 60 checkXlibResult XSetWMProtocols(display, window, addr(deleteMessage), 1) | |
| 61 | |
| 62 var data = "\0".cstring | |
| 63 var pixmap = display.XCreateBitmapFromData(window, data, 1, 1) | |
| 64 var color: XColor | |
| 65 var empty_cursor = display.XCreatePixmapCursor(pixmap, pixmap, addr(color), addr(color), 0, 0) | |
| 66 checkXlibResult display.XFreePixmap(pixmap) | |
| 67 return NativeWindow(display: display, window: window, emptyCursor: empty_cursor) | |
| 68 | |
| 69 proc SetTitle*(window: NativeWindow, title: string) = | |
| 70 checkXlibResult XSetStandardProperties(window.display, window.window, title, "window", 0, nil, 0, nil) | |
| 71 | |
| 72 proc Fullscreen*(window: var NativeWindow, enable: bool) = | |
| 73 var | |
| 74 wm_state = window.display.XInternAtom("_NET_WM_STATE", 0) | |
| 75 wm_fullscreen = window.display.XInternAtom("_NET_WM_STATE_FULLSCREEN", 0) | |
| 76 var | |
| 77 xev: XEvent | |
| 78 xev.xclient = XClientMessageEvent( | |
| 79 message_type: wm_state, | |
| 80 format: 32, | |
| 81 window: window.window, | |
| 82 data: XClientMessageData( | |
| 83 l: [ | |
| 84 int(not enable) xor 1, | |
| 85 clong(wm_fullscreen), | |
| 86 0, | |
| 87 0, | |
| 88 0 | |
| 89 ] | |
| 90 ) | |
| 91 ) | |
| 92 xev.theType = ClientMessage | |
| 93 | |
| 94 checkXlibResult window.display.XSendEvent( | |
| 95 window.display.DefaultRootWindow(), | |
| 96 0, | |
| 97 SubstructureRedirectMask or SubstructureNotifyMask, | |
| 98 addr xev | |
| 99 ) | |
| 100 checkXlibResult window.display.XFlush() | |
| 101 | |
| 102 proc HideSystemCursor*(window: NativeWindow) = | |
| 103 checkXlibResult XDefineCursor(window.display, window.window, window.emptyCursor) | |
| 104 checkXlibResult window.display.XFlush() | |
| 105 | |
| 106 proc ShowSystemCursor*(window: NativeWindow) = | |
| 107 checkXlibResult XUndefineCursor(window.display, window.window) | |
| 108 checkXlibResult window.display.XFlush() | |
| 109 | |
| 110 proc Destroy*(window: NativeWindow) = | |
| 111 checkXlibResult window.display.XFreeCursor(window.emptyCursor) | |
| 112 checkXlibResult window.display.XDestroyWindow(window.window) | |
| 113 discard window.display.XCloseDisplay() # always returns 0 | |
| 114 | |
| 115 proc Size*(window: NativeWindow): (int, int) = | |
| 116 var attribs: XWindowAttributes | |
| 117 checkXlibResult XGetWindowAttributes(window.display, window.window, addr(attribs)) | |
| 118 return (int(attribs.width), int(attribs.height)) | |
| 119 | |
| 120 proc PendingEvents*(window: NativeWindow): seq[Event] = | |
| 121 var event: XEvent | |
| 122 while window.display.XPending() > 0: | |
| 123 discard window.display.XNextEvent(addr(event)) | |
| 124 case event.theType | |
| 125 of ClientMessage: | |
| 126 if cast[Atom](event.xclient.data.l[0]) == deleteMessage: | |
| 127 result.add(Event(eventType: Quit)) | |
| 128 of KeyPress: | |
| 129 let keyevent = cast[PXKeyEvent](addr(event)) | |
| 130 let xkey = int(keyevent.keycode) | |
| 131 result.add Event(eventType: KeyPressed, key: KeyTypeMap.getOrDefault(xkey, Key.UNKNOWN)) | |
| 132 of KeyRelease: | |
| 133 let keyevent = cast[PXKeyEvent](addr(event)) | |
| 134 let xkey = int(keyevent.keycode) | |
| 135 result.add Event(eventType: KeyReleased, key: KeyTypeMap.getOrDefault(xkey, Key.UNKNOWN)) | |
| 136 of ButtonPress: | |
| 137 let button = int(cast[PXButtonEvent](addr(event)).button) | |
| 138 if button == Button4: | |
| 139 result.add Event(eventType: MouseWheel, amount: 1'f32) | |
| 140 elif button == Button5: | |
| 141 result.add Event(eventType: MouseWheel, amount: -1'f32) | |
| 142 else: | |
| 143 result.add Event(eventType: MousePressed, button: MouseButtonTypeMap.getOrDefault(button, MouseButton.UNKNOWN)) | |
| 144 of ButtonRelease: | |
| 145 let button = int(cast[PXButtonEvent](addr(event)).button) | |
| 146 result.add Event(eventType: MouseReleased, button: MouseButtonTypeMap.getOrDefault(button, MouseButton.UNKNOWN)) | |
| 147 of MotionNotify: | |
| 148 let motion = cast[PXMotionEvent](addr(event)) | |
| 149 result.add Event(eventType: MouseMoved, x: motion.x, y: motion.y) | |
| 150 of ConfigureNotify, Expose: | |
| 151 result.add Event(eventType: ResizedWindow) | |
| 152 else: | |
| 153 discard | |
| 154 | |
| 155 | |
| 156 proc GetMousePosition*(window: NativeWindow): Option[Vec2f] = | |
| 157 var | |
| 158 root: x11.Window | |
| 159 win: x11.Window | |
| 160 rootX: cint | |
| 161 rootY: cint | |
| 162 winX: cint | |
| 163 winY: cint | |
| 164 mask: cuint | |
| 165 onscreen = XQueryPointer( | |
| 166 window.display, | |
| 167 window.window, | |
| 168 addr(root), | |
| 169 addr(win), | |
| 170 addr(rootX), | |
| 171 addr(rootY), | |
| 172 addr(winX), | |
| 173 addr(winY), | |
| 174 addr(mask), | |
| 175 ) | |
| 176 if onscreen != 0: | |
| 177 result = some(Vec2f([float32(winX), float32(winY)])) | |
| 178 |
