Dirty Wayland backend implementation.

This commit is contained in:
Sergio L. Pascual 2016-02-16 23:30:32 +01:00 committed by Ivan Vučica
parent ecfa661d7a
commit 81456203b2
13 changed files with 2772 additions and 7 deletions

View file

@ -0,0 +1,16 @@
/*
Copyright (C) 2016 Sergio L. Pascual <slp@sinrega.org>
*/
#ifndef WaylandCairoSurface_h
#define WaylandCairoSurface_h
#include "cairo/CairoSurface.h"
@interface WaylandCairoSurface : CairoSurface
{
}
@end
#endif

View file

@ -0,0 +1,118 @@
/* <title>WaylandServer</title>
<abstract>Backend server using Wayland.</abstract>
Copyright (C) 2016 Sergio L. Pascual <slp@sinrega.org>
*/
#ifndef _WaylandServer_h_INCLUDE
#define _WaylandServer_h_INCLUDE
#include "config.h"
#include <GNUstepGUI/GSDisplayServer.h>
#include <wayland-client.h>
#include <cairo/cairo.h>
#include <xkbcommon/xkbcommon.h>
#include "cairo/WaylandCairoSurface.h"
#include "wayland/xdg-shell-unstable-v5-client-protocol.h"
struct pointer {
struct wl_pointer *wlpointer;
float x;
float y;
uint32_t last_click_button;
uint32_t last_click_time;
float last_click_x;
float last_click_y;
uint32_t serial;
struct window *focus;
};
typedef struct _WaylandConfig {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shell *shell;
struct xdg_shell *xdg_shell;
struct wl_shm *shm;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
struct wl_buffer *buffer;
struct wl_list output_list;
int output_count;
struct wl_list window_list;
int window_count;
int last_window_id;
struct pointer pointer;
struct xkb_context *xkb_context;
struct {
struct xkb_keymap *keymap;
struct xkb_state *state;
xkb_mod_mask_t control_mask;
xkb_mod_mask_t alt_mask;
xkb_mod_mask_t shift_mask;
} xkb;
int modifiers;
int seat_version;
} WaylandConfig;
struct output {
WaylandConfig *wlconfig;
struct wl_output *output;
uint32_t server_output_id;
struct wl_list link;
int alloc_x;
int alloc_y;
int width;
int height;
int transform;
int scale;
char *make;
char *model;
//display_output_handler_t destroy_handler;
void *user_data;
};
struct window {
WaylandConfig *wlconfig;
id instance;
int window_id;
struct wl_list link;
float pos_x;
float pos_y;
float width;
float height;
float saved_pos_x;
float saved_pos_y;
int is_out;
unsigned char *data;
struct wl_surface *surface;
struct wl_buffer *buffer;
struct wl_shell_surface *shell_surface;
struct xdg_surface *xdg_surface;
struct output *output;
WaylandCairoSurface *wcs;
};
cairo_surface_t *
create_shm_buffer(struct window *window);
@interface WaylandServer : GSDisplayServer
{
WaylandConfig *wlconfig;
}
@end
#endif /* _XGServer_h_INCLUDE */

View file

@ -0,0 +1,559 @@
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef XDG_SHELL_UNSTABLE_V5_CLIENT_PROTOCOL_H
#define XDG_SHELL_UNSTABLE_V5_CLIENT_PROTOCOL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
struct wl_client;
struct wl_resource;
struct wl_output;
struct wl_seat;
struct wl_surface;
struct xdg_popup;
struct xdg_shell;
struct xdg_surface;
extern const struct wl_interface xdg_shell_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_popup_interface;
#ifndef XDG_SHELL_VERSION_ENUM
#define XDG_SHELL_VERSION_ENUM
/**
* xdg_shell_version - latest protocol version
* @XDG_SHELL_VERSION_CURRENT: Always the latest version
*
* The 'current' member of this enum gives the version of the protocol.
* Implementations can compare this to the version they implement using
* static_assert to ensure the protocol and implementation versions match.
*/
enum xdg_shell_version {
XDG_SHELL_VERSION_CURRENT = 5,
};
#endif /* XDG_SHELL_VERSION_ENUM */
#ifndef XDG_SHELL_ERROR_ENUM
#define XDG_SHELL_ERROR_ENUM
enum xdg_shell_error {
XDG_SHELL_ERROR_ROLE = 0,
XDG_SHELL_ERROR_DEFUNCT_SURFACES = 1,
XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP = 2,
XDG_SHELL_ERROR_INVALID_POPUP_PARENT = 3,
};
#endif /* XDG_SHELL_ERROR_ENUM */
/**
* xdg_shell - create desktop-style surfaces
* @ping: check if the client is alive
*
* xdg_shell allows clients to turn a wl_surface into a "real window"
* which can be dragged, resized, stacked, and moved around by the user.
* Everything about this interface is suited towards traditional desktop
* environments.
*/
struct xdg_shell_listener {
/**
* ping - check if the client is alive
* @serial: pass this to the pong request
*
* The ping event asks the client if it's still alive. Pass the
* serial specified in the event back to the compositor by sending
* a "pong" request back with the specified serial.
*
* Compositors can use this to determine if the client is still
* alive. It's unspecified what will happen if the client doesn't
* respond to the ping request, or in what timeframe. Clients
* should try to respond in a reasonable amount of time.
*
* A compositor is free to ping in any way it wants, but a client
* must always respond to any xdg_shell object it created.
*/
void (*ping)(void *data,
struct xdg_shell *xdg_shell,
uint32_t serial);
};
static inline int
xdg_shell_add_listener(struct xdg_shell *xdg_shell,
const struct xdg_shell_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) xdg_shell,
(void (**)(void)) listener, data);
}
#define XDG_SHELL_DESTROY 0
#define XDG_SHELL_USE_UNSTABLE_VERSION 1
#define XDG_SHELL_GET_XDG_SURFACE 2
#define XDG_SHELL_GET_XDG_SURFACE_SPECIAL 3
#define XDG_SHELL_GET_XDG_POPUP 4
#define XDG_SHELL_PONG 5
static inline void
xdg_shell_set_user_data(struct xdg_shell *xdg_shell, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) xdg_shell, user_data);
}
static inline void *
xdg_shell_get_user_data(struct xdg_shell *xdg_shell)
{
return wl_proxy_get_user_data((struct wl_proxy *) xdg_shell);
}
static inline void
xdg_shell_destroy(struct xdg_shell *xdg_shell)
{
wl_proxy_marshal((struct wl_proxy *) xdg_shell,
XDG_SHELL_DESTROY);
wl_proxy_destroy((struct wl_proxy *) xdg_shell);
}
static inline void
xdg_shell_use_unstable_version(struct xdg_shell *xdg_shell, int32_t version)
{
wl_proxy_marshal((struct wl_proxy *) xdg_shell,
XDG_SHELL_USE_UNSTABLE_VERSION, version);
}
static inline struct xdg_surface *
xdg_shell_get_xdg_surface(struct xdg_shell *xdg_shell, struct wl_surface *surface)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell,
XDG_SHELL_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface);
return (struct xdg_surface *) id;
}
static inline struct xdg_surface *
xdg_shell_get_xdg_surface_special(struct xdg_shell *xdg_shell, struct wl_surface *surface, uint32_t type)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell,
XDG_SHELL_GET_XDG_SURFACE_SPECIAL, &xdg_surface_interface, NULL, surface, type);
return (struct xdg_surface *) id;
}
static inline struct xdg_popup *
xdg_shell_get_xdg_popup(struct xdg_shell *xdg_shell, struct wl_surface *surface, struct wl_surface *parent, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell,
XDG_SHELL_GET_XDG_POPUP, &xdg_popup_interface, NULL, surface, parent, seat, serial, x, y);
return (struct xdg_popup *) id;
}
static inline void
xdg_shell_pong(struct xdg_shell *xdg_shell, uint32_t serial)
{
wl_proxy_marshal((struct wl_proxy *) xdg_shell,
XDG_SHELL_PONG, serial);
}
#ifndef XDG_SURFACE_RESIZE_EDGE_ENUM
#define XDG_SURFACE_RESIZE_EDGE_ENUM
/**
* xdg_surface_resize_edge - edge values for resizing
* @XDG_SURFACE_RESIZE_EDGE_NONE: (none)
* @XDG_SURFACE_RESIZE_EDGE_TOP: (none)
* @XDG_SURFACE_RESIZE_EDGE_BOTTOM: (none)
* @XDG_SURFACE_RESIZE_EDGE_LEFT: (none)
* @XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: (none)
* @XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: (none)
* @XDG_SURFACE_RESIZE_EDGE_RIGHT: (none)
* @XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: (none)
* @XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: (none)
*
* These values are used to indicate which edge of a surface is being
* dragged in a resize operation.
*/
enum xdg_surface_resize_edge {
XDG_SURFACE_RESIZE_EDGE_NONE = 0,
XDG_SURFACE_RESIZE_EDGE_TOP = 1,
XDG_SURFACE_RESIZE_EDGE_BOTTOM = 2,
XDG_SURFACE_RESIZE_EDGE_LEFT = 4,
XDG_SURFACE_RESIZE_EDGE_TOP_LEFT = 5,
XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT = 6,
XDG_SURFACE_RESIZE_EDGE_RIGHT = 8,
XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT = 9,
XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT = 10,
};
#endif /* XDG_SURFACE_RESIZE_EDGE_ENUM */
#ifndef XDG_SURFACE_STATE_ENUM
#define XDG_SURFACE_STATE_ENUM
/**
* xdg_surface_state - the surface is now activated
* @XDG_SURFACE_STATE_MAXIMIZED: the surface is maximized
* @XDG_SURFACE_STATE_FULLSCREEN: the surface is fullscreen
* @XDG_SURFACE_STATE_RESIZING: the surface is being resized
* @XDG_SURFACE_STATE_ACTIVATED: the surface is now activated
*
* Client window decorations should be painted as if the window is
* active. Do not assume this means that the window actually has keyboard
* or pointer focus.
*/
enum xdg_surface_state {
XDG_SURFACE_STATE_MAXIMIZED = 1,
XDG_SURFACE_STATE_FULLSCREEN = 2,
XDG_SURFACE_STATE_RESIZING = 3,
XDG_SURFACE_STATE_ACTIVATED = 4,
};
#endif /* XDG_SURFACE_STATE_ENUM */
/**
* xdg_surface - A desktop window
* @configure: suggest a surface change
* @close: surface wants to be closed
*
* An interface that may be implemented by a wl_surface, for
* implementations that provide a desktop-style user interface.
*
* It provides requests to treat surfaces like windows, allowing to set
* properties like maximized, fullscreen, minimized, and to move and resize
* them, and associate metadata like title and app id.
*
* The client must call wl_surface.commit on the corresponding wl_surface
* for the xdg_surface state to take effect. Prior to committing the new
* state, it can set up initial configuration, such as maximizing or
* setting a window geometry.
*
* Even without attaching a buffer the compositor must respond to initial
* committed configuration, for instance sending a configure event with
* expected window geometry if the client maximized its surface during
* initialization.
*
* For a surface to be mapped by the compositor the client must have
* committed both an xdg_surface state and a buffer.
*/
struct xdg_surface_listener {
/**
* configure - suggest a surface change
* @x: (none)
* @y: (none)
* @width: (none)
* @height: (none)
* @states: (none)
* @serial: (none)
*
* The configure event asks the client to resize its surface or
* to change its state.
*
* The width and height arguments specify a hint to the window
* about how its surface should be resized in window geometry
* coordinates. See set_window_geometry.
*
* If the width or height arguments are zero, it means the client
* should decide its own window dimension. This may happen when the
* compositor need to configure the state of the surface but
* doesn't have any information about any previous or expected
* dimension.
*
* The states listed in the event specify how the width/height
* arguments should be interpreted, and possibly how it should be
* drawn.
*
* Clients should arrange their surface for the new size and
* states, and then send a ack_configure request with the serial
* sent in this configure event at some point before committing the
* new surface.
*
* If the client receives multiple configure events before it can
* respond to one, it is free to discard all but the last event it
* received.
*/
void (*configure)(void *data,
struct xdg_surface *xdg_surface,
int32_t x,
int32_t y,
int32_t width,
int32_t height,
struct wl_array *states,
uint32_t serial);
/**
* close - surface wants to be closed
*
* The close event is sent by the compositor when the user wants
* the surface to be closed. This should be equivalent to the user
* clicking the close button in client-side decorations, if your
* application has any...
*
* This is only a request that the user intends to close your
* window. The client may choose to ignore this request, or show a
* dialog to ask the user to save their data...
*/
void (*close)(void *data,
struct xdg_surface *xdg_surface);
};
static inline int
xdg_surface_add_listener(struct xdg_surface *xdg_surface,
const struct xdg_surface_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
(void (**)(void)) listener, data);
}
#define XDG_SURFACE_DESTROY 0
#define XDG_SURFACE_SET_PARENT 1
#define XDG_SURFACE_SET_TITLE 2
#define XDG_SURFACE_SET_APP_ID 3
#define XDG_SURFACE_SHOW_WINDOW_MENU 4
#define XDG_SURFACE_MOVE 5
#define XDG_SURFACE_RESIZE 6
#define XDG_SURFACE_ACK_CONFIGURE 7
#define XDG_SURFACE_SET_WINDOW_GEOMETRY 8
#define XDG_SURFACE_SET_MAXIMIZED 9
#define XDG_SURFACE_UNSET_MAXIMIZED 10
#define XDG_SURFACE_SET_FULLSCREEN 11
#define XDG_SURFACE_UNSET_FULLSCREEN 12
#define XDG_SURFACE_SET_MINIMIZED 13
static inline void
xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
}
static inline void *
xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
{
return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
}
static inline void
xdg_surface_destroy(struct xdg_surface *xdg_surface)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_DESTROY);
wl_proxy_destroy((struct wl_proxy *) xdg_surface);
}
static inline void
xdg_surface_set_parent(struct xdg_surface *xdg_surface, struct xdg_surface *parent)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_PARENT, parent);
}
static inline void
xdg_surface_set_title(struct xdg_surface *xdg_surface, const char *title)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_TITLE, title);
}
static inline void
xdg_surface_set_app_id(struct xdg_surface *xdg_surface, const char *app_id)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_APP_ID, app_id);
}
static inline void
xdg_surface_show_window_menu(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SHOW_WINDOW_MENU, seat, serial, x, y);
}
static inline void
xdg_surface_move(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_MOVE, seat, serial);
}
static inline void
xdg_surface_resize(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_RESIZE, seat, serial, edges);
}
static inline void
xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_ACK_CONFIGURE, serial);
}
static inline void
xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height);
}
static inline void
xdg_surface_set_maximized(struct xdg_surface *xdg_surface)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_MAXIMIZED);
}
static inline void
xdg_surface_unset_maximized(struct xdg_surface *xdg_surface)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_UNSET_MAXIMIZED);
}
static inline void
xdg_surface_set_fullscreen(struct xdg_surface *xdg_surface, struct wl_output *output)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_FULLSCREEN, output);
}
static inline void
xdg_surface_unset_fullscreen(struct xdg_surface *xdg_surface)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_UNSET_FULLSCREEN);
}
static inline void
xdg_surface_set_minimized(struct xdg_surface *xdg_surface)
{
wl_proxy_marshal((struct wl_proxy *) xdg_surface,
XDG_SURFACE_SET_MINIMIZED);
}
/**
* xdg_popup - short-lived, popup surfaces for menus
* @popup_done: popup interaction is done
*
* A popup surface is a short-lived, temporary surface that can be used
* to implement menus. It takes an explicit grab on the surface that will
* be dismissed when the user dismisses the popup. This can be done by the
* user clicking outside the surface, using the keyboard, or even locking
* the screen through closing the lid or a timeout.
*
* When the popup is dismissed, a popup_done event will be sent out, and at
* the same time the surface will be unmapped. The xdg_popup object is now
* inert and cannot be reactivated, so clients should destroy it.
* Explicitly destroying the xdg_popup object will also dismiss the popup
* and unmap the surface.
*
* Clients will receive events for all their surfaces during this grab
* (which is an "owner-events" grab in X11 parlance). This is done so that
* users can navigate through submenus and other "nested" popup windows
* without having to dismiss the topmost popup.
*
* Clients that want to dismiss the popup when another surface of their own
* is clicked should dismiss the popup using the destroy request.
*
* The parent surface must have either an xdg_surface or xdg_popup role.
*
* Specifying an xdg_popup for the parent means that the popups are nested,
* with this popup now being the topmost popup. Nested popups must be
* destroyed in the reverse order they were created in, e.g. the only popup
* you are allowed to destroy at all times is the topmost one.
*
* If there is an existing popup when creating a new popup, the parent must
* be the current topmost popup.
*
* A parent surface must be mapped before the new popup is mapped.
*
* When compositors choose to dismiss a popup, they will likely dismiss
* every nested popup as well. When a compositor dismisses popups, it will
* follow the same dismissing order as required from the client.
*
* The x and y arguments passed when creating the popup object specify
* where the top left of the popup should be placed, relative to the local
* surface coordinates of the parent surface. See xdg_shell.get_xdg_popup.
*
* The client must call wl_surface.commit on the corresponding wl_surface
* for the xdg_popup state to take effect.
*
* For a surface to be mapped by the compositor the client must have
* committed both the xdg_popup state and a buffer.
*/
struct xdg_popup_listener {
/**
* popup_done - popup interaction is done
*
* The popup_done event is sent out when a popup is dismissed by
* the compositor. The client should destroy the xdg_popup object
* at this point.
*/
void (*popup_done)(void *data,
struct xdg_popup *xdg_popup);
};
static inline int
xdg_popup_add_listener(struct xdg_popup *xdg_popup,
const struct xdg_popup_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
(void (**)(void)) listener, data);
}
#define XDG_POPUP_DESTROY 0
static inline void
xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
}
static inline void *
xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
{
return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
}
static inline void
xdg_popup_destroy(struct xdg_popup *xdg_popup)
{
wl_proxy_marshal((struct wl_proxy *) xdg_popup,
XDG_POPUP_DESTROY);
wl_proxy_destroy((struct wl_proxy *) xdg_popup);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -45,6 +45,11 @@
@interface WIN32Server (Initialize)
+ (void) initializeBackend;
@end
#elif BUILD_SERVER == SERVER_wayland
#include <wayland/WaylandServer.h>
@interface WaylandServer (Initialize)
+ (void) initializeBackend;
@end
#endif
/* Call the correct initalization routines for the choosen
@ -63,6 +68,8 @@
[XGServer initializeBackend];
#elif BUILD_SERVER == SERVER_win32
[WIN32Server initializeBackend];
#elif BUILD_SERVER == SERVER_wayland
[WaylandServer initializeBackend];
#else
[NSException raise: NSInternalInconsistencyException
format: @"No Window Server configured in backend"];

View file

@ -70,6 +70,12 @@
# define _CAIRO_SURFACE_CLASSNAME Win32CairoSurface
# include "cairo/Win32CairoSurface.h"
# endif /* USE_GLITZ */
#elif BUILD_SERVER == SERVER_wayland
# include "wayland/WaylandServer.h"
# define _CAIRO_GSTATE_CLASSNAME CairoGState
# include "cairo/CairoGState.h"
# define _CAIRO_SURFACE_CLASSNAME WaylandCairoSurface
# include "cairo/WaylandCairoSurface.h"
#else
# error Invalid server for Cairo backend : non implemented
#endif /* BUILD_SERVER */

View file

@ -49,12 +49,16 @@ ifeq ($(BUILD_SERVER),x11)
cairo_OBJC_FILES += XGCairoSurface.m XGCairoXImageSurface.m XGCairoModernSurface.m
endif
else
ifeq ($(BUILD_GRAPHICS),cairo)
ifeq ($(WITH_GLITZ),yes)
cairo_OBJC_FILES += Win32CairoGlitzSurface.m
else
cairo_OBJC_FILES += Win32CairoSurface.m Win32CairoGState.m
# Win32CairoXImageSurface.m
ifeq ($(BUILD_SERVER),wayland)
cairo_OBJC_FILES += WaylandCairoSurface.m
else
ifeq ($(BUILD_GRAPHICS),cairo)
ifeq ($(WITH_GLITZ),yes)
cairo_OBJC_FILES += Win32CairoGlitzSurface.m
else
cairo_OBJC_FILES += Win32CairoSurface.m Win32CairoGState.m
# Win32CairoXImageSurface.m
endif
endif
endif
endif

View file

@ -0,0 +1,262 @@
/*
Copyright (C) 2016 Sergio L. Pascual <slp@sinrega.org>
*/
#include "wayland/WaylandServer.h"
#include "cairo/WaylandCairoSurface.h"
#include <cairo/cairo.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define GSWINDEVICE ((struct window *)gsDevice)
int
os_fd_set_cloexec(int fd)
{
long flags;
if (fd == -1)
return -1;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
return -1;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
return -1;
return 0;
}
static int
set_cloexec_or_close(int fd)
{
if (os_fd_set_cloexec(fd) != 0) {
close(fd);
return -1;
}
return fd;
}
static int
create_tmpfile_cloexec(char *tmpname)
{
int fd;
fd = mkstemp(tmpname);
if (fd >= 0) {
fd = set_cloexec_or_close(fd);
unlink(tmpname);
}
return fd;
}
int
os_create_anonymous_file(off_t size)
{
static const char template[] = "/weston-shared-XXXXXX";
const char *path;
char *name;
int fd;
int ret;
path = getenv("XDG_RUNTIME_DIR");
if (!path) {
errno = ENOENT;
return -1;
}
name = malloc(strlen(path) + sizeof(template));
if (!name)
return -1;
strcpy(name, path);
strcat(name, template);
fd = create_tmpfile_cloexec(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;
}
cairo_surface_t *
create_shm_buffer(struct window *window)
{
struct wl_shm_pool *pool;
cairo_surface_t *surface;
int fd, size, stride;
stride = window->width * 4;
size = stride * window->height;
fd = os_create_anonymous_file(size);
if (fd < 0) {
NSLog(@"creating a buffer file for surface failed");
return NULL;
}
window->data =
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (window->data == MAP_FAILED) {
NSLog(@"error mapping anonymous file");
close(fd);
return NULL;
}
pool = wl_shm_create_pool(window->wlconfig->shm, fd, size);
surface = cairo_image_surface_create_for_data(window->data,
CAIRO_FORMAT_ARGB32,
window->width,
window->height,
stride);
window->buffer =
wl_shm_pool_create_buffer(pool, 0,
window->width, window->height, stride,
WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
close(fd);
return surface;
}
@implementation WaylandCairoSurface
- (id) initWithDevice: (void*)device
{
struct window *window = (struct window *) device;
NSDebugLog(@"WaylandCairoSurface: initWithDevice win=%d", window->window_id);
gsDevice = device;
//_surface = window->main_surface->cairo_surface;
_surface = create_shm_buffer(window);
if (_surface == NULL) {
NSDebugLog(@"can't create cairo surface");
return 0;
}
wl_surface_attach(window->surface, window->buffer, 0, 0);
window->wcs = self;
return self;
}
- (void) dealloc
{
struct window *window = (struct window*) gsDevice;
NSDebugLog(@"WaylandCairoSurface: dealloc win=%d", window->window_id);
[super dealloc];
}
- (NSSize) size
{
NSDebugLog(@"WaylandCairoSurface: size");
struct window *window = (struct window*) gsDevice;
return NSMakeSize(window->width, window->height);
}
- (void) setSurface: (cairo_surface_t*)surface
{
NSDebugLog(@"WaylandCairoSurface: setSurface");
_surface = surface;
}
- (void) handleExposeRect: (NSRect)rect
{
NSDebugLog(@"handleExposeRect");
struct window *window = (struct window*) gsDevice;
struct wl_surface *wlsurface = window->surface;
cairo_surface_t *cairo_surface;
double backupOffsetX = 0;
double backupOffsetY = 0;
int x = NSMinX(rect);
int y = NSMinY(rect);
int width = NSWidth(rect);
int height = NSHeight(rect);
NSDebugLog(@"updating region: %dx%d %dx%d", x, y, width, height);
if (cairo_surface_status(_surface) != CAIRO_STATUS_SUCCESS)
{
NSWarnMLog(@"cairo initial window error status: %s\n",
cairo_status_to_string(cairo_surface_status(_surface)));
}
/*
cairo_surface = create_shm_buffer(window);
if (cairo_surface == NULL) {
NSDebugLog(@"can't create cairo surface");
return;
}
*/
cairo_surface = _surface;
cairo_surface_get_device_offset(cairo_surface, &backupOffsetX, &backupOffsetY);
cairo_surface_set_device_offset(cairo_surface, 0, 0);
cairo_t *cr = cairo_create(cairo_surface);
if (width != window->width && 0) {
NSDebugLog(@"fake drawing");
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(cr, 0, 0, width, height);
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
cairo_fill(cr);
cairo_rectangle(cr, 10, 10, width - 20, height - 20);
cairo_set_source_rgba(cr, 1.0, 0, 0, 1);
cairo_fill(cr);
cairo_select_font_face(cr, "sans",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 12);
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_move_to(cr, 30, 30);
cairo_show_text(cr, "Hello, world!");
} else {
NSDebugLog(@"real drawing");
cairo_rectangle(cr, x, y, width, height);
cairo_clip(cr);
cairo_set_source_surface(cr, cairo_surface, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
}
cairo_destroy(cr);
cairo_surface_set_device_offset(_surface, backupOffsetX, backupOffsetY);
wl_surface_attach(wlsurface, window->buffer, 0, 0);
wl_surface_damage(wlsurface, 0, 0, window->width, window->height);
wl_surface_commit(wlsurface);
wl_display_dispatch_pending(window->wlconfig->display);
wl_display_flush(window->wlconfig->display);
NSDebugLog(@"handleExposeRect exit");
}
@end

View file

@ -0,0 +1,50 @@
#
# Main makefile for GNUstep Backend win32
#
# Copyright (C) 2002 Free Software Foundation, Inc.
#
# Author: Adam Fedor <fedor@gnu.org>
#
# This file is part of the GNUstep Backend.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; see the file COPYING.LIB.
# If not, see <http://www.gnu.org/licenses/> or write to the
# Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
PACKAGE_NAME = gnustep-back
GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../back.make
include $(GNUSTEP_MAKEFILES)/common.make
include ../../config.make
# The library to be compiled, as a library or as a bundle
SUBPROJECT_NAME=wayland
wayland_LOCALIZED_RESOURCE_FILES = \
# The C source files to be compiled
wayland_C_FILES = \
xdg-shell-unstable-v5-protocol.c \
# The Objective-C source files to be compiled
wayland_OBJC_FILES = \
WaylandServer.m \
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/subproject.make
-include GNUmakefile.postamble

View file

@ -0,0 +1,51 @@
# GNUmakefile.preamble
#
# Copyright (C) 2002 Free Software Foundation, Inc.
#
# Author: Adam Fedor <fedor@gnu.org>
#
# This file is part of the GNUstep Backend.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; see the file COPYING.LIB.
# If not, see <http://www.gnu.org/licenses/> or write to the
# Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# Flags dealing with compiling and linking
#
# Additional flags to pass to the preprocessor
ADDITIONAL_CPPFLAGS += -Wall $(CONFIG_SYSTEM_DEFS)
# Additional flags to pass to the Objective-C compiler
ADDITIONAL_OBJCFLAGS =
# Additional flags to pass to the C compiler
ADDITIONAL_CFLAGS =
# Additional include directories the compiler should search
ADDITIONAL_INCLUDE_DIRS += -I../../Headers \
-I../$(GNUSTEP_TARGET_DIR) $(GRAPHIC_CFLAGS)
# Additional LDFLAGS to pass to the linker
ADDITIONAL_LDFLAGS =
# Additional library directories the linker should search
ADDITIONAL_LIB_DIRS =
#
# Flags dealing with installing and uninstalling
#

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_surface_interface;
static const struct wl_interface *types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_surface_interface,
&wl_surface_interface,
NULL,
&xdg_popup_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&xdg_surface_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
};
static const struct wl_message xdg_shell_requests[] = {
{ "destroy", "", types + 0 },
{ "use_unstable_version", "i", types + 0 },
{ "get_xdg_surface", "no", types + 6 },
{ "get_xdg_surface_special", "nou", types + 8 },
{ "get_xdg_popup", "nooouii", types + 11 },
{ "pong", "u", types + 0 },
};
static const struct wl_message xdg_shell_events[] = {
{ "ping", "u", types + 0 },
};
WL_EXPORT const struct wl_interface xdg_shell_interface = {
"xdg_shell", 1,
6, xdg_shell_requests,
1, xdg_shell_events,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", types + 0 },
{ "set_parent", "?o", types + 18 },
{ "set_title", "s", types + 0 },
{ "set_app_id", "s", types + 0 },
{ "show_window_menu", "ouii", types + 19 },
{ "move", "ou", types + 23 },
{ "resize", "ouu", types + 25 },
{ "ack_configure", "u", types + 0 },
{ "set_window_geometry", "iiii", types + 0 },
{ "set_maximized", "", types + 0 },
{ "unset_maximized", "", types + 0 },
{ "set_fullscreen", "?o", types + 28 },
{ "unset_fullscreen", "", types + 0 },
{ "set_minimized", "", types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "iiiiau", types + 0 },
{ "close", "", types + 0 },
};
WL_EXPORT const struct wl_interface xdg_surface_interface = {
"xdg_surface", 1,
14, xdg_surface_requests,
2, xdg_surface_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", types + 0 },
};
static const struct wl_message xdg_popup_events[] = {
{ "popup_done", "", types + 0 },
};
WL_EXPORT const struct wl_interface xdg_popup_interface = {
"xdg_popup", 1,
1, xdg_popup_requests,
1, xdg_popup_events,
};

View file

@ -3,6 +3,7 @@
#define SERVER_x11 1
#define SERVER_win32 2
#define SERVER_wayland 3
#define GRAPHICS_xdps 0
#define GRAPHICS_art 1
#define GRAPHICS_xlib 2

View file

@ -565,7 +565,7 @@ case $target_os in
esac
AC_ARG_ENABLE(server,
[ --enable-server=SRV Build server type: x11, win32],,
[ --enable-server=SRV Build server type: x11, win32, wayland],,
enable_server=$BUILD_SERVER)
AC_ARG_ENABLE(graphics,
[ --enable-graphics=GPH Build graphics: xlib, xdps, winlib, art, cairo, opal],,
@ -584,6 +584,8 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then
AC_MSG_WARN([can't find freetype, required for graphics=cairo])
if test $BUILD_SERVER = win32; then
BUILD_GRAPHICS=winlib
elif test $BUILD_SERVER = wayland; then
AC_MSG_ERROR([wayland backend requires cairo])
else
BUILD_GRAPHICS=xlib
fi
@ -592,6 +594,8 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then
AC_MSG_WARN([can't find cairo, required for graphics=cairo!])
if test $BUILD_SERVER = win32; then
BUILD_GRAPHICS=winlib
elif test $BUILD_SERVER = wayland; then
AC_MSG_ERROR([wayland backend requires cairo])
else
BUILD_GRAPHICS=art
fi
@ -642,6 +646,9 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then
CAIRO_LIBS="$CAIRO_LIBS $CAIRO_XLIB_LIBS $XFT_LIBS"
CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_XLIB_CFLAGS"
AC_MSG_RESULT(xlib)
elif test $BUILD_SERVER = wayland; then
CAIRO_LIBS="$CAIRO_LIBS $XFT_LIBS"
CAIRO_CFLAGS="$CAIRO_CFLAGS"
else
AC_MSG_ERROR([Invalid Cairo installation])
fi
@ -743,6 +750,7 @@ fi
AH_TOP([
#define SERVER_x11 1
#define SERVER_win32 2
#define SERVER_wayland 3
#define GRAPHICS_xdps 0
#define GRAPHICS_art 1
#define GRAPHICS_xlib 2