1 /* 2 __ 3 / _| 4 __ _ _ _ _ __ ___ _ __ __ _ | |_ ___ ___ ___ 5 / _` | | | | '__/ _ \| '__/ _` | | _/ _ \/ __/ __| 6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \ 7 \__,_|\__,_|_| \___/|_| \__,_| |_| \___/|___/___/ 8 9 Copyright (C) 2018-2019 Aurora Free Open Source Software. 10 11 This file is part of the Aurora Free Open Source Software. This 12 organization promote free and open source software that you can 13 redistribute and/or modify under the terms of the GNU Lesser General 14 Public License Version 3 as published by the Free Software Foundation or 15 (at your option) any later version approved by the Aurora Free Open Source 16 Software Organization. The license is available in the package root path 17 as 'LICENSE' file. Please review the following information to ensure the 18 GNU Lesser General Public License version 3 requirements will be met: 19 https://www.gnu.org/licenses/lgpl.html . 20 21 Alternatively, this file may be used under the terms of the GNU General 22 Public License version 3 or later as published by the Free Software 23 Foundation. Please review the following information to ensure the GNU 24 General Public License requirements will be met: 25 http://www.gnu.org/licenses/gpl-3.0.html. 26 27 NOTE: All products, services or anything associated to trademarks and 28 service marks used or referenced on this file are the property of their 29 respective companies/owners or its subsidiaries. Other names and brands 30 may be claimed as the property of others. 31 32 For more info about intellectual property visit: aurorafoss.org or 33 directly send an email to: contact (at) aurorafoss.org . 34 */ 35 36 module aurorafw.gui.api.x11.backend; 37 38 import X = aurorafw.gui.platform.x11; 39 import std.conv : emplace; 40 import core.stdc.stdlib : malloc, free; 41 import aurorafw.math.vector : Vector2f; 42 import std.process : environment; 43 import aurorafw.core.logger : error; 44 import core.stdc.stdlib : exit; 45 import core.stdc.stdlib : atof; 46 import core.stdc.string : strcmp; 47 48 import aurorafw.gui.api.backend; 49 50 pure class X11Backend : Backend { 51 this() 52 { 53 super._type = BackendType.X11; 54 55 X.XInitThreads(); 56 X.XrmInitialize(); 57 _display = X.XOpenDisplay(null); 58 59 if(_display is null) 60 { 61 auto env_display = environment.get("DISPLAY"); 62 if(env_display) 63 error("X11: Cannot open display ", env_display); 64 else 65 error("X11: DISPLAY variable is missing"); 66 67 exit(1); //TODO: add error to Error Database 68 } 69 70 _screen = X.XDefaultScreen(_display); 71 _root = X.XRootWindow(_display, _screen); 72 _context = X.XUniqueContext(); 73 74 // get system content scale 75 float xdpi = X.XDisplayWidth(_display, _screen) * 25.4f / X.XDisplayWidthMM(_display, _screen); 76 float ydpi = X.XDisplayHeight(_display, _screen) * 25.4f / X.XDisplayHeightMM(_display, _screen); 77 78 char* rms = X.XResourceManagerString(_display); 79 if (rms) 80 { 81 X.XrmDatabase db = X.XrmGetStringDatabase(rms); 82 if (db) 83 { 84 X.XrmValue value; 85 char* type = null; 86 87 if (X.XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) 88 { 89 if (type && strcmp(type, "String") == 0) 90 xdpi = ydpi = atof(cast(char*)value.addr); 91 } 92 93 X.XrmDestroyDatabase(db); 94 } 95 } 96 97 _contentScale.x = xdpi / 96.0f; 98 _contentScale.y = ydpi / 96.0f; 99 100 //init x11 extensions 101 // TODO 102 initX11Extensions(); 103 104 X.XSetWindowAttributes wa; 105 wa.event_mask = X.PropertyChangeMask; 106 107 _helperWindowHandle = X.XCreateWindow(_display, _root, 108 0, 0, 1, 1, 0, 0, 109 X.InputOnly, 110 X.XDefaultVisual(_display, _screen), 111 X.CWEventMask, &wa); 112 113 immutable byte[16 * 16 * 4] pixels; 114 _hiddenCursorHandle = createXCursor(16, 16, pixels, 0, 0); 115 116 if (X.XSupportsLocale()) 117 { 118 X.XSetLocaleModifiers(""); 119 120 this._im = X.XOpenIM(_display, null, null, null); 121 if (this._im) 122 { 123 bool found = false; 124 X.XIMStyles* styles = null; 125 126 if(X.XGetIMValues(_im, X.XNQueryInputStyle, &styles, null) == null) 127 { 128 for (uint i = 0; i < styles.count_styles; i++) 129 { 130 if (styles.supported_styles[i] == (X.XIMPreeditNothing | X.XIMStatusNothing)) 131 { 132 found = true; 133 break; 134 } 135 } 136 137 X.XFree(styles); 138 } 139 140 if (!found) 141 { 142 X.XCloseIM(_im); 143 this._im = null; 144 } 145 } 146 } 147 } 148 149 ~this() 150 { 151 if(_display) 152 { 153 X.XCloseDisplay(_display); 154 _display = null; 155 } 156 } 157 158 X.Cursor createXCursor(immutable uint width, immutable uint height, immutable byte[] pixels, int xhot, int yhot) 159 { 160 X.Cursor cursor; 161 162 if (!_xcursor_handle.dylib.isLoaded) 163 return X.None; 164 165 X.XcursorImage* native = X.XcursorImageCreate(width, height); 166 if (native == null) 167 return X.None; 168 169 native.xhot = xhot; 170 native.yhot = yhot; 171 172 byte* source = cast(byte*) pixels; 173 X.XcursorPixel* target = native.pixels; 174 175 for (int i = 0; i < width * height; i++, target++, source += 4) 176 { 177 uint alpha = source[3]; 178 179 *target = (alpha << 24) | 180 (cast(byte) ((source[0] * alpha) / 255) << 16) | 181 (cast(byte) ((source[1] * alpha) / 255) << 8) | 182 (cast(byte) ((source[2] * alpha) / 255) << 0); 183 } 184 185 cursor = X.XcursorImageLoadCursor(_display, native); 186 X.XcursorImageDestroy(native); 187 188 return cursor; 189 } 190 191 X.Display* display() @property { return _display; } 192 int screen() @property { return _screen; } 193 X.Window root() @property { return _root; } 194 195 void initX11Extensions() 196 { 197 import aurorafw.gui.platform.x11.xcursor; 198 try _xf86vmode.handle = new X.XF86VModeDylibLoader(); catch(Exception e) debug trace(afwDebugFlag, e.msg); 199 200 if(_xf86vmode.handle.dylib.isLoaded) 201 { 202 _xf86vmode.available = X.XF86VidModeQueryExtension(_display,_xf86vmode.eventBase, _xf86vmode.errorBase); 203 } 204 205 try _xcursor.handle = new X.XCursorDylibLoader(); catch(Exception e) debug trace(afwDebugFlag, e.msg); 206 } 207 208 private: 209 X.Display* _display; 210 X.Window _root; 211 int _screen; 212 Vector2f _contentScale; 213 X.XContext _context; 214 X.XIM _im; 215 X.Window _helperWindowHandle; 216 X.Cursor _hiddenCursorHandle; 217 XCursorExtension _xcursor; 218 XF86VModeExtension _xf86vmode; 219 } 220 221 struct XCursorExtension { 222 X.XCursorDylibLoader handle; 223 } 224 225 struct XF86VModeExtension { 226 X.XF86VModeDylibLoader handle; 227 bool available; 228 int eventBase; 229 int errorBase; 230 }