diff --git a/CMakeLists.txt b/CMakeLists.txt index 7be65a03..0e61946b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,8 @@ project(sway C) set(CMAKE_C_FLAGS "-g") set(CMAKE_C_STANDARD 99) SET(CMAKE_C_EXTENSIONS OFF) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") +set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") add_definitions("-Wall -Wextra -Wno-unused-parameter -D_GNU_SOURCE") list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/CMake") @@ -38,21 +39,27 @@ find_package(XKBCommon REQUIRED) find_package(WLC REQUIRED) find_package(A2X REQUIRED) find_package(PCRE REQUIRED) +find_package(Wayland REQUIRED) find_package(JsonC REQUIRED) FILE(GLOB sources ${PROJECT_SOURCE_DIR}/sway/*.c) FILE(GLOB common ${PROJECT_SOURCE_DIR}/common/*.c) +include(Wayland) +WAYLAND_ADD_PROTOCOL_SERVER(proto-desktop-shell "${PROJECT_SOURCE_DIR}/protocols/desktop-shell.xml" desktop-shell) + include_directories( ${WLC_INCLUDE_DIRS} ${PCRE_INCLUDE_DIRS} ${JSONC_INCLUDE_DIRS} ${XKBCOMMON_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} ) add_executable(sway ${sources} ${common} + ${proto-desktop-shell} ) target_link_libraries(sway @@ -60,6 +67,7 @@ target_link_libraries(sway ${XKBCOMMON_LIBRARIES} ${PCRE_LIBRARIES} ${JSONC_LIBRARIES} + ${WAYLAND_SERVER_LIBRARIES} ) install( diff --git a/include/client/client.h b/include/client/client.h index b823235b..30ec25c0 100644 --- a/include/client/client.h +++ b/include/client/client.h @@ -2,6 +2,7 @@ #define _CLIENT_H #include +#include "wayland-desktop-shell-client-protocol.h" #include #include #include @@ -41,13 +42,14 @@ struct client_state { struct wl_surface *surface; struct wl_shell_surface *shell_surface; struct wl_callback *frame_cb; + struct desktop_shell *desktop_shell; struct cursor cursor; uint32_t width, height; cairo_t *cairo; list_t *outputs; }; -struct client_state *client_setup(uint32_t width, uint32_t height); +struct client_state *client_setup(uint32_t width, uint32_t height, bool shell_surface); void client_teardown(struct client_state *state); int client_prerender(struct client_state *state); int client_render(struct client_state *state); diff --git a/include/extensions.h b/include/extensions.h new file mode 100644 index 00000000..e122c59a --- /dev/null +++ b/include/extensions.h @@ -0,0 +1,6 @@ +#ifndef _SWAY_EXTENSIONS_H +#define _SWAY_EXTENSIONS_H + +void register_extensions(void); + +#endif diff --git a/protocols/desktop-shell.xml b/protocols/desktop-shell.xml new file mode 100644 index 00000000..dd81574a --- /dev/null +++ b/protocols/desktop-shell.xml @@ -0,0 +1,138 @@ + + + + + Traditional user interfaces can rely on this interface to define the + foundations of typical desktops. Currently it's possible to set up + background, panels and locking surfaces. + + + + + + + + + + + + + + + + + + + + + The surface set by this request will receive a fake + pointer.enter event during grabs at position 0, 0 and is + expected to set an appropriate cursor image as described by + the grab_cursor event sent just before the enter event. + + + + + + + + + + + + + + + Tell the client we want it to create and set the lock surface, which is + a GUI asking the user to unlock the screen. The lock surface is + announced with 'set_lock_surface'. Whether or not the client actually + implements locking, it MUST send 'unlock' request to let the normal + desktop resume. + + + + + + This event will be sent immediately before a fake enter event on the + grab surface. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tell the server, that enough desktop elements have been drawn + to make the desktop look ready for use. During start-up, the + server can wait for this request with a black screen before + starting to fade in the desktop, for instance. If the client + parts of a desktop take a long time to initialize, we avoid + showing temporary garbage. + + + + + + + + + + + + + + + + + + + + Tell the shell which side of the screen the panel is + located. This is so that new windows do not overlap the panel + and maximized windows maximize properly. + + + + + + + + Only one client can bind this interface at a time. + + + + + A screensaver surface is normally hidden, and only visible after an + idle timeout. + + + + + + + + diff --git a/sway/extensions.c b/sway/extensions.c new file mode 100644 index 00000000..a37ceaa8 --- /dev/null +++ b/sway/extensions.c @@ -0,0 +1,32 @@ +#include +#include +#include "wayland-desktop-shell-server-protocol.h" +#include "log.h" + +static void set_background(struct wl_client *client, struct wl_resource *resource, + struct wl_resource *output, struct wl_resource *surface) { + sway_log(L_DEBUG, "Surface requesting background for output"); +} + +static struct desktop_shell_interface desktop_shell_implementation = { + .set_background = set_background, +}; + +static void desktop_shell_bind(struct wl_client *client, void *data, + unsigned int version, unsigned int id) { + if (version > 1) { + // Unsupported version + return; + } + + struct wl_resource *resource = wl_resource_create(client, &desktop_shell_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + } + + wl_resource_set_implementation(resource, &desktop_shell_implementation, NULL, NULL); +} + +void register_extensions(void) { + wl_global_create(wlc_get_wl_display(), &desktop_shell_interface, 1, NULL, desktop_shell_bind); +} diff --git a/sway/main.c b/sway/main.c index 4afbccbd..ebb45930 100644 --- a/sway/main.c +++ b/sway/main.c @@ -7,6 +7,7 @@ #include #include #include +#include "extensions.h" #include "layout.h" #include "stringop.h" #include "config.h" @@ -73,6 +74,8 @@ int main(int argc, char **argv) { if (!wlc_init(&interface, argc, argv)) { return 1; } + + register_extensions(); char *config_path = NULL; diff --git a/swaybg/CMakeLists.txt b/swaybg/CMakeLists.txt index 7f0556df..d4de69de 100644 --- a/swaybg/CMakeLists.txt +++ b/swaybg/CMakeLists.txt @@ -7,6 +7,7 @@ find_package(Pango REQUIRED) include(Wayland) set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../bin/) WAYLAND_ADD_PROTOCOL_CLIENT(proto-xdg-shell "${PROJECT_SOURCE_DIR}/../protocols/xdg-shell.xml" xdg-shell) +WAYLAND_ADD_PROTOCOL_CLIENT(proto-desktop-shell "${PROJECT_SOURCE_DIR}/../protocols/desktop-shell.xml" desktop-shell) include_directories( ${WAYLAND_CLIENT_INCLUDE_DIR} @@ -24,6 +25,7 @@ add_executable(swaybg ${wl_sources} ${common} ${proto-xdg-shell} + ${proto-desktop-shell} ) TARGET_LINK_LIBRARIES(swaybg ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES} ${CAIRO_LIBRARIES} ${PANGO_LIBRARIES} m) diff --git a/swaybg/main.c b/swaybg/main.c index b4614ac0..8d95f60a 100644 --- a/swaybg/main.c +++ b/swaybg/main.c @@ -1,3 +1,4 @@ +#include "wayland-desktop-shell-client-protocol.h" #include #include #include @@ -14,12 +15,16 @@ void sway_terminate(void) { int main(int argc, char **argv) { init_log(L_INFO); - if (!(state = client_setup(100, 100))) { + if (!(state = client_setup(100, 100, false))) { return -1; } + if (!state->desktop_shell) { + sway_abort("swaybg requires the compositor to support the desktop-shell extension."); + } struct output_state *output = state->outputs->items[0]; state->width = output->width; state->height = output->height; + desktop_shell_set_background(state->desktop_shell, output->output, state->surface); uint8_t r = 0, g = 0, b = 0; diff --git a/wayland/client.c b/wayland/client.c index be93709b..ab8adc47 100644 --- a/wayland/client.c +++ b/wayland/client.c @@ -1,6 +1,7 @@ #include #include #include "wayland-xdg-shell-client-protocol.h" +#include "wayland-desktop-shell-client-protocol.h" #include #include #include @@ -96,6 +97,8 @@ static void registry_global(void *data, struct wl_registry *registry, ostate->output = output; wl_output_add_listener(output, &output_listener, ostate); list_add(state->outputs, ostate); + } else if (strcmp(interface, desktop_shell_interface.name) == 0) { + state->desktop_shell = wl_registry_bind(registry, name, &desktop_shell_interface, version); } } @@ -119,7 +122,7 @@ static const struct wl_shell_surface_listener surface_listener = { .configure = shell_surface_configure }; -struct client_state *client_setup(uint32_t width, uint32_t height) { +struct client_state *client_setup(uint32_t width, uint32_t height, bool shell_surface) { struct client_state *state = malloc(sizeof(struct client_state)); memset(state, 0, sizeof(struct client_state)); state->outputs = create_list(); @@ -140,9 +143,11 @@ struct client_state *client_setup(uint32_t width, uint32_t height) { wl_registry_destroy(registry); state->surface = wl_compositor_create_surface(state->compositor); - state->shell_surface = wl_shell_get_shell_surface(state->shell, state->surface); - wl_shell_surface_add_listener(state->shell_surface, &surface_listener, state); - wl_shell_surface_set_toplevel(state->shell_surface); + if (shell_surface) { + state->shell_surface = wl_shell_get_shell_surface(state->shell, state->surface); + wl_shell_surface_add_listener(state->shell_surface, &surface_listener, state); + wl_shell_surface_set_toplevel(state->shell_surface); + } state->cursor.cursor_theme = wl_cursor_theme_load("default", 32, state->shm); // TODO: let you customize this state->cursor.cursor = wl_cursor_theme_get_cursor(state->cursor.cursor_theme, "left_ptr");