From 5e969fd22954e5f14a22c9c5c44ec2fed0992402 Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Sat, 7 May 2016 12:19:45 +0200 Subject: [PATCH] extensions,handlers: Add notification area support notification-area.{c,h} are bare imports from the wayland-notification-area project. Signed-off-by: Quentin Glidic --- include/extensions.h | 2 + include/notification-area.h | 36 ++++++ protocols/CMakeLists.txt | 8 ++ sway/CMakeLists.txt | 1 + sway/extensions.c | 2 + sway/handlers.c | 12 ++ sway/notification-area.c | 244 ++++++++++++++++++++++++++++++++++++ 7 files changed, 305 insertions(+) create mode 100644 include/notification-area.h create mode 100644 sway/notification-area.c diff --git a/include/extensions.h b/include/extensions.h index 158a40a2..16fb5d0a 100644 --- a/include/extensions.h +++ b/include/extensions.h @@ -3,6 +3,7 @@ #include #include +#include "notification-area.h" #include "wayland-desktop-shell-server-protocol.h" #include "list.h" @@ -37,6 +38,7 @@ struct swaylock_state { }; extern struct desktop_shell_state desktop_shell; +extern struct wlc_notification_area *notification_area; void register_extensions(void); diff --git a/include/notification-area.h b/include/notification-area.h new file mode 100644 index 00000000..9e4e43bb --- /dev/null +++ b/include/notification-area.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2013-2016 Quentin “Sardem FF7” Glidic + * + * 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 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 _WLC_NOTIFICATION_AREA_H_ +#define _WLC_NOTIFICATION_AREA_H_ + +#include + +struct wlc_notification_area; + +struct wlc_notification_area *wlc_notification_area_init(void); +void wlc_notification_area_uninit(struct wlc_notification_area *na); +WLC_PURE wlc_handle wlc_notification_area_get_output(struct wlc_notification_area *na); +void wlc_notification_area_set_output(struct wlc_notification_area *na, wlc_handle output); +void wlc_notification_area_view_destroy(struct wlc_notification_area *na, wlc_handle view); + +#endif /* _WLC_NOTIFICATION_AREA_H_ */ diff --git a/protocols/CMakeLists.txt b/protocols/CMakeLists.txt index ff0a2e4d..0301fff3 100644 --- a/protocols/CMakeLists.txt +++ b/protocols/CMakeLists.txt @@ -22,12 +22,20 @@ WAYLAND_ADD_PROTOCOL_SERVER(proto-server-swaylock swaylock ) +pkg_check_modules(WLC_NOTIFICATION_AREA "wayland-notification-area >= 3") +pkg_get_variable(WAYLAND_NOTIFICATION_AREA_PKGDATADIR wayland-notification-area pkgdatadir) +WAYLAND_ADD_PROTOCOL_SERVER(proto-server-wayland-notification-area + ${WAYLAND_NOTIFICATION_AREA_PKGDATADIR}/notification-area-unstable-v2.xml + notification-area-unstable-v2 +) + add_library(sway-protocols STATIC ${proto-client-xdg-shell} ${proto-client-desktop-shell} ${proto-server-desktop-shell} ${proto-client-swaylock} ${proto-server-swaylock} + ${proto-server-wayland-notification-area} ) set(PROTOCOLS_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/protocols PARENT_SCOPE) diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 73df3b1b..cde1a3bb 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(sway ipc-server.c layout.c main.c + notification-area.c output.c resize.c workspace.c diff --git a/sway/extensions.c b/sway/extensions.c index c646ac91..b8673b34 100644 --- a/sway/extensions.c +++ b/sway/extensions.c @@ -10,6 +10,7 @@ #include "extensions.h" struct desktop_shell_state desktop_shell; +struct wlc_notification_area *notification_area; static struct panel_config *find_or_create_panel_config(struct wl_resource *resource) { for (int i = 0; i < desktop_shell.panels->length; i++) { @@ -214,4 +215,5 @@ void register_extensions(void) { desktop_shell.lock_surfaces = create_list(); desktop_shell.is_locked = false; wl_global_create(wlc_get_wl_display(), &lock_interface, 1, NULL, swaylock_bind); + notification_area = wlc_notification_area_init(); } diff --git a/sway/handlers.c b/sway/handlers.c index 3ac3c494..df227ea9 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -86,6 +86,10 @@ static bool handle_output_created(wlc_handle output) { wlc_handle prev = wlc_get_focused_output(); wlc_output_focus(output); wlc_output_focus(prev); + + if (wlc_notification_area_get_output(notification_area) == 0) + wlc_notification_area_set_output(notification_area, output); + return true; } @@ -108,6 +112,11 @@ static void handle_output_destroyed(wlc_handle output) { swayc_t *c = (swayc_t *)list->items[0]; // switch to other outputs active workspace workspace_switch(c->focused); + if (wlc_notification_area_get_output(notification_area) == output) + wlc_notification_area_set_output(notification_area, c->handle); + } else { + if (wlc_notification_area_get_output(notification_area) == output) + wlc_notification_area_set_output(notification_area, 0); } } @@ -165,6 +174,9 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_ c->width = to->w; c->height = to->h; arrange_windows(&root_container, -1, -1); + + if (wlc_notification_area_get_output(notification_area) == output) + wlc_notification_area_set_output(notification_area, output); } static void handle_output_focused(wlc_handle output, bool focus) { diff --git a/sway/notification-area.c b/sway/notification-area.c new file mode 100644 index 00000000..f61fa9b7 --- /dev/null +++ b/sway/notification-area.c @@ -0,0 +1,244 @@ +/* + * Copyright © 2013-2016 Quentin “Sardem FF7” Glidic + * + * 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 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 +#include +#include +#include +#include "wayland-notification-area-unstable-v2-server-protocol.h" + +#include "notification-area.h" + +struct wlc_notification_area { + struct wl_global *global; + struct wl_resource *binding; + struct wl_list notifications; + wlc_handle output; +}; + +struct wlc_notification_area_notification { + struct wlc_notification_area *na; + struct wl_list link; + wlc_handle view; +}; + +static void +_wlc_notification_area_request_destroy(struct wl_client *client, struct wl_resource *resource) +{ + (void) client; + wl_resource_destroy(resource); +} + +static void +_wlc_notification_area_notification_set_output(struct wlc_notification_area_notification *notification, wlc_handle output) +{ + if ( output == 0 ) + { + wlc_view_set_mask(notification->view, 0); + return; + } + + wlc_view_set_output(notification->view, output); + wlc_view_set_mask(notification->view, wlc_output_get_mask(output)); + wlc_view_bring_to_front(notification->view); +} + +static void +_wlc_notification_area_notification_request_move(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) +{ + (void) client; + struct wlc_notification_area_notification *notification = wl_resource_get_user_data(resource); + struct wlc_geometry geometry; + + geometry = *wlc_view_get_geometry(notification->view); + geometry.origin.x = x; + geometry.origin.y = y; + wlc_view_set_geometry(notification->view, WLC_RESIZE_EDGE_NONE, &geometry); + if ( wlc_view_get_mask(notification->view) == 0 ) + _wlc_notification_area_notification_set_output(notification, notification->na->output); +} + +static const struct zwna_notification_v2_interface wlc_notification_area_notification_implementation = { + .destroy = _wlc_notification_area_request_destroy, + .move = _wlc_notification_area_notification_request_move, +}; + +static void +_wlc_notification_area_destroy(struct wl_client *client, struct wl_resource *resource) +{ + (void) client; + wl_resource_destroy(resource); +} + +static void +_wlc_notification_area_create_notification(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource) +{ + struct wlc_notification_area *self = wl_resource_get_user_data(resource); + + struct wlc_notification_area_notification *notification; + notification = calloc(1, sizeof(struct wlc_notification_area_notification)); + if ( notification == NULL ) + { + wl_resource_post_no_memory(surface_resource); + return; + } + notification->na = self; + wl_list_insert(&self->notifications, ¬ification->link); + + notification->view = wlc_view_from_surface(wlc_resource_from_wl_surface_resource(surface_resource), client, &zwna_notification_v2_interface, &wlc_notification_area_notification_implementation, 1, id, notification); + if ( notification->view == 0 ) + return; + wlc_view_set_type(notification->view, WLC_BIT_OVERRIDE_REDIRECT, true); + wlc_view_set_type(notification->view, WLC_BIT_UNMANAGED, true); + wlc_view_set_mask(notification->view, 0); +} + +static const struct zwna_notification_area_v2_interface wlc_notification_area_implementation = { + .destroy = _wlc_notification_area_destroy, + .create_notification = _wlc_notification_area_create_notification, +}; + +static void +_wlc_notification_area_unbind(struct wl_resource *resource) +{ + struct wlc_notification_area *self = resource->data; + + self->binding = NULL; +} + +static void +_wlc_notification_area_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct wlc_notification_area *self = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &zwna_notification_area_v2_interface, version, id); + wl_resource_set_implementation(resource, &wlc_notification_area_implementation, self, _wlc_notification_area_unbind); + + if ( self->binding != NULL ) + { + wl_resource_post_error(resource, ZWNA_NOTIFICATION_AREA_V2_ERROR_BOUND, "interface object already bound"); + wl_resource_destroy(resource); + return; + } + + self->binding = resource; + + const struct wlc_size *size; + if ( self->output == 0 ) + size = &wlc_size_zero; + else + size = wlc_output_get_resolution(self->output); + zwna_notification_area_v2_send_geometry(self->binding, size->w, size->h, 1); +} + +struct wlc_notification_area * +wlc_notification_area_init(void) +{ + struct wlc_notification_area *self; + + self = calloc(1, sizeof(struct wlc_notification_area)); + + wl_list_init(&self->notifications); + + if ( ( self->global = wl_global_create(wlc_get_wl_display(), &zwna_notification_area_v2_interface, 1, self, _wlc_notification_area_bind) ) == NULL ) + { + free(self); + return NULL; + } + wl_global_destroy(self->global); + if ( ( self->global = wl_global_create(wlc_get_wl_display(), &zwna_notification_area_v2_interface, 1, self, _wlc_notification_area_bind) ) == NULL ) + { + free(self); + return NULL; + } + + return self; +} + +static void +_wlc_notification_area_view_destroy_internal(struct wlc_notification_area_notification *self) +{ + //wlc_view_close(notification->view); + + wl_list_remove(&self->link); + + free(self); +} + +void +wlc_notification_area_uninit(struct wlc_notification_area *self) +{ + struct wlc_notification_area_notification *notification, *tmp; + wl_list_for_each_safe(notification, tmp, &self->notifications, link) + _wlc_notification_area_view_destroy_internal(notification); + wl_global_destroy(self->global); + + free(self); +} + +wlc_handle +wlc_notification_area_get_output(struct wlc_notification_area *self) +{ + return self->output; +} + +void +wlc_notification_area_set_output(struct wlc_notification_area *self, wlc_handle output) +{ + if ( self->binding != NULL ) + { + const struct wlc_size *size; + if ( output == 0 ) + size = &wlc_size_zero; + else + size = wlc_output_get_resolution(output); + zwna_notification_area_v2_send_geometry(self->binding, size->w, size->h, 1); + } + + if ( self->output == output ) + return; + self->output = output; + + struct wlc_notification_area_notification *notification; + wl_list_for_each(notification, &self->notifications, link) + { + if ( wlc_view_get_mask(notification->view) == 0 ) + continue; + + _wlc_notification_area_notification_set_output(notification, output); + } +} + +void +wlc_notification_area_view_destroy(struct wlc_notification_area *self, wlc_handle view) +{ + struct wlc_notification_area_notification *notification, *tmp; + wl_list_for_each_safe(notification, tmp, &self->notifications, link) + { + if ( notification->view != view ) + continue; + + _wlc_notification_area_view_destroy_internal(notification); + return; + } +}