yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1#ifdef SLANG_ENABLE_XLIB 2 3#include "../window.h" 4 5#include <X11/Xlib.h> 6#include <X11/Xresource.h> 7#include <X11/Xutil.h> 8 9#ifdef None 10#undef None 11#endif 12 13#include "core/slang-basic.h" 14 15using namespace Slang ; 16 17namespace platform 18{ 19typedef ::Window X11WindowHandle ; 20class X11PlatformWindow ; 21 22void initKeyCodeTranslationTable (Display * display ); 23void freeKeyCodeTranslationTable (); 24KeyCode translateKeyCode (int keyCode ); 25int getKeyChar (KeyCode keyCode ,int keyState ); 26 27const int kKeyStateTableSize = 256 ; 28 29enum class KeyState 30{ 31Released , 32Pressed , 33Hold 34}; 35 36enum class KeyEvent 37{ 38Press , 39Release 40}; 41 42enum class MouseEvent 43{ 44Move , 45Down , 46Up , 47Scroll 48}; 49 50class X11AppContext 51{ 52public : 53static bool isTerminated ; 54static RefPtr < Window > mainWindow ; 55static OrderedDictionary < X11WindowHandle ,X11PlatformWindow *> windows ; 56static X11WindowHandle mainWindowHandle ; 57static Display * xdisplay ; 58static KeyState keyStates [kKeyStateTableSize ]; 59static X11PlatformWindow * currentMouseEventWindow ; 60}; 61 62bool X11AppContext ::isTerminated = false; 63RefPtr < Window > X11AppContext ::mainWindow ; 64OrderedDictionary < X11WindowHandle ,X11PlatformWindow *> X11AppContext ::windows ; 65X11WindowHandle X11AppContext ::mainWindowHandle ; 66Display * X11AppContext ::xdisplay = nullptr ; 67KeyState X11AppContext ::keyStates [kKeyStateTableSize ]= {}; 68X11PlatformWindow * X11AppContext ::currentMouseEventWindow = nullptr ; 69 70void Application ::init () {} 71 72static void doEventsImpl (bool waitForEvents ); 73 74void Application ::doEvents () 75{ 76doEventsImpl (false); 77} 78 79void Application ::quit () 80{ 81X11AppContext ::isTerminated = true; 82} 83 84void Application ::dispose () 85{ 86X11AppContext ::mainWindow = nullptr ; 87X11AppContext ::windows = decltype(X11AppContext ::windows )(); 88freeKeyCodeTranslationTable (); 89} 90 91void Application ::run (Window * mainWindow ,bool waitForEvents ) 92{ 93if (mainWindow ) 94 { 95X11AppContext ::mainWindow = mainWindow ; 96X11AppContext ::mainWindowHandle = 97 (X11WindowHandle )mainWindow -> getNativeHandle ().handleValues [1 ]; 98mainWindow -> show (); 99while (!X11AppContext ::isTerminated ) 100 { 101doEventsImpl (waitForEvents ); 102if (!X11AppContext ::isTerminated ) 103mainWindow -> events .mainLoop (); 104 } 105 } 106} 107 108class X11PlatformWindow :public Window 109{ 110public : 111X11WindowHandle handle ; 112bool visible = false; 113int currentWidth = 0 ; 114int currentHeight = 0 ; 115bool fixedSized = false; 116X11PlatformWindow (const WindowDesc & desc ) 117 { 118currentWidth = desc .width ; 119currentHeight = desc .height ; 120 121int blackColor = 122BlackPixel (X11AppContext ::xdisplay ,DefaultScreen (X11AppContext ::xdisplay )); 123int whiteColor = 124WhitePixel (X11AppContext ::xdisplay ,DefaultScreen (X11AppContext ::xdisplay )); 125handle = XCreateSimpleWindow ( 126X11AppContext ::xdisplay , 127DefaultRootWindow (X11AppContext ::xdisplay ), 1280 , 1290 , 130desc .width , 131desc .height , 1320 , 133blackColor , 134blackColor ); 135X11AppContext ::windows [handle ]= this ; 136Atom wmDelete = XInternAtom (X11AppContext ::xdisplay ,"WM_DELETE_WINDOW" ,True ); 137XSetWMProtocols (X11AppContext ::xdisplay ,handle ,& wmDelete ,1 ); 138XSelectInput ( 139X11AppContext ::xdisplay , 140handle , 141StructureNotifyMask |KeyPressMask |KeyReleaseMask |PointerMotionMask | 142ButtonPressMask |ButtonReleaseMask |ExposureMask |FocusChangeMask ); 143 144if (desc .style == WindowStyle ::FixedSize ) 145 { 146fixedSized = true; 147setFixedSizeHint (desc .width ,desc .height ); 148 } 149setText (desc .title ); 150 } 151 152 ~X11PlatformWindow () {close (); } 153 154void setFixedSizeHint (int w ,int h ) 155 { 156auto sizeHints = XAllocSizeHints (); 157sizeHints -> flags = PMinSize |PMaxSize ; 158sizeHints -> min_width = sizeHints -> max_width = w ; 159sizeHints -> min_height = sizeHints -> max_height = h ; 160XSetWMNormalHints (X11AppContext ::xdisplay ,handle ,sizeHints ); 161XFree (sizeHints ); 162 } 163 164virtual void setClientSize (uint32_t width ,uint32_t height )override 165 { 166if (fixedSized ) 167setFixedSizeHint (width ,height ); 168XResizeWindow (X11AppContext ::xdisplay ,handle ,width ,height ); 169handleResizeEvent (width ,height ); 170 } 171 172virtual Rect getClientRect ()override 173 { 174Rect rect = {}; 175if (!handle ) 176return rect ; 177X11WindowHandle winRoot = 0 ,winParent = 0 ; 178X11WindowHandle * winChildren = nullptr ; 179unsigned int numChilren = 0 ; 180XQueryTree ( 181X11AppContext ::xdisplay , 182handle , 183& winRoot , 184& winParent , 185& winChildren , 186& numChilren ); 187unsigned borderWidth ,depth ; 188XGetGeometry ( 189X11AppContext ::xdisplay , 190handle , 191& winRoot , 192& rect .x , 193& rect .y , 194 (uint32_t * )& rect .width , 195 (uint32_t * )& rect .height , 196& borderWidth , 197& depth ); 198return rect ; 199 } 200 201virtual void centerScreen ()override 202 { 203auto currentRect = getClientRect (); 204XWindowAttributes attributes ; 205XGetWindowAttributes (X11AppContext ::xdisplay ,handle ,& attributes ); 206int screenWidth = WidthOfScreen (attributes .screen ); 207int screenHeight = HeightOfScreen (attributes .screen ); 208int x = (screenWidth - currentRect .width ) /2 ; 209int y = (screenHeight - currentRect .height ) /2 ; 210XMoveWindow (X11AppContext ::xdisplay ,handle ,x ,y ); 211 } 212virtual void close ()override 213 { 214if (handle ) 215 { 216X11AppContext ::windows .remove (handle ); 217XDestroyWindow (X11AppContext ::xdisplay ,handle ); 218handle = 0 ; 219 } 220 } 221virtual bool getFocused ()override 222 { 223if (!handle ) 224return false; 225int revertTo ; 226X11WindowHandle focusedWindow ; 227XGetInputFocus (X11AppContext ::xdisplay ,& focusedWindow ,& revertTo ); 228return focusedWindow == handle ; 229 } 230virtual WindowHandle getNativeHandle ()override 231 { 232WindowHandle rs ; 233rs .type = WindowHandle ::Type ::XLibHandle ; 234rs .handleValues [0 ]= (intptr_t )X11AppContext ::xdisplay ; 235rs .handleValues [1 ]= (intptr_t )handle ; 236return rs ; 237 } 238virtual void setText (String text )override 239 { 240if (!handle ) 241return ; 242XStoreName (X11AppContext ::xdisplay ,handle ,text .getBuffer ()); 243XClassHint * hint = XAllocClassHint (); 244hint -> res_class = (char * )"Slang platform window" ; 245hint -> res_name = (char * )"Slang platform window" ; 246XSetClassHint (X11AppContext ::xdisplay ,handle ,hint ); 247XFree (hint ); 248 } 249virtual bool getVisible ()override {return visible ; } 250virtual void show ()override 251 { 252XMapWindow (X11AppContext ::xdisplay ,handle ); 253visible = true; 254 } 255virtual void hide ()override 256 { 257if (!handle ) 258return ; 259XUnmapWindow (X11AppContext ::xdisplay ,handle ); 260visible = false; 261 } 262virtual int getCurrentDpi ()override 263 { 264char * resourceString = XResourceManagerString (X11AppContext ::xdisplay ); 265XrmDatabase db ; 266XrmValue value ; 267char * type = NULL ; 268double dpi = 96.0 ; 269db = XrmGetStringDatabase (resourceString ); 270if (resourceString ) 271 { 272if (XrmGetResource (db ,"Xft.dpi" ,"String" ,& type ,& value )) 273 { 274if (value .addr ) 275 { 276dpi = atof (value .addr ); 277 } 278 } 279 } 280return (int )dpi ; 281 } 282void handleResizeEvent (int w ,int h ) 283 { 284if (w != currentWidth || h != currentHeight ) 285 { 286currentWidth = w ; 287currentHeight = h ; 288events .sizeChanged (); 289 } 290 } 291 292static void addButtonState (ButtonState ::Enum & state ,ButtonState ::Enum newState ) 293 { 294state = ButtonState ::Enum ((int )state | (int )newState ); 295 } 296 297ButtonState ::Enum getButtonState (int state ) 298 { 299ButtonState ::Enum buttonState = ButtonState ::Enum ::None ; 300if (state & ShiftMask ) 301addButtonState (buttonState ,ButtonState ::Enum ::Shift ); 302if (state & ControlMask ) 303addButtonState (buttonState ,ButtonState ::Enum ::Control ); 304if (state & Mod1Mask ) 305addButtonState (buttonState ,ButtonState ::Enum ::Alt ); 306if (state & Button1Mask ) 307addButtonState (buttonState ,ButtonState ::Enum ::LeftButton ); 308if (state & Button2Mask ) 309addButtonState (buttonState ,ButtonState ::Enum ::MiddleButton ); 310if (state & Button3Mask ) 311addButtonState (buttonState ,ButtonState ::Enum ::RightButton ); 312return buttonState ; 313 } 314 315void handleKeyEvent (KeyEvent eventType ,KeyCode keyCode ,int keyChar ,int state ) 316 { 317KeyEventArgs e ; 318e .buttons = getButtonState (state ); 319e .cancelEvent = false; 320e .key = keyCode ; 321e .keyChar = keyChar ; 322if (eventType == KeyEvent ::Press ) 323 { 324events .keyDown (e ); 325if (keyChar ) 326events .keyPress (e ); 327 } 328else 329 { 330events .keyUp (e ); 331 } 332 } 333 334void handleMouseEvent ( 335MouseEvent eventType , 336int x , 337int y , 338int delta , 339int button , 340int state , 341unsigned long time ) 342 { 343auto buttonState = getButtonState (state ); 344if (button == Button1 ) 345addButtonState (buttonState ,ButtonState ::Enum ::LeftButton ); 346else if (button == Button2 ) 347addButtonState (buttonState ,ButtonState ::Enum ::MiddleButton ); 348else if (button == Button3 ) 349addButtonState (buttonState ,ButtonState ::Enum ::RightButton ); 350MouseEventArgs e ; 351e .buttons = buttonState ; 352e .delta = delta ; 353e .x = x ; 354e .y = y ; 355 356switch (eventType ) 357 { 358case MouseEvent ::Down : 359events .mouseDown (e ); 360break ; 361case MouseEvent ::Up : 362events .mouseUp (e ); 363break ; 364case MouseEvent ::Move : 365events .mouseMove (e ); 366break ; 367case MouseEvent ::Scroll : 368events .mouseWheel (e ); 369break ; 370default : 371break ; 372 } 373 } 374 375void handleCloseEvent () 376 { 377hide (); 378if (X11AppContext ::mainWindowHandle == handle ) 379Application ::quit (); 380 } 381 382void handleExposeEvent () {} 383 384void handleFocus (bool focus ) {} 385}; 386 387Window * Application ::createWindow (const WindowDesc & desc ) 388{ 389if (!X11AppContext ::xdisplay ) 390 { 391XInitThreads (); 392XrmInitialize (); 393X11AppContext ::xdisplay = XOpenDisplay (nullptr ); 394initKeyCodeTranslationTable (X11AppContext ::xdisplay ); 395if (!X11AppContext ::xdisplay ) 396printf ("Failed to open XDisplay.\n" ); 397 } 398return new X11PlatformWindow (desc ); 399} 400 401void doEventsImpl (bool waitForEvents ) 402{ 403auto xdisplay = X11AppContext ::xdisplay ; 404if (!X11AppContext ::xdisplay ) 405return ; 406 407static bool supressInvokeTasks = false; 408X11PlatformWindow * sysWindow = nullptr ; 409KeyCode vKeyCode = KeyCode ::None ; 410int iKeyCode = 0 ; 411while (XPending (xdisplay )) 412 { 413XEvent nextEvent ; 414XNextEvent (xdisplay ,& nextEvent ); 415switch (nextEvent .type ) 416 { 417case KeyPress : 418vKeyCode = translateKeyCode (nextEvent .xkey .keycode ); 419iKeyCode = (int )vKeyCode ; 420if (iKeyCode < kKeyStateTableSize ) 421 { 422if (X11AppContext ::keyStates [iKeyCode ]== KeyState ::Released ) 423X11AppContext ::keyStates [iKeyCode ]= KeyState ::Pressed ; 424else if (X11AppContext ::keyStates [iKeyCode ]== KeyState ::Pressed ) 425X11AppContext ::keyStates [iKeyCode ]= KeyState ::Hold ; 426 } 427if (X11AppContext ::windows .tryGetValue (nextEvent .xkey .window ,sysWindow )) 428 { 429wchar_t keyChar = getKeyChar (vKeyCode ,nextEvent .xkey .state ); 430sysWindow -> handleKeyEvent (KeyEvent ::Press ,vKeyCode ,keyChar ,nextEvent .xkey .state ); 431 } 432break ; 433case KeyRelease : 434vKeyCode = translateKeyCode (nextEvent .xkey .keycode ); 435iKeyCode = (int )vKeyCode ; 436if (iKeyCode < kKeyStateTableSize ) 437 { 438X11AppContext ::keyStates [iKeyCode ]= KeyState ::Released ; 439 } 440if (X11AppContext ::windows .tryGetValue (nextEvent .xkey .window ,sysWindow )) 441 { 442sysWindow -> handleKeyEvent (KeyEvent ::Release ,vKeyCode ,0 ,nextEvent .xkey .state ); 443 } 444break ; 445case MotionNotify : 446if (X11AppContext ::windows .tryGetValue (nextEvent .xmotion .window ,sysWindow )) 447 { 448X11AppContext ::currentMouseEventWindow = sysWindow ; 449sysWindow -> handleMouseEvent ( 450MouseEvent ::Move , 451nextEvent .xmotion .x , 452nextEvent .xmotion .y , 4530 , 4540 , 455nextEvent .xmotion .state , 456nextEvent .xmotion .time ); 457 } 458break ; 459case ButtonPress : 460if (X11AppContext ::windows .tryGetValue (nextEvent .xbutton .window ,sysWindow )) 461 { 462X11AppContext ::currentMouseEventWindow = sysWindow ; 463if (nextEvent .xbutton .button <=Button3 ) 464sysWindow -> handleMouseEvent ( 465MouseEvent ::Down , 466nextEvent .xbutton .x , 467nextEvent .xbutton .y , 4680 , 469nextEvent .xbutton .button , 470nextEvent .xbutton .state , 471nextEvent .xbutton .time ); 472else if (nextEvent .xbutton .button == Button4 ) 473sysWindow -> handleMouseEvent ( 474MouseEvent ::Scroll , 475nextEvent .xbutton .x , 476nextEvent .xbutton .y , 477120 , 478nextEvent .xbutton .button , 479nextEvent .xbutton .state , 480nextEvent .xbutton .time ); 481else if (nextEvent .xbutton .button == Button5 ) 482sysWindow -> handleMouseEvent ( 483MouseEvent ::Scroll , 484nextEvent .xbutton .x , 485nextEvent .xbutton .y , 486-120 , 487nextEvent .xbutton .button , 488nextEvent .xbutton .state , 489nextEvent .xbutton .time ); 490 } 491break ; 492case ButtonRelease : 493if (X11AppContext ::windows .tryGetValue (nextEvent .xbutton .window ,sysWindow )) 494 { 495X11AppContext ::currentMouseEventWindow = sysWindow ; 496sysWindow -> handleMouseEvent ( 497MouseEvent ::Up , 498nextEvent .xbutton .x , 499nextEvent .xbutton .y , 5000 , 501nextEvent .xbutton .button , 502nextEvent .xbutton .state , 503nextEvent .xbutton .time ); 504 } 505break ; 506case ConfigureNotify : 507if (X11AppContext ::windows .tryGetValue (nextEvent .xconfigure .window ,sysWindow )) 508 { 509sysWindow -> handleResizeEvent ( 510nextEvent .xconfigure .width , 511nextEvent .xconfigure .height ); 512 } 513break ; 514case Expose : 515if (X11AppContext ::windows .tryGetValue (nextEvent .xexpose .window ,sysWindow )) 516 { 517sysWindow -> handleExposeEvent (); 518 } 519break ; 520case ClientMessage : 521if (X11AppContext ::windows .tryGetValue (nextEvent .xclient .window ,sysWindow )) 522 { 523Atom wmDelete = XInternAtom (X11AppContext ::xdisplay ,"WM_DELETE_WINDOW" ,True ); 524if (nextEvent .xclient .data .l [0 ]== wmDelete ) 525 { 526sysWindow -> handleCloseEvent (); 527 } 528 } 529break ; 530case FocusIn : 531if (X11AppContext ::windows .tryGetValue (nextEvent .xfocus .window ,sysWindow )) 532 { 533sysWindow -> handleFocus (true); 534 } 535break ; 536case FocusOut : 537if (X11AppContext ::windows .tryGetValue (nextEvent .xfocus .window ,sysWindow )) 538 { 539sysWindow -> handleFocus (false); 540 } 541break ; 542 } 543 } 544} 545 546}// namespace platform 547 548#endif