improve basic multi output support
This commit is contained in:
parent
7df1dec7f3
commit
fdb2843561
4
cursor.c
4
cursor.c
@ -57,6 +57,10 @@ static void process_cursor_move(struct diyac_server *server, uint32_t time)
|
||||
{
|
||||
struct diyac_view *toplevel = server->grabbed_view;
|
||||
/* Move the grabbed toplevel to the new position. */
|
||||
if(!toplevel->output)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (toplevel->state.fullscreen)
|
||||
{
|
||||
return;
|
||||
|
10
diyac.h
10
diyac.h
@ -18,7 +18,7 @@
|
||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||
|
||||
#define LAYER_TREE_SZ 4
|
||||
/* For brevity's sake, struct members are annotated where they are used. */
|
||||
|
||||
enum diyac_cursor_mode
|
||||
{
|
||||
DIYAC_CURSOR_PASSTHROUGH,
|
||||
@ -83,7 +83,7 @@ struct diyac_popup
|
||||
void *parent;
|
||||
};
|
||||
|
||||
struct diyac_layer_scenes
|
||||
struct diyac_output_scenes
|
||||
{
|
||||
struct wlr_scene_tree *background;
|
||||
struct wlr_scene_tree *bottom;
|
||||
@ -161,8 +161,8 @@ struct diyac_output
|
||||
struct wlr_box usable_area;
|
||||
|
||||
// layer output
|
||||
struct diyac_layer_scenes scenes;
|
||||
// alias to diyac_layer_scenes elements
|
||||
struct diyac_output_scenes scenes;
|
||||
// alias to diyac_output_scenes elements
|
||||
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_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 set_title;
|
||||
|
||||
|
@ -94,8 +94,11 @@ void diyac_init_foreign_toplevel(struct diyac_view *view)
|
||||
toplevel->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&toplevel->handle->events.destroy, &toplevel->destroy);
|
||||
|
||||
wlr_foreign_toplevel_handle_v1_output_enter(
|
||||
view->toplevel.handle, view->output->wlr_output);
|
||||
if(view->output)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_output_enter(
|
||||
view->toplevel.handle, view->output->wlr_output);
|
||||
}
|
||||
//wlr_foreign_toplevel_handle_v1_output_enter
|
||||
struct wlr_xdg_toplevel *xdg_toplevel = view->xdg_toplevel;
|
||||
if (!xdg_toplevel->parent)
|
||||
|
50
output.c
50
output.c
@ -2,6 +2,7 @@
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "output.h"
|
||||
#include "layer.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);
|
||||
|
||||
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->request_state.link);
|
||||
wl_list_remove(&output->destroy.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);
|
||||
}
|
||||
|
||||
@ -187,11 +212,11 @@ struct diyac_output *diyac_output_from_cursor(struct diyac_server *server)
|
||||
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;
|
||||
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);
|
||||
box.x -= ox;
|
||||
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));
|
||||
}
|
3
output.h
3
output.h
@ -5,5 +5,6 @@
|
||||
void diyac_server_new_output(struct wl_listener *listener, void *data);
|
||||
void diyac_output_update_usable_area(struct diyac_output *output);
|
||||
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
|
@ -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>
|
@ -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
61
view.c
@ -195,13 +195,22 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
|
||||
// if (wlr_output_layout_intersects(view->server->output_layout,
|
||||
// view->output->wlr_output, &view->current))
|
||||
//{
|
||||
if (!view->mapped)
|
||||
if (!view->mapped || !view->output)
|
||||
{
|
||||
wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
|
||||
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 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
|
||||
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)
|
||||
{
|
||||
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_scene_node_set_enabled(&view->output->scenes.top->node, false);
|
||||
if (view->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, true);
|
||||
}
|
||||
diyac_view_configure(view, box);
|
||||
diyac_view_configure(view, usable);
|
||||
updated = true;
|
||||
}
|
||||
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))
|
||||
//{
|
||||
/**Normal state, recalculate current geometry*/
|
||||
struct diyac_view *root = diyac_get_root_view(view);
|
||||
struct wlr_box geometry = view->pending_size;
|
||||
if (!root)
|
||||
// Only adjust position only when not in fullscreen mode
|
||||
if(!grabbed)
|
||||
{
|
||||
root = view;
|
||||
}
|
||||
if (!root->state.fullscreen)
|
||||
{
|
||||
|
||||
// Only adjust position only when not in fullscreen mode
|
||||
|
||||
if (!grabbed && geometry.x < usable.x)
|
||||
if (geometry.x > (usable.x + usable.width))
|
||||
{
|
||||
geometry.x = (usable.x + usable.width) - (geometry.width / 2);
|
||||
}
|
||||
if (geometry.y > (usable.y + usable.height))
|
||||
{
|
||||
geometry.y = (usable.y + usable.height) - (geometry.height / 2);
|
||||
}
|
||||
if (geometry.x < usable.x)
|
||||
{
|
||||
geometry.x = usable.x;
|
||||
}
|
||||
if (!grabbed && geometry.y < usable.y)
|
||||
if (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;
|
||||
}
|
||||
if (grabbed && server->seat.cursor->y <= usable.y)
|
||||
if (server->seat.cursor->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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -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 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);
|
||||
return box;
|
||||
}
|
||||
if (view->state.maximized)
|
||||
if (view->state.maximized && view->output)
|
||||
{
|
||||
return view->output->usable_area;
|
||||
}
|
||||
|
6
xdg.c
6
xdg.c
@ -114,7 +114,7 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
|
||||
{
|
||||
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
|
||||
@ -241,6 +241,10 @@ static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
|
||||
static void popup_unconstrain(struct diyac_popup *popup)
|
||||
{
|
||||
struct diyac_view *view = popup->parent;
|
||||
if(!view->output)
|
||||
{
|
||||
return;
|
||||
}
|
||||
struct diyac_server *server = view->server;
|
||||
struct wlr_output_layout *output_layout = server->output_layout;
|
||||
struct wlr_output *wlr_output = view->output->wlr_output;
|
||||
|
Loading…
Reference in New Issue
Block a user