mirror of
https://github.com/glfw/glfw.git
synced 2024-11-30 05:47:10 +00:00
Implement window decorations
This commit is contained in:
parent
9dc18a62a6
commit
9f7ec6b094
152
src/wl_init.c
152
src/wl_init.c
@ -42,6 +42,39 @@ static inline int min(int n1, int n2)
|
|||||||
return n1 < n2 ? n1 : n2;
|
return n1 < n2 ? n1 : n2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which)
|
||||||
|
{
|
||||||
|
int focus;
|
||||||
|
_GLFWwindow* window = _glfw.windowListHead;
|
||||||
|
if (!which)
|
||||||
|
which = &focus;
|
||||||
|
while (window)
|
||||||
|
{
|
||||||
|
if (surface == window->wl.decorations.top.surface)
|
||||||
|
{
|
||||||
|
*which = topDecoration;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (surface == window->wl.decorations.left.surface)
|
||||||
|
{
|
||||||
|
*which = leftDecoration;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (surface == window->wl.decorations.right.surface)
|
||||||
|
{
|
||||||
|
*which = rightDecoration;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (surface == window->wl.decorations.bottom.surface)
|
||||||
|
{
|
||||||
|
*which = bottomDecoration;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
window = window->next;
|
||||||
|
}
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
static void pointerHandleEnter(void* data,
|
static void pointerHandleEnter(void* data,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer,
|
||||||
uint32_t serial,
|
uint32_t serial,
|
||||||
@ -53,10 +86,16 @@ static void pointerHandleEnter(void* data,
|
|||||||
if (!surface)
|
if (!surface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
int focus = 0;
|
||||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
window = findWindowFromDecorationSurface(surface, &focus);
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->wl.decorations.focus = focus;
|
||||||
_glfw.wl.pointerSerial = serial;
|
_glfw.wl.pointerSerial = serial;
|
||||||
_glfw.wl.pointerFocus = window;
|
_glfw.wl.pointerFocus = window;
|
||||||
|
|
||||||
@ -83,6 +122,39 @@ static void pointerHandleLeave(void* data,
|
|||||||
_glfwInputCursorEnter(window, GLFW_FALSE);
|
_glfwInputCursorEnter(window, GLFW_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setCursor(const char* name)
|
||||||
|
{
|
||||||
|
struct wl_buffer* buffer;
|
||||||
|
struct wl_cursor* cursor;
|
||||||
|
struct wl_cursor_image* image;
|
||||||
|
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||||
|
|
||||||
|
cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
|
||||||
|
name);
|
||||||
|
if (!cursor)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Standard cursor not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
image = cursor->images[0];
|
||||||
|
|
||||||
|
if (!image)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer = wl_cursor_image_get_buffer(image);
|
||||||
|
if (!buffer)
|
||||||
|
return;
|
||||||
|
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||||
|
surface,
|
||||||
|
image->hotspot_x,
|
||||||
|
image->hotspot_y);
|
||||||
|
wl_surface_attach(surface, buffer, 0, 0);
|
||||||
|
wl_surface_damage(surface, 0, 0,
|
||||||
|
image->width, image->height);
|
||||||
|
wl_surface_commit(surface);
|
||||||
|
}
|
||||||
|
|
||||||
static void pointerHandleMotion(void* data,
|
static void pointerHandleMotion(void* data,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer,
|
||||||
uint32_t time,
|
uint32_t time,
|
||||||
@ -90,6 +162,7 @@ static void pointerHandleMotion(void* data,
|
|||||||
wl_fixed_t sy)
|
wl_fixed_t sy)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
|
const char* cursorName;
|
||||||
|
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
@ -102,9 +175,43 @@ static void pointerHandleMotion(void* data,
|
|||||||
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (window->wl.decorations.focus)
|
||||||
|
{
|
||||||
|
case mainWindow:
|
||||||
_glfwInputCursorPos(window,
|
_glfwInputCursorPos(window,
|
||||||
wl_fixed_to_double(sx),
|
wl_fixed_to_double(sx),
|
||||||
wl_fixed_to_double(sy));
|
wl_fixed_to_double(sy));
|
||||||
|
return;
|
||||||
|
case topDecoration:
|
||||||
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
|
cursorName = "n-resize";
|
||||||
|
else
|
||||||
|
cursorName = "left_ptr";
|
||||||
|
break;
|
||||||
|
case leftDecoration:
|
||||||
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
|
cursorName = "nw-resize";
|
||||||
|
else
|
||||||
|
cursorName = "w-resize";
|
||||||
|
break;
|
||||||
|
case rightDecoration:
|
||||||
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
|
cursorName = "ne-resize";
|
||||||
|
else
|
||||||
|
cursorName = "e-resize";
|
||||||
|
break;
|
||||||
|
case bottomDecoration:
|
||||||
|
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
|
||||||
|
cursorName = "sw-resize";
|
||||||
|
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
|
||||||
|
cursorName = "se-resize";
|
||||||
|
else
|
||||||
|
cursorName = "s-resize";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
setCursor(cursorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleButton(void* data,
|
static void pointerHandleButton(void* data,
|
||||||
@ -119,6 +226,47 @@ static void pointerHandleButton(void* data,
|
|||||||
|
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
switch (window->wl.decorations.focus)
|
||||||
|
{
|
||||||
|
case mainWindow:
|
||||||
|
break;
|
||||||
|
case topDecoration:
|
||||||
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_TOP);
|
||||||
|
else
|
||||||
|
wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial);
|
||||||
|
return;
|
||||||
|
case leftDecoration:
|
||||||
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_TOP_LEFT);
|
||||||
|
else
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_LEFT);
|
||||||
|
return;
|
||||||
|
case rightDecoration:
|
||||||
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_TOP_RIGHT);
|
||||||
|
else
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_RIGHT);
|
||||||
|
return;
|
||||||
|
case bottomDecoration:
|
||||||
|
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT);
|
||||||
|
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT);
|
||||||
|
else
|
||||||
|
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
|
||||||
|
serial, WL_SHELL_SURFACE_RESIZE_BOTTOM);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
_glfw.wl.pointerSerial = serial;
|
_glfw.wl.pointerSerial = serial;
|
||||||
|
|
||||||
@ -282,8 +430,12 @@ static void keyboardHandleEnter(void* data,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
window = findWindowFromDecorationSurface(surface, NULL);
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_glfw.wl.keyboardFocus = window;
|
_glfw.wl.keyboardFocus = window;
|
||||||
_glfwInputWindowFocus(window, GLFW_TRUE);
|
_glfwInputWindowFocus(window, GLFW_TRUE);
|
||||||
|
@ -141,6 +141,26 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st
|
|||||||
#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym
|
#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define _GLFW_DECORATION_WIDTH 4
|
||||||
|
#define _GLFW_DECORATION_TOP 24
|
||||||
|
|
||||||
|
typedef enum _GLFWdecorationSideWayland
|
||||||
|
{
|
||||||
|
mainWindow,
|
||||||
|
topDecoration,
|
||||||
|
leftDecoration,
|
||||||
|
rightDecoration,
|
||||||
|
bottomDecoration,
|
||||||
|
|
||||||
|
} _GLFWdecorationSideWayland;
|
||||||
|
|
||||||
|
typedef struct _GLFWdecorationWayland
|
||||||
|
{
|
||||||
|
struct wl_surface* surface;
|
||||||
|
struct wl_subsurface* subsurface;
|
||||||
|
struct wp_viewport* viewport;
|
||||||
|
|
||||||
|
} _GLFWdecorationWayland;
|
||||||
|
|
||||||
// Wayland-specific per-window data
|
// Wayland-specific per-window data
|
||||||
//
|
//
|
||||||
@ -183,6 +203,12 @@ typedef struct _GLFWwindowWayland
|
|||||||
// This is a hack to prevent auto-iconification on creation.
|
// This is a hack to prevent auto-iconification on creation.
|
||||||
GLFWbool justCreated;
|
GLFWbool justCreated;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_buffer* buffer;
|
||||||
|
_GLFWdecorationWayland top, left, right, bottom;
|
||||||
|
int focus;
|
||||||
|
} decorations;
|
||||||
|
|
||||||
} _GLFWwindowWayland;
|
} _GLFWwindowWayland;
|
||||||
|
|
||||||
// Wayland-specific global data
|
// Wayland-specific global data
|
||||||
|
314
src/wl_window.c
314
src/wl_window.c
@ -95,6 +95,193 @@ static const struct wl_shell_surface_listener shellSurfaceListener = {
|
|||||||
handlePopupDone
|
handlePopupDone
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
createTmpfileCloexec(char* tmpname)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = mkostemp(tmpname, O_CLOEXEC);
|
||||||
|
if (fd >= 0)
|
||||||
|
unlink(tmpname);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new, unique, anonymous file of the given size, and
|
||||||
|
* return the file descriptor for it. The file descriptor is set
|
||||||
|
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
||||||
|
* the given size at offset zero.
|
||||||
|
*
|
||||||
|
* The file should not have a permanent backing store like a disk,
|
||||||
|
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
||||||
|
*
|
||||||
|
* The file name is deleted from the file system.
|
||||||
|
*
|
||||||
|
* The file is suitable for buffer sharing between processes by
|
||||||
|
* transmitting the file descriptor over Unix sockets using the
|
||||||
|
* SCM_RIGHTS methods.
|
||||||
|
*
|
||||||
|
* posix_fallocate() is used to guarantee that disk space is available
|
||||||
|
* for the file at the given size. If disk space is insufficent, errno
|
||||||
|
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
||||||
|
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
createAnonymousFile(off_t size)
|
||||||
|
{
|
||||||
|
static const char template[] = "/glfw-shared-XXXXXX";
|
||||||
|
const char* path;
|
||||||
|
char* name;
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
path = getenv("XDG_RUNTIME_DIR");
|
||||||
|
if (!path)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = calloc(strlen(path) + sizeof(template), 1);
|
||||||
|
strcpy(name, path);
|
||||||
|
strcat(name, template);
|
||||||
|
|
||||||
|
fd = createTmpfileCloexec(name);
|
||||||
|
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
ret = posix_fallocate(fd, 0, size);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
errno = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||||
|
{
|
||||||
|
struct wl_shm_pool* pool;
|
||||||
|
struct wl_buffer* buffer;
|
||||||
|
int stride = image->width * 4;
|
||||||
|
int length = image->width * image->height * 4;
|
||||||
|
void* data;
|
||||||
|
int fd, i;
|
||||||
|
|
||||||
|
fd = createAnonymousFile(length);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Creating a buffer file for %d B failed: %m",
|
||||||
|
length);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (data == MAP_FAILED)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: mmap failed: %m");
|
||||||
|
close(fd);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
unsigned char* source = (unsigned char*) image->pixels;
|
||||||
|
unsigned char* target = data;
|
||||||
|
for (i = 0; i < image->width * image->height; i++, source += 4)
|
||||||
|
{
|
||||||
|
unsigned int alpha = source[3];
|
||||||
|
|
||||||
|
*target++ = (unsigned char) ((source[2] * alpha) / 255);
|
||||||
|
*target++ = (unsigned char) ((source[1] * alpha) / 255);
|
||||||
|
*target++ = (unsigned char) ((source[0] * alpha) / 255);
|
||||||
|
*target++ = (unsigned char) alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer =
|
||||||
|
wl_shm_pool_create_buffer(pool, 0,
|
||||||
|
image->width,
|
||||||
|
image->height,
|
||||||
|
stride, WL_SHM_FORMAT_ARGB8888);
|
||||||
|
munmap(data, length);
|
||||||
|
wl_shm_pool_destroy(pool);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createDecoration(_GLFWdecorationWayland* decoration,
|
||||||
|
struct wl_surface* parent,
|
||||||
|
struct wl_buffer* buffer, int x, int y,
|
||||||
|
int width, int height)
|
||||||
|
{
|
||||||
|
decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);
|
||||||
|
decoration->subsurface =
|
||||||
|
wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
|
||||||
|
decoration->surface, parent);
|
||||||
|
wl_subsurface_set_position(decoration->subsurface, x, y);
|
||||||
|
decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,
|
||||||
|
decoration->surface);
|
||||||
|
wp_viewport_set_destination(decoration->viewport, width, height);
|
||||||
|
wl_surface_attach(decoration->surface, buffer, 0, 0);
|
||||||
|
wl_surface_commit(decoration->surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createDecorations(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
unsigned char data[] = { 224, 224, 224, 255 };
|
||||||
|
const GLFWimage image = { 1, 1, data };
|
||||||
|
|
||||||
|
struct wl_buffer* buffer = createShmBuffer(&image);
|
||||||
|
|
||||||
|
createDecoration(&window->wl.decorations.top, window->wl.surface, buffer,
|
||||||
|
0, -_GLFW_DECORATION_TOP,
|
||||||
|
window->wl.width, _GLFW_DECORATION_TOP);
|
||||||
|
createDecoration(&window->wl.decorations.left, window->wl.surface, buffer,
|
||||||
|
-_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP,
|
||||||
|
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||||
|
createDecoration(&window->wl.decorations.right, window->wl.surface, buffer,
|
||||||
|
window->wl.width, -_GLFW_DECORATION_TOP,
|
||||||
|
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||||
|
createDecoration(&window->wl.decorations.bottom, window->wl.surface, buffer,
|
||||||
|
-_GLFW_DECORATION_WIDTH, window->wl.height,
|
||||||
|
window->wl.width + 2 * _GLFW_DECORATION_WIDTH, _GLFW_DECORATION_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resizeWindow(_GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
wl_egl_window_resize(window->wl.native, width, height, 0, 0);
|
||||||
|
|
||||||
|
// Top decoration.
|
||||||
|
wp_viewport_set_destination(window->wl.decorations.top.viewport, width, _GLFW_DECORATION_TOP);
|
||||||
|
wl_surface_commit(window->wl.decorations.top.surface);
|
||||||
|
|
||||||
|
// Left decoration.
|
||||||
|
wp_viewport_set_destination(window->wl.decorations.left.viewport,
|
||||||
|
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||||
|
wl_surface_commit(window->wl.decorations.left.surface);
|
||||||
|
|
||||||
|
// Right decoration.
|
||||||
|
wl_subsurface_set_position(window->wl.decorations.right.subsurface,
|
||||||
|
window->wl.width, -_GLFW_DECORATION_TOP);
|
||||||
|
wp_viewport_set_destination(window->wl.decorations.right.viewport,
|
||||||
|
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||||
|
wl_surface_commit(window->wl.decorations.right.surface);
|
||||||
|
|
||||||
|
// Bottom decoration.
|
||||||
|
wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,
|
||||||
|
-_GLFW_DECORATION_WIDTH, window->wl.height);
|
||||||
|
wp_viewport_set_destination(window->wl.decorations.bottom.viewport,
|
||||||
|
width + 2 * _GLFW_DECORATION_WIDTH, _GLFW_DECORATION_WIDTH);
|
||||||
|
wl_surface_commit(window->wl.decorations.bottom.surface);
|
||||||
|
}
|
||||||
|
|
||||||
static void checkScaleChange(_GLFWwindow* window)
|
static void checkScaleChange(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
int scaledWidth, scaledHeight;
|
int scaledWidth, scaledHeight;
|
||||||
@ -121,7 +308,7 @@ static void checkScaleChange(_GLFWwindow* window)
|
|||||||
scaledWidth = window->wl.width * scale;
|
scaledWidth = window->wl.width * scale;
|
||||||
scaledHeight = window->wl.height * scale;
|
scaledHeight = window->wl.height * scale;
|
||||||
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
||||||
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
|
resizeWindow(window, scaledWidth, scaledHeight);
|
||||||
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
||||||
_glfwInputWindowContentScale(window, scale, scale);
|
_glfwInputWindowContentScale(window, scale, scale);
|
||||||
}
|
}
|
||||||
@ -232,6 +419,8 @@ static GLFWbool createSurface(_GLFWwindow* window,
|
|||||||
if (!window->wl.transparent)
|
if (!window->wl.transparent)
|
||||||
setOpaqueRegion(window);
|
setOpaqueRegion(window);
|
||||||
|
|
||||||
|
createDecorations(window);
|
||||||
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,18 +614,6 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
|
|||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
createTmpfileCloexec(char* tmpname)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = mkostemp(tmpname, O_CLOEXEC);
|
|
||||||
if (fd >= 0)
|
|
||||||
unlink(tmpname);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handleEvents(int timeout)
|
handleEvents(int timeout)
|
||||||
{
|
{
|
||||||
@ -496,115 +673,6 @@ handleEvents(int timeout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a new, unique, anonymous file of the given size, and
|
|
||||||
* return the file descriptor for it. The file descriptor is set
|
|
||||||
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
|
||||||
* the given size at offset zero.
|
|
||||||
*
|
|
||||||
* The file should not have a permanent backing store like a disk,
|
|
||||||
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
|
||||||
*
|
|
||||||
* The file name is deleted from the file system.
|
|
||||||
*
|
|
||||||
* The file is suitable for buffer sharing between processes by
|
|
||||||
* transmitting the file descriptor over Unix sockets using the
|
|
||||||
* SCM_RIGHTS methods.
|
|
||||||
*
|
|
||||||
* posix_fallocate() is used to guarantee that disk space is available
|
|
||||||
* for the file at the given size. If disk space is insufficent, errno
|
|
||||||
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
|
||||||
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
createAnonymousFile(off_t size)
|
|
||||||
{
|
|
||||||
static const char template[] = "/glfw-shared-XXXXXX";
|
|
||||||
const char* path;
|
|
||||||
char* name;
|
|
||||||
int fd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
path = getenv("XDG_RUNTIME_DIR");
|
|
||||||
if (!path)
|
|
||||||
{
|
|
||||||
errno = ENOENT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = calloc(strlen(path) + sizeof(template), 1);
|
|
||||||
strcpy(name, path);
|
|
||||||
strcat(name, template);
|
|
||||||
|
|
||||||
fd = createTmpfileCloexec(name);
|
|
||||||
|
|
||||||
free(name);
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
return -1;
|
|
||||||
ret = posix_fallocate(fd, 0, size);
|
|
||||||
if (ret != 0)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
errno = ret;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
|
||||||
{
|
|
||||||
struct wl_shm_pool* pool;
|
|
||||||
struct wl_buffer* buffer;
|
|
||||||
int stride = image->width * 4;
|
|
||||||
int length = image->width * image->height * 4;
|
|
||||||
void* data;
|
|
||||||
int fd, i;
|
|
||||||
|
|
||||||
fd = createAnonymousFile(length);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Wayland: Creating a buffer file for %d B failed: %m",
|
|
||||||
length);
|
|
||||||
return GLFW_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
||||||
if (data == MAP_FAILED)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
|
||||||
"Wayland: Cursor mmap failed: %m");
|
|
||||||
close(fd);
|
|
||||||
return GLFW_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
unsigned char* source = (unsigned char*) image->pixels;
|
|
||||||
unsigned char* target = data;
|
|
||||||
for (i = 0; i < image->width * image->height; i++, source += 4)
|
|
||||||
{
|
|
||||||
unsigned int alpha = source[3];
|
|
||||||
|
|
||||||
*target++ = (unsigned char) ((source[2] * alpha) / 255);
|
|
||||||
*target++ = (unsigned char) ((source[1] * alpha) / 255);
|
|
||||||
*target++ = (unsigned char) ((source[0] * alpha) / 255);
|
|
||||||
*target++ = (unsigned char) alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer =
|
|
||||||
wl_shm_pool_create_buffer(pool, 0,
|
|
||||||
image->width,
|
|
||||||
image->height,
|
|
||||||
stride, WL_SHM_FORMAT_ARGB8888);
|
|
||||||
munmap(data, length);
|
|
||||||
wl_shm_pool_destroy(pool);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translates a GLFW standard cursor to a theme cursor name
|
// Translates a GLFW standard cursor to a theme cursor name
|
||||||
//
|
//
|
||||||
static char *translateCursorShape(int shape)
|
static char *translateCursorShape(int shape)
|
||||||
@ -783,7 +851,7 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
|||||||
int scaledHeight = height * window->wl.scale;
|
int scaledHeight = height * window->wl.scale;
|
||||||
window->wl.width = width;
|
window->wl.width = width;
|
||||||
window->wl.height = height;
|
window->wl.height = height;
|
||||||
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
|
resizeWindow(window, scaledWidth, scaledHeight);
|
||||||
if (!window->wl.transparent)
|
if (!window->wl.transparent)
|
||||||
setOpaqueRegion(window);
|
setOpaqueRegion(window);
|
||||||
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
||||||
|
Loading…
Reference in New Issue
Block a user