improve basic multi output support

This commit is contained in:
DanyLE 2024-04-15 13:56:11 +02:00
parent 7df1dec7f3
commit fdb2843561
9 changed files with 100 additions and 202 deletions

View File

@ -57,6 +57,10 @@ static void process_cursor_move(struct diyac_server *server, uint32_t time)
{ {
struct diyac_view *toplevel = server->grabbed_view; struct diyac_view *toplevel = server->grabbed_view;
/* Move the grabbed toplevel to the new position. */ /* Move the grabbed toplevel to the new position. */
if(!toplevel->output)
{
return;
}
if (toplevel->state.fullscreen) if (toplevel->state.fullscreen)
{ {
return; return;

10
diyac.h
View File

@ -18,7 +18,7 @@
#include <wlr/types/wlr_foreign_toplevel_management_v1.h> #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#define LAYER_TREE_SZ 4 #define LAYER_TREE_SZ 4
/* For brevity's sake, struct members are annotated where they are used. */
enum diyac_cursor_mode enum diyac_cursor_mode
{ {
DIYAC_CURSOR_PASSTHROUGH, DIYAC_CURSOR_PASSTHROUGH,
@ -83,7 +83,7 @@ struct diyac_popup
void *parent; void *parent;
}; };
struct diyac_layer_scenes struct diyac_output_scenes
{ {
struct wlr_scene_tree *background; struct wlr_scene_tree *background;
struct wlr_scene_tree *bottom; struct wlr_scene_tree *bottom;
@ -161,8 +161,8 @@ struct diyac_output
struct wlr_box usable_area; struct wlr_box usable_area;
// layer output // layer output
struct diyac_layer_scenes scenes; struct diyac_output_scenes scenes;
// alias to diyac_layer_scenes elements // alias to diyac_output_scenes elements
struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ]; struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ];
}; };
@ -207,7 +207,7 @@ struct diyac_view
struct wl_listener request_maximize; struct wl_listener request_maximize;
struct wl_listener request_fullscreen; struct wl_listener request_fullscreen;
struct wl_listener set_app_id; // only useful when using SSD struct wl_listener set_app_id;
struct wl_listener new_popup; struct wl_listener new_popup;
struct wl_listener set_title; struct wl_listener set_title;

View File

@ -94,8 +94,11 @@ void diyac_init_foreign_toplevel(struct diyac_view *view)
toplevel->destroy.notify = handle_destroy; toplevel->destroy.notify = handle_destroy;
wl_signal_add(&toplevel->handle->events.destroy, &toplevel->destroy); wl_signal_add(&toplevel->handle->events.destroy, &toplevel->destroy);
wlr_foreign_toplevel_handle_v1_output_enter( if(view->output)
view->toplevel.handle, view->output->wlr_output); {
wlr_foreign_toplevel_handle_v1_output_enter(
view->toplevel.handle, view->output->wlr_output);
}
//wlr_foreign_toplevel_handle_v1_output_enter //wlr_foreign_toplevel_handle_v1_output_enter
struct wlr_xdg_toplevel *xdg_toplevel = view->xdg_toplevel; struct wlr_xdg_toplevel *xdg_toplevel = view->xdg_toplevel;
if (!xdg_toplevel->parent) if (!xdg_toplevel->parent)

View File

@ -2,6 +2,7 @@
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include "output.h" #include "output.h"
#include "layer.h" #include "layer.h"
#include "node.h" #include "node.h"
@ -38,10 +39,34 @@ static void output_destroy(struct wl_listener *listener, void *data)
{ {
struct diyac_output *output = wl_container_of(listener, output, destroy); struct diyac_output *output = wl_container_of(listener, output, destroy);
wlr_scene_node_destroy(&output->scenes.background->node);
wlr_scene_node_destroy(&output->scenes.bottom->node);
wlr_scene_node_destroy(&output->scenes.top->node);
wlr_scene_node_destroy(&output->scenes.popup->node);
wlr_scene_node_destroy(&output->scenes.overlay->node);
wlr_scene_node_destroy(&output->scenes.session->node);
wl_list_remove(&output->frame.link); wl_list_remove(&output->frame.link);
wl_list_remove(&output->request_state.link); wl_list_remove(&output->request_state.link);
wl_list_remove(&output->destroy.link); wl_list_remove(&output->destroy.link);
wl_list_remove(&output->link); wl_list_remove(&output->link);
struct diyac_server* server = output->server;
struct diyac_view * view;
wl_list_for_each(view, &server->views, link) {
if (view->output == output) {
/**
* TODO: testing this case
*/
view->output = NULL;
if(&server->outputs != server->outputs.next)
{
view->output = wl_container_of(server->outputs.next, view->output, link);
diyac_view_update_geometry(view, false);
}
}
}
free(output); free(output);
} }
@ -187,11 +212,11 @@ struct diyac_output *diyac_output_from_cursor(struct diyac_server *server)
return output->data; return output->data;
} }
struct wlr_box diyac_output_usable_area(struct diyac_output *output) void diyac_output_usable_area(struct diyac_output *output,struct wlr_box* area)
{ {
if (!output) if(!area | !output)
{ {
return (struct wlr_box){0}; return;
} }
struct wlr_box box = output->usable_area; struct wlr_box box = output->usable_area;
double ox = 0, oy = 0; double ox = 0, oy = 0;
@ -199,5 +224,22 @@ struct wlr_box diyac_output_usable_area(struct diyac_output *output)
output->wlr_output, &ox, &oy); output->wlr_output, &ox, &oy);
box.x -= ox; box.x -= ox;
box.y -= oy; box.y -= oy;
return box; memcpy(area,&box,sizeof(box));
}
void diyac_output_full_area(struct diyac_output *output,struct wlr_box* area)
{
if(!area | !output)
{
return;
}
struct wlr_box box = {0};
wlr_output_effective_resolution(output->wlr_output,
&box.width, &box.height);
double ox = 0, oy = 0;
wlr_output_layout_output_coords(output->server->output_layout,
output->wlr_output, &ox, &oy);
box.x -= ox;
box.y -= oy;
memcpy(area,&box,sizeof(box));
} }

View File

@ -5,5 +5,6 @@
void diyac_server_new_output(struct wl_listener *listener, void *data); void diyac_server_new_output(struct wl_listener *listener, void *data);
void diyac_output_update_usable_area(struct diyac_output *output); void diyac_output_update_usable_area(struct diyac_output *output);
struct diyac_output *diyac_output_from_cursor(struct diyac_server *server); struct diyac_output *diyac_output_from_cursor(struct diyac_server *server);
struct wlr_box diyac_output_usable_area(struct diyac_output * output); void diyac_output_usable_area(struct diyac_output * output,struct wlr_box* box);
void diyac_output_full_area(struct diyac_output *output,struct wlr_box* area);
#endif #endif

View File

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="server_decoration">
<copyright><![CDATA[
Copyright (C) 2015 Martin Gräßlin
This program 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.1 of the License, or
(at your option) any later version.
This program 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 program. If not, see <http://www.gnu.org/licenses/>.
]]></copyright>
<interface name="org_kde_kwin_server_decoration_manager" version="1">
<description summary="Server side window decoration manager">
This interface allows to coordinate whether the server should create
a server-side window decoration around a wl_surface representing a
shell surface (wl_shell_surface or similar). By announcing support
for this interface the server indicates that it supports server
side decorations.
</description>
<request name="create">
<description summary="Create a server-side decoration object for a given surface">
When a client creates a server-side decoration object it indicates
that it supports the protocol. The client is supposed to tell the
server whether it wants server-side decorations or will provide
client-side decorations.
If the client does not create a server-side decoration object for
a surface the server interprets this as lack of support for this
protocol and considers it as client-side decorated. Nevertheless a
client-side decorated surface should use this protocol to indicate
to the server that it does not want a server-side deco.
</description>
<arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<enum name="mode">
<description summary="Possible values to use in request_mode and the event mode."/>
<entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
<entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
<entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
</enum>
<event name="default_mode">
<description summary="The default mode used on the server">
This event is emitted directly after binding the interface. It contains
the default mode for the decoration. When a new server decoration object
is created this new object will be in the default mode until the first
request_mode is requested.
The server may change the default mode at any time.
</description>
<arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/>
</event>
</interface>
<interface name="org_kde_kwin_server_decoration" version="1">
<request name="release" type="destructor">
<description summary="release the server decoration object"/>
</request>
<enum name="mode">
<description summary="Possible values to use in request_mode and the event mode."/>
<entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
<entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
<entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
</enum>
<request name="request_mode">
<description summary="The decoration mode the surface wants to use."/>
<arg name="mode" type="uint" summary="The mode this surface wants to use."/>
</request>
<event name="mode">
<description summary="The new decoration mode applied by the server">
This event is emitted directly after the decoration is created and
represents the base decoration policy by the server. E.g. a server
which wants all surfaces to be client-side decorated will send Client,
a server which wants server-side decoration will send Server.
The client can request a different mode through the decoration request.
The server will acknowledge this by another event with the same mode. So
even if a server prefers server-side decoration it's possible to force a
client-side decoration.
The server may emit this event at any time. In this case the client can
again request a different mode. It's the responsibility of the server to
prevent a feedback loop.
</description>
<arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/>
</event>
</interface>
</protocol>

View File

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_input_inhibit_unstable_v1">
<copyright>
Copyright © 2018 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_input_inhibit_manager_v1" version="1">
<description summary="inhibits input events to other clients">
Clients can use this interface to prevent input events from being sent to
any surfaces but its own, which is useful for example in lock screen
software. It is assumed that access to this interface will be locked down
to whitelisted clients by the compositor.
</description>
<request name="get_inhibitor">
<description summary="inhibit input to other clients">
Activates the input inhibitor. As long as the inhibitor is active, the
compositor will not send input events to other clients.
</description>
<arg name="id" type="new_id" interface="zwlr_input_inhibitor_v1"/>
</request>
<enum name="error">
<entry name="already_inhibited" value="0" summary="an input inhibitor is already in use on the compositor"/>
</enum>
</interface>
<interface name="zwlr_input_inhibitor_v1" version="1">
<description summary="inhibits input to other clients">
While this resource exists, input to clients other than the owner of the
inhibitor resource will not receive input events. The client that owns
this resource will receive all input events normally. The compositor will
also disable all of its own input processing (such as keyboard shortcuts)
while the inhibitor is active.
The compositor may continue to send input events to selected clients,
such as an on-screen keyboard (via the input-method protocol).
</description>
<request name="destroy" type="destructor">
<description summary="destroy the input inhibitor object">
Destroy the inhibitor and allow other clients to receive input.
</description>
</request>
</interface>
</protocol>

61
view.c
View File

@ -195,13 +195,22 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
// if (wlr_output_layout_intersects(view->server->output_layout, // if (wlr_output_layout_intersects(view->server->output_layout,
// view->output->wlr_output, &view->current)) // view->output->wlr_output, &view->current))
//{ //{
if (!view->mapped) if (!view->mapped || !view->output)
{ {
wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base); wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
return false; return false;
} }
struct wlr_box usable = diyac_output_usable_area(view->output); struct diyac_view *root = diyac_get_root_view(view);
struct diyac_server *server = view->server; struct diyac_server *server = view->server;
struct wlr_box usable = {0};
if((root && root->state.fullscreen) || view->requested.fullscreen)
{
diyac_output_full_area(view->output, &usable);
}
else
{
diyac_output_usable_area(view->output, &usable);
}
// invalidate old state if change state // invalidate old state if change state
if (view->state.fullscreen && !view->requested.fullscreen) if (view->state.fullscreen && !view->requested.fullscreen)
{ {
@ -232,21 +241,13 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
} }
else if (!view->state.fullscreen && view->requested.fullscreen) else if (!view->state.fullscreen && view->requested.fullscreen)
{ {
struct wlr_box box = {0};
wlr_output_effective_resolution(view->output->wlr_output,
&box.width, &box.height);
double ox = 0, oy = 0;
wlr_output_layout_output_coords(view->server->output_layout,
view->output->wlr_output, &ox, &oy);
box.x -= ox;
box.y -= oy;
wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, true); wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, true);
wlr_scene_node_set_enabled(&view->output->scenes.top->node, false); wlr_scene_node_set_enabled(&view->output->scenes.top->node, false);
if (view->toplevel.handle) if (view->toplevel.handle)
{ {
wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, true); wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, true);
} }
diyac_view_configure(view, box); diyac_view_configure(view, usable);
updated = true; updated = true;
} }
else if (view->requested.maximized) else if (view->requested.maximized)
@ -265,38 +266,42 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
// view->output->wlr_output, &view->current)) // view->output->wlr_output, &view->current))
//{ //{
/**Normal state, recalculate current geometry*/ /**Normal state, recalculate current geometry*/
struct diyac_view *root = diyac_get_root_view(view);
struct wlr_box geometry = view->pending_size; struct wlr_box geometry = view->pending_size;
if (!root) // Only adjust position only when not in fullscreen mode
if(!grabbed)
{ {
root = view; if (geometry.x > (usable.x + usable.width))
} {
if (!root->state.fullscreen) geometry.x = (usable.x + usable.width) - (geometry.width / 2);
{ }
if (geometry.y > (usable.y + usable.height))
// Only adjust position only when not in fullscreen mode {
geometry.y = (usable.y + usable.height) - (geometry.height / 2);
if (!grabbed && geometry.x < usable.x) }
if (geometry.x < usable.x)
{ {
geometry.x = usable.x; geometry.x = usable.x;
} }
if (!grabbed && geometry.y < usable.y) if (geometry.y < usable.y)
{ {
geometry.y = usable.y; geometry.y = usable.y;
} }
if (grabbed && server->seat.cursor->x <= usable.x) }
else
{
if (server->seat.cursor->x <= usable.x)
{ {
geometry.x = usable.x - server->grab_x; geometry.x = usable.x - server->grab_x;
} }
if (grabbed && server->seat.cursor->y <= usable.y) if (server->seat.cursor->y <= usable.y)
{ {
geometry.y = usable.y; geometry.y = usable.y;
} }
if (grabbed && server->seat.cursor->x >= usable.x + usable.width) if (server->seat.cursor->x >= usable.x + usable.width)
{ {
geometry.x = usable.x + usable.width - server->grab_x; geometry.x = usable.x + usable.width - server->grab_x;
} }
if (grabbed && server->seat.cursor->y >= usable.y + usable.height) if (server->seat.cursor->y >= usable.y + usable.height)
{ {
geometry.y = usable.y + usable.height - server->grab_y; geometry.y = usable.y + usable.height - server->grab_y;
} }
@ -349,12 +354,12 @@ struct diyac_view *diyac_get_root_view(struct diyac_view *view)
struct wlr_box diyac_view_get_geometry(struct diyac_view *view) struct wlr_box diyac_view_get_geometry(struct diyac_view *view)
{ {
struct wlr_box box; struct wlr_box box;
if (view->state.fullscreen) if (view->state.fullscreen && view->output)
{ {
wlr_output_layout_get_box(view->server->output_layout, view->output->wlr_output, &box); wlr_output_layout_get_box(view->server->output_layout, view->output->wlr_output, &box);
return box; return box;
} }
if (view->state.maximized) if (view->state.maximized && view->output)
{ {
return view->output->usable_area; return view->output->usable_area;
} }

6
xdg.c
View File

@ -114,7 +114,7 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
{ {
diyac_reset_cursor_mode(toplevel->server); diyac_reset_cursor_mode(toplevel->server);
} }
if (toplevel->state.fullscreen) if (toplevel->state.fullscreen && toplevel->output)
{ {
/** /**
* When a client exit during fullscreen mode, the top layer shall * When a client exit during fullscreen mode, the top layer shall
@ -241,6 +241,10 @@ static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
static void popup_unconstrain(struct diyac_popup *popup) static void popup_unconstrain(struct diyac_popup *popup)
{ {
struct diyac_view *view = popup->parent; struct diyac_view *view = popup->parent;
if(!view->output)
{
return;
}
struct diyac_server *server = view->server; struct diyac_server *server = view->server;
struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output_layout *output_layout = server->output_layout;
struct wlr_output *wlr_output = view->output->wlr_output; struct wlr_output *wlr_output = view->output->wlr_output;