diff options
-rw-r--r-- | include/sway/output.h | 1 | ||||
-rw-r--r-- | include/sway/tree/container.h | 5 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 2 | ||||
-rw-r--r-- | include/sway/tree/view.h | 59 | ||||
-rw-r--r-- | protocols/desktop-shell.xml | 138 | ||||
-rw-r--r-- | protocols/gamma-control.xml | 57 | ||||
-rw-r--r-- | protocols/server-decoration.xml | 94 | ||||
-rw-r--r-- | protocols/swaylock.xml | 18 | ||||
-rw-r--r-- | protocols/xdg-shell.xml | 430 | ||||
-rw-r--r-- | sway/desktop/output.c | 87 | ||||
-rw-r--r-- | sway/desktop/wl_shell.c | 61 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 67 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 136 | ||||
-rw-r--r-- | sway/input/cursor.c | 11 | ||||
-rw-r--r-- | sway/tree/layout.c | 11 | ||||
-rw-r--r-- | sway/tree/output.c | 1 | ||||
-rw-r--r-- | sway/tree/view.c | 188 |
17 files changed, 356 insertions, 1010 deletions
diff --git a/include/sway/output.h b/include/sway/output.h index b343ecff..98d0f83f 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -24,6 +24,7 @@ struct sway_output { struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; + struct wl_listener scale; struct wl_listener damage_destroy; struct wl_listener damage_frame; diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index fa22ea75..464f80c4 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -70,9 +70,10 @@ struct sway_container { enum sway_container_layout prev_layout; enum sway_container_layout workspace_layout; - // TODO convert to layout coordinates + // For C_ROOT, this has no meaning + // For C_OUTPUT, this is the output position in layout coordinates + // For other types, this is the position in output-local coordinates double x, y; - // does not include borders or gaps. double width, height; diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index fbc3d6af..8badb244 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -20,7 +20,7 @@ struct sway_root { struct wl_listener output_layout_change; - struct wl_list unmanaged_views; // sway_view::unmanaged_view_link + struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link struct { struct wl_signal new_container; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 3965d2b7..4b84205e 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -4,6 +4,8 @@ #include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/xwayland.h> +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" struct sway_container; struct sway_view; @@ -37,6 +39,13 @@ struct sway_xwayland_surface { int pending_width, pending_height; }; +struct sway_xwayland_unmanaged { + struct wlr_xwayland_surface *wlr_xwayland_surface; + struct wl_list link; + + struct wl_listener destroy; +}; + struct sway_wl_shell_surface { struct sway_view *view; @@ -64,10 +73,21 @@ enum sway_view_prop { VIEW_PROP_INSTANCE, }; +struct sway_view_impl { + const char *(*get_prop)(struct sway_view *view, + enum sway_view_prop prop); + void (*configure)(struct sway_view *view, double ox, double oy, int width, + int height); + void (*set_activated)(struct sway_view *view, bool activated); + void (*close)(struct sway_view *view); +}; + struct sway_view { enum sway_view_type type; - struct sway_container *swayc; - struct wlr_surface *surface; + const struct sway_view_impl *impl; + + struct sway_container *swayc; // NULL for unmanaged views + struct wlr_surface *surface; // NULL for unmapped views int width, height; union { @@ -82,21 +102,15 @@ struct sway_view { struct sway_wl_shell_surface *sway_wl_shell_surface; }; - struct { - const char *(*get_prop)(struct sway_view *view, - enum sway_view_prop prop); - void (*set_size)(struct sway_view *view, - int width, int height); - void (*set_position)(struct sway_view *view, - double ox, double oy); - void (*set_activated)(struct sway_view *view, bool activated); - void (*close)(struct sway_view *view); - } iface; - // only used for unmanaged views (shell specific) - struct wl_list unmanaged_view_link; // sway_root::unmanaged views + struct wl_list unmanaged_view_link; // sway_root::unmanaged_views }; +struct sway_view *view_create(enum sway_view_type type, + const struct sway_view_impl *impl); + +void view_destroy(struct sway_view *view); + const char *view_get_title(struct sway_view *view); const char *view_get_app_id(struct sway_view *view); @@ -105,18 +119,25 @@ const char *view_get_class(struct sway_view *view); const char *view_get_instance(struct sway_view *view); -void view_set_size(struct sway_view *view, int width, int height); - -void view_set_position(struct sway_view *view, double ox, double oy); +void view_configure(struct sway_view *view, double ox, double oy, int width, + int height); void view_set_activated(struct sway_view *view, bool activated); void view_close(struct sway_view *view); -void view_update_outputs(struct sway_view *view, const struct wlr_box *before); - void view_damage_whole(struct sway_view *view); void view_damage_from(struct sway_view *view); +// view implementation + +void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); + +void view_unmap(struct sway_view *view); + +void view_update_position(struct sway_view *view, double ox, double oy); + +void view_update_size(struct sway_view *view, int width, int height); + #endif diff --git a/protocols/desktop-shell.xml b/protocols/desktop-shell.xml deleted file mode 100644 index 581f0c5d..00000000 --- a/protocols/desktop-shell.xml +++ /dev/null @@ -1,138 +0,0 @@ -<protocol name="desktop"> - - <interface name="desktop_shell" version="3"> - <description summary="create desktop widgets and helpers"> - 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. - </description> - - <request name="set_background"> - <arg name="output" type="object" interface="wl_output"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <request name="set_panel"> - <arg name="output" type="object" interface="wl_output"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <request name="set_lock_surface"> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <request name="unlock"/> - - <request name="set_grab_surface"> - <description summary="set grab surface"> - 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. - </description> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <!-- We'll fold most of wl_shell into this interface and then - they'll share the configure event. --> - <event name="configure"> - <arg name="edges" type="uint"/> - <arg name="surface" type="object" interface="wl_surface"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> - </event> - - <event name="prepare_lock_surface"> - <description summary="tell the client to create, set the lock surface"> - 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. - </description> - </event> - - <event name="grab_cursor"> - <description summary="tell client what cursor to show during a grab"> - This event will be sent immediately before a fake enter event on the - grab surface. - </description> - <arg name="cursor" type="uint"/> - </event> - - <enum name="cursor"> - <entry name="none" value="0"/> - - <entry name="resize_top" value="1"/> - <entry name="resize_bottom" value="2"/> - - <entry name="arrow" value="3"/> - - <entry name="resize_left" value="4"/> - <entry name="resize_top_left" value="5"/> - <entry name="resize_bottom_left" value="6"/> - - <entry name="move" value="7"/> - - <entry name="resize_right" value="8"/> - <entry name="resize_top_right" value="9"/> - <entry name="resize_bottom_right" value="10"/> - - <entry name="busy" value="11"/> - </enum> - - <!-- Version 2 additions --> - - <request name="desktop_ready" since="2"> - <description summary="desktop is ready to be shown"> - 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. - </description> - </request> - - <!-- Version 3 additions --> - - <enum name="panel_position"> - <entry name="top" value="0"/> - <entry name="bottom" value="1"/> - <entry name="left" value="2"/> - <entry name="right" value="3"/> - </enum> - - <enum name="error"> - <entry name="invalid_argument" value="0" - summary="an invalid argument was provided in a request"/> - </enum> - - <request name="set_panel_position" since="3"> - <description summary="set panel position"> - 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. - </description> - <arg name="position" type="uint"/> - </request> - - </interface> - - <interface name="screensaver" version="1"> - <description summary="interface for implementing screensavers"> - Only one client can bind this interface at a time. - </description> - - <request name="set_surface"> - <description summary="set the surface type as a screensaver"> - A screensaver surface is normally hidden, and only visible after an - idle timeout. - </description> - - <arg name="surface" type="object" interface="wl_surface"/> - <arg name="output" type="object" interface="wl_output"/> - </request> - - </interface> -</protocol> diff --git a/protocols/gamma-control.xml b/protocols/gamma-control.xml deleted file mode 100644 index e6e33265..00000000 --- a/protocols/gamma-control.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<protocol name="gamma_control"> - - <copyright> - Copyright © 2015 Giulio camuffo - - 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="gamma_control_manager" version="1"> - <request name="destroy" type="destructor"/> - - <request name="get_gamma_control"> - <arg name="id" type="new_id" interface="gamma_control"/> - <arg name="output" type="object" interface="wl_output"/> - </request> - </interface> - - <interface name="gamma_control" version="1"> - <enum name="error"> - <entry name="invalid_gamma" value="0"/> - </enum> - - <request name="destroy" type="destructor"/> - - <request name="set_gamma"> - <arg name="red" type="array"/> - <arg name="green" type="array"/> - <arg name="blue" type="array"/> - </request> - - <request name="reset_gamma"/> - - <event name="gamma_size"> - <arg name="size" type="uint"/> - </event> - </interface> -</protocol> diff --git a/protocols/server-decoration.xml b/protocols/server-decoration.xml deleted file mode 100644 index 8bc106c7..00000000 --- a/protocols/server-decoration.xml +++ /dev/null @@ -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> diff --git a/protocols/swaylock.xml b/protocols/swaylock.xml deleted file mode 100644 index c7a102dd..00000000 --- a/protocols/swaylock.xml +++ /dev/null @@ -1,18 +0,0 @@ -<protocol name="lock"> - - <interface name="lock" version="1"> - <description summary="create lock screen UIs"> - The Weston desktop-shell protocol's locking functionality depends more - on the behavior of the compositor than of a screen locking client, so - another protocol is necessary. - </description> - - <request name="set_lock_surface"> - <arg name="output" type="object" interface="wl_output"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <request name="unlock"/> - - </interface> -</protocol> diff --git a/protocols/xdg-shell.xml b/protocols/xdg-shell.xml deleted file mode 100644 index 7bf4ae3a..00000000 --- a/protocols/xdg-shell.xml +++ /dev/null @@ -1,430 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<protocol name="xdg_shell"> - - <copyright> - Copyright © 2008-2013 Kristian Høgsberg - Copyright © 2013 Rafael Antognolli - Copyright © 2013 Jasper St. Pierre - Copyright © 2010-2013 Intel Corporation - - 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="xdg_shell" version="1"> - <description summary="create desktop-style surfaces"> - This interface is implemented by servers that provide - desktop-style user interfaces. - - It allows clients to associate a xdg_surface with - a basic surface. - </description> - - <enum name="version"> - <description summary="latest protocol 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. - </description> - <entry name="current" value="4" summary="Always the latest version"/> - </enum> - - <enum name="error"> - <entry name="role" value="0" summary="given wl_surface has another role"/> - </enum> - - <request name="use_unstable_version"> - <description summary="enable use of this unstable version"> - Negotiate the unstable version of the interface. This - mechanism is in place to ensure client and server agree on the - unstable versions of the protocol that they speak or exit - cleanly if they don't agree. This request will go away once - the xdg-shell protocol is stable. - </description> - <arg name="version" type="int"/> - </request> - - <request name="get_xdg_surface"> - <description summary="create a shell surface from a surface"> - Create a shell surface for an existing surface. - - This request gives the surface the role of xdg_surface. If the - surface already has another role, it raises a protocol error. - - Only one shell or popup surface can be associated with a given - surface. - </description> - <arg name="id" type="new_id" interface="xdg_surface"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - - <request name="get_xdg_popup"> - <description summary="create a shell surface from a surface"> - Create a popup surface for an existing surface. - - This request gives the surface the role of xdg_popup. If the - surface already has another role, it raises a protocol error. - - Only one shell or popup surface can be associated with a given - surface. - </description> - <arg name="id" type="new_id" interface="xdg_popup"/> - <arg name="surface" type="object" interface="wl_surface"/> - <arg name="parent" type="object" interface="wl_surface"/> - <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="flags" type="uint"/> - </request> - - <event name="ping"> - <description summary="check if the client is alive"> - 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. - </description> - <arg name="serial" type="uint" summary="pass this to the callback"/> - </event> - - <request name="pong"> - <description summary="respond to a ping event"> - A client must respond to a ping event with a pong request or - the client may be deemed unresponsive. - </description> - <arg name="serial" type="uint" summary="serial of the ping event"/> - </request> - </interface> - - <interface name="xdg_surface" version="1"> - - <description summary="desktop-style metadata interface"> - 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. - - On the server side the object is automatically destroyed when - the related wl_surface is destroyed. On client side, - xdg_surface.destroy() must be called before destroying - the wl_surface object. - </description> - - <request name="destroy" type="destructor"> - <description summary="remove xdg_surface interface"> - The xdg_surface interface is removed from the wl_surface object - that was turned into a xdg_surface with - xdg_shell.get_xdg_surface request. The xdg_surface properties, - like maximized and fullscreen, are lost. The wl_surface loses - its role as a xdg_surface. The wl_surface is unmapped. - </description> - </request> - - <request name="set_parent"> - <description summary="surface is a child of another surface"> - Child surfaces are stacked above their parents, and will be - unmapped if the parent is unmapped too. They should not appear - on task bars and alt+tab. - </description> - <arg name="parent" type="object" interface="wl_surface" allow-null="true"/> - </request> - - <request name="set_title"> - <description summary="set surface title"> - Set a short title for the surface. - - This string may be used to identify the surface in a task bar, - window list, or other user interface elements provided by the - compositor. - - The string must be encoded in UTF-8. - </description> - <arg name="title" type="string"/> - </request> - - <request name="set_app_id"> - <description summary="set surface class"> - Set an id for the surface. - - The app id identifies the general class of applications to which - the surface belongs. - - It should be the ID that appears in the new desktop entry - specification, the interface name. - </description> - <arg name="app_id" type="string"/> - </request> - - <request name="show_window_menu"> - <description summary="show the window menu"> - Clients implementing client-side decorations might want to show - a context menu when right-clicking on the decorations, giving the - user a menu that they can use to maximize or minimize the window. - - This request asks the compositor to pop up such a window menu at - the given position, relative to the parent surface. There are - no guarantees as to what the window menu contains. - - Your surface must have focus on the seat passed in to pop up the - window menu. - </description> - - <arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/> - <arg name="serial" type="uint" summary="serial of the event to pop up the window for"/> - <arg name="x" type="int" summary="the x position to pop up the window menu at"/> - <arg name="y" type="int" summary="the y position to pop up the window menu at"/> - </request> - - <request name="move"> - <description summary="start an interactive move"> - Start a pointer-driven move of the surface. - - This request must be used in response to a button press event. - The server may ignore move requests depending on the state of - the surface (e.g. fullscreen or maximized). - </description> - <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> - </request> - - <enum name="resize_edge"> - <description summary="edge values for resizing"> - These values are used to indicate which edge of a surface - is being dragged in a resize operation. The server may - use this information to adapt its behavior, e.g. choose - an appropriate cursor image. - </description> - <entry name="none" value="0"/> - <entry name="top" value="1"/> - <entry name="bottom" value="2"/> - <entry name="left" value="4"/> - <entry name="top_left" value="5"/> - <entry name="bottom_left" value="6"/> - <entry name="right" value="8"/> - <entry name="top_right" value="9"/> - <entry name="bottom_right" value="10"/> - </enum> - - <request name="resize"> - <description summary="start an interactive resize"> - Start a pointer-driven resizing of the surface. - - This request must be used in response to a button press event. - The server may ignore resize requests depending on the state of - the surface (e.g. fullscreen or maximized). - </description> - <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> - <arg name="edges" type="uint" summary="which edge or corner is being dragged"/> - </request> - - <enum name="state"> - <description summary="types of state on the surface"> - The different state values used on the surface. This is designed for - state values like maximized, fullscreen. It is paired with the - configure event to ensure that both the client and the compositor - setting the state can be synchronized. - - States set in this way are double-buffered. They will get applied on - the next commit. - - Desktop environments may extend this enum by taking up a range of - values and documenting the range they chose in this description. - They are not required to document the values for the range that they - chose. Ideally, any good extensions from a desktop environment should - make its way into standardization into this enum. - - The current reserved ranges are: - - 0x0000 - 0x0FFF: xdg-shell core values, documented below. - 0x1000 - 0x1FFF: GNOME - </description> - <entry name="maximized" value="1"> - <description summary="the surface is maximized"> - The surface is maximized. The window geometry specified in the configure - event must be obeyed by the client. - </description> - </entry> - <entry name="fullscreen" value="2"> - <description summary="the surface is fullscreen"> - The surface is fullscreen. The window geometry specified in the configure - event must be obeyed by the client. - </description> - </entry> - <entry name="resizing" value="3"> - <description summary="the surface is being resized"> - The surface is being resized. The window geometry specified in the - configure event is a maximum; the client cannot resize beyond it. - Clients that have aspect ratio or cell sizing configuration can use - a smaller size, however. - </description> - </entry> - <entry name="activated" value="4"> - <description summary="the client window is active"> - 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. - </description> - </entry> - </enum> - - <event name="configure"> - <description summary="suggest a surface change"> - The configure event asks the client to resize its surface. - - The width and height arguments specify a hint to the window - about how its surface should be resized in window geometry - coordinates. The states listed in the event specify how the - width/height arguments should be interpreted. - - A client should arrange a new surface, and then send a - ack_configure request with the serial sent in this configure - event before attaching a 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. - </description> - - <arg name="width" type="int"/> - <arg name="height" type="int"/> - <arg name="states" type="array"/> - <arg name="serial" type="uint"/> - </event> - - <request name="ack_configure"> - <description summary="ack a configure event"> - When a configure event is received, a client should then ack it - using the ack_configure request to ensure that the compositor - knows the client has seen the event. - - By this point, the state is confirmed, and the next attach should - contain the buffer drawn for the configure event you are acking. - </description> - <arg name="serial" type="uint" summary="a serial to configure for"/> - </request> - - <request name="set_window_geometry"> - <description summary="set the new window geometry"> - The window geometry of a window is its "visible bounds" from the - user's perspective. Client-side decorations often have invisible - portions like drop-shadows which should be ignored for the - purposes of aligning, placing and constraining windows. - - The default value is the full bounds of the surface, including any - subsurfaces. Once the window geometry of the surface is set once, - it is not possible to unset it, and it will remain the same until - set_window_geometry is called again, even if a new subsurface or - buffer is attached. - - If responding to a configure event, the window geometry in here - must respect the sizing negotiations specified by the states in - the configure event. - </description> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> - </request> - - <request name="set_maximized" /> - <request name="unset_maximized" /> - - <request name="set_fullscreen"> - <description summary="set the window as fullscreen on a monitor"> - Make the surface fullscreen. - - You can specify an output that you would prefer to be fullscreen. - If this value is NULL, it's up to the compositor to choose which - display will be used to map this surface. - </description> - <arg name="output" type="object" interface="wl_output" allow-null="true"/> - </request> - <request name="unset_fullscreen" /> - - <request name="set_minimized" /> - - <event name="close"> - <description summary="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... - </description> - </event> - </interface> - - <interface name="xdg_popup" version="1"> - <description summary="desktop-style metadata interface"> - An interface that may be implemented by a wl_surface, for - implementations that provide a desktop-style popups/menus. A popup - surface is a transient surface with an added pointer grab. - - An existing implicit grab will be changed to owner-events mode, - and the popup grab will continue after the implicit grab ends - (i.e. releasing the mouse button does not cause the popup to be - unmapped). - - The popup grab continues until the window is destroyed or a mouse - button is pressed in any other clients window. A click in any of - the clients surfaces is reported as normal, however, clicks in - other clients surfaces will be discarded and trigger the callback. - - The x and y arguments specify the locations of the upper left - corner of the surface relative to the upper left corner of the - parent surface, in surface local coordinates. - - xdg_popup surfaces are always transient for another surface. - </description> - - <request name="destroy" type="destructor"> - <description summary="remove xdg_surface interface"> - The xdg_surface interface is removed from the wl_surface object - that was turned into a xdg_surface with - xdg_shell.get_xdg_surface request. The xdg_surface properties, - like maximized and fullscreen, are lost. The wl_surface loses - its role as a xdg_surface. The wl_surface is unmapped. - </description> - </request> - - <event name="popup_done"> - <description summary="popup interaction is done"> - The popup_done event is sent out when a popup grab is broken, - that is, when the users clicks a surface that doesn't belong - to the client owning the popup surface. - </description> - <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> - </event> - - </interface> -</protocol> diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 5e8a081c..10ed1f6d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -39,6 +39,32 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, } } +/** + * Checks whether a surface at (lx, ly) intersects an output. If `box` is not + * NULL, it populates it with the surface box in the output, in output-local + * coordinates. + */ +static bool surface_intersect_output(struct wlr_surface *surface, + struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, + double lx, double ly, float rotation, struct wlr_box *box) { + double ox = lx, oy = ly; + wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); + + if (box != NULL) { + box->x = ox * wlr_output->scale; + box->y = oy * wlr_output->scale; + box->width = surface->current->width * wlr_output->scale; + box->height = surface->current->height * wlr_output->scale; + } + + struct wlr_box layout_box = { + .x = lx, .y = ly, + .width = surface->current->width, .height = surface->current->height, + }; + wlr_box_rotated_bounds(&layout_box, rotation, &layout_box); + return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); +} + static void render_surface(struct wlr_surface *surface, struct wlr_output *wlr_output, struct timespec *when, double lx, double ly, float rotation) { @@ -48,29 +74,21 @@ static void render_surface(struct wlr_surface *surface, if (!wlr_surface_has_buffer(surface)) { return; } + struct wlr_output_layout *layout = root_container.sway_root->output_layout; - int width = surface->current->width; - int height = surface->current->height; - int render_width = width * wlr_output->scale; - int render_height = height * wlr_output->scale; - int owidth, oheight; - wlr_output_effective_resolution(wlr_output, &owidth, &oheight); - - // FIXME: view coords are inconsistently assumed to be in output or layout coords - struct wlr_box layout_box = { - .x = lx + wlr_output->lx, .y = ly + wlr_output->ly, - .width = render_width, .height = render_height, - }; - if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) { - struct wlr_box render_box = { - .x = lx, .y = ly, - .width = render_width, .height = render_height - }; + + struct wlr_box box; + bool intersects = surface_intersect_output(surface, layout, wlr_output, + lx, ly, rotation, &box); + if (intersects) { float matrix[9]; - wlr_matrix_project_box(matrix, &render_box, surface->current->transform, - 0, wlr_output->transform_matrix); - wlr_render_texture_with_matrix(renderer, surface->texture, matrix, - 1.0f); // TODO: configurable alpha + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current->transform); + wlr_matrix_project_box(matrix, &box, transform, rotation, + wlr_output->transform_matrix); + + // TODO: configurable alpha + wlr_render_texture_with_matrix(renderer, surface->texture, matrix, 1.0f); wlr_surface_send_frame_done(surface, when); } @@ -80,9 +98,8 @@ static void render_surface(struct wlr_surface *surface, struct wlr_surface_state *state = subsurface->surface->current; double sx = state->subsurface_position.x; double sy = state->subsurface_position.y; - double sw = state->buffer_width / state->scale; - double sh = state->buffer_height / state->scale; - rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); + rotate_child_position(&sx, &sy, state->width, state->height, + surface->current->width, surface->current->height, rotation); render_surface(subsurface->surface, wlr_output, when, lx + sx, ly + sy, rotation); @@ -243,15 +260,15 @@ static void render_output(struct sway_output *output, struct timespec *when, container_descendants(workspace, C_VIEW, render_view, &rdata); // render unmanaged views on top - struct sway_view *view; - wl_list_for_each(view, &root_container.sway_root->unmanaged_views, - unmanaged_view_link) { - if (view->type != SWAY_XWAYLAND_VIEW) { + struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; + struct sway_xwayland_unmanaged *sway_surface; + wl_list_for_each(sway_surface, unmanaged, link) { + struct wlr_xwayland_surface *xsurface = + sway_surface->wlr_xwayland_surface; + if (xsurface->surface == NULL) { continue; } - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - const struct wlr_box view_box = { .x = xsurface->x, .y = xsurface->y, @@ -263,7 +280,7 @@ static void render_output(struct sway_output *output, struct timespec *when, continue; } - render_surface(view->surface, wlr_output, &output->last_frame, + render_surface(xsurface->surface, wlr_output, &output->last_frame, view_box.x - output_box->x, view_box.y - output_box->y, 0); } @@ -341,6 +358,12 @@ static void handle_transform(struct wl_listener *listener, void *data) { arrange_windows(output->swayc, -1, -1); } +static void handle_scale(struct wl_listener *listener, void *data) { + struct sway_output *output = wl_container_of(listener, output, scale); + arrange_layers(output); + arrange_windows(output->swayc, -1, -1); +} + void handle_new_output(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; @@ -381,6 +404,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { output->mode.notify = handle_mode; wl_signal_add(&wlr_output->events.transform, &output->transform); output->transform.notify = handle_transform; + wl_signal_add(&wlr_output->events.scale, &output->scale); + output->scale.notify = handle_scale; wl_signal_add(&output->damage->events.frame, &output->damage_frame); output->damage_frame.notify = damage_handle_frame; diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index c44fcf27..6528a397 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -30,28 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { } } -static void set_size(struct sway_view *view, int width, int height) { +static void configure(struct sway_view *view, double ox, double oy, int width, + int height) { if (!assert_wl_shell(view)) { return; } + view_update_position(view, ox, oy); view->sway_wl_shell_surface->pending_width = width; view->sway_wl_shell_surface->pending_height = height; wlr_wl_shell_surface_configure(view->wlr_wl_shell_surface, 0, width, height); } -static void set_position(struct sway_view *view, double ox, double oy) { - if (!assert_wl_shell(view)) { - return; - } - view->swayc->x = ox; - view->swayc->y = oy; -} - -static void set_activated(struct sway_view *view, bool activated) { - // no way to activate wl_shell -} - -static void close(struct sway_view *view) { +static void _close(struct sway_view *view) { if (!assert_wl_shell(view)) { return; } @@ -59,14 +49,20 @@ static void close(struct sway_view *view) { wl_client_destroy(view->wlr_wl_shell_surface->client); } +static const struct sway_view_impl view_impl = { + .get_prop = get_prop, + .configure = configure, + .close = _close, +}; + static void handle_commit(struct wl_listener *listener, void *data) { struct sway_wl_shell_surface *sway_surface = wl_container_of(listener, sway_surface, commit); struct sway_view *view = sway_surface->view; // NOTE: We intentionally discard the view's desired width here // TODO: Let floating views do whatever - view->width = sway_surface->pending_width; - view->height = sway_surface->pending_height; + view_update_size(view, sway_surface->pending_width, + sway_surface->pending_height); view_damage_from(view); } @@ -75,15 +71,13 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, sway_surface, destroy); wl_list_remove(&sway_surface->commit.link); wl_list_remove(&sway_surface->destroy.link); - struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); - free(sway_surface->view); + view_destroy(sway_surface->view); free(sway_surface); - arrange_windows(parent, -1, -1); } void handle_wl_shell_surface(struct wl_listener *listener, void *data) { - struct sway_server *server = wl_container_of( - listener, server, wl_shell_surface); + struct sway_server *server = wl_container_of(listener, server, + wl_shell_surface); struct wlr_wl_shell_surface *shell_surface = data; if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { @@ -103,20 +97,13 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { return; } - struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); - if (!sway_assert(sway_view, "Failed to allocate view!")) { + struct sway_view *view = view_create(SWAY_WL_SHELL_VIEW, &view_impl); + if (!sway_assert(view, "Failed to allocate view")) { return; } - sway_view->type = SWAY_WL_SHELL_VIEW; - sway_view->iface.get_prop = get_prop; - sway_view->iface.set_size = set_size; - sway_view->iface.set_position = set_position; - sway_view->iface.set_activated = set_activated; - sway_view->iface.close = close; - sway_view->wlr_wl_shell_surface = shell_surface; - sway_view->sway_wl_shell_surface = sway_surface; - sway_view->surface = shell_surface->surface; - sway_surface->view = sway_view; + view->wlr_wl_shell_surface = shell_surface; + view->sway_wl_shell_surface = sway_surface; + sway_surface->view = view; // TODO: // - Wire up listeners @@ -132,11 +119,5 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { sway_surface->destroy.notify = handle_destroy; wl_signal_add(&shell_surface->events.destroy, &sway_surface->destroy); - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, &root_container); - struct sway_container *cont = container_view_create(focus, sway_view); - sway_view->swayc = cont; - - arrange_windows(cont->parent, -1, -1); - input_manager_set_focus(input_manager, cont); + view_map(view, shell_surface->surface); } diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index cffe83fb..49305b39 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -30,23 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { } } -static void set_size(struct sway_view *view, int width, int height) { +static void configure(struct sway_view *view, double ox, double oy, int width, + int height) { if (!assert_xdg(view)) { return; } + + view_update_position(view, ox, oy); view->sway_xdg_surface_v6->pending_width = width; view->sway_xdg_surface_v6->pending_height = height; wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height); } -static void set_position(struct sway_view *view, double ox, double oy) { - if (!assert_xdg(view)) { - return; - } - view->swayc->x = ox; - view->swayc->y = oy; -} - static void set_activated(struct sway_view *view, bool activated) { if (!assert_xdg(view)) { return; @@ -57,7 +52,7 @@ static void set_activated(struct sway_view *view, bool activated) { } } -static void close(struct sway_view *view) { +static void _close(struct sway_view *view) { if (!assert_xdg(view)) { return; } @@ -67,6 +62,13 @@ static void close(struct sway_view *view) { } } +static const struct sway_view_impl view_impl = { + .get_prop = get_prop, + .configure = configure, + .set_activated = set_activated, + .close = _close, +}; + static void handle_commit(struct wl_listener *listener, void *data) { struct sway_xdg_surface_v6 *sway_surface = wl_container_of(listener, sway_surface, commit); @@ -74,37 +76,22 @@ static void handle_commit(struct wl_listener *listener, void *data) { // NOTE: We intentionally discard the view's desired width here // TODO: Store this for restoration when moving to floating plane // TODO: Let floating views do whatever - view->width = sway_surface->pending_width; - view->height = sway_surface->pending_height; + view_update_size(view, sway_surface->pending_width, + sway_surface->pending_height); view_damage_from(view); } static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_surface_v6 *sway_surface = wl_container_of(listener, sway_surface, unmap); - view_damage_whole(sway_surface->view); - container_view_destroy(sway_surface->view->swayc); - sway_surface->view->swayc = NULL; - sway_surface->view->surface = NULL; + view_unmap(sway_surface->view); } static void handle_map(struct wl_listener *listener, void *data) { struct sway_xdg_surface_v6 *sway_surface = wl_container_of(listener, sway_surface, map); struct sway_view *view = sway_surface->view; - - sway_surface->view->surface = view->wlr_xdg_surface_v6->surface; - - container_view_destroy(view->swayc); - - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, &root_container); - struct sway_container *cont = container_view_create(focus, view); - view->swayc = cont; - arrange_windows(cont->parent, -1, -1); - input_manager_set_focus(input_manager, cont); - - view_damage_whole(sway_surface->view); + view_map(view, view->wlr_xdg_surface_v6->surface); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -112,8 +99,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, sway_xdg_surface, destroy); wl_list_remove(&sway_xdg_surface->commit.link); wl_list_remove(&sway_xdg_surface->destroy.link); - container_view_destroy(sway_xdg_surface->view->swayc); - free(sway_xdg_surface->view); + wl_list_remove(&sway_xdg_surface->map.link); + wl_list_remove(&sway_xdg_surface->unmap.link); + view_destroy(sway_xdg_surface->view); free(sway_xdg_surface); } @@ -138,23 +126,16 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { return; } - struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); - if (!sway_assert(sway_view, "Failed to allocate view!")) { + struct sway_view *view = view_create(SWAY_XDG_SHELL_V6_VIEW, &view_impl); + if (!sway_assert(view, "Failed to allocate view")) { return; } - sway_view->type = SWAY_XDG_SHELL_V6_VIEW; - sway_view->iface.get_prop = get_prop; - sway_view->iface.set_size = set_size; - sway_view->iface.set_position = set_position; - sway_view->iface.set_activated = set_activated; - sway_view->iface.close = close; - sway_view->wlr_xdg_surface_v6 = xdg_surface; - sway_view->sway_xdg_surface_v6 = sway_surface; - sway_surface->view = sway_view; + view->wlr_xdg_surface_v6 = xdg_surface; + view->sway_xdg_surface_v6 = sway_surface; + sway_surface->view = view; // TODO: // - Look up pid and open on appropriate workspace - // - Set new view to maximized so it behaves nicely // - Criteria sway_surface->commit.notify = handle_commit; diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 17f827d9..bfef68cf 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -14,6 +14,33 @@ #include "sway/input/input-manager.h" #include "log.h" +static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_xwayland_unmanaged *sway_surface = + wl_container_of(listener, sway_surface, destroy); + wl_list_remove(&sway_surface->destroy.link); + wl_list_remove(&sway_surface->link); + free(sway_surface); +} + +static void create_unmanaged(struct wlr_xwayland_surface *xsurface) { + struct sway_xwayland_unmanaged *sway_surface = + calloc(1, sizeof(struct sway_xwayland_unmanaged)); + if (!sway_assert(sway_surface, "Failed to allocate surface")) { + return; + } + + sway_surface->wlr_xwayland_surface = xsurface; + + wl_signal_add(&xsurface->events.destroy, &sway_surface->destroy); + sway_surface->destroy.notify = unmanaged_handle_destroy; + + wl_list_insert(&root_container.sway_root->xwayland_unmanaged, + &sway_surface->link); + + // TODO: damage tracking +} + + static bool assert_xwayland(struct sway_view *view) { return sway_assert(view->type == SWAY_XWAYLAND_VIEW, "Expected xwayland view!"); @@ -33,22 +60,13 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { } } -static void set_size(struct sway_view *view, int width, int height) { +static void configure(struct sway_view *view, double ox, double oy, int width, + int height) { if (!assert_xwayland(view)) { return; } - view->sway_xwayland_surface->pending_width = width; - view->sway_xwayland_surface->pending_height = height; - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - wlr_xwayland_surface_configure(xsurface, xsurface->x, xsurface->y, - width, height); -} -static void set_position(struct sway_view *view, double ox, double oy) { - if (!assert_xwayland(view)) { - return; - } struct sway_container *output = container_parent(view->swayc, C_OUTPUT); if (!sway_assert(output, "view must be within tree to set position")) { return; @@ -64,13 +82,12 @@ static void set_position(struct sway_view *view, double ox, double oy) { return; } - view->swayc->x = ox; - view->swayc->y = oy; + view_update_position(view, ox, oy); - wlr_xwayland_surface_configure(view->wlr_xwayland_surface, - ox + loutput->x, oy + loutput->y, - view->wlr_xwayland_surface->width, - view->wlr_xwayland_surface->height); + view->sway_xwayland_surface->pending_width = width; + view->sway_xwayland_surface->pending_height = height; + wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y, + width, height); } static void set_activated(struct sway_view *view, bool activated) { @@ -81,77 +98,58 @@ static void set_activated(struct sway_view *view, bool activated) { wlr_xwayland_surface_activate(surface, activated); } -static void close_view(struct sway_view *view) { +static void _close(struct sway_view *view) { if (!assert_xwayland(view)) { return; } wlr_xwayland_surface_close(view->wlr_xwayland_surface); } +static const struct sway_view_impl view_impl = { + .get_prop = get_prop, + .configure = configure, + .set_activated = set_activated, + .close = _close, +}; + static void handle_commit(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, commit); struct sway_view *view = sway_surface->view; // NOTE: We intentionally discard the view's desired width here // TODO: Let floating views do whatever - view->width = sway_surface->pending_width; - view->height = sway_surface->pending_height; + view_update_size(view, sway_surface->pending_width, + sway_surface->pending_height); view_damage_from(view); } static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, destroy); - wl_list_remove(&sway_surface->commit.link); wl_list_remove(&sway_surface->destroy.link); wl_list_remove(&sway_surface->request_configure.link); - wl_list_remove(&sway_surface->view->unmanaged_view_link); - container_view_destroy(sway_surface->view->swayc); - sway_surface->view->swayc = NULL; - sway_surface->view->surface = NULL; + wl_list_remove(&sway_surface->map.link); + wl_list_remove(&sway_surface->unmap.link); + view_destroy(sway_surface->view); + free(sway_surface); } static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, unmap); - view_damage_whole(sway_surface->view); - wl_list_remove(&sway_surface->view->unmanaged_view_link); - wl_list_init(&sway_surface->view->unmanaged_view_link); - container_view_destroy(sway_surface->view->swayc); - sway_surface->view->swayc = NULL; - sway_surface->view->surface = NULL; + view_unmap(sway_surface->view); } static void handle_map(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, map); struct wlr_xwayland_surface *xsurface = data; - - sway_surface->view->surface = xsurface->surface; + struct sway_view *view = sway_surface->view; // put it back into the tree - if (wlr_xwayland_surface_is_unmanaged(xsurface) || - xsurface->override_redirect) { - wl_list_remove(&sway_surface->view->unmanaged_view_link); - wl_list_insert(&root_container.sway_root->unmanaged_views, - &sway_surface->view->unmanaged_view_link); - } else { - struct sway_view *view = sway_surface->view; - container_view_destroy(view->swayc); - - wlr_xwayland_surface_set_maximized(xsurface, true); - - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, - &root_container); - struct sway_container *cont = container_view_create(focus, view); - view->swayc = cont; - arrange_windows(cont->parent, -1, -1); - input_manager_set_focus(input_manager, cont); - } - - view_damage_whole(sway_surface->view); + wlr_xwayland_surface_set_maximized(xsurface, true); + view_map(view, xsurface->surface); } static void handle_request_configure(struct wl_listener *listener, void *data) { @@ -171,34 +169,32 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { listener, server, xwayland_surface); struct wlr_xwayland_surface *xsurface = data; + if (wlr_xwayland_surface_is_unmanaged(xsurface) || + xsurface->override_redirect) { + wlr_log(L_DEBUG, "New xwayland unmanaged surface"); + create_unmanaged(xsurface); + return; + } + wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", - xsurface->title, xsurface->class); + xsurface->title, xsurface->class); struct sway_xwayland_surface *sway_surface = calloc(1, sizeof(struct sway_xwayland_surface)); - if (!sway_assert(sway_surface, "Failed to allocate surface!")) { + if (!sway_assert(sway_surface, "Failed to allocate surface")) { return; } - struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); - if (!sway_assert(sway_view, "Failed to allocate view!")) { + struct sway_view *view = view_create(SWAY_XWAYLAND_VIEW, &view_impl); + if (!sway_assert(view, "Failed to allocate view")) { return; } - sway_view->type = SWAY_XWAYLAND_VIEW; - sway_view->iface.get_prop = get_prop; - sway_view->iface.set_size = set_size; - sway_view->iface.set_position = set_position; - sway_view->iface.set_activated = set_activated; - sway_view->iface.close = close_view; - sway_view->wlr_xwayland_surface = xsurface; - sway_view->sway_xwayland_surface = sway_surface; - sway_surface->view = sway_view; - - wl_list_init(&sway_view->unmanaged_view_link); + view->wlr_xwayland_surface = xsurface; + view->sway_xwayland_surface = sway_surface; + sway_surface->view = view; // TODO: // - Look up pid and open on appropriate workspace - // - Set new view to maximized so it behaves nicely // - Criteria wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 7d05e942..97b4473c 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -47,14 +47,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, static struct sway_container *container_at_cursor(struct sway_cursor *cursor, struct wlr_surface **surface, double *sx, double *sy) { // check for unmanaged views first - struct wl_list *unmanaged = &root_container.sway_root->unmanaged_views; - struct sway_view *view; - wl_list_for_each_reverse(view, unmanaged, unmanaged_view_link) { - if (view->type != SWAY_XWAYLAND_VIEW) { + struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; + struct sway_xwayland_unmanaged *sway_surface; + wl_list_for_each_reverse(sway_surface, unmanaged, link) { + struct wlr_xwayland_surface *xsurface = + sway_surface->wlr_xwayland_surface; + if (xsurface->surface == NULL) { continue; } - struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; struct wlr_box box = { .x = xsurface->x, .y = xsurface->y, diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 88463e3b..95a84d12 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -58,7 +58,7 @@ void layout_init(void) { root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); root_container.sway_root->output_layout = wlr_output_layout_create(); - wl_list_init(&root_container.sway_root->unmanaged_views); + wl_list_init(&root_container.sway_root->xwayland_unmanaged); wl_signal_init(&root_container.sway_root->events.new_container); root_container.sway_root->output_layout_change.notify = @@ -288,7 +288,7 @@ void arrange_windows(struct sway_container *container, { container->width = width; container->height = height; - view_set_size(container->sway_view, + view_configure(container->sway_view, container->x, container->y, container->width, container->height); wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", container->width, container->height, @@ -349,8 +349,10 @@ static void apply_horiz_layout(struct sway_container *container, wlr_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); + if (child->type == C_VIEW) { - view_set_position(child->sway_view, child_x, y); + view_configure(child->sway_view, child_x, y, child->width, + child->height); } else { child->x = child_x; child->y = y; @@ -406,7 +408,8 @@ void apply_vert_layout(struct sway_container *container, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale); if (child->type == C_VIEW) { - view_set_position(child->sway_view, x, child_y); + view_configure(child->sway_view, x, child_y, child->width, + child->height); } else { child->x = x; child->y = child_y; diff --git a/sway/tree/output.c b/sway/tree/output.c index 2331dc2b..0509db23 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -30,6 +30,7 @@ struct sway_container *container_output_destroy(struct sway_container *output) { wl_list_remove(&output->sway_output->destroy.link); wl_list_remove(&output->sway_output->mode.link); wl_list_remove(&output->sway_output->transform.link); + wl_list_remove(&output->sway_output->scale.link); wl_list_remove(&output->sway_output->damage_destroy.link); wl_list_remove(&output->sway_output->damage_frame.link); diff --git a/sway/tree/view.c b/sway/tree/view.c index b7d1a41b..09c804e4 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1,3 +1,4 @@ +#include <stdlib.h> #include <wayland-server.h> #include <wlr/types/wlr_output_layout.h> #include "log.h" @@ -6,82 +7,117 @@ #include "sway/tree/layout.h" #include "sway/tree/view.h" +struct sway_view *view_create(enum sway_view_type type, + const struct sway_view_impl *impl) { + struct sway_view *view = calloc(1, sizeof(struct sway_view)); + if (view == NULL) { + return NULL; + } + view->type = type; + view->impl = impl; + return view; +} + +void view_destroy(struct sway_view *view) { + if (view == NULL) { + return; + } + + if (view->surface != NULL) { + view_unmap(view); + } + + container_view_destroy(view->swayc); + free(view); +} + const char *view_get_title(struct sway_view *view) { - if (view->iface.get_prop) { - return view->iface.get_prop(view, VIEW_PROP_TITLE); + if (view->impl->get_prop) { + return view->impl->get_prop(view, VIEW_PROP_TITLE); } return NULL; } const char *view_get_app_id(struct sway_view *view) { - if (view->iface.get_prop) { - return view->iface.get_prop(view, VIEW_PROP_APP_ID); + if (view->impl->get_prop) { + return view->impl->get_prop(view, VIEW_PROP_APP_ID); } return NULL; } const char *view_get_class(struct sway_view *view) { - if (view->iface.get_prop) { - return view->iface.get_prop(view, VIEW_PROP_CLASS); + if (view->impl->get_prop) { + return view->impl->get_prop(view, VIEW_PROP_CLASS); } return NULL; } const char *view_get_instance(struct sway_view *view) { - if (view->iface.get_prop) { - return view->iface.get_prop(view, VIEW_PROP_INSTANCE); + if (view->impl->get_prop) { + return view->impl->get_prop(view, VIEW_PROP_INSTANCE); } return NULL; } -void view_set_size(struct sway_view *view, int width, int height) { - if (view->iface.set_size) { - struct wlr_box box = { - .x = view->swayc->x, - .y = view->swayc->y, - .width = view->width, - .height = view->height, - }; - view->iface.set_size(view, width, height); - view_update_outputs(view, &box); +void view_configure(struct sway_view *view, double ox, double oy, int width, + int height) { + if (view->impl->configure) { + view->impl->configure(view, ox, oy, width, height); } } -// TODO make view coordinates in layout coordinates -void view_set_position(struct sway_view *view, double ox, double oy) { - if (view->iface.set_position) { - struct wlr_box box = { - .x = view->swayc->x, - .y = view->swayc->y, - .width = view->width, - .height = view->height, - }; - view->iface.set_position(view, ox, oy); - view_update_outputs(view, &box); +void view_set_activated(struct sway_view *view, bool activated) { + if (view->impl->set_activated) { + view->impl->set_activated(view, activated); } } -void view_set_activated(struct sway_view *view, bool activated) { - if (view->iface.set_activated) { - view->iface.set_activated(view, activated); +void view_close(struct sway_view *view) { + if (view->impl->close) { + view->impl->close(view); } } -void view_close(struct sway_view *view) { - if (view->iface.close) { - view->iface.close(view); +struct sway_container *container_view_destroy(struct sway_container *view) { + if (!view) { + return NULL; } + wlr_log(L_DEBUG, "Destroying view '%s'", view->name); + struct sway_container *parent = container_destroy(view); + arrange_windows(parent, -1, -1); + return parent; +} + +void view_damage_whole(struct sway_view *view) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT) { + output_damage_whole_view(cont->sway_output, view); + } + } +} + +void view_damage_from(struct sway_view *view) { + // TODO + view_damage_whole(view); +} + +static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + + box->x = output->x + view->swayc->x; + box->y = output->y + view->swayc->y; + box->width = view->width; + box->height = view->height; } -void view_update_outputs(struct sway_view *view, const struct wlr_box *before) { +static void view_update_outputs(struct sway_view *view, + const struct wlr_box *before) { + struct wlr_box box; + view_get_layout_box(view, &box); + struct wlr_output_layout *output_layout = root_container.sway_root->output_layout; - struct wlr_box box = { - .x = view->swayc->x, - .y = view->swayc->y, - .width = view->width, - .height = view->height, - }; struct wlr_output_layout_output *layout_output; wl_list_for_each(layout_output, &output_layout->outputs, link) { bool intersected = before != NULL && wlr_output_layout_intersects( @@ -97,27 +133,63 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) { } } -struct sway_container *container_view_destroy(struct sway_container *view) { - if (!view) { - return NULL; +void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { + if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { + return; } - wlr_log(L_DEBUG, "Destroying view '%s'", view->name); - struct sway_container *parent = container_destroy(view); - arrange_windows(parent, -1, -1); - return parent; + + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus_inactive(seat, + &root_container); + struct sway_container *cont = container_view_create(focus, view); + + view->surface = wlr_surface; + view->swayc = cont; + + arrange_windows(cont->parent, -1, -1); + input_manager_set_focus(input_manager, cont); + + view_damage_whole(view); + view_update_outputs(view, NULL); } -void view_damage_whole(struct sway_view *view) { - struct sway_container *cont = NULL; - for (int i = 0; i < root_container.children->length; ++i) { - cont = root_container.children->items[i]; - if (cont->type == C_OUTPUT) { - output_damage_whole_view(cont->sway_output, view); - } +void view_unmap(struct sway_view *view) { + if (!sway_assert(view->surface != NULL, "cannot unmap unmapped view")) { + return; } + + view_damage_whole(view); + + container_view_destroy(view->swayc); + + view->swayc = NULL; + view->surface = NULL; } -void view_damage_from(struct sway_view *view) { - // TODO +void view_update_position(struct sway_view *view, double ox, double oy) { + if (view->swayc->x == ox && view->swayc->y == oy) { + return; + } + + struct wlr_box box; + view_get_layout_box(view, &box); + view_damage_whole(view); + view->swayc->x = ox; + view->swayc->y = oy; + view_update_outputs(view, &box); + view_damage_whole(view); +} + +void view_update_size(struct sway_view *view, int width, int height) { + if (view->width == width && view->height == height) { + return; + } + + struct wlr_box box; + view_get_layout_box(view, &box); + view_damage_whole(view); + view->width = width; + view->height = height; + view_update_outputs(view, &box); view_damage_whole(view); } |