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.x; 39 import riverd.xcursor; 40 41 import std.conv : emplace; 42 import core.stdc.stdlib : malloc, free; 43 import aurorafw.math.vector : Vector2f; 44 import std.process : environment; 45 import aurorafw.core.logger : error; 46 import core.stdc.stdlib : exit; 47 import core.stdc.stdlib : atof; 48 import core.stdc..string : strcmp; 49 50 import aurorafw.gui.api.backend; 51 52 pure class X11Backend : Backend { 53 this() 54 { 55 super._type = BackendType.X11; 56 57 X.XInitThreads(); 58 X.XrmInitialize(); 59 _display = X.XOpenDisplay(null); 60 61 if(_display is null) 62 { 63 auto env_display = environment.get("DISPLAY"); 64 if(env_display) 65 error("X11: Cannot open display ", env_display); 66 else 67 error("X11: DISPLAY variable is missing"); 68 69 exit(1); 70 } 71 72 _screen = X.XDefaultScreen(_display); 73 _root = X.XRootWindow(_display, _screen); 74 _context = X.XUniqueContext(); 75 76 // get system content scale 77 float xdpi = X.XDisplayWidth(_display, _screen) * 25.4f / X.XDisplayWidthMM(_display, _screen); 78 float ydpi = X.XDisplayHeight(_display, _screen) * 25.4f / X.XDisplayHeightMM(_display, _screen); 79 80 char* rms = X.XResourceManagerString(_display); 81 if (rms) 82 { 83 X.XrmDatabase db = X.XrmGetStringDatabase(rms); 84 if (db) 85 { 86 X.XrmValue value; 87 char* type = null; 88 89 if (X.XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) 90 { 91 if (type && strcmp(type, "String") == 0) 92 xdpi = ydpi = atof(cast(char*)value.addr); 93 } 94 95 X.XrmDestroyDatabase(db); 96 } 97 } 98 99 _contentScale.x = xdpi / 96.0f; 100 _contentScale.y = ydpi / 96.0f; 101 102 //init x11 extensions 103 // TODO 104 initX11Extensions(); 105 106 X.XSetWindowAttributes wa; 107 wa.event_mask = X.PropertyChangeMask; 108 109 _helperWindowHandle = X.XCreateWindow(_display, _root, 110 0, 0, 1, 1, 0, 0, 111 X.InputOnly, 112 X.XDefaultVisual(_display, _screen), 113 X.CWEventMask, &wa); 114 115 immutable byte[16 * 16 * 4] pixels; 116 _hiddenCursorHandle = createXCursor(16, 16, pixels, 0, 0); 117 118 if (X.XSupportsLocale()) 119 { 120 X.XSetLocaleModifiers(""); 121 122 this._im = X.XOpenIM(_display, null, null, null); 123 if (this._im) 124 { 125 bool found = false; 126 X.XIMStyles* styles = null; 127 128 if(X.XGetIMValues(_im, X.XNQueryInputStyle, &styles, null) == null) 129 { 130 for (uint i = 0; i < styles.count_styles; i++) 131 { 132 if (styles.supported_styles[i] == (X.XIMPreeditNothing | X.XIMStatusNothing)) 133 { 134 found = true; 135 break; 136 } 137 } 138 139 X.XFree(styles); 140 } 141 142 if (!found) 143 { 144 X.XCloseIM(_im); 145 this._im = null; 146 } 147 } 148 } 149 } 150 151 ~this() 152 { 153 if(_display) 154 { 155 X.XCloseDisplay(_display); 156 _display = null; 157 } 158 } 159 160 X.Cursor createXCursor(immutable uint width, immutable uint height, immutable byte[] pixels, int xhot, int yhot) 161 { 162 X.Cursor cursor; 163 164 if (!X.dylib_is_loaded(_xcursor.handle)) 165 return X.None; 166 167 X.XcursorImage* native = X.XcursorImageCreate(width, height); 168 if (native == null) 169 return X.None; 170 171 native.xhot = xhot; 172 native.yhot = yhot; 173 174 byte* source = cast(byte*) pixels; 175 X.XcursorPixel* target = native.pixels; 176 177 for (int i = 0; i < width * height; i++, target++, source += 4) 178 { 179 uint alpha = source[3]; 180 181 *target = (alpha << 24) | 182 (cast(byte) ((source[0] * alpha) / 255) << 16) | 183 (cast(byte) ((source[1] * alpha) / 255) << 8) | 184 (cast(byte) ((source[2] * alpha) / 255) << 0); 185 } 186 187 cursor = X.XcursorImageLoadCursor(_display, native); 188 X.XcursorImageDestroy(native); 189 190 return cursor; 191 } 192 193 X.Display* display() @property { return _display; } 194 int screen() @property { return _screen; } 195 X.Window root() @property { return _root; } 196 197 private void initX11Extensions() 198 { 199 //TODO: Remove/improve logger 200 import std.experimental.logger; 201 try _xf86vmode.handle = X.dylib_load_xxf86vm(); catch(Exception e) debug trace(e.msg); 202 203 if(X.dylib_is_loaded(_xf86vmode.handle)) 204 { 205 _xf86vmode.available = cast(bool)X.XF86VidModeQueryExtension(_display, &_xf86vmode.eventBase, &_xf86vmode.errorBase); 206 } 207 208 try _xcursor.handle = X.dylib_load_xcursor(); catch(Exception e) debug trace(e.msg); 209 } 210 211 private: 212 X.Display* _display; 213 X.Window _root; 214 int _screen; 215 Vector2f _contentScale; 216 X.XContext _context; 217 X.XIM _im; 218 X.Window _helperWindowHandle; 219 X.Cursor _hiddenCursorHandle; 220 XCursorExtension _xcursor; 221 XF86VModeExtension _xf86vmode; 222 } 223 224 struct XCursorExtension { 225 void* handle; 226 } 227 228 struct XF86VModeExtension { 229 void* handle; 230 bool available; 231 int eventBase; 232 int errorBase; 233 }