├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── REFERENCE.md ├── examples └── simple │ ├── Makefile │ └── main.c └── src ├── swfw.c └── swfw.h /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | This is a file with a list of contributors to this project. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017 Felipe Ferreira da Silva 2 | 3 | This software is provided 'as-is', without any express or implied warranty. In 4 | no event will the authors be held liable for any damages arising from the use of 5 | this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, including 8 | commercial applications, and to alter it and redistribute it freely, subject to 9 | the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not claim 12 | that you wrote the original software. If you use this software in a 13 | product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SWFW - Simple Window Framework 2 | 3 | This library is a cross-platform simple window framework containing only two files, `swfw.c` and `swfw.h`. 4 | 5 | ## Version 6 | 7 | This library still hasn't reached its first major release, which means that the API might change and break backward compatility. 8 | 9 | ## Planned Support 10 | 11 | - Platforms: 12 | - Linux and BSD `in-progress` 13 | - X11 `in-progress` 14 | - Wayland `in-progress` 15 | - Windows `not-started` 16 | - Mac OS `not-started` 17 | - Web (using Emscripten) `not-started` 18 | - Mobile (Android and iOS) `not-started` 19 | 20 | - Graphic APIs: 21 | - No hardware acceleration 22 | - GL 23 | - Vulkan 24 | 25 | The graphic APIs will be supported depending on the platform. 26 | 27 | - Input: 28 | - Keyboard `in-progress` 29 | - Mouse `in-progress` 30 | - Tablet `not-started` 31 | - Controller `not-started` 32 | 33 | As controller and tablet input are not used by everyone, especially by small developers, it will be possible to disable their implementation in compilation time using macros. By default, their implementation will be enabled. 34 | 35 | ## Building 36 | 37 | This project doesn't include a build system because it's intended that you add the files `swfw.c` and `swfw.h` in the build system of your project. 38 | 39 | ### Linux and BSD 40 | 41 | On Linux and BSD, the library can be compiled to support only X11, only Wayland, or both. 42 | 43 | The macro `SWFW_X11` is used for supporting X11, and the macro `SWFW_WAYLAND` is used for supporting Wayland. With GCC, the macros can be defined using the `-D` option: 44 | 45 | ```Makefile 46 | # When no macro is provided, `SWFW_X11` is automatically defined internally. 47 | gcc -c ./swfw.c 48 | ``` 49 | 50 | ```Makefile 51 | gcc -DSWFW_X11 -c ./swfw.c 52 | ``` 53 | 54 | ```Makefile 55 | gcc -DSWFW_WAYLAND -c ./swfw.c 56 | ``` 57 | 58 | ```Makefile 59 | gcc -DSWFW_X11 -DSWFW_WAYLAND -c ./swfw.c 60 | ``` 61 | 62 | The last option above is for building with support for both X11 and Wayland backends. 63 | 64 | On Linux and BSD, when including `swfw.h` in your file, the same macros for the supported backends should be defined before the inclusion of the header: 65 | 66 | ```c 67 | #if defined(__bsdi__) || defined(__linux__) 68 | #define SWFW_X11 69 | #endif 70 | #include "swfw.h" 71 | ``` 72 | 73 | ```c 74 | #if defined(__bsdi__) || defined(__linux__) 75 | #define SWFW_WAYLAND 76 | #endif 77 | #include "swfw.h" 78 | ``` 79 | 80 | ```c 81 | #if defined(__bsdi__) || defined(__linux__) 82 | #define SWFW_X11 83 | #define SWFW_WAYLAND 84 | #endif 85 | #include "swfw.h" 86 | ``` 87 | 88 | ### Windows, Mac OS and Web 89 | 90 | On Windows, Mac OS and Web, there are only one backend for each of these platforms, then there's no need to define any backend macro, only include the files `swfw.c` and `swfw.h` in the build system. 91 | 92 | ## Contributing 93 | 94 | Contributions are very welcome. The coding style is similar to Linux Kernel coding style, but some flexibiliy is allowed. 95 | 96 | ## Contact 97 | 98 | You can use the e-mail in my profile to contact me. 99 | 100 | ## License 101 | 102 | The source code of this project is licensed under the terms of the ZLIB license: 103 | 104 | Copyright (C) 2017 Felipe Ferreira da Silva 105 | 106 | This software is provided 'as-is', without any express or implied warranty. In 107 | no event will the authors be held liable for any damages arising from the use of 108 | this software. 109 | 110 | Permission is granted to anyone to use this software for any purpose, including 111 | commercial applications, and to alter it and redistribute it freely, subject to 112 | the following restrictions: 113 | 114 | 1. The origin of this software must not be misrepresented; you must not claim 115 | that you wrote the original software. If you use this software in a 116 | product, an acknowledgment in the product documentation would be 117 | appreciated but is not required. 118 | 2. Altered source versions must be plainly marked as such, and must not be 119 | misrepresented as being the original software. 120 | 3. This notice may not be removed or altered from any source distribution. 121 | -------------------------------------------------------------------------------- /REFERENCE.md: -------------------------------------------------------------------------------- 1 | # SWFW Reference 2 | 3 | ## Types 4 | 5 | ```c 6 | enum swfw_status { 7 | SWFW_OK, 8 | SWFW_ERROR, 9 | SWFW_INVALID_BACKEND, 10 | SWFW_UNSUPPORTED 11 | }; 12 | ``` 13 | 14 | The type used to indicate status. 15 | 16 | - `SWFW_OK` indicates that the operation was successful. 17 | - `SWFW_ERROR` indicates that the an error occurred. 18 | - `SWFW_INVALID_BACKEND` indicates that the operation failed when trying to use an invalid backend. This value should never be returned, except if the value of `backend` inside the structure `swfw_context` was modified by the user. 19 | - `SWFW_UNSUPPORTED` indicates that the operation is not supported by the backend used in the context. 20 | 21 | ```c 22 | enum swfw_backend { 23 | SWFW_BACKEND_AUTOMATIC, 24 | SWFW_BACKEND_X11, 25 | SWFW_BACKEND_WAYLAND, 26 | SWFW_BACKEND_WINDOWS, 27 | SWFW_BACKEND_COCOA, 28 | SWFW_BACKEND_WEB 29 | }; 30 | ``` 31 | 32 | The type used to indicate the context backend. 33 | 34 | On Windows, Mac OS X and Web: 35 | 36 | - If you use `SWFW_BACKEND_AUTOMATIC`, the context will be created for their respective platform. 37 | - Using `SWFW_BACKEND_WINDOWS`, `SWFW_BACKEND_COCOA` or `SWFW_BACKEND_WEB`, as long as in their respective platform, is also correct. 38 | 39 | On Linux or FreeBSD: 40 | 41 | - If you compiled only with X11 support, `SWFW_BACKEND_AUTOMATIC` and `SWFW_BACKEND_X11` will create a X11 context. 42 | - If you compiled only with Wayland support, `SWFW_BACKEND_AUTOMATIC` and `SWFW_BACKEND_WAYLAND` will create a Wayland context. 43 | - If you compiled with both X11 and Wayland support, `SWFW_BACKEND_AUTOMATIC` will create a X11 context. If you want to be specific, use `SWFW_BACKEND_X11` or `SWFW_BACKEND_WAYLAND`. 44 | 45 | ```c 46 | enum swfw_window_border { 47 | SWFW_WINDOW_BORDER_LEFT, 48 | SWFW_WINDOW_BORDER_TOP, 49 | SWFW_WINDOW_BORDER_RIGHT, 50 | SWFW_WINDOW_BORDER_BOTTOM, 51 | SWFW_WINDOW_BORDER_TOP_LEFT, 52 | SWFW_WINDOW_BORDER_TOP_RIGHT, 53 | SWFW_WINDOW_BORDER_BOTTOM_LEFT, 54 | SWFW_WINDOW_BORDER_BOTTOM_RIGHT 55 | }; 56 | ``` 57 | 58 | The type used to indicate the window border. 59 | 60 | ```c 61 | struct swfw_context { 62 | /* Internal structures */ 63 | }; 64 | 65 | struct swfw_window { 66 | /* Internal structures */ 67 | }; 68 | ``` 69 | 70 | The structures `swfw_context` and `swfw_window` are used in the context initialization and creation of the window. 71 | 72 | ## Functions 73 | 74 | ```c 75 | enum swfw_status swfw_drag_window(struct swfw_window *swfw_win); 76 | ``` 77 | 78 | Starts a dragging operation on the window. This function is supposed to work correctly only from a event of type `SWFW_EVENT_BUTTON_PRESS`. 79 | 80 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 81 | 82 | ```c 83 | enum swfw_status swfw_resize_window(struct swfw_window *swfw_win, enum swfw_window_border window_border); 84 | ``` 85 | 86 | Starts a resize operation on one of the borders of the window. This function is supposed to work correctly only from a event of type `SWFW_EVENT_BUTTON_PRESS`. 87 | 88 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 89 | 90 | ```c 91 | enum swfw_status swfw_hide_window(struct swfw_window *swfw_win); 92 | ``` 93 | 94 | Hides the window. 95 | 96 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 97 | 98 | ```c 99 | enum swfw_status swfw_show_window(struct swfw_window *swfw_win); 100 | ``` 101 | 102 | Shows the window. 103 | 104 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 105 | 106 | ```c 107 | enum swfw_status swfw_get_window_work_area(struct swfw_window *swfw_win, int32_t *x, int32_t *y, int32_t *width, int32_t *height); 108 | ``` 109 | 110 | Gets the display work area. The value of `x` and `y` will represent the top-left corner, and the value `width` and `height` the size of the work area. 111 | 112 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 113 | 114 | ```c 115 | enum swfw_status swfw_set_window_position(struct swfw_window *swfw_win, int32_t x, int32_t y); 116 | ``` 117 | 118 | Sets the window position to `x` and `y`. 119 | 120 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 121 | 122 | ```c 123 | enum swfw_status swfw_set_window_size(struct swfw_window *swfw_win, int32_t width, int32_t height); 124 | ``` 125 | 126 | Sets the window size to `width` and `height`. 127 | 128 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 129 | 130 | ```c 131 | enum swfw_status swfw_set_window_size_limits(struct swfw_window *swfw_win, int32_t min_width, int32_t min_height, int32_t max_width, int32_t max_height); 132 | ``` 133 | 134 | Sets the minimum size of the window to `min_width` and `min_height`, and the maximum size to `max_width` and `max_height`. If one of the values are negative, then the limit is unset. 135 | 136 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 137 | 138 | ```c 139 | enum swfw_status swfw_set_window_resizable(struct swfw_window *swfw_win, bool resizable); 140 | ``` 141 | 142 | Sets if the window can be resized. 143 | 144 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 145 | 146 | ```c 147 | enum swfw_status swfw_set_window_decorated(struct swfw_window *swfw_win, bool decorated); 148 | ``` 149 | 150 | Sets if the window is decorated. 151 | 152 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 153 | 154 | ```c 155 | enum swfw_status swfw_set_window_title(struct swfw_window *swfw_win, char *title); 156 | ``` 157 | 158 | Sets if the window title. 159 | 160 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 161 | 162 | ```c 163 | enum swfw_status swfw_window_swap_interval(struct swfw_window *swfw_win, int32_t interval); 164 | ``` 165 | 166 | Sets the swap interval of the window. 167 | 168 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 169 | 170 | ```c 171 | enum swfw_status swfw_window_swap_buffers(struct swfw_window *swfw_win); 172 | ``` 173 | 174 | Swaps the front and back buffers of the window. 175 | 176 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 177 | 178 | ```c 179 | enum swfw_status swfw_destroy_window(struct swfw_window *swfw_win); 180 | ``` 181 | 182 | Destroys the window. 183 | 184 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 185 | 186 | ```c 187 | enum swfw_status swfw_make_window(struct swfw_context *swfw_ctx, struct swfw_window *swfw_win); 188 | ``` 189 | 190 | The window is created for the context and passed to the structure `swfw_win`. 191 | 192 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 193 | 194 | ```c 195 | enum swfw_status swfw_hint_window_size(struct swfw_context *swfw_ctx, int32_t width, int32_t height); 196 | ``` 197 | 198 | Sets the initial size used for the creation of the window. 199 | 200 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 201 | 202 | ```c 203 | enum swfw_status swfw_hint_gl_version(struct swfw_context *swfw_ctx, int32_t major, int32_t minor); 204 | ``` 205 | 206 | If using OpenGL for hardware acceleration, specify the OpenGL version. 207 | 208 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 209 | 210 | ```c 211 | enum swfw_status swfw_hint_use_hardware_acceleration(struct swfw_context *swfw_ctx, bool use_hardware_acceleration); 212 | ``` 213 | 214 | Specify if the context will use hardware acceleration. 215 | 216 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 217 | 218 | ```c 219 | bool swfw_poll_event(struct swfw_context *swfw_ctx, struct swfw_event *event); 220 | ``` 221 | 222 | Poll event and returns to the structure `event`. 223 | 224 | If there was an event, the function returns `true`, otherwise the function returns `false`. 225 | 226 | ```c 227 | enum swfw_status swfw_destroy_context(struct swfw_context *swfw_ctx); 228 | ``` 229 | 230 | Destroys the context. 231 | 232 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 233 | 234 | ```c 235 | enum swfw_status swfw_make_context(struct swfw_context *swfw_ctx, enum swfw_backend backend); 236 | ``` 237 | 238 | The SWFW context is created using the backend defined by `backend` and passed to the structure `swfw_ctx`. 239 | 240 | If successful, the function returns `SWFW_OK`, otherwise the function returns one of the error values. 241 | 242 | ## License 243 | 244 | The source code of this project is licensed under the terms of the ZLIB license: 245 | 246 | Copyright (C) 2017 Felipe Ferreira da Silva 247 | 248 | This software is provided 'as-is', without any express or implied warranty. In 249 | no event will the authors be held liable for any damages arising from the use of 250 | this software. 251 | 252 | Permission is granted to anyone to use this software for any purpose, including 253 | commercial applications, and to alter it and redistribute it freely, subject to 254 | the following restrictions: 255 | 256 | 1. The origin of this software must not be misrepresented; you must not claim 257 | that you wrote the original software. If you use this software in a 258 | product, an acknowledgment in the product documentation would be 259 | appreciated but is not required. 260 | 2. Altered source versions must be plainly marked as such, and must not be 261 | misrepresented as being the original software. 262 | 3. This notice may not be removed or altered from any source distribution. 263 | -------------------------------------------------------------------------------- /examples/simple/Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | CFLAGS ?= -g 3 | CFLAGS_WARNINGS ?= -Wall 4 | 5 | CCINCL ?= -I ../../src 6 | CCLIBS_X11 ?= -lX11 -lEGL -lGL 7 | CCLIBS_WAYLAND ?= -lwayland-client -lwayland-egl -lEGL -lGL 8 | CCLIBS_X11_WAYLAND ?= -lX11 -lwayland-client -lwayland-egl -lEGL -lGL 9 | 10 | target-x11: 11 | $(MAKE) clear 12 | $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CCINCL) -DSWFW_X11 -c ../../src/swfw.c 13 | $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CCINCL) -DSWFW_X11 -c ./main.c 14 | $(CC) $(CFLAGS) -o ./simple ./*.o $(CCLIBS_X11) 15 | $(MAKE) clear 16 | 17 | target-wayland: 18 | $(MAKE) clear 19 | $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CCINCL) -DSWFW_WAYLAND -c ../../src/swfw.c 20 | $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CCINCL) -DSWFW_WAYLAND -c ./main.c 21 | $(CC) $(CFLAGS) -o ./simple ./*.o $(CCLIBS_WAYLAND) 22 | $(MAKE) clear 23 | 24 | target-x11-wayland: 25 | $(MAKE) clear 26 | $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CCINCL) -DSWFW_X11 -DSWFW_WAYLAND -c ../../src/swfw.c 27 | $(CC) $(CFLAGS) $(CFLAGS_WARNINGS) $(CCINCL) -DSWFW_X11 -DSWFW_WAYLAND -c ./main.c 28 | $(CC) $(CFLAGS) -o ./simple ./*.o $(CCLIBS_X11_WAYLAND) 29 | $(MAKE) clear 30 | 31 | clear: 32 | rm -f ./*.o 33 | -------------------------------------------------------------------------------- /examples/simple/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct swfw_context swfw_ctx = {0}; 9 | struct swfw_window swfw_win = {0}; 10 | 11 | int32_t main(void) 12 | { 13 | enum swfw_status status = SWFW_OK; 14 | struct swfw_event event = {0}; 15 | bool running = true; 16 | int32_t screen_width = 0; 17 | int32_t screen_height = 0; 18 | status = swfw_make_context(&swfw_ctx, SWFW_BACKEND_AUTOMATIC); 19 | if (status != SWFW_OK) { 20 | printf("Error: failed to create context.\n"); 21 | abort(); 22 | } 23 | if (swfw_get_screen_size(&swfw_ctx, 0, &screen_width, &screen_height) == SWFW_OK) { 24 | printf("Screen size: %d, %d.\n", screen_width, screen_height); 25 | } 26 | status = swfw_make_window(&swfw_ctx, &swfw_win); 27 | if (status != SWFW_OK) { 28 | printf("Error: failed to create window.\n"); 29 | abort(); 30 | } 31 | swfw_window_swap_interval(&swfw_win, 1); 32 | swfw_set_window_resizable(&swfw_win, false); 33 | swfw_show_window(&swfw_win); 34 | swfw_set_window_title(&swfw_win, "Simple"); 35 | while (running) { 36 | while (swfw_poll_event(&swfw_ctx, &event)) { 37 | if (event.type == SWFW_EVENT_KEY_PRESS) { 38 | if (event.key_code) { 39 | printf("Event: key %d pressed.\n", event.key_code); 40 | } 41 | if (event.string_length) { 42 | printf(" utf %.*s pressed.\n", event.string_length, event.string); 43 | } 44 | } else if (event.type == SWFW_EVENT_KEY_RELEASE) { 45 | printf("Event: key %d released.\n", event.key_code); 46 | } else if (event.type == SWFW_EVENT_BUTTON_PRESS) { 47 | printf("Event: button pressed.\n"); 48 | swfw_drag_window(&swfw_win); 49 | } else if (event.type == SWFW_EVENT_BUTTON_RELEASE) { 50 | printf("Event: button released.\n"); 51 | } else if (event.type == SWFW_EVENT_CURSOR_MOTION) { 52 | printf("Event: cursor motion (%.0f, %.0f).\n", event.x, event.y); 53 | } else if (event.type == SWFW_EVENT_SCROLL) { 54 | printf("Event: scroll %u, %.2f.\n", event.axis, event.scroll); 55 | } else if (event.type == SWFW_EVENT_CURSOR_ENTER) { 56 | printf("Event: cursor enter.\n"); 57 | } else if (event.type == SWFW_EVENT_CURSOR_LEAVE) { 58 | printf("Event: cursor leave.\n"); 59 | } else if (event.type == SWFW_EVENT_DESTROY) { 60 | printf("Event: destroy window.\n"); 61 | running = false; 62 | } 63 | } 64 | glClearColor(0.5, 0.5, 0.5, 1.0); 65 | glClear(GL_COLOR_BUFFER_BIT); 66 | glFlush(); 67 | swfw_window_swap_buffers(&swfw_win); 68 | } 69 | swfw_destroy_window(&swfw_win); 70 | swfw_destroy_context(&swfw_ctx); 71 | return EXIT_SUCCESS; 72 | } 73 | -------------------------------------------------------------------------------- /src/swfw.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Felipe Ferreira da Silva 3 | 4 | This software is provided 'as-is', without any express or implied warranty. In 5 | no event will the authors be held liable for any damages arising from the use of 6 | this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including 9 | commercial applications, and to alter it and redistribute it freely, subject to3 10 | the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not claim 13 | that you wrote the original software. If you use this software in a 14 | product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include "swfw.h" 25 | 26 | #ifdef SWFW_WAYLAND 27 | #include 28 | #include 29 | #include 30 | #include 31 | #endif 32 | 33 | #define DEFAULT_HINT_USE_HARDWARE_ACCELERATION true 34 | #define DEFAULT_HINT_SIZE_WIDTH 256 35 | #define DEFAULT_HINT_SIZE_HEIGHT 256 36 | 37 | #ifdef SWFW_EGL 38 | static enum swfw_status swfw_egl_get_config(struct swfw_context_egl *swfw_ctx_egl) 39 | { 40 | enum swfw_status status = SWFW_OK; 41 | EGLConfig egl_conf = {0}; 42 | EGLConfig *configs = NULL; 43 | EGLint egl_num_configs = 0; 44 | EGLint val_EGL_SURFACE_TYPE = 0; 45 | EGLint val_EGL_RENDERABLE_TYPE = 0; 46 | EGLint val_EGL_COLOR_BUFFER_TYPE = 0; 47 | EGLint val_EGL_RED_SIZE = 0; 48 | EGLint val_EGL_GREEN_SIZE = 0; 49 | EGLint val_EGL_BLUE_SIZE = 0; 50 | EGLint val_EGL_ALPHA_SIZE = 0; 51 | EGLint val_EGL_DEPTH_SIZE = 0; 52 | EGLBoolean result = false; 53 | EGLint i = 0; 54 | result = eglGetConfigs(swfw_ctx_egl->display, NULL, 0, &egl_num_configs); 55 | if (result != EGL_TRUE) { 56 | status = SWFW_ERROR; 57 | goto done; 58 | } 59 | if (egl_num_configs == 0) { 60 | status = SWFW_ERROR; 61 | goto done; 62 | } 63 | configs = malloc(egl_num_configs * sizeof(*configs)); 64 | if (configs == NULL) { 65 | status = SWFW_ERROR; 66 | goto done; 67 | } 68 | result = eglGetConfigs(swfw_ctx_egl->display, configs, egl_num_configs, &egl_num_configs); 69 | if (result != EGL_TRUE) { 70 | free(configs); 71 | status = SWFW_ERROR; 72 | goto done; 73 | } 74 | status = SWFW_ERROR; 75 | while (i < egl_num_configs) { 76 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_SURFACE_TYPE, &val_EGL_SURFACE_TYPE); 77 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_COLOR_BUFFER_TYPE, &val_EGL_COLOR_BUFFER_TYPE); 78 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_RENDERABLE_TYPE, &val_EGL_RENDERABLE_TYPE); 79 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_RED_SIZE, &val_EGL_RED_SIZE); 80 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_GREEN_SIZE, &val_EGL_GREEN_SIZE); 81 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_BLUE_SIZE, &val_EGL_BLUE_SIZE); 82 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_ALPHA_SIZE, &val_EGL_ALPHA_SIZE); 83 | eglGetConfigAttrib(swfw_ctx_egl->display, configs[i], EGL_DEPTH_SIZE, &val_EGL_DEPTH_SIZE); 84 | if (val_EGL_SURFACE_TYPE & EGL_WINDOW_BIT && 85 | val_EGL_COLOR_BUFFER_TYPE & EGL_RGB_BUFFER && 86 | val_EGL_RENDERABLE_TYPE & EGL_OPENGL_ES2_BIT && 87 | val_EGL_RED_SIZE == 8 && 88 | val_EGL_GREEN_SIZE == 8 && 89 | val_EGL_BLUE_SIZE == 8 && 90 | val_EGL_ALPHA_SIZE == 8 && 91 | val_EGL_DEPTH_SIZE != 0) { 92 | egl_conf = configs[i]; 93 | i = egl_num_configs; 94 | status = SWFW_OK; 95 | } 96 | i++; 97 | } 98 | free(configs); 99 | swfw_ctx_egl->config = egl_conf; 100 | done: 101 | return status; 102 | } 103 | 104 | static enum swfw_status swfw_egl_swap_interval(struct swfw_context_egl *swfw_ctx_egl, int32_t interval) 105 | { 106 | enum swfw_status status = SWFW_OK; 107 | eglSwapInterval(swfw_ctx_egl->display, interval); 108 | if (eglGetError() != EGL_SUCCESS) { 109 | status = SWFW_ERROR; 110 | } 111 | return status; 112 | } 113 | 114 | static enum swfw_status swfw_egl_swap_buffers(struct swfw_context_egl *swfw_ctx_egl) 115 | { 116 | enum swfw_status status = SWFW_OK; 117 | eglSwapBuffers(swfw_ctx_egl->display, swfw_ctx_egl->surface); 118 | if (eglGetError() != EGL_SUCCESS) { 119 | status = SWFW_ERROR; 120 | } 121 | return status; 122 | } 123 | 124 | static enum swfw_status initialize_egl(struct swfw_context_egl *swfw_ctx_egl, void *native_display) 125 | { 126 | enum swfw_status status = SWFW_OK; 127 | swfw_ctx_egl->display = eglGetDisplay(native_display); 128 | if (swfw_ctx_egl->display == EGL_NO_DISPLAY) { 129 | status = SWFW_ERROR; 130 | } else { 131 | if (eglInitialize(swfw_ctx_egl->display, &swfw_ctx_egl->major, &swfw_ctx_egl->minor) != EGL_TRUE) { 132 | status = SWFW_ERROR; 133 | } 134 | } 135 | return status; 136 | } 137 | 138 | static enum swfw_status swfw_egl_create_context(struct swfw_context_egl *swfw_ctx_egl) 139 | { 140 | enum swfw_status status = SWFW_OK; 141 | EGLint context_attribs[] = { 142 | EGL_CONTEXT_CLIENT_VERSION, 2, 143 | EGL_NONE 144 | }; 145 | if (!eglBindAPI(EGL_OPENGL_API)) { 146 | status = SWFW_ERROR; 147 | goto done; 148 | } 149 | swfw_ctx_egl->context = eglCreateContext(swfw_ctx_egl->display, 150 | swfw_ctx_egl->config, 151 | EGL_NO_CONTEXT, 152 | context_attribs); 153 | if (swfw_ctx_egl->context == EGL_NO_CONTEXT) { 154 | status = SWFW_ERROR; 155 | } 156 | done: 157 | return status; 158 | } 159 | 160 | static enum swfw_status swfw_egl_create_surface(struct swfw_context_egl *swfw_ctx_egl, EGLNativeWindowType native_window) 161 | { 162 | enum swfw_status status = SWFW_OK; 163 | EGLint egl_surf_attr[] = { 164 | EGL_RENDER_BUFFER, EGL_BACK_BUFFER, 165 | EGL_NONE 166 | }; 167 | swfw_ctx_egl->surface = eglCreateWindowSurface(swfw_ctx_egl->display, 168 | swfw_ctx_egl->config, 169 | native_window, 170 | egl_surf_attr); 171 | if (swfw_ctx_egl->surface == EGL_NO_SURFACE) { 172 | status = SWFW_ERROR; 173 | } 174 | return status; 175 | } 176 | 177 | static enum swfw_status swfw_egl_make_current(struct swfw_context_egl *swfw_ctx_egl) 178 | { 179 | enum swfw_status status = SWFW_OK; 180 | if (eglMakeCurrent(swfw_ctx_egl->display, swfw_ctx_egl->surface, swfw_ctx_egl->surface, swfw_ctx_egl->context) == EGL_FALSE) { 181 | status = SWFW_ERROR; 182 | } 183 | return status; 184 | } 185 | #endif 186 | 187 | #ifdef SWFW_X11 188 | #ifndef _NET_WM_MOVERESIZE 189 | #define _NET_WM_MOVERESIZE 8 190 | #endif 191 | #ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT 192 | #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 193 | #endif 194 | #ifndef _NET_WM_MOVERESIZE_SIZE_TOP 195 | #define _NET_WM_MOVERESIZE_SIZE_TOP 1 196 | #endif 197 | #ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 198 | #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 199 | #endif 200 | #ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT 201 | #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 202 | #endif 203 | #ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 204 | #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 205 | #endif 206 | #ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM 207 | #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 208 | #endif 209 | #ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 210 | #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 211 | #endif 212 | #ifndef _NET_WM_MOVERESIZE_SIZE_LEFT 213 | #define _NET_WM_MOVERESIZE_SIZE_LEFT 7 214 | #endif 215 | #ifndef Button6 216 | #define Button6 6 217 | #endif 218 | #ifndef Button7 219 | #define Button7 7 220 | #endif 221 | 222 | struct x11_hints { 223 | uint64_t flags; 224 | uint64_t functions; 225 | uint64_t decorations; 226 | int64_t input_mode; 227 | uint64_t status; 228 | }; 229 | 230 | enum swfw_status swfw_drag_window_x11(struct swfw_window_x11 *swfw_win_x11) 231 | { 232 | Window child; 233 | Window root; 234 | int32_t window_x = 0; 235 | int32_t window_y = 0; 236 | int32_t root_x = 0; 237 | int32_t root_y = 0; 238 | int32_t cursor_x = 0; 239 | int32_t cursor_y = 0; 240 | unsigned int mask = 0; 241 | XClientMessageEvent xclient = {0}; 242 | XUngrabPointer(swfw_win_x11->swfw_ctx_x11->display, 0); 243 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 244 | XTranslateCoordinates(swfw_win_x11->swfw_ctx_x11->display, 245 | swfw_win_x11->window, 246 | swfw_win_x11->swfw_ctx_x11->root, 247 | 0, 0, 248 | &window_x, &window_y, 249 | &child); 250 | XQueryPointer(swfw_win_x11->swfw_ctx_x11->display, 251 | swfw_win_x11->window, 252 | &root, &child, 253 | &root_x, &root_y, &cursor_x, &cursor_y, 254 | &mask); 255 | xclient.type = ClientMessage; 256 | xclient.window = swfw_win_x11->window; 257 | xclient.message_type = swfw_win_x11->swfw_ctx_x11->atom_NET_WM_MOVERESIZE; 258 | xclient.format = 32; 259 | xclient.data.l[0] = window_x + cursor_x; 260 | xclient.data.l[1] = window_y + cursor_y; 261 | xclient.data.l[2] = _NET_WM_MOVERESIZE; 262 | xclient.data.l[3] = 0; 263 | xclient.data.l[4] = 0; 264 | XSendEvent(swfw_win_x11->swfw_ctx_x11->display, 265 | swfw_win_x11->swfw_ctx_x11->root, 266 | False, 267 | SubstructureRedirectMask | SubstructureNotifyMask, 268 | (XEvent *)&xclient); 269 | return SWFW_OK; 270 | } 271 | 272 | enum swfw_status swfw_resize_window_x11(struct swfw_window_x11 *swfw_win_x11, enum swfw_window_border window_border) 273 | { 274 | enum swfw_status status = SWFW_OK; 275 | Window child; 276 | Window root; 277 | int32_t window_x = 0; 278 | int32_t window_y = 0; 279 | int32_t root_x = 0; 280 | int32_t root_y = 0; 281 | int32_t cursor_x = 0.0; 282 | int32_t cursor_y = 0.0; 283 | unsigned int mask = 0; 284 | XClientMessageEvent xclient = {0}; 285 | XUngrabPointer(swfw_win_x11->swfw_ctx_x11->display, 0); 286 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 287 | XTranslateCoordinates(swfw_win_x11->swfw_ctx_x11->display, 288 | swfw_win_x11->window, 289 | swfw_win_x11->swfw_ctx_x11->root, 290 | 0, 0, 291 | &window_x, &window_y, 292 | &child); 293 | XQueryPointer(swfw_win_x11->swfw_ctx_x11->display, 294 | swfw_win_x11->window, 295 | &root, &child, 296 | &root_x, &root_y, &cursor_x, &cursor_y, 297 | &mask); 298 | xclient.type = ClientMessage; 299 | xclient.window = swfw_win_x11->window; 300 | xclient.message_type = swfw_win_x11->swfw_ctx_x11->atom_NET_WM_MOVERESIZE; 301 | xclient.format = 32; 302 | xclient.data.l[0] = window_x + cursor_x; 303 | xclient.data.l[1] = window_y + cursor_y; 304 | xclient.data.l[3] = 0; 305 | xclient.data.l[4] = 0; 306 | if (window_border == SWFW_WINDOW_BORDER_LEFT) { 307 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_LEFT; 308 | } else if (window_border == SWFW_WINDOW_BORDER_TOP) { 309 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOP; 310 | } else if (window_border == SWFW_WINDOW_BORDER_RIGHT) { 311 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_RIGHT; 312 | } else if (window_border == SWFW_WINDOW_BORDER_BOTTOM) { 313 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOM; 314 | } else if (window_border == SWFW_WINDOW_BORDER_TOP_LEFT) { 315 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; 316 | } else if (window_border == SWFW_WINDOW_BORDER_TOP_RIGHT) { 317 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; 318 | } else if (window_border == SWFW_WINDOW_BORDER_BOTTOM_LEFT) { 319 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; 320 | } else if (window_border == SWFW_WINDOW_BORDER_BOTTOM_RIGHT) { 321 | xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; 322 | } else { 323 | status = SWFW_ERROR; 324 | } 325 | if (status == SWFW_OK) { 326 | XSendEvent(swfw_win_x11->swfw_ctx_x11->display, 327 | swfw_win_x11->swfw_ctx_x11->root, 328 | False, 329 | SubstructureRedirectMask | SubstructureNotifyMask, 330 | (XEvent *)&xclient); 331 | } 332 | return status; 333 | } 334 | 335 | enum swfw_status swfw_hide_window_x11(struct swfw_window_x11 *swfw_win_x11) 336 | { 337 | XUnmapWindow(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window); 338 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 339 | return SWFW_OK; 340 | } 341 | 342 | enum swfw_status swfw_show_window_x11(struct swfw_window_x11 *swfw_win_x11) 343 | { 344 | XMapWindow(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window); 345 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 346 | return SWFW_OK; 347 | } 348 | 349 | enum swfw_status swfw_get_window_work_area_x11(struct swfw_window_x11 *swfw_win_x11, int32_t *x, int32_t *y, int32_t *width, int32_t *height) 350 | { 351 | Atom *extents = NULL; 352 | Atom actual_type; 353 | int32_t actual_format = 0; 354 | uint64_t item_count = 0; 355 | uint64_t bytes_after = 0; 356 | XGetWindowProperty(swfw_win_x11->swfw_ctx_x11->display, 357 | swfw_win_x11->swfw_ctx_x11->root, 358 | swfw_win_x11->swfw_ctx_x11->atom_NET_WORKAREA, 359 | 0, 360 | 4 * sizeof(uint64_t), 361 | False, 362 | AnyPropertyType, 363 | &actual_type, 364 | &actual_format, 365 | &item_count, 366 | &bytes_after, 367 | (uint8_t **)&extents); 368 | if (extents) { 369 | *x = extents[0]; 370 | *y = extents[1]; 371 | *width = extents[2]; 372 | *height = extents[3]; 373 | XFree(extents); 374 | } 375 | return SWFW_OK; 376 | } 377 | 378 | enum swfw_status swfw_set_window_position_x11(struct swfw_window_x11 *swfw_win_x11, int32_t x, int32_t y) 379 | { 380 | XMoveWindow(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window, x, y); 381 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 382 | return SWFW_OK; 383 | } 384 | 385 | enum swfw_status swfw_set_window_size_x11(struct swfw_window_x11 *swfw_win_x11, int32_t width, int32_t height) 386 | { 387 | XResizeWindow(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window, width, height); 388 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 389 | return SWFW_OK; 390 | } 391 | 392 | enum swfw_status swfw_set_window_size_limits_x11(struct swfw_window_x11 *swfw_win_x11, int32_t min_width, int32_t min_height, int32_t max_width, int32_t max_height) 393 | { 394 | XWindowAttributes attribs = {0}; 395 | XSizeHints size_hints = {0}; 396 | size_hints.flags = PMinSize | PMaxSize; 397 | XGetWindowAttributes(swfw_win_x11->swfw_ctx_x11->display, 398 | swfw_win_x11->window, 399 | &attribs); 400 | if (min_width > 0) { 401 | size_hints.min_width = min_width; 402 | } 403 | if (min_height > 0) { 404 | size_hints.min_height = min_height; 405 | } 406 | if (min_width > 0) { 407 | size_hints.max_width = max_width; 408 | } 409 | if (min_width > 0) { 410 | size_hints.max_height = max_height; 411 | } 412 | XSetWMNormalHints(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window, &size_hints); 413 | return SWFW_OK; 414 | } 415 | 416 | enum swfw_status swfw_set_window_resizable_x11(struct swfw_window_x11 *swfw_win_x11, bool resizable) 417 | { 418 | XWindowAttributes attribs = {0}; 419 | XSizeHints size_hints = {0}; 420 | size_hints.flags = PMinSize | PMaxSize; 421 | XGetWindowAttributes(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window, &attribs); 422 | if (resizable) { 423 | size_hints.min_width = 0; 424 | size_hints.min_height = 0; 425 | size_hints.max_width = INT32_MAX; 426 | size_hints.max_height = INT32_MAX; 427 | } else { 428 | size_hints.min_width = attribs.width; 429 | size_hints.min_height = attribs.height; 430 | size_hints.max_width = attribs.width; 431 | size_hints.max_height = attribs.height; 432 | } 433 | XSetWMNormalHints(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window, &size_hints); 434 | return SWFW_OK; 435 | } 436 | 437 | enum swfw_status swfw_set_window_decorated_x11(struct swfw_window_x11 *swfw_win_x11, bool decorated) 438 | { 439 | struct x11_hints hints = {0}; 440 | if (decorated) { 441 | XDeleteProperty(swfw_win_x11->swfw_ctx_x11->display, 442 | swfw_win_x11->window, 443 | swfw_win_x11->swfw_ctx_x11->atom_MOTIF_WM_HINTS); 444 | } else if (swfw_win_x11->swfw_ctx_x11->atom_MOTIF_WM_HINTS != None) { 445 | hints.flags = 2; 446 | hints.decorations = 0; 447 | XChangeProperty(swfw_win_x11->swfw_ctx_x11->display, 448 | swfw_win_x11->window, 449 | swfw_win_x11->swfw_ctx_x11->atom_MOTIF_WM_HINTS, 450 | swfw_win_x11->swfw_ctx_x11->atom_MOTIF_WM_HINTS, 451 | 32, 452 | PropModeReplace, 453 | (uint8_t *)&hints, 454 | sizeof(struct x11_hints)); 455 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 456 | } 457 | return SWFW_OK; 458 | } 459 | 460 | enum swfw_status swfw_set_window_title_x11(struct swfw_window_x11 *swfw_win_x11, char *title) 461 | { 462 | XStoreName(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window, title); 463 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 464 | return SWFW_OK; 465 | } 466 | 467 | enum swfw_status swfw_window_swap_interval_x11(struct swfw_window_x11 *swfw_win_x11, int32_t interval) 468 | { 469 | enum swfw_status status = SWFW_OK; 470 | #ifdef SWFW_EGL 471 | status = swfw_egl_swap_interval(&swfw_win_x11->swfw_ctx_egl, interval); 472 | #endif 473 | return status; 474 | } 475 | 476 | enum swfw_status swfw_window_swap_buffers_x11(struct swfw_window_x11 *swfw_win_x11) 477 | { 478 | enum swfw_status status = SWFW_OK; 479 | #ifdef SWFW_EGL 480 | status = swfw_egl_swap_buffers(&swfw_win_x11->swfw_ctx_egl); 481 | #endif 482 | return status; 483 | } 484 | 485 | enum swfw_status swfw_destroy_window_x11(struct swfw_window_x11 *swfw_win_x11) 486 | { 487 | XUnmapWindow(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window); 488 | XDestroyWindow(swfw_win_x11->swfw_ctx_x11->display, swfw_win_x11->window); 489 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 490 | return SWFW_OK; 491 | } 492 | 493 | enum swfw_status swfw_make_window_x11(struct swfw_context_x11 *swfw_ctx_x11, struct swfw_window_x11 *swfw_win_x11, struct swfw_hints hints) 494 | { 495 | enum swfw_status status = SWFW_OK; 496 | swfw_win_x11->swfw_ctx_x11 = swfw_ctx_x11; 497 | swfw_win_x11->window = XCreateWindow(swfw_win_x11->swfw_ctx_x11->display, 498 | swfw_win_x11->swfw_ctx_x11->root, 499 | hints.x, hints.y, 500 | hints.width, hints.height, 501 | 0, 502 | swfw_win_x11->swfw_ctx_x11->depth, 503 | InputOutput, 504 | swfw_win_x11->swfw_ctx_x11->visual, 505 | swfw_win_x11->swfw_ctx_x11->mask, 506 | &swfw_win_x11->swfw_ctx_x11->attributes); 507 | if (swfw_win_x11->window) { 508 | XSetWMProtocols(swfw_win_x11->swfw_ctx_x11->display, 509 | swfw_win_x11->window, 510 | &swfw_win_x11->swfw_ctx_x11->atom_WM_DELETE_WINDOW, 511 | 1); 512 | XFlush(swfw_win_x11->swfw_ctx_x11->display); 513 | } else { 514 | status = SWFW_ERROR; 515 | } 516 | if (swfw_win_x11->swfw_ctx_x11->im) { 517 | swfw_win_x11->ic = XCreateIC(swfw_win_x11->swfw_ctx_x11->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, swfw_win_x11->window, NULL); 518 | if (swfw_win_x11->ic) { 519 | XSetICFocus(swfw_win_x11->ic); 520 | } 521 | } 522 | XSaveContext(swfw_win_x11->swfw_ctx_x11->display, 523 | swfw_win_x11->window, 524 | swfw_win_x11->swfw_ctx_x11->context, 525 | (char *)swfw_win_x11); 526 | swfw_win_x11->use_hardware_acceleration = hints.use_hardware_acceleration; 527 | #ifdef SWFW_EGL 528 | if (swfw_win_x11->use_hardware_acceleration) { 529 | if (initialize_egl(&swfw_win_x11->swfw_ctx_egl, swfw_ctx_x11->display) != SWFW_OK) { 530 | abort(); 531 | } 532 | if (swfw_egl_get_config(&swfw_win_x11->swfw_ctx_egl) != SWFW_OK) { 533 | abort(); 534 | } 535 | if (swfw_egl_create_context(&swfw_win_x11->swfw_ctx_egl) != SWFW_OK) { 536 | abort(); 537 | } 538 | if (swfw_egl_create_surface(&swfw_win_x11->swfw_ctx_egl, (EGLNativeWindowType)swfw_win_x11->window) != SWFW_OK) { 539 | abort(); 540 | } 541 | if (swfw_egl_make_current(&swfw_win_x11->swfw_ctx_egl) != SWFW_OK) { 542 | abort(); 543 | } 544 | glClearColor(0.0, 0.0, 0.0, 1.0); 545 | glClear(GL_COLOR_BUFFER_BIT); 546 | glFlush(); 547 | if (swfw_window_swap_buffers_x11(swfw_win_x11) != SWFW_OK) { 548 | abort(); 549 | } 550 | } 551 | #endif 552 | return status; 553 | } 554 | 555 | enum swfw_status swfw_get_screen_size_x11(struct swfw_context_x11 *swfw_ctx_x11, int32_t i, int32_t *width, int32_t *height) 556 | { 557 | enum swfw_status status = SWFW_OK; 558 | if (i > XScreenCount(swfw_ctx_x11->display)) { 559 | status = SWFW_ERROR; 560 | goto done; 561 | } 562 | *width = XWidthOfScreen(swfw_ctx_x11->screen); 563 | *height = XHeightOfScreen(swfw_ctx_x11->screen); 564 | done: 565 | return status; 566 | } 567 | 568 | enum swfw_status swfw_get_screens_x11(struct swfw_context_x11 *swfw_ctx_x11, int32_t *i) 569 | { 570 | *i = XScreenCount(swfw_ctx_x11->display); 571 | return SWFW_OK; 572 | } 573 | 574 | bool swfw_poll_event_x11(struct swfw_context_x11 *swfw_ctx_x11, struct swfw_event *event) 575 | { 576 | struct swfw_event e = {0}; 577 | XEvent x11_event = {0}; 578 | bool has_event = false; 579 | struct swfw_window_x11 *swfw_win_x11 = NULL; 580 | bool event_filtered = false; 581 | if (XPending(swfw_ctx_x11->display) > 0) { 582 | XNextEvent(swfw_ctx_x11->display, &x11_event); 583 | if (XFilterEvent(&x11_event, None)) { 584 | event_filtered = true; 585 | } 586 | if (XFindContext(swfw_ctx_x11->display, x11_event.xany.window, swfw_ctx_x11->context, (char **)&swfw_win_x11) != 0) { 587 | abort(); 588 | } 589 | if (x11_event.type == Expose) { 590 | e.type = SWFW_EVENT_EXPOSE; 591 | } else if (x11_event.type == KeyPress) { 592 | KeySym keysym = 0; 593 | Status status = 0; 594 | e.type = SWFW_EVENT_KEY_PRESS; 595 | e.key_code = x11_event.xkey.keycode; 596 | if (swfw_win_x11->ic) { 597 | e.string_length = Xutf8LookupString(swfw_win_x11->ic, &x11_event.xkey, e.string, 4, &keysym, &status); 598 | if ((status == XLookupChars || status == XLookupBoth) && status != XBufferOverflow) { 599 | if (event_filtered) { 600 | e.string_length = 0; 601 | } 602 | } else { 603 | e.string_length = 0; 604 | } 605 | e.key_sym = keysym; 606 | } 607 | } else if (x11_event.type == KeyRelease) { 608 | e.type = SWFW_EVENT_KEY_RELEASE; 609 | e.key_code = x11_event.xkey.keycode; 610 | } else if (x11_event.type == MotionNotify) { 611 | e.type = SWFW_EVENT_CURSOR_MOTION; 612 | e.x = x11_event.xmotion.x; 613 | e.y = x11_event.xmotion.y; 614 | } else if (x11_event.type == ButtonPress || x11_event.type == ButtonRelease) { 615 | if (x11_event.xbutton.button == Button1 || x11_event.xbutton.button == Button2 || x11_event.xbutton.button == Button3) { 616 | if (x11_event.type == ButtonPress) { 617 | e.type = SWFW_EVENT_BUTTON_PRESS; 618 | } else if (x11_event.type == ButtonRelease) { 619 | e.type = SWFW_EVENT_BUTTON_RELEASE; 620 | } 621 | e.button = x11_event.xbutton.button; 622 | } else { 623 | e.type = SWFW_EVENT_SCROLL; 624 | if (x11_event.xbutton.button == Button4) { 625 | e.axis = 0; 626 | e.scroll = -1; 627 | } 628 | if (x11_event.xbutton.button == Button5) { 629 | e.axis = 0; 630 | e.scroll = 1; 631 | } 632 | if (x11_event.xbutton.button == Button6) { 633 | e.axis = 1; 634 | e.scroll = -1; 635 | } 636 | if (x11_event.xbutton.button == Button7) { 637 | e.axis = 1; 638 | e.scroll = 1; 639 | } 640 | } 641 | } else if (x11_event.type == EnterNotify) { 642 | e.type = SWFW_EVENT_CURSOR_ENTER; 643 | } else if (x11_event.type == LeaveNotify) { 644 | e.type = SWFW_EVENT_CURSOR_LEAVE; 645 | } else if (x11_event.type == ConfigureNotify) { 646 | e.type = SWFW_EVENT_CONFIGURE; 647 | } else if (x11_event.type == MapNotify) { 648 | e.type = SWFW_EVENT_MAP; 649 | } else if (x11_event.type == UnmapNotify) { 650 | e.type = SWFW_EVENT_UNMAP; 651 | } else if (x11_event.type == DestroyNotify) { 652 | e.type = SWFW_EVENT_DESTROY; 653 | } else if (x11_event.type == ClientMessage) { 654 | if(x11_event.xclient.data.l[0] == swfw_ctx_x11->atom_WM_DELETE_WINDOW) { 655 | e.type = SWFW_EVENT_DESTROY; 656 | } 657 | } 658 | if (e.type != 0) { 659 | has_event = true; 660 | } 661 | } 662 | *event = e; 663 | return has_event; 664 | } 665 | 666 | enum swfw_status swfw_destroy_context_x11(struct swfw_context_x11 *swfw_ctx_x11) 667 | { 668 | XCloseDisplay(swfw_ctx_x11->display); 669 | return SWFW_OK; 670 | } 671 | 672 | enum swfw_status swfw_make_context_x11(struct swfw_context_x11 *swfw_ctx_x11) 673 | { 674 | enum swfw_status status = SWFW_OK; 675 | bool locale_ok = true; 676 | if (setlocale(LC_ALL, "") == NULL) { 677 | locale_ok = false; 678 | } 679 | if (locale_ok) { 680 | if (!XSupportsLocale()) { 681 | locale_ok = false; 682 | } 683 | } 684 | if (locale_ok) { 685 | if (XSetLocaleModifiers("@im=none") == NULL) { 686 | locale_ok = false; 687 | } 688 | } 689 | /* Display */ 690 | swfw_ctx_x11->display = XOpenDisplay(NULL); 691 | swfw_ctx_x11->screen = XDefaultScreenOfDisplay(swfw_ctx_x11->display); 692 | swfw_ctx_x11->visual = XDefaultVisualOfScreen(swfw_ctx_x11->screen); 693 | swfw_ctx_x11->root = XRootWindowOfScreen(swfw_ctx_x11->screen); 694 | swfw_ctx_x11->depth = XDefaultDepthOfScreen(swfw_ctx_x11->screen); 695 | swfw_ctx_x11->colormap = XCreateColormap(swfw_ctx_x11->display, 696 | swfw_ctx_x11->root, 697 | swfw_ctx_x11->visual, 698 | AllocNone); 699 | XFlush(swfw_ctx_x11->display); 700 | /* Attributes */ 701 | swfw_ctx_x11->mask = CWBackPixel | CWColormap | CWEventMask; 702 | swfw_ctx_x11->attributes.background_pixel = 0; 703 | swfw_ctx_x11->attributes.event_mask = StructureNotifyMask | 704 | KeyPressMask | KeyReleaseMask | 705 | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | 706 | ExposureMask | FocusChangeMask | VisibilityChangeMask | 707 | EnterWindowMask | LeaveWindowMask | PropertyChangeMask; 708 | /* Save X11 atoms */ 709 | swfw_ctx_x11->atom_WM_PROTOCOLS = XInternAtom(swfw_ctx_x11->display, "WM_PROTOCOLS", False); 710 | swfw_ctx_x11->atom_WM_STATE = XInternAtom(swfw_ctx_x11->display, "WM_STATE", False); 711 | swfw_ctx_x11->atom_WM_DELETE_WINDOW = XInternAtom(swfw_ctx_x11->display, "WM_DELETE_WINDOW", False); 712 | swfw_ctx_x11->atom_NET_WM_ICON = XInternAtom(swfw_ctx_x11->display, "_NET_WM_ICON", False); 713 | swfw_ctx_x11->atom_NET_WM_PING = XInternAtom(swfw_ctx_x11->display, "_NET_WM_PING", False); 714 | swfw_ctx_x11->atom_NET_WM_PID = XInternAtom(swfw_ctx_x11->display, "_NET_WM_PID", False); 715 | swfw_ctx_x11->atom_NET_WM_NAME = XInternAtom(swfw_ctx_x11->display, "_NET_WM_NAME", False); 716 | swfw_ctx_x11->atom_NET_WM_ICON_NAME = XInternAtom(swfw_ctx_x11->display, "_NET_WM_ICON_NAME", False); 717 | swfw_ctx_x11->atom_NET_WM_MOVERESIZE = XInternAtom(swfw_ctx_x11->display, "_NET_WM_MOVERESIZE", False); 718 | swfw_ctx_x11->atom_NET_WORKAREA = XInternAtom(swfw_ctx_x11->display, "_NET_WORKAREA", True); 719 | swfw_ctx_x11->atom_NET_WM_BYPASS_COMPOSITOR = XInternAtom(swfw_ctx_x11->display, "_NET_WM_BYPASS_COMPOSITOR", False); 720 | swfw_ctx_x11->atom_MOTIF_WM_HINTS = XInternAtom(swfw_ctx_x11->display, "_MOTIF_WM_HINTS", True); 721 | if (locale_ok) { 722 | swfw_ctx_x11->im = XOpenIM(swfw_ctx_x11->display, NULL, NULL, NULL); 723 | if (swfw_ctx_x11->im) { 724 | char *arg = XGetIMValues(swfw_ctx_x11->im, XNQueryInputStyle, &swfw_ctx_x11->styles, NULL); 725 | if (arg) { 726 | XCloseIM(swfw_ctx_x11->im); 727 | swfw_ctx_x11->im = NULL; 728 | } 729 | } 730 | } 731 | swfw_ctx_x11->context = XUniqueContext(); 732 | return status; 733 | } 734 | #endif /* SWFW_X11 */ 735 | 736 | #ifdef SWFW_WAYLAND 737 | 738 | #ifndef SWFW_WAYLAND_TMP_FILE_TEMPLATE 739 | #define SWFW_WAYLAND_TMP_FILE_TEMPLATE "/swfwsoXXXXXX" 740 | #endif 741 | 742 | static int32_t swfw_wl_create_file(off_t size) 743 | { 744 | static const char template[] = SWFW_WAYLAND_TMP_FILE_TEMPLATE; 745 | const char *path = NULL; 746 | char *tmp_name = NULL; 747 | int32_t fd = -1; 748 | path = getenv("XDG_RUNTIME_DIR"); 749 | if (!path) { 750 | goto done; 751 | } 752 | tmp_name = calloc(strlen(path) + sizeof(template) + 1, sizeof(char)); 753 | if (!tmp_name) { 754 | goto done; 755 | } 756 | strcpy(tmp_name, path); 757 | strcat(tmp_name, template); 758 | #ifdef HAVE_MKOSTEMP 759 | fd = mkostemp(tmp_name, O_CLOEXEC | O_TMPFILE); 760 | #else 761 | fd = mkstemp(tmp_name); 762 | if (fd >= 0) { 763 | long flags = fcntl(fd, F_GETFD); 764 | if (flags == -1) { 765 | close(fd); 766 | fd = -1; 767 | } else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) { 768 | close(fd); 769 | fd = -1; 770 | } 771 | } 772 | #endif 773 | if (fd < 0) { 774 | goto done; 775 | } 776 | if (unlink(tmp_name)) { 777 | close(fd); 778 | fd = -1; 779 | goto done; 780 | } 781 | if (ftruncate(fd, size) < 0) { 782 | close(fd); 783 | fd = -1; 784 | } 785 | done: 786 | if (tmp_name) { 787 | free(tmp_name); 788 | } 789 | return fd; 790 | } 791 | 792 | static void shell_surface_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) 793 | { 794 | wl_shell_surface_pong(shell_surface, serial); 795 | } 796 | 797 | static void shell_surface_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) 798 | { 799 | struct swfw_window_wl *swfw_win_wl = data; 800 | struct wl_region *region = NULL; 801 | swfw_win_wl->width = width; 802 | swfw_win_wl->height = height; 803 | region = wl_compositor_create_region(swfw_win_wl->swfw_ctx_wl->compositor); 804 | wl_region_add(region, 0, 0, width, height); 805 | wl_surface_set_opaque_region(swfw_win_wl->surface, region); 806 | wl_surface_commit(swfw_win_wl->surface); 807 | wl_region_destroy(region); 808 | #ifdef SWFW_EGL 809 | if (swfw_win_wl->use_hardware_acceleration) { 810 | wl_egl_window_resize(swfw_win_wl->egl_window, width, height, 0, 0); 811 | } 812 | #endif 813 | } 814 | 815 | static const struct wl_shell_surface_listener shell_surface_listener = { 816 | shell_surface_ping, 817 | shell_surface_configure 818 | }; 819 | 820 | static void swfw_wl_create_shell_surface(struct swfw_window_wl *swfw_win_wl) 821 | { 822 | swfw_win_wl->shell_surface = wl_shell_get_shell_surface(swfw_win_wl->swfw_ctx_wl->shell, swfw_win_wl->surface); 823 | wl_shell_surface_add_listener(swfw_win_wl->shell_surface, &shell_surface_listener, swfw_win_wl); 824 | wl_shell_surface_set_toplevel(swfw_win_wl->shell_surface); 825 | } 826 | 827 | enum swfw_status swfw_drag_window_wl(struct swfw_window_wl *swfw_win_wl) 828 | { 829 | if (swfw_win_wl->shell_surface) { 830 | wl_shell_surface_move(swfw_win_wl->shell_surface, swfw_win_wl->swfw_ctx_wl->seat, swfw_win_wl->swfw_ctx_wl->pointer_serial); 831 | } 832 | return SWFW_OK; 833 | } 834 | 835 | enum swfw_status swfw_resize_window_wl(struct swfw_window_wl *swfw_win_wl, enum swfw_window_border window_border) 836 | { 837 | enum swfw_status status = SWFW_OK; 838 | int32_t border = 0; 839 | if (window_border == SWFW_WINDOW_BORDER_LEFT) { 840 | border = WL_SHELL_SURFACE_RESIZE_LEFT; 841 | } else if (window_border == SWFW_WINDOW_BORDER_TOP) { 842 | border = WL_SHELL_SURFACE_RESIZE_TOP; 843 | } else if (window_border == SWFW_WINDOW_BORDER_RIGHT) { 844 | border = WL_SHELL_SURFACE_RESIZE_RIGHT; 845 | } else if (window_border == SWFW_WINDOW_BORDER_BOTTOM) { 846 | border = WL_SHELL_SURFACE_RESIZE_BOTTOM; 847 | } else if (window_border == SWFW_WINDOW_BORDER_TOP_LEFT) { 848 | border = WL_SHELL_SURFACE_RESIZE_TOP_LEFT; 849 | } else if (window_border == SWFW_WINDOW_BORDER_TOP_RIGHT) { 850 | border = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; 851 | } else if (window_border == SWFW_WINDOW_BORDER_BOTTOM_LEFT) { 852 | border = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; 853 | } else if (window_border == SWFW_WINDOW_BORDER_BOTTOM_RIGHT) { 854 | border = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; 855 | } else { 856 | status = SWFW_ERROR; 857 | } 858 | if (status == SWFW_OK && swfw_win_wl->shell_surface) { 859 | wl_shell_surface_resize(swfw_win_wl->shell_surface, 860 | swfw_win_wl->swfw_ctx_wl->seat, 861 | swfw_win_wl->swfw_ctx_wl->pointer_serial, 862 | border); 863 | } 864 | return status; 865 | } 866 | 867 | enum swfw_status swfw_hide_window_wl(struct swfw_window_wl *swfw_win_wl) 868 | { 869 | if (swfw_win_wl->surface) { 870 | wl_surface_attach(swfw_win_wl->surface, NULL, 0, 0); 871 | wl_surface_commit(swfw_win_wl->surface); 872 | wl_display_dispatch(swfw_win_wl->swfw_ctx_wl->display); 873 | } 874 | return SWFW_OK; 875 | } 876 | 877 | enum swfw_status swfw_show_window_wl(struct swfw_window_wl *swfw_win_wl) 878 | { 879 | if (swfw_win_wl->surface) { 880 | wl_surface_attach(swfw_win_wl->surface, swfw_win_wl->buffer, 0, 0); 881 | } 882 | wl_surface_commit(swfw_win_wl->surface); 883 | wl_display_dispatch(swfw_win_wl->swfw_ctx_wl->display); 884 | return SWFW_OK; 885 | } 886 | 887 | enum swfw_status swfw_get_window_work_area_wl(struct swfw_window_wl *swfw_win_wl, int32_t *x, int32_t *y, int32_t *width, int32_t *height) 888 | { 889 | return SWFW_UNSUPPORTED; 890 | } 891 | 892 | enum swfw_status swfw_set_window_position_wl(struct swfw_window_wl *swfw_win_wl, int32_t x, int32_t y) 893 | { 894 | return SWFW_UNSUPPORTED; 895 | } 896 | 897 | enum swfw_status swfw_set_window_size_wl(struct swfw_window_wl *swfw_win_wl, int32_t width, int32_t height) 898 | { 899 | return SWFW_UNSUPPORTED; 900 | } 901 | 902 | enum swfw_status swfw_set_window_size_limits_wl(struct swfw_window_wl *swfw_win_wl, int32_t min_width, int32_t min_height, int32_t max_width, int32_t max_height) 903 | { 904 | return SWFW_UNSUPPORTED; 905 | } 906 | 907 | enum swfw_status swfw_set_window_resizable_wl(struct swfw_window_wl *swfw_win_wl, bool resizable) 908 | { 909 | return SWFW_UNSUPPORTED; 910 | } 911 | 912 | enum swfw_status swfw_set_window_decorated_wl(struct swfw_window_wl *swfw_win_wl, bool decorated) 913 | { 914 | return SWFW_UNSUPPORTED; 915 | } 916 | 917 | enum swfw_status swfw_set_window_title_wl(struct swfw_window_wl *swfw_win_wl, char *title) 918 | { 919 | if (swfw_win_wl->shell_surface) { 920 | wl_shell_surface_set_title(swfw_win_wl->shell_surface, title); 921 | } 922 | return SWFW_OK; 923 | } 924 | 925 | enum swfw_status swfw_window_swap_interval_wl(struct swfw_window_wl *swfw_win_wl, int32_t interval) 926 | { 927 | enum swfw_status status = SWFW_OK; 928 | #ifdef SWFW_EGL 929 | if (swfw_win_wl->use_hardware_acceleration) { 930 | status = swfw_egl_swap_interval(&swfw_win_wl->swfw_ctx_egl, interval); 931 | } 932 | #endif 933 | return status; 934 | } 935 | 936 | enum swfw_status swfw_window_swap_buffers_wl(struct swfw_window_wl *swfw_win_wl) 937 | { 938 | enum swfw_status status = SWFW_OK; 939 | #ifdef SWFW_EGL 940 | if (swfw_win_wl->use_hardware_acceleration) { 941 | status = swfw_egl_swap_buffers(&swfw_win_wl->swfw_ctx_egl); 942 | } 943 | #endif 944 | return status; 945 | } 946 | 947 | enum swfw_status swfw_destroy_window_wl(struct swfw_window_wl *swfw_win_wl) 948 | { 949 | if (swfw_win_wl->buffer) { 950 | wl_surface_attach(swfw_win_wl->surface, NULL, 0, 0); 951 | wl_buffer_destroy(swfw_win_wl->buffer); 952 | wl_shm_pool_destroy(swfw_win_wl->shm_pool); 953 | close(swfw_win_wl->fd); 954 | } 955 | wl_surface_destroy(swfw_win_wl->surface); 956 | wl_shell_surface_destroy(swfw_win_wl->shell_surface); 957 | return SWFW_OK; 958 | } 959 | 960 | void surface_listener_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) 961 | { 962 | } 963 | 964 | static void surface_listener_leave(void *data, struct wl_surface *wl_surface, struct wl_output *output) 965 | { 966 | } 967 | 968 | static const struct wl_surface_listener surface_listener = { 969 | surface_listener_enter, 970 | surface_listener_leave 971 | }; 972 | 973 | enum swfw_status swfw_make_window_wl(struct swfw_context_wl *swfw_ctx_wl, struct swfw_window_wl *swfw_win_wl, struct swfw_hints hints) 974 | { 975 | enum swfw_status status = SWFW_OK; 976 | struct wl_region *region = NULL; 977 | swfw_win_wl->width = hints.width; 978 | swfw_win_wl->height = hints.height; 979 | /* Wayland surface */ 980 | swfw_win_wl->swfw_ctx_wl = swfw_ctx_wl; 981 | swfw_win_wl->surface = wl_compositor_create_surface(swfw_ctx_wl->compositor); 982 | wl_surface_add_listener(swfw_win_wl->surface, &surface_listener, swfw_win_wl); 983 | swfw_wl_create_shell_surface(swfw_win_wl); 984 | /* Opaque region */ 985 | region = wl_compositor_create_region(swfw_win_wl->swfw_ctx_wl->compositor); 986 | wl_region_add(region, 0, 0, hints.width, hints.height); 987 | wl_surface_set_opaque_region(swfw_win_wl->surface, region); 988 | wl_surface_commit(swfw_win_wl->surface); 989 | wl_region_destroy(region); 990 | /* Buffer */ 991 | swfw_win_wl->fd = swfw_wl_create_file(swfw_win_wl->width * 4 * swfw_win_wl->height); 992 | if (swfw_win_wl->fd >= 0) { 993 | swfw_win_wl->shm_data = mmap(NULL, swfw_win_wl->width * 4 * swfw_win_wl->height, PROT_READ | PROT_WRITE, MAP_SHARED, swfw_win_wl->fd, 0); 994 | swfw_win_wl->shm_pool = wl_shm_create_pool(swfw_win_wl->swfw_ctx_wl->shm, swfw_win_wl->fd, swfw_win_wl->width * 4 * swfw_win_wl->height); 995 | } 996 | if (swfw_win_wl->shm_pool) { 997 | swfw_win_wl->buffer = wl_shm_pool_create_buffer(swfw_win_wl->shm_pool, 0, 998 | swfw_win_wl->width, swfw_win_wl->height, swfw_win_wl->width * 4, WL_SHM_FORMAT_XRGB8888); 999 | } 1000 | /* Hardware acceleration */ 1001 | swfw_win_wl->use_hardware_acceleration = hints.use_hardware_acceleration; 1002 | #ifdef SWFW_EGL 1003 | if (swfw_win_wl->use_hardware_acceleration) { 1004 | if (initialize_egl(&swfw_win_wl->swfw_ctx_egl, swfw_ctx_wl->display) != SWFW_OK) { 1005 | abort(); 1006 | } 1007 | if (swfw_egl_get_config(&swfw_win_wl->swfw_ctx_egl) != SWFW_OK) { 1008 | abort(); 1009 | } 1010 | swfw_win_wl->egl_window = wl_egl_window_create(swfw_win_wl->surface, 1011 | hints.width, hints.height); 1012 | if (!swfw_win_wl->egl_window) { 1013 | abort(); 1014 | } 1015 | if (swfw_egl_create_context(&swfw_win_wl->swfw_ctx_egl) != SWFW_OK) { 1016 | abort(); 1017 | } 1018 | if (swfw_egl_create_surface(&swfw_win_wl->swfw_ctx_egl, (EGLNativeWindowType)swfw_win_wl->egl_window) != SWFW_OK) { 1019 | abort(); 1020 | } 1021 | if (swfw_egl_make_current(&swfw_win_wl->swfw_ctx_egl) != SWFW_OK) { 1022 | abort(); 1023 | } 1024 | glClearColor(0.0, 0.0, 0.0, 1.0); 1025 | glClear(GL_COLOR_BUFFER_BIT); 1026 | glFlush(); 1027 | if (swfw_window_swap_buffers_wl(swfw_win_wl) != SWFW_OK) { 1028 | abort(); 1029 | } 1030 | } 1031 | #endif 1032 | return status; 1033 | } 1034 | 1035 | enum swfw_status swfw_get_screen_size_wl(struct swfw_context_wl *swfw_ctx_wl, int32_t i, int32_t *width, int32_t *height) 1036 | { 1037 | return SWFW_UNSUPPORTED; 1038 | } 1039 | 1040 | enum swfw_status swfw_get_screens_wl(struct swfw_context_wl *swfw_ctx_wl, int32_t *i) 1041 | { 1042 | return SWFW_UNSUPPORTED; 1043 | } 1044 | 1045 | bool swfw_poll_event_wl(struct swfw_context_wl *swfw_ctx_wl, struct swfw_event *event) 1046 | { 1047 | bool has_event = false; 1048 | if (wl_display_dispatch_pending(swfw_ctx_wl->display) > 0) { 1049 | *event = swfw_ctx_wl->event; 1050 | if (swfw_ctx_wl->event.type != 0) { 1051 | has_event = true; 1052 | } 1053 | } 1054 | return has_event; 1055 | } 1056 | 1057 | enum swfw_status swfw_destroy_context_wl(struct swfw_context_wl *swfw_ctx_wl) 1058 | { 1059 | return SWFW_OK; 1060 | } 1061 | 1062 | static void pointer_listener_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) 1063 | { 1064 | struct swfw_context_wl *swfw_ctx_wl = data; 1065 | struct swfw_event e = {0}; 1066 | swfw_ctx_wl->pointer_serial = serial; 1067 | e.type = SWFW_EVENT_CURSOR_ENTER; 1068 | swfw_ctx_wl->event = e; 1069 | } 1070 | 1071 | static void pointer_listener_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) 1072 | { 1073 | struct swfw_context_wl *swfw_ctx_wl = data; 1074 | struct swfw_event e = {0}; 1075 | swfw_ctx_wl->pointer_serial = serial; 1076 | e.type = SWFW_EVENT_CURSOR_LEAVE; 1077 | swfw_ctx_wl->event = e; 1078 | } 1079 | 1080 | static void pointer_listener_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) 1081 | { 1082 | struct swfw_context_wl *swfw_ctx_wl = data; 1083 | struct swfw_event e = {0}; 1084 | e.type = SWFW_EVENT_CURSOR_MOTION; 1085 | e.x = wl_fixed_to_double(x); 1086 | e.y = wl_fixed_to_double(y); 1087 | swfw_ctx_wl->event = e; 1088 | } 1089 | 1090 | static void pointer_listener_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) 1091 | { 1092 | struct swfw_context_wl *swfw_ctx_wl = data; 1093 | struct swfw_event e = {0}; 1094 | swfw_ctx_wl->pointer_serial = serial; 1095 | if (state == WL_POINTER_BUTTON_STATE_PRESSED) { 1096 | e.type = SWFW_EVENT_BUTTON_PRESS; 1097 | } else { 1098 | e.type = SWFW_EVENT_BUTTON_RELEASE; 1099 | } 1100 | e.button = button; 1101 | swfw_ctx_wl->event = e; 1102 | } 1103 | 1104 | static void pointer_listener_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) 1105 | { 1106 | struct swfw_context_wl *swfw_ctx_wl = data; 1107 | struct swfw_event e = {0}; 1108 | e.type = SWFW_EVENT_SCROLL; 1109 | e.axis = axis; 1110 | e.scroll = wl_fixed_to_double(value); 1111 | swfw_ctx_wl->event = e; 1112 | } 1113 | 1114 | static void keyboard_listener_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) 1115 | { 1116 | } 1117 | 1118 | static void keyboard_listener_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) 1119 | { 1120 | } 1121 | 1122 | static void keyboard_listener_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) 1123 | { 1124 | } 1125 | 1126 | static void keyboard_listener_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) 1127 | { 1128 | struct swfw_context_wl *swfw_ctx_wl = data; 1129 | struct swfw_event e = {0}; 1130 | if (state == 0) { 1131 | e.type = SWFW_EVENT_KEY_RELEASE; 1132 | } else { 1133 | e.type = SWFW_EVENT_KEY_PRESS; 1134 | } 1135 | e.key_code = key; 1136 | swfw_ctx_wl->event = e; 1137 | } 1138 | 1139 | static void keyboard_listener_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) 1140 | { 1141 | } 1142 | 1143 | static struct wl_pointer_listener pointer_listener = { 1144 | pointer_listener_enter, 1145 | pointer_listener_leave, 1146 | pointer_listener_motion, 1147 | pointer_listener_button, 1148 | pointer_listener_axis 1149 | }; 1150 | 1151 | static struct wl_keyboard_listener keyboard_listener = { 1152 | keyboard_listener_keymap, 1153 | keyboard_listener_enter, 1154 | keyboard_listener_leave, 1155 | keyboard_listener_key, 1156 | keyboard_listener_modifiers 1157 | }; 1158 | 1159 | static void seat_listener_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability capabilities) 1160 | { 1161 | struct swfw_context_wl *swfw_ctx_wl = data; 1162 | if (capabilities & WL_SEAT_CAPABILITY_POINTER) { 1163 | swfw_ctx_wl->pointer = wl_seat_get_pointer(seat); 1164 | wl_pointer_add_listener(swfw_ctx_wl->pointer, &pointer_listener, swfw_ctx_wl); 1165 | } 1166 | if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { 1167 | swfw_ctx_wl->keyboard = wl_seat_get_keyboard(seat); 1168 | wl_keyboard_add_listener(swfw_ctx_wl->keyboard, &keyboard_listener, swfw_ctx_wl); 1169 | } 1170 | } 1171 | 1172 | static void shm_listener_format(void *data, struct wl_shm *wl_shm, uint32_t format) 1173 | { 1174 | struct swfw_context_wl *swfw_ctx_wl = data; 1175 | if (format == WL_SHM_FORMAT_XRGB8888) { 1176 | swfw_ctx_wl->has_xrgb = true; 1177 | } 1178 | } 1179 | 1180 | static void output_listener_geometry(void *data, struct wl_output *output, 1181 | int32_t x, int32_t y, int32_t width, int32_t height, int32_t subpixel, const char *make, const char *model, int32_t transform) 1182 | { 1183 | } 1184 | 1185 | static void output_listener_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) 1186 | { 1187 | } 1188 | 1189 | static void output_listener_done(void *data, struct wl_output *wl_output) 1190 | { 1191 | } 1192 | 1193 | static void output_listener_scale(void *data, struct wl_output *wl_output, int32_t factor) 1194 | { 1195 | } 1196 | 1197 | static struct wl_seat_listener seat_listener = { 1198 | seat_listener_capabilities 1199 | }; 1200 | 1201 | struct wl_shm_listener shm_listener = { 1202 | shm_listener_format 1203 | }; 1204 | 1205 | struct wl_output_listener output_listener = { 1206 | output_listener_geometry, 1207 | output_listener_mode, 1208 | output_listener_done, 1209 | output_listener_scale 1210 | }; 1211 | 1212 | static void registry_listener_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) 1213 | { 1214 | struct wl_output *output = NULL; 1215 | struct swfw_context_wl *swfw_ctx_wl = data; 1216 | if (!strcmp(interface, "wl_compositor")) { 1217 | swfw_ctx_wl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); 1218 | } else if (!strcmp(interface, "wl_shell")) { 1219 | swfw_ctx_wl->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); 1220 | } else if (!strcmp(interface, "wl_seat")) { 1221 | swfw_ctx_wl->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); 1222 | wl_seat_add_listener(swfw_ctx_wl->seat, &seat_listener, swfw_ctx_wl); 1223 | } else if (!strcmp(interface, "wl_shm")) { 1224 | swfw_ctx_wl->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); 1225 | wl_shm_add_listener(swfw_ctx_wl->shm, &shm_listener, swfw_ctx_wl); 1226 | } else if (!strcmp(interface, "wl_output")) { 1227 | output = wl_registry_bind(registry, name, &wl_output_interface, 1); 1228 | wl_output_add_listener(output, &output_listener, swfw_ctx_wl); 1229 | } 1230 | } 1231 | 1232 | static void registry_listener_global_remove(void *data, struct wl_registry *registry, uint32_t id) 1233 | { 1234 | } 1235 | 1236 | static const struct wl_registry_listener registry_listener = { 1237 | registry_listener_global, 1238 | registry_listener_global_remove 1239 | }; 1240 | 1241 | enum swfw_status swfw_make_context_wl(struct swfw_context_wl *swfw_ctx_wl) 1242 | { 1243 | enum swfw_status status = SWFW_OK; 1244 | struct wl_registry *registry = NULL; 1245 | swfw_ctx_wl->display = wl_display_connect(NULL); 1246 | if (!swfw_ctx_wl->display) { 1247 | status = SWFW_ERROR; 1248 | goto done; 1249 | } 1250 | registry = wl_display_get_registry(swfw_ctx_wl->display); 1251 | wl_registry_add_listener(registry, ®istry_listener, swfw_ctx_wl); 1252 | wl_display_dispatch(swfw_ctx_wl->display); 1253 | wl_display_roundtrip(swfw_ctx_wl->display); 1254 | if (!swfw_ctx_wl->compositor || !swfw_ctx_wl->shell || !swfw_ctx_wl->seat || !swfw_ctx_wl->shm) { 1255 | status = SWFW_ERROR; 1256 | } 1257 | done: 1258 | return status; 1259 | } 1260 | #endif /* SWFW_WAYLAND */ 1261 | 1262 | /* SWFW API */ 1263 | 1264 | /* Window */ 1265 | enum swfw_status swfw_drag_window(struct swfw_window *swfw_win) 1266 | { 1267 | enum swfw_status status = SWFW_INVALID_BACKEND; 1268 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1269 | #ifdef SWFW_X11 1270 | status = swfw_drag_window_x11(&swfw_win->swfw_win_x11); 1271 | #endif 1272 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1273 | #ifdef SWFW_WAYLAND 1274 | status = swfw_drag_window_wl(&swfw_win->swfw_win_wl); 1275 | #endif 1276 | } 1277 | return status; 1278 | } 1279 | 1280 | enum swfw_status swfw_resize_window(struct swfw_window *swfw_win, enum swfw_window_border window_border) 1281 | { 1282 | enum swfw_status status = SWFW_INVALID_BACKEND; 1283 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1284 | #ifdef SWFW_X11 1285 | status = swfw_resize_window_x11(&swfw_win->swfw_win_x11, window_border); 1286 | #endif 1287 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1288 | #ifdef SWFW_WAYLAND 1289 | status = swfw_resize_window_wl(&swfw_win->swfw_win_wl, window_border); 1290 | #endif 1291 | } 1292 | return status; 1293 | } 1294 | 1295 | enum swfw_status swfw_hide_window(struct swfw_window *swfw_win) 1296 | { 1297 | enum swfw_status status = SWFW_INVALID_BACKEND; 1298 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1299 | #ifdef SWFW_X11 1300 | status = swfw_hide_window_x11(&swfw_win->swfw_win_x11); 1301 | #endif 1302 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1303 | #ifdef SWFW_WAYLAND 1304 | status = swfw_hide_window_wl(&swfw_win->swfw_win_wl); 1305 | #endif 1306 | } 1307 | return status; 1308 | } 1309 | 1310 | enum swfw_status swfw_show_window(struct swfw_window *swfw_win) 1311 | { 1312 | enum swfw_status status = SWFW_INVALID_BACKEND; 1313 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1314 | #ifdef SWFW_X11 1315 | status = swfw_show_window_x11(&swfw_win->swfw_win_x11); 1316 | #endif 1317 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1318 | #ifdef SWFW_WAYLAND 1319 | status = swfw_show_window_wl(&swfw_win->swfw_win_wl); 1320 | #endif 1321 | } 1322 | return status; 1323 | } 1324 | 1325 | enum swfw_status swfw_get_window_work_area(struct swfw_window *swfw_win, int32_t *x, int32_t *y, int32_t *width, int32_t *height) 1326 | { 1327 | enum swfw_status status = SWFW_INVALID_BACKEND; 1328 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1329 | #ifdef SWFW_X11 1330 | status = swfw_get_window_work_area_x11(&swfw_win->swfw_win_x11, x, y, width, height); 1331 | #endif 1332 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1333 | #ifdef SWFW_WAYLAND 1334 | status = swfw_get_window_work_area_wl(&swfw_win->swfw_win_wl, x, y, width, height); 1335 | #endif 1336 | } 1337 | return status; 1338 | } 1339 | 1340 | enum swfw_status swfw_set_window_position(struct swfw_window *swfw_win, int32_t x, int32_t y) 1341 | { 1342 | enum swfw_status status = SWFW_INVALID_BACKEND; 1343 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1344 | #ifdef SWFW_X11 1345 | status = swfw_set_window_position_x11(&swfw_win->swfw_win_x11, x, y); 1346 | #endif 1347 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1348 | #ifdef SWFW_WAYLAND 1349 | status = swfw_set_window_position_wl(&swfw_win->swfw_win_wl, x, y); 1350 | #endif 1351 | } 1352 | return status; 1353 | } 1354 | 1355 | enum swfw_status swfw_set_window_size(struct swfw_window *swfw_win, int32_t width, int32_t height) 1356 | { 1357 | enum swfw_status status = SWFW_INVALID_BACKEND; 1358 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1359 | #ifdef SWFW_X11 1360 | status = swfw_set_window_size_x11(&swfw_win->swfw_win_x11, width, height); 1361 | #endif 1362 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1363 | #ifdef SWFW_WAYLAND 1364 | status = swfw_set_window_size_wl(&swfw_win->swfw_win_wl, width, height); 1365 | #endif 1366 | } 1367 | return status; 1368 | } 1369 | 1370 | enum swfw_status swfw_set_window_size_limits(struct swfw_window *swfw_win, int32_t min_width, int32_t min_height, int32_t max_width, int32_t max_height) 1371 | { 1372 | enum swfw_status status = SWFW_INVALID_BACKEND; 1373 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1374 | #ifdef SWFW_X11 1375 | status = swfw_set_window_size_limits_x11(&swfw_win->swfw_win_x11, min_width, min_height, max_width, max_height); 1376 | #endif 1377 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1378 | #ifdef SWFW_WAYLAND 1379 | status = swfw_set_window_size_limits_wl(&swfw_win->swfw_win_wl, min_width, min_height, max_width, max_height); 1380 | #endif 1381 | } 1382 | return status; 1383 | } 1384 | 1385 | enum swfw_status swfw_set_window_resizable(struct swfw_window *swfw_win, bool resizable) 1386 | { 1387 | enum swfw_status status = SWFW_INVALID_BACKEND; 1388 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1389 | #ifdef SWFW_X11 1390 | status = swfw_set_window_resizable_x11(&swfw_win->swfw_win_x11, resizable); 1391 | #endif 1392 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1393 | #ifdef SWFW_WAYLAND 1394 | status = swfw_set_window_resizable_wl(&swfw_win->swfw_win_wl, resizable); 1395 | #endif 1396 | } 1397 | return status; 1398 | } 1399 | 1400 | enum swfw_status swfw_set_window_decorated(struct swfw_window *swfw_win, bool decorated) 1401 | { 1402 | enum swfw_status status = SWFW_INVALID_BACKEND; 1403 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1404 | #ifdef SWFW_X11 1405 | status = swfw_set_window_decorated_x11(&swfw_win->swfw_win_x11, decorated); 1406 | #endif 1407 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1408 | #ifdef SWFW_WAYLAND 1409 | status = swfw_set_window_decorated_wl(&swfw_win->swfw_win_wl, decorated); 1410 | #endif 1411 | } 1412 | return status; 1413 | } 1414 | 1415 | enum swfw_status swfw_set_window_title(struct swfw_window *swfw_win, char *title) 1416 | { 1417 | enum swfw_status status = SWFW_INVALID_BACKEND; 1418 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1419 | #ifdef SWFW_X11 1420 | status = swfw_set_window_title_x11(&swfw_win->swfw_win_x11, title); 1421 | #endif 1422 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1423 | #ifdef SWFW_WAYLAND 1424 | status = swfw_set_window_title_wl(&swfw_win->swfw_win_wl, title); 1425 | #endif 1426 | } 1427 | return status; 1428 | } 1429 | 1430 | enum swfw_status swfw_window_swap_interval(struct swfw_window *swfw_win, int32_t interval) 1431 | { 1432 | enum swfw_status status = SWFW_INVALID_BACKEND; 1433 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1434 | #ifdef SWFW_X11 1435 | status = swfw_window_swap_interval_x11(&swfw_win->swfw_win_x11, interval); 1436 | #endif 1437 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1438 | #ifdef SWFW_WAYLAND 1439 | status = swfw_window_swap_interval_wl(&swfw_win->swfw_win_wl, interval); 1440 | #endif 1441 | } 1442 | return status; 1443 | } 1444 | 1445 | enum swfw_status swfw_window_swap_buffers(struct swfw_window *swfw_win) 1446 | { 1447 | enum swfw_status status = SWFW_INVALID_BACKEND; 1448 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1449 | #ifdef SWFW_X11 1450 | status = swfw_window_swap_buffers_x11(&swfw_win->swfw_win_x11); 1451 | #endif 1452 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1453 | #ifdef SWFW_WAYLAND 1454 | status = swfw_window_swap_buffers_wl(&swfw_win->swfw_win_wl); 1455 | #endif 1456 | } 1457 | return status; 1458 | 1459 | } 1460 | 1461 | enum swfw_status swfw_destroy_window(struct swfw_window *swfw_win) 1462 | { 1463 | enum swfw_status status = SWFW_INVALID_BACKEND; 1464 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1465 | #ifdef SWFW_X11 1466 | status = swfw_destroy_window_x11(&swfw_win->swfw_win_x11); 1467 | #endif 1468 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1469 | #ifdef SWFW_WAYLAND 1470 | status = swfw_destroy_window_wl(&swfw_win->swfw_win_wl); 1471 | #endif 1472 | } 1473 | return status; 1474 | } 1475 | 1476 | enum swfw_status swfw_make_window(struct swfw_context *swfw_ctx, struct swfw_window *swfw_win) 1477 | { 1478 | enum swfw_status status = SWFW_INVALID_BACKEND; 1479 | swfw_win->swfw_ctx = swfw_ctx; 1480 | if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_X11) { 1481 | #ifdef SWFW_X11 1482 | status = swfw_make_window_x11(&swfw_ctx->swfw_ctx_x11, &swfw_win->swfw_win_x11, swfw_ctx->hints); 1483 | #endif 1484 | } else if (swfw_win->swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1485 | #ifdef SWFW_WAYLAND 1486 | status = swfw_make_window_wl(&swfw_ctx->swfw_ctx_wl, &swfw_win->swfw_win_wl, swfw_ctx->hints); 1487 | #endif 1488 | } 1489 | return status; 1490 | } 1491 | 1492 | /* Context */ 1493 | enum swfw_status swfw_hint_window_size(struct swfw_context *swfw_ctx, int32_t width, int32_t height) 1494 | { 1495 | swfw_ctx->hints.width = width; 1496 | swfw_ctx->hints.height = height; 1497 | return SWFW_OK; 1498 | } 1499 | 1500 | enum swfw_status swfw_hint_gl_version(struct swfw_context *swfw_ctx, int32_t major, int32_t minor) 1501 | { 1502 | swfw_ctx->hints.gl.major = major; 1503 | swfw_ctx->hints.gl.minor = minor; 1504 | return SWFW_OK; 1505 | } 1506 | 1507 | enum swfw_status swfw_hint_use_hardware_acceleration(struct swfw_context *swfw_ctx, bool use_hardware_acceleration) 1508 | { 1509 | swfw_ctx->hints.use_hardware_acceleration = use_hardware_acceleration; 1510 | return SWFW_OK; 1511 | } 1512 | 1513 | enum swfw_status swfw_get_screen_size(struct swfw_context *swfw_ctx, int32_t i, int32_t *width, int32_t *height) 1514 | { 1515 | enum swfw_status status = SWFW_INVALID_BACKEND; 1516 | if (swfw_ctx->backend == SWFW_BACKEND_X11) { 1517 | #ifdef SWFW_X11 1518 | status = swfw_get_screen_size_x11(&swfw_ctx->swfw_ctx_x11, i, width, height); 1519 | #endif 1520 | } else if (swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1521 | #ifdef SWFW_WAYLAND 1522 | status = swfw_get_screen_size_wl(&swfw_ctx->swfw_ctx_wl, i, width, height); 1523 | #endif 1524 | } 1525 | return status; 1526 | } 1527 | 1528 | enum swfw_status swfw_get_screens(struct swfw_context *swfw_ctx, int32_t *i) 1529 | { 1530 | enum swfw_status status = SWFW_INVALID_BACKEND; 1531 | if (swfw_ctx->backend == SWFW_BACKEND_X11) { 1532 | #ifdef SWFW_X11 1533 | status = swfw_get_screens_x11(&swfw_ctx->swfw_ctx_x11, i); 1534 | #endif 1535 | } else if (swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1536 | #ifdef SWFW_WAYLAND 1537 | status = swfw_get_screens_wl(&swfw_ctx->swfw_ctx_wl, i); 1538 | #endif 1539 | } 1540 | return status; 1541 | } 1542 | 1543 | bool swfw_poll_event(struct swfw_context *swfw_ctx, struct swfw_event *event) 1544 | { 1545 | bool has_event = false; 1546 | if (swfw_ctx->backend == SWFW_BACKEND_X11) { 1547 | #ifdef SWFW_X11 1548 | has_event = swfw_poll_event_x11(&swfw_ctx->swfw_ctx_x11, event); 1549 | #endif 1550 | } else if (swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1551 | #ifdef SWFW_WAYLAND 1552 | has_event = swfw_poll_event_wl(&swfw_ctx->swfw_ctx_wl, event); 1553 | #endif 1554 | } 1555 | return has_event; 1556 | } 1557 | 1558 | enum swfw_status swfw_destroy_context(struct swfw_context *swfw_ctx) 1559 | { 1560 | enum swfw_status status = SWFW_INVALID_BACKEND; 1561 | if (swfw_ctx->backend == SWFW_BACKEND_X11) { 1562 | #ifdef SWFW_X11 1563 | status = swfw_destroy_context_x11(&swfw_ctx->swfw_ctx_x11); 1564 | #endif 1565 | } else if (swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1566 | #ifdef SWFW_WAYLAND 1567 | status = swfw_destroy_context_wl(&swfw_ctx->swfw_ctx_wl); 1568 | #endif 1569 | } 1570 | return status; 1571 | } 1572 | 1573 | enum swfw_status swfw_make_context(struct swfw_context *swfw_ctx, enum swfw_backend backend) 1574 | { 1575 | enum swfw_status status = SWFW_INVALID_BACKEND; 1576 | swfw_ctx->backend = backend; 1577 | if (swfw_ctx->backend == SWFW_BACKEND_X11) { 1578 | #ifdef SWFW_X11 1579 | status = swfw_make_context_x11(&swfw_ctx->swfw_ctx_x11); 1580 | #endif 1581 | } else if (swfw_ctx->backend == SWFW_BACKEND_WAYLAND) { 1582 | #ifdef SWFW_WAYLAND 1583 | status = swfw_make_context_wl(&swfw_ctx->swfw_ctx_wl); 1584 | #endif 1585 | } else if (swfw_ctx->backend == SWFW_BACKEND_AUTOMATIC) { 1586 | #if defined(SWFW_X11) && !defined(SWFW_WAYLAND) 1587 | swfw_ctx->backend = SWFW_BACKEND_X11; 1588 | status = swfw_make_context_x11(&swfw_ctx->swfw_ctx_x11); 1589 | #endif 1590 | #if !defined(SWFW_X11) && defined(SWFW_WAYLAND) 1591 | swfw_ctx->backend = SWFW_BACKEND_WAYLAND; 1592 | status = swfw_make_context_wl(&swfw_ctx->swfw_ctx_wl); 1593 | #endif 1594 | #if defined(SWFW_X11) && defined(SWFW_WAYLAND) 1595 | swfw_ctx->backend = SWFW_BACKEND_X11; 1596 | status = swfw_make_context_x11(&swfw_ctx->swfw_ctx_x11); 1597 | #endif 1598 | } 1599 | swfw_ctx->hints.x = 0; 1600 | swfw_ctx->hints.y = 0; 1601 | swfw_ctx->hints.width = DEFAULT_HINT_SIZE_WIDTH; 1602 | swfw_ctx->hints.height = DEFAULT_HINT_SIZE_HEIGHT; 1603 | swfw_ctx->hints.use_hardware_acceleration = DEFAULT_HINT_USE_HARDWARE_ACCELERATION; 1604 | return status; 1605 | } 1606 | -------------------------------------------------------------------------------- /src/swfw.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Felipe Ferreira da Silva 3 | 4 | This software is provided 'as-is', without any express or implied warranty. In 5 | no event will the authors be held liable for any damages arising from the use of 6 | this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including 9 | commercial applications, and to alter it and redistribute it freely, subject to 10 | the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not claim 13 | that you wrote the original software. If you use this software in a 14 | product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | */ 20 | 21 | #ifndef SWFW_H 22 | #define SWFW_H 23 | 24 | #include 25 | #include 26 | 27 | /* Compile by default with support for X11 on Linux and BSD */ 28 | #if (defined(__linux__) || defined(__bsdi__)) && !defined(SWFW_X11) && !defined(SWFW_WAYLAND) 29 | #define SWFW_X11 30 | #endif 31 | #ifdef SWFW_X11 32 | #include 33 | #include 34 | #include 35 | #include 36 | #ifndef SWFW_NO_HARDWARE_ACCELERATION 37 | #define SWFW_EGL 38 | #endif 39 | #ifdef SWFW_EGL 40 | #include 41 | #include 42 | #endif 43 | #endif 44 | #ifdef SWFW_WAYLAND 45 | #include 46 | #include 47 | #ifndef SWFW_NO_HARDWARE_ACCELERATION 48 | #define SWFW_EGL 49 | #endif 50 | #ifdef SWFW_EGL 51 | #include 52 | #include 53 | #include 54 | #endif 55 | #endif 56 | 57 | enum swfw_status { 58 | SWFW_OK, 59 | SWFW_ERROR, 60 | SWFW_INVALID_BACKEND, 61 | SWFW_UNSUPPORTED 62 | }; 63 | 64 | enum swfw_backend { 65 | SWFW_BACKEND_AUTOMATIC, 66 | SWFW_BACKEND_X11, 67 | SWFW_BACKEND_WAYLAND, 68 | SWFW_BACKEND_WIN32, 69 | SWFW_BACKEND_COCOA, 70 | SWFW_BACKEND_WEB 71 | }; 72 | 73 | enum swfw_window_border { 74 | SWFW_WINDOW_BORDER_LEFT, 75 | SWFW_WINDOW_BORDER_TOP, 76 | SWFW_WINDOW_BORDER_RIGHT, 77 | SWFW_WINDOW_BORDER_BOTTOM, 78 | SWFW_WINDOW_BORDER_TOP_LEFT, 79 | SWFW_WINDOW_BORDER_TOP_RIGHT, 80 | SWFW_WINDOW_BORDER_BOTTOM_LEFT, 81 | SWFW_WINDOW_BORDER_BOTTOM_RIGHT 82 | }; 83 | 84 | struct swfw_gl_hints { 85 | int32_t major; 86 | int32_t minor; 87 | }; 88 | 89 | struct swfw_hints { 90 | int32_t x; 91 | int32_t y; 92 | int32_t width; 93 | int32_t height; 94 | bool use_hardware_acceleration; 95 | struct swfw_gl_hints gl; 96 | }; 97 | 98 | enum swfw_event_type { 99 | SWFW_EVENT_NONE, 100 | SWFW_EVENT_CONFIGURE, 101 | SWFW_EVENT_MAP, 102 | SWFW_EVENT_UNMAP, 103 | SWFW_EVENT_CLOSE, 104 | SWFW_EVENT_MAXIMIZE, 105 | SWFW_EVENT_ICONIFY, 106 | SWFW_EVENT_RESTORE, 107 | SWFW_EVENT_KEY_PRESS, 108 | SWFW_EVENT_KEY_RELEASE, 109 | SWFW_EVENT_CURSOR_ENTER, 110 | SWFW_EVENT_CURSOR_LEAVE, 111 | SWFW_EVENT_CURSOR_MOTION, 112 | SWFW_EVENT_BUTTON_PRESS, 113 | SWFW_EVENT_BUTTON_RELEASE, 114 | SWFW_EVENT_SCROLL, 115 | SWFW_EVENT_EXPOSE, 116 | SWFW_EVENT_DESTROY 117 | }; 118 | 119 | struct swfw_event { 120 | enum swfw_event_type type; 121 | uint32_t key_code; 122 | uint32_t key_sym; 123 | char string[5]; 124 | int32_t string_length; 125 | double x; 126 | double y; 127 | uint32_t button; 128 | uint32_t axis; 129 | double scroll; 130 | }; 131 | 132 | #ifdef SWFW_EGL 133 | struct swfw_context_egl { 134 | EGLint major; 135 | EGLint minor; 136 | EGLDisplay display; 137 | EGLContext context; 138 | EGLConfig config; 139 | EGLSurface surface; 140 | }; 141 | #endif 142 | 143 | #ifdef SWFW_X11 144 | struct swfw_context_x11 { 145 | Display *display; 146 | Visual *visual; 147 | Screen *screen; 148 | int32_t depth; 149 | XIM im; 150 | XIMStyles *styles; 151 | XIMStyle xim_requested_style; 152 | Window root; 153 | XSetWindowAttributes attributes; 154 | Colormap colormap; 155 | unsigned long mask; 156 | XContext context; 157 | Atom atom_WM_PROTOCOLS; 158 | Atom atom_WM_STATE; 159 | Atom atom_WM_DELETE_WINDOW; 160 | Atom atom_NET_WM_NAME; 161 | Atom atom_NET_WM_ICON_NAME; 162 | Atom atom_NET_WM_ICON; 163 | Atom atom_NET_WM_PID; 164 | Atom atom_NET_WM_PING; 165 | Atom atom_NET_WM_WINDOW_TYPE; 166 | Atom atom_NET_WM_WINDOW_TYPE_NORMAL; 167 | Atom atom_NET_WM_STATE; 168 | Atom atom_NET_WM_STATE_ABOVE; 169 | Atom atom_NET_WM_STATE_FULLSCREEN; 170 | Atom atom_NET_WM_STATE_MAXIMIZED_VERT; 171 | Atom atom_NET_WM_STATE_MAXIMIZED_HORZ; 172 | Atom atom_NET_WM_STATE_DEMANDS_ATTENTION; 173 | Atom atom_NET_WM_BYPASS_COMPOSITOR; 174 | Atom atom_NET_WM_FULLSCREEN_MONITORS; 175 | Atom atom_NET_WM_MOVERESIZE; 176 | Atom atom_MOTIF_WM_HINTS; 177 | Atom atom_NET_ACTIVE_WINDOW; 178 | Atom atom_NET_FRAME_EXTENTS; 179 | Atom atom_NET_REQUEST_FRAME_EXTENTS; 180 | Atom atom_NET_WORKAREA; 181 | }; 182 | 183 | struct swfw_window_x11 { 184 | Window window; 185 | XIC ic; 186 | struct swfw_context_x11 *swfw_ctx_x11; 187 | bool use_hardware_acceleration; 188 | #ifdef SWFW_EGL 189 | struct swfw_context_egl swfw_ctx_egl; 190 | #endif 191 | }; 192 | #endif 193 | 194 | #ifdef SWFW_WAYLAND 195 | struct swfw_context_wl { 196 | struct wl_display *display; 197 | struct wl_compositor *compositor; 198 | struct wl_shell *shell; 199 | struct wl_seat *seat; 200 | struct wl_pointer *pointer; 201 | struct wl_keyboard *keyboard; 202 | struct wl_shm *shm; 203 | bool has_xrgb; 204 | uint32_t pointer_serial; 205 | struct swfw_event event; 206 | }; 207 | 208 | struct swfw_window_wl { 209 | struct wl_surface *surface; 210 | struct wl_shell_surface *shell_surface; 211 | struct swfw_context_wl *swfw_ctx_wl; 212 | struct wl_buffer *buffer; 213 | uint32_t *shm_data; 214 | int32_t fd; 215 | struct wl_shm_pool *shm_pool; 216 | int32_t width; 217 | int32_t height; 218 | bool use_hardware_acceleration; 219 | #ifdef SWFW_EGL 220 | struct wl_egl_window *egl_window; 221 | struct swfw_context_egl swfw_ctx_egl; 222 | #endif 223 | }; 224 | #endif 225 | 226 | /* SWFW */ 227 | struct swfw_context { 228 | #ifdef SWFW_X11 229 | struct swfw_context_x11 swfw_ctx_x11; 230 | #endif 231 | #ifdef SWFW_WAYLAND 232 | struct swfw_context_wl swfw_ctx_wl; 233 | #endif 234 | enum swfw_backend backend; 235 | struct swfw_hints hints; 236 | }; 237 | 238 | struct swfw_window { 239 | #ifdef SWFW_X11 240 | struct swfw_window_x11 swfw_win_x11; 241 | #endif 242 | #ifdef SWFW_WAYLAND 243 | struct swfw_window_wl swfw_win_wl; 244 | #endif 245 | struct swfw_context *swfw_ctx; 246 | }; 247 | 248 | /* Window */ 249 | enum swfw_status swfw_drag_window(struct swfw_window *swfw_win); 250 | enum swfw_status swfw_resize_window(struct swfw_window *swfw_win, enum swfw_window_border window_border); 251 | enum swfw_status swfw_hide_window(struct swfw_window *swfw_win); 252 | enum swfw_status swfw_show_window(struct swfw_window *swfw_win); 253 | enum swfw_status swfw_get_window_work_area(struct swfw_window *swfw_win, int32_t *x, int32_t *y, int32_t *width, int32_t *height); 254 | enum swfw_status swfw_set_window_position(struct swfw_window *swfw_win, int32_t x, int32_t y); 255 | enum swfw_status swfw_set_window_size(struct swfw_window *swfw_win, int32_t width, int32_t height); 256 | enum swfw_status swfw_set_window_size_limits(struct swfw_window *swfw_win, int32_t min_width, int32_t min_height, int32_t max_width, int32_t max_height); 257 | enum swfw_status swfw_set_window_resizable(struct swfw_window *swfw_win, bool resizable); 258 | enum swfw_status swfw_set_window_decorated(struct swfw_window *swfw_win, bool decorated); 259 | enum swfw_status swfw_set_window_title(struct swfw_window *swfw_win, char *title); 260 | enum swfw_status swfw_window_swap_interval(struct swfw_window *swfw_win, int32_t interval); 261 | enum swfw_status swfw_window_swap_buffers(struct swfw_window *swfw_win); 262 | enum swfw_status swfw_destroy_window(struct swfw_window *swfw_win); 263 | enum swfw_status swfw_make_window(struct swfw_context *swfw_ctx, struct swfw_window *swfw_win); 264 | 265 | /* Context */ 266 | enum swfw_status swfw_hint_window_size(struct swfw_context *swfw_ctx, int32_t width, int32_t height); 267 | enum swfw_status swfw_hint_gl_version(struct swfw_context *swfw_ctx, int32_t major, int32_t minor); 268 | enum swfw_status swfw_hint_use_hardware_acceleration(struct swfw_context *swfw_ctx, bool use_hardware_acceleration); 269 | enum swfw_status swfw_get_screen_size(struct swfw_context *swfw_ctx, int32_t i, int32_t *width, int32_t *height); 270 | enum swfw_status swfw_get_screens(struct swfw_context *swfw_ctx, int32_t *i); 271 | bool swfw_poll_event(struct swfw_context *swfw_ctx, struct swfw_event *event); 272 | enum swfw_status swfw_destroy_context(struct swfw_context *swfw_ctx); 273 | enum swfw_status swfw_make_context(struct swfw_context *swfw_ctx, enum swfw_backend backend); 274 | 275 | #endif 276 | --------------------------------------------------------------------------------