From fcbe63d119816a20b8f139324b55866c41c1dad7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 10 Aug 2023 20:37:26 +0200 Subject: [PATCH 001/390] Adds draft graph of an object model. --- doc/Doxyfile.in | 2 +- src/toolkit/toolkit.h | 94 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index e6c20976..4ad9857e 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -2542,7 +2542,7 @@ DIAFILE_DIRS = # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = /usr/share/plantuml/plantuml.jar # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # configuration file for plantuml. diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index b9216a39..3fa44509 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -17,6 +17,100 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/** + * @page toolkit_page Toolkit Page + * + * Work in progress ... + * + * * Where do we compose, vs. inherit? + * + * @startuml + + class Element { + int x, y + struct wlr_scene_node *node_ptr + Container *container_ptr + + Element *create(void) + void destroy(Element*) + set_parent(Container*) + map() + unmap() + + {abstract}#create_node() + } + note right of Element::"map()" + Only permitted if element is a member of a (mapped?) container. + end note + + class Container { + Element parent + Element children[] + + Container *create(void) + void destroy(Container*) + add_element(Element*) + remove_element(Element*) + + map() + unmap() + } + Element <|-- Container + + class Workspace { + Container parent + + Container *create(void) + void destroy(Container*) + } + Container <|-- Workspace + + class HBox { + Container parent + } + Container <|-- HBox + + class VBox { + Container parent + } + Container <|-- VBox + + class Surface { + Element parent + } + Element <|-- Surface + + class Buffer { + Element parent + } + Element <|-- Buffer + + + class Workspace { + Container parent + + Workspace *create(void) + void destroy(Workspace*) + } + + + + class Window { + VBox parent + Surface surface + TitleBar title_bar + } + VBox <|-- Window + + class TitleBar { + HBox parent + } + HBox <|-- TitleBar + + + * @enduml + */ #ifndef __TOOLKIT_H__ #define __TOOLKIT_H__ From adbe90fbdbfee6780bd3d19d880d39fbb9b67545 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 11 Aug 2023 15:23:44 +0200 Subject: [PATCH 002/390] Adds plantuml as cmake configurable, and permit configuring criticality of doxygen errors. --- doc/CMakeLists.txt | 24 ++++++++++++++++++++++++ doc/Doxyfile.in | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index f7e0d7e3..ae1e6579 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -17,6 +17,30 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.13) FIND_PACKAGE(Doxygen) IF(DOXYGEN_FOUND) + FIND_FILE(PLANTUML_JAR + NAMES plantuml.jar + HINTS ENV{PLANTUML_JAR_PATH} + PATHS + /usr/global/share/java/plantuml/ + /usr/local/share/java/plantuml/ + /usr/share/java/ + /usr/local/share/java/ + /usr/share/plantuml/) + IF(PLANTUML_JAR) + SET(DOXYGEN_PLANTUML_JAR_FILE ${PLANTUML_JAR}) + ELSE() + SET(DOXYGEN_PLANTUML_JAR_FILE "") + MESSAGE( + NOTICE + "Did not find plantuml.jar -- Will not generate class diagrams.") + ENDIF(PLANTUML_JAR_FOUND) + + IF(config_DOXYGEN_CRITICAL) + SET(DOXYGEN_WARN_AS_ERROR "YES") + ELSE(config_DOXYGEN_CRITICAL) + SET(DOXYGEN_WARN_AS_ERROR "NO") + ENDIF(config_DOXYGEN_CRITICAL) + # set input and output files SET(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) SET(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 4ad9857e..24ca7cb3 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -828,7 +828,7 @@ WARN_NO_PARAMDOC = NO # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. -WARN_AS_ERROR = YES +WARN_AS_ERROR = @DOXYGEN_WARN_AS_ERROR@ # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -2542,7 +2542,7 @@ DIAFILE_DIRS = # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. -PLANTUML_JAR_PATH = /usr/share/plantuml/plantuml.jar +PLANTUML_JAR_PATH = @DOXYGEN_PLANTUML_JAR_FILE@ # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # configuration file for plantuml. From a3e2b809b78987e40879dd940870ef163842e507 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 11 Aug 2023 17:46:31 +0200 Subject: [PATCH 003/390] Adds thoughts on object model. --- src/toolkit/toolkit.h | 162 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 17 deletions(-) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 3fa44509..927179fb 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -24,6 +24,7 @@ * Work in progress ... * * * Where do we compose, vs. inherit? + * * How do we map tiles in a dock, or at the clip? * * @startuml @@ -32,13 +33,16 @@ struct wlr_scene_node *node_ptr Container *container_ptr - Element *create(void) + init(handlers) void destroy(Element*) set_parent(Container*) map() unmap() - {abstract}#create_node() + {abstract}#void enter(Element*) + {abstract}#void leave(Element*) + {abstract}#void click(Element*) + {abstract}#create_or_reparent_node(Element*, parent_node*) } note right of Element::"map()" Only permitted if element is a member of a (mapped?) container. @@ -53,18 +57,26 @@ add_element(Element*) remove_element(Element*) - map() - unmap() + -void enter(Element*) + -void leave(Element*) + -void click(Element*) } Element <|-- Container class Workspace { Container parent + Container layers[] Container *create(void) void destroy(Container*) + + map_window(Window*) + unmap_window(Window*) + + map_layer_element(LayerElement *, layer) + unmap_layer_element(LayerElement *, layer) } - Container <|-- Workspace + Container *-- Workspace class HBox { Container parent @@ -76,41 +88,157 @@ } Container <|-- VBox - class Surface { + abstract class Content { Element parent + + init(handlers) + + {abstract}#void set_active(bool) + {abstract}#void set_maximized(bool) + {abstract}#void set_fullscreen(bool) + {abstract}#void enter(Element*) + {abstract}#void leave(Element*) + {abstract}#void click(Element*) } - Element <|-- Surface + Element <|-- Content + note right of Content + Interface for Window contents. + A surface (or... buffer? ...). Ultimately wraps a node, + thus may be an element. + end note - class Buffer { + class LayerElement { Element parent - } - Element <|-- Buffer + {abstract}#void enter(Element*) + {abstract}#void leave(Element*) + {abstract}#void click(Element*) - class Workspace { - Container parent + {abstract}#configure() + } + Element <|-- LayerElement - Workspace *create(void) - void destroy(Workspace*) + class LayerShell { } + LayerElement <|-- LayerShell + class XdgToplevelSurface { + } + Content <|-- XdgToplevelSurface + class Buffer { + Element parent + } + Element <|-- Buffer + + class Button { + + } + Buffer <|-- Button class Window { VBox parent - Surface surface + Content content TitleBar title_bar } - VBox <|-- Window + VBox *-- Window class TitleBar { HBox parent } - HBox <|-- TitleBar + HBox *-- TitleBar + + class Menu { + VBox parent + } + VBox *-- Menu + + class MenuItem { + } + Buffer <|-- MenuItem * @enduml + * + * */ + +#if 0 +// Scenario: Create a window + +xdg_toplevel... => on handle_new_surface + +* XdgToplevelSurface::create(wlr surface) + * listeners for map, unmap, destroy + + => so yes, what will this do when mapped? + +* Window::create(surface) + * registers the window for workspace + + * creates the container, with parent of window::element + * if decoration: + + + + +* will setup listeners for the various events, ... + * request maximize + * request move + * request show window menu + * set title + * ... + + + +set title handler: +* window::set_title + +request maximize handler: +* window::request_maximize + * window::set_maximized + * internally: get view from workspace, ... set_size + * callback to surface (if set): set_maximized + + +upon surface::map + +* workspace::add_window(window) (unsure: do we need this?) + => should set "container" of window::parent...::element to workspace::container + (ie. set_parent(...); and add "element" to "container") + +* workspace::map_window(window) + => this should add window to the set of workspace::mapped_windows + => window::element->container -> map_element(element) + (expects the container to be mapped) + + => will call map(node?) on window::element + - is implemented in Container: + - create a scene tree (from parent's node) oc reparent (from parent) + - calls map for every item in container + + +upon surface::unmap +* workspace::unmap_window + + => window::element->container -> unmap_element(element) + => will call unmap() on window::element + => destroy the node + +* workspace::remove_window(window) (do we need this?) + + + + +There is a click ("pointer button event") -> goes to workspace. + +* use node lookup -> should give data -> element +* element::click(...) +* Button::click gets called. Has a "button_from_element" & goes from there. + +#endif + + #ifndef __TOOLKIT_H__ #define __TOOLKIT_H__ From ee71bb88cc5068fd57ec33c630dfebed2cc2c66e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 11 Aug 2023 21:18:59 +0200 Subject: [PATCH 004/390] Adds some ideas around the Dock/Clip object model. --- src/toolkit/toolkit.h | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 927179fb..cd9825bb 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -24,7 +24,6 @@ * Work in progress ... * * * Where do we compose, vs. inherit? - * * How do we map tiles in a dock, or at the clip? * * @startuml @@ -161,6 +160,35 @@ * @enduml * * + * @startuml + + class Dock { + Container container[] + DockEntry entries[] + } + + class DockEntry { + Element + } + + class Launcher { + } + DockEntry <|-- Launcher + + class Icon {} + DockEntry <|-- Icon + + class IconSurface {} + DockEntry <|-- IconSurface + + class Clip {} + Dock <|-- Clip + + class IconArea {} + Dock <|-- IconArea + + + * @enduml */ #if 0 @@ -214,7 +242,7 @@ upon surface::map => will call map(node?) on window::element - is implemented in Container: - - create a scene tree (from parent's node) oc reparent (from parent) + - create a scene tree (from parents node) oc reparent (from parent) - calls map for every item in container From eb39aadfcb27487a2cbe6471ab3570ca086f1c58 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 18 Aug 2023 14:47:09 +0200 Subject: [PATCH 005/390] Adds a configurable whether to fail on doxygen warnings. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec20896e..8d9746fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ PKG_CHECK_MODULES(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon>=1.0.3) # 1.4.1) # Configuration. Remove CMakeCache.txt to rerun... OPTION(config_DEBUG "Include debugging information" ON) OPTION(config_OPTIM "Optimizations" OFF) +OPTION(config_DOXYGEN_CRITICAL "Whether to fail on doxygen warnings" OFF) # Toplevel compile options, for GCC. IF(CMAKE_C_COMPILER_ID STREQUAL "GNU") From c5bc1d5f58b0709b7ab320bcc76685919cab3866 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 18 Aug 2023 15:16:37 +0200 Subject: [PATCH 006/390] Moves the class hierarchy and user journeys into a markdown file. --- src/toolkit/toolkit.h | 252 +--------------------------------------- src/toolkit/toolkit.md | 255 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+), 250 deletions(-) create mode 100644 src/toolkit/toolkit.md diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index cd9825bb..ed7e0abf 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -2,6 +2,8 @@ /** * @file toolkit.h * + * See @ref toolkit_page for documentation. + * * @copyright * Copyright 2023 Google LLC * @@ -17,256 +19,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @page toolkit_page Toolkit Page - * - * Work in progress ... - * - * * Where do we compose, vs. inherit? - * - * @startuml - - class Element { - int x, y - struct wlr_scene_node *node_ptr - Container *container_ptr - - init(handlers) - void destroy(Element*) - set_parent(Container*) - map() - unmap() - - {abstract}#void enter(Element*) - {abstract}#void leave(Element*) - {abstract}#void click(Element*) - {abstract}#create_or_reparent_node(Element*, parent_node*) - } - note right of Element::"map()" - Only permitted if element is a member of a (mapped?) container. - end note - - class Container { - Element parent - Element children[] - - Container *create(void) - void destroy(Container*) - add_element(Element*) - remove_element(Element*) - - -void enter(Element*) - -void leave(Element*) - -void click(Element*) - } - Element <|-- Container - - class Workspace { - Container parent - Container layers[] - - Container *create(void) - void destroy(Container*) - - map_window(Window*) - unmap_window(Window*) - - map_layer_element(LayerElement *, layer) - unmap_layer_element(LayerElement *, layer) - } - Container *-- Workspace - - class HBox { - Container parent - } - Container <|-- HBox - - class VBox { - Container parent - } - Container <|-- VBox - - abstract class Content { - Element parent - - init(handlers) - - {abstract}#void set_active(bool) - {abstract}#void set_maximized(bool) - {abstract}#void set_fullscreen(bool) - {abstract}#void enter(Element*) - {abstract}#void leave(Element*) - {abstract}#void click(Element*) - } - Element <|-- Content - note right of Content - Interface for Window contents. - A surface (or... buffer? ...). Ultimately wraps a node, - thus may be an element. - end note - - class LayerElement { - Element parent - - {abstract}#void enter(Element*) - {abstract}#void leave(Element*) - {abstract}#void click(Element*) - - {abstract}#configure() - } - Element <|-- LayerElement - - class LayerShell { - } - LayerElement <|-- LayerShell - - class XdgToplevelSurface { - } - Content <|-- XdgToplevelSurface - - class Buffer { - Element parent - } - Element <|-- Buffer - - class Button { - - } - Buffer <|-- Button - - class Window { - VBox parent - Content content - TitleBar title_bar - } - VBox *-- Window - - class TitleBar { - HBox parent - } - HBox *-- TitleBar - - class Menu { - VBox parent - } - VBox *-- Menu - - class MenuItem { - - } - Buffer <|-- MenuItem - - * @enduml - * - * - * @startuml - - class Dock { - Container container[] - DockEntry entries[] - } - - class DockEntry { - Element - } - - class Launcher { - } - DockEntry <|-- Launcher - - class Icon {} - DockEntry <|-- Icon - - class IconSurface {} - DockEntry <|-- IconSurface - - class Clip {} - Dock <|-- Clip - - class IconArea {} - Dock <|-- IconArea - - - * @enduml - */ - -#if 0 -// Scenario: Create a window - -xdg_toplevel... => on handle_new_surface - -* XdgToplevelSurface::create(wlr surface) - * listeners for map, unmap, destroy - - => so yes, what will this do when mapped? - -* Window::create(surface) - * registers the window for workspace - - * creates the container, with parent of window::element - * if decoration: - - - - -* will setup listeners for the various events, ... - * request maximize - * request move - * request show window menu - * set title - * ... - - - -set title handler: -* window::set_title - -request maximize handler: -* window::request_maximize - * window::set_maximized - * internally: get view from workspace, ... set_size - * callback to surface (if set): set_maximized - - -upon surface::map - -* workspace::add_window(window) (unsure: do we need this?) - => should set "container" of window::parent...::element to workspace::container - (ie. set_parent(...); and add "element" to "container") - -* workspace::map_window(window) - => this should add window to the set of workspace::mapped_windows - => window::element->container -> map_element(element) - (expects the container to be mapped) - - => will call map(node?) on window::element - - is implemented in Container: - - create a scene tree (from parents node) oc reparent (from parent) - - calls map for every item in container - - -upon surface::unmap -* workspace::unmap_window - - => window::element->container -> unmap_element(element) - => will call unmap() on window::element - => destroy the node - -* workspace::remove_window(window) (do we need this?) - - - - -There is a click ("pointer button event") -> goes to workspace. - -* use node lookup -> should give data -> element -* element::click(...) -* Button::click gets called. Has a "button_from_element" & goes from there. - -#endif - - #ifndef __TOOLKIT_H__ #define __TOOLKIT_H__ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md new file mode 100644 index 00000000..257742fb --- /dev/null +++ b/src/toolkit/toolkit.md @@ -0,0 +1,255 @@ + +# Toolkit {#toolkit_page} + +## Compositor Elements + +### Class Hierarchy + +* Where do we use composition, vs. inheritance? + +```plantuml +class Element { + int x, y + struct wlr_scene_node *node_ptr + Container *container_ptr + + init(handlers) + void destroy(Element*) + set_parent(Container*) + map() + unmap() + + {abstract}#void enter(Element*) + {abstract}#void leave(Element*) + {abstract}#void click(Element*) + {abstract}#create_or_reparent_node(Element*, parent_node*) +} +note right of Element::"map()" + Only permitted if element is a member of a (mapped?) container. +end note + +class Container { + Element parent + Element children[] + + Container *create(void) + void destroy(Container*) + add_element(Element*) + remove_element(Element*) + + -void enter(Element*) + -void leave(Element*) + -void click(Element*) +} +Element <|-- Container + +class Workspace { + Container parent + Container layers[] + + Container *create(void) + void destroy(Container*) + + map_window(Window*) + unmap_window(Window*) + + map_layer_element(LayerElement *, layer) + unmap_layer_element(LayerElement *, layer) +} +Container *-- Workspace + +class HBox { + Container parent +} +Container <|-- HBox + +class VBox { + Container parent +} +Container <|-- VBox + +abstract class Content { + Element parent + + init(handlers) + + {abstract}#void set_active(bool) + {abstract}#void set_maximized(bool) + {abstract}#void set_fullscreen(bool) + {abstract}#void enter(Element*) + {abstract}#void leave(Element*) + {abstract}#void click(Element*) +} +Element <|-- Content +note right of Content + Interface for Window contents. + A surface (or... buffer? ...). Ultimately wraps a node, + thus may be an element. +end note + +class LayerElement { + Element parent + + {abstract}#void enter(Element*) + {abstract}#void leave(Element*) + {abstract}#void click(Element*) + + {abstract}#configure() + } +Element <|-- LayerElement + +class LayerShell { +} +LayerElement <|-- LayerShell + +class XdgToplevelSurface { +} +Content <|-- XdgToplevelSurface + +class Buffer { + Element parent +} +Element <|-- Buffer + +class Button { + +} +Buffer <|-- Button + +class Window { + VBox parent + Content content + TitleBar title_bar +} +VBox *-- Window + +class TitleBar { + HBox parent +} +HBox *-- TitleBar + +class Menu { + VBox parent +} +VBox *-- Menu + +class MenuItem { + +} +Buffer <|-- MenuItem +``` + +### User Journeys + +#### Creating a new XDG toplevel + +* xdg_toplevel... => on handle_new_surface + + * XdgToplevelSurface::create(wlr surface) + * listeners for map, unmap, destroy + + => so yes, what will this do when mapped? + + * Window::create(surface) + * registers the window for workspace + + * creates the container, with parent of window element + * if decoration: + + + * will setup listeners for the various events, ... + * request maximize + * request move + * request show window menu + * set title + * ... + + + set title handler: + + * window::set_title + + request maximize handler: + * window::request_maximize + * window::set_maximized + * internally: get view from workspace, ... set_size + * callback to surface (if set): set_maximized + + + upon surface::map + + * workspace::add_window(window) (unsure: do we need this?) + => should set "container" of window parent... element to workspace::container + (ie. set_parent(...); and add "element" to "container") + + * workspace::map_window(window) + => this should add window to the set of workspace::mapped_windows + => window element->container -> map_element(element) + (expects the container to be mapped) + + => will call map(node?) on window element + - is implemented in Container: + - create a scene tree (from parents node) oc reparent (from parent) + - calls map for every item in container + + upon surface::unmap + * workspace::unmap_window + + => window element->container -> unmap_element(element) + => will call unmap() on window element + => destroy the node + + * workspace::remove_window(window) (do we need this?) + + +There is a click ("pointer button event") -> goes to workspace. + + * use node lookup -> should give data -> element + * element::click(...) + * Button::click gets called. Has a "button_from_element" & goes from there. + + + +## Dock and Clip class elements + +```plantuml +class Dock { + Container container[] + DockEntry entries[] +} + +class DockEntry { + Element +} + +class Launcher { +} +DockEntry <|-- Launcher + +class Icon {} +DockEntry <|-- Icon + +class IconSurface {} +DockEntry <|-- IconSurface + +class Clip {} +Dock <|-- Clip + +class IconArea {} +Dock <|-- IconArea +``` + From 9b064137f5fd0d47e8952d63a1394fca38a4d5f3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 18 Aug 2023 17:41:55 +0200 Subject: [PATCH 007/390] Adds boiler plate basics for the toolkit's Element and Container classes. --- src/toolkit/CMakeLists.txt | 5 +- src/toolkit/container.c | 102 ++++++++++++++++++++++++++ src/toolkit/element.c | 73 +++++++++++++++++++ src/toolkit/toolkit.h | 146 +++++++++++++++++++++++++++++++++++++ 4 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 src/toolkit/container.c create mode 100644 src/toolkit/element.c diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 4de4648e..6f090bd7 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -17,10 +17,13 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.13) SET(PUBLIC_HEADER_FILES gfxbuf.h primitives.h - style.h) + style.h + toolkit.h) ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE + element.c + container.c gfxbuf.c primitives.c) TARGET_INCLUDE_DIRECTORIES( diff --git a/src/toolkit/container.c b/src/toolkit/container.c new file mode 100644 index 00000000..21432caa --- /dev/null +++ b/src/toolkit/container.c @@ -0,0 +1,102 @@ +/* ========================================================================= */ +/** + * @file container.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toolkit.h" + +/* == Declarations ========================================================= */ + +static void element_destroy(wlmtk_element_t *element_ptr); + +/** Virtual method table for the container's super class: Element. */ +static const wlmtk_element_impl_t super_element_impl = { + .destroy = element_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_container_init( + wlmtk_container_t *container_ptr, + const wlmtk_container_impl_t *container_impl_ptr) +{ + BS_ASSERT(NULL != container_ptr); + BS_ASSERT(NULL != container_impl_ptr); + memset(container_ptr, 0, sizeof(wlmtk_container_t)); + + if (!wlmtk_element_init(&container_ptr->super_element, + &super_element_impl)) { + return false; + } + + container_ptr->impl_ptr = container_impl_ptr; + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_container_fini(wlmtk_container_t *container_ptr) +{ + bs_dllist_node_t *dlnode_ptr; + while (NULL != (dlnode_ptr = container_ptr->elements.head_ptr)) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + wlmtk_container_remove_element(container_ptr, element_ptr); + BS_ASSERT(container_ptr->elements.head_ptr != dlnode_ptr); + } + + wlmtk_element_fini(&container_ptr->super_element); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_container_add_element( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr) +{ + bs_dllist_push_back( + &container_ptr->elements, + wlmtk_dlnode_from_element(element_ptr)); + wlmtk_element_set_parent_container(element_ptr, container_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_container_remove_element( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr) +{ + wlmtk_element_set_parent_container(element_ptr, NULL); + bs_dllist_remove( + &container_ptr->elements, + wlmtk_dlnode_from_element(element_ptr)); +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::destroy method. + * + * @param element_ptr + */ +void element_destroy(wlmtk_element_t *element_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + container_ptr->impl_ptr->destroy(container_ptr); +} + +/* == End of container.c =================================================== */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c new file mode 100644 index 00000000..8de4f27a --- /dev/null +++ b/src/toolkit/element.c @@ -0,0 +1,73 @@ +/* ========================================================================= */ +/** + * @file element.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toolkit.h" + +/* == Declarations ========================================================= */ + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_element_init( + wlmtk_element_t *element_ptr, + const wlmtk_element_impl_t *element_impl_ptr) +{ + BS_ASSERT(NULL != element_ptr); + BS_ASSERT(NULL != element_impl_ptr); + memset(element_ptr, 0, sizeof(wlmtk_element_t)); + + element_ptr->impl_ptr = element_impl_ptr; + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_element_fini( + wlmtk_element_t *element_ptr) +{ + // Verify we're no longer mapped, nor part of a container. + BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + BS_ASSERT(NULL == element_ptr->container_ptr); +} + +/* ------------------------------------------------------------------------- */ +bs_dllist_node_t *wlmtk_dlnode_from_element( + wlmtk_element_t *element_ptr) +{ + return &element_ptr->dlnode; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_element_from_dlnode( + bs_dllist_node_t *dlnode_ptr) +{ + return BS_CONTAINER_OF(dlnode_ptr, wlmtk_element_t, dlnode); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_element_set_parent_container( + wlmtk_element_t *element_ptr, + wlmtk_container_t *parent_container_ptr) +{ + element_ptr->container_ptr = parent_container_ptr; +} + +/* == Local (static) methods =============================================== */ + +/* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index ed7e0abf..708b6b11 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -26,10 +26,156 @@ #include "primitives.h" #include "style.h" +#include + #ifdef __cplusplus extern "C" { #endif // __cplusplus +/** Forward declaration: Element. */ +typedef struct _wlmtk_element_t wlmtk_element_t; +/** Forward declaration: Container. */ +typedef struct _wlmtk_container_t wlmtk_container_t; + +/** Forward declaration: Element virtual method implementations. */ +typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; +/** Forward declaration: Container virtual method implementations. */ +typedef struct _wlmtk_container_impl_t wlmtk_container_impl_t; + +/** State of an element. */ +struct _wlmtk_element_t { + /** X position of the element, relative to the container. */ + int x; + /** Y position of the element, relative to the container. */ + int y; + + /** wlroots scene graph API node. Only set when mapped. */ + struct wlr_scene_node_t *wlr_scene_node_ptr; + /** The container this element belongs to, if any. */ + wlmtk_container_t *container_ptr; + /** The node of elements. */ + bs_dllist_node_t dlnode; + + /** Implementation of abstract virtual methods. */ + const wlmtk_element_impl_t *impl_ptr; +}; + +/** Pointers to the implementation of Element's virtual methods. */ +struct _wlmtk_element_impl_t { + /** Destroys the implementation of the element. */ + void (*destroy)(wlmtk_element_t *element_ptr); +}; + +/** + * Initializes the element. + * + * @param element_ptr + * @param element_impl_ptr + * + * @return true on success. + */ +bool wlmtk_element_init( + wlmtk_element_t *element_ptr, + const wlmtk_element_impl_t *element_impl_ptr); + +/** + * Cleans up the element. + * + * @param element_ptr + */ +void wlmtk_element_fini( + wlmtk_element_t *element_ptr); + +/** Gets the dlnode from the element. */ +bs_dllist_node_t *wlmtk_dlnode_from_element( + wlmtk_element_t *element_ptr); +/** Gets the element from the dlnode. */ +wlmtk_element_t *wlmtk_element_from_dlnode( + bs_dllist_node_t *dlnode_ptr); + +/** + * Sets the parent container for the element. + * + * Should only be called by wlmtk_container_add_element, respectively + * wlmtk_container_remove_element. + * + * @param element_ptr + * @param parent_container_ptr Pointer to the parent contqainer, or NULL if + * the parent should be cleared. + */ +void wlmtk_element_set_parent_container( + wlmtk_element_t *element_ptr, + wlmtk_container_t *parent_container_ptr); + +/** Virtual method: Calls the dtor of the element's implementation. */ +static inline void wlmtk_element_destroy( + wlmtk_element_t *element_ptr) { + element_ptr->impl_ptr->destroy(element_ptr); +} + +/** State of the container. */ +struct _wlmtk_container_t { + /** Super class of the container. */ + wlmtk_element_t super_element; + + /** Elements contained here. */ + bs_dllist_t elements; + + /** Implementation of the container's virtual methods. */ + const wlmtk_container_impl_t *impl_ptr; +}; + +/** Virtual method table of the container. */ +struct _wlmtk_container_impl_t { + /** dtor. */ + void (*destroy)(wlmtk_container_t *container_ptr); +}; + +/** + * Initializes the container with the provided virtual method table. + * + * @param container_ptr + * @param container_impl_ptr + * + * @return true on success. + */ +bool wlmtk_container_init( + wlmtk_container_t *container_ptr, + const wlmtk_container_impl_t *container_impl_ptr); + +/** + * Un-initializes the container. + * + * @param container_ptr + */ +void wlmtk_container_fini( + wlmtk_container_t *container_ptr); + +/** + * Adds `element_ptr` to the container. + * + * @param container_ptr + * @param element_ptr + */ +void wlmtk_container_add_element( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr); + +/** + * Removes `element_ptr` from the container. + * + * @param container_ptr + * @param element_ptr + */ +void wlmtk_container_remove_element( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr); + +/** Virtual method: Calls the dtor of the container's implementation. */ +static inline void wlmtk_container_destroy( + wlmtk_container_t *container_ptr) { + container_ptr->impl_ptr->destroy(container_ptr); +} #ifdef __cplusplus From 957fe515026cd5bdb46b5dc54947851975084612 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 19 Aug 2023 13:44:51 +0200 Subject: [PATCH 008/390] Adds the framework for unit tests in element. --- src/toolkit/element.c | 6 ++++++ src/toolkit/toolkit.h | 5 +++++ src/toolkit/toolkit_test.c | 1 + 3 files changed, 12 insertions(+) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 8de4f27a..0d5c9131 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -70,4 +70,10 @@ void wlmtk_element_set_parent_container( /* == Local (static) methods =============================================== */ +/* == Unit tests =========================================================== */ + +const bs_test_case_t wlmtk_element_test_cases[] = { + { 0, NULL, NULL } +}; + /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 708b6b11..391cb778 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -113,6 +113,11 @@ static inline void wlmtk_element_destroy( element_ptr->impl_ptr->destroy(element_ptr); } +/** Unit tests for the element. */ +extern const bs_test_case_t wlmtk_element_test_cases[]; + +/* ========================================================================= */ + /** State of the container. */ struct _wlmtk_container_t { /** Super class of the container. */ diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 89fbcef5..3ed61fcd 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -22,6 +22,7 @@ /** Toolkit unit tests. */ const bs_test_set_t toolkit_tests[] = { + { 1, "element", wlmtk_element_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } }; From e08e434acee8b223c7f4567957687643b2cf927e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 19 Aug 2023 13:54:26 +0200 Subject: [PATCH 009/390] Adds the framework for unit tests in element. --- src/toolkit/element.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 0d5c9131..0f96e6f0 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -44,6 +44,8 @@ void wlmtk_element_fini( // Verify we're no longer mapped, nor part of a container. BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); BS_ASSERT(NULL == element_ptr->container_ptr); + + element_ptr->impl_ptr = NULL; } /* ------------------------------------------------------------------------- */ @@ -72,8 +74,31 @@ void wlmtk_element_set_parent_container( /* == Unit tests =========================================================== */ + + const bs_test_case_t wlmtk_element_test_cases[] = { { 0, NULL, NULL } }; +static bool test_destroy_cb_called; + +void test_destroy_cb(wlmtk_element_t *element_ptr) +{ + wlmtk_element_fini(element_ptr); +} + +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_element_t element; + wlmtk_element_impl_t impl = { .destroy = test_destroy_cb }; + + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &impl)); + + test_destroy_cb_called = false; + wlmtk_element_destroy(&element); + BS_TEST_VERIFY_TRUE(test_ptr, test_destroy_cb_called); + + BS_TEST_VERIFY_EQ(test_ptr, element.impl_ptr); +} + /* == End of toolkit.c ===================================================== */ From a4e6b0713d6eba6ce22c8518b65f5ca050b325dd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 19 Aug 2023 14:19:30 +0200 Subject: [PATCH 010/390] Adds test cases for container. --- src/toolkit/container.c | 83 ++++++++++++++++++++++++++++++++++++++ src/toolkit/element.c | 18 ++++++--- src/toolkit/toolkit.h | 6 ++- src/toolkit/toolkit_test.c | 1 + 4 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 21432caa..3cf15a39 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -57,9 +57,12 @@ void wlmtk_container_fini(wlmtk_container_t *container_ptr) wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); wlmtk_container_remove_element(container_ptr, element_ptr); BS_ASSERT(container_ptr->elements.head_ptr != dlnode_ptr); + + wlmtk_element_destroy(element_ptr); } wlmtk_element_fini(&container_ptr->super_element); + container_ptr->impl_ptr = NULL; } /* ------------------------------------------------------------------------- */ @@ -99,4 +102,84 @@ void element_destroy(wlmtk_element_t *element_ptr) container_ptr->impl_ptr->destroy(container_ptr); } +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); +static void test_add_remove(bs_test_t *test_ptr); + +/* == End of container.c =================================================== */ + +const bs_test_case_t wlmtk_container_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 1, "add_remove", test_add_remove }, + { 0, NULL, NULL } +}; + +/** dtor for the container under test. */ +static void test_destroy_cb(wlmtk_container_t *container_ptr) +{ + wlmtk_container_fini(container_ptr); +} + +/** dtor for the element under test. */ +static void test_element_destroy_cb(wlmtk_element_t *element_ptr) +{ + wlmtk_element_fini(element_ptr); +} + +/** Method table for the container we're using for test. */ +static const wlmtk_container_impl_t test_container_impl = { + .destroy = test_destroy_cb +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises init() and fini() methods, verifies dtor forwarding. */ +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( + &container, &test_container_impl)); + // Also expect the super element to be initialized. + BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.impl_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl_ptr); + + wlmtk_container_destroy(&container); + + // Also expect the super element to be un-initialized. + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.impl_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.impl_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Exercises adding and removing elements, verifies destruction on fini. */ +void test_add_remove(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( + &container, &test_container_impl)); + + wlmtk_element_t element1, element2, element3; + wlmtk_element_impl_t impl = { .destroy = test_element_destroy_cb }; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element1, &impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element2, &impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element3, &impl)); + + wlmtk_container_add_element(&container, &element1); + BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, &container); + wlmtk_container_add_element(&container, &element2); + BS_TEST_VERIFY_EQ(test_ptr, element2.parent_container_ptr, &container); + wlmtk_container_add_element(&container, &element3); + BS_TEST_VERIFY_EQ(test_ptr, element3.parent_container_ptr, &container); + + wlmtk_container_remove_element(&container, &element2); + BS_TEST_VERIFY_EQ(test_ptr, element2.parent_container_ptr, NULL); + + wlmtk_container_destroy(&container); + BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, NULL); + BS_TEST_VERIFY_EQ(test_ptr, element3.parent_container_ptr, NULL); + + BS_TEST_VERIFY_EQ(test_ptr, element1.impl_ptr, NULL); + BS_TEST_VERIFY_EQ(test_ptr, element3.impl_ptr, NULL); +} + /* == End of container.c =================================================== */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 0f96e6f0..c9278631 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -31,6 +31,7 @@ bool wlmtk_element_init( { BS_ASSERT(NULL != element_ptr); BS_ASSERT(NULL != element_impl_ptr); + BS_ASSERT(NULL != element_impl_ptr->destroy); memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; @@ -43,7 +44,7 @@ void wlmtk_element_fini( { // Verify we're no longer mapped, nor part of a container. BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); - BS_ASSERT(NULL == element_ptr->container_ptr); + BS_ASSERT(NULL == element_ptr->parent_container_ptr); element_ptr->impl_ptr = NULL; } @@ -67,26 +68,31 @@ void wlmtk_element_set_parent_container( wlmtk_element_t *element_ptr, wlmtk_container_t *parent_container_ptr) { - element_ptr->container_ptr = parent_container_ptr; + element_ptr->parent_container_ptr = parent_container_ptr; } /* == Local (static) methods =============================================== */ /* == Unit tests =========================================================== */ - +static void test_init_fini(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { + { 1, "init_fini", test_init_fini }, { 0, NULL, NULL } }; +/** Reports whether the fake dtor was called. */ static bool test_destroy_cb_called; - -void test_destroy_cb(wlmtk_element_t *element_ptr) +/** dtor for the element under test. */ +static void test_destroy_cb(wlmtk_element_t *element_ptr) { + test_destroy_cb_called = true; wlmtk_element_fini(element_ptr); } +/* ------------------------------------------------------------------------- */ +/** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_element_t element; @@ -98,7 +104,7 @@ void test_init_fini(bs_test_t *test_ptr) wlmtk_element_destroy(&element); BS_TEST_VERIFY_TRUE(test_ptr, test_destroy_cb_called); - BS_TEST_VERIFY_EQ(test_ptr, element.impl_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl_ptr); } /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 391cb778..07b5e84d 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -52,7 +52,7 @@ struct _wlmtk_element_t { /** wlroots scene graph API node. Only set when mapped. */ struct wlr_scene_node_t *wlr_scene_node_ptr; /** The container this element belongs to, if any. */ - wlmtk_container_t *container_ptr; + wlmtk_container_t *parent_container_ptr; /** The node of elements. */ bs_dllist_node_t dlnode; @@ -151,6 +151,8 @@ bool wlmtk_container_init( /** * Un-initializes the container. * + * Any element still in `elements` will be destroyed. + * * @param container_ptr */ void wlmtk_container_fini( @@ -182,6 +184,8 @@ static inline void wlmtk_container_destroy( container_ptr->impl_ptr->destroy(container_ptr); } +/** Unit tests for the element. */ +extern const bs_test_case_t wlmtk_container_test_cases[]; #ifdef __cplusplus } // extern "C" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 3ed61fcd..33ce5bdc 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -22,6 +22,7 @@ /** Toolkit unit tests. */ const bs_test_set_t toolkit_tests[] = { + { 1, "container", wlmtk_container_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } From 4f132a6d0275dcf968080cd2b43f30b05215df70 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 19 Aug 2023 15:21:16 +0200 Subject: [PATCH 011/390] Adds boilerplate for toolkit's workspace. --- src/toolkit/CMakeLists.txt | 3 +- src/toolkit/toolkit.h | 20 +++++++++++ src/toolkit/workspace.c | 74 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/toolkit/workspace.c diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 6f090bd7..57b05cbb 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -25,7 +25,8 @@ TARGET_SOURCES(toolkit PRIVATE element.c container.c gfxbuf.c - primitives.c) + primitives.c + workspace.c) TARGET_INCLUDE_DIRECTORIES( toolkit PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 07b5e84d..58b3e2a6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -187,6 +187,26 @@ static inline void wlmtk_container_destroy( /** Unit tests for the element. */ extern const bs_test_case_t wlmtk_container_test_cases[]; +/* ========================================================================= */ + +/** State of the workspace. */ +typedef struct _wlmtk_workspace_t wlmtk_workspace_t; + +/** + * Creates a workspace. + * + * @return Pointer to the workspace state, or NULL on error. Must be free'd + * via @ref wlmtk_workspace_destroy. + */ +wlmtk_workspace_t *wlmtk_workspace_create(void); + +/** + * Destroys the workspace. Will destroy any still-mapped element. + * + * @param workspace_ptr + */ +void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c new file mode 100644 index 00000000..2b7b37c3 --- /dev/null +++ b/src/toolkit/workspace.c @@ -0,0 +1,74 @@ +/* ========================================================================= */ +/** + * @file workspace.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toolkit.h" + +/* == Declarations ========================================================= */ + +/** State of the workspace. */ +struct _wlmtk_workspace_t { + /** Superclass: Container. */ + wlmtk_container_t super_container; +}; + +static void workspace_container_destroy(wlmtk_container_t *container_ptr); + +/** Method table for the container's virtual methods. */ +const wlmtk_container_impl_t workspace_container_impl = { + .destroy = workspace_container_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_workspace_t *wlmtk_workspace_create(void) +{ + wlmtk_workspace_t *workspace_ptr = + logged_calloc(1, sizeof(wlmtk_workspace_t)); + if (NULL == workspace_ptr) return NULL; + + if (!wlmtk_container_init(&workspace_ptr->super_container, + &workspace_container_impl)) { + wlmtk_workspace_destroy(workspace_ptr); + return NULL; + } + + return workspace_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) +{ + wlmtk_container_fini(&workspace_ptr->super_container); + free(workspace_ptr); +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, in case called from container. Wraps to our dtor. */ +void workspace_container_destroy(wlmtk_container_t *container_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_workspace_t, super_container); + wlmtk_workspace_destroy(workspace_ptr); +} + +/* == End of workspace.c =================================================== */ From cbe1b1b009e4b0a715e66713142d7cf01e9abc0d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 19 Aug 2023 16:57:23 +0200 Subject: [PATCH 012/390] Adds the doxygen flag preference. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbe069a3..1fb849f5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ for existing and planned features. ### To configure ```bash -cmake -B build/ -DCMAKE_INSTALL_PREFIX="${HOME}/.local" +cmake -Dconfig_DOXYGEN_CRITICAL=ON -DCMAKE_INSTALL_PREFIX="${HOME}/.local" -B build/ ``` ### To build From 0fb85449d0c3a4f5e547dd4d1cf2f8124115f708 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 19 Aug 2023 16:58:19 +0200 Subject: [PATCH 013/390] Adds the scene graph implementation and wires them into the element's map and unmap methods. --- src/toolkit/container.c | 41 +++++++++++++++++++++++++++- src/toolkit/element.c | 24 +++++++++++++++++ src/toolkit/toolkit.h | 55 +++++++++++++++++++++++++++++++++++--- src/toolkit/toolkit_test.c | 1 + src/toolkit/workspace.c | 55 +++++++++++++++++++++++++++++++++++++- 5 files changed, 170 insertions(+), 6 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 3cf15a39..3dd166d6 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -20,13 +20,21 @@ #include "toolkit.h" +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + /* == Declarations ========================================================= */ static void element_destroy(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_impl_t super_element_impl = { - .destroy = element_destroy + .destroy = element_destroy, + .create_scene_node = element_create_scene_node }; /* == Exported methods ===================================================== */ @@ -87,6 +95,13 @@ void wlmtk_container_remove_element( wlmtk_dlnode_from_element(element_ptr)); } +/* ------------------------------------------------------------------------- */ +struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( + wlmtk_container_t *container_ptr) +{ + return container_ptr->wlr_scene_tree_ptr; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -102,6 +117,30 @@ void element_destroy(wlmtk_element_t *element_ptr) container_ptr->impl_ptr->destroy(container_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::create_scene_node method. + * + * @param element_ptr + * @param wlr_scene_tree_ptr + * + * @return Pointer to the scene graph API node. + */ +struct wlr_scene_node *element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + + BS_ASSERT(NULL == container_ptr->wlr_scene_tree_ptr); + container_ptr->wlr_scene_tree_ptr = wlr_scene_tree_create( + wlr_scene_tree_ptr); + BS_ASSERT(NULL != container_ptr->wlr_scene_tree_ptr); + + return &container_ptr->wlr_scene_tree_ptr->node; +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index c9278631..34f462ce 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -20,6 +20,10 @@ #include "toolkit.h" +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + /* == Declarations ========================================================= */ /* == Exported methods ===================================================== */ @@ -71,6 +75,26 @@ void wlmtk_element_set_parent_container( element_ptr->parent_container_ptr = parent_container_ptr; } +/* ------------------------------------------------------------------------- */ +void wlmtk_element_map(wlmtk_element_t *element_ptr) +{ + BS_ASSERT(NULL != element_ptr->parent_container_ptr); + BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + + element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( + element_ptr, + wlmtk_container_wlr_scene_tree(element_ptr->parent_container_ptr)); + BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_element_unmap(wlmtk_element_t *element_ptr) +{ + BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); + wlr_scene_node_destroy(element_ptr->wlr_scene_node_ptr); + element_ptr->wlr_scene_node_ptr = NULL; +} + /* == Local (static) methods =============================================== */ /* == Unit tests =========================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 58b3e2a6..9bd83a7a 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -32,6 +32,8 @@ extern "C" { #endif // __cplusplus +struct wlr_scene_tree; + /** Forward declaration: Element. */ typedef struct _wlmtk_element_t wlmtk_element_t; /** Forward declaration: Container. */ @@ -49,8 +51,6 @@ struct _wlmtk_element_t { /** Y position of the element, relative to the container. */ int y; - /** wlroots scene graph API node. Only set when mapped. */ - struct wlr_scene_node_t *wlr_scene_node_ptr; /** The container this element belongs to, if any. */ wlmtk_container_t *parent_container_ptr; /** The node of elements. */ @@ -58,12 +58,19 @@ struct _wlmtk_element_t { /** Implementation of abstract virtual methods. */ const wlmtk_element_impl_t *impl_ptr; + + /** Points to the wlroots scene graph API node. Is set when mapped. */ + struct wlr_scene_node *wlr_scene_node_ptr; }; /** Pointers to the implementation of Element's virtual methods. */ struct _wlmtk_element_impl_t { /** Destroys the implementation of the element. */ void (*destroy)(wlmtk_element_t *element_ptr); + /** Creates element's scene graph API node, child to wlr_scene_tree_ptr. */ + struct wlr_scene_node *(*create_scene_node)( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); }; /** @@ -107,6 +114,24 @@ void wlmtk_element_set_parent_container( wlmtk_element_t *element_ptr, wlmtk_container_t *parent_container_ptr); +/** + * Maps the element. + * + * Requires a parent container to be set. Will call `create_scene_node` to + * build the scene graph API node attached to the parent container's tree. + * + * @param element_ptr + */ +void wlmtk_element_map(wlmtk_element_t *element_ptr); + +/** + * Unmaps the element. + * + * @param element_ptr + */ +void wlmtk_element_unmap(wlmtk_element_t *element_ptr); + + /** Virtual method: Calls the dtor of the element's implementation. */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { @@ -128,6 +153,9 @@ struct _wlmtk_container_t { /** Implementation of the container's virtual methods. */ const wlmtk_container_impl_t *impl_ptr; + + /** Scene tree. */ + struct wlr_scene_tree *wlr_scene_tree_ptr; }; /** Virtual method table of the container. */ @@ -178,13 +206,26 @@ void wlmtk_container_remove_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr); +/** + * Returns the wlroots scene graph tree for this node. + * + * Requires this container's element to be mapped. Should be called only from + * members of `elements`. + * + * @param container_ptr + * + * @return The scene tree. + */ +struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( + wlmtk_container_t *container_ptr); + /** Virtual method: Calls the dtor of the container's implementation. */ static inline void wlmtk_container_destroy( wlmtk_container_t *container_ptr) { container_ptr->impl_ptr->destroy(container_ptr); } -/** Unit tests for the element. */ +/** Unit tests for the container. */ extern const bs_test_case_t wlmtk_container_test_cases[]; /* ========================================================================= */ @@ -195,10 +236,13 @@ typedef struct _wlmtk_workspace_t wlmtk_workspace_t; /** * Creates a workspace. * + * @param wlr_scene_tree_ptr + * * @return Pointer to the workspace state, or NULL on error. Must be free'd * via @ref wlmtk_workspace_destroy. */ -wlmtk_workspace_t *wlmtk_workspace_create(void); +wlmtk_workspace_t *wlmtk_workspace_create( + struct wlr_scene_tree *wlr_scene_tree_ptr); /** * Destroys the workspace. Will destroy any still-mapped element. @@ -207,6 +251,9 @@ wlmtk_workspace_t *wlmtk_workspace_create(void); */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); +/** Unit tests for the workspace. */ +extern const bs_test_case_t wlmtk_workspace_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 33ce5bdc..039ca7e8 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -24,6 +24,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "container", wlmtk_container_test_cases }, { 1, "element", wlmtk_element_test_cases }, + { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } }; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 2b7b37c3..1a49b038 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -20,12 +20,26 @@ #include "toolkit.h" +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + /* == Declarations ========================================================= */ /** State of the workspace. */ struct _wlmtk_workspace_t { /** Superclass: Container. */ wlmtk_container_t super_container; + + /** + * The workspace's element map() method will expect a parent from where to + * retrieve the wlroots scene graph tree from. As a toplevel construct, + * there is not really a parent, so we use this fake class instead. + * + * TODO(kaeser@gubbe.ch): This should live in wlmaker_server_t; ultimately + * that is the "container" that holds all workspaces. + */ + wlmtk_container_t fake_parent; }; static void workspace_container_destroy(wlmtk_container_t *container_ptr); @@ -38,7 +52,8 @@ const wlmtk_container_impl_t workspace_container_impl = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_workspace_t *wlmtk_workspace_create(void) +wlmtk_workspace_t *wlmtk_workspace_create( + struct wlr_scene_tree *wlr_scene_tree_ptr) { wlmtk_workspace_t *workspace_ptr = logged_calloc(1, sizeof(wlmtk_workspace_t)); @@ -50,12 +65,25 @@ wlmtk_workspace_t *wlmtk_workspace_create(void) return NULL; } + workspace_ptr->fake_parent.wlr_scene_tree_ptr = wlr_scene_tree_ptr; + wlmtk_element_set_parent_container( + &workspace_ptr->super_container.super_element, + &workspace_ptr->fake_parent); + + wlmtk_element_map(&workspace_ptr->super_container.super_element); + return workspace_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) { + wlmtk_element_unmap(&workspace_ptr->super_container.super_element); + + wlmtk_element_set_parent_container( + &workspace_ptr->super_container.super_element, + NULL); + wlmtk_container_fini(&workspace_ptr->super_container); free(workspace_ptr); } @@ -71,4 +99,29 @@ void workspace_container_destroy(wlmtk_container_t *container_ptr) wlmtk_workspace_destroy(workspace_ptr); } + +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_workspace_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises workspace create & destroy methods. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + &wlr_scene_ptr->tree); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); + + wlmtk_workspace_destroy(workspace_ptr); + + // Note: There is no destroy method for wlr_scene_ptr. +} + /* == End of workspace.c =================================================== */ From 0ae29a6e95af4997f45930421a6e3a3bcf42d176 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 24 Aug 2023 21:36:13 +0200 Subject: [PATCH 014/390] Adds boilerplate for the window container. --- src/toolkit/CMakeLists.txt | 1 + src/toolkit/toolkit.h | 20 +++++++++++ src/toolkit/window.c | 73 ++++++++++++++++++++++++++++++++++++++ src/toolkit/workspace.c | 1 - 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/toolkit/window.c diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 57b05cbb..65385724 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -26,6 +26,7 @@ TARGET_SOURCES(toolkit PRIVATE container.c gfxbuf.c primitives.c + window.c workspace.c) TARGET_INCLUDE_DIRECTORIES( toolkit PUBLIC diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 9bd83a7a..e8c93b0b 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -254,6 +254,26 @@ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; +/* ========================================================================= */ + +/** State of the window. */ +typedef struct _wlmtk_window_t wlmtk_window_t; + +/** + * Creates a window. + * + * @return Pointer to the window state, or NULL on error. Must be free'd + * by calling @ref wlmtk_window_destroy. + */ +wlmtk_window_t *wlmtk_window_create(void); + +/** + * Destroys the window. + * + * @param window_ptr + */ +void wlmtk_window_destroy(wlmtk_window_t *window_ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/window.c b/src/toolkit/window.c new file mode 100644 index 00000000..f382efe4 --- /dev/null +++ b/src/toolkit/window.c @@ -0,0 +1,73 @@ +/* ========================================================================= */ +/** + * @file window.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toolkit.h" + +/* == Declarations ========================================================= */ + +/** State of the window. */ +struct _wlmtk_window_t { + /** Superclass: Container. */ + wlmtk_container_t super_container; +}; + +static void window_container_destroy(wlmtk_container_t *container_ptr); + +/** Method table for the container's virtual methods. */ +const wlmtk_container_impl_t window_container_impl = { + .destroy = window_container_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_window_create(void) +{ + wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); + if (NULL == window_ptr) return NULL; + + if (!wlmtk_container_init(&window_ptr->super_container, + &window_container_impl)) { + wlmtk_window_destroy(window_ptr); + return NULL; + } + + return window_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_destroy(wlmtk_window_t *window_ptr) +{ + wlmtk_container_fini(&window_ptr->super_container); + free(window_ptr); +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, in case called from container. Wraps to our dtor. */ +void window_container_destroy(wlmtk_container_t *container_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_window_t, super_container); + wlmtk_window_destroy(window_ptr); +} + +/* == End of window.c ====================================================== */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 1a49b038..03c7e182 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -99,7 +99,6 @@ void workspace_container_destroy(wlmtk_container_t *container_ptr) wlmtk_workspace_destroy(workspace_ptr); } - /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); From 64e2d575dffe32328554620f87e880a199c4cf63 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 24 Aug 2023 21:50:43 +0200 Subject: [PATCH 015/390] Adds trivial test case for window. --- src/toolkit/container.c | 2 -- src/toolkit/toolkit.h | 3 +++ src/toolkit/toolkit_test.c | 1 + src/toolkit/window.c | 18 ++++++++++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 3dd166d6..008b4322 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -146,8 +146,6 @@ struct wlr_scene_node *element_create_scene_node( static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); -/* == End of container.c =================================================== */ - const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index e8c93b0b..dc9676d8 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -274,6 +274,9 @@ wlmtk_window_t *wlmtk_window_create(void); */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); +/** Unit tests for window. */ +extern const bs_test_case_t wlmtk_window_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 039ca7e8..386bc64c 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -24,6 +24,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "container", wlmtk_container_test_cases }, { 1, "element", wlmtk_element_test_cases }, + { 1, "winodw", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f382efe4..f2247afa 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -70,4 +70,22 @@ void window_container_destroy(wlmtk_container_t *container_ptr) wlmtk_window_destroy(window_ptr); } +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_window_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + wlmtk_window_t *window_ptr = wlmtk_window_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); + wlmtk_window_destroy(window_ptr); +} + /* == End of window.c ====================================================== */ From 70bebfa54fa5513adfe0c0fc831e1d867f50f8fa Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 24 Aug 2023 21:59:26 +0200 Subject: [PATCH 016/390] Adds blanket headers for workspace_map_window and workspace_unmap_window. --- src/toolkit/toolkit.h | 37 ++++++++++++++++++++++++++++++++++--- src/toolkit/window.c | 6 ++++++ src/toolkit/workspace.c | 18 ++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index dc9676d8..c7a05e4f 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -38,6 +38,8 @@ struct wlr_scene_tree; typedef struct _wlmtk_element_t wlmtk_element_t; /** Forward declaration: Container. */ typedef struct _wlmtk_container_t wlmtk_container_t; +/** Forward declaration: Window. */ +typedef struct _wlmtk_window_t wlmtk_window_t; /** Forward declaration: Element virtual method implementations. */ typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; @@ -251,14 +253,30 @@ wlmtk_workspace_t *wlmtk_workspace_create( */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); +/** + * Maps the window: Adds it to the workspace container and maps it. + * + * @param workspace_ptr + * @param window_ptr + */ +void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + +/** + * Maps the window: Unmaps the window and removes it from the workspace + * container. + * + * @param workspace_ptr + * @param window_ptr + */ +void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; /* ========================================================================= */ -/** State of the window. */ -typedef struct _wlmtk_window_t wlmtk_window_t; - /** * Creates a window. * @@ -274,6 +292,19 @@ wlmtk_window_t *wlmtk_window_create(void); */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); +/** + * Returns the super Element of the window. + * + * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or + * whether to keep the members public. + * + * @param window_ptr + * + * @return Potiner to the @ref wlmtk_element_t base instantiation to + * window_ptr. + */ +wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f2247afa..4627982a 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -59,6 +59,12 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) free(window_ptr); } +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) +{ + return &window_ptr->super_container.super_element; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 03c7e182..b75e0d6e 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -88,6 +88,24 @@ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) free(workspace_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) +{ + wlmtk_container_add_element( + &workspace_ptr->super_container, + wlmtk_window_element(window_ptr)); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) +{ + wlmtk_container_remove_element( + &workspace_ptr->super_container, + wlmtk_window_element(window_ptr)); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ From 6f04798d696952fd1397ff37099f12a08808a5cd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 25 Aug 2023 16:30:40 +0200 Subject: [PATCH 017/390] Adds test cases to verify mapping and unmapping. --- src/toolkit/container.c | 68 ++++++++++++++++++++++++++++++++++++++--- src/toolkit/element.c | 65 +++++++++++++++++++++++++++++++++++---- src/toolkit/toolkit.h | 15 +++++++-- 3 files changed, 135 insertions(+), 13 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 008b4322..0f47b310 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -89,6 +89,12 @@ void wlmtk_container_remove_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr) { + BS_ASSERT(element_ptr->parent_container_ptr == container_ptr); + + if (wlmtk_element_mapped(element_ptr)) { + wlmtk_element_unmap(element_ptr); + } + wlmtk_element_set_parent_container(element_ptr, NULL); bs_dllist_remove( &container_ptr->elements, @@ -145,10 +151,12 @@ struct wlr_scene_node *element_create_scene_node( static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); +static void test_remove_mapped(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, + { 1, "remove_mapped", test_remove_mapped }, { 0, NULL, NULL } }; @@ -163,11 +171,25 @@ static void test_element_destroy_cb(wlmtk_element_t *element_ptr) { wlmtk_element_fini(element_ptr); } +/** Creates a scene node attached to the three. */ +static struct wlr_scene_node *test_element_create_scene_node( + __UNUSED__ wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( + wlr_scene_tree_ptr, NULL); + return &wlr_scene_buffer_ptr->node; +} /** Method table for the container we're using for test. */ static const wlmtk_container_impl_t test_container_impl = { .destroy = test_destroy_cb }; +/** Method table for the element we're using for test. */ +static const wlmtk_element_impl_t test_element_impl = { + .destroy = test_element_destroy_cb, + .create_scene_node = test_element_create_scene_node +}; /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ @@ -196,10 +218,12 @@ void test_add_remove(bs_test_t *test_ptr) &container, &test_container_impl)); wlmtk_element_t element1, element2, element3; - wlmtk_element_impl_t impl = { .destroy = test_element_destroy_cb }; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element1, &impl)); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element2, &impl)); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element3, &impl)); + BS_TEST_VERIFY_TRUE(test_ptr, + wlmtk_element_init(&element1, &test_element_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, + wlmtk_element_init(&element2, &test_element_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, + wlmtk_element_init(&element3, &test_element_impl)); wlmtk_container_add_element(&container, &element1); BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, &container); @@ -217,6 +241,42 @@ void test_add_remove(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, element1.impl_ptr, NULL); BS_TEST_VERIFY_EQ(test_ptr, element3.impl_ptr, NULL); + + wlmtk_container_fini(&container); +} + +/* ------------------------------------------------------------------------- */ +void test_remove_mapped(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( + &container, &test_container_impl)); + + struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + wlmtk_container_t fake_parent = { + .wlr_scene_tree_ptr = &wlr_scene_ptr->tree + }; + wlmtk_element_set_parent_container( + &container.super_element, &fake_parent); + + // Self must be mapped before mapping any contained element. + wlmtk_element_map(&container.super_element); + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_element_mapped(&container.super_element)); + + wlmtk_element_t element; + BS_TEST_VERIFY_TRUE(test_ptr, + wlmtk_element_init(&element, &test_element_impl)); + wlmtk_container_add_element(&container, &element); + wlmtk_element_map(&element); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); + + + wlmtk_container_remove_element(&container, &element); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_element_mapped(&element)); + + wlmtk_element_set_parent_container(&container.super_element, NULL); + wlmtk_container_fini(&container); } /* == End of container.c =================================================== */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 34f462ce..f1d6eca3 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -36,6 +36,7 @@ bool wlmtk_element_init( BS_ASSERT(NULL != element_ptr); BS_ASSERT(NULL != element_impl_ptr); BS_ASSERT(NULL != element_impl_ptr->destroy); + BS_ASSERT(NULL != element_impl_ptr->create_scene_node); memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; @@ -47,7 +48,7 @@ void wlmtk_element_fini( wlmtk_element_t *element_ptr) { // Verify we're no longer mapped, nor part of a container. - BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + BS_ASSERT(!wlmtk_element_mapped(element_ptr)); BS_ASSERT(NULL == element_ptr->parent_container_ptr); element_ptr->impl_ptr = NULL; @@ -72,6 +73,11 @@ void wlmtk_element_set_parent_container( wlmtk_element_t *element_ptr, wlmtk_container_t *parent_container_ptr) { + if (element_ptr->parent_container_ptr == parent_container_ptr) return; + + if (wlmtk_element_mapped(element_ptr)) { + wlmtk_element_unmap(element_ptr); + } element_ptr->parent_container_ptr = parent_container_ptr; } @@ -80,10 +86,12 @@ void wlmtk_element_map(wlmtk_element_t *element_ptr) { BS_ASSERT(NULL != element_ptr->parent_container_ptr); BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + struct wlr_scene_tree *parent_wlr_scene_tree_ptr = + wlmtk_container_wlr_scene_tree(element_ptr->parent_container_ptr); + BS_ASSERT(NULL != parent_wlr_scene_tree_ptr); element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( - element_ptr, - wlmtk_container_wlr_scene_tree(element_ptr->parent_container_ptr)); + element_ptr, parent_wlr_scene_tree_ptr); BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); } @@ -100,9 +108,11 @@ void wlmtk_element_unmap(wlmtk_element_t *element_ptr) /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); +static void test_map_unmap(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { { 1, "init_fini", test_init_fini }, + { 1, "map_unmap", test_map_unmap }, { 0, NULL, NULL } }; @@ -114,15 +124,27 @@ static void test_destroy_cb(wlmtk_element_t *element_ptr) test_destroy_cb_called = true; wlmtk_element_fini(element_ptr); } +/** A dummy implementation for a 'create_scene_node'. */ +static struct wlr_scene_node *test_create_scene_node( + __UNUSED__ wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( + wlr_scene_tree_ptr, NULL); + return &wlr_scene_buffer_ptr->node; +} + +static const wlmtk_element_impl_t test_impl = { + .destroy = test_destroy_cb, + .create_scene_node = test_create_scene_node +}; /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_element_t element; - wlmtk_element_impl_t impl = { .destroy = test_destroy_cb }; - - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); test_destroy_cb_called = false; wlmtk_element_destroy(&element); @@ -131,4 +153,35 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests map and unmap, and that unmapping is done on reparenting or fini. */ +void test_map_unmap(bs_test_t *test_ptr) +{ + wlmtk_element_t element; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); + + struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + wlmtk_container_t fake_parent = { + .wlr_scene_tree_ptr = &wlr_scene_ptr->tree + }; + wlmtk_element_set_parent_container(&element, &fake_parent); + + // Map & unmap. + wlmtk_element_map(&element); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); + wlmtk_element_unmap(&element); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_element_mapped(&element)); + + // Remain mapped, if the parent container remains unchanged. + wlmtk_element_map(&element); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); + wlmtk_element_set_parent_container(&element, &fake_parent); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); + + // Changing the parent (eg. to 'None') must unmap the element. + wlmtk_element_set_parent_container(&element, NULL); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_element_mapped(&element)); + wlmtk_element_fini(&element); +} + /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index c7a05e4f..40853d36 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -106,10 +106,11 @@ wlmtk_element_t *wlmtk_element_from_dlnode( * Sets the parent container for the element. * * Should only be called by wlmtk_container_add_element, respectively - * wlmtk_container_remove_element. + * wlmtk_container_remove_element. Will unmap the element, if the parent + * container changes. * * @param element_ptr - * @param parent_container_ptr Pointer to the parent contqainer, or NULL if + * @param parent_container_ptr Pointer to the parent container, or NULL if * the parent should be cleared. */ void wlmtk_element_set_parent_container( @@ -133,6 +134,11 @@ void wlmtk_element_map(wlmtk_element_t *element_ptr); */ void wlmtk_element_unmap(wlmtk_element_t *element_ptr); +/** Returns whether this element is currently mapped. */ +static inline bool wlmtk_element_mapped(wlmtk_element_t *element_ptr) +{ + return NULL != element_ptr->wlr_scene_node_ptr; +} /** Virtual method: Calls the dtor of the element's implementation. */ static inline void wlmtk_element_destroy( @@ -201,6 +207,9 @@ void wlmtk_container_add_element( /** * Removes `element_ptr` from the container. * + * Expects that `container_ptr` is `element_ptr`'s parent container. Will unmap + * the element, in case it is currently mapped. + * * @param container_ptr * @param element_ptr */ @@ -296,7 +305,7 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); * Returns the super Element of the window. * * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or - * whether to keep the members public. + * whether to keep the ancestry members public. * * @param window_ptr * From f62879fcd2aceebeca8e8a74997fb1f5778aecfc Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 25 Aug 2023 16:40:03 +0200 Subject: [PATCH 018/390] Adds missing doxygen comments. --- src/toolkit/container.c | 1 + src/toolkit/element.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 0f47b310..0485034b 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -246,6 +246,7 @@ void test_add_remove(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ +/** Tests that mapped elements are unmapped when removed. */ void test_remove_mapped(bs_test_t *test_ptr) { wlmtk_container_t container; diff --git a/src/toolkit/element.c b/src/toolkit/element.c index f1d6eca3..fdf41579 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -133,7 +133,7 @@ static struct wlr_scene_node *test_create_scene_node( wlr_scene_tree_ptr, NULL); return &wlr_scene_buffer_ptr->node; } - +/** Method table for the element we're using as test dummy. */ static const wlmtk_element_impl_t test_impl = { .destroy = test_destroy_cb, .create_scene_node = test_create_scene_node From 2f0195fbeddc731c3e8f8ea3ea2e1f1d41c24ea1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 25 Aug 2023 16:45:03 +0200 Subject: [PATCH 019/390] Adds workspace test for mapping and unmapping a window. --- src/toolkit/workspace.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index b75e0d6e..20674382 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -95,12 +95,14 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_container_add_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); + wlmtk_element_map(wlmtk_window_element(window_ptr)); } /* ------------------------------------------------------------------------- */ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { + wlmtk_element_unmap(wlmtk_window_element(window_ptr)); wlmtk_container_remove_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); @@ -120,9 +122,11 @@ void workspace_container_destroy(wlmtk_container_t *container_ptr) /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_map_unmap(bs_test_t *test_ptr); const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "map_unmap", test_map_unmap }, { 0, NULL, NULL } }; @@ -141,4 +145,31 @@ void test_create_destroy(bs_test_t *test_ptr) // Note: There is no destroy method for wlr_scene_ptr. } +/* ------------------------------------------------------------------------- */ +/** Verifies that mapping and unmapping windows works. */ +void test_map_unmap(bs_test_t *test_ptr) +{ + struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + &wlr_scene_ptr->tree); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); + + wlmtk_window_t *window_ptr = wlmtk_window_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); + + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_mapped(wlmtk_window_element(window_ptr))); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_mapped(wlmtk_window_element(window_ptr))); + + wlmtk_window_destroy(window_ptr); + wlmtk_workspace_destroy(workspace_ptr); +} + /* == End of workspace.c =================================================== */ From b9b21bb9b5d7596109525b233ce022dc4fa07442 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 25 Aug 2023 17:23:00 +0200 Subject: [PATCH 020/390] Adds assertion on virtual methods. --- src/toolkit/container.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 0485034b..9284efaa 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -46,6 +46,7 @@ bool wlmtk_container_init( { BS_ASSERT(NULL != container_ptr); BS_ASSERT(NULL != container_impl_ptr); + BS_ASSERT(NULL != container_impl_ptr->destroy); memset(container_ptr, 0, sizeof(wlmtk_container_t)); if (!wlmtk_element_init(&container_ptr->super_element, @@ -171,7 +172,7 @@ static void test_element_destroy_cb(wlmtk_element_t *element_ptr) { wlmtk_element_fini(element_ptr); } -/** Creates a scene node attached to the three. */ +/** Creates a scene node attached to the tree. */ static struct wlr_scene_node *test_element_create_scene_node( __UNUSED__ wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) From 41b48e734ea571ffc792933577cbcf506d1f8f61 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 25 Aug 2023 17:23:37 +0200 Subject: [PATCH 021/390] Adds base implementation of 'content', the window's content element. --- src/toolkit/CMakeLists.txt | 1 + src/toolkit/content.c | 153 +++++++++++++++++++++++++++++++++++++ src/toolkit/toolkit.h | 47 ++++++++++++ src/toolkit/toolkit_test.c | 1 + 4 files changed, 202 insertions(+) create mode 100644 src/toolkit/content.c diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 65385724..499883f3 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -24,6 +24,7 @@ ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE element.c container.c + content.c gfxbuf.c primitives.c window.c diff --git a/src/toolkit/content.c b/src/toolkit/content.c new file mode 100644 index 00000000..adf80a78 --- /dev/null +++ b/src/toolkit/content.c @@ -0,0 +1,153 @@ +/* ========================================================================= */ +/** + * @file content.c + * Copyright (c) 2023 by Philipp Kaeser + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toolkit.h" + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +static void element_destroy(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); + +/** Method table for the container's virtual methods. */ +const wlmtk_element_impl_t super_element_impl = { + .destroy = element_destroy, + .create_scene_node = element_create_scene_node +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_content_init( + wlmtk_content_t *content_ptr, + const wlmtk_content_impl_t *content_impl_ptr) +{ + BS_ASSERT(NULL != content_ptr); + BS_ASSERT(NULL != content_impl_ptr); + BS_ASSERT(NULL != content_impl_ptr->destroy); + BS_ASSERT(NULL != content_impl_ptr->create_scene_node); + memset(content_ptr, 0, sizeof(wlmtk_content_t)); + + if (!wlmtk_element_init(&content_ptr->super_element, + &super_element_impl)) { + return false; + } + + content_ptr->impl_ptr = content_impl_ptr; + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_fini(wlmtk_content_t *content_ptr) +{ + wlmtk_element_fini(&content_ptr->super_element); + content_ptr->impl_ptr = NULL; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::destroy method. + * + * Forwards the call to the wlmtk_content_t::destroy method. + * + * @param element_ptr + */ +void element_destroy(wlmtk_element_t *element_ptr) +{ + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + content_ptr->impl_ptr->destroy(content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::create_scene_node method. + * + * Forwards the call to the wlmtk_content_t::create_scene_node method. + * + * @param element_ptr + * @param wlr_scene_tree_ptr + */ +struct wlr_scene_node *element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + return content_ptr->impl_ptr->create_scene_node( + content_ptr, wlr_scene_tree_ptr); +} + +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_content_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 0, NULL, NULL } +}; + +/** dtor for the content under test. */ +static void test_destroy_cb(wlmtk_content_t *content_ptr) +{ + wlmtk_content_fini(content_ptr); +} +/** Creates a scene node attached to the tree. */ +static struct wlr_scene_node *test_create_scene_node_cb( + __UNUSED__ wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( + wlr_scene_tree_ptr, NULL); + return &wlr_scene_buffer_ptr->node; +} +/** Method table for the content we're using for test. */ +static const wlmtk_content_impl_t test_content_impl = { + .destroy = test_destroy_cb, + .create_scene_node = test_create_scene_node_cb +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises init() and fini() methods, verifies dtor forwarding. */ +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_content_t content; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_content_init( + &content, &test_content_impl)); + // Also expect the super element to be initialized. + BS_TEST_VERIFY_NEQ(test_ptr, NULL, content.super_element.impl_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, content.impl_ptr); + + content.impl_ptr->destroy(&content); + + // Also expect the super element to be un-initialized. + BS_TEST_VERIFY_EQ(test_ptr, NULL, content.super_element.impl_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, content.impl_ptr); +} + +/* == End of content.c ================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 40853d36..0f389b73 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -40,11 +40,15 @@ typedef struct _wlmtk_element_t wlmtk_element_t; typedef struct _wlmtk_container_t wlmtk_container_t; /** Forward declaration: Window. */ typedef struct _wlmtk_window_t wlmtk_window_t; +/** Forward declaration: Window content. */ +typedef struct _wlmtk_content_t wlmtk_content_t; /** Forward declaration: Element virtual method implementations. */ typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; /** Forward declaration: Container virtual method implementations. */ typedef struct _wlmtk_container_impl_t wlmtk_container_impl_t; +/** Forward declaration: Content virtual method implementations. */ +typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; /** State of an element. */ struct _wlmtk_element_t { @@ -317,6 +321,49 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; +/* ========================================================================= */ + +/** State of the element. */ +struct _wlmtk_content_t { + /** Super class of the content: An element. */ + wlmtk_element_t super_element; + + /** Implementation of abstract virtual methods. */ + const wlmtk_content_impl_t *impl_ptr; +}; + +/** Method table of the content. */ +struct _wlmtk_content_impl_t { + /** Destroys thje implementation of the content. */ + void (*destroy)(wlmtk_content_t *content_ptr); + /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ + struct wlr_scene_node *(*create_scene_node)( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +}; + +/** + * Initializes the content. + * + * @param content_ptr + * @param content_impl_ptr + * + * @return true on success. + */ +bool wlmtk_content_init( + wlmtk_content_t *content_ptr, + const wlmtk_content_impl_t *content_impl_ptr); + +/** + * Cleans up the content. + * + * @param content_ptr + */ +void wlmtk_content_fini(wlmtk_content_t *content_ptr); + +/** Unit tests for content. */ +extern const bs_test_case_t wlmtk_content_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 386bc64c..482cdbfe 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -23,6 +23,7 @@ /** Toolkit unit tests. */ const bs_test_set_t toolkit_tests[] = { { 1, "container", wlmtk_container_test_cases }, + { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "winodw", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, From 21c904f10e1f0dc3343641e908549fc3cffa9297 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 25 Aug 2023 17:51:40 +0200 Subject: [PATCH 022/390] Wires up the content in the window initialization. --- src/toolkit/content.c | 14 ++++++++++++++ src/toolkit/toolkit.h | 34 +++++++++++++++++++++++++++++++--- src/toolkit/window.c | 22 ++++++++++++++++++++-- src/toolkit/workspace.c | 4 +++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index adf80a78..c1a3a76b 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -67,6 +67,20 @@ void wlmtk_content_fini(wlmtk_content_t *content_ptr) content_ptr->impl_ptr = NULL; } +/* ------------------------------------------------------------------------- */ +void wlmtk_content_set_window( + wlmtk_content_t *content_ptr, + wlmtk_window_t *window_ptr) +{ + content_ptr->window_ptr = window_ptr; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr) +{ + return &content_ptr->super_element; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 0f389b73..d782a300 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -291,12 +291,14 @@ extern const bs_test_case_t wlmtk_workspace_test_cases[]; /* ========================================================================= */ /** - * Creates a window. + * Creates a window for the given content. + * + * @param content_ptr * * @return Pointer to the window state, or NULL on error. Must be free'd * by calling @ref wlmtk_window_destroy. */ -wlmtk_window_t *wlmtk_window_create(void); +wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr); /** * Destroys the window. @@ -313,7 +315,7 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); * * @param window_ptr * - * @return Potiner to the @ref wlmtk_element_t base instantiation to + * @return Pointer to the @ref wlmtk_element_t base instantiation to * window_ptr. */ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); @@ -330,6 +332,12 @@ struct _wlmtk_content_t { /** Implementation of abstract virtual methods. */ const wlmtk_content_impl_t *impl_ptr; + + /** + * The window this content belongs to. Will be set when creating + * the window. + */ + wlmtk_window_t *window_ptr; }; /** Method table of the content. */ @@ -361,6 +369,26 @@ bool wlmtk_content_init( */ void wlmtk_content_fini(wlmtk_content_t *content_ptr); +/** + * Sets the window for the content. + * + * @param content_ptr + * @param window_ptr + */ +void wlmtk_content_set_window( + wlmtk_content_t *content_ptr, + wlmtk_window_t *window_ptr); + +/** + * Returns the super Element of the content. + * + * @param content_ptr + * + * @return Pointer to the @ref wlmtk_element_t base instantiation to + * content_ptr. + */ +wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); + /** Unit tests for content. */ extern const bs_test_case_t wlmtk_content_test_cases[]; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 4627982a..a7ef5fae 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -26,6 +26,9 @@ struct _wlmtk_window_t { /** Superclass: Container. */ wlmtk_container_t super_container; + + /** Content of this window. */ + wlmtk_content_t *content_ptr; }; static void window_container_destroy(wlmtk_container_t *container_ptr); @@ -38,7 +41,7 @@ const wlmtk_container_impl_t window_container_impl = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create(void) +wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) { wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; @@ -49,12 +52,23 @@ wlmtk_window_t *wlmtk_window_create(void) return NULL; } + wlmtk_container_add_element( + &window_ptr->super_container, + wlmtk_content_element(content_ptr)); + window_ptr->content_ptr = content_ptr; + wlmtk_content_set_window(content_ptr, window_ptr); return window_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { + wlmtk_container_remove_element( + &window_ptr->super_container, + wlmtk_content_element(window_ptr->content_ptr)); + wlmtk_content_set_window(window_ptr->content_ptr, NULL); + window_ptr->content_ptr = NULL; + wlmtk_container_fini(&window_ptr->super_container); free(window_ptr); } @@ -89,8 +103,12 @@ const bs_test_case_t wlmtk_window_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_window_t *window_ptr = wlmtk_window_create(); + wlmtk_content_t content; + memset(&content, 0, sizeof(content)); + + wlmtk_window_t *window_ptr = wlmtk_window_create(&content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, window_ptr, content.window_ptr); wlmtk_window_destroy(window_ptr); } diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 20674382..4f1afef9 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -155,7 +155,9 @@ void test_map_unmap(bs_test_t *test_ptr) &wlr_scene_ptr->tree); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); - wlmtk_window_t *window_ptr = wlmtk_window_create(); + wlmtk_content_t content; + memset(&content, 0, sizeof(content)); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); wlmtk_workspace_map_window(workspace_ptr, window_ptr); From f7734359abdab111c1424c0ad9bc94febe2a6780 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 26 Aug 2023 14:11:48 +0200 Subject: [PATCH 023/390] Updates class documentation for plantuml, and fixes a comment typo. --- src/toolkit/toolkit.h | 10 ++++--- src/toolkit/toolkit.md | 62 ++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index d782a300..98525c4d 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -109,9 +109,9 @@ wlmtk_element_t *wlmtk_element_from_dlnode( /** * Sets the parent container for the element. * - * Should only be called by wlmtk_container_add_element, respectively - * wlmtk_container_remove_element. Will unmap the element, if the parent - * container changes. + * Private: Should only be called by wlmtk_container_add_element, respectively + * wlmtk_container_remove_element ("friends"). Will unmap the element, if the + * parent container changes. * * @param element_ptr * @param parent_container_ptr Pointer to the parent container, or NULL if @@ -342,7 +342,7 @@ struct _wlmtk_content_t { /** Method table of the content. */ struct _wlmtk_content_impl_t { - /** Destroys thje implementation of the content. */ + /** Destroys the implementation of the content. */ void (*destroy)(wlmtk_content_t *content_ptr); /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ struct wlr_scene_node *(*create_scene_node)( @@ -372,6 +372,8 @@ void wlmtk_content_fini(wlmtk_content_t *content_ptr); /** * Sets the window for the content. * + * Private: Should only be called by Window ctor (a friend). + * * @param content_ptr * @param window_ptr */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 257742fb..d2cb20ff 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -19,50 +19,56 @@ limitations under the License. ### Class Hierarchy + * Where do we use composition, vs. inheritance? ```plantuml class Element { int x, y struct wlr_scene_node *node_ptr - Container *container_ptr - - init(handlers) - void destroy(Element*) - set_parent(Container*) - map() - unmap() - - {abstract}#void enter(Element*) - {abstract}#void leave(Element*) - {abstract}#void click(Element*) - {abstract}#create_or_reparent_node(Element*, parent_node*) + Container *parent_container_ptr + + bool init(handlers) + void fini() + -void set_parent_container(Container*) + void map() + void unmap() + bool mapped() + + {abstract}#void destroy() + {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) + {abstract}#void enter() + {abstract}#void leave() + {abstract}#void click() } note right of Element::"map()" Only permitted if element is a member of a (mapped?) container. end note class Container { - Element parent - Element children[] + Element super_element + Element elements[] - Container *create(void) - void destroy(Container*) + bool init(handlers) + void fini() add_element(Element*) remove_element(Element*) + struct wlr_scene_tree *wlr_scene_tree() + + {abstract}#void destroy() - -void enter(Element*) - -void leave(Element*) - -void click(Element*) + void enter(Element*) + void leave(Element*) + void click(Element*) } Element <|-- Container class Workspace { - Container parent + Container super_container Container layers[] - Container *create(void) - void destroy(Container*) + Container *create() + void destroy() map_window(Window*) unmap_window(Window*) @@ -86,6 +92,10 @@ abstract class Content { Element parent init(handlers) + fini() + struct wlr_scene_node *create_scene_node() + Element *element() + -set_window(Window*) {abstract}#void set_active(bool) {abstract}#void set_maximized(bool) @@ -131,9 +141,13 @@ class Button { Buffer <|-- Button class Window { - VBox parent - Content content + VBox super_container + Content *content TitleBar title_bar + + Window *create(Content*) + destroy() + Element *element() } VBox *-- Window From 9c91737e65ba0416bc956cd4433146e12de6ae6a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 10:28:20 +0200 Subject: [PATCH 024/390] Additions on toolkit to consider mapping & making nodes visible. --- src/toolkit/element.c | 4 ++++ src/toolkit/toolkit.h | 12 ++++++++++++ src/toolkit/toolkit.md | 7 +++++++ src/toolkit/workspace.c | 15 +++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index fdf41579..e30e21ea 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -92,6 +92,8 @@ void wlmtk_element_map(wlmtk_element_t *element_ptr) element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( element_ptr, parent_wlr_scene_tree_ptr); + // TODO(kaeser@gubbe.ch): Separate map method into set_visible/attach. + wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, true); BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); } @@ -99,6 +101,8 @@ void wlmtk_element_map(wlmtk_element_t *element_ptr) void wlmtk_element_unmap(wlmtk_element_t *element_ptr) { BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); + // TODO(kaeser@gubbe.ch): Separate map method into set_visible/attach. + wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, false); wlr_scene_node_destroy(element_ptr->wlr_scene_node_ptr); element_ptr->wlr_scene_node_ptr = NULL; } diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 98525c4d..5cf69e04 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -126,6 +126,7 @@ void wlmtk_element_set_parent_container( * * Requires a parent container to be set. Will call `create_scene_node` to * build the scene graph API node attached to the parent container's tree. + * Implies that the parent container also is required to be mapped. * * @param element_ptr */ @@ -285,6 +286,17 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); +/** + * Type conversion: Returns the @ref wlmtk_workspace_t from the container_ptr + * pointing to wlmtk_workspace_t::super_container. + * + * Asserts that the container is indeed from a wlmtk_workspace_t. + * + * @reutrn Pointer to the workspace. + */ +wlmtk_workspace_t *wlmtk_workspace_from_container( + wlmtk_container_t *container_ptr); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index d2cb20ff..9aa04dd0 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -167,6 +167,13 @@ class MenuItem { Buffer <|-- MenuItem ``` +### Pending work + +* Separate the "map" method into "attach_to_node" and "set_visible". Elements + should be marked as visible even if their parent is not "mapped" yet; thus + leading to lazy instantiation of the node, once their parent gets "mapped" + (ie. attached to the scene graph). + ### User Journeys #### Creating a new XDG toplevel diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 4f1afef9..95353d60 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -102,12 +102,22 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { + BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( + wlmtk_window_element(window_ptr)->parent_container_ptr)); wlmtk_element_unmap(wlmtk_window_element(window_ptr)); wlmtk_container_remove_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); } +/* ------------------------------------------------------------------------- */ +wlmtk_workspace_t *wlmtk_workspace_from_container( + wlmtk_container_t *container_ptr) +{ + BS_ASSERT(container_ptr->impl_ptr == &workspace_container_impl); + return BS_CONTAINER_OF(container_ptr, wlmtk_workspace_t, super_container); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -140,6 +150,11 @@ void test_create_destroy(bs_test_t *test_ptr) &wlr_scene_ptr->tree); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); + BS_TEST_VERIFY_EQ( + test_ptr, + workspace_ptr, + wlmtk_workspace_from_container(&workspace_ptr->super_container)); + wlmtk_workspace_destroy(workspace_ptr); // Note: There is no destroy method for wlr_scene_ptr. From 54f508a8c547765738e8ab78a03a5f663dae49dd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 10:29:41 +0200 Subject: [PATCH 025/390] Transitional: Adds setup & teardown of toolkit workspace to ... workspace. --- src/workspace.c | 22 ++++++++++++++++++++++ src/workspace.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/src/workspace.c b/src/workspace.c index b55f47b7..27ee473d 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -21,6 +21,7 @@ #include "workspace.h" #include "tile_container.h" +#include "toolkit/toolkit.h" #include @@ -70,6 +71,9 @@ struct _wlmaker_workspace_t { /** Scene graph subtree holding all layers of this workspace. */ struct wlr_scene_tree *wlr_scene_tree_ptr; + /** Transitional: Link up to toolkit workspace. */ + wlmtk_workspace_t *wlmtk_workspace_ptr; + /** Data regarding each layer. */ wlmaker_workspace_layer_data_t layers[WLMAKER_WORKSPACE_LAYER_NUM]; @@ -126,6 +130,13 @@ wlmaker_workspace_t *wlmaker_workspace_create(wlmaker_server_t *server_ptr, return NULL; } + workspace_ptr->wlmtk_workspace_ptr = wlmtk_workspace_create( + workspace_ptr->wlr_scene_tree_ptr); + if (NULL == workspace_ptr->wlmtk_workspace_ptr) { + wlmaker_workspace_destroy(workspace_ptr); + return NULL; + } + workspace_ptr->fullscreen_wlr_scene_tree_ptr = wlr_scene_tree_create(workspace_ptr->wlr_scene_tree_ptr); if (NULL == workspace_ptr->fullscreen_wlr_scene_tree_ptr) { @@ -203,6 +214,11 @@ void wlmaker_workspace_destroy(wlmaker_workspace_t *workspace_ptr) workspace_ptr->fullscreen_wlr_scene_tree_ptr = NULL; } + if (NULL != workspace_ptr->wlmtk_workspace_ptr) { + wlmtk_workspace_destroy(workspace_ptr->wlmtk_workspace_ptr); + workspace_ptr->wlmtk_workspace_ptr = NULL; + } + if (NULL != workspace_ptr->wlr_scene_tree_ptr) { wlr_scene_node_destroy(&workspace_ptr->wlr_scene_tree_ptr->node); } @@ -639,6 +655,12 @@ wlmaker_tile_container_t *wlmaker_workspace_get_tile_container( return workspace_ptr->tile_container_ptr; } +/* ------------------------------------------------------------------------- */ +wlmtk_workspace_t *wlmaker_workspace_wlmtk(wlmaker_workspace_t *workspace_ptr) +{ + return workspace_ptr->wlmtk_workspace_ptr; +} + /* == Static (local) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/workspace.h b/src/workspace.h index 32d39a2a..a63735e5 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -333,6 +333,11 @@ bs_dllist_node_t *wlmaker_dlnode_from_workspace( wlmaker_tile_container_t *wlmaker_workspace_get_tile_container( wlmaker_workspace_t *workspace_ptr); +typedef struct _wlmtk_workspace_t wlmtk_workspace_t; + +/** Transitional: Returns the @ref wlmtk_workspace_t. */ +wlmtk_workspace_t *wlmaker_workspace_wlmtk(wlmaker_workspace_t *workspace_ptr); + /** Unit tests. */ extern const bs_test_case_t wlmaker_workspace_test_cases[]; From 6cf655a85d241782b94c92b9fb597518b00caed4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 10:30:08 +0200 Subject: [PATCH 026/390] Adds prototype wiring of toolkit's window and content into XDG toplevel code. --- src/xdg_toplevel.c | 184 ++++++++++++++++++++++++++++++++++++++++++++- src/xdg_toplevel.h | 24 ++++++ 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index ef9238a9..7ae899ec 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -24,6 +24,8 @@ #include "util.h" #include "xdg_popup.h" +#include "toolkit/toolkit.h" + /* == Declarations ========================================================= */ /** State of an XDG toplevel surface. */ @@ -45,7 +47,6 @@ struct _wlmaker_xdg_toplevel_t { /** ID of the last 'set_size' call. */ uint32_t pending_resize_serial; - /** Listener for the `destroy` signal of the `wlr_xdg_surface`. */ struct wl_listener destroy_listener; /** Listener for the `new_popup` signal of the `wlr_xdg_surface`. */ @@ -76,6 +77,9 @@ struct _wlmaker_xdg_toplevel_t { struct wl_listener toplevel_set_title_listener; /** Listener for the `set_app_id` signal of the `wlr_xdg_toplevel`. */ struct wl_listener toplevel_set_app_id_listener; + + /** Transitional: Content. */ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr; }; static wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_from_view( @@ -147,6 +151,33 @@ static void wlmaker_xdg_toplevel_set_fullscreen( wlmaker_view_t *view_ptr, bool fullscreen); + +/* ######################################################################### */ + +/** State of the content for an XDG toplevel surface. */ +struct _wlmtk_xdg_toplevel_content_t { + /** Super class. */ + wlmtk_content_t super_content; + + /** Back-link to server. */ + wlmaker_server_t *server_ptr; + + /** The corresponding wlroots XDG surface. */ + struct wlr_xdg_surface *wlr_xdg_surface_ptr; + + /** Listener for the `map` signal of the `wlr_surface`. */ + struct wl_listener surface_map_listener; + /** Listener for the `unmap` signal of the `wlr_surface`. */ + struct wl_listener surface_unmap_listener; +}; + +static void handle_surface_map( + struct wl_listener *listener_ptr, + void *data_ptr); +static void handle_surface_unmap( + struct wl_listener *listener_ptr, + void *data_ptr); + /* == Data ================================================================= */ /** View implementor methods. */ @@ -158,6 +189,19 @@ const wlmaker_view_impl_t xdg_toplevel_view_impl = { .set_fullscreen = wlmaker_xdg_toplevel_set_fullscreen }; +/* ######################################################################### */ + +static void xdg_tl_content_destroy(wlmtk_content_t *content_ptr); +static struct wlr_scene_node *xdg_tl_content_create_scene_node( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); + +/** Method table for the `wlmtk_content_t` virtual methods. */ +const wlmtk_content_impl_t content_impl = { + .destroy = xdg_tl_content_destroy, + .create_scene_node = xdg_tl_content_create_scene_node +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -239,6 +283,10 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( return NULL; } + xdg_toplevel_ptr->xdg_tl_content_ptr = + wlmtk_xdg_toplevel_content_create( + wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); + wlmaker_view_init( &xdg_toplevel_ptr->view, &xdg_toplevel_view_impl, @@ -251,6 +299,8 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( wlmaker_view_set_position(&xdg_toplevel_ptr->view, 32, 40); + + return xdg_toplevel_ptr; } @@ -259,6 +309,11 @@ void wlmaker_xdg_toplevel_destroy(wlmaker_xdg_toplevel_t *xdg_toplevel_ptr) { wlmaker_view_fini(&xdg_toplevel_ptr->view); + if (NULL != xdg_toplevel_ptr->xdg_tl_content_ptr) { + wlmtk_xdg_toplevel_content_destroy(xdg_toplevel_ptr->xdg_tl_content_ptr); + xdg_toplevel_ptr->xdg_tl_content_ptr = NULL; + } + wlmaker_xdg_toplevel_t *tl_ptr = xdg_toplevel_ptr; // For shorter lines. wl_list_remove(&tl_ptr->destroy_listener.link); wl_list_remove(&tl_ptr->surface_map_listener.link); @@ -279,6 +334,48 @@ void wlmaker_xdg_toplevel_destroy(wlmaker_xdg_toplevel_t *xdg_toplevel_ptr) free(xdg_toplevel_ptr); } +/* ######################################################################### */ + +/* ------------------------------------------------------------------------- */ +wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( + struct wlr_xdg_surface *wlr_xdg_surface_ptr, + wlmaker_server_t *server_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = logged_calloc( + 1, sizeof(wlmtk_xdg_toplevel_content_t)); + if (NULL == xdg_tl_content_ptr) return NULL; + + if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, + &content_impl)) { + wlmtk_xdg_toplevel_content_destroy(xdg_tl_content_ptr); + return NULL; + } + xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; + xdg_tl_content_ptr->server_ptr = server_ptr; + + wlm_util_connect_listener_signal( + &wlr_xdg_surface_ptr->surface->events.map, + &xdg_tl_content_ptr->surface_map_listener, + handle_surface_map); + wlm_util_connect_listener_signal( + &wlr_xdg_surface_ptr->surface->events.unmap, + &xdg_tl_content_ptr->surface_unmap_listener, + handle_surface_unmap); + + return xdg_tl_content_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_xdg_toplevel_content_destroy( + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) +{ + wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); + wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); + + wlmtk_content_fini(&xdg_tl_content_ptr->super_content); + free(xdg_tl_content_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -685,4 +782,89 @@ void handle_toplevel_set_app_id(struct wl_listener *listener_ptr, xdg_toplevel_ptr->wlr_xdg_surface_ptr->toplevel->app_id); } +/* ######################################################################### */ + +/* ------------------------------------------------------------------------- */ +/** + * Destructor. Wraps to @ref wlmtk_xdg_toplevel_content_destroy. + * + * @param content_ptr + */ +void xdg_tl_content_destroy(wlmtk_content_t *content_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + wlmtk_xdg_toplevel_content_destroy(xdg_tl_content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Destructor. Wraps to @ref wlmtk_xdg_toplevel_content_destroy. + * + * @param content_ptr + */ +struct wlr_scene_node *xdg_tl_content_create_scene_node( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + struct wlr_scene_tree *surface_wlr_scene_tree_ptr = + wlr_scene_xdg_surface_create( + wlr_scene_tree_ptr, + xdg_tl_content_ptr->wlr_xdg_surface_ptr); + return &surface_wlr_scene_tree_ptr->node; +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `map` signal. + * + * Issued when the XDG toplevel is fully configured and ready to be shown. + * Will add it to the current workspace. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_surface_map( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, surface_map_listener); + + wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( + wlmaker_server_get_current_workspace(xdg_tl_content_ptr->server_ptr)); + + wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( + &xdg_tl_content_ptr->super_content); + + wlmtk_workspace_map_window(wlmtk_workspace_ptr, wlmtk_window_ptr); + wlmtk_element_map(&xdg_tl_content_ptr->super_content.super_element); +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `unmap` signal. Removes it from the workspace. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_surface_unmap( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, surface_unmap_listener); + + wlmtk_window_t *window_ptr = xdg_tl_content_ptr->super_content.window_ptr; + wlmtk_workspace_unmap_window( + wlmtk_workspace_from_container( + wlmtk_window_element(window_ptr)->parent_container_ptr), + window_ptr); + + wlmtk_window_destroy(window_ptr); +} + /* == End of xdg_toplevel.c ================================================ */ diff --git a/src/xdg_toplevel.h b/src/xdg_toplevel.h index 5b531d05..cce28516 100644 --- a/src/xdg_toplevel.h +++ b/src/xdg_toplevel.h @@ -21,6 +21,7 @@ #define __XDG_TOPLEVEL_H__ #include "xdg_shell.h" +#include "toolkit/toolkit.h" #ifdef __cplusplus extern "C" { @@ -48,6 +49,29 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( */ void wlmaker_xdg_toplevel_destroy(wlmaker_xdg_toplevel_t *xdg_toplevel_ptr); +/** Content for XDG toplvel. */ +typedef struct _wlmtk_xdg_toplevel_content_t wlmtk_xdg_toplevel_content_t; + +/** + * Creates a `wlmtk_content` for the given XDG surface. + * + * @param xdg_surface_ptr + * + * @return Pointer to the content. + */ +wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( + struct wlr_xdg_surface *wlr_xdg_surface_ptr, + wlmaker_server_t *server_ptrx); + +/** + * Destroys the toplevel content. + * + * @param xdgtl_content_ptr + */ +void wlmtk_xdg_toplevel_content_destroy( + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr); + + #ifdef __cplusplus } // extern "C" #endif // __cplusplus From 3ef7f20424ebe57c23a14a6d2f474ccbb0a1d19b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 10:32:30 +0200 Subject: [PATCH 027/390] Fixes doxygen comments and warnings. --- src/toolkit/toolkit.h | 2 +- src/workspace.h | 3 +-- src/xdg_toplevel.c | 5 ++++- src/xdg_toplevel.h | 7 ++++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 5cf69e04..2e5ace93 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -292,7 +292,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, * * Asserts that the container is indeed from a wlmtk_workspace_t. * - * @reutrn Pointer to the workspace. + * @return Pointer to the workspace. */ wlmtk_workspace_t *wlmtk_workspace_from_container( wlmtk_container_t *container_ptr); diff --git a/src/workspace.h b/src/workspace.h index a63735e5..eb0fdfbf 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -50,6 +50,7 @@ enum _wlmaker_workspace_layer_t { #include "layer_surface.h" #include "server.h" #include "tile_container.h" +#include "toolkit/toolkit.h" #ifdef __cplusplus extern "C" { @@ -333,8 +334,6 @@ bs_dllist_node_t *wlmaker_dlnode_from_workspace( wlmaker_tile_container_t *wlmaker_workspace_get_tile_container( wlmaker_workspace_t *workspace_ptr); -typedef struct _wlmtk_workspace_t wlmtk_workspace_t; - /** Transitional: Returns the @ref wlmtk_workspace_t. */ wlmtk_workspace_t *wlmaker_workspace_wlmtk(wlmaker_workspace_t *workspace_ptr); diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index 7ae899ec..7bb8ed7b 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -799,9 +799,12 @@ void xdg_tl_content_destroy(wlmtk_content_t *content_ptr) /* ------------------------------------------------------------------------- */ /** - * Destructor. Wraps to @ref wlmtk_xdg_toplevel_content_destroy. + * Creates the wlroots scene graph API node, attached to `wlr_scene_tree_ptr`. * * @param content_ptr + * @param wlr_scene_tree_ptr + * + * @return Scene graph API node that represents the content. */ struct wlr_scene_node *xdg_tl_content_create_scene_node( wlmtk_content_t *content_ptr, diff --git a/src/xdg_toplevel.h b/src/xdg_toplevel.h index cce28516..aa061095 100644 --- a/src/xdg_toplevel.h +++ b/src/xdg_toplevel.h @@ -55,18 +55,19 @@ typedef struct _wlmtk_xdg_toplevel_content_t wlmtk_xdg_toplevel_content_t; /** * Creates a `wlmtk_content` for the given XDG surface. * - * @param xdg_surface_ptr + * @param wlr_xdg_surface_ptr + * @param server_ptr * * @return Pointer to the content. */ wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( struct wlr_xdg_surface *wlr_xdg_surface_ptr, - wlmaker_server_t *server_ptrx); + wlmaker_server_t *server_ptr); /** * Destroys the toplevel content. * - * @param xdgtl_content_ptr + * @param xdg_tl_content_ptr */ void wlmtk_xdg_toplevel_content_destroy( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr); From 4272d384a74e7f9014e91eb1faf18962d440fba6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 13:18:29 +0200 Subject: [PATCH 028/390] Changes container behaviour to map children elements when creating the own scene node. --- src/toolkit/CMakeLists.txt | 2 ++ src/toolkit/container.c | 53 ++++++++++++++++++++++++++++++++++++++ src/toolkit/element.c | 30 +++++++++++++++++++++ src/toolkit/toolkit.h | 7 +++++ src/toolkit/workspace.c | 29 ++++++++++++++++++++- src/xdg_toplevel.c | 1 - 6 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 499883f3..06e680f2 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ TARGET_SOURCES(toolkit PRIVATE content.c gfxbuf.c primitives.c + ../util.c window.c workspace.c) TARGET_INCLUDE_DIRECTORIES( @@ -55,6 +56,7 @@ TARGET_LINK_LIBRARIES( base PkgConfig::CAIRO PkgConfig::LIBDRM + PkgConfig::WAYLAND PkgConfig::WLROOTS ) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 9284efaa..91a1ac6a 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -20,6 +20,8 @@ #include "toolkit.h" +#include "../util.h" + #define WLR_USE_UNSTABLE #include #undef WLR_USE_UNSTABLE @@ -30,6 +32,9 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void handle_wlr_scene_tree_node_destroy( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr); /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_impl_t super_element_impl = { @@ -128,6 +133,9 @@ void element_destroy(wlmtk_element_t *element_ptr) /** * Implementation of the superclass wlmtk_element_t::create_scene_node method. * + * Creates the wlroots scene graph tree for the container, and will map all + * already-contained elements. + * * @param element_ptr * @param wlr_scene_tree_ptr * @@ -145,9 +153,54 @@ struct wlr_scene_node *element_create_scene_node( wlr_scene_tree_ptr); BS_ASSERT(NULL != container_ptr->wlr_scene_tree_ptr); + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + // We are only just now creating the tree node for this very container, + // so none of the children can be mapped already. Do that now. + BS_ASSERT(!wlmtk_element_mapped(element_ptr)); + wlmtk_element_map(element_ptr); + } + + wlm_util_connect_listener_signal( + &container_ptr->wlr_scene_tree_ptr->node.events.destroy, + &container_ptr->wlr_scene_tree_node_destroy_listener, + handle_wlr_scene_tree_node_destroy); return &container_ptr->wlr_scene_tree_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** + * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. + * + * Will explicitly unmap each of the contained elements. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_wlr_scene_tree_node_destroy( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_container_t, wlr_scene_tree_node_destroy_listener); + + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + if (wlmtk_element_mapped(element_ptr)) { + wlmtk_element_unmap(element_ptr); + } + } + + // Since this is a callback from the tree node dtor, the tree is going to + // be destroyed. We are using this to reset the container's reference. + wl_list_remove(&container_ptr->wlr_scene_tree_node_destroy_listener.link); + container_ptr->wlr_scene_tree_ptr = NULL; +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index e30e21ea..3f2e6618 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -20,12 +20,18 @@ #include "toolkit.h" +#include "../util.h" + #define WLR_USE_UNSTABLE #include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ +static void handle_wlr_scene_node_destroy( + struct wl_listener *listener_ptr, + void *data_ptr); + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -92,6 +98,11 @@ void wlmtk_element_map(wlmtk_element_t *element_ptr) element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( element_ptr, parent_wlr_scene_tree_ptr); + wlm_util_connect_listener_signal( + &element_ptr->wlr_scene_node_ptr->events.destroy, + &element_ptr->wlr_scene_node_destroy_listener, + handle_wlr_scene_node_destroy); + // TODO(kaeser@gubbe.ch): Separate map method into set_visible/attach. wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, true); BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); @@ -103,12 +114,31 @@ void wlmtk_element_unmap(wlmtk_element_t *element_ptr) BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); // TODO(kaeser@gubbe.ch): Separate map method into set_visible/attach. wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, false); + wl_list_remove(&element_ptr->wlr_scene_node_destroy_listener.link); wlr_scene_node_destroy(element_ptr->wlr_scene_node_ptr); element_ptr->wlr_scene_node_ptr = NULL; } /* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** + * Handles the 'destroy' callback of the wlr_scene_node. + * + * A call here indicates that teardown was not executed properly! + * + * @param listener_ptr + * @param data_ptr + */ +void handle_wlr_scene_node_destroy( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_element_t *element_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_element_t, wlr_scene_node_destroy_listener); + bs_log(BS_FATAL, "Unexpected call into node's dtor on %p!", element_ptr); +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 2e5ace93..e4dd6da2 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -27,6 +27,7 @@ #include "style.h" #include +#include #ifdef __cplusplus extern "C" { @@ -67,6 +68,9 @@ struct _wlmtk_element_t { /** Points to the wlroots scene graph API node. Is set when mapped. */ struct wlr_scene_node *wlr_scene_node_ptr; + + /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ + struct wl_listener wlr_scene_node_destroy_listener; }; /** Pointers to the implementation of Element's virtual methods. */ @@ -169,6 +173,9 @@ struct _wlmtk_container_t { /** Scene tree. */ struct wlr_scene_tree *wlr_scene_tree_ptr; + + /** Listener for the `destroy` signal of `wlr_scene_tree_ptr->node`. */ + struct wl_listener wlr_scene_tree_node_destroy_listener; }; /** Virtual method table of the container. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 95353d60..8c77dec3 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -160,6 +160,27 @@ void test_create_destroy(bs_test_t *test_ptr) // Note: There is no destroy method for wlr_scene_ptr. } +/** dtor for the content under test. */ +static void test_content_destroy( + wlmtk_content_t *content_ptr) +{ + wlmtk_content_fini(content_ptr); +} +/** scene node creation for the node under test. */ +static struct wlr_scene_node *test_content_create_scene_node( + __UNUSED__ wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( + wlr_scene_tree_ptr, NULL); + return &wlr_scene_buffer_ptr->node; +} +/** Method table for the node under test. */ +static const wlmtk_content_impl_t test_content_impl = { + .destroy = test_content_destroy, + .create_scene_node = test_content_create_scene_node +}; + /* ------------------------------------------------------------------------- */ /** Verifies that mapping and unmapping windows works. */ void test_map_unmap(bs_test_t *test_ptr) @@ -171,7 +192,7 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); wlmtk_content_t content; - memset(&content, 0, sizeof(content)); + wlmtk_content_init(&content, &test_content_impl); wlmtk_window_t *window_ptr = wlmtk_window_create(&content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); @@ -179,11 +200,17 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_mapped(wlmtk_window_element(window_ptr))); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_mapped(&content.super_element)); wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); BS_TEST_VERIFY_FALSE( test_ptr, wlmtk_element_mapped(wlmtk_window_element(window_ptr))); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_mapped(&content.super_element)); wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index 7bb8ed7b..95bde5b4 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -844,7 +844,6 @@ void handle_surface_map( &xdg_tl_content_ptr->super_content); wlmtk_workspace_map_window(wlmtk_workspace_ptr, wlmtk_window_ptr); - wlmtk_element_map(&xdg_tl_content_ptr->super_content.super_element); } /* ------------------------------------------------------------------------- */ From acf9f2fd91544b648b93ea1d2c617dca20b45cf0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 13:23:39 +0200 Subject: [PATCH 029/390] Moves util.h into the toolkit subdirectory. --- src/CMakeLists.txt | 2 -- src/clip.c | 4 ++-- src/cursor.c | 14 +++++++------- src/dock.c | 4 ++-- src/icon_manager.c | 4 ++-- src/keyboard.c | 6 +++--- src/layer_shell.c | 6 +++--- src/layer_surface.c | 12 ++++++------ src/output.c | 8 ++++---- src/server.c | 10 +++++----- src/subprocess_monitor.c | 10 +++++----- src/task_list.c | 10 +++++----- src/toolkit/CMakeLists.txt | 5 +++-- src/toolkit/container.c | 4 ++-- src/toolkit/element.c | 4 ++-- src/toolkit/toolkit.h | 1 + src/{ => toolkit}/util.c | 2 +- src/{ => toolkit}/util.h | 2 +- src/view.c | 4 ++-- src/xdg_decoration.c | 10 +++++----- src/xdg_popup.c | 6 +++--- src/xdg_shell.c | 6 +++--- src/xdg_toplevel.c | 34 +++++++++++++++++----------------- 23 files changed, 84 insertions(+), 84 deletions(-) rename src/{ => toolkit}/util.c (96%) rename src/{ => toolkit}/util.h (97%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1e89d140..eca4285b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,7 +39,6 @@ SET(SOURCES tile.c tile_container.c titlebar.c - util.c view.c workspace.c xdg_decoration.c @@ -73,7 +72,6 @@ SET(HEADERS tile_container.h tile.h titlebar.h - util.h view.h workspace.h xdg_decoration.h diff --git a/src/clip.c b/src/clip.c index acfcf688..c7996e73 100644 --- a/src/clip.c +++ b/src/clip.c @@ -23,7 +23,7 @@ #include "button.h" #include "config.h" #include "decorations.h" -#include "util.h" +#include "toolkit/toolkit.h" /* == Declarations ========================================================= */ @@ -250,7 +250,7 @@ wlmaker_clip_t *wlmaker_clip_create( clip_ptr->view.anchor = WLMAKER_VIEW_ANCHOR_BOTTOM | WLMAKER_VIEW_ANCHOR_RIGHT; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->workspace_changed, &clip_ptr->workspace_changed_listener, handle_workspace_changed); diff --git a/src/cursor.c b/src/cursor.c index 9e40fce6..8f1af2a8 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -21,7 +21,7 @@ #include "cursor.h" #include "config.h" -#include "util.h" +#include "toolkit/toolkit.h" #include @@ -107,28 +107,28 @@ wlmaker_cursor_t *wlmaker_cursor_create(wlmaker_server_t *server_ptr) // https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html // TODO: Need a mode for 'normal', 'move', 'resize'. - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &cursor_ptr->wlr_cursor_ptr->events.motion, &cursor_ptr->motion_listener, handle_motion); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &cursor_ptr->wlr_cursor_ptr->events.motion_absolute, &cursor_ptr->motion_absolute_listener, handle_motion_absolute); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &cursor_ptr->wlr_cursor_ptr->events.button, &cursor_ptr->button_listener, handle_button); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &cursor_ptr->wlr_cursor_ptr->events.axis, &cursor_ptr->axis_listener, handle_axis); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &cursor_ptr->wlr_cursor_ptr->events.frame, &cursor_ptr->frame_listener, handle_frame); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &cursor_ptr->server_ptr->wlr_seat_ptr->events.request_set_cursor, &cursor_ptr->seat_request_set_cursor_listener, handle_seat_request_set_cursor); diff --git a/src/dock.c b/src/dock.c index 8b72011e..d32e06fb 100644 --- a/src/dock.c +++ b/src/dock.c @@ -22,7 +22,7 @@ #include "config.h" #include "dock_app.h" -#include "util.h" +#include "toolkit/toolkit.h" #include "view.h" /* == Declarations ========================================================= */ @@ -129,7 +129,7 @@ wlmaker_dock_t *wlmaker_dock_create( } } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->workspace_changed, &dock_ptr->workspace_changed_listener, handle_workspace_changed); diff --git a/src/icon_manager.c b/src/icon_manager.c index c49b2bad..30c9d788 100644 --- a/src/icon_manager.c +++ b/src/icon_manager.c @@ -26,7 +26,7 @@ #include #undef WLR_USE_UNSTABLE -#include "util.h" +#include "toolkit/toolkit.h" #include "wlmaker-icon-unstable-v1-server-protocol.h" /* == Declarations ========================================================= */ @@ -345,7 +345,7 @@ wlmaker_toplevel_icon_t *wlmaker_toplevel_icon_create( toplevel_icon_ptr, toplevel_icon_resource_destroy); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &toplevel_icon_ptr->wlr_surface_ptr->events.commit, &toplevel_icon_ptr->surface_commit_listener, handle_surface_commit); diff --git a/src/keyboard.c b/src/keyboard.c index 8df2f301..f3680fbc 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -21,7 +21,7 @@ #include "keyboard.h" #include "config.h" -#include "util.h" +#include "toolkit/toolkit.h" #include "server.h" /* == Declarations ========================================================= */ @@ -79,11 +79,11 @@ wlmaker_keyboard_t *wlmaker_keyboard_create( config_keyboard_repeat_rate, config_keyboard_repeat_delay); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &keyboard_ptr->wlr_keyboard_ptr->events.key, &keyboard_ptr->key_listener, handle_key); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &keyboard_ptr->wlr_keyboard_ptr->events.modifiers, &keyboard_ptr->modifiers_listener, handle_modifiers); diff --git a/src/layer_shell.c b/src/layer_shell.c index 8653fe13..d317f533 100644 --- a/src/layer_shell.c +++ b/src/layer_shell.c @@ -21,7 +21,7 @@ #include "layer_shell.h" #include "layer_surface.h" -#include "util.h" +#include "toolkit/toolkit.h" #include @@ -69,11 +69,11 @@ wlmaker_layer_shell_t *wlmaker_layer_shell_create(wlmaker_server_t *server_ptr) return NULL; } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &layer_shell_ptr->wlr_layer_shell_v1_ptr->events.new_surface, &layer_shell_ptr->new_surface_listener, handle_new_surface); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &layer_shell_ptr->wlr_layer_shell_v1_ptr->events.destroy, &layer_shell_ptr->destroy_listener, handle_destroy); diff --git a/src/layer_surface.c b/src/layer_surface.c index e1792f63..e02f2d85 100644 --- a/src/layer_surface.c +++ b/src/layer_surface.c @@ -20,7 +20,7 @@ #include "layer_surface.h" -#include "util.h" +#include "toolkit/toolkit.h" #include "view.h" #include "xdg_popup.h" @@ -109,25 +109,25 @@ wlmaker_layer_surface_t *wlmaker_layer_surface_create( return NULL; } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_layer_surface_v1_ptr->events.destroy, &layer_surface_ptr->destroy_listener, handle_destroy); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_layer_surface_v1_ptr->events.new_popup, &layer_surface_ptr->new_popup_listener, handle_new_popup); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_layer_surface_v1_ptr->surface->events.map, &layer_surface_ptr->surface_map_listener, handle_map); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_layer_surface_v1_ptr->surface->events.unmap, &layer_surface_ptr->surface_unmap_listener, handle_unmap); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_layer_surface_v1_ptr->surface->events.commit, &layer_surface_ptr->surface_commit_listener, handle_surface_commit); diff --git a/src/output.c b/src/output.c index e05acb24..b90f7423 100644 --- a/src/output.c +++ b/src/output.c @@ -23,7 +23,7 @@ #include "output.h" -#include "util.h" +#include "toolkit/toolkit.h" #include @@ -54,15 +54,15 @@ wlmaker_output_t *wlmaker_output_create( output_ptr->wlr_scene_ptr = wlr_scene_ptr; output_ptr->server_ptr = server_ptr; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &output_ptr->wlr_output_ptr->events.destroy, &output_ptr->output_destroy_listener, handle_output_destroy); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &output_ptr->wlr_output_ptr->events.frame, &output_ptr->output_frame_listener, handle_output_frame); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &output_ptr->wlr_output_ptr->events.request_state, &output_ptr->output_request_state_listener, handle_request_state); diff --git a/src/server.c b/src/server.c index 443d2fbb..03b2e5a4 100644 --- a/src/server.c +++ b/src/server.c @@ -22,7 +22,7 @@ #include "config.h" #include "output.h" -#include "util.h" +#include "toolkit/toolkit.h" #include @@ -141,11 +141,11 @@ wlmaker_server_t *wlmaker_server_create(void) } // Listen for new (or newly recognized) output and input devices. - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->wlr_backend_ptr->events.new_output, &server_ptr->backend_new_output_listener, handle_new_output); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->wlr_backend_ptr->events.new_input, &server_ptr->backend_new_input_device_listener, handle_new_input_device); @@ -181,7 +181,7 @@ wlmaker_server_t *wlmaker_server_create(void) wlmaker_server_destroy(server_ptr); return NULL; } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->wlr_output_layout_ptr->events.change, &server_ptr->output_layout_change_listener, handle_output_layout_change); @@ -554,7 +554,7 @@ bool register_input_device(wlmaker_server_t *server_ptr, input_device_ptr->wlr_input_device_ptr = wlr_input_device_ptr; input_device_ptr->handle_ptr = handle_ptr; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_input_device_ptr->events.destroy, &input_device_ptr->destroy_listener, handle_destroy_input_device); diff --git a/src/subprocess_monitor.c b/src/subprocess_monitor.c index 84bc1ae1..6176ce43 100644 --- a/src/subprocess_monitor.c +++ b/src/subprocess_monitor.c @@ -20,7 +20,7 @@ #include "subprocess_monitor.h" -#include "util.h" +#include "toolkit/toolkit.h" #include #include @@ -133,19 +133,19 @@ wlmaker_subprocess_monitor_t* wlmaker_subprocess_monitor_create( handle_sigchld, monitor_ptr); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->view_created_event, &monitor_ptr->view_created_listener, handle_view_created); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->view_mapped_event, &monitor_ptr->view_mapped_listener, handle_view_mapped); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->view_unmapped_event, &monitor_ptr->view_unmapped_listener, handle_view_unmapped); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->view_destroyed_event, &monitor_ptr->view_destroyed_listener, handle_view_destroyed); diff --git a/src/task_list.c b/src/task_list.c index 1e692bbb..b98f6857 100644 --- a/src/task_list.c +++ b/src/task_list.c @@ -24,7 +24,7 @@ #include "task_list.h" #include "config.h" -#include "util.h" +#include "toolkit/toolkit.h" #include #include @@ -144,19 +144,19 @@ wlmaker_task_list_t *wlmaker_task_list_create( task_list_ptr->wlr_scene_tree_ptr, NULL); // send_close_callback. - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->task_list_enabled_event, &task_list_ptr->task_list_enabled_listener, handle_task_list_enabled); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->task_list_disabled_event, &task_list_ptr->task_list_disabled_listener, handle_task_list_disabled); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->view_mapped_event, &task_list_ptr->view_mapped_listener, handle_view_mapped); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &server_ptr->view_unmapped_event, &task_list_ptr->view_unmapped_listener, handle_view_unmapped); diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 06e680f2..254a8e00 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -18,7 +18,8 @@ SET(PUBLIC_HEADER_FILES gfxbuf.h primitives.h style.h - toolkit.h) + toolkit.h + util.h) ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE @@ -27,7 +28,7 @@ TARGET_SOURCES(toolkit PRIVATE content.c gfxbuf.c primitives.c - ../util.c + util.c window.c workspace.c) TARGET_INCLUDE_DIRECTORIES( diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 91a1ac6a..81a57a1b 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -20,7 +20,7 @@ #include "toolkit.h" -#include "../util.h" +#include "util.h" #define WLR_USE_UNSTABLE #include @@ -163,7 +163,7 @@ struct wlr_scene_node *element_create_scene_node( wlmtk_element_map(element_ptr); } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &container_ptr->wlr_scene_tree_ptr->node.events.destroy, &container_ptr->wlr_scene_tree_node_destroy_listener, handle_wlr_scene_tree_node_destroy); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 3f2e6618..1447b0a6 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -20,7 +20,7 @@ #include "toolkit.h" -#include "../util.h" +#include "util.h" #define WLR_USE_UNSTABLE #include @@ -98,7 +98,7 @@ void wlmtk_element_map(wlmtk_element_t *element_ptr) element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( element_ptr, parent_wlr_scene_tree_ptr); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &element_ptr->wlr_scene_node_ptr->events.destroy, &element_ptr->wlr_scene_node_destroy_listener, handle_wlr_scene_node_destroy); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index e4dd6da2..b1e04484 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -25,6 +25,7 @@ #include "gfxbuf.h" #include "primitives.h" #include "style.h" +#include "util.h" #include #include diff --git a/src/util.c b/src/toolkit/util.c similarity index 96% rename from src/util.c rename to src/toolkit/util.c index 40683822..5521e0b4 100644 --- a/src/util.c +++ b/src/toolkit/util.c @@ -23,7 +23,7 @@ /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -void wlm_util_connect_listener_signal( +void wlmtk_util_connect_listener_signal( struct wl_signal *signal_ptr, struct wl_listener *listener_ptr, void (*notifier_func)(struct wl_listener *, void *)) diff --git a/src/util.h b/src/toolkit/util.h similarity index 97% rename from src/util.h rename to src/toolkit/util.h index 796432fd..2af9823e 100644 --- a/src/util.h +++ b/src/toolkit/util.h @@ -38,7 +38,7 @@ extern "C" { * @param listener_ptr * @param notifier_func */ -void wlm_util_connect_listener_signal( +void wlmtk_util_connect_listener_signal( struct wl_signal *signal_ptr, struct wl_listener *listener_ptr, void (*notifier_func)(struct wl_listener *, void *)); diff --git a/src/view.c b/src/view.c index ed3c8b41..3577c840 100644 --- a/src/view.c +++ b/src/view.c @@ -26,7 +26,7 @@ #include "menu.h" #include "resizebar.h" #include "titlebar.h" -#include "util.h" +#include "toolkit/toolkit.h" #include @@ -110,7 +110,7 @@ void wlmaker_view_init( wlmaker_interactive_node_destroy); BS_ASSERT(view_ptr->interactive_tree_ptr); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &view_ptr->server_ptr->cursor_ptr->button_release_event, &view_ptr->button_release_listener, handle_button_release); diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 48709186..afa01cce 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -23,7 +23,7 @@ #include #include "config.h" -#include "util.h" +#include "toolkit/toolkit.h" #define WLR_USE_UNSTABLE #include @@ -92,12 +92,12 @@ wlmaker_xdg_decoration_manager_t *wlmaker_xdg_decoration_manager_create( return NULL; } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &decoration_manager_ptr->wlr_xdg_decoration_manager_v1_ptr-> events.new_toplevel_decoration, &decoration_manager_ptr->new_toplevel_decoration_listener, handle_new_toplevel_decoration); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &decoration_manager_ptr->wlr_xdg_decoration_manager_v1_ptr-> events.destroy, &decoration_manager_ptr->destroy_listener, @@ -179,11 +179,11 @@ wlmaker_xdg_decoration_t *wlmaker_xdg_decoration_create( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr = wlr_xdg_toplevel_decoration_v1_ptr; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->events.destroy, &decoration_ptr->destroy_listener, handle_decoration_destroy); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->events.request_mode, &decoration_ptr->request_mode_listener, handle_decoration_request_mode); diff --git a/src/xdg_popup.c b/src/xdg_popup.c index 90528af6..ec67a42a 100644 --- a/src/xdg_popup.c +++ b/src/xdg_popup.c @@ -22,7 +22,7 @@ #include -#include "util.h" +#include "toolkit/toolkit.h" /* == Declarations ========================================================= */ @@ -58,11 +58,11 @@ wlmaker_xdg_popup_t *wlmaker_xdg_popup_create( if (NULL == xdg_popup_ptr) return NULL; xdg_popup_ptr->wlr_xdg_popup_ptr = wlr_xdg_popup_ptr; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_popup_ptr->base->events.destroy, &xdg_popup_ptr->destroy_listener, handle_destroy); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_popup_ptr->base->events.new_popup, &xdg_popup_ptr->new_popup_listener, handle_new_popup); diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 4c10e674..54fdc6c7 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -20,7 +20,7 @@ #include "xdg_shell.h" -#include "util.h" +#include "toolkit/toolkit.h" #include "view.h" #include "xdg_toplevel.h" @@ -52,11 +52,11 @@ wlmaker_xdg_shell_t *wlmaker_xdg_shell_create(wlmaker_server_t *server_ptr) return NULL; } - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &xdg_shell_ptr->wlr_xdg_shell_ptr->events.new_surface, &xdg_shell_ptr->new_surface_listener, handle_new_surface); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &xdg_shell_ptr->wlr_xdg_shell_ptr->events.destroy, &xdg_shell_ptr->destroy_listener, handle_destroy); diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index 95bde5b4..a658c8f5 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -21,7 +21,7 @@ #include "xdg_toplevel.h" #include "iconified.h" -#include "util.h" +#include "toolkit/toolkit.h" #include "xdg_popup.h" #include "toolkit/toolkit.h" @@ -214,61 +214,61 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( if (NULL == xdg_toplevel_ptr) return NULL; xdg_toplevel_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->events.destroy, &xdg_toplevel_ptr->destroy_listener, handle_destroy); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->events.new_popup, &xdg_toplevel_ptr->new_popup_listener, handle_new_popup); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.map, &xdg_toplevel_ptr->surface_map_listener, handle_map); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.unmap, &xdg_toplevel_ptr->surface_unmap_listener, handle_unmap); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.commit, &xdg_toplevel_ptr->surface_commit_listener, handle_surface_commit); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_maximize, &xdg_toplevel_ptr->toplevel_request_maximize_listener, handle_toplevel_maximize); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_fullscreen, &xdg_toplevel_ptr->toplevel_request_fullscreen_listener, handle_toplevel_fullscreen); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_minimize, &xdg_toplevel_ptr->toplevel_request_minimize_listener, handle_toplevel_minimize); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_move, &xdg_toplevel_ptr->toplevel_request_move_listener, handle_toplevel_move); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_resize, &xdg_toplevel_ptr->toplevel_request_resize_listener, handle_toplevel_resize); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_show_window_menu, &xdg_toplevel_ptr->toplevel_request_show_window_menu_listener, handle_toplevel_show_window_menu); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.set_parent, &xdg_toplevel_ptr->toplevel_set_parent_listener, handle_toplevel_set_parent); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.set_title, &xdg_toplevel_ptr->toplevel_set_title_listener, handle_toplevel_set_title); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.set_app_id, &xdg_toplevel_ptr->toplevel_set_app_id_listener, handle_toplevel_set_app_id); @@ -353,11 +353,11 @@ wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; xdg_tl_content_ptr->server_ptr = server_ptr; - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.map, &xdg_tl_content_ptr->surface_map_listener, handle_surface_map); - wlm_util_connect_listener_signal( + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.unmap, &xdg_tl_content_ptr->surface_unmap_listener, handle_surface_unmap); From 97c88a657f02d02fc1d48a41f8c2273c2d82b77b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 14:09:06 +0200 Subject: [PATCH 030/390] Adds a configurable for using the toolkit prototype. --- CMakeLists.txt | 1 + src/CMakeLists.txt | 3 +++ src/workspace.c | 18 +++++++++++------- src/xdg_toplevel.c | 3 +++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d9746fa..f597fb51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ PKG_CHECK_MODULES(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon>=1.0.3) # 1.4.1) OPTION(config_DEBUG "Include debugging information" ON) OPTION(config_OPTIM "Optimizations" OFF) OPTION(config_DOXYGEN_CRITICAL "Whether to fail on doxygen warnings" OFF) +OPTION(config_TOOLKIT_PROTOTYPE "Whether to include the toolkit prototype." OFF) # Toplevel compile options, for GCC. IF(CMAKE_C_COMPILER_ID STREQUAL "GNU") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eca4285b..58296c76 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,6 +93,9 @@ TARGET_COMPILE_OPTIONS( ${WAYLAND_CFLAGS} ${WAYLAND_CFLAGS_OTHER} ) +IF(config_TOOLKIT_PROTOTYPE) + TARGET_COMPILE_DEFINITIONS(wlmaker PUBLIC ENABLE_TOOLKIT_PROTOTYPE) +ENDIF(config_TOOLKIT_PROTOTYPE) TARGET_INCLUDE_DIRECTORIES( wlmaker PRIVATE ${PROJECT_BINARY_DIR}/third_party/protocols diff --git a/src/workspace.c b/src/workspace.c index 27ee473d..c6d78d47 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -130,13 +130,6 @@ wlmaker_workspace_t *wlmaker_workspace_create(wlmaker_server_t *server_ptr, return NULL; } - workspace_ptr->wlmtk_workspace_ptr = wlmtk_workspace_create( - workspace_ptr->wlr_scene_tree_ptr); - if (NULL == workspace_ptr->wlmtk_workspace_ptr) { - wlmaker_workspace_destroy(workspace_ptr); - return NULL; - } - workspace_ptr->fullscreen_wlr_scene_tree_ptr = wlr_scene_tree_create(workspace_ptr->wlr_scene_tree_ptr); if (NULL == workspace_ptr->fullscreen_wlr_scene_tree_ptr) { @@ -176,6 +169,17 @@ wlmaker_workspace_t *wlmaker_workspace_create(wlmaker_server_t *server_ptr, workspace_ptr->injectable_view_set_active = wlmaker_view_set_active; wlmaker_workspace_arrange_views(workspace_ptr); + +#if defined(ENABLE_TOOLKIT_PROTOTYPE) + // Transitional -- enable for prototyping: Toolkit-based workspace. + workspace_ptr->wlmtk_workspace_ptr = wlmtk_workspace_create( + workspace_ptr->wlr_scene_tree_ptr); + if (NULL == workspace_ptr->wlmtk_workspace_ptr) { + wlmaker_workspace_destroy(workspace_ptr); + return NULL; + } +#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) + return workspace_ptr; } diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index a658c8f5..d26130e5 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -283,9 +283,12 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( return NULL; } +#if defined(ENABLE_TOOLKIT_PROTOTYPE) + // Transitional -- enable for prototyping: Toolkit-based workspace. xdg_toplevel_ptr->xdg_tl_content_ptr = wlmtk_xdg_toplevel_content_create( wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); +#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) wlmaker_view_init( &xdg_toplevel_ptr->view, From e0d4dcfac25cbed3371a487c77a653072f282492 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 27 Aug 2023 14:18:20 +0200 Subject: [PATCH 031/390] Updates design for toolkit, preparing for the map() -> set_visible() move and automatic node initialization. --- src/toolkit/toolkit.md | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 9aa04dd0..de42e8bb 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -31,9 +31,8 @@ class Element { bool init(handlers) void fini() -void set_parent_container(Container*) - void map() - void unmap() - bool mapped() + void set_visible(bool) + bool is_visible() {abstract}#void destroy() {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) @@ -41,8 +40,17 @@ class Element { {abstract}#void leave() {abstract}#void click() } -note right of Element::"map()" - Only permitted if element is a member of a (mapped?) container. +note right of Element::"set_parent_container()" + If the parent is already part of the scene graph, this will also + invoke create_scene_node. +note right of Element::"set_visible()" + Marks the element as visible. + + If this element is already part of the scene graph, will adjust the + visibility of the node. Otherwise, if the parent is already part of the + scene graph (parent_container_ptr->wlr_scene_tree() is not NULL), this will + also invoke create_scene_node to create the scene node. + And then set visibility accordingly. end note class Container { @@ -54,7 +62,7 @@ class Container { add_element(Element*) remove_element(Element*) struct wlr_scene_tree *wlr_scene_tree() - + {abstract}#void destroy() void enter(Element*) @@ -62,6 +70,10 @@ class Container { void click(Element*) } Element <|-- Container +note right of Element::"add_element(Element*)" + If the super_element is already part of the scene graph, this will also + invoke the added element's create_scene_node. +end note class Workspace { Container super_container @@ -144,9 +156,9 @@ class Window { VBox super_container Content *content TitleBar title_bar - + Window *create(Content*) - destroy() + destroy() Element *element() } VBox *-- Window @@ -201,7 +213,7 @@ Buffer <|-- MenuItem set title handler: - + * window::set_title request maximize handler: From b62e24f6e8b606a7055240d36f4ca3f065702b4c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 29 Aug 2023 21:51:54 +0200 Subject: [PATCH 032/390] Updates the toolkid with a better scene graph integration: * Scene nodes will be created when the element's parent is set and has a node, or (delayed) once the parent's scene tree is created. * Same applies for scene node deletion, this is done when the element changes parent, or when the parent's tree is destroyed. * Also switch wording to use "set_visible" rather than map/unmap for elements, to clearly separate it from the node attach/detach function. Verified with the tests. --- src/toolkit/container.c | 47 ++++++--------- src/toolkit/element.c | 127 +++++++++++++++++++++++++--------------- src/toolkit/toolkit.h | 57 ++++++++++-------- src/toolkit/toolkit.md | 26 ++++---- src/toolkit/workspace.c | 33 ++++++----- 5 files changed, 162 insertions(+), 128 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 81a57a1b..04cef63d 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -71,7 +71,6 @@ void wlmtk_container_fini(wlmtk_container_t *container_ptr) wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); wlmtk_container_remove_element(container_ptr, element_ptr); BS_ASSERT(container_ptr->elements.head_ptr != dlnode_ptr); - wlmtk_element_destroy(element_ptr); } @@ -84,6 +83,8 @@ void wlmtk_container_add_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr) { + BS_ASSERT(NULL == element_ptr->parent_container_ptr); + bs_dllist_push_back( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); @@ -97,10 +98,6 @@ void wlmtk_container_remove_element( { BS_ASSERT(element_ptr->parent_container_ptr == container_ptr); - if (wlmtk_element_mapped(element_ptr)) { - wlmtk_element_unmap(element_ptr); - } - wlmtk_element_set_parent_container(element_ptr, NULL); bs_dllist_remove( &container_ptr->elements, @@ -133,8 +130,8 @@ void element_destroy(wlmtk_element_t *element_ptr) /** * Implementation of the superclass wlmtk_element_t::create_scene_node method. * - * Creates the wlroots scene graph tree for the container, and will map all - * already-contained elements. + * Creates the wlroots scene graph tree for the container, and will attach all + * already-contained elements to the scene graph, as well. * * @param element_ptr * @param wlr_scene_tree_ptr @@ -157,10 +154,8 @@ struct wlr_scene_node *element_create_scene_node( dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - // We are only just now creating the tree node for this very container, - // so none of the children can be mapped already. Do that now. - BS_ASSERT(!wlmtk_element_mapped(element_ptr)); - wlmtk_element_map(element_ptr); + BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + wlmtk_element_attach_to_scene_graph(element_ptr); } wlmtk_util_connect_listener_signal( @@ -174,7 +169,7 @@ struct wlr_scene_node *element_create_scene_node( /** * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. * - * Will explicitly unmap each of the contained elements. + * Will also detach (but not destroy) each of the still-contained elements. * * @param listener_ptr * @param data_ptr @@ -186,31 +181,29 @@ void handle_wlr_scene_tree_node_destroy( wlmtk_container_t *container_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_container_t, wlr_scene_tree_node_destroy_listener); + container_ptr->wlr_scene_tree_ptr = NULL; for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - if (wlmtk_element_mapped(element_ptr)) { - wlmtk_element_unmap(element_ptr); - } + wlmtk_element_attach_to_scene_graph(element_ptr); } // Since this is a callback from the tree node dtor, the tree is going to // be destroyed. We are using this to reset the container's reference. wl_list_remove(&container_ptr->wlr_scene_tree_node_destroy_listener.link); - container_ptr->wlr_scene_tree_ptr = NULL; } /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); -static void test_remove_mapped(bs_test_t *test_ptr); +static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, - { 1, "remove_mapped", test_remove_mapped }, + { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, { 0, NULL, NULL } }; @@ -300,8 +293,8 @@ void test_add_remove(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests that mapped elements are unmapped when removed. */ -void test_remove_mapped(bs_test_t *test_ptr) +/** Tests that elements are attached, resp. detached from scene graph. */ +void test_add_remove_with_scene_graph(bs_test_t *test_ptr) { wlmtk_container_t container; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( @@ -314,21 +307,19 @@ void test_remove_mapped(bs_test_t *test_ptr) wlmtk_element_set_parent_container( &container.super_element, &fake_parent); - // Self must be mapped before mapping any contained element. - wlmtk_element_map(&container.super_element); - BS_TEST_VERIFY_TRUE( - test_ptr, wlmtk_element_mapped(&container.super_element)); + // Want to have the node. + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, container.super_element.wlr_scene_node_ptr); wlmtk_element_t element; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_element_impl)); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_container_add_element(&container, &element); - wlmtk_element_map(&element); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); - + BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_container_remove_element(&container, &element); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_element_mapped(&element)); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_element_set_parent_container(&container.super_element, NULL); wlmtk_container_fini(&container); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 1447b0a6..b0126bdd 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -53,8 +53,8 @@ bool wlmtk_element_init( void wlmtk_element_fini( wlmtk_element_t *element_ptr) { - // Verify we're no longer mapped, nor part of a container. - BS_ASSERT(!wlmtk_element_mapped(element_ptr)); + // Verify we're no longer part of the scene graph, nor part of a container. + BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); BS_ASSERT(NULL == element_ptr->parent_container_ptr); element_ptr->impl_ptr = NULL; @@ -80,43 +80,61 @@ void wlmtk_element_set_parent_container( wlmtk_container_t *parent_container_ptr) { if (element_ptr->parent_container_ptr == parent_container_ptr) return; - - if (wlmtk_element_mapped(element_ptr)) { - wlmtk_element_unmap(element_ptr); - } element_ptr->parent_container_ptr = parent_container_ptr; + wlmtk_element_attach_to_scene_graph(element_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_element_map(wlmtk_element_t *element_ptr) +void wlmtk_element_attach_to_scene_graph( + wlmtk_element_t *element_ptr) { - BS_ASSERT(NULL != element_ptr->parent_container_ptr); - BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); - struct wlr_scene_tree *parent_wlr_scene_tree_ptr = - wlmtk_container_wlr_scene_tree(element_ptr->parent_container_ptr); - BS_ASSERT(NULL != parent_wlr_scene_tree_ptr); - - element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( - element_ptr, parent_wlr_scene_tree_ptr); - wlmtk_util_connect_listener_signal( - &element_ptr->wlr_scene_node_ptr->events.destroy, - &element_ptr->wlr_scene_node_destroy_listener, - handle_wlr_scene_node_destroy); - - // TODO(kaeser@gubbe.ch): Separate map method into set_visible/attach. - wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, true); + struct wlr_scene_tree *parent_wlr_scene_tree_ptr = NULL; + if (NULL != element_ptr->parent_container_ptr) { + parent_wlr_scene_tree_ptr = wlmtk_container_wlr_scene_tree( + element_ptr->parent_container_ptr); + } + + if (NULL == parent_wlr_scene_tree_ptr) { + if (NULL != element_ptr->wlr_scene_node_ptr) { + wl_list_remove(&element_ptr->wlr_scene_node_destroy_listener.link); + wlr_scene_node_destroy(element_ptr->wlr_scene_node_ptr); + element_ptr->wlr_scene_node_ptr = NULL; + } + return; + } + + if (NULL == element_ptr->wlr_scene_node_ptr) { + element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( + element_ptr, parent_wlr_scene_tree_ptr); + wlmtk_util_connect_listener_signal( + &element_ptr->wlr_scene_node_ptr->events.destroy, + &element_ptr->wlr_scene_node_destroy_listener, + handle_wlr_scene_node_destroy); + wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, + element_ptr->visible); + return; + } + BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); + if (element_ptr->wlr_scene_node_ptr->parent == parent_wlr_scene_tree_ptr) { + // Parent does not change, nothing to do. + return; + } + + wlr_scene_node_reparent(element_ptr->wlr_scene_node_ptr, + parent_wlr_scene_tree_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_element_unmap(wlmtk_element_t *element_ptr) +void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible) { - BS_ASSERT(NULL != element_ptr->wlr_scene_node_ptr); - // TODO(kaeser@gubbe.ch): Separate map method into set_visible/attach. - wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, false); - wl_list_remove(&element_ptr->wlr_scene_node_destroy_listener.link); - wlr_scene_node_destroy(element_ptr->wlr_scene_node_ptr); - element_ptr->wlr_scene_node_ptr = NULL; + // Nothing to do? + if (element_ptr->visible == visible) return; + + element_ptr->visible = visible; + if (NULL != element_ptr->wlr_scene_node_ptr) { + wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, visible); + } } /* == Local (static) methods =============================================== */ @@ -142,11 +160,11 @@ void handle_wlr_scene_node_destroy( /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); -static void test_map_unmap(bs_test_t *test_ptr); +static void test_set_parent_container(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { { 1, "init_fini", test_init_fini }, - { 1, "map_unmap", test_map_unmap }, + { 1, "set_parent_container", test_set_parent_container }, { 0, NULL, NULL } }; @@ -188,33 +206,48 @@ void test_init_fini(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests map and unmap, and that unmapping is done on reparenting or fini. */ -void test_map_unmap(bs_test_t *test_ptr) +/** Tests set_parent_container, and that scene graph follows. */ +void test_set_parent_container(bs_test_t *test_ptr) { wlmtk_element_t element; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); - wlmtk_container_t fake_parent = { - .wlr_scene_tree_ptr = &wlr_scene_ptr->tree + wlmtk_container_t fake_parent = {}; + struct wlr_scene *other_wlr_scene_ptr = wlr_scene_create(); + wlmtk_container_t other_fake_parent = { + .wlr_scene_tree_ptr = &other_wlr_scene_ptr->tree }; + + // Setting a parent without a scene graph tree will not set a node. wlmtk_element_set_parent_container(&element, &fake_parent); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); - // Map & unmap. - wlmtk_element_map(&element); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); - wlmtk_element_unmap(&element); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_element_mapped(&element)); + wlmtk_element_set_parent_container(&element, NULL); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); - // Remain mapped, if the parent container remains unchanged. - wlmtk_element_map(&element); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); + // Setting a parent with a tree must create & attach the node there. + wlmtk_element_set_visible(&element, true); + fake_parent.wlr_scene_tree_ptr = &wlr_scene_ptr->tree; wlmtk_element_set_parent_container(&element, &fake_parent); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_mapped(&element)); - - // Changing the parent (eg. to 'None') must unmap the element. + BS_TEST_VERIFY_EQ( + test_ptr, + &wlr_scene_ptr->tree, + element.wlr_scene_node_ptr->parent); + BS_TEST_VERIFY_TRUE(test_ptr, element.wlr_scene_node_ptr->enabled); + + // Resetting the parent must also re-attach the node. + wlmtk_element_set_parent_container(&element, &other_fake_parent); + BS_TEST_VERIFY_EQ( + test_ptr, + &other_wlr_scene_ptr->tree, + element.wlr_scene_node_ptr->parent); + BS_TEST_VERIFY_TRUE(test_ptr, element.wlr_scene_node_ptr->enabled); + + // Clearing the parent most remove the node. wlmtk_element_set_parent_container(&element, NULL); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_element_mapped(&element)); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); + wlmtk_element_fini(&element); } diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index b1e04484..e3ce1c61 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -67,9 +67,12 @@ struct _wlmtk_element_t { /** Implementation of abstract virtual methods. */ const wlmtk_element_impl_t *impl_ptr; - /** Points to the wlroots scene graph API node. Is set when mapped. */ + /** Points to the wlroots scene graph API node, if attached. */ struct wlr_scene_node *wlr_scene_node_ptr; + /** Whether the element is visible (drawn, when part of a scene graph). */ + bool visible; + /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ struct wl_listener wlr_scene_node_destroy_listener; }; @@ -114,9 +117,11 @@ wlmtk_element_t *wlmtk_element_from_dlnode( /** * Sets the parent container for the element. * + * Will call @ref wlmtk_element_attach_to_scene_graph to align the scene graph + * with the new (or deleted) parent. + * * Private: Should only be called by wlmtk_container_add_element, respectively - * wlmtk_container_remove_element ("friends"). Will unmap the element, if the - * parent container changes. + * wlmtk_container_remove_element ("friends"). * * @param element_ptr * @param parent_container_ptr Pointer to the parent container, or NULL if @@ -127,28 +132,31 @@ void wlmtk_element_set_parent_container( wlmtk_container_t *parent_container_ptr); /** - * Maps the element. + * Attaches or detaches the element to the parent's wlroots scene tree. + * + * If the element has a parent, and that parent is itself attached to the + * wlroots scene tree, this will either re-parent an already existing node, + * or invoke wlmtk_element_impl_t::create_scene_node to create and attach a + * new node to the paren'ts tree. + * Otherwise, it will clear any existing node. + * + * The function is idempotent. * - * Requires a parent container to be set. Will call `create_scene_node` to - * build the scene graph API node attached to the parent container's tree. - * Implies that the parent container also is required to be mapped. + * Private: Should only called by wlmtk_container_t methods, when there are + * changes to wlmtk_container_t::wlr_scene_tree. * * @param element_ptr */ -void wlmtk_element_map(wlmtk_element_t *element_ptr); +void wlmtk_element_attach_to_scene_graph( + wlmtk_element_t *element_ptr); /** - * Unmaps the element. + * Sets the element's visibility. * * @param element_ptr + * @param visible */ -void wlmtk_element_unmap(wlmtk_element_t *element_ptr); - -/** Returns whether this element is currently mapped. */ -static inline bool wlmtk_element_mapped(wlmtk_element_t *element_ptr) -{ - return NULL != element_ptr->wlr_scene_node_ptr; -} +void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible); /** Virtual method: Calls the dtor of the element's implementation. */ static inline void wlmtk_element_destroy( @@ -210,6 +218,8 @@ void wlmtk_container_fini( /** * Adds `element_ptr` to the container. * + * Requires that `element_ptr` is not added to a container yet. + * * @param container_ptr * @param element_ptr */ @@ -220,8 +230,7 @@ void wlmtk_container_add_element( /** * Removes `element_ptr` from the container. * - * Expects that `container_ptr` is `element_ptr`'s parent container. Will unmap - * the element, in case it is currently mapped. + * Expects that `container_ptr` is `element_ptr`'s parent container. * * @param container_ptr * @param element_ptr @@ -233,12 +242,11 @@ void wlmtk_container_remove_element( /** * Returns the wlroots scene graph tree for this node. * - * Requires this container's element to be mapped. Should be called only from - * members of `elements`. + * Private: Should be called only by wlmtk_element_t. * * @param container_ptr * - * @return The scene tree. + * @return The scene tree, or NULL if not attached to a scene graph. */ struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( wlmtk_container_t *container_ptr); @@ -269,14 +277,14 @@ wlmtk_workspace_t *wlmtk_workspace_create( struct wlr_scene_tree *wlr_scene_tree_ptr); /** - * Destroys the workspace. Will destroy any still-mapped element. + * Destroys the workspace. Will destroy any stil-contained element. * * @param workspace_ptr */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); /** - * Maps the window: Adds it to the workspace container and maps it. + * Maps the window: Adds it to the workspace container and makes it visible. * * @param workspace_ptr * @param window_ptr @@ -285,8 +293,7 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); /** - * Maps the window: Unmaps the window and removes it from the workspace - * container. + * Unmaps the window: Sets it as invisible and removes it from the container. * * @param workspace_ptr * @param window_ptr diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index de42e8bb..0a29ff30 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -31,6 +31,7 @@ class Element { bool init(handlers) void fini() -void set_parent_container(Container*) + -void attach_to_scene_graph() void set_visible(bool) bool is_visible() @@ -40,17 +41,13 @@ class Element { {abstract}#void leave() {abstract}#void click() } -note right of Element::"set_parent_container()" - If the parent is already part of the scene graph, this will also - invoke create_scene_node. -note right of Element::"set_visible()" - Marks the element as visible. - - If this element is already part of the scene graph, will adjust the - visibility of the node. Otherwise, if the parent is already part of the - scene graph (parent_container_ptr->wlr_scene_tree() is not NULL), this will - also invoke create_scene_node to create the scene node. - And then set visibility accordingly. +note right of Element::"set_parent_container(Container*)" + Will invoke set_parent_container. +end note +note right of Element::"attach_to_scene_graph()" + Will create or reparent this element's node to the parent's scene tree, or + detach and destroy this element's node, if the parent does not have a scene + tree. end note class Container { @@ -61,7 +58,7 @@ class Container { void fini() add_element(Element*) remove_element(Element*) - struct wlr_scene_tree *wlr_scene_tree() + -struct wlr_scene_tree *wlr_scene_tree() {abstract}#void destroy() @@ -71,8 +68,9 @@ class Container { } Element <|-- Container note right of Element::"add_element(Element*)" - If the super_element is already part of the scene graph, this will also - invoke the added element's create_scene_node. + Both add_element() and remove_element() will call + Element::set_parent_container() and thus alignt he element's scene node + with the container's tree. end note class Workspace { diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 8c77dec3..63a2d2c3 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -69,8 +69,8 @@ wlmtk_workspace_t *wlmtk_workspace_create( wlmtk_element_set_parent_container( &workspace_ptr->super_container.super_element, &workspace_ptr->fake_parent); - - wlmtk_element_map(&workspace_ptr->super_container.super_element); + wlmtk_element_set_visible( + &workspace_ptr->super_container.super_element, true); return workspace_ptr; } @@ -78,8 +78,6 @@ wlmtk_workspace_t *wlmtk_workspace_create( /* ------------------------------------------------------------------------- */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) { - wlmtk_element_unmap(&workspace_ptr->super_container.super_element); - wlmtk_element_set_parent_container( &workspace_ptr->super_container.super_element, NULL); @@ -92,10 +90,10 @@ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { + wlmtk_element_set_visible(wlmtk_window_element(window_ptr), true); wlmtk_container_add_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); - wlmtk_element_map(wlmtk_window_element(window_ptr)); } /* ------------------------------------------------------------------------- */ @@ -104,7 +102,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, { BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( wlmtk_window_element(window_ptr)->parent_container_ptr)); - wlmtk_element_unmap(wlmtk_window_element(window_ptr)); + wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); wlmtk_container_remove_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); @@ -196,21 +194,28 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_window_t *window_ptr = wlmtk_window_create(&content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_workspace_map_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_TRUE( + BS_TEST_VERIFY_NEQ( test_ptr, - wlmtk_element_mapped(wlmtk_window_element(window_ptr))); - BS_TEST_VERIFY_TRUE( + NULL, + wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); + BS_TEST_VERIFY_NEQ( test_ptr, - wlmtk_element_mapped(&content.super_element)); + NULL, + content.super_element.wlr_scene_node_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_FALSE( + BS_TEST_VERIFY_EQ( test_ptr, - wlmtk_element_mapped(wlmtk_window_element(window_ptr))); - BS_TEST_VERIFY_FALSE( + NULL, + wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); + BS_TEST_VERIFY_EQ( test_ptr, - wlmtk_element_mapped(&content.super_element)); + NULL, + content.super_element.wlr_scene_node_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); From 76b7ecef612b9449b9a00154cad14411904fcd16 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 31 Aug 2023 21:59:12 +0200 Subject: [PATCH 033/390] Fixes visibility for window content. --- src/toolkit/window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a7ef5fae..7dd5384c 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -57,6 +57,7 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_content_element(content_ptr)); window_ptr->content_ptr = content_ptr; wlmtk_content_set_window(content_ptr, window_ptr); + wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); return window_ptr; } @@ -66,6 +67,8 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) wlmtk_container_remove_element( &window_ptr->super_container, wlmtk_content_element(window_ptr->content_ptr)); + wlmtk_element_set_visible( + wlmtk_content_element(window_ptr->content_ptr), false); wlmtk_content_set_window(window_ptr->content_ptr, NULL); window_ptr->content_ptr = NULL; From 46d2438f9ab1d255f11df575009bfccd7dcc0923 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 31 Aug 2023 22:21:02 +0200 Subject: [PATCH 034/390] Fixes NULL dereference when looking up view in a mixed toolkit/non-toolkit setup. --- src/view.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/view.c b/src/view.c index 3577c840..9507d9cf 100644 --- a/src/view.c +++ b/src/view.c @@ -275,8 +275,9 @@ wlmaker_view_t *wlmaker_view_at( NULL == wlr_scene_tree_ptr->node.data) { wlr_scene_tree_ptr = wlr_scene_tree_ptr->node.parent; } - return (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; + if (NULL == wlr_scene_tree_ptr) return NULL; + return (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; } /* ------------------------------------------------------------------------- */ From 344a4714d67851f1e71a1370454f01e8ba40d23c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 31 Aug 2023 22:40:25 +0200 Subject: [PATCH 035/390] Adds set_position and get_position for Element. --- src/toolkit/element.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/toolkit/toolkit.h | 24 +++++++++++++++ src/toolkit/toolkit.md | 2 ++ 3 files changed, 94 insertions(+) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index b0126bdd..5b5bd03c 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -112,6 +112,9 @@ void wlmtk_element_attach_to_scene_graph( handle_wlr_scene_node_destroy); wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, element_ptr->visible); + wlr_scene_node_set_position(element_ptr->wlr_scene_node_ptr, + element_ptr->x, + element_ptr->y); return; } @@ -137,6 +140,32 @@ void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible) } } +/* ------------------------------------------------------------------------- */ +void wlmtk_element_get_position( + wlmtk_element_t *element_ptr, + int *x_ptr, + int *y_ptr) +{ + if (NULL != x_ptr) *x_ptr = element_ptr->x; + if (NULL != y_ptr) *y_ptr = element_ptr->y; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_element_set_position( + wlmtk_element_t *element_ptr, + int x, + int y) +{ + element_ptr->x = x; + element_ptr->y = y; + + if (NULL != element_ptr->wlr_scene_node_ptr) { + wlr_scene_node_set_position(element_ptr->wlr_scene_node_ptr, + element_ptr->x, + element_ptr->y); + } +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -161,10 +190,12 @@ void handle_wlr_scene_node_destroy( static void test_init_fini(bs_test_t *test_ptr); static void test_set_parent_container(bs_test_t *test_ptr); +static void test_set_get_position(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "set_parent_container", test_set_parent_container }, + { 1, "set_get_position", test_set_get_position }, { 0, NULL, NULL } }; @@ -251,4 +282,41 @@ void test_set_parent_container(bs_test_t *test_ptr) wlmtk_element_fini(&element); } +/* ------------------------------------------------------------------------- */ +/** Tests get_position and set_position, and that scene graph follows. */ +void test_set_get_position(bs_test_t *test_ptr) +{ + wlmtk_element_t element; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); + + // Exercise, must not crash. + wlmtk_element_get_position(&element, NULL, NULL); + + int x, y; + wlmtk_element_get_position(&element, &x, &y); + BS_TEST_VERIFY_EQ(test_ptr, 0, x); + BS_TEST_VERIFY_EQ(test_ptr, 0, y); + + wlmtk_element_set_position(&element, 10, 20); + wlmtk_element_get_position(&element, &x, &y); + BS_TEST_VERIFY_EQ(test_ptr, 10, x); + BS_TEST_VERIFY_EQ(test_ptr, 20, y); + + struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + wlmtk_container_t fake_parent = { + .wlr_scene_tree_ptr = &wlr_scene_ptr->tree + }; + wlmtk_element_set_parent_container(&element, &fake_parent); + + BS_TEST_VERIFY_EQ(test_ptr, 10, element.wlr_scene_node_ptr->x); + BS_TEST_VERIFY_EQ(test_ptr, 20, element.wlr_scene_node_ptr->y); + + wlmtk_element_set_position(&element, 30, 40); + BS_TEST_VERIFY_EQ(test_ptr, 30, element.wlr_scene_node_ptr->x); + BS_TEST_VERIFY_EQ(test_ptr, 40, element.wlr_scene_node_ptr->y); + + wlmtk_element_set_parent_container(&element, NULL); + wlmtk_element_fini(&element); +} + /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index e3ce1c61..0827c828 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -158,6 +158,30 @@ void wlmtk_element_attach_to_scene_graph( */ void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible); +/** + * Returns the position of the element. + * + * @param element_ptr + * @param x_ptr Optional, may be NULL. + * @param y_ptr Optional, may be NULL. + */ +void wlmtk_element_get_position( + wlmtk_element_t *element_ptr, + int *x_ptr, + int *y_ptr); + +/** + * Sets the position of the element. + * + * @param element_ptr + * @param x + * @param y + */ +void wlmtk_element_set_position( + wlmtk_element_t *element_ptr, + int x, + int y); + /** Virtual method: Calls the dtor of the element's implementation. */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 0a29ff30..367407de 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -34,6 +34,8 @@ class Element { -void attach_to_scene_graph() void set_visible(bool) bool is_visible() + void set_position(int, int) + void get_position(int*, int*) {abstract}#void destroy() {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) From c1114b93f15d7149933ee828329e939342c30297 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 1 Sep 2023 16:18:25 +0200 Subject: [PATCH 036/390] Make the 'fake' test element reusable --- src/toolkit/element.c | 46 +++++++++++++++++++++++++------------------ src/toolkit/toolkit.h | 3 +++ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 5b5bd03c..2ef29230 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -199,16 +199,26 @@ const bs_test_case_t wlmtk_element_test_cases[] = { { 0, NULL, NULL } }; -/** Reports whether the fake dtor was called. */ -static bool test_destroy_cb_called; -/** dtor for the element under test. */ -static void test_destroy_cb(wlmtk_element_t *element_ptr) +static void fake_destroy_cb(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *fake_create_scene_node( + __UNUSED__ wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); + +const wlmtk_element_impl_t wlmtk_element_fake__impl = { + .destroy = fake_destroy_cb, + .create_scene_node = fake_create_scene_node +}; + +/* ------------------------------------------------------------------------- */ +/** dtor for the "fake" element used for tests. */ +static void fake_destroy_cb(wlmtk_element_t *element_ptr) { - test_destroy_cb_called = true; wlmtk_element_fini(element_ptr); } -/** A dummy implementation for a 'create_scene_node'. */ -static struct wlr_scene_node *test_create_scene_node( + +/* ------------------------------------------------------------------------- */ +/** A "fake" 'create_scene_node': Creates a non-attached buffer node. */ +static struct wlr_scene_node *fake_create_scene_node( __UNUSED__ wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { @@ -216,23 +226,17 @@ static struct wlr_scene_node *test_create_scene_node( wlr_scene_tree_ptr, NULL); return &wlr_scene_buffer_ptr->node; } -/** Method table for the element we're using as test dummy. */ -static const wlmtk_element_impl_t test_impl = { - .destroy = test_destroy_cb, - .create_scene_node = test_create_scene_node -}; - /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element, &wlmtk_element_fake__impl)); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl_ptr); - test_destroy_cb_called = false; wlmtk_element_destroy(&element); - BS_TEST_VERIFY_TRUE(test_ptr, test_destroy_cb_called); - BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl_ptr); } @@ -241,7 +245,9 @@ void test_init_fini(bs_test_t *test_ptr) void test_set_parent_container(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element, &wlmtk_element_fake__impl)); struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); wlmtk_container_t fake_parent = {}; @@ -287,7 +293,9 @@ void test_set_parent_container(bs_test_t *test_ptr) void test_set_get_position(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, &test_impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element, &wlmtk_element_fake__impl)); // Exercise, must not crash. wlmtk_element_get_position(&element, NULL, NULL); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 0827c828..986dadd6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -191,6 +191,9 @@ static inline void wlmtk_element_destroy( /** Unit tests for the element. */ extern const bs_test_case_t wlmtk_element_test_cases[]; +/** Implementation table of a "fake" element for tests. */ +extern const wlmtk_element_impl_t wlmtk_element_fake__impl; + /* ========================================================================= */ /** State of the container. */ From 8bdddb5f0c30958879a65eb69ffaf60d0e8ad61b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 1 Sep 2023 16:20:48 +0200 Subject: [PATCH 037/390] Makes use of the fake element built for tests. --- src/toolkit/container.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 04cef63d..f63e934b 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -213,30 +213,10 @@ static void test_destroy_cb(wlmtk_container_t *container_ptr) wlmtk_container_fini(container_ptr); } -/** dtor for the element under test. */ -static void test_element_destroy_cb(wlmtk_element_t *element_ptr) -{ - wlmtk_element_fini(element_ptr); -} -/** Creates a scene node attached to the tree. */ -static struct wlr_scene_node *test_element_create_scene_node( - __UNUSED__ wlmtk_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr) -{ - struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( - wlr_scene_tree_ptr, NULL); - return &wlr_scene_buffer_ptr->node; -} - /** Method table for the container we're using for test. */ static const wlmtk_container_impl_t test_container_impl = { .destroy = test_destroy_cb }; -/** Method table for the element we're using for test. */ -static const wlmtk_element_impl_t test_element_impl = { - .destroy = test_element_destroy_cb, - .create_scene_node = test_element_create_scene_node -}; /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ @@ -265,12 +245,15 @@ void test_add_remove(bs_test_t *test_ptr) &container, &test_container_impl)); wlmtk_element_t element1, element2, element3; - BS_TEST_VERIFY_TRUE(test_ptr, - wlmtk_element_init(&element1, &test_element_impl)); - BS_TEST_VERIFY_TRUE(test_ptr, - wlmtk_element_init(&element2, &test_element_impl)); - BS_TEST_VERIFY_TRUE(test_ptr, - wlmtk_element_init(&element3, &test_element_impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element1, &wlmtk_element_fake__impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element2, &wlmtk_element_fake__impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element3, &wlmtk_element_fake__impl)); wlmtk_container_add_element(&container, &element1); BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, &container); @@ -312,8 +295,10 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) test_ptr, NULL, container.super_element.wlr_scene_node_ptr); wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, - wlmtk_element_init(&element, &test_element_impl)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element, &wlmtk_element_fake__impl)); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_container_add_element(&container, &element); BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.wlr_scene_node_ptr); From c0dc305b1e2fd29baf5e48e284f6b44d7c1ea69e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 10:37:08 +0200 Subject: [PATCH 038/390] Fixes typo in fake element impl. --- src/toolkit/container.c | 8 ++++---- src/toolkit/element.c | 8 ++++---- src/toolkit/toolkit.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index f63e934b..0f0a0d40 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -247,13 +247,13 @@ void test_add_remove(bs_test_t *test_ptr) wlmtk_element_t element1, element2, element3; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element1, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element1, &wlmtk_element_fake_impl)); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element2, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element2, &wlmtk_element_fake_impl)); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element3, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element3, &wlmtk_element_fake_impl)); wlmtk_container_add_element(&container, &element1); BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, &container); @@ -297,7 +297,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element, &wlmtk_element_fake_impl)); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_container_add_element(&container, &element); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 2ef29230..186371fb 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -204,7 +204,7 @@ static struct wlr_scene_node *fake_create_scene_node( __UNUSED__ wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -const wlmtk_element_impl_t wlmtk_element_fake__impl = { +const wlmtk_element_impl_t wlmtk_element_fake_impl = { .destroy = fake_destroy_cb, .create_scene_node = fake_create_scene_node }; @@ -233,7 +233,7 @@ void test_init_fini(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element, &wlmtk_element_fake_impl)); BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl_ptr); wlmtk_element_destroy(&element); @@ -247,7 +247,7 @@ void test_set_parent_container(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element, &wlmtk_element_fake_impl)); struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); wlmtk_container_t fake_parent = {}; @@ -295,7 +295,7 @@ void test_set_get_position(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake__impl)); + wlmtk_element_init(&element, &wlmtk_element_fake_impl)); // Exercise, must not crash. wlmtk_element_get_position(&element, NULL, NULL); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 986dadd6..920a530a 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -192,7 +192,7 @@ static inline void wlmtk_element_destroy( extern const bs_test_case_t wlmtk_element_test_cases[]; /** Implementation table of a "fake" element for tests. */ -extern const wlmtk_element_impl_t wlmtk_element_fake__impl; +extern const wlmtk_element_impl_t wlmtk_element_fake_impl; /* ========================================================================= */ From 55e1f6defb33c99446aaa7da2ec7cb6b42345bb4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 10:40:27 +0200 Subject: [PATCH 039/390] Adjusts method name of fake dtor. --- src/toolkit/element.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 186371fb..1a22f121 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -199,19 +199,19 @@ const bs_test_case_t wlmtk_element_test_cases[] = { { 0, NULL, NULL } }; -static void fake_destroy_cb(wlmtk_element_t *element_ptr); +static void fake_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_create_scene_node( __UNUSED__ wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); const wlmtk_element_impl_t wlmtk_element_fake_impl = { - .destroy = fake_destroy_cb, + .destroy = fake_destroy, .create_scene_node = fake_create_scene_node }; /* ------------------------------------------------------------------------- */ /** dtor for the "fake" element used for tests. */ -static void fake_destroy_cb(wlmtk_element_t *element_ptr) +static void fake_destroy(wlmtk_element_t *element_ptr) { wlmtk_element_fini(element_ptr); } From b0788f84ff2918ff1fcfe9d08b04e2b555c7bcf5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 10:41:37 +0200 Subject: [PATCH 040/390] Also use an exported fake class for the container, for tests. --- src/toolkit/container.c | 22 ++++++++++++---------- src/toolkit/toolkit.h | 3 +++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 0f0a0d40..04f93f3a 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -207,24 +207,26 @@ const bs_test_case_t wlmtk_container_test_cases[] = { { 0, NULL, NULL } }; -/** dtor for the container under test. */ -static void test_destroy_cb(wlmtk_container_t *container_ptr) -{ - wlmtk_container_fini(container_ptr); -} +static void fake_destroy(wlmtk_container_t *container_ptr); /** Method table for the container we're using for test. */ -static const wlmtk_container_impl_t test_container_impl = { - .destroy = test_destroy_cb +const wlmtk_container_impl_t wlmtk_container_fake_impl = { + .destroy = fake_destroy }; +/* ------------------------------------------------------------------------- */ +/** dtor for the container under test. */ +void fake_destroy(wlmtk_container_t *container_ptr) +{ + wlmtk_container_fini(container_ptr); +} /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_container_t container; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( - &container, &test_container_impl)); + &container, &wlmtk_container_fake_impl)); // Also expect the super element to be initialized. BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.impl_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl_ptr); @@ -242,7 +244,7 @@ void test_add_remove(bs_test_t *test_ptr) { wlmtk_container_t container; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( - &container, &test_container_impl)); + &container, &wlmtk_container_fake_impl)); wlmtk_element_t element1, element2, element3; BS_TEST_VERIFY_TRUE( @@ -281,7 +283,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) { wlmtk_container_t container; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( - &container, &test_container_impl)); + &container, &wlmtk_container_fake_impl)); struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); wlmtk_container_t fake_parent = { diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 920a530a..84ba059d 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -287,6 +287,9 @@ static inline void wlmtk_container_destroy( /** Unit tests for the container. */ extern const bs_test_case_t wlmtk_container_test_cases[]; +/** Implementation table of a "fake" container for tests. */ +extern const wlmtk_container_impl_t wlmtk_container_fake_impl; + /* ========================================================================= */ /** State of the workspace. */ From 489be100b7c65222756e5b48aa66b81b0347e0ce Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 11:11:42 +0200 Subject: [PATCH 041/390] Adds a fake parent container, useful for tests. --- src/toolkit/container.c | 98 ++++++++++++++++++++++++++++++++++------- src/toolkit/toolkit.h | 3 ++ 2 files changed, 84 insertions(+), 17 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 04f93f3a..38da67c3 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -194,18 +194,7 @@ void handle_wlr_scene_tree_node_destroy( wl_list_remove(&container_ptr->wlr_scene_tree_node_destroy_listener.link); } -/* == Unit tests =========================================================== */ - -static void test_init_fini(bs_test_t *test_ptr); -static void test_add_remove(bs_test_t *test_ptr); -static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); - -const bs_test_case_t wlmtk_container_test_cases[] = { - { 1, "init_fini", test_init_fini }, - { 1, "add_remove", test_add_remove }, - { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, - { 0, NULL, NULL } -}; +/* == Helper for unit test: A fake container =============================== */ static void fake_destroy(wlmtk_container_t *container_ptr); @@ -220,6 +209,80 @@ void fake_destroy(wlmtk_container_t *container_ptr) { wlmtk_container_fini(container_ptr); } + +/* == Helper for unit tests: A fake container with a tree, as parent ======= */ + +/** State of the "fake" parent container. Refers to a scene graph. */ +typedef struct { + /** The actual container */ + wlmtk_container_t container; + /** A scene graph. Not attached to any output, */ + struct wlr_scene *wlr_scene_ptr; +} fake_parent_container_t; + +static void fake_parent_destroy(wlmtk_container_t *container_ptr); + +/* ------------------------------------------------------------------------- */ +wlmtk_container_t *wlmtk_container_create_fake_parent(void) +{ + static const wlmtk_container_impl_t fake_parent_impl = { + .destroy = fake_parent_destroy + }; + + fake_parent_container_t *fake_parent_container_ptr = logged_calloc( + 1, sizeof(fake_parent_container_t)); + if (NULL == fake_parent_container_ptr) return NULL; + + if (!wlmtk_container_init( + &fake_parent_container_ptr->container, + &fake_parent_impl)) { + fake_parent_destroy(&fake_parent_container_ptr->container); + return NULL; + } + + fake_parent_container_ptr->wlr_scene_ptr = wlr_scene_create(); + if (NULL == fake_parent_container_ptr->wlr_scene_ptr) { + fake_parent_destroy(&fake_parent_container_ptr->container); + return NULL; + } + fake_parent_container_ptr->container.wlr_scene_tree_ptr = + &fake_parent_container_ptr->wlr_scene_ptr->tree; + + return &fake_parent_container_ptr->container; +} + +/* ------------------------------------------------------------------------- */ +/** Destructor for the "fake" parent, to be used for tests. */ +void fake_parent_destroy(wlmtk_container_t *container_ptr) +{ + fake_parent_container_t *fake_parent_container_ptr = BS_CONTAINER_OF( + container_ptr, fake_parent_container_t, container); + + if (NULL != fake_parent_container_ptr->wlr_scene_ptr) { + // Note: There is no "wlr_scene_destroy()" method; as of 2023-09-02, + // this is just a flat allocated struct. + free(fake_parent_container_ptr->wlr_scene_ptr); + fake_parent_container_ptr->wlr_scene_ptr = NULL; + } + + wlmtk_container_fini(&fake_parent_container_ptr->container); + + free(fake_parent_container_ptr); +} + +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); +static void test_add_remove(bs_test_t *test_ptr); +static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_container_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 1, "add_remove", test_add_remove }, + { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, + { 0, NULL, NULL } +}; + /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) @@ -285,12 +348,11 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( &container, &wlmtk_container_fake_impl)); - struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); - wlmtk_container_t fake_parent = { - .wlr_scene_tree_ptr = &wlr_scene_ptr->tree - }; + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_parent_ptr); + wlmtk_element_set_parent_container( - &container.super_element, &fake_parent); + &container.super_element, fake_parent_ptr); // Want to have the node. BS_TEST_VERIFY_NEQ( @@ -310,6 +372,8 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_element_set_parent_container(&container.super_element, NULL); wlmtk_container_fini(&container); + + wlmtk_container_destroy(fake_parent_ptr); } /* == End of container.c =================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 84ba059d..fbc01d21 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -290,6 +290,9 @@ extern const bs_test_case_t wlmtk_container_test_cases[]; /** Implementation table of a "fake" container for tests. */ extern const wlmtk_container_impl_t wlmtk_container_fake_impl; +/** Constructor for a fake container with a scene tree. */ +wlmtk_container_t *wlmtk_container_create_fake_parent(void); + /* ========================================================================= */ /** State of the workspace. */ From a5e36c3da0444c6ede099a9c0bc4744412df5bde Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 11:22:07 +0200 Subject: [PATCH 042/390] Applies fake parent to element unit tests, eliminates any leak there. --- src/toolkit/element.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 1a22f121..399b321e 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -249,35 +249,36 @@ void test_set_parent_container(bs_test_t *test_ptr) test_ptr, wlmtk_element_init(&element, &wlmtk_element_fake_impl)); - struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); - wlmtk_container_t fake_parent = {}; - struct wlr_scene *other_wlr_scene_ptr = wlr_scene_create(); - wlmtk_container_t other_fake_parent = { - .wlr_scene_tree_ptr = &other_wlr_scene_ptr->tree - }; - // Setting a parent without a scene graph tree will not set a node. - wlmtk_element_set_parent_container(&element, &fake_parent); + wlmtk_container_t parent_no_tree; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_container_init(&parent_no_tree, &wlmtk_container_fake_impl)); + wlmtk_element_set_parent_container(&element, &parent_no_tree); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_element_set_parent_container(&element, NULL); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); + wlmtk_container_fini(&parent_no_tree); // Setting a parent with a tree must create & attach the node there. + wlmtk_container_t *parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != parent_ptr); wlmtk_element_set_visible(&element, true); - fake_parent.wlr_scene_tree_ptr = &wlr_scene_ptr->tree; - wlmtk_element_set_parent_container(&element, &fake_parent); + wlmtk_element_set_parent_container(&element, parent_ptr); BS_TEST_VERIFY_EQ( test_ptr, - &wlr_scene_ptr->tree, + parent_ptr->wlr_scene_tree_ptr, element.wlr_scene_node_ptr->parent); BS_TEST_VERIFY_TRUE(test_ptr, element.wlr_scene_node_ptr->enabled); // Resetting the parent must also re-attach the node. - wlmtk_element_set_parent_container(&element, &other_fake_parent); + wlmtk_container_t *other_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != other_parent_ptr); + wlmtk_element_set_parent_container(&element, other_parent_ptr); BS_TEST_VERIFY_EQ( test_ptr, - &other_wlr_scene_ptr->tree, + other_parent_ptr->wlr_scene_tree_ptr, element.wlr_scene_node_ptr->parent); BS_TEST_VERIFY_TRUE(test_ptr, element.wlr_scene_node_ptr->enabled); @@ -285,6 +286,8 @@ void test_set_parent_container(bs_test_t *test_ptr) wlmtk_element_set_parent_container(&element, NULL); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); + wlmtk_container_destroy(other_parent_ptr); + wlmtk_container_destroy(parent_ptr); wlmtk_element_fini(&element); } @@ -310,11 +313,9 @@ void test_set_get_position(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 10, x); BS_TEST_VERIFY_EQ(test_ptr, 20, y); - struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); - wlmtk_container_t fake_parent = { - .wlr_scene_tree_ptr = &wlr_scene_ptr->tree - }; - wlmtk_element_set_parent_container(&element, &fake_parent); + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_element_set_parent_container(&element, fake_parent_ptr); BS_TEST_VERIFY_EQ(test_ptr, 10, element.wlr_scene_node_ptr->x); BS_TEST_VERIFY_EQ(test_ptr, 20, element.wlr_scene_node_ptr->y); @@ -325,6 +326,7 @@ void test_set_get_position(bs_test_t *test_ptr) wlmtk_element_set_parent_container(&element, NULL); wlmtk_element_fini(&element); + wlmtk_container_destroy(fake_parent_ptr); } /* == End of toolkit.c ===================================================== */ From 6a3266a1af21635e9c26c0b37a9a8bf6899e7de2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 11:27:52 +0200 Subject: [PATCH 043/390] Uses fake parent also for workspace tests, eliminating the test leaks there. --- src/toolkit/workspace.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 63a2d2c3..812c9944 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -142,10 +142,11 @@ const bs_test_case_t wlmtk_workspace_test_cases[] = { /** Exercises workspace create & destroy methods. */ void test_create_destroy(bs_test_t *test_ptr) { - struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - &wlr_scene_ptr->tree); + fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); BS_TEST_VERIFY_EQ( @@ -154,8 +155,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_workspace_from_container(&workspace_ptr->super_container)); wlmtk_workspace_destroy(workspace_ptr); - - // Note: There is no destroy method for wlr_scene_ptr. + wlmtk_container_destroy(fake_parent_ptr); } /** dtor for the content under test. */ @@ -183,10 +183,11 @@ static const wlmtk_content_impl_t test_content_impl = { /** Verifies that mapping and unmapping windows works. */ void test_map_unmap(bs_test_t *test_ptr) { - struct wlr_scene *wlr_scene_ptr = wlr_scene_create(); + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - &wlr_scene_ptr->tree); + fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); wlmtk_content_t content; @@ -219,6 +220,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy(fake_parent_ptr); } /* == End of workspace.c =================================================== */ From 4ed79126a34f05d34733ef7b4a45009a843af1c0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 11:35:21 +0200 Subject: [PATCH 044/390] Adds suggestion to wrkspace ctor. --- src/toolkit/toolkit.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index fbc01d21..94854dc9 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -301,6 +301,9 @@ typedef struct _wlmtk_workspace_t wlmtk_workspace_t; /** * Creates a workspace. * + * TODO(kaeser@gubbe.ch): Consider replacing the interface with a container, + * and permit a "toplevel" container that will be at the server level. + * * @param wlr_scene_tree_ptr * * @return Pointer to the workspace state, or NULL on error. Must be free'd From bac72e3e2b9b51e62dd3497a8aea4e18dec19bcd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 11:42:10 +0200 Subject: [PATCH 045/390] Adds get_size method. --- src/toolkit/element.c | 30 ++++++++++++++++++++++++++++++ src/toolkit/toolkit.h | 16 ++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 399b321e..2a34e532 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -166,6 +166,16 @@ void wlmtk_element_set_position( } } +/* ------------------------------------------------------------------------- */ +void wlmtk_element_get_size( + wlmtk_element_t *element_ptr, + int *width_ptr, + int *height_ptr) +{ + if (NULL != width_ptr) *width_ptr = element_ptr->width; + if (NULL != height_ptr) *height_ptr = element_ptr->height; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -329,4 +339,24 @@ void test_set_get_position(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests get_size. */ +void test_get_size(bs_test_t *test_ptr) +{ + wlmtk_element_t element; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_init(&element, &wlmtk_element_fake_impl)); + element.width = 42; + element.height = 21; + + // Must not crash. + wlmtk_element_get_size(&element, NULL, NULL); + + int width, height; + wlmtk_element_get_size(&element, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 42, width); + BS_TEST_VERIFY_EQ(test_ptr, 21, height); +} + /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 94854dc9..9da0ab84 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -58,6 +58,10 @@ struct _wlmtk_element_t { int x; /** Y position of the element, relative to the container. */ int y; + /** Width of the element, in pixels. */ + int width; + /** Height of the element, in pixels. */ + int height; /** The container this element belongs to, if any. */ wlmtk_container_t *parent_container_ptr; @@ -182,6 +186,18 @@ void wlmtk_element_set_position( int x, int y); +/** + * Returns the size of the element, in pixels. + * + * @param element_ptr + * @param width_ptr Optional, may be NULL. + * @param height_ptr Optional, may be NULL. + */ +void wlmtk_element_get_size( + wlmtk_element_t *element_ptr, + int *width_ptr, + int *height_ptr); + /** Virtual method: Calls the dtor of the element's implementation. */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { From 695a5f9a2865e59f569637e9f3e2a2802ac0ef1d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 11:42:36 +0200 Subject: [PATCH 046/390] Adds get_size method. --- src/toolkit/toolkit.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 367407de..464ae181 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -36,6 +36,7 @@ class Element { bool is_visible() void set_position(int, int) void get_position(int*, int*) + void get_size(int*, int*) {abstract}#void destroy() {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) From ad98113250457935ff0d4d5db781392d4d4deb06 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 12:15:24 +0200 Subject: [PATCH 047/390] Adds boilerplate methods for Element::enter(). --- src/toolkit/container.c | 24 +++++++++++++++++++++++- src/toolkit/content.c | 23 ++++++++++++++++++++++- src/toolkit/element.c | 22 ++++++++++++++++++---- src/toolkit/toolkit.h | 4 ++++ 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 38da67c3..e967c2a7 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -32,6 +32,10 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void element_enter( + wlmtk_element_t *element_ptr, + int x, int y); + static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr); @@ -39,7 +43,8 @@ static void handle_wlr_scene_tree_node_destroy( /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, - .create_scene_node = element_create_scene_node + .create_scene_node = element_create_scene_node, + .enter = element_enter }; /* == Exported methods ===================================================== */ @@ -165,6 +170,23 @@ struct wlr_scene_node *element_create_scene_node( return &container_ptr->wlr_scene_tree_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's enter method: Handle pointer moves. + * + * @param element_ptr + * @param x + * @param y + */ +void element_enter( + wlmtk_element_t *element_ptr, + __UNUSED__ int x, + __UNUSED__ int y) +{ + __UNUSED__ wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); +} + /* ------------------------------------------------------------------------- */ /** * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. diff --git a/src/toolkit/content.c b/src/toolkit/content.c index c1a3a76b..c8a17146 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -31,11 +31,15 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void element_enter( + wlmtk_element_t *element_ptr, + int x, int y); /** Method table for the container's virtual methods. */ const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, - .create_scene_node = element_create_scene_node + .create_scene_node = element_create_scene_node, + .enter = element_enter }; /* == Exported methods ===================================================== */ @@ -117,6 +121,23 @@ struct wlr_scene_node *element_create_scene_node( content_ptr, wlr_scene_tree_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's enter method: Handle pointer moves. + * + * @param element_ptr + * @param x + * @param y + */ +void element_enter( + wlmtk_element_t *element_ptr, + __UNUSED__ int x, + __UNUSED__ int y) +{ + __UNUSED__ wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 2a34e532..9031b360 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -43,6 +43,7 @@ bool wlmtk_element_init( BS_ASSERT(NULL != element_impl_ptr); BS_ASSERT(NULL != element_impl_ptr->destroy); BS_ASSERT(NULL != element_impl_ptr->create_scene_node); + BS_ASSERT(NULL != element_impl_ptr->enter); memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; @@ -211,24 +212,28 @@ const bs_test_case_t wlmtk_element_test_cases[] = { static void fake_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_create_scene_node( - __UNUSED__ wlmtk_element_t *element_ptr, + wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void fake_enter( + wlmtk_element_t *element_ptr, + int x, int y); const wlmtk_element_impl_t wlmtk_element_fake_impl = { .destroy = fake_destroy, - .create_scene_node = fake_create_scene_node + .create_scene_node = fake_create_scene_node, + .enter = fake_enter }; /* ------------------------------------------------------------------------- */ /** dtor for the "fake" element used for tests. */ -static void fake_destroy(wlmtk_element_t *element_ptr) +void fake_destroy(wlmtk_element_t *element_ptr) { wlmtk_element_fini(element_ptr); } /* ------------------------------------------------------------------------- */ /** A "fake" 'create_scene_node': Creates a non-attached buffer node. */ -static struct wlr_scene_node *fake_create_scene_node( +struct wlr_scene_node *fake_create_scene_node( __UNUSED__ wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { @@ -236,6 +241,15 @@ static struct wlr_scene_node *fake_create_scene_node( wlr_scene_tree_ptr, NULL); return &wlr_scene_buffer_ptr->node; } + +/* ------------------------------------------------------------------------- */ +/** Handles 'tnter' events for the fake element. */ +void fake_enter( + __UNUSED__ wlmtk_element_t *element_ptr, + __UNUSED__ int x, + __UNUSED__ int y) +{} + /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 9da0ab84..1dd88b19 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -89,6 +89,10 @@ struct _wlmtk_element_impl_t { struct wlr_scene_node *(*create_scene_node)( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); + + /** Notifies that the pointer is within the element's area, at x,y. */ + void (*enter)(wlmtk_element_t *element_ptr, + int x, int y); }; /** From 026e165f749932878c352aef7b5857140b50ff16 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 12:23:45 +0200 Subject: [PATCH 048/390] Adds implementation for Container::enter(): Pass to elements. --- src/toolkit/container.c | 25 ++++++++++++++++++++++--- src/toolkit/toolkit.h | 8 ++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index e967c2a7..bdef54dc 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -180,11 +180,30 @@ struct wlr_scene_node *element_create_scene_node( */ void element_enter( wlmtk_element_t *element_ptr, - __UNUSED__ int x, - __UNUSED__ int y) + int x, + int y) { - __UNUSED__ wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); + + + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + + // Compute the box occupied by "element_ptr", relative to container. + int x_from, y_from, x_to, y_to; + wlmtk_element_get_position(element_ptr, &x_from, &y_from); + wlmtk_element_get_size(element_ptr, &x_to, &y_to); + x_to += x_from; + y_to += y_from; + + if (x_from <= x && x < y_to && y_from <= y && y < y_to) { + wlmtk_element_enter(element_ptr, x - x_from, y - y_from); + return; + } + } } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 1dd88b19..433857bd 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -202,6 +202,14 @@ void wlmtk_element_get_size( int *width_ptr, int *height_ptr); +/** Virtual method: Calls 'enter' for the element's implementation. */ +static inline void wlmtk_element_enter( + wlmtk_element_t *element_ptr, + int x, + int y) { + element_ptr->impl_ptr->enter(element_ptr, x, y); +} + /** Virtual method: Calls the dtor of the element's implementation. */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { From 00191219ff6f9edcc07fd2805874b0d14d9568fe Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Sep 2023 12:55:02 +0200 Subject: [PATCH 049/390] Adds unit test for Container::enter(). --- src/toolkit/container.c | 61 ++++++++++++++++++++++++++++++++--- src/toolkit/element.c | 71 ++++++++++++++++++++++++++++------------- src/toolkit/toolkit.h | 17 +++++++++- 3 files changed, 121 insertions(+), 28 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index bdef54dc..2d29f66d 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -199,7 +199,7 @@ void element_enter( x_to += x_from; y_to += y_from; - if (x_from <= x && x < y_to && y_from <= y && y < y_to) { + if (x_from <= x && x < x_to && y_from <= y && y < y_to) { wlmtk_element_enter(element_ptr, x - x_from, y - y_from); return; } @@ -316,11 +316,13 @@ void fake_parent_destroy(wlmtk_container_t *container_ptr) static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); +static void test_enter(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, + { 1, "enter", test_enter }, { 0, NULL, NULL } }; @@ -353,13 +355,13 @@ void test_add_remove(bs_test_t *test_ptr) wlmtk_element_t element1, element2, element3; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element1, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element1, &wlmtk_fake_element_impl)); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element2, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element2, &wlmtk_fake_element_impl)); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element3, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element3, &wlmtk_fake_element_impl)); wlmtk_container_add_element(&container, &element1); BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, &container); @@ -402,7 +404,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element, &wlmtk_fake_element_impl)); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_container_add_element(&container, &element); @@ -417,4 +419,53 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests the 'enter' method for container. */ +void test_enter(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + + wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_position(&elem1_ptr->element, -20, -40); + elem1_ptr->element.width = 10; + elem1_ptr->element.height = 5; + wlmtk_container_add_element(&container, &elem1_ptr->element); + wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_position(&elem2_ptr->element, 100, 200); + elem2_ptr->element.width = 10; + elem2_ptr->element.height = 5; + wlmtk_container_add_element(&container, &elem2_ptr->element); + + wlmtk_element_enter(&container.super_element, 0, 0); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->enter_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->enter_called); + + elem1_ptr->enter_x = 42; + elem1_ptr->enter_y = 42; + wlmtk_element_enter(&container.super_element, -20, -40); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->enter_called); + elem1_ptr->enter_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->enter_called); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->enter_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->enter_y); + + wlmtk_element_enter(&container.super_element, 107, 203); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->enter_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->enter_called); + elem2_ptr->enter_called = false; + BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->enter_x); + BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->enter_y); + + wlmtk_element_enter(&container.super_element, 110, 205); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->enter_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->enter_called); + + wlmtk_container_remove_element(&container, &elem1_ptr->element); + wlmtk_element_destroy(&elem1_ptr->element); + wlmtk_container_remove_element(&container, &elem2_ptr->element); + wlmtk_element_destroy(&elem2_ptr->element); + wlmtk_container_fini(&container); +} + /* == End of container.c =================================================== */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 9031b360..75b702c8 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -197,18 +197,7 @@ void handle_wlr_scene_node_destroy( bs_log(BS_FATAL, "Unexpected call into node's dtor on %p!", element_ptr); } -/* == Unit tests =========================================================== */ - -static void test_init_fini(bs_test_t *test_ptr); -static void test_set_parent_container(bs_test_t *test_ptr); -static void test_set_get_position(bs_test_t *test_ptr); - -const bs_test_case_t wlmtk_element_test_cases[] = { - { 1, "init_fini", test_init_fini }, - { 1, "set_parent_container", test_set_parent_container }, - { 1, "set_get_position", test_set_get_position }, - { 0, NULL, NULL } -}; +/* == Fake element, useful for unit tests. ================================= */ static void fake_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_create_scene_node( @@ -218,17 +207,36 @@ static void fake_enter( wlmtk_element_t *element_ptr, int x, int y); -const wlmtk_element_impl_t wlmtk_element_fake_impl = { +const wlmtk_element_impl_t wlmtk_fake_element_impl = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, .enter = fake_enter }; +/* ------------------------------------------------------------------------- */ +wlmtk_fake_element_t *wlmtk_fake_element_create(void) +{ + wlmtk_fake_element_t *fake_element_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_element_t)); + if (NULL == fake_element_ptr) return NULL; + + if (!wlmtk_element_init(&fake_element_ptr->element, + &wlmtk_fake_element_impl)) { + fake_destroy(&fake_element_ptr->element); + return NULL; + } + + return fake_element_ptr; +} + /* ------------------------------------------------------------------------- */ /** dtor for the "fake" element used for tests. */ void fake_destroy(wlmtk_element_t *element_ptr) { - wlmtk_element_fini(element_ptr); + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + wlmtk_element_fini(&fake_element_ptr->element); + free(fake_element_ptr); } /* ------------------------------------------------------------------------- */ @@ -245,10 +253,29 @@ struct wlr_scene_node *fake_create_scene_node( /* ------------------------------------------------------------------------- */ /** Handles 'tnter' events for the fake element. */ void fake_enter( - __UNUSED__ wlmtk_element_t *element_ptr, - __UNUSED__ int x, - __UNUSED__ int y) -{} + wlmtk_element_t *element_ptr, + int x, + int y) +{ + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + fake_element_ptr->enter_called = true; + fake_element_ptr->enter_x = x; + fake_element_ptr->enter_y = y; +} + +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); +static void test_set_parent_container(bs_test_t *test_ptr); +static void test_set_get_position(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_element_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 1, "set_parent_container", test_set_parent_container }, + { 1, "set_get_position", test_set_get_position }, + { 0, NULL, NULL } +}; /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ @@ -257,7 +284,7 @@ void test_init_fini(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element, &wlmtk_fake_element_impl)); BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl_ptr); wlmtk_element_destroy(&element); @@ -271,7 +298,7 @@ void test_set_parent_container(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element, &wlmtk_fake_element_impl)); // Setting a parent without a scene graph tree will not set a node. wlmtk_container_t parent_no_tree; @@ -322,7 +349,7 @@ void test_set_get_position(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element, &wlmtk_fake_element_impl)); // Exercise, must not crash. wlmtk_element_get_position(&element, NULL, NULL); @@ -360,7 +387,7 @@ void test_get_size(bs_test_t *test_ptr) wlmtk_element_t element; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_element_init(&element, &wlmtk_element_fake_impl)); + wlmtk_element_init(&element, &wlmtk_fake_element_impl)); element.width = 42; element.height = 21; diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 433857bd..9d8993c7 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -219,8 +219,23 @@ static inline void wlmtk_element_destroy( /** Unit tests for the element. */ extern const bs_test_case_t wlmtk_element_test_cases[]; +/** Fake element, useful for unit test. */ +typedef struct { + /** State of the element. */ + wlmtk_element_t element; + /** Indicates that Element::enter() was called. */ + bool enter_called; + /** The x argument of the last Element::enter() call. */ + int enter_x; + /** The y arguemnt of the last element::enter() call. */ + int enter_y; +} wlmtk_fake_element_t; + +/** Ctor for the fake element. */ +wlmtk_fake_element_t *wlmtk_fake_element_create(void); + /** Implementation table of a "fake" element for tests. */ -extern const wlmtk_element_impl_t wlmtk_element_fake_impl; +extern const wlmtk_element_impl_t wlmtk_fake_element_impl; /* ========================================================================= */ From ea1e4e6ea75c9902734e3cd1f560a8e2798434cb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Sep 2023 08:45:02 +0200 Subject: [PATCH 050/390] Changes current 'enter' method into 'motion'; as it has different purpose. --- src/toolkit/container.c | 64 ++++++++++++++++++++--------------------- src/toolkit/content.c | 21 -------------- src/toolkit/element.c | 13 ++++----- src/toolkit/toolkit.h | 24 +++++++++------- src/toolkit/toolkit.md | 22 ++++++++------ 5 files changed, 64 insertions(+), 80 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 2d29f66d..33854230 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -32,7 +32,7 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void element_enter( +static void element_motion( wlmtk_element_t *element_ptr, int x, int y); @@ -44,7 +44,7 @@ static void handle_wlr_scene_tree_node_destroy( static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, - .enter = element_enter + .motion = element_motion }; /* == Exported methods ===================================================== */ @@ -172,13 +172,13 @@ struct wlr_scene_node *element_create_scene_node( /* ------------------------------------------------------------------------- */ /** - * Implementation of the element's enter method: Handle pointer moves. + * Implementation of the element's motion method: Handle pointer moves. * * @param element_ptr * @param x * @param y */ -void element_enter( +void element_motion( wlmtk_element_t *element_ptr, int x, int y) @@ -200,7 +200,7 @@ void element_enter( y_to += y_from; if (x_from <= x && x < x_to && y_from <= y && y < y_to) { - wlmtk_element_enter(element_ptr, x - x_from, y - y_from); + wlmtk_element_motion(element_ptr, x - x_from, y - y_from); return; } } @@ -316,13 +316,13 @@ void fake_parent_destroy(wlmtk_container_t *container_ptr) static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); -static void test_enter(bs_test_t *test_ptr); +static void test_motion(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, - { 1, "enter", test_enter }, + { 1, "motion", test_motion }, { 0, NULL, NULL } }; @@ -420,8 +420,8 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests the 'enter' method for container. */ -void test_enter(bs_test_t *test_ptr) +/** Tests the 'motion' method for container. */ +void test_motion(bs_test_t *test_ptr) { wlmtk_container_t container; BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); @@ -437,29 +437,29 @@ void test_enter(bs_test_t *test_ptr) elem2_ptr->element.height = 5; wlmtk_container_add_element(&container, &elem2_ptr->element); - wlmtk_element_enter(&container.super_element, 0, 0); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->enter_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->enter_called); - - elem1_ptr->enter_x = 42; - elem1_ptr->enter_y = 42; - wlmtk_element_enter(&container.super_element, -20, -40); - BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->enter_called); - elem1_ptr->enter_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->enter_called); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->enter_x); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->enter_y); - - wlmtk_element_enter(&container.super_element, 107, 203); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->enter_called); - BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->enter_called); - elem2_ptr->enter_called = false; - BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->enter_x); - BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->enter_y); - - wlmtk_element_enter(&container.super_element, 110, 205); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->enter_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->enter_called); + wlmtk_element_motion(&container.super_element, 0, 0); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + + elem1_ptr->motion_x = 42; + elem1_ptr->motion_y = 42; + wlmtk_element_motion(&container.super_element, -20, -40); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); + elem1_ptr->motion_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); + + wlmtk_element_motion(&container.super_element, 107, 203); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->motion_called); + elem2_ptr->motion_called = false; + BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->motion_y); + + wlmtk_element_motion(&container.super_element, 110, 205); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); wlmtk_container_remove_element(&container, &elem1_ptr->element); wlmtk_element_destroy(&elem1_ptr->element); diff --git a/src/toolkit/content.c b/src/toolkit/content.c index c8a17146..80d400a0 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -31,15 +31,11 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void element_enter( - wlmtk_element_t *element_ptr, - int x, int y); /** Method table for the container's virtual methods. */ const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, - .enter = element_enter }; /* == Exported methods ===================================================== */ @@ -121,23 +117,6 @@ struct wlr_scene_node *element_create_scene_node( content_ptr, wlr_scene_tree_ptr); } -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the element's enter method: Handle pointer moves. - * - * @param element_ptr - * @param x - * @param y - */ -void element_enter( - wlmtk_element_t *element_ptr, - __UNUSED__ int x, - __UNUSED__ int y) -{ - __UNUSED__ wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); -} - /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 75b702c8..4f01fe5c 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -43,7 +43,6 @@ bool wlmtk_element_init( BS_ASSERT(NULL != element_impl_ptr); BS_ASSERT(NULL != element_impl_ptr->destroy); BS_ASSERT(NULL != element_impl_ptr->create_scene_node); - BS_ASSERT(NULL != element_impl_ptr->enter); memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; @@ -203,14 +202,14 @@ static void fake_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void fake_enter( +static void fake_motion( wlmtk_element_t *element_ptr, int x, int y); const wlmtk_element_impl_t wlmtk_fake_element_impl = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, - .enter = fake_enter + .motion = fake_motion }; /* ------------------------------------------------------------------------- */ @@ -252,16 +251,16 @@ struct wlr_scene_node *fake_create_scene_node( /* ------------------------------------------------------------------------- */ /** Handles 'tnter' events for the fake element. */ -void fake_enter( +void fake_motion( wlmtk_element_t *element_ptr, int x, int y) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); - fake_element_ptr->enter_called = true; - fake_element_ptr->enter_x = x; - fake_element_ptr->enter_y = y; + fake_element_ptr->motion_called = true; + fake_element_ptr->motion_x = x; + fake_element_ptr->motion_y = y; } /* == Unit tests =========================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 9d8993c7..3c980b17 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -91,8 +91,8 @@ struct _wlmtk_element_impl_t { struct wlr_scene_tree *wlr_scene_tree_ptr); /** Notifies that the pointer is within the element's area, at x,y. */ - void (*enter)(wlmtk_element_t *element_ptr, - int x, int y); + void (*motion)(wlmtk_element_t *element_ptr, + int x, int y); }; /** @@ -202,12 +202,14 @@ void wlmtk_element_get_size( int *width_ptr, int *height_ptr); -/** Virtual method: Calls 'enter' for the element's implementation. */ -static inline void wlmtk_element_enter( +/** Virtual method: Calls 'motion' for the element's implementation. */ +static inline void wlmtk_element_motion( wlmtk_element_t *element_ptr, int x, int y) { - element_ptr->impl_ptr->enter(element_ptr, x, y); + if (NULL != element_ptr->impl_ptr->motion) { + element_ptr->impl_ptr->motion(element_ptr, x, y); + } } /** Virtual method: Calls the dtor of the element's implementation. */ @@ -223,12 +225,12 @@ extern const bs_test_case_t wlmtk_element_test_cases[]; typedef struct { /** State of the element. */ wlmtk_element_t element; - /** Indicates that Element::enter() was called. */ - bool enter_called; - /** The x argument of the last Element::enter() call. */ - int enter_x; - /** The y arguemnt of the last element::enter() call. */ - int enter_y; + /** Indicates that Element::motion() was called. */ + bool motion_called; + /** The x argument of the last Element::motion() call. */ + int motion_x; + /** The y arguemnt of the last element::motion() call. */ + int motion_y; } wlmtk_fake_element_t; /** Ctor for the fake element. */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 464ae181..9752e660 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -40,6 +40,7 @@ class Element { {abstract}#void destroy() {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) + {abstract}#void motion(double x, double y) {abstract}#void enter() {abstract}#void leave() {abstract}#void click() @@ -65,9 +66,10 @@ class Container { {abstract}#void destroy() - void enter(Element*) - void leave(Element*) - void click(Element*) + void motion(double x, double y) + void enter() + void leave() + void click() } Element <|-- Container note right of Element::"add_element(Element*)" @@ -113,9 +115,10 @@ abstract class Content { {abstract}#void set_active(bool) {abstract}#void set_maximized(bool) {abstract}#void set_fullscreen(bool) - {abstract}#void enter(Element*) - {abstract}#void leave(Element*) - {abstract}#void click(Element*) + {abstract}#void motion(double x, double y) + {abstract}#void enter() + {abstract}#void leave() + {abstract}#void click() } Element <|-- Content note right of Content @@ -127,9 +130,10 @@ end note class LayerElement { Element parent - {abstract}#void enter(Element*) - {abstract}#void leave(Element*) - {abstract}#void click(Element*) + {abstract}#void motion(double x, double y) + {abstract}#void enter() + {abstract}#void leave() + {abstract}#void click() {abstract}#configure() } From 59544953ffef46166e8238566fe3d654236a7db8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Sep 2023 18:13:59 +0200 Subject: [PATCH 051/390] Fixes improper test teardown. --- src/toolkit/container.c | 45 ++++++++++++++++++----------------------- src/toolkit/element.c | 2 +- src/toolkit/toolkit.h | 8 +++++++- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 33854230..4fbddc7a 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -352,34 +352,29 @@ void test_add_remove(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( &container, &wlmtk_container_fake_impl)); - wlmtk_element_t element1, element2, element3; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element1, &wlmtk_fake_element_impl)); - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element2, &wlmtk_fake_element_impl)); - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element3, &wlmtk_fake_element_impl)); - - wlmtk_container_add_element(&container, &element1); - BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, &container); - wlmtk_container_add_element(&container, &element2); - BS_TEST_VERIFY_EQ(test_ptr, element2.parent_container_ptr, &container); - wlmtk_container_add_element(&container, &element3); - BS_TEST_VERIFY_EQ(test_ptr, element3.parent_container_ptr, &container); + wlmtk_fake_element_t *elem1_ptr, *elem2_ptr, *elem3_ptr; + elem1_ptr = wlmtk_fake_element_create(); + BS_ASSERT(NULL != elem1_ptr); + elem2_ptr = wlmtk_fake_element_create(); + BS_ASSERT(NULL != elem2_ptr); + elem3_ptr = wlmtk_fake_element_create(); + BS_ASSERT(NULL != elem3_ptr); - wlmtk_container_remove_element(&container, &element2); - BS_TEST_VERIFY_EQ(test_ptr, element2.parent_container_ptr, NULL); - - wlmtk_container_destroy(&container); - BS_TEST_VERIFY_EQ(test_ptr, element1.parent_container_ptr, NULL); - BS_TEST_VERIFY_EQ(test_ptr, element3.parent_container_ptr, NULL); + wlmtk_container_add_element(&container, &elem1_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, elem1_ptr->element.parent_container_ptr, &container); + wlmtk_container_add_element(&container, &elem2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, elem2_ptr->element.parent_container_ptr, &container); + wlmtk_container_add_element(&container, &elem3_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, elem3_ptr->element.parent_container_ptr, &container); - BS_TEST_VERIFY_EQ(test_ptr, element1.impl_ptr, NULL); - BS_TEST_VERIFY_EQ(test_ptr, element3.impl_ptr, NULL); + wlmtk_container_remove_element(&container, &elem2_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, elem2_ptr->element.parent_container_ptr); + wlmtk_element_destroy(&elem2_ptr->element); + // Will destroy contained elements. wlmtk_container_fini(&container); } diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 4f01fe5c..60e54d33 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -286,7 +286,7 @@ void test_init_fini(bs_test_t *test_ptr) wlmtk_element_init(&element, &wlmtk_fake_element_impl)); BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl_ptr); - wlmtk_element_destroy(&element); + wlmtk_element_fini(&element); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl_ptr); } diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 3c980b17..9de9911f 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -212,7 +212,13 @@ static inline void wlmtk_element_motion( } } -/** Virtual method: Calls the dtor of the element's implementation. */ +/** + * Virtual method: Calls the dtor of the element's implementation. + * + * The implementation is required to call @ref wlmtk_element_fini(). + * + * @param element_ptr + */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { element_ptr->impl_ptr->destroy(element_ptr); From 45addd710f10275a6159bec518488b08d64016a1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Sep 2023 18:20:44 +0200 Subject: [PATCH 052/390] Changes type of pointer motion args to double. --- src/toolkit/container.c | 6 +++--- src/toolkit/element.c | 6 +++--- src/toolkit/toolkit.h | 10 +++++----- src/toolkit/toolkit.md | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 4fbddc7a..fe707bdd 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -34,7 +34,7 @@ static struct wlr_scene_node *element_create_scene_node( struct wlr_scene_tree *wlr_scene_tree_ptr); static void element_motion( wlmtk_element_t *element_ptr, - int x, int y); + double x, double y); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -180,8 +180,8 @@ struct wlr_scene_node *element_create_scene_node( */ void element_motion( wlmtk_element_t *element_ptr, - int x, - int y) + double x, + double y) { wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 60e54d33..b1f446e2 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -204,7 +204,7 @@ static struct wlr_scene_node *fake_create_scene_node( struct wlr_scene_tree *wlr_scene_tree_ptr); static void fake_motion( wlmtk_element_t *element_ptr, - int x, int y); + double x, double y); const wlmtk_element_impl_t wlmtk_fake_element_impl = { .destroy = fake_destroy, @@ -253,8 +253,8 @@ struct wlr_scene_node *fake_create_scene_node( /** Handles 'tnter' events for the fake element. */ void fake_motion( wlmtk_element_t *element_ptr, - int x, - int y) + double x, + double y) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 9de9911f..b78207f6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -92,7 +92,7 @@ struct _wlmtk_element_impl_t { /** Notifies that the pointer is within the element's area, at x,y. */ void (*motion)(wlmtk_element_t *element_ptr, - int x, int y); + double x, double y); }; /** @@ -205,8 +205,8 @@ void wlmtk_element_get_size( /** Virtual method: Calls 'motion' for the element's implementation. */ static inline void wlmtk_element_motion( wlmtk_element_t *element_ptr, - int x, - int y) { + double x, + double y) { if (NULL != element_ptr->impl_ptr->motion) { element_ptr->impl_ptr->motion(element_ptr, x, y); } @@ -234,9 +234,9 @@ typedef struct { /** Indicates that Element::motion() was called. */ bool motion_called; /** The x argument of the last Element::motion() call. */ - int motion_x; + double motion_x; /** The y arguemnt of the last element::motion() call. */ - int motion_y; + double motion_y; } wlmtk_fake_element_t; /** Ctor for the fake element. */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 9752e660..a4ec1fa4 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -115,7 +115,7 @@ abstract class Content { {abstract}#void set_active(bool) {abstract}#void set_maximized(bool) {abstract}#void set_fullscreen(bool) - {abstract}#void motion(double x, double y) + {abstract}#void motion(double, double) {abstract}#void enter() {abstract}#void leave() {abstract}#void click() @@ -130,7 +130,7 @@ end note class LayerElement { Element parent - {abstract}#void motion(double x, double y) + {abstract}#void motion(double, double) {abstract}#void enter() {abstract}#void leave() {abstract}#void click() From 3e1711bafd3ea92f53bb989ae982535ce1c4cfc8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Sep 2023 18:35:20 +0200 Subject: [PATCH 053/390] Adds 'leave' method and a few minor fixes. --- src/toolkit/element.c | 39 +++++++++++++++++++++++++++++++++++++-- src/toolkit/toolkit.h | 17 ++++++++++++++++- src/toolkit/toolkit.md | 10 +++------- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index b1f446e2..31518b7b 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -205,11 +205,14 @@ static struct wlr_scene_node *fake_create_scene_node( static void fake_motion( wlmtk_element_t *element_ptr, double x, double y); +static void fake_leave( + wlmtk_element_t *element_ptr); const wlmtk_element_impl_t wlmtk_fake_element_impl = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, - .motion = fake_motion + .motion = fake_motion, + .leave = fake_leave }; /* ------------------------------------------------------------------------- */ @@ -250,7 +253,7 @@ struct wlr_scene_node *fake_create_scene_node( } /* ------------------------------------------------------------------------- */ -/** Handles 'tnter' events for the fake element. */ +/** Handles 'motion' events for the fake element. */ void fake_motion( wlmtk_element_t *element_ptr, double x, @@ -263,16 +266,30 @@ void fake_motion( fake_element_ptr->motion_y = y; } +/* ------------------------------------------------------------------------- */ +/** Handles 'leave' events for the fake element. */ +void fake_leave( + wlmtk_element_t *element_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + fake_element_ptr->leave_called = true; +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); static void test_set_parent_container(bs_test_t *test_ptr); static void test_set_get_position(bs_test_t *test_ptr); +static void test_get_size(bs_test_t *test_ptr); +static void test_motion_leave(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "set_parent_container", test_set_parent_container }, { 1, "set_get_position", test_set_get_position }, + { 1, "get_size", test_get_size }, + { 1, "motion_leave", test_motion_leave }, { 0, NULL, NULL } }; @@ -399,4 +416,22 @@ void test_get_size(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 21, height); } +/* ------------------------------------------------------------------------- */ +/** Exercises "motion" and "leave" methods. */ +void test_motion_leave(bs_test_t *test_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); + BS_ASSERT(NULL != fake_element_ptr); + + wlmtk_element_motion(&fake_element_ptr->element, 1.0, 2.0); + BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->motion_y); + + wlmtk_element_leave(&fake_element_ptr->element); + BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->leave_called); + + wlmtk_element_destroy(&fake_element_ptr->element); +} + /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index b78207f6..b1d8210c 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -90,9 +90,11 @@ struct _wlmtk_element_impl_t { wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); - /** Notifies that the pointer is within the element's area, at x,y. */ + /** Indicates pointer motion into or within the element area to (x,y). */ void (*motion)(wlmtk_element_t *element_ptr, double x, double y); + /** Indicates the pointer has left the element's area. */ + void (*leave)(wlmtk_element_t *element_ptr); }; /** @@ -212,6 +214,15 @@ static inline void wlmtk_element_motion( } } +/** Virtual method: Calls 'leave' for the element's implementation. */ +static inline void wlmtk_element_leave( + wlmtk_element_t *element_ptr) +{ + if (NULL != element_ptr->impl_ptr->leave) { + element_ptr->impl_ptr->leave(element_ptr); + } +} + /** * Virtual method: Calls the dtor of the element's implementation. * @@ -231,12 +242,16 @@ extern const bs_test_case_t wlmtk_element_test_cases[]; typedef struct { /** State of the element. */ wlmtk_element_t element; + /** Indicates that Element::motion() was called. */ bool motion_called; /** The x argument of the last Element::motion() call. */ double motion_x; /** The y arguemnt of the last element::motion() call. */ double motion_y; + + /** Indicates that Element::leave() was called. */ + bool leave_called; } wlmtk_fake_element_t; /** Ctor for the fake element. */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index a4ec1fa4..fd79c747 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -40,9 +40,8 @@ class Element { {abstract}#void destroy() {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) - {abstract}#void motion(double x, double y) - {abstract}#void enter() - {abstract}#void leave() + #void motion(double, double) + #void leave() {abstract}#void click() } note right of Element::"set_parent_container(Container*)" @@ -66,8 +65,7 @@ class Container { {abstract}#void destroy() - void motion(double x, double y) - void enter() + void motion(double, double) void leave() void click() } @@ -116,7 +114,6 @@ abstract class Content { {abstract}#void set_maximized(bool) {abstract}#void set_fullscreen(bool) {abstract}#void motion(double, double) - {abstract}#void enter() {abstract}#void leave() {abstract}#void click() } @@ -131,7 +128,6 @@ class LayerElement { Element parent {abstract}#void motion(double, double) - {abstract}#void enter() {abstract}#void leave() {abstract}#void click() From 3f49fe71fcc99d50b2b7a47924c320b299682ab6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Sep 2023 18:53:58 +0200 Subject: [PATCH 054/390] Adds test and implementation of Container::leave(). --- src/toolkit/container.c | 40 ++++++++++++++++++++++++++++++++++++++-- src/toolkit/toolkit.h | 3 +++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index fe707bdd..39cd1b50 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -35,6 +35,8 @@ static struct wlr_scene_node *element_create_scene_node( static void element_motion( wlmtk_element_t *element_ptr, double x, double y); +static void element_leave( + wlmtk_element_t *element_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -44,7 +46,8 @@ static void handle_wlr_scene_tree_node_destroy( static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, - .motion = element_motion + .motion = element_motion, + .leave = element_leave }; /* == Exported methods ===================================================== */ @@ -186,7 +189,6 @@ void element_motion( wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); - for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { @@ -201,9 +203,39 @@ void element_motion( if (x_from <= x && x < x_to && y_from <= y && y < y_to) { wlmtk_element_motion(element_ptr, x - x_from, y - y_from); + + if (NULL != container_ptr->pointer_focus_element_ptr) { + wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); + } + container_ptr->pointer_focus_element_ptr = element_ptr; return; } } + + // Getting here implies we didn't have an element catching the motion, + // so it must have happened outside our araea. We also should free + // pointer focus element now. + if (NULL != container_ptr->pointer_focus_element_ptr) { + wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); + container_ptr->pointer_focus_element_ptr = NULL; + } +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's leave method> Forwards it to the element + * currently having pointer focus, and clears that. + * + * @param element_ptr + */ +void element_leave(wlmtk_element_t *element_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + if (NULL == container_ptr->pointer_focus_element_ptr) return; + + wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); + container_ptr->pointer_focus_element_ptr = NULL; } /* ------------------------------------------------------------------------- */ @@ -446,6 +478,8 @@ void test_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); wlmtk_element_motion(&container.super_element, 107, 203); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); + elem1_ptr->leave_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->motion_called); elem2_ptr->motion_called = false; @@ -455,6 +489,8 @@ void test_motion(bs_test_t *test_ptr) wlmtk_element_motion(&container.super_element, 110, 205); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); + elem2_ptr->leave_called = false; wlmtk_container_remove_element(&container, &elem1_ptr->element); wlmtk_element_destroy(&elem1_ptr->element); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index b1d8210c..ad147074 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -278,6 +278,9 @@ struct _wlmtk_container_t { /** Listener for the `destroy` signal of `wlr_scene_tree_ptr->node`. */ struct wl_listener wlr_scene_tree_node_destroy_listener; + + /** Stores the element with current pointer focus. May be NULL. */ + wlmtk_element_t *pointer_focus_element_ptr; }; /** Virtual method table of the container. */ From cf04baeeb4a4db0b02e41efb462da754c37d4389 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Sep 2023 19:15:46 +0200 Subject: [PATCH 055/390] Starts moving toolkit header declarations into sub-files. --- src/toolkit/container.c | 2 +- src/toolkit/container.h | 142 +++++++++++++++++ src/toolkit/element.c | 3 +- src/toolkit/element.h | 252 ++++++++++++++++++++++++++++++ src/toolkit/toolkit.h | 329 +--------------------------------------- 5 files changed, 402 insertions(+), 326 deletions(-) create mode 100644 src/toolkit/container.h create mode 100644 src/toolkit/element.h diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 39cd1b50..33f5dd77 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -18,7 +18,7 @@ * limitations under the License. */ -#include "toolkit.h" +#include "container.h" #include "util.h" diff --git a/src/toolkit/container.h b/src/toolkit/container.h new file mode 100644 index 00000000..0fa14ebc --- /dev/null +++ b/src/toolkit/container.h @@ -0,0 +1,142 @@ +/* ========================================================================= */ +/** + * @file container.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_CONTAINER_H__ +#define __WLMTK_CONTAINER_H__ + +#include +#include + +/** Forward declaration: Container. */ +typedef struct _wlmtk_container_t wlmtk_container_t; +/** Forward declaration: Container virtual method implementations. */ +typedef struct _wlmtk_container_impl_t wlmtk_container_impl_t; + +#include "element.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** State of the container. */ +struct _wlmtk_container_t { + /** Super class of the container. */ + wlmtk_element_t super_element; + + /** Elements contained here. */ + bs_dllist_t elements; + + /** Implementation of the container's virtual methods. */ + const wlmtk_container_impl_t *impl_ptr; + + /** Scene tree. */ + struct wlr_scene_tree *wlr_scene_tree_ptr; + + /** Listener for the `destroy` signal of `wlr_scene_tree_ptr->node`. */ + struct wl_listener wlr_scene_tree_node_destroy_listener; + + /** Stores the element with current pointer focus. May be NULL. */ + wlmtk_element_t *pointer_focus_element_ptr; +}; + +/** Virtual method table of the container. */ +struct _wlmtk_container_impl_t { + /** dtor. */ + void (*destroy)(wlmtk_container_t *container_ptr); +}; + +/** + * Initializes the container with the provided virtual method table. + * + * @param container_ptr + * @param container_impl_ptr + * + * @return true on success. + */ +bool wlmtk_container_init( + wlmtk_container_t *container_ptr, + const wlmtk_container_impl_t *container_impl_ptr); + +/** + * Un-initializes the container. + * + * Any element still in `elements` will be destroyed. + * + * @param container_ptr + */ +void wlmtk_container_fini( + wlmtk_container_t *container_ptr); + +/** + * Adds `element_ptr` to the container. + * + * Requires that `element_ptr` is not added to a container yet. + * + * @param container_ptr + * @param element_ptr + */ +void wlmtk_container_add_element( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr); + +/** + * Removes `element_ptr` from the container. + * + * Expects that `container_ptr` is `element_ptr`'s parent container. + * + * @param container_ptr + * @param element_ptr + */ +void wlmtk_container_remove_element( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr); + +/** + * Returns the wlroots scene graph tree for this node. + * + * Private: Should be called only by wlmtk_element_t. + * + * @param container_ptr + * + * @return The scene tree, or NULL if not attached to a scene graph. + */ +struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( + wlmtk_container_t *container_ptr); + +/** Virtual method: Calls the dtor of the container's implementation. */ +static inline void wlmtk_container_destroy( + wlmtk_container_t *container_ptr) { + container_ptr->impl_ptr->destroy(container_ptr); +} + +/** Unit tests for the container. */ +extern const bs_test_case_t wlmtk_container_test_cases[]; + +/** Implementation table of a "fake" container for tests. */ +extern const wlmtk_container_impl_t wlmtk_container_fake_impl; + +/** Constructor for a fake container with a scene tree. */ +wlmtk_container_t *wlmtk_container_create_fake_parent(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_CONTAINER_H__ */ +/* == End of container.h =================================================== */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 31518b7b..08e077e2 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -18,7 +18,8 @@ * limitations under the License. */ -#include "toolkit.h" +#include "element.h" +#include "container.h" #include "util.h" diff --git a/src/toolkit/element.h b/src/toolkit/element.h new file mode 100644 index 00000000..f5099442 --- /dev/null +++ b/src/toolkit/element.h @@ -0,0 +1,252 @@ +/* ========================================================================= */ +/** + * @file element.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_ELEMENT_H__ +#define __WLMTK_ELEMENT_H__ + +#include +#include + +/** Forward declaration: Element. */ +typedef struct _wlmtk_element_t wlmtk_element_t; +/** Forward declaration: Element virtual method implementations. */ +typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; + +/** Forward declaration: Container. */ +typedef struct _wlmtk_container_t wlmtk_container_t; +struct wlr_scene_tree; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** State of an element. */ +struct _wlmtk_element_t { + /** X position of the element, relative to the container. */ + int x; + /** Y position of the element, relative to the container. */ + int y; + /** Width of the element, in pixels. */ + int width; + /** Height of the element, in pixels. */ + int height; + + /** The container this element belongs to, if any. */ + wlmtk_container_t *parent_container_ptr; + /** The node of elements. */ + bs_dllist_node_t dlnode; + + /** Implementation of abstract virtual methods. */ + const wlmtk_element_impl_t *impl_ptr; + + /** Points to the wlroots scene graph API node, if attached. */ + struct wlr_scene_node *wlr_scene_node_ptr; + + /** Whether the element is visible (drawn, when part of a scene graph). */ + bool visible; + + /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ + struct wl_listener wlr_scene_node_destroy_listener; +}; + +/** Pointers to the implementation of Element's virtual methods. */ +struct _wlmtk_element_impl_t { + /** Destroys the implementation of the element. */ + void (*destroy)(wlmtk_element_t *element_ptr); + /** Creates element's scene graph API node, child to wlr_scene_tree_ptr. */ + struct wlr_scene_node *(*create_scene_node)( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); + + /** Indicates pointer motion into or within the element area to (x,y). */ + void (*motion)(wlmtk_element_t *element_ptr, + double x, double y); + /** Indicates the pointer has left the element's area. */ + void (*leave)(wlmtk_element_t *element_ptr); +}; + +/** + * Initializes the element. + * + * @param element_ptr + * @param element_impl_ptr + * + * @return true on success. + */ +bool wlmtk_element_init( + wlmtk_element_t *element_ptr, + const wlmtk_element_impl_t *element_impl_ptr); + +/** + * Cleans up the element. + * + * @param element_ptr + */ +void wlmtk_element_fini( + wlmtk_element_t *element_ptr); + +/** Gets the dlnode from the element. */ +bs_dllist_node_t *wlmtk_dlnode_from_element( + wlmtk_element_t *element_ptr); +/** Gets the element from the dlnode. */ +wlmtk_element_t *wlmtk_element_from_dlnode( + bs_dllist_node_t *dlnode_ptr); + +/** + * Sets the parent container for the element. + * + * Will call @ref wlmtk_element_attach_to_scene_graph to align the scene graph + * with the new (or deleted) parent. + * + * Private: Should only be called by wlmtk_container_add_element, respectively + * wlmtk_container_remove_element ("friends"). + * + * @param element_ptr + * @param parent_container_ptr Pointer to the parent container, or NULL if + * the parent should be cleared. + */ +void wlmtk_element_set_parent_container( + wlmtk_element_t *element_ptr, + wlmtk_container_t *parent_container_ptr); + +/** + * Attaches or detaches the element to the parent's wlroots scene tree. + * + * If the element has a parent, and that parent is itself attached to the + * wlroots scene tree, this will either re-parent an already existing node, + * or invoke wlmtk_element_impl_t::create_scene_node to create and attach a + * new node to the paren'ts tree. + * Otherwise, it will clear any existing node. + * + * The function is idempotent. + * + * Private: Should only called by wlmtk_container_t methods, when there are + * changes to wlmtk_container_t::wlr_scene_tree. + * + * @param element_ptr + */ +void wlmtk_element_attach_to_scene_graph( + wlmtk_element_t *element_ptr); + +/** + * Sets the element's visibility. + * + * @param element_ptr + * @param visible + */ +void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible); + +/** + * Returns the position of the element. + * + * @param element_ptr + * @param x_ptr Optional, may be NULL. + * @param y_ptr Optional, may be NULL. + */ +void wlmtk_element_get_position( + wlmtk_element_t *element_ptr, + int *x_ptr, + int *y_ptr); + +/** + * Sets the position of the element. + * + * @param element_ptr + * @param x + * @param y + */ +void wlmtk_element_set_position( + wlmtk_element_t *element_ptr, + int x, + int y); + +/** + * Returns the size of the element, in pixels. + * + * @param element_ptr + * @param width_ptr Optional, may be NULL. + * @param height_ptr Optional, may be NULL. + */ +void wlmtk_element_get_size( + wlmtk_element_t *element_ptr, + int *width_ptr, + int *height_ptr); + +/** Virtual method: Calls 'motion' for the element's implementation. */ +static inline void wlmtk_element_motion( + wlmtk_element_t *element_ptr, + double x, + double y) { + if (NULL != element_ptr->impl_ptr->motion) { + element_ptr->impl_ptr->motion(element_ptr, x, y); + } +} + +/** Virtual method: Calls 'leave' for the element's implementation. */ +static inline void wlmtk_element_leave( + wlmtk_element_t *element_ptr) +{ + if (NULL != element_ptr->impl_ptr->leave) { + element_ptr->impl_ptr->leave(element_ptr); + } +} + +/** + * Virtual method: Calls the dtor of the element's implementation. + * + * The implementation is required to call @ref wlmtk_element_fini(). + * + * @param element_ptr + */ +static inline void wlmtk_element_destroy( + wlmtk_element_t *element_ptr) { + element_ptr->impl_ptr->destroy(element_ptr); +} + +/** Unit tests for the element. */ +extern const bs_test_case_t wlmtk_element_test_cases[]; + +/** Fake element, useful for unit test. */ +typedef struct { + /** State of the element. */ + wlmtk_element_t element; + + /** Indicates that Element::motion() was called. */ + bool motion_called; + /** The x argument of the last Element::motion() call. */ + double motion_x; + /** The y arguemnt of the last element::motion() call. */ + double motion_y; + + /** Indicates that Element::leave() was called. */ + bool leave_called; +} wlmtk_fake_element_t; + +/** Ctor for the fake element. */ +wlmtk_fake_element_t *wlmtk_fake_element_create(void); + +/** Implementation table of a "fake" element for tests. */ +extern const wlmtk_element_impl_t wlmtk_fake_element_impl; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_ELEMENT_H__ */ +/* == End of element.h ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index ad147074..560d4458 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,339 +30,20 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -struct wlr_scene_tree; - -/** Forward declaration: Element. */ -typedef struct _wlmtk_element_t wlmtk_element_t; -/** Forward declaration: Container. */ -typedef struct _wlmtk_container_t wlmtk_container_t; /** Forward declaration: Window. */ typedef struct _wlmtk_window_t wlmtk_window_t; /** Forward declaration: Window content. */ typedef struct _wlmtk_content_t wlmtk_content_t; -/** Forward declaration: Element virtual method implementations. */ -typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; -/** Forward declaration: Container virtual method implementations. */ -typedef struct _wlmtk_container_impl_t wlmtk_container_impl_t; /** Forward declaration: Content virtual method implementations. */ typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; -/** State of an element. */ -struct _wlmtk_element_t { - /** X position of the element, relative to the container. */ - int x; - /** Y position of the element, relative to the container. */ - int y; - /** Width of the element, in pixels. */ - int width; - /** Height of the element, in pixels. */ - int height; - - /** The container this element belongs to, if any. */ - wlmtk_container_t *parent_container_ptr; - /** The node of elements. */ - bs_dllist_node_t dlnode; - - /** Implementation of abstract virtual methods. */ - const wlmtk_element_impl_t *impl_ptr; - - /** Points to the wlroots scene graph API node, if attached. */ - struct wlr_scene_node *wlr_scene_node_ptr; - - /** Whether the element is visible (drawn, when part of a scene graph). */ - bool visible; - - /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ - struct wl_listener wlr_scene_node_destroy_listener; -}; - -/** Pointers to the implementation of Element's virtual methods. */ -struct _wlmtk_element_impl_t { - /** Destroys the implementation of the element. */ - void (*destroy)(wlmtk_element_t *element_ptr); - /** Creates element's scene graph API node, child to wlr_scene_tree_ptr. */ - struct wlr_scene_node *(*create_scene_node)( - wlmtk_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); - - /** Indicates pointer motion into or within the element area to (x,y). */ - void (*motion)(wlmtk_element_t *element_ptr, - double x, double y); - /** Indicates the pointer has left the element's area. */ - void (*leave)(wlmtk_element_t *element_ptr); -}; - -/** - * Initializes the element. - * - * @param element_ptr - * @param element_impl_ptr - * - * @return true on success. - */ -bool wlmtk_element_init( - wlmtk_element_t *element_ptr, - const wlmtk_element_impl_t *element_impl_ptr); - -/** - * Cleans up the element. - * - * @param element_ptr - */ -void wlmtk_element_fini( - wlmtk_element_t *element_ptr); - -/** Gets the dlnode from the element. */ -bs_dllist_node_t *wlmtk_dlnode_from_element( - wlmtk_element_t *element_ptr); -/** Gets the element from the dlnode. */ -wlmtk_element_t *wlmtk_element_from_dlnode( - bs_dllist_node_t *dlnode_ptr); - -/** - * Sets the parent container for the element. - * - * Will call @ref wlmtk_element_attach_to_scene_graph to align the scene graph - * with the new (or deleted) parent. - * - * Private: Should only be called by wlmtk_container_add_element, respectively - * wlmtk_container_remove_element ("friends"). - * - * @param element_ptr - * @param parent_container_ptr Pointer to the parent container, or NULL if - * the parent should be cleared. - */ -void wlmtk_element_set_parent_container( - wlmtk_element_t *element_ptr, - wlmtk_container_t *parent_container_ptr); - -/** - * Attaches or detaches the element to the parent's wlroots scene tree. - * - * If the element has a parent, and that parent is itself attached to the - * wlroots scene tree, this will either re-parent an already existing node, - * or invoke wlmtk_element_impl_t::create_scene_node to create and attach a - * new node to the paren'ts tree. - * Otherwise, it will clear any existing node. - * - * The function is idempotent. - * - * Private: Should only called by wlmtk_container_t methods, when there are - * changes to wlmtk_container_t::wlr_scene_tree. - * - * @param element_ptr - */ -void wlmtk_element_attach_to_scene_graph( - wlmtk_element_t *element_ptr); - -/** - * Sets the element's visibility. - * - * @param element_ptr - * @param visible - */ -void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible); - -/** - * Returns the position of the element. - * - * @param element_ptr - * @param x_ptr Optional, may be NULL. - * @param y_ptr Optional, may be NULL. - */ -void wlmtk_element_get_position( - wlmtk_element_t *element_ptr, - int *x_ptr, - int *y_ptr); - -/** - * Sets the position of the element. - * - * @param element_ptr - * @param x - * @param y - */ -void wlmtk_element_set_position( - wlmtk_element_t *element_ptr, - int x, - int y); +#include "element.h" +#include "container.h" -/** - * Returns the size of the element, in pixels. - * - * @param element_ptr - * @param width_ptr Optional, may be NULL. - * @param height_ptr Optional, may be NULL. - */ -void wlmtk_element_get_size( - wlmtk_element_t *element_ptr, - int *width_ptr, - int *height_ptr); - -/** Virtual method: Calls 'motion' for the element's implementation. */ -static inline void wlmtk_element_motion( - wlmtk_element_t *element_ptr, - double x, - double y) { - if (NULL != element_ptr->impl_ptr->motion) { - element_ptr->impl_ptr->motion(element_ptr, x, y); - } -} - -/** Virtual method: Calls 'leave' for the element's implementation. */ -static inline void wlmtk_element_leave( - wlmtk_element_t *element_ptr) -{ - if (NULL != element_ptr->impl_ptr->leave) { - element_ptr->impl_ptr->leave(element_ptr); - } -} - -/** - * Virtual method: Calls the dtor of the element's implementation. - * - * The implementation is required to call @ref wlmtk_element_fini(). - * - * @param element_ptr - */ -static inline void wlmtk_element_destroy( - wlmtk_element_t *element_ptr) { - element_ptr->impl_ptr->destroy(element_ptr); -} - -/** Unit tests for the element. */ -extern const bs_test_case_t wlmtk_element_test_cases[]; - -/** Fake element, useful for unit test. */ -typedef struct { - /** State of the element. */ - wlmtk_element_t element; - - /** Indicates that Element::motion() was called. */ - bool motion_called; - /** The x argument of the last Element::motion() call. */ - double motion_x; - /** The y arguemnt of the last element::motion() call. */ - double motion_y; - - /** Indicates that Element::leave() was called. */ - bool leave_called; -} wlmtk_fake_element_t; - -/** Ctor for the fake element. */ -wlmtk_fake_element_t *wlmtk_fake_element_create(void); - -/** Implementation table of a "fake" element for tests. */ -extern const wlmtk_element_impl_t wlmtk_fake_element_impl; - -/* ========================================================================= */ - -/** State of the container. */ -struct _wlmtk_container_t { - /** Super class of the container. */ - wlmtk_element_t super_element; - - /** Elements contained here. */ - bs_dllist_t elements; - - /** Implementation of the container's virtual methods. */ - const wlmtk_container_impl_t *impl_ptr; - - /** Scene tree. */ - struct wlr_scene_tree *wlr_scene_tree_ptr; - - /** Listener for the `destroy` signal of `wlr_scene_tree_ptr->node`. */ - struct wl_listener wlr_scene_tree_node_destroy_listener; - - /** Stores the element with current pointer focus. May be NULL. */ - wlmtk_element_t *pointer_focus_element_ptr; -}; - -/** Virtual method table of the container. */ -struct _wlmtk_container_impl_t { - /** dtor. */ - void (*destroy)(wlmtk_container_t *container_ptr); -}; - -/** - * Initializes the container with the provided virtual method table. - * - * @param container_ptr - * @param container_impl_ptr - * - * @return true on success. - */ -bool wlmtk_container_init( - wlmtk_container_t *container_ptr, - const wlmtk_container_impl_t *container_impl_ptr); - -/** - * Un-initializes the container. - * - * Any element still in `elements` will be destroyed. - * - * @param container_ptr - */ -void wlmtk_container_fini( - wlmtk_container_t *container_ptr); - -/** - * Adds `element_ptr` to the container. - * - * Requires that `element_ptr` is not added to a container yet. - * - * @param container_ptr - * @param element_ptr - */ -void wlmtk_container_add_element( - wlmtk_container_t *container_ptr, - wlmtk_element_t *element_ptr); - -/** - * Removes `element_ptr` from the container. - * - * Expects that `container_ptr` is `element_ptr`'s parent container. - * - * @param container_ptr - * @param element_ptr - */ -void wlmtk_container_remove_element( - wlmtk_container_t *container_ptr, - wlmtk_element_t *element_ptr); - -/** - * Returns the wlroots scene graph tree for this node. - * - * Private: Should be called only by wlmtk_element_t. - * - * @param container_ptr - * - * @return The scene tree, or NULL if not attached to a scene graph. - */ -struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( - wlmtk_container_t *container_ptr); - -/** Virtual method: Calls the dtor of the container's implementation. */ -static inline void wlmtk_container_destroy( - wlmtk_container_t *container_ptr) { - container_ptr->impl_ptr->destroy(container_ptr); -} - -/** Unit tests for the container. */ -extern const bs_test_case_t wlmtk_container_test_cases[]; - -/** Implementation table of a "fake" container for tests. */ -extern const wlmtk_container_impl_t wlmtk_container_fake_impl; - -/** Constructor for a fake container with a scene tree. */ -wlmtk_container_t *wlmtk_container_create_fake_parent(void); - -/* ========================================================================= */ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus /** State of the workspace. */ typedef struct _wlmtk_workspace_t wlmtk_workspace_t; From a6ca49b2de83ace925da3e596ef8336e938fa98a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 4 Sep 2023 21:19:13 +0200 Subject: [PATCH 056/390] Moves remaining toolkit elements into their own header files. --- src/toolkit/CMakeLists.txt | 8 +- src/toolkit/content.c | 2 +- src/toolkit/content.h | 109 +++++++++++++++++++++++ src/toolkit/toolkit.h | 174 +------------------------------------ src/toolkit/window.c | 4 +- src/toolkit/window.h | 71 +++++++++++++++ src/toolkit/workspace.c | 2 +- src/toolkit/workspace.h | 91 +++++++++++++++++++ 8 files changed, 287 insertions(+), 174 deletions(-) create mode 100644 src/toolkit/content.h create mode 100644 src/toolkit/window.h create mode 100644 src/toolkit/workspace.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 254a8e00..29299073 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -19,7 +19,13 @@ SET(PUBLIC_HEADER_FILES primitives.h style.h toolkit.h - util.h) + util.h + + container.h + content.h + element.h + window.h + workspace.h) ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 80d400a0..44eedcf1 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -19,7 +19,7 @@ * limitations under the License. */ -#include "toolkit.h" +#include "content.h" #define WLR_USE_UNSTABLE #include diff --git a/src/toolkit/content.h b/src/toolkit/content.h new file mode 100644 index 00000000..7818fcc2 --- /dev/null +++ b/src/toolkit/content.h @@ -0,0 +1,109 @@ +/* ========================================================================= */ +/** + * @file content.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_CONTENT_H__ +#define __WLMTK_CONTENT_H__ + +/** Forward declaration: Window content. */ +typedef struct _wlmtk_content_t wlmtk_content_t; + +/** Forward declaration: Content virtual method implementations. */ +typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; + +#include "window.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** State of the element. */ +struct _wlmtk_content_t { + /** Super class of the content: An element. */ + wlmtk_element_t super_element; + + /** Implementation of abstract virtual methods. */ + const wlmtk_content_impl_t *impl_ptr; + + /** + * The window this content belongs to. Will be set when creating + * the window. + */ + wlmtk_window_t *window_ptr; +}; + +/** Method table of the content. */ +struct _wlmtk_content_impl_t { + /** Destroys the implementation of the content. */ + void (*destroy)(wlmtk_content_t *content_ptr); + /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ + struct wlr_scene_node *(*create_scene_node)( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +}; + +/** + * Initializes the content. + * + * @param content_ptr + * @param content_impl_ptr + * + * @return true on success. + */ +bool wlmtk_content_init( + wlmtk_content_t *content_ptr, + const wlmtk_content_impl_t *content_impl_ptr); + +/** + * Cleans up the content. + * + * @param content_ptr + */ +void wlmtk_content_fini(wlmtk_content_t *content_ptr); + +/** + * Sets the window for the content. + * + * Private: Should only be called by Window ctor (a friend). + * + * @param content_ptr + * @param window_ptr + */ +void wlmtk_content_set_window( + wlmtk_content_t *content_ptr, + wlmtk_window_t *window_ptr); + +/** + * Returns the super Element of the content. + * + * @param content_ptr + * + * @return Pointer to the @ref wlmtk_element_t base instantiation to + * content_ptr. + */ +wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); + +/** Unit tests for content. */ +extern const bs_test_case_t wlmtk_content_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_CONTENT_H__ */ +/* == End of content.h ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 560d4458..12408465 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,182 +30,16 @@ #include #include -/** Forward declaration: Window. */ -typedef struct _wlmtk_window_t wlmtk_window_t; -/** Forward declaration: Window content. */ -typedef struct _wlmtk_content_t wlmtk_content_t; - -/** Forward declaration: Content virtual method implementations. */ -typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; - -#include "element.h" #include "container.h" +#include "content.h" +#include "element.h" +#include "window.h" +#include "workspace.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus -/** State of the workspace. */ -typedef struct _wlmtk_workspace_t wlmtk_workspace_t; - -/** - * Creates a workspace. - * - * TODO(kaeser@gubbe.ch): Consider replacing the interface with a container, - * and permit a "toplevel" container that will be at the server level. - * - * @param wlr_scene_tree_ptr - * - * @return Pointer to the workspace state, or NULL on error. Must be free'd - * via @ref wlmtk_workspace_destroy. - */ -wlmtk_workspace_t *wlmtk_workspace_create( - struct wlr_scene_tree *wlr_scene_tree_ptr); - -/** - * Destroys the workspace. Will destroy any stil-contained element. - * - * @param workspace_ptr - */ -void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); - -/** - * Maps the window: Adds it to the workspace container and makes it visible. - * - * @param workspace_ptr - * @param window_ptr - */ -void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); - -/** - * Unmaps the window: Sets it as invisible and removes it from the container. - * - * @param workspace_ptr - * @param window_ptr - */ -void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); - -/** - * Type conversion: Returns the @ref wlmtk_workspace_t from the container_ptr - * pointing to wlmtk_workspace_t::super_container. - * - * Asserts that the container is indeed from a wlmtk_workspace_t. - * - * @return Pointer to the workspace. - */ -wlmtk_workspace_t *wlmtk_workspace_from_container( - wlmtk_container_t *container_ptr); - -/** Unit tests for the workspace. */ -extern const bs_test_case_t wlmtk_workspace_test_cases[]; - -/* ========================================================================= */ - -/** - * Creates a window for the given content. - * - * @param content_ptr - * - * @return Pointer to the window state, or NULL on error. Must be free'd - * by calling @ref wlmtk_window_destroy. - */ -wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr); - -/** - * Destroys the window. - * - * @param window_ptr - */ -void wlmtk_window_destroy(wlmtk_window_t *window_ptr); - -/** - * Returns the super Element of the window. - * - * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or - * whether to keep the ancestry members public. - * - * @param window_ptr - * - * @return Pointer to the @ref wlmtk_element_t base instantiation to - * window_ptr. - */ -wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); - -/** Unit tests for window. */ -extern const bs_test_case_t wlmtk_window_test_cases[]; - -/* ========================================================================= */ - -/** State of the element. */ -struct _wlmtk_content_t { - /** Super class of the content: An element. */ - wlmtk_element_t super_element; - - /** Implementation of abstract virtual methods. */ - const wlmtk_content_impl_t *impl_ptr; - - /** - * The window this content belongs to. Will be set when creating - * the window. - */ - wlmtk_window_t *window_ptr; -}; - -/** Method table of the content. */ -struct _wlmtk_content_impl_t { - /** Destroys the implementation of the content. */ - void (*destroy)(wlmtk_content_t *content_ptr); - /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ - struct wlr_scene_node *(*create_scene_node)( - wlmtk_content_t *content_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); -}; - -/** - * Initializes the content. - * - * @param content_ptr - * @param content_impl_ptr - * - * @return true on success. - */ -bool wlmtk_content_init( - wlmtk_content_t *content_ptr, - const wlmtk_content_impl_t *content_impl_ptr); - -/** - * Cleans up the content. - * - * @param content_ptr - */ -void wlmtk_content_fini(wlmtk_content_t *content_ptr); - -/** - * Sets the window for the content. - * - * Private: Should only be called by Window ctor (a friend). - * - * @param content_ptr - * @param window_ptr - */ -void wlmtk_content_set_window( - wlmtk_content_t *content_ptr, - wlmtk_window_t *window_ptr); - -/** - * Returns the super Element of the content. - * - * @param content_ptr - * - * @return Pointer to the @ref wlmtk_element_t base instantiation to - * content_ptr. - */ -wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); - -/** Unit tests for content. */ -extern const bs_test_case_t wlmtk_content_test_cases[]; #ifdef __cplusplus } // extern "C" diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7dd5384c..6a5982a3 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -18,7 +18,9 @@ * limitations under the License. */ -#include "toolkit.h" +#include "window.h" + +#include "container.h" /* == Declarations ========================================================= */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h new file mode 100644 index 00000000..a8f16dac --- /dev/null +++ b/src/toolkit/window.h @@ -0,0 +1,71 @@ +/* ========================================================================= */ +/** + * @file window.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_WINDOW_H__ +#define __WLMTK_WINDOW_H__ + +/** Forward declaration: Window. */ +typedef struct _wlmtk_window_t wlmtk_window_t; + +#include "element.h" +#include "content.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a window for the given content. + * + * @param content_ptr + * + * @return Pointer to the window state, or NULL on error. Must be free'd + * by calling @ref wlmtk_window_destroy. + */ +wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr); + +/** + * Destroys the window. + * + * @param window_ptr + */ +void wlmtk_window_destroy(wlmtk_window_t *window_ptr); + +/** + * Returns the super Element of the window. + * + * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or + * whether to keep the ancestry members public. + * + * @param window_ptr + * + * @return Pointer to the @ref wlmtk_element_t base instantiation to + * window_ptr. + */ +wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); + +/** Unit tests for window. */ +extern const bs_test_case_t wlmtk_window_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_WINDOW_H__ */ +/* == End of window.h ====================================================== */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 812c9944..8b0b30c5 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -18,7 +18,7 @@ * limitations under the License. */ -#include "toolkit.h" +#include "workspace.h" #define WLR_USE_UNSTABLE #include diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h new file mode 100644 index 00000000..9e3301b2 --- /dev/null +++ b/src/toolkit/workspace.h @@ -0,0 +1,91 @@ +/* ========================================================================= */ +/** + * @file workspace.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_WORKSPACE_H__ +#define __WLMTK_WORKSPACE_H__ + +#include "container.h" +#include "window.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** State of the workspace. */ +typedef struct _wlmtk_workspace_t wlmtk_workspace_t; + +/** + * Creates a workspace. + * + * TODO(kaeser@gubbe.ch): Consider replacing the interface with a container, + * and permit a "toplevel" container that will be at the server level. + * + * @param wlr_scene_tree_ptr + * + * @return Pointer to the workspace state, or NULL on error. Must be free'd + * via @ref wlmtk_workspace_destroy. + */ +wlmtk_workspace_t *wlmtk_workspace_create( + struct wlr_scene_tree *wlr_scene_tree_ptr); + +/** + * Destroys the workspace. Will destroy any stil-contained element. + * + * @param workspace_ptr + */ +void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); + +/** + * Maps the window: Adds it to the workspace container and makes it visible. + * + * @param workspace_ptr + * @param window_ptr + */ +void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + +/** + * Unmaps the window: Sets it as invisible and removes it from the container. + * + * @param workspace_ptr + * @param window_ptr + */ +void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + +/** + * Type conversion: Returns the @ref wlmtk_workspace_t from the container_ptr + * pointing to wlmtk_workspace_t::super_container. + * + * Asserts that the container is indeed from a wlmtk_workspace_t. + * + * @return Pointer to the workspace. + */ +wlmtk_workspace_t *wlmtk_workspace_from_container( + wlmtk_container_t *container_ptr); + +/** Unit tests for the workspace. */ +extern const bs_test_case_t wlmtk_workspace_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_WORKSPACE_H__ */ +/* == End of workspace.h =================================================== */ From 7516332e8c4c18c9e716d7c11305047a9b7ea811 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 4 Sep 2023 21:37:27 +0200 Subject: [PATCH 057/390] Extends motion() loop to proceed if the element did not handle the motion. --- src/toolkit/container.c | 28 +++++++++++++++++++++------- src/toolkit/element.c | 5 +++-- src/toolkit/element.h | 13 +++++++------ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 33f5dd77..b7fbccc2 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -32,7 +32,7 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void element_motion( +static wlmtk_element_t *element_motion( wlmtk_element_t *element_ptr, double x, double y); static void element_leave( @@ -180,8 +180,11 @@ struct wlr_scene_node *element_create_scene_node( * @param element_ptr * @param x * @param y + * + * @return Pointer to the (non-container) element handling the motion, or NULL + * if the motion wasn't handled. */ -void element_motion( +wlmtk_element_t *element_motion( wlmtk_element_t *element_ptr, double x, double y) @@ -202,13 +205,15 @@ void element_motion( y_to += y_from; if (x_from <= x && x < x_to && y_from <= y && y < y_to) { - wlmtk_element_motion(element_ptr, x - x_from, y - y_from); + wlmtk_element_t *motion_element_ptr = wlmtk_element_motion( + element_ptr, x - x_from, y - y_from); + if (NULL == motion_element_ptr) continue; if (NULL != container_ptr->pointer_focus_element_ptr) { wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); } container_ptr->pointer_focus_element_ptr = element_ptr; - return; + return motion_element_ptr; } } @@ -219,6 +224,7 @@ void element_motion( wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); container_ptr->pointer_focus_element_ptr = NULL; } + return NULL; } /* ------------------------------------------------------------------------- */ @@ -457,11 +463,13 @@ void test_motion(bs_test_t *test_ptr) wlmtk_element_set_position(&elem1_ptr->element, -20, -40); elem1_ptr->element.width = 10; elem1_ptr->element.height = 5; + elem1_ptr->motion_return_value = &elem1_ptr->element; wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem2_ptr->element, 100, 200); elem2_ptr->element.width = 10; elem2_ptr->element.height = 5; + elem2_ptr->motion_return_value = &elem2_ptr->element; wlmtk_container_add_element(&container, &elem2_ptr->element); wlmtk_element_motion(&container.super_element, 0, 0); @@ -470,14 +478,18 @@ void test_motion(bs_test_t *test_ptr) elem1_ptr->motion_x = 42; elem1_ptr->motion_y = 42; - wlmtk_element_motion(&container.super_element, -20, -40); + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + wlmtk_element_motion(&container.super_element, -20, -40)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); elem1_ptr->motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); - wlmtk_element_motion(&container.super_element, 107, 203); + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + wlmtk_element_motion(&container.super_element, 107, 203)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); elem1_ptr->leave_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); @@ -486,7 +498,9 @@ void test_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->motion_x); BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->motion_y); - wlmtk_element_motion(&container.super_element, 110, 205); + BS_TEST_VERIFY_EQ( + test_ptr, NULL, + wlmtk_element_motion(&container.super_element, 110, 205)); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 08e077e2..dccacf51 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -203,7 +203,7 @@ static void fake_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void fake_motion( +static wlmtk_element_t *fake_motion( wlmtk_element_t *element_ptr, double x, double y); static void fake_leave( @@ -255,7 +255,7 @@ struct wlr_scene_node *fake_create_scene_node( /* ------------------------------------------------------------------------- */ /** Handles 'motion' events for the fake element. */ -void fake_motion( +wlmtk_element_t *fake_motion( wlmtk_element_t *element_ptr, double x, double y) @@ -265,6 +265,7 @@ void fake_motion( fake_element_ptr->motion_called = true; fake_element_ptr->motion_x = x; fake_element_ptr->motion_y = y; + return fake_element_ptr->motion_return_value; } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/element.h b/src/toolkit/element.h index f5099442..c331d98e 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -75,8 +75,8 @@ struct _wlmtk_element_impl_t { struct wlr_scene_tree *wlr_scene_tree_ptr); /** Indicates pointer motion into or within the element area to (x,y). */ - void (*motion)(wlmtk_element_t *element_ptr, - double x, double y); + wlmtk_element_t *(*motion)(wlmtk_element_t *element_ptr, + double x, double y); /** Indicates the pointer has left the element's area. */ void (*leave)(wlmtk_element_t *element_ptr); }; @@ -189,13 +189,12 @@ void wlmtk_element_get_size( int *height_ptr); /** Virtual method: Calls 'motion' for the element's implementation. */ -static inline void wlmtk_element_motion( +static inline wlmtk_element_t *wlmtk_element_motion( wlmtk_element_t *element_ptr, double x, double y) { - if (NULL != element_ptr->impl_ptr->motion) { - element_ptr->impl_ptr->motion(element_ptr, x, y); - } + if (NULL == element_ptr->impl_ptr->motion) return NULL; + return element_ptr->impl_ptr->motion(element_ptr, x, y); } /** Virtual method: Calls 'leave' for the element's implementation. */ @@ -233,6 +232,8 @@ typedef struct { double motion_x; /** The y arguemnt of the last element::motion() call. */ double motion_y; + /** Return value to pass when motion is called. */ + wlmtk_element_t *motion_return_value; /** Indicates that Element::leave() was called. */ bool leave_called; From 64253afc6ebb4249887bac1023057b68f8b6676a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 4 Sep 2023 21:38:32 +0200 Subject: [PATCH 058/390] Adds a TODO for motion test. --- src/toolkit/container.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index b7fbccc2..14efb231 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -513,4 +513,10 @@ void test_motion(bs_test_t *test_ptr) wlmtk_container_fini(&container); } +/* + * TODO(kaeser@gubbe.ch): Extend motion test to verify a search is continued + * if an element in the area returns NULL. Also verify it continues if the + * element is not visible. + */ + /* == End of container.c =================================================== */ From 2252c52c09b06f4ab3bb47447bbed94979b2fd97 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 15 Sep 2023 17:40:39 +0200 Subject: [PATCH 059/390] Replaces get_size with get_dimensions. This permits to fix the handling of containers where (content) elements are placed further left or on top of the container's position. Adds the corresponding test case and adjusts behaviour suitably. --- src/toolkit/container.c | 173 +++++++++++++++++++++++++++++++++++++--- src/toolkit/content.c | 54 ++++++++++++- src/toolkit/content.h | 3 + src/toolkit/element.c | 70 +++++++++++----- src/toolkit/workspace.c | 11 ++- src/xdg_toplevel.c | 30 ++++++- 6 files changed, 308 insertions(+), 33 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 14efb231..4289ff62 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -32,6 +32,12 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); static wlmtk_element_t *element_motion( wlmtk_element_t *element_ptr, double x, double y); @@ -46,6 +52,7 @@ static void handle_wlr_scene_tree_node_destroy( static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, + .get_dimensions = element_get_dimensions, .motion = element_motion, .leave = element_leave }; @@ -173,6 +180,53 @@ struct wlr_scene_node *element_create_scene_node( return &container_ptr->wlr_scene_tree_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's get_dimensions method: Return dimensions. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + + int left = 0, top = 0, right = 0, bottom = 0; + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + + int x, y; + wlmtk_element_get_position(element_ptr, &x, &y); + + int l, t, r, b; + wlmtk_element_get_dimensions(element_ptr, &l, &t, &r, &b); + l += x; + t += y; + r += x; + b += y; + left = BS_MIN(left, l); + top = BS_MIN(top, t); + right = BS_MAX(right, r); + bottom = BS_MAX(bottom, b); + } + + if (NULL != left_ptr) *left_ptr = left; + if (NULL != top_ptr) *top_ptr = top; + if (NULL != right_ptr) *right_ptr = right; + if (NULL != bottom_ptr) *bottom_ptr = bottom; +} + /* ------------------------------------------------------------------------- */ /** * Implementation of the element's motion method: Handle pointer moves. @@ -198,15 +252,19 @@ wlmtk_element_t *element_motion( wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); // Compute the box occupied by "element_ptr", relative to container. + int x_pos, y_pos; + wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); int x_from, y_from, x_to, y_to; - wlmtk_element_get_position(element_ptr, &x_from, &y_from); - wlmtk_element_get_size(element_ptr, &x_to, &y_to); - x_to += x_from; - y_to += y_from; + wlmtk_element_get_dimensions( + element_ptr, &x_from, &y_from, &x_to, &y_to); + x_from += x_pos; + y_from += y_pos; + x_to += x_pos; + y_to += y_pos; if (x_from <= x && x < x_to && y_from <= y && y < y_to) { wlmtk_element_t *motion_element_ptr = wlmtk_element_motion( - element_ptr, x - x_from, y - y_from); + element_ptr, x - x_pos, y - y_pos); if (NULL == motion_element_ptr) continue; if (NULL != container_ptr->pointer_focus_element_ptr) { @@ -355,12 +413,14 @@ static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); static void test_motion(bs_test_t *test_ptr); +static void test_motion_nested(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, { 1, "motion", test_motion }, + { 1, "motion_nested", test_motion_nested }, { 0, NULL, NULL } }; @@ -461,17 +521,98 @@ void test_motion(bs_test_t *test_ptr) wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem1_ptr->element, -20, -40); - elem1_ptr->element.width = 10; - elem1_ptr->element.height = 5; + elem1_ptr->width = 10; + elem1_ptr->height = 5; + elem1_ptr->motion_return_value = &elem1_ptr->element; + wlmtk_container_add_element(&container, &elem1_ptr->element); + wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_position(&elem2_ptr->element, 100, 200); + elem2_ptr->width = 10; + elem2_ptr->height = 5; + elem2_ptr->motion_return_value = &elem2_ptr->element; + wlmtk_container_add_element(&container, &elem2_ptr->element); + + wlmtk_element_motion(&container.super_element, 0, 0); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + + elem1_ptr->motion_x = 42; + elem1_ptr->motion_y = 42; + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + wlmtk_element_motion(&container.super_element, -20, -40)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); + elem1_ptr->motion_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); + + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + wlmtk_element_motion(&container.super_element, 107, 203)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); + elem1_ptr->leave_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->motion_called); + elem2_ptr->motion_called = false; + BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->motion_y); + + BS_TEST_VERIFY_EQ( + test_ptr, NULL, + wlmtk_element_motion(&container.super_element, 110, 205)); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); + elem2_ptr->leave_called = false; + + wlmtk_container_remove_element(&container, &elem1_ptr->element); + wlmtk_element_destroy(&elem1_ptr->element); + wlmtk_container_remove_element(&container, &elem2_ptr->element); + wlmtk_element_destroy(&elem2_ptr->element); + wlmtk_container_fini(&container); +} + +/* ------------------------------------------------------------------------- */ +/** Tests the 'motion' method for container. */ +void test_motion_nested(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + + wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_position(&elem1_ptr->element, -20, -40); + elem1_ptr->width = 10; + elem1_ptr->height = 5; elem1_ptr->motion_return_value = &elem1_ptr->element; wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem2_ptr->element, 100, 200); - elem2_ptr->element.width = 10; - elem2_ptr->element.height = 5; + elem2_ptr->width = 10; + elem2_ptr->height = 5; elem2_ptr->motion_return_value = &elem2_ptr->element; wlmtk_container_add_element(&container, &elem2_ptr->element); + int l, t, r, b; + wlmtk_element_get_dimensions(&container.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, -20, l); + BS_TEST_VERIFY_EQ(test_ptr, -40, t); + BS_TEST_VERIFY_EQ(test_ptr, 110, r); + BS_TEST_VERIFY_EQ(test_ptr, 205, b); + + wlmtk_container_t parent_container; + BS_ASSERT(wlmtk_container_init(&parent_container, + &wlmtk_container_fake_impl)); + wlmtk_container_add_element(&parent_container, + &container.super_element); + + wlmtk_element_get_dimensions(&parent_container.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, -20, l); + BS_TEST_VERIFY_EQ(test_ptr, -40, t); + BS_TEST_VERIFY_EQ(test_ptr, 110, r); + BS_TEST_VERIFY_EQ(test_ptr, 205, b); + + wlmtk_element_motion(&container.super_element, 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); @@ -487,6 +628,16 @@ void test_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + wlmtk_element_motion(&parent_container.super_element, -20, -40)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); + elem1_ptr->motion_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); + + BS_TEST_VERIFY_NEQ( test_ptr, NULL, wlmtk_element_motion(&container.super_element, 107, 203)); @@ -510,6 +661,10 @@ void test_motion(bs_test_t *test_ptr) wlmtk_element_destroy(&elem1_ptr->element); wlmtk_container_remove_element(&container, &elem2_ptr->element); wlmtk_element_destroy(&elem2_ptr->element); + + wlmtk_container_remove_element(&parent_container, + &container.super_element); + wlmtk_container_fini(&parent_container); wlmtk_container_fini(&container); } diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 44eedcf1..085847e2 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -31,11 +31,18 @@ static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); /** Method table for the container's virtual methods. */ const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, + .get_dimensions = element_get_dimensions, }; /* == Exported methods ===================================================== */ @@ -49,6 +56,8 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr); BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); + BS_ASSERT(NULL != content_impl_ptr->get_size); + memset(content_ptr, 0, sizeof(wlmtk_content_t)); if (!wlmtk_element_init(&content_ptr->super_element, @@ -117,6 +126,31 @@ struct wlr_scene_node *element_create_scene_node( content_ptr, wlr_scene_tree_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's get_dimensions method: Return dimensions. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + if (NULL != left_ptr) *left_ptr = 0; + if (NULL != top_ptr) *top_ptr = 0; + + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + content_ptr->impl_ptr->get_size(content_ptr, right_ptr, bottom_ptr); +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); @@ -140,10 +174,20 @@ static struct wlr_scene_node *test_create_scene_node_cb( wlr_scene_tree_ptr, NULL); return &wlr_scene_buffer_ptr->node; } +/** returns a fake size. */ +static void test_get_size_cb( + __UNUSED__ wlmtk_content_t *content_ptr, + int *width_ptr, int *height_ptr) +{ + if (NULL != width_ptr) *width_ptr = 42; + if (NULL != height_ptr) *height_ptr = 21; +} + /** Method table for the content we're using for test. */ static const wlmtk_content_impl_t test_content_impl = { .destroy = test_destroy_cb, - .create_scene_node = test_create_scene_node_cb + .create_scene_node = test_create_scene_node_cb, + .get_size = test_get_size_cb, }; /* ------------------------------------------------------------------------- */ @@ -157,11 +201,19 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, content.super_element.impl_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, content.impl_ptr); + int l, t, r, b; + wlmtk_element_get_dimensions(&content.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, 0, l); + BS_TEST_VERIFY_EQ(test_ptr, 0, t); + BS_TEST_VERIFY_EQ(test_ptr, 42, r); + BS_TEST_VERIFY_EQ(test_ptr, 21, b); + content.impl_ptr->destroy(&content); // Also expect the super element to be un-initialized. BS_TEST_VERIFY_EQ(test_ptr, NULL, content.super_element.impl_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, content.impl_ptr); + } /* == End of content.c ================================================== */ diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 7818fcc2..a0dd47de 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -55,6 +55,9 @@ struct _wlmtk_content_impl_t { struct wlr_scene_node *(*create_scene_node)( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); + /** Gets width and height of the content. */ + void (*get_size)(wlmtk_content_t *content_ptr, + int *width_ptr, int *height_ptr); }; /** diff --git a/src/toolkit/element.c b/src/toolkit/element.c index dccacf51..8ba9a731 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -44,6 +44,7 @@ bool wlmtk_element_init( BS_ASSERT(NULL != element_impl_ptr); BS_ASSERT(NULL != element_impl_ptr->destroy); BS_ASSERT(NULL != element_impl_ptr->create_scene_node); + BS_ASSERT(NULL != element_impl_ptr->get_dimensions); memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; @@ -168,13 +169,15 @@ void wlmtk_element_set_position( } /* ------------------------------------------------------------------------- */ -void wlmtk_element_get_size( +void wlmtk_element_get_dimensions( wlmtk_element_t *element_ptr, - int *width_ptr, - int *height_ptr) + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) { - if (NULL != width_ptr) *width_ptr = element_ptr->width; - if (NULL != height_ptr) *height_ptr = element_ptr->height; + element_ptr->impl_ptr->get_dimensions( + element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } /* == Local (static) methods =============================================== */ @@ -203,6 +206,12 @@ static void fake_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void fake_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); static wlmtk_element_t *fake_motion( wlmtk_element_t *element_ptr, double x, double y); @@ -212,6 +221,7 @@ static void fake_leave( const wlmtk_element_impl_t wlmtk_fake_element_impl = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, + .get_dimensions = fake_get_dimensions, .motion = fake_motion, .leave = fake_leave }; @@ -253,6 +263,23 @@ struct wlr_scene_node *fake_create_scene_node( return &wlr_scene_buffer_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** A "fake" 'get_dimensions'. */ +void fake_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + if (NULL != left_ptr) *left_ptr = 0; + if (NULL != top_ptr) *top_ptr = 0; + if (NULL != right_ptr) *right_ptr = fake_element_ptr->width; + if (NULL != bottom_ptr) *bottom_ptr = fake_element_ptr->height; +} + /* ------------------------------------------------------------------------- */ /** Handles 'motion' events for the fake element. */ wlmtk_element_t *fake_motion( @@ -283,14 +310,14 @@ void fake_leave( static void test_init_fini(bs_test_t *test_ptr); static void test_set_parent_container(bs_test_t *test_ptr); static void test_set_get_position(bs_test_t *test_ptr); -static void test_get_size(bs_test_t *test_ptr); +static void test_get_dimensions(bs_test_t *test_ptr); static void test_motion_leave(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "set_parent_container", test_set_parent_container }, { 1, "set_get_position", test_set_get_position }, - { 1, "get_size", test_get_size }, + { 1, "get_dimensions", test_get_dimensions }, { 1, "motion_leave", test_motion_leave }, { 0, NULL, NULL } }; @@ -399,23 +426,24 @@ void test_set_get_position(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests get_size. */ -void test_get_size(bs_test_t *test_ptr) +/** Tests get_dimensions. */ +void test_get_dimensions(bs_test_t *test_ptr) { - wlmtk_element_t element; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element, &wlmtk_fake_element_impl)); - element.width = 42; - element.height = 21; + wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); + fake_element_ptr->width = 42; + fake_element_ptr->height = 21; // Must not crash. - wlmtk_element_get_size(&element, NULL, NULL); - - int width, height; - wlmtk_element_get_size(&element, &width, &height); - BS_TEST_VERIFY_EQ(test_ptr, 42, width); - BS_TEST_VERIFY_EQ(test_ptr, 21, height); + wlmtk_element_get_dimensions( + &fake_element_ptr->element, NULL, NULL, NULL, NULL); + + int top, left, right, bottom; + wlmtk_element_get_dimensions( + &fake_element_ptr->element, &top, &left, &right, &bottom); + BS_TEST_VERIFY_EQ(test_ptr, 0, top); + BS_TEST_VERIFY_EQ(test_ptr, 0, left); + BS_TEST_VERIFY_EQ(test_ptr, 42, right); + BS_TEST_VERIFY_EQ(test_ptr, 21, bottom); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 8b0b30c5..f3a50577 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -173,10 +173,19 @@ static struct wlr_scene_node *test_content_create_scene_node( wlr_scene_tree_ptr, NULL); return &wlr_scene_buffer_ptr->node; } +/** Gets size of the content, fake mode. */ +static void test_content_get_size( + __UNUSED__ wlmtk_content_t *content_ptr, + int *width_ptr, int *height_ptr) +{ + if (NULL != width_ptr) *width_ptr = 42; + if (NULL != height_ptr) *height_ptr = 21; +} /** Method table for the node under test. */ static const wlmtk_content_impl_t test_content_impl = { .destroy = test_content_destroy, - .create_scene_node = test_content_create_scene_node + .create_scene_node = test_content_create_scene_node, + .get_size = test_content_get_size }; /* ------------------------------------------------------------------------- */ diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index d26130e5..7ed32ae2 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -195,11 +195,16 @@ static void xdg_tl_content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *xdg_tl_content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void xdg_tl_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr); /** Method table for the `wlmtk_content_t` virtual methods. */ const wlmtk_content_impl_t content_impl = { .destroy = xdg_tl_content_destroy, - .create_scene_node = xdg_tl_content_create_scene_node + .create_scene_node = xdg_tl_content_create_scene_node, + .get_size = xdg_tl_content_get_size, }; /* == Exported methods ===================================================== */ @@ -823,6 +828,29 @@ struct wlr_scene_node *xdg_tl_content_create_scene_node( return &surface_wlr_scene_tree_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** + * Gets the dimensions of the element in pixels, relative to the position. + * + * @param content_ptr + * @param width_ptr Width of content. May be NULL. + * @param height_ptr Height of content. May be NULL. + */ +void xdg_tl_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry( + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->base, &geo_box); + if (NULL != width_ptr) *width_ptr = geo_box.width; + if (NULL != height_ptr) *height_ptr = geo_box.height; +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `map` signal. From d9855d4d5ec8613b022fb2488ade8fe5fe5c1b55 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 18:17:47 +0200 Subject: [PATCH 060/390] Adds missing commit from earlier. --- src/toolkit/element.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/toolkit/element.h b/src/toolkit/element.h index c331d98e..20bb763e 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -42,10 +42,6 @@ struct _wlmtk_element_t { int x; /** Y position of the element, relative to the container. */ int y; - /** Width of the element, in pixels. */ - int width; - /** Height of the element, in pixels. */ - int height; /** The container this element belongs to, if any. */ wlmtk_container_t *parent_container_ptr; @@ -74,6 +70,14 @@ struct _wlmtk_element_impl_t { wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); + /** Gets dimensions of the element, relative to the position. */ + void (*get_dimensions)( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); + /** Indicates pointer motion into or within the element area to (x,y). */ wlmtk_element_t *(*motion)(wlmtk_element_t *element_ptr, double x, double y); @@ -177,16 +181,20 @@ void wlmtk_element_set_position( int y); /** - * Returns the size of the element, in pixels. + * Gets the dimensions of the element in pixels, relative to the position. * * @param element_ptr - * @param width_ptr Optional, may be NULL. - * @param height_ptr Optional, may be NULL. + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. */ -void wlmtk_element_get_size( +void wlmtk_element_get_dimensions( wlmtk_element_t *element_ptr, - int *width_ptr, - int *height_ptr); + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); /** Virtual method: Calls 'motion' for the element's implementation. */ static inline wlmtk_element_t *wlmtk_element_motion( @@ -225,6 +233,10 @@ extern const bs_test_case_t wlmtk_element_test_cases[]; typedef struct { /** State of the element. */ wlmtk_element_t element; + /** Width of the element, in pixels. */ + int width; + /** Height of the element, in pixels. */ + int height; /** Indicates that Element::motion() was called. */ bool motion_called; From 48fd868b22b352249fe333f7eacc3aecf41583fb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 13:00:22 -0400 Subject: [PATCH 061/390] Fixes typo in test case name. --- src/toolkit/toolkit_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 482cdbfe..b3018578 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -25,7 +25,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "container", wlmtk_container_test_cases }, { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, - { 1, "winodw", wlmtk_window_test_cases }, + { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } From 1dfc8b78893bcd9fd269e7868d287a666cb2cb4e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 13:03:16 -0400 Subject: [PATCH 062/390] Adds a fake content class and use in tests. --- src/toolkit/content.c | 113 ++++++++++++++++++++++++++++------------ src/toolkit/content.h | 13 +++++ src/toolkit/workspace.c | 40 ++------------ 3 files changed, 99 insertions(+), 67 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 085847e2..4abdaff8 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -151,22 +151,61 @@ void element_get_dimensions( content_ptr->impl_ptr->get_size(content_ptr, right_ptr, bottom_ptr); } -/* == Unit tests =========================================================== */ +/* == Fake content, useful for unit tests. ================================= */ -static void test_init_fini(bs_test_t *test_ptr); +static void fake_content_destroy( + wlmtk_content_t *content_ptr); +static struct wlr_scene_node *fake_content_create_scene_node( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +static void fake_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr); -const bs_test_case_t wlmtk_content_test_cases[] = { - { 1, "init_fini", test_init_fini }, - { 0, NULL, NULL } +/** Method table of the fake content. */ +static const wlmtk_content_impl_t wlmtk_fake_content_impl = { + .destroy = fake_content_destroy, + .create_scene_node = fake_content_create_scene_node, + .get_size = fake_content_get_size }; -/** dtor for the content under test. */ -static void test_destroy_cb(wlmtk_content_t *content_ptr) +/* ------------------------------------------------------------------------- */ +wlmtk_fake_content_t *wlmtk_fake_content_create(void) { - wlmtk_content_fini(content_ptr); + wlmtk_fake_content_t *fake_content_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_content_t)); + if (NULL == fake_content_ptr) return NULL; + + if (!wlmtk_content_init(&fake_content_ptr->content, + &wlmtk_fake_content_impl)) { + free(fake_content_ptr); + return NULL; + } + + BS_ASSERT(NULL != fake_content_ptr->content.super_element.impl_ptr); + BS_ASSERT(NULL != fake_content_ptr->content.impl_ptr); + return fake_content_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** Dtor for the fake content. */ +void fake_content_destroy(wlmtk_content_t *content_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_fake_content_t, content); + + wlmtk_content_fini(&fake_content_ptr->content); + + // Also expect the super element to be un-initialized. + BS_ASSERT(NULL == fake_content_ptr->content.super_element.impl_ptr); + BS_ASSERT(NULL == fake_content_ptr->content.impl_ptr); + free(fake_content_ptr); } -/** Creates a scene node attached to the tree. */ -static struct wlr_scene_node *test_create_scene_node_cb( + +/* ------------------------------------------------------------------------- */ +/** Creates a scene node for the fake content. */ +struct wlr_scene_node *fake_content_create_scene_node( __UNUSED__ wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { @@ -174,46 +213,56 @@ static struct wlr_scene_node *test_create_scene_node_cb( wlr_scene_tree_ptr, NULL); return &wlr_scene_buffer_ptr->node; } -/** returns a fake size. */ -static void test_get_size_cb( - __UNUSED__ wlmtk_content_t *content_ptr, + +/* ------------------------------------------------------------------------- */ +/** Gets the size of the fake content. */ +void fake_content_get_size( + wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr) { - if (NULL != width_ptr) *width_ptr = 42; - if (NULL != height_ptr) *height_ptr = 21; + wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_fake_content_t, content); + if (NULL != width_ptr) *width_ptr = fake_content_ptr->width; + if (NULL != height_ptr) *height_ptr = fake_content_ptr->height; } -/** Method table for the content we're using for test. */ -static const wlmtk_content_impl_t test_content_impl = { - .destroy = test_destroy_cb, - .create_scene_node = test_create_scene_node_cb, - .get_size = test_get_size_cb, +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_content_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 0, NULL, NULL } }; /* ------------------------------------------------------------------------- */ /** Exercises init() and fini() methods, verifies dtor forwarding. */ void test_init_fini(bs_test_t *test_ptr) { - wlmtk_content_t content; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_content_init( - &content, &test_content_impl)); + wlmtk_fake_content_t *fake_content_ptr; + + fake_content_ptr = wlmtk_fake_content_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_content_ptr); + // Also expect the super element to be initialized. - BS_TEST_VERIFY_NEQ(test_ptr, NULL, content.super_element.impl_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, content.impl_ptr); + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + fake_content_ptr->content.super_element.impl_ptr); + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + fake_content_ptr->content.impl_ptr); int l, t, r, b; - wlmtk_element_get_dimensions(&content.super_element, &l, &t, &r, &b); + fake_content_ptr->width = 42; + fake_content_ptr->height = 21; + wlmtk_element_get_dimensions( + &fake_content_ptr->content.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, 0, l); BS_TEST_VERIFY_EQ(test_ptr, 0, t); BS_TEST_VERIFY_EQ(test_ptr, 42, r); BS_TEST_VERIFY_EQ(test_ptr, 21, b); - content.impl_ptr->destroy(&content); - - // Also expect the super element to be un-initialized. - BS_TEST_VERIFY_EQ(test_ptr, NULL, content.super_element.impl_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, content.impl_ptr); - + wlmtk_element_destroy(&fake_content_ptr->content.super_element); } /* == End of content.c ================================================== */ diff --git a/src/toolkit/content.h b/src/toolkit/content.h index a0dd47de..3eafb7fc 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -104,6 +104,19 @@ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); /** Unit tests for content. */ extern const bs_test_case_t wlmtk_content_test_cases[]; +/** Fake content, useful for unit test. */ +typedef struct { + /** State of the content. */ + wlmtk_content_t content; + /** Width to return on a wlmtk_content_impl_t::get_size call. */ + int width; + /** Height to return on a wlmtk_content_impl_t::get_size call. */ + int height; +} wlmtk_fake_content_t; + +/** Ctor for a fake content. */ +wlmtk_fake_content_t *wlmtk_fake_content_create(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index f3a50577..68a56502 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -158,36 +158,6 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } -/** dtor for the content under test. */ -static void test_content_destroy( - wlmtk_content_t *content_ptr) -{ - wlmtk_content_fini(content_ptr); -} -/** scene node creation for the node under test. */ -static struct wlr_scene_node *test_content_create_scene_node( - __UNUSED__ wlmtk_content_t *content_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr) -{ - struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( - wlr_scene_tree_ptr, NULL); - return &wlr_scene_buffer_ptr->node; -} -/** Gets size of the content, fake mode. */ -static void test_content_get_size( - __UNUSED__ wlmtk_content_t *content_ptr, - int *width_ptr, int *height_ptr) -{ - if (NULL != width_ptr) *width_ptr = 42; - if (NULL != height_ptr) *height_ptr = 21; -} -/** Method table for the node under test. */ -static const wlmtk_content_impl_t test_content_impl = { - .destroy = test_content_destroy, - .create_scene_node = test_content_create_scene_node, - .get_size = test_content_get_size -}; - /* ------------------------------------------------------------------------- */ /** Verifies that mapping and unmapping windows works. */ void test_map_unmap(bs_test_t *test_ptr) @@ -199,9 +169,9 @@ void test_map_unmap(bs_test_t *test_ptr) fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); - wlmtk_content_t content; - wlmtk_content_init(&content, &test_content_impl); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content); + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -213,7 +183,7 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, - content.super_element.wlr_scene_node_ptr); + fake_content_ptr->content.super_element.wlr_scene_node_ptr); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); @@ -224,7 +194,7 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, NULL, - content.super_element.wlr_scene_node_ptr); + fake_content_ptr->content.super_element.wlr_scene_node_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_window_destroy(window_ptr); From 59a8f66ec7921dedb426aa4ce232ce2d2f7463e7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 13:16:14 -0400 Subject: [PATCH 063/390] Re-uses bounding box call and moves it into a separate method. --- src/toolkit/container.c | 65 ++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 4289ff62..7063a27c 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -43,6 +43,9 @@ static wlmtk_element_t *element_motion( double x, double y); static void element_leave( wlmtk_element_t *element_ptr); +static void element_get_bounding_box( + wlmtk_element_t *element_ptr, + int *x_from_ptr, int *y_from_ptr, int *x_to_ptr, int *y_to_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -206,19 +209,12 @@ void element_get_dimensions( dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - int x, y; - wlmtk_element_get_position(element_ptr, &x, &y); - - int l, t, r, b; - wlmtk_element_get_dimensions(element_ptr, &l, &t, &r, &b); - l += x; - t += y; - r += x; - b += y; - left = BS_MIN(left, l); - top = BS_MIN(top, t); - right = BS_MAX(right, r); - bottom = BS_MAX(bottom, b); + int x_from, y_from, x_to, y_to; + element_get_bounding_box(element_ptr, &x_from, &y_from, &x_to, &y_to); + left = BS_MIN(left, x_from); + top = BS_MIN(top, y_from); + right = BS_MAX(right, x_to); + bottom = BS_MAX(bottom, y_to); } if (NULL != left_ptr) *left_ptr = left; @@ -251,18 +247,11 @@ wlmtk_element_t *element_motion( dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - // Compute the box occupied by "element_ptr", relative to container. - int x_pos, y_pos; - wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); int x_from, y_from, x_to, y_to; - wlmtk_element_get_dimensions( - element_ptr, &x_from, &y_from, &x_to, &y_to); - x_from += x_pos; - y_from += y_pos; - x_to += x_pos; - y_to += y_pos; - + element_get_bounding_box(element_ptr, &x_from, &y_from, &x_to, &y_to); if (x_from <= x && x < x_to && y_from <= y && y < y_to) { + int x_pos, y_pos; + wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); wlmtk_element_t *motion_element_ptr = wlmtk_element_motion( element_ptr, x - x_pos, y - y_pos); if (NULL == motion_element_ptr) continue; @@ -287,7 +276,7 @@ wlmtk_element_t *element_motion( /* ------------------------------------------------------------------------- */ /** - * Implementation of the element's leave method> Forwards it to the element + * Implementation of the element's leave method: Forwards it to the element * currently having pointer focus, and clears that. * * @param element_ptr @@ -331,6 +320,34 @@ void handle_wlr_scene_tree_node_destroy( wl_list_remove(&container_ptr->wlr_scene_tree_node_destroy_listener.link); } +/* ------------------------------------------------------------------------- */ +/** + * Computes the bounding box position for the element, relative to parent. + * + * The element (or the element's sub-elements) will all be contained in the + * area spanned by [*x_from_ptr, *x_to_ptr), [*y_from_ptr, *y_to_ptr). + * + * @param element_ptr + * @param x_from_ptr Minimum horizontal position (inclusive). + * @param y_from_ptr Minimum vertical position (inclusive). + * @param x_to_ptr Maximum horizontal position (exclusive). + * @param y_to_ptr Maximum vertical position (exclusive). + */ +void element_get_bounding_box( + wlmtk_element_t *element_ptr, + int *x_from_ptr, int *y_from_ptr, int *x_to_ptr, int *y_to_ptr) +{ + int x_pos, y_pos; + wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); + + wlmtk_element_get_dimensions( + element_ptr, x_from_ptr, y_from_ptr, x_to_ptr, y_to_ptr); + if (NULL != x_from_ptr) *x_from_ptr += x_pos; + if (NULL != x_to_ptr) *x_to_ptr += x_pos; + if (NULL != y_from_ptr) *y_from_ptr += y_pos; + if (NULL != y_to_ptr) *y_to_ptr += y_pos; +} + /* == Helper for unit test: A fake container =============================== */ static void fake_destroy(wlmtk_container_t *container_ptr); From 0bf31a9350e5be3665e8adcb32b3afcafbadde82 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 14:47:51 -0400 Subject: [PATCH 064/390] Adds wlmtk_content_get_size() method. --- src/toolkit/content.c | 2 +- src/toolkit/content.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 4abdaff8..0af0cbbf 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -148,7 +148,7 @@ void element_get_dimensions( wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); - content_ptr->impl_ptr->get_size(content_ptr, right_ptr, bottom_ptr); + wlmtk_content_get_size(content_ptr, right_ptr, bottom_ptr); } /* == Fake content, useful for unit tests. ================================= */ diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 3eafb7fc..febf06ef 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -101,6 +101,13 @@ void wlmtk_content_set_window( */ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); +/** Wraps to @ref wlmt_content_t::get_size. */ +static inline void wlmtk_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, int *height_ptr) { + content_ptr->impl_ptr->get_size(content_ptr, width_ptr, height_ptr); +} + /** Unit tests for content. */ extern const bs_test_case_t wlmtk_content_test_cases[]; From d2ff65cf88fa78d1664ffa2ff04f5e03343e860b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 15:04:26 -0400 Subject: [PATCH 065/390] Wires up the motion method with passing it to the seat. --- src/toolkit/container.c | 27 ++++++++++++++----------- src/toolkit/content.c | 44 +++++++++++++++++++++++++++++++++++++++-- src/toolkit/content.h | 15 ++++++++++++-- src/toolkit/element.c | 8 +++++--- src/toolkit/element.h | 8 +++++--- 5 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 7063a27c..c97c5798 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -40,7 +40,8 @@ static void element_get_dimensions( int *bottom_ptr); static wlmtk_element_t *element_motion( wlmtk_element_t *element_ptr, - double x, double y); + double x, double y, + uint32_t time_msec); static void element_leave( wlmtk_element_t *element_ptr); static void element_get_bounding_box( @@ -230,6 +231,7 @@ void element_get_dimensions( * @param element_ptr * @param x * @param y + * @param time_msec * * @return Pointer to the (non-container) element handling the motion, or NULL * if the motion wasn't handled. @@ -237,7 +239,8 @@ void element_get_dimensions( wlmtk_element_t *element_motion( wlmtk_element_t *element_ptr, double x, - double y) + double y, + uint32_t time_msec) { wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); @@ -253,7 +256,7 @@ wlmtk_element_t *element_motion( int x_pos, y_pos; wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); wlmtk_element_t *motion_element_ptr = wlmtk_element_motion( - element_ptr, x - x_pos, y - y_pos); + element_ptr, x - x_pos, y - y_pos, time_msec); if (NULL == motion_element_ptr) continue; if (NULL != container_ptr->pointer_focus_element_ptr) { @@ -549,7 +552,7 @@ void test_motion(bs_test_t *test_ptr) elem2_ptr->motion_return_value = &elem2_ptr->element; wlmtk_container_add_element(&container, &elem2_ptr->element); - wlmtk_element_motion(&container.super_element, 0, 0); + wlmtk_element_motion(&container.super_element, 0, 0, 1234); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); @@ -557,7 +560,7 @@ void test_motion(bs_test_t *test_ptr) elem1_ptr->motion_y = 42; BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, -20, -40)); + wlmtk_element_motion(&container.super_element, -20, -40, 1234)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); elem1_ptr->motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); @@ -566,7 +569,7 @@ void test_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 107, 203)); + wlmtk_element_motion(&container.super_element, 107, 203, 1234)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); elem1_ptr->leave_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); @@ -577,7 +580,7 @@ void test_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 110, 205)); + wlmtk_element_motion(&container.super_element, 110, 205, 1234)); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); @@ -630,7 +633,7 @@ void test_motion_nested(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 205, b); - wlmtk_element_motion(&container.super_element, 0, 0); + wlmtk_element_motion(&container.super_element, 0, 0, 1234); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); @@ -638,7 +641,7 @@ void test_motion_nested(bs_test_t *test_ptr) elem1_ptr->motion_y = 42; BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, -20, -40)); + wlmtk_element_motion(&container.super_element, -20, -40, 1234)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); elem1_ptr->motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); @@ -647,7 +650,7 @@ void test_motion_nested(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&parent_container.super_element, -20, -40)); + wlmtk_element_motion(&parent_container.super_element, -20, -40, 1234)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); elem1_ptr->motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); @@ -657,7 +660,7 @@ void test_motion_nested(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 107, 203)); + wlmtk_element_motion(&container.super_element, 107, 203, 1234)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); elem1_ptr->leave_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); @@ -668,7 +671,7 @@ void test_motion_nested(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 110, 205)); + wlmtk_element_motion(&container.super_element, 110, 205, 1234)); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 0af0cbbf..02d57834 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -23,6 +23,7 @@ #define WLR_USE_UNSTABLE #include +#include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -50,7 +51,8 @@ const wlmtk_element_impl_t super_element_impl = { /* ------------------------------------------------------------------------- */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - const wlmtk_content_impl_t *content_impl_ptr) + const wlmtk_content_impl_t *content_impl_ptr, + struct wlr_seat *wlr_seat_ptr) { BS_ASSERT(NULL != content_ptr); BS_ASSERT(NULL != content_impl_ptr); @@ -65,6 +67,8 @@ bool wlmtk_content_init( return false; } + content_ptr->wlr_seat_ptr = wlr_seat_ptr; + content_ptr->impl_ptr = content_impl_ptr; return true; } @@ -151,6 +155,41 @@ void element_get_dimensions( wlmtk_content_get_size(content_ptr, right_ptr, bottom_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's motion method: Sets the surface as active + * and -- if (x, y) is within the area -- returns this element's pointer. + * + * @param element_ptr + * @param x + * @param y + * @param time_msec + * + * @return element_ptr + */ +wlmtk_element_t *element_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + __UNUSED__ uint32_t time_msec) +{ + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + + // Guard clause: only forward if the motion is inside the content. + int width, height; + wlmtk_content_get_size(content_ptr, &width, &height); + if (x < 0 || width <= x || y < 0 || height <= y) return NULL; + + if (NULL != content_ptr->wlr_surface_ptr) { + wlr_seat_pointer_notify_enter( + content_ptr->wlr_seat_ptr, + content_ptr->wlr_surface_ptr, + x, y); + } + return element_ptr; +} + /* == Fake content, useful for unit tests. ================================= */ static void fake_content_destroy( @@ -178,7 +217,8 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) if (NULL == fake_content_ptr) return NULL; if (!wlmtk_content_init(&fake_content_ptr->content, - &wlmtk_fake_content_impl)) { + &wlmtk_fake_content_impl, + NULL)) { free(fake_content_ptr); return NULL; } diff --git a/src/toolkit/content.h b/src/toolkit/content.h index febf06ef..0a4bd5fc 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -45,6 +45,16 @@ struct _wlmtk_content_t { * the window. */ wlmtk_window_t *window_ptr; + + /** Back-link to the the associated seat. */ + struct wlr_seat *wlr_seat_ptr; + /** + * Surface associated with this content. + * + * TODO(kaeser@gubbe.ch): If we extend 'content' to support different + * elements (eg. buffer), this should be abstracted away. + */ + struct wlr_surface *wlr_surface_ptr; }; /** Method table of the content. */ @@ -65,13 +75,14 @@ struct _wlmtk_content_impl_t { * * @param content_ptr * @param content_impl_ptr + * @param wlr_seat_ptr * * @return true on success. */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - const wlmtk_content_impl_t *content_impl_ptr); - + const wlmtk_content_impl_t *content_impl_ptr, + struct wlr_seat *wlr_seat_ptr); /** * Cleans up the content. * diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 8ba9a731..43ea5e1a 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -214,7 +214,8 @@ static void fake_get_dimensions( int *bottom_ptr); static wlmtk_element_t *fake_motion( wlmtk_element_t *element_ptr, - double x, double y); + double x, double y, + uint32_t time_msec); static void fake_leave( wlmtk_element_t *element_ptr); @@ -285,7 +286,8 @@ void fake_get_dimensions( wlmtk_element_t *fake_motion( wlmtk_element_t *element_ptr, double x, - double y) + double y, + __UNUSED__ uint32_t time_msec) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); @@ -453,7 +455,7 @@ void test_motion_leave(bs_test_t *test_ptr) wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); BS_ASSERT(NULL != fake_element_ptr); - wlmtk_element_motion(&fake_element_ptr->element, 1.0, 2.0); + wlmtk_element_motion(&fake_element_ptr->element, 1.0, 2.0, 1234); BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->motion_called); BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->motion_x); BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->motion_y); diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 20bb763e..f336e792 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -80,7 +80,8 @@ struct _wlmtk_element_impl_t { /** Indicates pointer motion into or within the element area to (x,y). */ wlmtk_element_t *(*motion)(wlmtk_element_t *element_ptr, - double x, double y); + double x, double y, + uint32_t time_msec); /** Indicates the pointer has left the element's area. */ void (*leave)(wlmtk_element_t *element_ptr); }; @@ -200,9 +201,10 @@ void wlmtk_element_get_dimensions( static inline wlmtk_element_t *wlmtk_element_motion( wlmtk_element_t *element_ptr, double x, - double y) { + double y, + uint32_t time_msec) { if (NULL == element_ptr->impl_ptr->motion) return NULL; - return element_ptr->impl_ptr->motion(element_ptr, x, y); + return element_ptr->impl_ptr->motion(element_ptr, x, y, time_msec); } /** Virtual method: Calls 'leave' for the element's implementation. */ From d00ab9c30f4ebdba499d64849f4ea863c4a2163e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Sep 2023 15:31:59 -0400 Subject: [PATCH 066/390] Adds missing file. --- src/xdg_toplevel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index 7ed32ae2..6bd637ee 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -354,7 +354,8 @@ wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( if (NULL == xdg_tl_content_ptr) return NULL; if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, - &content_impl)) { + &content_impl, + server_ptr->wlr_seat_ptr)) { wlmtk_xdg_toplevel_content_destroy(xdg_tl_content_ptr); return NULL; } From f5f9870c994c9398f03158d8a651d5d04f11d8fb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 16:20:26 -0400 Subject: [PATCH 067/390] Adds boilerplate for XDG toplevel toolkit window. --- src/toolkit/xdg_toplevel.c | 29 +++++++++++++++++++++++ src/toolkit/xdg_toplevel.h | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/toolkit/xdg_toplevel.c create mode 100644 src/toolkit/xdg_toplevel.h diff --git a/src/toolkit/xdg_toplevel.c b/src/toolkit/xdg_toplevel.c new file mode 100644 index 00000000..9d9ec965 --- /dev/null +++ b/src/toolkit/xdg_toplevel.c @@ -0,0 +1,29 @@ +/* ========================================================================= */ +/** + * @file xdg_toplevel.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "xdg_toplevel.h" + +/* == Declarations ========================================================= */ + +/* == Exported methods ===================================================== */ + +/* == Local (static) methods =============================================== */ + +/* == End of xdg_toplevel.c ================================================ */ diff --git a/src/toolkit/xdg_toplevel.h b/src/toolkit/xdg_toplevel.h new file mode 100644 index 00000000..11e72c37 --- /dev/null +++ b/src/toolkit/xdg_toplevel.h @@ -0,0 +1,47 @@ +/* ========================================================================= */ +/** + * @file xdg_toplevel.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_XDG_TOPLEVEL_H__ +#define __WLMTK_XDG_TOPLEVEL_H__ + +#include "window.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Forward declaration. */ +struct wlr_xdg_surface; + +/** + * Creates a toolkit window with the XDG surface as content. + * + * @param wlr_xdg_surface_ptr + * + * @return The window, or NULL on error. + */ +wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( + struct wlr_xdg_surface *wlr_xdg_surface_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_XDG_TOPLEVEL_H__ */ +/* == End of xdg_toplevel.h ================================================ */ From 0c06ec4badde72e6a2b55ac88e64c35fa40f5f34 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 16:20:33 -0400 Subject: [PATCH 068/390] Adds boilerplate for XDG toplevel toolkit window. --- src/toolkit/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 29299073..bbc369a1 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -25,7 +25,8 @@ SET(PUBLIC_HEADER_FILES content.h element.h window.h - workspace.h) + workspace.h + xdg_toplevel.h) ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE @@ -36,7 +37,8 @@ TARGET_SOURCES(toolkit PRIVATE primitives.c util.c window.c - workspace.c) + workspace.c + xdg_toplevel.c) TARGET_INCLUDE_DIRECTORIES( toolkit PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. From 880105cbae3fc49a8776dcebcf59eb81536067aa Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 16:53:03 -0400 Subject: [PATCH 069/390] Moves wlmtk_xdg_toplevel to src/ due to dependency management. --- src/CMakeLists.txt | 2 + src/toolkit/CMakeLists.txt | 6 +- src/toolkit/content.h | 7 +- src/toolkit/xdg_toplevel.c | 29 --- src/wlmtk_xdg_toplevel.c | 244 ++++++++++++++++++ .../xdg_toplevel.h => wlmtk_xdg_toplevel.h} | 9 +- src/xdg_shell.c | 9 + src/xdg_toplevel.c | 213 --------------- src/xdg_toplevel.h | 24 -- 9 files changed, 267 insertions(+), 276 deletions(-) delete mode 100644 src/toolkit/xdg_toplevel.c create mode 100644 src/wlmtk_xdg_toplevel.c rename src/{toolkit/xdg_toplevel.h => wlmtk_xdg_toplevel.h} (90%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 58296c76..5aa0a083 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,7 @@ SET(SOURCES tile_container.c titlebar.c view.c + wlmtk_xdg_toplevel.c workspace.c xdg_decoration.c xdg_popup.c @@ -73,6 +74,7 @@ SET(HEADERS tile.h titlebar.h view.h + wlmtk_xdg_toplevel.h workspace.h xdg_decoration.h xdg_popup.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index bbc369a1..29299073 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -25,8 +25,7 @@ SET(PUBLIC_HEADER_FILES content.h element.h window.h - workspace.h - xdg_toplevel.h) + workspace.h) ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE @@ -37,8 +36,7 @@ TARGET_SOURCES(toolkit PRIVATE primitives.c util.c window.c - workspace.c - xdg_toplevel.c) + workspace.c) TARGET_INCLUDE_DIRECTORIES( toolkit PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 0a4bd5fc..56535f27 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -112,13 +112,18 @@ void wlmtk_content_set_window( */ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); -/** Wraps to @ref wlmt_content_t::get_size. */ +/** Wraps to @ref wlmtk_content_impl_t::get_size. */ static inline void wlmtk_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr) { content_ptr->impl_ptr->get_size(content_ptr, width_ptr, height_ptr); } +/** Wraps to @ref wlmtk_content_impl_t::destroy. */ +static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { + content_ptr->impl_ptr->destroy(content_ptr); +} + /** Unit tests for content. */ extern const bs_test_case_t wlmtk_content_test_cases[]; diff --git a/src/toolkit/xdg_toplevel.c b/src/toolkit/xdg_toplevel.c deleted file mode 100644 index 9d9ec965..00000000 --- a/src/toolkit/xdg_toplevel.c +++ /dev/null @@ -1,29 +0,0 @@ -/* ========================================================================= */ -/** - * @file xdg_toplevel.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "xdg_toplevel.h" - -/* == Declarations ========================================================= */ - -/* == Exported methods ===================================================== */ - -/* == Local (static) methods =============================================== */ - -/* == End of xdg_toplevel.c ================================================ */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c new file mode 100644 index 00000000..d543cb41 --- /dev/null +++ b/src/wlmtk_xdg_toplevel.c @@ -0,0 +1,244 @@ +/* ========================================================================= */ +/** + * @file xdg_toplevel.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "xdg_toplevel.h" + +/* == Declarations ========================================================= */ + +/** State of the content for an XDG toplevel surface. */ +typedef struct { + /** Super class. */ + wlmtk_content_t super_content; + + /** Back-link to server. */ + wlmaker_server_t *server_ptr; + + /** The corresponding wlroots XDG surface. */ + struct wlr_xdg_surface *wlr_xdg_surface_ptr; + + /** Listener for the `map` signal of the `wlr_surface`. */ + struct wl_listener surface_map_listener; + /** Listener for the `unmap` signal of the `wlr_surface`. */ + struct wl_listener surface_unmap_listener; +} wlmtk_xdg_toplevel_content_t; + +static wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( + struct wlr_xdg_surface *wlr_xdg_surface_ptr, + wlmaker_server_t *server_ptr); +static void xdg_toplevel_content_destroy( + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr); + + +static void handle_surface_map( + struct wl_listener *listener_ptr, + void *data_ptr); +static void handle_surface_unmap( + struct wl_listener *listener_ptr, + void *data_ptr); + +static void content_destroy(wlmtk_content_t *content_ptr); +static struct wlr_scene_node *content_create_scene_node( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +static void content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr); + +/* == Data ================================================================= */ + +/** Method table for the `wlmtk_content_t` virtual methods. */ +const wlmtk_content_impl_t content_impl = { + .destroy = content_destroy, + .create_scene_node = content_create_scene_node, + .get_size = content_get_size, +}; + + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( + struct wlr_xdg_surface *wlr_xdg_surface_ptr, + wlmaker_server_t *server_ptr) +{ + wlmtk_xdg_toplevel_content_t *content_ptr = xdg_toplevel_content_create( + wlr_xdg_surface_ptr, server_ptr); + if (NULL == content_ptr) return NULL; + + wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( + &content_ptr->super_content); + if (NULL == wlmtk_window_ptr) { + wlmtk_content_destroy(&content_ptr->super_content); + return NULL; + } + + return wlmtk_window_ptr; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( + struct wlr_xdg_surface *wlr_xdg_surface_ptr, + wlmaker_server_t *server_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = logged_calloc( + 1, sizeof(wlmtk_xdg_toplevel_content_t)); + if (NULL == xdg_tl_content_ptr) return NULL; + + if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, + &content_impl, + server_ptr->wlr_seat_ptr)) { + xdg_toplevel_content_destroy(xdg_tl_content_ptr); + return NULL; + } + xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; + xdg_tl_content_ptr->server_ptr = server_ptr; + + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->surface->events.map, + &xdg_tl_content_ptr->surface_map_listener, + handle_surface_map); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->surface->events.unmap, + &xdg_tl_content_ptr->surface_unmap_listener, + handle_surface_unmap); + + return xdg_tl_content_ptr; +} + +/* ------------------------------------------------------------------------- */ +void xdg_toplevel_content_destroy( + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) +{ + wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); + wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); + + wlmtk_content_fini(&xdg_tl_content_ptr->super_content); + free(xdg_tl_content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Destructor. Wraps to @ref wlmtk_xdg_toplevel_content_destroy. + * + * @param content_ptr + */ +void content_destroy(wlmtk_content_t *content_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + xdg_toplevel_content_destroy(xdg_tl_content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Creates the wlroots scene graph API node, attached to `wlr_scene_tree_ptr`. + * + * @param content_ptr + * @param wlr_scene_tree_ptr + * + * @return Scene graph API node that represents the content. + */ +struct wlr_scene_node *content_create_scene_node( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + struct wlr_scene_tree *surface_wlr_scene_tree_ptr = + wlr_scene_xdg_surface_create( + wlr_scene_tree_ptr, + xdg_tl_content_ptr->wlr_xdg_surface_ptr); + return &surface_wlr_scene_tree_ptr->node; +} + +/* ------------------------------------------------------------------------- */ +/** + * Gets the dimensions of the element in pixels, relative to the position. + * + * @param content_ptr + * @param width_ptr Width of content. May be NULL. + * @param height_ptr Height of content. May be NULL. + */ +void content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry( + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->base, &geo_box); + if (NULL != width_ptr) *width_ptr = geo_box.width; + if (NULL != height_ptr) *height_ptr = geo_box.height; +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `map` signal. + * + * Issued when the XDG toplevel is fully configured and ready to be shown. + * Will add it to the current workspace. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_surface_map( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, surface_map_listener); + + wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( + wlmaker_server_get_current_workspace(xdg_tl_content_ptr->server_ptr)); + + wlmtk_workspace_map_window( + wlmtk_workspace_ptr, + xdg_tl_content_ptr->super_content.window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `unmap` signal. Removes it from the workspace. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_surface_unmap( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, surface_unmap_listener); + + wlmtk_window_t *window_ptr = xdg_tl_content_ptr->super_content.window_ptr; + wlmtk_workspace_unmap_window( + wlmtk_workspace_from_container( + wlmtk_window_element(window_ptr)->parent_container_ptr), + window_ptr); +} + +/* == End of xdg_toplevel.c ================================================ */ diff --git a/src/toolkit/xdg_toplevel.h b/src/wlmtk_xdg_toplevel.h similarity index 90% rename from src/toolkit/xdg_toplevel.h rename to src/wlmtk_xdg_toplevel.h index 11e72c37..c4cae753 100644 --- a/src/toolkit/xdg_toplevel.h +++ b/src/wlmtk_xdg_toplevel.h @@ -20,15 +20,13 @@ #ifndef __WLMTK_XDG_TOPLEVEL_H__ #define __WLMTK_XDG_TOPLEVEL_H__ -#include "window.h" +#include "server.h" +#include "toolkit/toolkit.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus -/** Forward declaration. */ -struct wlr_xdg_surface; - /** * Creates a toolkit window with the XDG surface as content. * @@ -37,7 +35,8 @@ struct wlr_xdg_surface; * @return The window, or NULL on error. */ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( - struct wlr_xdg_surface *wlr_xdg_surface_ptr); + struct wlr_xdg_surface *wlr_xdg_surface_ptr, + wlmaker_server_t *server_ptr); #ifdef __cplusplus } // extern "C" diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 54fdc6c7..03c8d724 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -22,6 +22,7 @@ #include "toolkit/toolkit.h" #include "view.h" +#include "wlmtk_xdg_toplevel.h" #include "xdg_toplevel.h" #include @@ -115,6 +116,14 @@ void handle_new_surface(struct wl_listener *listener_ptr, break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + +#if defined(ENABLE_TOOLKIT_PROTOTYPE) + // Transitional -- enable for prototyping: Toolkit-based workspace. + wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( + wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); + window_ptr = window_ptr; +#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) + xdg_toplevel_ptr = wlmaker_xdg_toplevel_create( xdg_shell_ptr, wlr_xdg_surface_ptr); bs_log(BS_INFO, "XDG shell: Surface %p created toplevel view %p", diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index 6bd637ee..aefe5ac4 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -77,9 +77,6 @@ struct _wlmaker_xdg_toplevel_t { struct wl_listener toplevel_set_title_listener; /** Listener for the `set_app_id` signal of the `wlr_xdg_toplevel`. */ struct wl_listener toplevel_set_app_id_listener; - - /** Transitional: Content. */ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr; }; static wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_from_view( @@ -152,32 +149,6 @@ static void wlmaker_xdg_toplevel_set_fullscreen( bool fullscreen); -/* ######################################################################### */ - -/** State of the content for an XDG toplevel surface. */ -struct _wlmtk_xdg_toplevel_content_t { - /** Super class. */ - wlmtk_content_t super_content; - - /** Back-link to server. */ - wlmaker_server_t *server_ptr; - - /** The corresponding wlroots XDG surface. */ - struct wlr_xdg_surface *wlr_xdg_surface_ptr; - - /** Listener for the `map` signal of the `wlr_surface`. */ - struct wl_listener surface_map_listener; - /** Listener for the `unmap` signal of the `wlr_surface`. */ - struct wl_listener surface_unmap_listener; -}; - -static void handle_surface_map( - struct wl_listener *listener_ptr, - void *data_ptr); -static void handle_surface_unmap( - struct wl_listener *listener_ptr, - void *data_ptr); - /* == Data ================================================================= */ /** View implementor methods. */ @@ -189,24 +160,6 @@ const wlmaker_view_impl_t xdg_toplevel_view_impl = { .set_fullscreen = wlmaker_xdg_toplevel_set_fullscreen }; -/* ######################################################################### */ - -static void xdg_tl_content_destroy(wlmtk_content_t *content_ptr); -static struct wlr_scene_node *xdg_tl_content_create_scene_node( - wlmtk_content_t *content_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); -static void xdg_tl_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, - int *height_ptr); - -/** Method table for the `wlmtk_content_t` virtual methods. */ -const wlmtk_content_impl_t content_impl = { - .destroy = xdg_tl_content_destroy, - .create_scene_node = xdg_tl_content_create_scene_node, - .get_size = xdg_tl_content_get_size, -}; - /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -288,13 +241,6 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( return NULL; } -#if defined(ENABLE_TOOLKIT_PROTOTYPE) - // Transitional -- enable for prototyping: Toolkit-based workspace. - xdg_toplevel_ptr->xdg_tl_content_ptr = - wlmtk_xdg_toplevel_content_create( - wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); -#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) - wlmaker_view_init( &xdg_toplevel_ptr->view, &xdg_toplevel_view_impl, @@ -306,9 +252,6 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( xdg_toplevel_ptr->wlr_scene_tree_ptr; wlmaker_view_set_position(&xdg_toplevel_ptr->view, 32, 40); - - - return xdg_toplevel_ptr; } @@ -317,11 +260,6 @@ void wlmaker_xdg_toplevel_destroy(wlmaker_xdg_toplevel_t *xdg_toplevel_ptr) { wlmaker_view_fini(&xdg_toplevel_ptr->view); - if (NULL != xdg_toplevel_ptr->xdg_tl_content_ptr) { - wlmtk_xdg_toplevel_content_destroy(xdg_toplevel_ptr->xdg_tl_content_ptr); - xdg_toplevel_ptr->xdg_tl_content_ptr = NULL; - } - wlmaker_xdg_toplevel_t *tl_ptr = xdg_toplevel_ptr; // For shorter lines. wl_list_remove(&tl_ptr->destroy_listener.link); wl_list_remove(&tl_ptr->surface_map_listener.link); @@ -342,49 +280,6 @@ void wlmaker_xdg_toplevel_destroy(wlmaker_xdg_toplevel_t *xdg_toplevel_ptr) free(xdg_toplevel_ptr); } -/* ######################################################################### */ - -/* ------------------------------------------------------------------------- */ -wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( - struct wlr_xdg_surface *wlr_xdg_surface_ptr, - wlmaker_server_t *server_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = logged_calloc( - 1, sizeof(wlmtk_xdg_toplevel_content_t)); - if (NULL == xdg_tl_content_ptr) return NULL; - - if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, - &content_impl, - server_ptr->wlr_seat_ptr)) { - wlmtk_xdg_toplevel_content_destroy(xdg_tl_content_ptr); - return NULL; - } - xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; - xdg_tl_content_ptr->server_ptr = server_ptr; - - wlmtk_util_connect_listener_signal( - &wlr_xdg_surface_ptr->surface->events.map, - &xdg_tl_content_ptr->surface_map_listener, - handle_surface_map); - wlmtk_util_connect_listener_signal( - &wlr_xdg_surface_ptr->surface->events.unmap, - &xdg_tl_content_ptr->surface_unmap_listener, - handle_surface_unmap); - - return xdg_tl_content_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_xdg_toplevel_content_destroy( - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) -{ - wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); - wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); - - wlmtk_content_fini(&xdg_tl_content_ptr->super_content); - free(xdg_tl_content_ptr); -} - /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -793,112 +688,4 @@ void handle_toplevel_set_app_id(struct wl_listener *listener_ptr, /* ######################################################################### */ -/* ------------------------------------------------------------------------- */ -/** - * Destructor. Wraps to @ref wlmtk_xdg_toplevel_content_destroy. - * - * @param content_ptr - */ -void xdg_tl_content_destroy(wlmtk_content_t *content_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); - wlmtk_xdg_toplevel_content_destroy(xdg_tl_content_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Creates the wlroots scene graph API node, attached to `wlr_scene_tree_ptr`. - * - * @param content_ptr - * @param wlr_scene_tree_ptr - * - * @return Scene graph API node that represents the content. - */ -struct wlr_scene_node *xdg_tl_content_create_scene_node( - wlmtk_content_t *content_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); - - struct wlr_scene_tree *surface_wlr_scene_tree_ptr = - wlr_scene_xdg_surface_create( - wlr_scene_tree_ptr, - xdg_tl_content_ptr->wlr_xdg_surface_ptr); - return &surface_wlr_scene_tree_ptr->node; -} - -/* ------------------------------------------------------------------------- */ -/** - * Gets the dimensions of the element in pixels, relative to the position. - * - * @param content_ptr - * @param width_ptr Width of content. May be NULL. - * @param height_ptr Height of content. May be NULL. - */ -void xdg_tl_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, - int *height_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); - - struct wlr_box geo_box; - wlr_xdg_surface_get_geometry( - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->base, &geo_box); - if (NULL != width_ptr) *width_ptr = geo_box.width; - if (NULL != height_ptr) *height_ptr = geo_box.height; -} - -/* ------------------------------------------------------------------------- */ -/** - * Handler for the `map` signal. - * - * Issued when the XDG toplevel is fully configured and ready to be shown. - * Will add it to the current workspace. - * - * @param listener_ptr - * @param data_ptr - */ -void handle_surface_map( - struct wl_listener *listener_ptr, - __UNUSED__ void *data_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, surface_map_listener); - - wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( - wlmaker_server_get_current_workspace(xdg_tl_content_ptr->server_ptr)); - - wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( - &xdg_tl_content_ptr->super_content); - - wlmtk_workspace_map_window(wlmtk_workspace_ptr, wlmtk_window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Handler for the `unmap` signal. Removes it from the workspace. - * - * @param listener_ptr - * @param data_ptr - */ -void handle_surface_unmap( - struct wl_listener *listener_ptr, - __UNUSED__ void *data_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, surface_unmap_listener); - - wlmtk_window_t *window_ptr = xdg_tl_content_ptr->super_content.window_ptr; - wlmtk_workspace_unmap_window( - wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr), - window_ptr); - - wlmtk_window_destroy(window_ptr); -} - /* == End of xdg_toplevel.c ================================================ */ diff --git a/src/xdg_toplevel.h b/src/xdg_toplevel.h index aa061095..98bce69d 100644 --- a/src/xdg_toplevel.h +++ b/src/xdg_toplevel.h @@ -49,30 +49,6 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( */ void wlmaker_xdg_toplevel_destroy(wlmaker_xdg_toplevel_t *xdg_toplevel_ptr); -/** Content for XDG toplvel. */ -typedef struct _wlmtk_xdg_toplevel_content_t wlmtk_xdg_toplevel_content_t; - -/** - * Creates a `wlmtk_content` for the given XDG surface. - * - * @param wlr_xdg_surface_ptr - * @param server_ptr - * - * @return Pointer to the content. - */ -wlmtk_xdg_toplevel_content_t *wlmtk_xdg_toplevel_content_create( - struct wlr_xdg_surface *wlr_xdg_surface_ptr, - wlmaker_server_t *server_ptr); - -/** - * Destroys the toplevel content. - * - * @param xdg_tl_content_ptr - */ -void wlmtk_xdg_toplevel_content_destroy( - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr); - - #ifdef __cplusplus } // extern "C" #endif // __cplusplus From de65cfbd78f3fac04c331b3c6da52f7b3a11360b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 17:27:39 -0400 Subject: [PATCH 070/390] Make 'foot' be a toolkit window. --- src/xdg_decoration.c | 4 ++++ src/xdg_shell.c | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index afa01cce..cfb7bc91 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -219,6 +219,10 @@ void handle_decoration_request_mode( listener_ptr, decoration_ptr, request_mode_listener); struct wlr_scene_tree *wlr_scene_tree_ptr = (struct wlr_scene_tree*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->surface->data; + if (NULL == wlr_scene_tree_ptr) { + bs_log(BS_ERROR, "No tree associated with surface. Toolkit window?"); + return; + } wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; enum wlr_xdg_toplevel_decoration_v1_mode mode = diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 03c8d724..2bc5dd1a 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -26,6 +26,7 @@ #include "xdg_toplevel.h" #include +#include /* == Declarations ========================================================= */ @@ -118,10 +119,21 @@ void handle_new_surface(struct wl_listener *listener_ptr, case WLR_XDG_SURFACE_ROLE_TOPLEVEL: #if defined(ENABLE_TOOLKIT_PROTOTYPE) - // Transitional -- enable for prototyping: Toolkit-based workspace. - wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( - wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); - window_ptr = window_ptr; + pid_t pid; + wl_client_get_credentials( + wlr_xdg_surface_ptr->resource->client, &pid, NULL, NULL); + + char path_procps[PATH_MAX], path_exe[PATH_MAX]; + snprintf(path_procps, sizeof(path_procps), "/proc/%"PRIdMAX"/exe", + (intmax_t)pid); + readlink(path_procps, path_exe, sizeof(path_exe)); + if (0 == strcmp(path_exe, "/usr/bin/foot")) { + wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( + wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); + bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", + window_ptr, wlr_xdg_surface_ptr); + break; + } #endif // defined(ENABLE_TOOLKIT_PROTOTYPE) xdg_toplevel_ptr = wlmaker_xdg_toplevel_create( From 43e9b96649dd27cd91ebbc2e8f040816618f5518 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 17:54:47 -0400 Subject: [PATCH 071/390] Adds set_active methods for window and content. --- src/toolkit/content.c | 21 ++++++++++++++++++++- src/toolkit/content.h | 18 ++++++++++++++---- src/toolkit/toolkit.md | 4 ++++ src/toolkit/window.c | 8 ++++++++ src/toolkit/window.h | 13 +++++++++++++ 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 02d57834..07785dc8 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -59,6 +59,7 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); BS_ASSERT(NULL != content_impl_ptr->get_size); + BS_ASSERT(NULL != content_impl_ptr->set_active); memset(content_ptr, 0, sizeof(wlmtk_content_t)); @@ -201,12 +202,16 @@ static void fake_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); +static void fake_content_set_active( + wlmtk_content_t *content_ptr, + bool active); /** Method table of the fake content. */ static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, .create_scene_node = fake_content_create_scene_node, - .get_size = fake_content_get_size + .get_size = fake_content_get_size, + .set_active = fake_content_set_active, }; /* ------------------------------------------------------------------------- */ @@ -266,6 +271,17 @@ void fake_content_get_size( if (NULL != height_ptr) *height_ptr = fake_content_ptr->height; } +/* ------------------------------------------------------------------------- */ +/** Sets the content's activation status. */ +void fake_content_set_active( + wlmtk_content_t *content_ptr, + bool active) +{ + wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_fake_content_t, content); + fake_content_ptr->active = active; +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); @@ -302,6 +318,9 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 42, r); BS_TEST_VERIFY_EQ(test_ptr, 21, b); + wlmtk_content_set_active(&fake_content_ptr->content, true); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->active); + wlmtk_element_destroy(&fake_content_ptr->content.super_element); } diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 56535f27..f22bf17e 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -68,6 +68,8 @@ struct _wlmtk_content_impl_t { /** Gets width and height of the content. */ void (*get_size)(wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); + /** Sets the content as active (or not). */ + void (*set_active)(wlmtk_content_t *content_ptr, bool active); }; /** @@ -112,18 +114,24 @@ void wlmtk_content_set_window( */ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); +/** Wraps to @ref wlmtk_content_impl_t::destroy. */ +static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { + content_ptr->impl_ptr->destroy(content_ptr); +} /** Wraps to @ref wlmtk_content_impl_t::get_size. */ static inline void wlmtk_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr) { content_ptr->impl_ptr->get_size(content_ptr, width_ptr, height_ptr); } - -/** Wraps to @ref wlmtk_content_impl_t::destroy. */ -static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { - content_ptr->impl_ptr->destroy(content_ptr); +/** Wraps to @ref wlmtk_content_impl_t::set_active. */ +static inline void wlmtk_content_set_active( + wlmtk_content_t *content_ptr, + bool active) { + content_ptr->impl_ptr->set_active(content_ptr, active); } + /** Unit tests for content. */ extern const bs_test_case_t wlmtk_content_test_cases[]; @@ -135,6 +143,8 @@ typedef struct { int width; /** Height to return on a wlmtk_content_impl_t::get_size call. */ int height; + /** Argument of last @ref wlmtk_content_set_active call. */ + bool active; } wlmtk_fake_content_t; /** Ctor for a fake content. */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index fd79c747..84dd0d2b 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -86,6 +86,8 @@ class Workspace { map_window(Window*) unmap_window(Window*) + activate_window(Window*) + map_layer_element(LayerElement *, layer) unmap_layer_element(LayerElement *, layer) } @@ -161,6 +163,8 @@ class Window { Window *create(Content*) destroy() Element *element() + + set_active(bool) } VBox *-- Window diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 6a5982a3..a8605e9e 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -84,6 +84,14 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) return &window_ptr->super_container.super_element; } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_active( + wlmtk_window_t *window_ptr, + bool active) +{ + wlmtk_content_set_active(window_ptr->content_ptr, active); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index a8f16dac..e0a8ce3a 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -60,6 +60,19 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); */ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); +/** + * Sets the window as activated, depending on the argument's value. + * + * An activated window will have keyboard focus and would have distinct + * decorations to indicate state. + * + * @param window_ptr + * @param active + */ +void wlmtk_window_set_active( + wlmtk_window_t *window_ptr, + bool active); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; From 56c4f21529eff5be5ac044ce7921de4062a09ecc Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 17:59:27 -0400 Subject: [PATCH 072/390] Updates window to take ownership of content. --- src/toolkit/window.c | 17 +++++++++++------ src/toolkit/window.h | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a8605e9e..9eb2251e 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -72,7 +72,11 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) wlmtk_element_set_visible( wlmtk_content_element(window_ptr->content_ptr), false); wlmtk_content_set_window(window_ptr->content_ptr, NULL); - window_ptr->content_ptr = NULL; + + if (NULL != window_ptr->content_ptr) { + wlmtk_content_destroy(window_ptr->content_ptr); + window_ptr->content_ptr = NULL; + } wlmtk_container_fini(&window_ptr->super_container); free(window_ptr); @@ -116,12 +120,13 @@ const bs_test_case_t wlmtk_window_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_content_t content; - memset(&content, 0, sizeof(content)); - - wlmtk_window_t *window_ptr = wlmtk_window_create(&content); + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, window_ptr, content.window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, window_ptr, + fake_content_ptr->content.window_ptr); + wlmtk_window_destroy(window_ptr); } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index e0a8ce3a..52827c2c 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -33,7 +33,7 @@ extern "C" { /** * Creates a window for the given content. * - * @param content_ptr + * @param content_ptr Will take ownership of content_ptr. * * @return Pointer to the window state, or NULL on error. Must be free'd * by calling @ref wlmtk_window_destroy. From 0cd4fe3753ef6e96e1896a15d05e4fcfcfb64e87 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 18:00:35 -0400 Subject: [PATCH 073/390] Adds a test for wlmtk_window_set_active(). --- src/toolkit/window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 9eb2251e..2512f479 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -127,6 +127,9 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, window_ptr, fake_content_ptr->content.window_ptr); + wlmtk_window_set_active(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->active); + wlmtk_window_destroy(window_ptr); } From 33b146255d358cbb33879096c47a96db97e6d4f9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 18:02:52 -0400 Subject: [PATCH 074/390] Factors out the set_active test in window. --- src/toolkit/window.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 2512f479..708bd00f 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -110,9 +110,11 @@ void window_container_destroy(wlmtk_container_t *container_ptr) /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_set_active(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "set_active", test_set_active }, { 0, NULL, NULL } }; @@ -127,10 +129,25 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, window_ptr, fake_content_ptr->content.window_ptr); + wlmtk_window_destroy(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests activation. */ +void test_set_active(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + &fake_content_ptr->content); + wlmtk_window_set_active(window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->active); + wlmtk_window_set_active(window_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->active); + wlmtk_window_destroy(window_ptr); } + /* == End of window.c ====================================================== */ From 2c1250086223a219e92997f6d5db2992f74226f1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 18:15:04 -0400 Subject: [PATCH 075/390] Wires up activation for XDG toplevel, and when mapped. --- src/toolkit/workspace.c | 3 +++ src/wlmtk_xdg_toplevel.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 68a56502..14ee9182 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -94,6 +94,9 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_container_add_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); + + // TODO(kaeser@gubbe.ch): Refine and test this. + wlmtk_window_set_active(window_ptr, true); } /* ------------------------------------------------------------------------- */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index d543cb41..f1c85a42 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -61,6 +61,9 @@ static void content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); +static void content_set_active( + wlmtk_content_t *content_ptr, + bool active); /* == Data ================================================================= */ @@ -69,6 +72,7 @@ const wlmtk_content_impl_t content_impl = { .destroy = content_destroy, .create_scene_node = content_create_scene_node, .get_size = content_get_size, + .set_active = content_set_active, }; @@ -195,6 +199,37 @@ void content_get_size( if (NULL != height_ptr) *height_ptr = geo_box.height; } +/* ------------------------------------------------------------------------- */ +/** + * Sets the keyboard activation status for the surface. + * + * @param content_ptr + * @param active + */ +void content_set_active( + wlmtk_content_t *content_ptr, + bool active) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + wlr_xdg_toplevel_set_activated( + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, active); + + if (active) { + struct wlr_keyboard *wlr_keyboard_ptr = wlr_seat_get_keyboard( + xdg_tl_content_ptr->server_ptr->wlr_seat_ptr); + if (NULL != wlr_keyboard_ptr) { + wlr_seat_keyboard_notify_enter( + xdg_tl_content_ptr->server_ptr->wlr_seat_ptr, + xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface, + wlr_keyboard_ptr->keycodes, + wlr_keyboard_ptr->num_keycodes, + &wlr_keyboard_ptr->modifiers); + } + } +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `map` signal. From 1f72d705e97b9728cc9cb0a1d43d0061bf2ce948 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 24 Sep 2023 18:20:42 -0400 Subject: [PATCH 076/390] Renames toolkit's 'active' to 'activated' throughout. --- src/toolkit/content.c | 20 ++++++++++---------- src/toolkit/content.h | 16 ++++++++-------- src/toolkit/toolkit.md | 4 ++-- src/toolkit/window.c | 20 ++++++++++---------- src/toolkit/window.h | 6 +++--- src/toolkit/workspace.c | 2 +- src/wlmtk_xdg_toplevel.c | 16 ++++++++-------- 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 07785dc8..c76e3473 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -59,7 +59,7 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); BS_ASSERT(NULL != content_impl_ptr->get_size); - BS_ASSERT(NULL != content_impl_ptr->set_active); + BS_ASSERT(NULL != content_impl_ptr->set_activated); memset(content_ptr, 0, sizeof(wlmtk_content_t)); @@ -202,16 +202,16 @@ static void fake_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); -static void fake_content_set_active( +static void fake_content_set_activated( wlmtk_content_t *content_ptr, - bool active); + bool activated); /** Method table of the fake content. */ static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, .create_scene_node = fake_content_create_scene_node, .get_size = fake_content_get_size, - .set_active = fake_content_set_active, + .set_activated = fake_content_set_activated, }; /* ------------------------------------------------------------------------- */ @@ -272,14 +272,14 @@ void fake_content_get_size( } /* ------------------------------------------------------------------------- */ -/** Sets the content's activation status. */ -void fake_content_set_active( +/** Sets the content's activated status. */ +void fake_content_set_activated( wlmtk_content_t *content_ptr, - bool active) + bool activated) { wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( content_ptr, wlmtk_fake_content_t, content); - fake_content_ptr->active = active; + fake_content_ptr->activated = activated; } /* == Unit tests =========================================================== */ @@ -318,8 +318,8 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 42, r); BS_TEST_VERIFY_EQ(test_ptr, 21, b); - wlmtk_content_set_active(&fake_content_ptr->content, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->active); + wlmtk_content_set_activated(&fake_content_ptr->content, true); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); wlmtk_element_destroy(&fake_content_ptr->content.super_element); } diff --git a/src/toolkit/content.h b/src/toolkit/content.h index f22bf17e..29ba2aad 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -68,8 +68,8 @@ struct _wlmtk_content_impl_t { /** Gets width and height of the content. */ void (*get_size)(wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); - /** Sets the content as active (or not). */ - void (*set_active)(wlmtk_content_t *content_ptr, bool active); + /** Sets whether the content is activated (has keyboard focus). */ + void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); }; /** @@ -124,11 +124,11 @@ static inline void wlmtk_content_get_size( int *width_ptr, int *height_ptr) { content_ptr->impl_ptr->get_size(content_ptr, width_ptr, height_ptr); } -/** Wraps to @ref wlmtk_content_impl_t::set_active. */ -static inline void wlmtk_content_set_active( +/** Wraps to @ref wlmtk_content_impl_t::set_activated. */ +static inline void wlmtk_content_set_activated( wlmtk_content_t *content_ptr, - bool active) { - content_ptr->impl_ptr->set_active(content_ptr, active); + bool activated) { + content_ptr->impl_ptr->set_activated(content_ptr, activated); } @@ -143,8 +143,8 @@ typedef struct { int width; /** Height to return on a wlmtk_content_impl_t::get_size call. */ int height; - /** Argument of last @ref wlmtk_content_set_active call. */ - bool active; + /** Argument of last @ref wlmtk_content_set_activated call. */ + bool activated; } wlmtk_fake_content_t; /** Ctor for a fake content. */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 84dd0d2b..bf419134 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -112,7 +112,7 @@ abstract class Content { Element *element() -set_window(Window*) - {abstract}#void set_active(bool) + {abstract}#void set_activated(bool) {abstract}#void set_maximized(bool) {abstract}#void set_fullscreen(bool) {abstract}#void motion(double, double) @@ -164,7 +164,7 @@ class Window { destroy() Element *element() - set_active(bool) + set_activated(bool) } VBox *-- Window diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 708bd00f..f5297840 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -89,11 +89,11 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) } /* ------------------------------------------------------------------------- */ -void wlmtk_window_set_active( +void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, - bool active) + bool activated) { - wlmtk_content_set_active(window_ptr->content_ptr, active); + wlmtk_content_set_activated(window_ptr->content_ptr, activated); } /* == Local (static) methods =============================================== */ @@ -110,11 +110,11 @@ void window_container_destroy(wlmtk_container_t *container_ptr) /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); -static void test_set_active(bs_test_t *test_ptr); +static void test_set_activated(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "create_destroy", test_create_destroy }, - { 1, "set_active", test_set_active }, + { 1, "set_activated", test_set_activated }, { 0, NULL, NULL } }; @@ -134,17 +134,17 @@ void test_create_destroy(bs_test_t *test_ptr) /* ------------------------------------------------------------------------- */ /** Tests activation. */ -void test_set_active(bs_test_t *test_ptr) +void test_set_activated(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( &fake_content_ptr->content); - wlmtk_window_set_active(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->active); + wlmtk_window_set_activated(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); - wlmtk_window_set_active(window_ptr, false); - BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->active); + wlmtk_window_set_activated(window_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->activated); wlmtk_window_destroy(window_ptr); } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 52827c2c..10624637 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -67,11 +67,11 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); * decorations to indicate state. * * @param window_ptr - * @param active + * @param activated */ -void wlmtk_window_set_active( +void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, - bool active); + bool activated); /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 14ee9182..40a2fd18 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -96,7 +96,7 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_element(window_ptr)); // TODO(kaeser@gubbe.ch): Refine and test this. - wlmtk_window_set_active(window_ptr, true); + wlmtk_window_set_activated(window_ptr, true); } /* ------------------------------------------------------------------------- */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index f1c85a42..7b262d4b 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -61,9 +61,9 @@ static void content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); -static void content_set_active( +static void content_set_activated( wlmtk_content_t *content_ptr, - bool active); + bool activated); /* == Data ================================================================= */ @@ -72,7 +72,7 @@ const wlmtk_content_impl_t content_impl = { .destroy = content_destroy, .create_scene_node = content_create_scene_node, .get_size = content_get_size, - .set_active = content_set_active, + .set_activated = content_set_activated, }; @@ -204,19 +204,19 @@ void content_get_size( * Sets the keyboard activation status for the surface. * * @param content_ptr - * @param active + * @param activated */ -void content_set_active( +void content_set_activated( wlmtk_content_t *content_ptr, - bool active) + bool activated) { wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( content_ptr, wlmtk_xdg_toplevel_content_t, super_content); wlr_xdg_toplevel_set_activated( - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, active); + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, activated); - if (active) { + if (activated) { struct wlr_keyboard *wlr_keyboard_ptr = wlr_seat_get_keyboard( xdg_tl_content_ptr->server_ptr->wlr_seat_ptr); if (NULL != wlr_keyboard_ptr) { From 239cfc705c810de1309320cf74fabd28b8b7058a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Sep 2023 16:35:43 +0200 Subject: [PATCH 077/390] Clears seat pointer focus when XDG toplevel gets deactivated. --- src/wlmtk_xdg_toplevel.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 7b262d4b..0886dc48 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -32,6 +32,8 @@ typedef struct { /** The corresponding wlroots XDG surface. */ struct wlr_xdg_surface *wlr_xdg_surface_ptr; + /** Whether this surface is currently activated. */ + bool activated; /** Listener for the `map` signal of the `wlr_surface`. */ struct wl_listener surface_map_listener; @@ -212,22 +214,34 @@ void content_set_activated( { wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + // Early return, if nothing to be done. + if (xdg_tl_content_ptr->activated == activated) return; + struct wlr_seat *wlr_seat_ptr = + xdg_tl_content_ptr->server_ptr->wlr_seat_ptr; wlr_xdg_toplevel_set_activated( xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, activated); if (activated) { struct wlr_keyboard *wlr_keyboard_ptr = wlr_seat_get_keyboard( - xdg_tl_content_ptr->server_ptr->wlr_seat_ptr); + wlr_seat_ptr); if (NULL != wlr_keyboard_ptr) { wlr_seat_keyboard_notify_enter( - xdg_tl_content_ptr->server_ptr->wlr_seat_ptr, + wlr_seat_ptr, xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface, wlr_keyboard_ptr->keycodes, wlr_keyboard_ptr->num_keycodes, &wlr_keyboard_ptr->modifiers); } + } else { + BS_ASSERT(xdg_tl_content_ptr->activated); + if (wlr_seat_ptr->keyboard_state.focused_surface == + xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface) { + wlr_seat_pointer_clear_focus(wlr_seat_ptr); + } } + + xdg_tl_content_ptr->activated = activated; } /* ------------------------------------------------------------------------- */ From 15991ddefcc74535573f95b0d63717fb27a06cb2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Sep 2023 17:17:25 +0200 Subject: [PATCH 078/390] Wires up decoration manager with a dummy function of the window. --- src/toolkit/content.c | 5 +++++ src/toolkit/content.h | 9 +++++++++ src/toolkit/window.c | 9 +++++++++ src/toolkit/window.h | 10 ++++++++++ src/wlmtk_xdg_toplevel.c | 2 ++ src/xdg_decoration.c | 18 ++++++++++++++++-- 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index c76e3473..8f52deb6 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -39,6 +39,8 @@ static void element_get_dimensions( int *right_ptr, int *bottom_ptr); +/* == Data ================================================================= */ + /** Method table for the container's virtual methods. */ const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, @@ -46,6 +48,8 @@ const wlmtk_element_impl_t super_element_impl = { .get_dimensions = element_get_dimensions, }; +void *wlmtk_content_identifier_ptr = wlmtk_content_init; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -71,6 +75,7 @@ bool wlmtk_content_init( content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->impl_ptr = content_impl_ptr; + content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; return true; } diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 29ba2aad..23388861 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -34,6 +34,9 @@ extern "C" { /** State of the element. */ struct _wlmtk_content_t { + /** Temporary: Identifier, to disambiguate from XDG nodes. */ + void *identifier_ptr; + /** Super class of the content: An element. */ wlmtk_element_t super_element; @@ -131,6 +134,12 @@ static inline void wlmtk_content_set_activated( content_ptr->impl_ptr->set_activated(content_ptr, activated); } +/** + * Identifying pointer: Value unique to wlmtk_content. + * + * TODO(kaeser@gubbe.ch): Remove, once migrated to toolkit. + */ +extern void *wlmtk_content_identifier_ptr; /** Unit tests for content. */ extern const bs_test_case_t wlmtk_content_test_cases[]; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f5297840..8c564f91 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -96,6 +96,15 @@ void wlmtk_window_set_activated( wlmtk_content_set_activated(window_ptr->content_ptr, activated); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_server_side_decorated( + wlmtk_window_t *window_ptr, + bool decorated) +{ + bs_log(BS_INFO, "Set server side decoration for window %p: %d", + window_ptr, decorated); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 10624637..33bd07e5 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -73,6 +73,16 @@ void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated); +/** + * Sets whether to have server-side decorations for this window. + * + * @param window_ptr + * @param decorated + */ +void wlmtk_window_set_server_side_decorated( + wlmtk_window_t *window_ptr, + bool decorated); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 0886dc48..2250728a 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -128,6 +128,8 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &xdg_tl_content_ptr->surface_unmap_listener, handle_surface_unmap); + xdg_tl_content_ptr->wlr_xdg_surface_ptr->data = + &xdg_tl_content_ptr->super_content; return xdg_tl_content_ptr; } diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index cfb7bc91..78260740 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -219,8 +219,22 @@ void handle_decoration_request_mode( listener_ptr, decoration_ptr, request_mode_listener); struct wlr_scene_tree *wlr_scene_tree_ptr = (struct wlr_scene_tree*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->surface->data; - if (NULL == wlr_scene_tree_ptr) { - bs_log(BS_ERROR, "No tree associated with surface. Toolkit window?"); + + wlmtk_content_t *content_ptr = (wlmtk_content_t*) + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->surface->data; + if (NULL != content_ptr && + content_ptr->identifier_ptr == wlmtk_content_identifier_ptr) { + bs_log(BS_WARNING, + "Toolkit window: Enforcing client-side decoration."); + + enum wlr_xdg_toplevel_decoration_v1_mode mode = + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + wlr_xdg_toplevel_decoration_v1_set_mode( + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr, + mode); + wlmtk_window_set_server_side_decorated( + content_ptr->window_ptr, + mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); return; } wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; From 95962fb25a1b9114fa2b6056710fb902f68f5e92 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Sep 2023 17:18:48 +0200 Subject: [PATCH 079/390] Adds documentation reference for set_server_side_decorated. --- src/toolkit/toolkit.md | 1 + src/toolkit/window.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index bf419134..e83c3530 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -165,6 +165,7 @@ class Window { Element *element() set_activated(bool) + set_server_side_decorated(bool) } VBox *-- Window diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 8c564f91..0117b34b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -101,6 +101,7 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated) { + // TODO(kaeser@gubbe.ch): Implement. bs_log(BS_INFO, "Set server side decoration for window %p: %d", window_ptr, decorated); } From 810fd6ef49e2231bfc74556505822a0634e0a4d9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Sep 2023 17:49:42 +0200 Subject: [PATCH 080/390] Adds some thoughts on handling pointer events. --- src/toolkit/toolkit.md | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index e83c3530..38991a3c 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -87,6 +87,7 @@ class Workspace { unmap_window(Window*) activate_window(Window*) + begin_window_move(Window*) map_layer_element(LayerElement *, layer) unmap_layer_element(LayerElement *, layer) @@ -262,6 +263,49 @@ There is a click ("pointer button event") -> goes to workspace. * Button::click gets called. Has a "button_from_element" & goes from there. +Button is pressed => pass down to pointer-focussed element. + Would eg. show the "pressed" state of a button, but not activate. + + button_down + +Button is released => pass down to pointer-focussed element. + (actually: pass down to the element where the button-press was passed to) + Would eg. acivate the button, and restore the state of a pressed button. + + button_up + click + +Button remains pressed and pointer moves. + Means: We might be dragging something around. + Start a "drag" => pass down a "drag" event to pointer focussed element. + Keep track of drag start, and pass on relative drag motion down to element. + Keeps passing drag elements to same element until drag ends. + Would keep the element pointer focussed (?) + + A 'button' would ignore drags. drag_begin, drag_end, drag_motion ? + A 'titlebar' would use this to begin a move, and update position. + A 'iconified' would use this to de-couple from eg. dock + + drags have a pointer button associated (left, middle, right), + and a relative position since. They also have the starting position, + relative to the element. + + button_down + [lingering time, some light move] + drag_begin + drag_motion + drag_motion + button_up + drag_end + +Button is pressed again, without much move since last press. + Means: We have a double-click. + Pass down a double-click to the pointer-focussed element. + + button_down + button_up + double_click + ## Dock and Clip class elements From b6bc03b7377e35519ac756504d29a795f9d35120 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 1 Oct 2023 14:56:02 +0200 Subject: [PATCH 081/390] Starts adding boilerplate for button handling. --- src/toolkit/workspace.c | 15 +++++++++++++++ src/toolkit/workspace.h | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 40a2fd18..6d5bb391 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -21,6 +21,7 @@ #include "workspace.h" #define WLR_USE_UNSTABLE +#include #include #undef WLR_USE_UNSTABLE @@ -119,6 +120,20 @@ wlmtk_workspace_t *wlmtk_workspace_from_container( return BS_CONTAINER_OF(container_ptr, wlmtk_workspace_t, super_container); } +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_handle_button( + wlmtk_workspace_t *workspace_ptr, + const struct wlr_pointer_button_event *event_ptr, + double x, + double y) +{ + bs_log(BS_INFO, "Workspace %p: button event %p ad %.0f, %.0f", + workspace_ptr, event_ptr, x, y); + if (WLR_BUTTON_PRESSED == event_ptr->state) { + // Pass BUTTON_DOWN. + } +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 9e3301b2..1cc74276 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -30,6 +30,9 @@ extern "C" { /** State of the workspace. */ typedef struct _wlmtk_workspace_t wlmtk_workspace_t; +/** Forward declaration. */ +struct wlr_pointer_button_event; + /** * Creates a workspace. * @@ -80,6 +83,26 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_workspace_t *wlmtk_workspace_from_container( wlmtk_container_t *container_ptr); +/** + * Handles a button event: Translates to button down/up/click/dblclick events. + * + * Each button activity (button pressed or released) will directly trigger a + * corresponding BUTTON_DOWN or BUTTON_UP event. Depending on timing and + * motion, a "released" event may also triccer a CLICK, DOUBLE_CLICK or + * DRAG event. + * These events will be forwarded to the event currently having pointer focus. + * + * @param workspace_ptr + * @paran event_ptr + * @param x + * @param y + */ +void wlmtk_workspace_handle_button( + wlmtk_workspace_t *workspace_ptr, + const struct wlr_pointer_button_event *event_ptr, + double x, + double y); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; From aa3d0315d994674df8dd80617c21c9a1f71ea629 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 2 Oct 2023 21:40:24 +0200 Subject: [PATCH 082/390] Wires up the element::motion method for content. --- src/toolkit/content.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 8f52deb6..9ac84244 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -38,6 +38,11 @@ static void element_get_dimensions( int *top_ptr, int *right_ptr, int *bottom_ptr); +static wlmtk_element_t *element_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + __UNUSED__ uint32_t time_msec); /* == Data ================================================================= */ @@ -46,6 +51,7 @@ const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, + .motion = element_motion, }; void *wlmtk_content_identifier_ptr = wlmtk_content_init; From 7f200eb2cb1fe02a02fceebd34c07378414dfe05 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 16 Oct 2023 16:39:51 +0200 Subject: [PATCH 083/390] Checks in current state due to workstation switch. Needs more work, though... --- src/cursor.c | 23 ++ src/toolkit/button.h | 54 +++++ src/toolkit/container.c | 488 +++++++++++++++++++++++++-------------- src/toolkit/container.h | 8 + src/toolkit/content.c | 165 +++++++++++-- src/toolkit/element.c | 168 ++++++++++++-- src/toolkit/element.h | 117 ++++++++-- src/toolkit/toolkit.md | 6 +- src/toolkit/workspace.c | 44 +++- src/toolkit/workspace.h | 19 +- src/wlmtk_xdg_toplevel.c | 41 ++++ src/xdg_toplevel.c | 2 - 12 files changed, 881 insertions(+), 254 deletions(-) create mode 100644 src/toolkit/button.h diff --git a/src/cursor.c b/src/cursor.c index 8f1af2a8..2de99830 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -305,6 +305,13 @@ void handle_button(struct wl_listener *listener_ptr, listener_ptr, cursor_ptr, button_listener); struct wlr_pointer_button_event *wlr_pointer_button_event_ptr = data_ptr; + wlmtk_workspace_button( + wlmaker_workspace_wlmtk(wlmaker_server_get_current_workspace( + cursor_ptr->server_ptr)), + wlr_pointer_button_event_ptr); + + if (true) return; // FIXME + struct wlr_keyboard *wlr_keyboard_ptr = wlr_seat_get_keyboard( cursor_ptr->server_ptr->wlr_seat_ptr); if (NULL != wlr_keyboard_ptr) { @@ -473,6 +480,22 @@ void handle_seat_request_set_cursor( */ void process_motion(wlmaker_cursor_t *cursor_ptr, uint32_t time_msec) { + bool rv = wlmtk_workspace_motion( + wlmaker_workspace_wlmtk(wlmaker_server_get_current_workspace( + cursor_ptr->server_ptr)), + cursor_ptr->wlr_cursor_ptr->x, + cursor_ptr->wlr_cursor_ptr->y, + time_msec); + + if (!rv) { // FIXME + wlr_xcursor_manager_set_cursor_image( + cursor_ptr->wlr_xcursor_manager_ptr, + "left_ptr", + cursor_ptr->wlr_cursor_ptr); + } + + if (true) return; + if (cursor_ptr->mode == WLMAKER_CURSOR_MOVE) { wlmaker_view_set_position( cursor_ptr->grabbed_view_ptr, diff --git a/src/toolkit/button.h b/src/toolkit/button.h new file mode 100644 index 00000000..019bfe58 --- /dev/null +++ b/src/toolkit/button.h @@ -0,0 +1,54 @@ +/* ========================================================================= */ +/** + * @file button.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_BUTTON_H__ +#define __WLMTK_BUTTON_H__ + +/** Forward declaration: Button event. */ +typedef struct _wlmtk_button_event_t wlmtk_button_event_t; + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Button state. */ +typedef enum { + WLMTK_BUTTON_DOWN, + WLMTK_BUTTON_UP, + WLMTK_BUTTON_CLICK, + WLMTK_BUTTON_DOUBLE_CLICK, +} wlmtk_button_event_type_t; + +/** Button events. */ +struct _wlmtk_button_event_t { + /** Button for which the event applies: linux/input-event-codes.h */ + uint32_t button; + /** Type of the event: DOWN, UP, ... */ + wlmtk_button_event_type_t type; + /** Time of the button event, in milliseconds. */ + uint32_t time_msec; +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_BUTTON_H__ */ +/* == End of button.h ====================================================== */ diff --git a/src/toolkit/container.c b/src/toolkit/container.c index c97c5798..88c42d14 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -38,27 +38,36 @@ static void element_get_dimensions( int *top_ptr, int *right_ptr, int *bottom_ptr); -static wlmtk_element_t *element_motion( +static void element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); +static wlmtk_element_t *element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static void element_leave( +static void element_pointer_leave( wlmtk_element_t *element_ptr); -static void element_get_bounding_box( - wlmtk_element_t *element_ptr, - int *x_from_ptr, int *y_from_ptr, int *x_to_ptr, int *y_to_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr); +static wlmtk_element_t *update_pointer_focus_at( + wlmtk_container_t *container_ptr, + double x, + double y, + uint32_t time_msec); /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, - .motion = element_motion, - .leave = element_leave + .get_pointer_area = element_get_pointer_area, + .pointer_motion = element_pointer_motion, + .pointer_leave = element_pointer_leave }; /* == Exported methods ===================================================== */ @@ -108,6 +117,10 @@ void wlmtk_container_add_element( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); wlmtk_element_set_parent_container(element_ptr, container_ptr); + + // Need to re-compute pointer focus, since we might have added an element + // below the current cursor position. + wlmtk_container_update_pointer_focus(container_ptr); } /* ------------------------------------------------------------------------- */ @@ -121,6 +134,18 @@ void wlmtk_container_remove_element( bs_dllist_remove( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); + wlmtk_container_update_pointer_focus(container_ptr); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_container_update_pointer_focus( + wlmtk_container_t *container_ptr) +{ + return update_pointer_focus_at( + container_ptr, + container_ptr->super_element.pointer_x, + container_ptr->super_element.pointer_y, + container_ptr->super_element.pointer_time_msec); } /* ------------------------------------------------------------------------- */ @@ -210,12 +235,56 @@ void element_get_dimensions( dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - int x_from, y_from, x_to, y_to; - element_get_bounding_box(element_ptr, &x_from, &y_from, &x_to, &y_to); - left = BS_MIN(left, x_from); - top = BS_MIN(top, y_from); - right = BS_MAX(right, x_to); - bottom = BS_MAX(bottom, y_to); + int x_pos, y_pos; + wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); + int x1, y1, x2, y2; + wlmtk_element_get_dimensions(element_ptr, &x1, &y1, &x2, &y2); + left = BS_MIN(left, x_pos + x1); + top = BS_MIN(top, y_pos + y1); + right = BS_MAX(right, x_pos + x2); + bottom = BS_MAX(bottom, y_pos + y2); + } + + if (NULL != left_ptr) *left_ptr = left; + if (NULL != top_ptr) *top_ptr = top; + if (NULL != right_ptr) *right_ptr = right; + if (NULL != bottom_ptr) *bottom_ptr = bottom; +} + +/* ------------------------------------------------------------------------- */ +/** + * Returns the minimal rectangle covering all element's pointer areas. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + + int left = 0, top = 0, right = 0, bottom = 0; + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + + int x_pos, y_pos; + wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); + int x1, y1, x2, y2; + wlmtk_element_get_pointer_area(element_ptr, &x1, &y1, &x2, &y2); + left = BS_MIN(left, x_pos + x1); + top = BS_MIN(top, y_pos + y1); + right = BS_MAX(right, x_pos + x2); + bottom = BS_MAX(bottom, y_pos + y2); } if (NULL != left_ptr) *left_ptr = left; @@ -236,7 +305,7 @@ void element_get_dimensions( * @return Pointer to the (non-container) element handling the motion, or NULL * if the motion wasn't handled. */ -wlmtk_element_t *element_motion( +wlmtk_element_t *element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -245,36 +314,7 @@ wlmtk_element_t *element_motion( wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); - for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; - dlnode_ptr != NULL; - dlnode_ptr = dlnode_ptr->next_ptr) { - wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - - int x_from, y_from, x_to, y_to; - element_get_bounding_box(element_ptr, &x_from, &y_from, &x_to, &y_to); - if (x_from <= x && x < x_to && y_from <= y && y < y_to) { - int x_pos, y_pos; - wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); - wlmtk_element_t *motion_element_ptr = wlmtk_element_motion( - element_ptr, x - x_pos, y - y_pos, time_msec); - if (NULL == motion_element_ptr) continue; - - if (NULL != container_ptr->pointer_focus_element_ptr) { - wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); - } - container_ptr->pointer_focus_element_ptr = element_ptr; - return motion_element_ptr; - } - } - - // Getting here implies we didn't have an element catching the motion, - // so it must have happened outside our araea. We also should free - // pointer focus element now. - if (NULL != container_ptr->pointer_focus_element_ptr) { - wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); - container_ptr->pointer_focus_element_ptr = NULL; - } - return NULL; + return update_pointer_focus_at(container_ptr, x, y, time_msec); } /* ------------------------------------------------------------------------- */ @@ -284,13 +324,13 @@ wlmtk_element_t *element_motion( * * @param element_ptr */ -void element_leave(wlmtk_element_t *element_ptr) +void element_pointer_leave(wlmtk_element_t *element_ptr) { wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); if (NULL == container_ptr->pointer_focus_element_ptr) return; - wlmtk_element_leave(container_ptr->pointer_focus_element_ptr); + wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); container_ptr->pointer_focus_element_ptr = NULL; } @@ -325,30 +365,58 @@ void handle_wlr_scene_tree_node_destroy( /* ------------------------------------------------------------------------- */ /** - * Computes the bounding box position for the element, relative to parent. + * Updates pointer focus of container for position (x, y). * - * The element (or the element's sub-elements) will all be contained in the - * area spanned by [*x_from_ptr, *x_to_ptr), [*y_from_ptr, *y_to_ptr). + * Updates wlmtk_container_t::pointer_focus_element_ptr. * - * @param element_ptr - * @param x_from_ptr Minimum horizontal position (inclusive). - * @param y_from_ptr Minimum vertical position (inclusive). - * @param x_to_ptr Maximum horizontal position (exclusive). - * @param y_to_ptr Maximum vertical position (exclusive). + * @param container_ptr + * @param x + * @param y + * @param time_msec + * + * @return The leave element at position (x, y). */ -void element_get_bounding_box( - wlmtk_element_t *element_ptr, - int *x_from_ptr, int *y_from_ptr, int *x_to_ptr, int *y_to_ptr) +wlmtk_element_t *update_pointer_focus_at( + wlmtk_container_t *container_ptr, + double x, + double y, + uint32_t time_msec) { - int x_pos, y_pos; - wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - wlmtk_element_get_dimensions( - element_ptr, x_from_ptr, y_from_ptr, x_to_ptr, y_to_ptr); - if (NULL != x_from_ptr) *x_from_ptr += x_pos; - if (NULL != x_to_ptr) *x_to_ptr += x_pos; - if (NULL != y_from_ptr) *y_from_ptr += y_pos; - if (NULL != y_to_ptr) *y_to_ptr += y_pos; + if (!element_ptr->visible) continue; + + int x_pos, y_pos; + wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); + int x1, y1, x2, y2; + wlmtk_element_get_pointer_area(element_ptr, &x1, &y1, &x2, &y2); + if (x_pos + x1 <= x && x < x_pos + x2 && + y_pos + y1 <= y && y < y_pos + y2) { + wlmtk_element_t *motion_element_ptr = wlmtk_element_pointer_motion( + element_ptr, x - x_pos, y - y_pos, time_msec); + if (NULL == motion_element_ptr) continue; + + if (NULL != container_ptr->pointer_focus_element_ptr && + container_ptr->pointer_focus_element_ptr != element_ptr) { + wlmtk_element_pointer_leave( + container_ptr->pointer_focus_element_ptr); + } + container_ptr->pointer_focus_element_ptr = element_ptr; + return motion_element_ptr; + } + } + + // Getting here implies we didn't have an element catching the motion, + // so it must have happened outside our araea. We also should free + // pointer focus element now. + if (NULL != container_ptr->pointer_focus_element_ptr) { + wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); + container_ptr->pointer_focus_element_ptr = NULL; + } + return NULL; } /* == Helper for unit test: A fake container =============================== */ @@ -432,15 +500,15 @@ void fake_parent_destroy(wlmtk_container_t *container_ptr) static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); -static void test_motion(bs_test_t *test_ptr); -static void test_motion_nested(bs_test_t *test_ptr); +static void test_pointer_motion(bs_test_t *test_ptr); +static void test_pointer_focus(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, - { 1, "motion", test_motion }, - { 1, "motion_nested", test_motion_nested }, + { 1, "pointer_motion", test_pointer_motion }, + { 1, "pointer_focus", test_pointer_focus }, { 0, NULL, NULL } }; @@ -534,85 +602,29 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) /* ------------------------------------------------------------------------- */ /** Tests the 'motion' method for container. */ -void test_motion(bs_test_t *test_ptr) +void test_pointer_motion(bs_test_t *test_ptr) { wlmtk_container_t container; BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + wlmtk_element_set_visible(&container.super_element, true); + // Note: pointer area extends by (-1, -2, 3, 4) on each fake element. wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem1_ptr->element, -20, -40); elem1_ptr->width = 10; elem1_ptr->height = 5; - elem1_ptr->motion_return_value = &elem1_ptr->element; + elem1_ptr->pointer_motion_return_value = &elem1_ptr->element; + wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem2_ptr->element, 100, 200); elem2_ptr->width = 10; elem2_ptr->height = 5; - elem2_ptr->motion_return_value = &elem2_ptr->element; - wlmtk_container_add_element(&container, &elem2_ptr->element); - - wlmtk_element_motion(&container.super_element, 0, 0, 1234); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - - elem1_ptr->motion_x = 42; - elem1_ptr->motion_y = 42; - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, - wlmtk_element_motion(&container.super_element, -20, -40, 1234)); - BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); - elem1_ptr->motion_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); - - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 107, 203, 1234)); - BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); - elem1_ptr->leave_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); - BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->motion_called); - elem2_ptr->motion_called = false; - BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->motion_y); - - BS_TEST_VERIFY_EQ( - test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 110, 205, 1234)); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); - elem2_ptr->leave_called = false; - - wlmtk_container_remove_element(&container, &elem1_ptr->element); - wlmtk_element_destroy(&elem1_ptr->element); - wlmtk_container_remove_element(&container, &elem2_ptr->element); - wlmtk_element_destroy(&elem2_ptr->element); - wlmtk_container_fini(&container); -} - -/* ------------------------------------------------------------------------- */ -/** Tests the 'motion' method for container. */ -void test_motion_nested(bs_test_t *test_ptr) -{ - wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); - - wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); - wlmtk_element_set_position(&elem1_ptr->element, -20, -40); - elem1_ptr->width = 10; - elem1_ptr->height = 5; - elem1_ptr->motion_return_value = &elem1_ptr->element; - wlmtk_container_add_element(&container, &elem1_ptr->element); - wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); - wlmtk_element_set_position(&elem2_ptr->element, 100, 200); - elem2_ptr->width = 10; - elem2_ptr->height = 5; - elem2_ptr->motion_return_value = &elem2_ptr->element; + wlmtk_element_set_visible(&elem2_ptr->element, true); + elem2_ptr->pointer_motion_return_value = &elem2_ptr->element; wlmtk_container_add_element(&container, &elem2_ptr->element); + // Verify 'dimensions' and 'pointer_area', derived from children. int l, t, r, b; wlmtk_element_get_dimensions(&container.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, -20, l); @@ -620,63 +632,100 @@ void test_motion_nested(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 110, r); BS_TEST_VERIFY_EQ(test_ptr, 205, b); + wlmtk_element_get_pointer_area(&container.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, -21, l); + BS_TEST_VERIFY_EQ(test_ptr, -42, t); + BS_TEST_VERIFY_EQ(test_ptr, 113, r); + BS_TEST_VERIFY_EQ(test_ptr, 209, b); + + // Same must hold for the parent container. wlmtk_container_t parent_container; BS_ASSERT(wlmtk_container_init(&parent_container, &wlmtk_container_fake_impl)); wlmtk_container_add_element(&parent_container, &container.super_element); - wlmtk_element_get_dimensions(&parent_container.super_element, &l, &t, &r, &b); + wlmtk_element_get_dimensions( + &parent_container.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, -20, l); BS_TEST_VERIFY_EQ(test_ptr, -40, t); BS_TEST_VERIFY_EQ(test_ptr, 110, r); BS_TEST_VERIFY_EQ(test_ptr, 205, b); - - wlmtk_element_motion(&container.super_element, 0, 0, 1234); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - - elem1_ptr->motion_x = 42; - elem1_ptr->motion_y = 42; + wlmtk_element_get_pointer_area( + &parent_container.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, -21, l); + BS_TEST_VERIFY_EQ(test_ptr, -42, t); + BS_TEST_VERIFY_EQ(test_ptr, 113, r); + BS_TEST_VERIFY_EQ(test_ptr, 209, b); + + // There's nothing at (0, 0). + wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); + + wlmtk_element_pointer_motion(&parent_container.super_element, 0, 0, 7); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); + + // elem1 is at (-20, -40). + elem1_ptr->pointer_motion_x = 42; + elem1_ptr->pointer_motion_y = 42; BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, -20, -40, 1234)); - BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); - elem1_ptr->motion_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); + wlmtk_element_pointer_motion(&container.super_element, -20, -40, 7)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); + elem1_ptr->pointer_motion_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_y); BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&parent_container.super_element, -20, -40, 1234)); - BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->motion_called); - elem1_ptr->motion_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->motion_y); - - + wlmtk_element_pointer_motion( + &parent_container.super_element, -20, -40, 7)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); + elem1_ptr->pointer_motion_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_y); + + // elem2 is covering the area at (107, 302). BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 107, 203, 1234)); - BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->leave_called); - elem1_ptr->leave_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); - BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->motion_called); - elem2_ptr->motion_called = false; - BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->motion_y); - + wlmtk_element_pointer_motion( + &parent_container.super_element, 107, 203, 7)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_leave_called); + elem1_ptr->pointer_leave_called = false; + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_motion_called); + elem2_ptr->pointer_motion_called = false; + BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->pointer_motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->pointer_motion_y); + + // The pointer area of elem2 is covering the area at (112, 208). + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, + wlmtk_element_pointer_motion( + &parent_container.super_element, 112, 208, 7)); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_leave_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_motion_called); + elem2_ptr->pointer_motion_called = false; + BS_TEST_VERIFY_EQ(test_ptr, 12, elem2_ptr->pointer_motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 8, elem2_ptr->pointer_motion_y); + + // The pointer area of elem2 does not include (113, 209). BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_element_motion(&container.super_element, 110, 205, 1234)); - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->motion_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->motion_called); - BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->leave_called); - elem2_ptr->leave_called = false; - + wlmtk_element_pointer_motion( + &parent_container.super_element, 113, 209, 7)); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_leave_called); + elem2_ptr->pointer_leave_called = false; + + // All set. clean it up. wlmtk_container_remove_element(&container, &elem1_ptr->element); wlmtk_element_destroy(&elem1_ptr->element); wlmtk_container_remove_element(&container, &elem2_ptr->element); @@ -688,10 +737,103 @@ void test_motion_nested(bs_test_t *test_ptr) wlmtk_container_fini(&container); } +/* ------------------------------------------------------------------------- */ +/** Tests that pointer focus is updated when elements are updated. */ +void test_pointer_focus(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + + wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); + elem1_ptr->pointer_motion_return_value = &elem1_ptr->element; + wlmtk_element_set_visible(&elem1_ptr->element, true); + wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); + elem2_ptr->pointer_motion_return_value = &elem2_ptr->element; + wlmtk_element_set_visible(&elem2_ptr->element, true); + + // Case 1: An empty container, will not have a pointer-focussed element. + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.pointer_focus_element_ptr); + + // Case 2: Adding a visible element at (0, 0): Focus remains NULL, since + // motion() was not called yet and we don't have known pointer position. + wlmtk_container_add_element(&container, &elem1_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.pointer_focus_element_ptr); + wlmtk_container_remove_element(&container, &elem1_ptr->element); + + // Case 3: Call motion() first, then add a visible element at (0, 0). Focus + // should switch there. + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7)); + wlmtk_container_add_element(&container, &elem1_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container.pointer_focus_element_ptr); + + // Case 4: Add another visible element. Focus remains, though. + wlmtk_container_add_element(&container, &elem2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container.pointer_focus_element_ptr); + + // Case 5: Elem1 (added first = in front) becomes invisible. Focus changes. + wlmtk_element_set_visible(&elem1_ptr->element, false); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem2_ptr->element, + container.pointer_focus_element_ptr); + + // Case 6: Elem2 becomes invisible. Focus changes to NULL. + wlmtk_element_set_visible(&elem2_ptr->element, false); + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + container.pointer_focus_element_ptr); + + // Case 7: Elem1 becomes visible. Focus changes to elem1 again. + wlmtk_element_set_visible(&elem1_ptr->element, true); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container.pointer_focus_element_ptr); + + // Case 8: Remove Elem1. Focus changes to NULL. + wlmtk_container_remove_element(&container, &elem1_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + container.pointer_focus_element_ptr); + + // Case 9: Elem2 becomes visible, focus changes there. + wlmtk_element_set_visible(&elem2_ptr->element, true); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem2_ptr->element, + container.pointer_focus_element_ptr); + + // Case 10: Elem2 is removed. Focus is now NULL, and leave() is called for + // the element that was removed. + elem2_ptr->pointer_leave_called = false; + wlmtk_container_remove_element(&container, &elem2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + container.pointer_focus_element_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + elem2_ptr->pointer_leave_called); + + wlmtk_element_destroy(&elem2_ptr->element); + wlmtk_element_destroy(&elem1_ptr->element); + wlmtk_container_fini(&container); +} + /* - * TODO(kaeser@gubbe.ch): Extend motion test to verify a search is continued - * if an element in the area returns NULL. Also verify it continues if the - * element is not visible. + * TODO(kaeser@gubbe.ch): Extend tests to verify parent container is upated + * when focus falls through. */ /* == End of container.c =================================================== */ diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 0fa14ebc..db090944 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -107,6 +107,14 @@ void wlmtk_container_remove_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr); +/** + * Updates pointer focus for the container. Re-uses last motion coordinates. + * + * @param container_ptr + */ +wlmtk_element_t *wlmtk_container_update_pointer_focus( + wlmtk_container_t *container_ptr); + /** * Returns the wlroots scene graph tree for this node. * diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 9ac84244..48c88bd2 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -22,6 +22,7 @@ #include "content.h" #define WLR_USE_UNSTABLE +#include #include #include #undef WLR_USE_UNSTABLE @@ -38,11 +39,21 @@ static void element_get_dimensions( int *top_ptr, int *right_ptr, int *bottom_ptr); -static wlmtk_element_t *element_motion( +static void element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); +static void element_pointer_leave(wlmtk_element_t *element_ptr); +static wlmtk_element_t *element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, __UNUSED__ uint32_t time_msec); +static bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); /* == Data ================================================================= */ @@ -51,7 +62,10 @@ const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, - .motion = element_motion, + .get_pointer_area = element_get_pointer_area, + .pointer_leave = element_pointer_leave, + .pointer_motion = element_pointer_motion, + .pointer_button = element_pointer_button, }; void *wlmtk_content_identifier_ptr = wlmtk_content_init; @@ -169,39 +183,154 @@ void element_get_dimensions( /* ------------------------------------------------------------------------- */ /** - * Implementation of the element's motion method: Sets the surface as active - * and -- if (x, y) is within the area -- returns this element's pointer. + * Overwrites the element's get_pointer_area method: Returns the extents of + * the surface and all subsurfaces. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + + struct wlr_box box; + if (NULL == content_ptr->wlr_surface_ptr) { + // DEBT: Should only get initialized with a valid surface. + box.x = 0; + box.y = 0; + box.width = 0; + box.height = 0; + } else { + wlr_surface_get_extends(content_ptr->wlr_surface_ptr, &box); + } + + if (NULL != left_ptr) *left_ptr = box.x; + if (NULL != top_ptr) *top_ptr = box.y; + if (NULL != right_ptr) *right_ptr = box.width - box.x; + if (NULL != bottom_ptr) *bottom_ptr = box.height - box.y; +} + +/* ------------------------------------------------------------------------- */ +void element_pointer_leave(wlmtk_element_t *element_ptr) +{ + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + + // If the current surface's parent is our surface: clear it. + struct wlr_surface *focused_wlr_surface_ptr = + content_ptr->wlr_seat_ptr->pointer_state.focused_surface; + if (NULL != focused_wlr_surface_ptr && + wlr_surface_get_root_surface(focused_wlr_surface_ptr) == + content_ptr->wlr_surface_ptr) { + wlr_seat_pointer_clear_focus(content_ptr->wlr_seat_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +/** + * Pass pointer motion events to client's surface. + * + * Identifies the surface (or sub-surface) at the given coordinates, and pass + * on the motion event to that surface. If needed, will update the seat's + * pointer focus. * * @param element_ptr - * @param x - * @param y + * @param x Pointer horizontal position, relative to this + * element's node. + * @param y Pointer vertical position, relative to this + * element's node. * @param time_msec * - * @return element_ptr + * @return Pointer to this element, if the motion is within the area. */ -wlmtk_element_t *element_motion( +wlmtk_element_t *element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - __UNUSED__ uint32_t time_msec) + uint32_t time_msec) { wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); - // Guard clause: only forward if the motion is inside the content. - int width, height; - wlmtk_content_get_size(content_ptr, &width, &height); - if (x < 0 || width <= x || y < 0 || height <= y) return NULL; + // Get the node below the cursor. Return if there's no buffer node. + double node_x, node_y; + struct wlr_scene_node *wlr_scene_node_ptr = wlr_scene_node_at( + content_ptr->super_element.wlr_scene_node_ptr, x, y, &node_x, &node_y); + if (NULL == wlr_scene_node_ptr || + WLR_SCENE_NODE_BUFFER != wlr_scene_node_ptr->type) { + return NULL; + } - if (NULL != content_ptr->wlr_surface_ptr) { - wlr_seat_pointer_notify_enter( - content_ptr->wlr_seat_ptr, - content_ptr->wlr_surface_ptr, - x, y); + struct wlr_scene_buffer *wlr_scene_buffer_ptr = + wlr_scene_buffer_from_node(wlr_scene_node_ptr); + struct wlr_scene_surface *wlr_scene_surface_ptr = + wlr_scene_surface_try_from_buffer(wlr_scene_buffer_ptr); + if (NULL == wlr_scene_surface_ptr) { + return NULL; } + + BS_ASSERT(content_ptr->wlr_surface_ptr == + wlr_surface_get_root_surface(wlr_scene_surface_ptr->surface)); + wlr_seat_pointer_notify_enter( + content_ptr->wlr_seat_ptr, + wlr_scene_surface_ptr->surface, + node_x, node_y); + wlr_seat_pointer_notify_motion( + content_ptr->wlr_seat_ptr, + time_msec, + node_x, node_y); return element_ptr; } +/* ------------------------------------------------------------------------- */ +/** + * Passes pointer button event further to the focused surface, if any. + * + * The actual passing is handled by `wlr_seat`. Here we just verify that the + * currently-focused surface (or sub-surface) is part of this content. + * + * @param element_ptr + * @param button_event_ptr + * + * @return Whether the button event was consumed. + */ +bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_content_t *content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_content_t, super_element); + + // Complain if the surface isn't part of our responsibility. + struct wlr_surface *focused_wlr_surface_ptr = + content_ptr->wlr_seat_ptr->pointer_state.focused_surface; + if (NULL == focused_wlr_surface_ptr) return false; + BS_ASSERT(content_ptr->wlr_surface_ptr == + wlr_surface_get_root_surface(focused_wlr_surface_ptr)); + + // We're only forwarding PRESSED & RELEASED events. + if (WLMTK_BUTTON_DOWN == button_event_ptr->type || + WLMTK_BUTTON_UP == button_event_ptr->type) { + wlr_seat_pointer_notify_button( + content_ptr->wlr_seat_ptr, + button_event_ptr->time_msec, + button_event_ptr->button, + (button_event_ptr->type == WLMTK_BUTTON_DOWN) ? + WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); + return true; + } + return false; +} + /* == Fake content, useful for unit tests. ================================= */ static void fake_content_destroy( diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 43ea5e1a..64466113 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -48,6 +48,8 @@ bool wlmtk_element_init( memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; + element_ptr->pointer_x = NAN; + element_ptr->pointer_y = NAN; return true; } @@ -136,10 +138,15 @@ void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible) // Nothing to do? if (element_ptr->visible == visible) return; + // FIXME: If visibility changed, update parent container's pointer focus! element_ptr->visible = visible; if (NULL != element_ptr->wlr_scene_node_ptr) { wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, visible); } + + if (NULL != element_ptr->parent_container_ptr) { + wlmtk_container_update_pointer_focus(element_ptr->parent_container_ptr); + } } /* ------------------------------------------------------------------------- */ @@ -180,6 +187,40 @@ void wlmtk_element_get_dimensions( element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + if (NULL != element_ptr->impl_ptr->get_pointer_area) { + element_ptr->impl_ptr->get_pointer_area( + element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); + } else { + wlmtk_element_get_dimensions( + element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +static inline wlmtk_element_t *wlmtk_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec) +{ + // FIXME: Add tests. + element_ptr->last_pointer_x = x; + element_ptr->last_pointer_y = y; + element_ptr->last_pointer_time_msec = time_msec; + + if (NULL == element_ptr->impl_ptr->pointer_motion) return NULL; + return element_ptr->impl_ptr->pointer_motion( + element_ptr, x, y, time_msec); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -212,19 +253,30 @@ static void fake_get_dimensions( int *top_ptr, int *right_ptr, int *bottom_ptr); -static wlmtk_element_t *fake_motion( +static void fake_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); +static wlmtk_element_t *fake_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static void fake_leave( +static bool fake_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void fake_pointer_leave( wlmtk_element_t *element_ptr); const wlmtk_element_impl_t wlmtk_fake_element_impl = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, .get_dimensions = fake_get_dimensions, - .motion = fake_motion, - .leave = fake_leave + .get_pointer_area = fake_get_pointer_area, + .pointer_motion = fake_pointer_motion, + .pointer_button = fake_pointer_button, + .pointer_leave = fake_pointer_leave, }; /* ------------------------------------------------------------------------- */ @@ -281,9 +333,26 @@ void fake_get_dimensions( if (NULL != bottom_ptr) *bottom_ptr = fake_element_ptr->height; } +/* ------------------------------------------------------------------------- */ +/** A "fake" 'get_pointer_area'. */ +void fake_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + if (NULL != left_ptr) *left_ptr = -1; + if (NULL != top_ptr) *top_ptr = -2; + if (NULL != right_ptr) *right_ptr = fake_element_ptr->width + 3; + if (NULL != bottom_ptr) *bottom_ptr = fake_element_ptr->height + 4; +} + /* ------------------------------------------------------------------------- */ /** Handles 'motion' events for the fake element. */ -wlmtk_element_t *fake_motion( +wlmtk_element_t *fake_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -291,20 +360,38 @@ wlmtk_element_t *fake_motion( { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); - fake_element_ptr->motion_called = true; - fake_element_ptr->motion_x = x; - fake_element_ptr->motion_y = y; - return fake_element_ptr->motion_return_value; + fake_element_ptr->pointer_motion_called = true; + fake_element_ptr->pointer_motion_x = x; + fake_element_ptr->pointer_motion_y = y; + // FIXME: Replace with 'this' if x, y in space. + return fake_element_ptr->pointer_motion_return_value; +} + +/* ------------------------------------------------------------------------- */ +/** Handles 'button' events for the fake element. */ +bool fake_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + + fake_element_ptr->pointer_button_called = true; + memcpy( + &fake_element_ptr->pointer_button_event, + button_event_ptr, + sizeof(wlmtk_button_event_t)); + return true; } /* ------------------------------------------------------------------------- */ /** Handles 'leave' events for the fake element. */ -void fake_leave( +void fake_pointer_leave( wlmtk_element_t *element_ptr) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); - fake_element_ptr->leave_called = true; + fake_element_ptr->pointer_leave_called = true; } /* == Unit tests =========================================================== */ @@ -313,14 +400,18 @@ static void test_init_fini(bs_test_t *test_ptr); static void test_set_parent_container(bs_test_t *test_ptr); static void test_set_get_position(bs_test_t *test_ptr); static void test_get_dimensions(bs_test_t *test_ptr); -static void test_motion_leave(bs_test_t *test_ptr); +static void test_get_pointer_area(bs_test_t *test_ptr); +static void test_pointer_motion_leave(bs_test_t *test_ptr); +static void test_pointer_button(bs_test_t *test_ptr); const bs_test_case_t wlmtk_element_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "set_parent_container", test_set_parent_container }, { 1, "set_get_position", test_set_get_position }, { 1, "get_dimensions", test_get_dimensions }, - { 1, "motion_leave", test_motion_leave }, + { 1, "get_pointer_area", test_get_pointer_area }, + { 1, "pointer_motion_leave", test_pointer_motion_leave }, + { 1, "pointer_button", test_pointer_button }, { 0, NULL, NULL } }; @@ -449,21 +540,56 @@ void test_get_dimensions(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Exercises "motion" and "leave" methods. */ -void test_motion_leave(bs_test_t *test_ptr) +/** Tests get_dimensions. */ +void test_get_pointer_area(bs_test_t *test_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); + fake_element_ptr->width = 42; + fake_element_ptr->height = 21; + + // Must not crash. + wlmtk_element_get_pointer_area( + &fake_element_ptr->element, NULL, NULL, NULL, NULL); + + int top, left, right, bottom; + wlmtk_element_get_pointer_area( + &fake_element_ptr->element, &top, &left, &right, &bottom); + BS_TEST_VERIFY_EQ(test_ptr, -1, top); + BS_TEST_VERIFY_EQ(test_ptr, -2, left); + BS_TEST_VERIFY_EQ(test_ptr, 45, right); + BS_TEST_VERIFY_EQ(test_ptr, 25, bottom); +} + +/* ------------------------------------------------------------------------- */ +/** Exercises "pointer_motion" and "pointer_leave" methods. */ +void test_pointer_motion_leave(bs_test_t *test_ptr) { wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); BS_ASSERT(NULL != fake_element_ptr); - wlmtk_element_motion(&fake_element_ptr->element, 1.0, 2.0, 1234); - BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->motion_y); + wlmtk_element_pointer_motion(&fake_element_ptr->element, 1.0, 2.0, 1234); + BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_motion_called); + BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->pointer_motion_x); + BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->pointer_motion_y); - wlmtk_element_leave(&fake_element_ptr->element); - BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->leave_called); + wlmtk_element_pointer_leave(&fake_element_ptr->element); + BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_leave_called); wlmtk_element_destroy(&fake_element_ptr->element); } +/* ------------------------------------------------------------------------- */ +/** Exercises "pointer_button" method. */ +void test_pointer_button(bs_test_t *test_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); + BS_ASSERT(NULL != fake_element_ptr); + + wlmtk_button_event_t event = {}; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(&fake_element_ptr->element, &event)); + BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_button_called); +} + /* == End of toolkit.c ===================================================== */ diff --git a/src/toolkit/element.h b/src/toolkit/element.h index f336e792..29cf1c1a 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -32,6 +32,8 @@ typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; typedef struct _wlmtk_container_t wlmtk_container_t; struct wlr_scene_tree; +#include "button.h" + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -59,12 +61,20 @@ struct _wlmtk_element_t { /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ struct wl_listener wlr_scene_node_destroy_listener; + + /** Pointer horizontal position of last motion(). */ + double last_pointer_x; + /** Pointer vertical position of last motion(). */ + double last_pointer_y; + /** Time of last motion() call. */ + uint32_t last_pointer_time_msec; }; /** Pointers to the implementation of Element's virtual methods. */ struct _wlmtk_element_impl_t { /** Destroys the implementation of the element. */ void (*destroy)(wlmtk_element_t *element_ptr); + /** Creates element's scene graph API node, child to wlr_scene_tree_ptr. */ struct wlr_scene_node *(*create_scene_node)( wlmtk_element_t *element_ptr, @@ -78,12 +88,34 @@ struct _wlmtk_element_impl_t { int *right_ptr, int *bottom_ptr); - /** Indicates pointer motion into or within the element area to (x,y). */ - wlmtk_element_t *(*motion)(wlmtk_element_t *element_ptr, - double x, double y, - uint32_t time_msec); + /** Gets element area to accept pointer activity, relative to position. */ + void (*get_pointer_area)( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); + + /** + * Indicates pointer motion into or within the element area to (x,y). + * + * @param element_ptr + * @param x + * @param y + * @param time_msec + * + * @return A pointer to the element handling the motion. + * FIXME: Or just a bool? + */ + wlmtk_element_t *(*pointer_motion)(wlmtk_element_t *element_ptr, + double x, double y, + uint32_t time_msec); + /** Indicates pointer button event. */ + bool (*pointer_button)(wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); + /** Indicates the pointer has left the element's area. */ - void (*leave)(wlmtk_element_t *element_ptr); + void (*pointer_leave)(wlmtk_element_t *element_ptr); }; /** @@ -197,23 +229,54 @@ void wlmtk_element_get_dimensions( int *right_ptr, int *bottom_ptr); -/** Virtual method: Calls 'motion' for the element's implementation. */ -static inline wlmtk_element_t *wlmtk_element_motion( +/** + * Gets the area that the element on which the element accepts pointer events. + * + * The area extents are relative to the element's position. By default, this + * overlaps with the element dimensions. Some elements (eg. a surface with + * further-extending sub-surfaces) may differ. + * + * @param element_ptr + * @param left_ptr Leftmost position of pointer area. May be NULL. + * @param top_ptr Topmost position of pointer area. May be NULL. + * @param right_ptr Rightmost position of pointer area. May be NULL. + * @param bottom_ptr Bottommost position of pointer area. May be NULL. + */ +void wlmtk_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); + +/** + Virtual method: Calls 'pointer_motion' for the element's implementation. +*/ +wlmtk_element_t *wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - uint32_t time_msec) { - if (NULL == element_ptr->impl_ptr->motion) return NULL; - return element_ptr->impl_ptr->motion(element_ptr, x, y, time_msec); + uint32_t time_msec); + +/** Virtual method: calls 'button' for the element's implementation. */ +static inline bool wlmtk_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + if (NULL == element_ptr->impl_ptr->pointer_button) return false; + return element_ptr->impl_ptr->pointer_button( + element_ptr, button_event_ptr); } -/** Virtual method: Calls 'leave' for the element's implementation. */ -static inline void wlmtk_element_leave( +/** Virtual method: Calls 'pointer_leave' for the element's implementation. */ +static inline void wlmtk_element_pointer_leave( wlmtk_element_t *element_ptr) { - if (NULL != element_ptr->impl_ptr->leave) { - element_ptr->impl_ptr->leave(element_ptr); + if (NULL != element_ptr->impl_ptr->pointer_leave) { + element_ptr->impl_ptr->pointer_leave(element_ptr); } + element_ptr->pointer_x = NAN; + element_ptr->pointer_y = NAN; } /** @@ -240,17 +303,21 @@ typedef struct { /** Height of the element, in pixels. */ int height; - /** Indicates that Element::motion() was called. */ - bool motion_called; - /** The x argument of the last Element::motion() call. */ - double motion_x; - /** The y arguemnt of the last element::motion() call. */ - double motion_y; - /** Return value to pass when motion is called. */ - wlmtk_element_t *motion_return_value; - - /** Indicates that Element::leave() was called. */ - bool leave_called; + /** Indicates that Element::pointer_motion() was called. */ + bool pointer_motion_called; + /** The x argument of the last Element::pointer_motion() call. */ + double pointer_motion_x; + /** The y arguemnt of the last element::pointer_motion() call. */ + double pointer_motion_y; + /** Return value to pass when pointer_motion is called. */ + wlmtk_element_t *pointer_motion_return_value; + + /** Indicates that Element::pointer_leave() was called. */ + bool pointer_leave_called; + + /** Indicates that Element::pointer_button() was called. */ + bool pointer_button_called; + wlmtk_button_event_t pointer_button_event; } wlmtk_fake_element_t; /** Ctor for the fake element. */ diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 38991a3c..dcf5c5a2 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -40,9 +40,9 @@ class Element { {abstract}#void destroy() {abstract}#struct wlr_scene_node *create_scene_node(parent_node*) - #void motion(double, double) - #void leave() - {abstract}#void click() + #void pointer_motion(double, double) + #void pointer_button(wlmtk_button_event_t) + #void pointer_leave() } note right of Element::"set_parent_container(Container*)" Will invoke set_parent_container. diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 6d5bb391..e5f6f3f4 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -121,17 +121,49 @@ wlmtk_workspace_t *wlmtk_workspace_from_container( } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_handle_button( +bool wlmtk_workspace_motion( wlmtk_workspace_t *workspace_ptr, - const struct wlr_pointer_button_event *event_ptr, double x, - double y) + double y, + uint32_t time_msec) { - bs_log(BS_INFO, "Workspace %p: button event %p ad %.0f, %.0f", - workspace_ptr, event_ptr, x, y); + wlmtk_element_t *element_ptr = wlmtk_element_pointer_motion( + &workspace_ptr->super_container.super_element, x, y, time_msec); + return element_ptr != NULL; +} + +/* ------------------------------------------------------------------------- */ +// FIXME : Add tests for button. +void wlmtk_workspace_button( + wlmtk_workspace_t *workspace_ptr, + const struct wlr_pointer_button_event *event_ptr) +{ + wlmtk_button_event_t event; + wlmtk_element_t *focused_element_ptr; + + // Guard clause: nothing to pass on if no element has the focus. + focused_element_ptr = + workspace_ptr->super_container.pointer_focus_element_ptr; + if (NULL == focused_element_ptr) return; + + event.button = event_ptr->button; if (WLR_BUTTON_PRESSED == event_ptr->state) { - // Pass BUTTON_DOWN. + event.type = WLMTK_BUTTON_DOWN; + wlmtk_element_pointer_button(focused_element_ptr, &event); + + } else if (WLR_BUTTON_RELEASED == event_ptr->state) { + event.type = WLMTK_BUTTON_UP; + wlmtk_element_pointer_button(focused_element_ptr, &event); + event.type = WLMTK_BUTTON_CLICK; + wlmtk_element_pointer_button(focused_element_ptr, &event); + + } else { + bs_log(BS_WARNING, + "Workspace %p: Unhandled state 0x%x for button 0x%x", + workspace_ptr, event_ptr->state, event_ptr->button); } + + event = event; } /* == Local (static) methods =============================================== */ diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 1cc74276..bdbfefb1 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -83,6 +83,15 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_workspace_t *wlmtk_workspace_from_container( wlmtk_container_t *container_ptr); +/** + * Handles a motion event. + */ +bool wlmtk_workspace_motion( + wlmtk_workspace_t *workspace_ptr, + double x, + double y, + uint32_t time_msec); + /** * Handles a button event: Translates to button down/up/click/dblclick events. * @@ -92,16 +101,14 @@ wlmtk_workspace_t *wlmtk_workspace_from_container( * DRAG event. * These events will be forwarded to the event currently having pointer focus. * + * TODO(kaeser@gubbe.ch): Implement DOUBLE_CLICK and DRAG events. + * * @param workspace_ptr * @paran event_ptr - * @param x - * @param y */ -void wlmtk_workspace_handle_button( +void wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, - const struct wlr_pointer_button_event *event_ptr, - double x, - double y); + const struct wlr_pointer_button_event *event_ptr); /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 2250728a..839674df 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -39,6 +39,9 @@ typedef struct { struct wl_listener surface_map_listener; /** Listener for the `unmap` signal of the `wlr_surface`. */ struct wl_listener surface_unmap_listener; + + /** Listener for the `move` signal of the `wlr_xdg_toplevel`. */ + struct wl_listener toplevel_request_move_listener; } wlmtk_xdg_toplevel_content_t; static wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( @@ -54,6 +57,9 @@ static void handle_surface_map( static void handle_surface_unmap( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_request_move( + struct wl_listener *listener_ptr, + void *data_ptr); static void content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *content_create_scene_node( @@ -128,8 +134,18 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &xdg_tl_content_ptr->surface_unmap_listener, handle_surface_unmap); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.request_move, + &xdg_tl_content_ptr->toplevel_request_move_listener, + handle_toplevel_request_move); + xdg_tl_content_ptr->wlr_xdg_surface_ptr->data = &xdg_tl_content_ptr->super_content; + + // FIXME + xdg_tl_content_ptr->super_content.wlr_surface_ptr = + xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface; + return xdg_tl_content_ptr; } @@ -137,6 +153,8 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( void xdg_toplevel_content_destroy( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) { + wl_list_remove(&xdg_tl_content_ptr->toplevel_request_move_listener.link); + wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); @@ -196,9 +214,11 @@ void content_get_size( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + // FIXME -> this should be get_pointer_area ! struct wlr_box geo_box; wlr_xdg_surface_get_geometry( xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->base, &geo_box); + // FIXME -- WARNING: THIS HAS A x AND y WITH RELATIVE POSITION!! if (NULL != width_ptr) *width_ptr = geo_box.width; if (NULL != height_ptr) *height_ptr = geo_box.height; } @@ -237,6 +257,7 @@ void content_set_activated( } } else { BS_ASSERT(xdg_tl_content_ptr->activated); + // FIXME: This clears pointer focus. But, this is keyboard focus? if (wlr_seat_ptr->keyboard_state.focused_surface == xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface) { wlr_seat_pointer_clear_focus(wlr_seat_ptr); @@ -292,4 +313,24 @@ void handle_surface_unmap( window_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `reuqest_move` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_request_move( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_content_t, + toplevel_request_move_listener); + + bs_log(BS_INFO, "XDG toplevel content %p: Request move", + xdg_tl_content_ptr); +} + /* == End of xdg_toplevel.c ================================================ */ diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index aefe5ac4..107738fc 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -686,6 +686,4 @@ void handle_toplevel_set_app_id(struct wl_listener *listener_ptr, xdg_toplevel_ptr->wlr_xdg_surface_ptr->toplevel->app_id); } -/* ######################################################################### */ - /* == End of xdg_toplevel.c ================================================ */ From bba6eb6d38f5a55d17456f454a11f3ce11424147 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 16 Oct 2023 16:43:20 +0200 Subject: [PATCH 084/390] Fixes compile errors. --- src/toolkit/container.c | 6 +++--- src/toolkit/element.c | 6 +++--- src/toolkit/element.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 88c42d14..2e014b9e 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -143,9 +143,9 @@ wlmtk_element_t *wlmtk_container_update_pointer_focus( { return update_pointer_focus_at( container_ptr, - container_ptr->super_element.pointer_x, - container_ptr->super_element.pointer_y, - container_ptr->super_element.pointer_time_msec); + container_ptr->super_element.last_pointer_x, + container_ptr->super_element.last_pointer_y, + container_ptr->super_element.last_pointer_time_msec); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 64466113..0566f4e8 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -48,8 +48,8 @@ bool wlmtk_element_init( memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; - element_ptr->pointer_x = NAN; - element_ptr->pointer_y = NAN; + element_ptr->last_pointer_x = NAN; + element_ptr->last_pointer_y = NAN; return true; } @@ -205,7 +205,7 @@ void wlmtk_element_get_pointer_area( } /* ------------------------------------------------------------------------- */ -static inline wlmtk_element_t *wlmtk_element_pointer_motion( +wlmtk_element_t *wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 29cf1c1a..ca61289b 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -275,8 +275,8 @@ static inline void wlmtk_element_pointer_leave( if (NULL != element_ptr->impl_ptr->pointer_leave) { element_ptr->impl_ptr->pointer_leave(element_ptr); } - element_ptr->pointer_x = NAN; - element_ptr->pointer_y = NAN; + element_ptr->last_pointer_x = NAN; + element_ptr->last_pointer_y = NAN; } /** From 60622e969ed6be6d2efc4673e989c6a82efaa2d9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 16 Oct 2023 20:32:19 +0200 Subject: [PATCH 085/390] Applies the fix for showing output on backends without modes. --- src/output.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/output.c b/src/output.c index b90f7423..d482d351 100644 --- a/src/output.c +++ b/src/output.c @@ -83,12 +83,14 @@ wlmaker_output_t *wlmaker_output_create( if (!wl_list_empty(&output_ptr->wlr_output_ptr->modes)) { struct wlr_output_mode *mode_ptr = wlr_output_preferred_mode(output_ptr->wlr_output_ptr); wlr_output_set_mode(output_ptr->wlr_output_ptr, mode_ptr); - wlr_output_enable(output_ptr->wlr_output_ptr, true); - if (!wlr_output_commit(output_ptr->wlr_output_ptr)) { - bs_log(BS_ERROR, "Failed wlr_output_commit()"); - wlmaker_output_destroy(output_ptr); - return NULL; - } + } + + // Enable the output and commit. + wlr_output_enable(output_ptr->wlr_output_ptr, true); + if (!wlr_output_commit(output_ptr->wlr_output_ptr)) { + bs_log(BS_ERROR, "Failed wlr_output_commit()"); + wlmaker_output_destroy(output_ptr); + return NULL; } return output_ptr; From 23495dc4d6bfd82fa69d6cbb3a8f02d936fb500e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 16 Oct 2023 20:48:56 +0200 Subject: [PATCH 086/390] Adds tests on storing last pointer position. --- src/toolkit/container.c | 18 +++++++------- src/toolkit/element.c | 52 +++++++++++++++++++++++++++++++++-------- src/toolkit/element.h | 51 ++++++++++++++++++++++++---------------- 3 files changed, 81 insertions(+), 40 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 2e014b9e..85134631 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -669,16 +669,14 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); // elem1 is at (-20, -40). - elem1_ptr->pointer_motion_x = 42; - elem1_ptr->pointer_motion_y = 42; BS_TEST_VERIFY_NEQ( test_ptr, NULL, wlmtk_element_pointer_motion(&container.super_element, -20, -40, 7)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); elem1_ptr->pointer_motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_y); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_y); BS_TEST_VERIFY_NEQ( test_ptr, NULL, @@ -687,8 +685,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); elem1_ptr->pointer_motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->pointer_motion_y); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_x); + BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_y); // elem2 is covering the area at (107, 302). BS_TEST_VERIFY_NEQ( @@ -700,8 +698,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_motion_called); elem2_ptr->pointer_motion_called = false; - BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->pointer_motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->pointer_motion_y); + BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->element.last_pointer_x); + BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->element.last_pointer_y); // The pointer area of elem2 is covering the area at (112, 208). BS_TEST_VERIFY_NEQ( @@ -712,8 +710,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_motion_called); elem2_ptr->pointer_motion_called = false; - BS_TEST_VERIFY_EQ(test_ptr, 12, elem2_ptr->pointer_motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 8, elem2_ptr->pointer_motion_y); + BS_TEST_VERIFY_EQ(test_ptr, 12, elem2_ptr->element.last_pointer_x); + BS_TEST_VERIFY_EQ(test_ptr, 8, elem2_ptr->element.last_pointer_y); // The pointer area of elem2 does not include (113, 209). BS_TEST_VERIFY_EQ( diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 0566f4e8..7f4d43a9 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -48,8 +48,10 @@ bool wlmtk_element_init( memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->impl_ptr = element_impl_ptr; + element_ptr->last_pointer_x = NAN; element_ptr->last_pointer_y = NAN; + element_ptr->last_pointer_time_msec = 0; return true; } @@ -211,16 +213,29 @@ wlmtk_element_t *wlmtk_element_pointer_motion( double y, uint32_t time_msec) { - // FIXME: Add tests. element_ptr->last_pointer_x = x; element_ptr->last_pointer_y = y; element_ptr->last_pointer_time_msec = time_msec; + // Guard clause: No implementation for `pointer_motion`. if (NULL == element_ptr->impl_ptr->pointer_motion) return NULL; - return element_ptr->impl_ptr->pointer_motion( + + return element_ptr->impl_ptr->pointer_motion( element_ptr, x, y, time_msec); } +/* ------------------------------------------------------------------------- */ +void wlmtk_element_pointer_leave( + wlmtk_element_t *element_ptr) +{ + if (NULL != element_ptr->impl_ptr->pointer_leave) { + element_ptr->impl_ptr->pointer_leave(element_ptr); + } + element_ptr->last_pointer_x = NAN; + element_ptr->last_pointer_y = NAN; + element_ptr->last_pointer_time_msec = 0; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -354,16 +369,13 @@ void fake_get_pointer_area( /** Handles 'motion' events for the fake element. */ wlmtk_element_t *fake_pointer_motion( wlmtk_element_t *element_ptr, - double x, - double y, + __UNUSED__ double x, + __UNUSED__ double y, __UNUSED__ uint32_t time_msec) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); fake_element_ptr->pointer_motion_called = true; - fake_element_ptr->pointer_motion_x = x; - fake_element_ptr->pointer_motion_y = y; - // FIXME: Replace with 'this' if x, y in space. return fake_element_ptr->pointer_motion_return_value; } @@ -567,13 +579,33 @@ void test_pointer_motion_leave(bs_test_t *test_ptr) wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); BS_ASSERT(NULL != fake_element_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + isnan(fake_element_ptr->element.last_pointer_x)); + BS_TEST_VERIFY_TRUE( + test_ptr, + isnan(fake_element_ptr->element.last_pointer_y)); + wlmtk_element_pointer_motion(&fake_element_ptr->element, 1.0, 2.0, 1234); - BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_motion_called); - BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->pointer_motion_x); - BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->pointer_motion_y); + BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->element.last_pointer_x); + BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->element.last_pointer_y); + BS_TEST_VERIFY_EQ( + test_ptr, + 1234, + fake_element_ptr->element.last_pointer_time_msec); wlmtk_element_pointer_leave(&fake_element_ptr->element); BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_leave_called); + BS_TEST_VERIFY_TRUE( + test_ptr, + isnan(fake_element_ptr->element.last_pointer_x)); + BS_TEST_VERIFY_TRUE( + test_ptr, + isnan(fake_element_ptr->element.last_pointer_y)); + BS_TEST_VERIFY_EQ( + test_ptr, + 0, + fake_element_ptr->element.last_pointer_time_msec); wlmtk_element_destroy(&fake_element_ptr->element); } diff --git a/src/toolkit/element.h b/src/toolkit/element.h index ca61289b..f8cbb292 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -62,11 +62,23 @@ struct _wlmtk_element_t { /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ struct wl_listener wlr_scene_node_destroy_listener; - /** Pointer horizontal position of last motion(). */ + /** + * Horizontal pointer position from last @ref wlmtk_element_pointer_motion + * call. NAN if there was no motion call yet, or if @ref + * wlmtk_element_pointer_leave was called since. + * + * Does not imply that the element has pointer focus. + */ double last_pointer_x; - /** Pointer vertical position of last motion(). */ + /** + * Vertical pointer position from last @ref wlmtk_element_pointer_motion + * call. NAN if there was no motion call yet, or if @ref + * wlmtk_element_pointer_leave was called since. + * + * Does not imply that the element has pointer focus. + */ double last_pointer_y; - /** Time of last motion() call. */ + /** Time of last @ref wlmtk_element_pointer_motion call, 0 otherwise. */ uint32_t last_pointer_time_msec; }; @@ -250,14 +262,28 @@ void wlmtk_element_get_pointer_area( int *bottom_ptr); /** - Virtual method: Calls 'pointer_motion' for the element's implementation. -*/ + * Virtual method: Calls 'pointer_motion' for the element's implementation. + * + * Also updates wlmtk_element_t::last_pointer_x, + * wlmtk_element_t::last_pointer_y and wlmtk_element_t::last_pointer_time_msec. + * + * @param element_ptr + * @param x + * @param y + * @param time_msec + */ wlmtk_element_t *wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); +/** + * Virtual method: Calls 'pointer_leave' for the element's implementation. + */ +void wlmtk_element_pointer_leave( + wlmtk_element_t *element_ptr); + /** Virtual method: calls 'button' for the element's implementation. */ static inline bool wlmtk_element_pointer_button( wlmtk_element_t *element_ptr, @@ -268,17 +294,6 @@ static inline bool wlmtk_element_pointer_button( element_ptr, button_event_ptr); } -/** Virtual method: Calls 'pointer_leave' for the element's implementation. */ -static inline void wlmtk_element_pointer_leave( - wlmtk_element_t *element_ptr) -{ - if (NULL != element_ptr->impl_ptr->pointer_leave) { - element_ptr->impl_ptr->pointer_leave(element_ptr); - } - element_ptr->last_pointer_x = NAN; - element_ptr->last_pointer_y = NAN; -} - /** * Virtual method: Calls the dtor of the element's implementation. * @@ -305,10 +320,6 @@ typedef struct { /** Indicates that Element::pointer_motion() was called. */ bool pointer_motion_called; - /** The x argument of the last Element::pointer_motion() call. */ - double pointer_motion_x; - /** The y arguemnt of the last element::pointer_motion() call. */ - double pointer_motion_y; /** Return value to pass when pointer_motion is called. */ wlmtk_element_t *pointer_motion_return_value; From b32eb166ccc1198a4f8afdf43627a6d39d8617d2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 12:13:10 +0200 Subject: [PATCH 087/390] Adds method for recomputing pointer focus for entire tree. --- src/toolkit/container.c | 34 +++++++++++++++++++++++----------- src/toolkit/container.h | 7 +++++-- src/toolkit/element.c | 6 ++---- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 85134631..062ddb48 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -120,7 +120,7 @@ void wlmtk_container_add_element( // Need to re-compute pointer focus, since we might have added an element // below the current cursor position. - wlmtk_container_update_pointer_focus(container_ptr); + wlmtk_container_pointer_refocus_tree(container_ptr); } /* ------------------------------------------------------------------------- */ @@ -134,25 +134,37 @@ void wlmtk_container_remove_element( bs_dllist_remove( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); - wlmtk_container_update_pointer_focus(container_ptr); + + // We can be more lenient in asking for re-focus: If the removed element + // is NOT having pointer focus, we won't have to bother. + if (element_ptr == container_ptr->pointer_focus_element_ptr) { + wlmtk_container_pointer_refocus_tree(container_ptr); + } + BS_ASSERT(element_ptr != container_ptr->pointer_focus_element_ptr); } /* ------------------------------------------------------------------------- */ -wlmtk_element_t *wlmtk_container_update_pointer_focus( +struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( wlmtk_container_t *container_ptr) { - return update_pointer_focus_at( - container_ptr, - container_ptr->super_element.last_pointer_x, - container_ptr->super_element.last_pointer_y, - container_ptr->super_element.last_pointer_time_msec); + return container_ptr->wlr_scene_tree_ptr; } /* ------------------------------------------------------------------------- */ -struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( - wlmtk_container_t *container_ptr) +void wlmtk_container_pointer_refocus_tree(wlmtk_container_t *container_ptr) { - return container_ptr->wlr_scene_tree_ptr; + // Guard clause: Don't throw over if there's no container. + if (NULL == container_ptr) return; + + while (NULL != container_ptr->super_element.parent_container_ptr) { + container_ptr = container_ptr->super_element.parent_container_ptr; + } + + update_pointer_focus_at( + container_ptr, + container_ptr->super_element.last_pointer_x, + container_ptr->super_element.last_pointer_y, + container_ptr->super_element.last_pointer_time_msec); } /* == Local (static) methods =============================================== */ diff --git a/src/toolkit/container.h b/src/toolkit/container.h index db090944..b69d03ee 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -108,11 +108,14 @@ void wlmtk_container_remove_element( wlmtk_element_t *element_ptr); /** - * Updates pointer focus for the container. Re-uses last motion coordinates. + * Re-computes pointer focus for the entire container tree. + * + * Will retract to the top of parent containers, and then (re)compute the + * pointer focus from there. * * @param container_ptr */ -wlmtk_element_t *wlmtk_container_update_pointer_focus( +void wlmtk_container_pointer_refocus_tree( wlmtk_container_t *container_ptr); /** diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 7f4d43a9..a5e23a7b 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -140,15 +140,13 @@ void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible) // Nothing to do? if (element_ptr->visible == visible) return; - // FIXME: If visibility changed, update parent container's pointer focus! element_ptr->visible = visible; if (NULL != element_ptr->wlr_scene_node_ptr) { wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, visible); } - if (NULL != element_ptr->parent_container_ptr) { - wlmtk_container_update_pointer_focus(element_ptr->parent_container_ptr); - } + // Changing visibility may lose or re-gain focus. Re-compute thta. + wlmtk_container_pointer_refocus_tree(element_ptr->parent_container_ptr); } /* ------------------------------------------------------------------------- */ From baf02a23a42d6d3e70b74089cb90fdc49c78e190 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 12:46:51 +0200 Subject: [PATCH 088/390] Adds an initial testcase to verify layered refocus. --- src/toolkit/container.c | 51 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 062ddb48..e01b638b 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -514,6 +514,7 @@ static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); static void test_pointer_motion(bs_test_t *test_ptr); static void test_pointer_focus(bs_test_t *test_ptr); +static void test_pointer_focus_layered(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, @@ -521,6 +522,7 @@ const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, { 1, "pointer_motion", test_pointer_motion }, { 1, "pointer_focus", test_pointer_focus }, + { 1, "pointer_focus_layered", test_pointer_focus_layered }, { 0, NULL, NULL } }; @@ -841,9 +843,50 @@ void test_pointer_focus(bs_test_t *test_ptr) wlmtk_container_fini(&container); } -/* - * TODO(kaeser@gubbe.ch): Extend tests to verify parent container is upated - * when focus falls through. - */ +/* ------------------------------------------------------------------------- */ +/** Tests that pointer focus is updated across layers of containers. */ +void test_pointer_focus_layered(bs_test_t *test_ptr) +{ + wlmtk_container_t container1; + BS_ASSERT(wlmtk_container_init(&container1, &wlmtk_container_fake_impl)); + wlmtk_container_t container2; + BS_ASSERT(wlmtk_container_init(&container2, &wlmtk_container_fake_impl)); + wlmtk_element_set_visible(&container2.super_element, true); + + wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); + elem1_ptr->pointer_motion_return_value = &elem1_ptr->element; + wlmtk_element_set_visible(&elem1_ptr->element, true); + wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); + elem2_ptr->pointer_motion_return_value = &elem2_ptr->element; + wlmtk_element_set_visible(&elem2_ptr->element, true); + + // Prepare: Motion was called, will not have any focus. + wlmtk_element_pointer_motion(&container1.super_element, 0, 0, 7); + BS_TEST_VERIFY_EQ(test_ptr, NULL, container1.pointer_focus_element_ptr); + + // Case 1: Add element 2 to second container, then add this container. + // this must re-trigger focus and pass it to elem2. + wlmtk_container_add_element(&container2, &elem2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + container1.pointer_focus_element_ptr); + wlmtk_container_add_element(&container1, &container2.super_element); + BS_TEST_VERIFY_EQ( + test_ptr, + &container2.super_element, + container1.pointer_focus_element_ptr); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem2_ptr->element, container2.pointer_focus_element_ptr); + + wlmtk_container_remove_element(&container2, &elem2_ptr->element); + wlmtk_element_destroy(&elem2_ptr->element); + wlmtk_element_destroy(&elem1_ptr->element); + + wlmtk_container_remove_element(&container1, &container2.super_element); + wlmtk_container_fini(&container2); + wlmtk_container_fini(&container1); +} /* == End of container.c =================================================== */ From da1428fd761811dd7da783b4d7cf12a51871ab88 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 16:02:04 +0200 Subject: [PATCH 089/390] Adds one more testcase. --- src/toolkit/container.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index e01b638b..a541e9fa 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -880,6 +880,17 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) test_ptr, &elem2_ptr->element, container2.pointer_focus_element_ptr); + // Case 2: Add elem1 to container1. Must change focus there, and call + // leave for container2 and elem2. + elem2_ptr->pointer_leave_called = false; + wlmtk_container_add_element(&container1, &elem1_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container1.pointer_focus_element_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_leave_called); + + wlmtk_container_remove_element(&container1, &elem1_ptr->element); wlmtk_container_remove_element(&container2, &elem2_ptr->element); wlmtk_element_destroy(&elem2_ptr->element); wlmtk_element_destroy(&elem1_ptr->element); From f661086618727913566903ebe2eb3a9b46a2ae43 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 16:06:14 +0200 Subject: [PATCH 090/390] Change behaviour of wlmtk_container_add_element to add new elements in front. --- src/toolkit/container.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index a541e9fa..ce299b80 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -113,7 +113,7 @@ void wlmtk_container_add_element( { BS_ASSERT(NULL == element_ptr->parent_container_ptr); - bs_dllist_push_back( + bs_dllist_push_front( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); wlmtk_element_set_parent_container(element_ptr, container_ptr); @@ -784,22 +784,22 @@ void test_pointer_focus(bs_test_t *test_ptr) &elem1_ptr->element, container.pointer_focus_element_ptr); - // Case 4: Add another visible element. Focus remains, though. + // Case 4: Add another visible element. Focus changes, since in front. wlmtk_container_add_element(&container, &elem2_ptr->element); BS_TEST_VERIFY_EQ( test_ptr, - &elem1_ptr->element, + &elem2_ptr->element, container.pointer_focus_element_ptr); - // Case 5: Elem1 (added first = in front) becomes invisible. Focus changes. - wlmtk_element_set_visible(&elem1_ptr->element, false); + // Case 5: Elem2 (added last = in front) becomes invisible. Focus changes. + wlmtk_element_set_visible(&elem2_ptr->element, false); BS_TEST_VERIFY_EQ( test_ptr, - &elem2_ptr->element, + &elem1_ptr->element, container.pointer_focus_element_ptr); - // Case 6: Elem2 becomes invisible. Focus changes to NULL. - wlmtk_element_set_visible(&elem2_ptr->element, false); + // Case 6: Elem1 becomes invisible. Focus changes to NULL. + wlmtk_element_set_visible(&elem1_ptr->element, false); BS_TEST_VERIFY_EQ( test_ptr, NULL, From 916acebd5b99c9671da51ab86fb41b8e83498792 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 16:06:15 +0200 Subject: [PATCH 091/390] Change behaviour of wlmtk_container_add_element to add new elements in front. --- src/toolkit/container.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/toolkit/container.h b/src/toolkit/container.h index b69d03ee..d8a543a3 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -86,7 +86,8 @@ void wlmtk_container_fini( /** * Adds `element_ptr` to the container. * - * Requires that `element_ptr` is not added to a container yet. + * Requires that `element_ptr` is not added to a container yet. The element + * will be added at the front of the container. * * * @param container_ptr * @param element_ptr From c98c04f55d25b43b6c5802d7f9a718a42d82ca2b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 16:10:44 +0200 Subject: [PATCH 092/390] Adds 2 more testcases for layered containers. Wraps it up. --- src/toolkit/container.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index ce299b80..39d267ff 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -890,8 +890,30 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) container1.pointer_focus_element_ptr); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_leave_called); - wlmtk_container_remove_element(&container1, &elem1_ptr->element); + // Case 3: Bring container2 in front. Now elem2 has focus. + elem1_ptr->pointer_leave_called = false; + wlmtk_container_remove_element(&container1, &container2.super_element); + wlmtk_container_add_element(&container1, &container2.super_element); + BS_TEST_VERIFY_EQ( + test_ptr, + &container2.super_element, + container1.pointer_focus_element_ptr); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem2_ptr->element, + container2.pointer_focus_element_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_leave_called); + + // Case 4: Remove elem2, drop focus back to elem1. + elem2_ptr->pointer_leave_called = false; wlmtk_container_remove_element(&container2, &elem2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container1.pointer_focus_element_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_leave_called); + + wlmtk_container_remove_element(&container1, &elem1_ptr->element); wlmtk_element_destroy(&elem2_ptr->element); wlmtk_element_destroy(&elem1_ptr->element); From c99886e193043114db6c7d42e48520c44db3755a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 16:30:21 +0200 Subject: [PATCH 093/390] Fixes return handling of readlink. --- src/xdg_shell.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 2bc5dd1a..fc05dead 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -126,7 +126,13 @@ void handle_new_surface(struct wl_listener *listener_ptr, char path_procps[PATH_MAX], path_exe[PATH_MAX]; snprintf(path_procps, sizeof(path_procps), "/proc/%"PRIdMAX"/exe", (intmax_t)pid); - readlink(path_procps, path_exe, sizeof(path_exe)); + ssize_t rv = readlink(path_procps, path_exe, sizeof(path_exe)); + if (0 > rv || (size_t)rv >= sizeof(path_exe)) { + bs_log(BS_WARNING | BS_ERRNO, "Failed readlink(%s, %p, %zu)", + path_procps, path_exe, sizeof(path_exe)); + break; + } + path_exe[rv] = '\0'; if (0 == strcmp(path_exe, "/usr/bin/foot")) { wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); From 08c92018e38c059ba3af2eac74fd30cf31fd9f22 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 17:03:26 +0200 Subject: [PATCH 094/390] Fixes handling of fake parent in workspace. --- src/toolkit/workspace.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index e5f6f3f4..fab9ff01 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -67,9 +67,9 @@ wlmtk_workspace_t *wlmtk_workspace_create( } workspace_ptr->fake_parent.wlr_scene_tree_ptr = wlr_scene_tree_ptr; - wlmtk_element_set_parent_container( - &workspace_ptr->super_container.super_element, - &workspace_ptr->fake_parent); + wlmtk_container_add_element( + &workspace_ptr->fake_parent, + &workspace_ptr->super_container.super_element); wlmtk_element_set_visible( &workspace_ptr->super_container.super_element, true); @@ -79,9 +79,9 @@ wlmtk_workspace_t *wlmtk_workspace_create( /* ------------------------------------------------------------------------- */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) { - wlmtk_element_set_parent_container( - &workspace_ptr->super_container.super_element, - NULL); + wlmtk_container_remove_element( + &workspace_ptr->fake_parent, + &workspace_ptr->super_container.super_element); wlmtk_container_fini(&workspace_ptr->super_container); free(workspace_ptr); From 926549d47b7c75271d5a9ef9c08fae93e0c452d0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 17:03:58 +0200 Subject: [PATCH 095/390] Adds pass-through of pointer button events to focussed element. --- src/toolkit/container.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 39d267ff..06ce971e 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -50,6 +50,9 @@ static wlmtk_element_t *element_pointer_motion( uint32_t time_msec); static void element_pointer_leave( wlmtk_element_t *element_ptr); +static bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -67,7 +70,8 @@ static const wlmtk_element_impl_t super_element_impl = { .get_dimensions = element_get_dimensions, .get_pointer_area = element_get_pointer_area, .pointer_motion = element_pointer_motion, - .pointer_leave = element_pointer_leave + .pointer_leave = element_pointer_leave, + .pointer_button = element_pointer_button }; /* == Exported methods ===================================================== */ @@ -346,6 +350,20 @@ void element_pointer_leave(wlmtk_element_t *element_ptr) container_ptr->pointer_focus_element_ptr = NULL; } +/* ------------------------------------------------------------------------- */ +bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + if (NULL == container_ptr->pointer_focus_element_ptr) return false; + + return wlmtk_element_pointer_button( + container_ptr->pointer_focus_element_ptr, + button_event_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. From b4a2d6b6cbf185727b89a324662d69766dcdd5a9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 17:14:28 +0200 Subject: [PATCH 096/390] Adds a testcase for forwarding pointer button events through container. --- src/toolkit/container.c | 74 ++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 06ce971e..d81990d3 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -48,11 +48,11 @@ static wlmtk_element_t *element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static void element_pointer_leave( - wlmtk_element_t *element_ptr); static bool element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); +static void element_pointer_leave( + wlmtk_element_t *element_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -70,8 +70,8 @@ static const wlmtk_element_impl_t super_element_impl = { .get_dimensions = element_get_dimensions, .get_pointer_area = element_get_pointer_area, .pointer_motion = element_pointer_motion, + .pointer_button = element_pointer_button, .pointer_leave = element_pointer_leave, - .pointer_button = element_pointer_button }; /* == Exported methods ===================================================== */ @@ -335,22 +335,14 @@ wlmtk_element_t *element_pointer_motion( /* ------------------------------------------------------------------------- */ /** - * Implementation of the element's leave method: Forwards it to the element - * currently having pointer focus, and clears that. + * Implementation of the element's pointer_button() method. Forwards it to the + * element currently having pointer focus. * * @param element_ptr + * @param button_event_ptr + * + * @return true if the button was handled. */ -void element_pointer_leave(wlmtk_element_t *element_ptr) -{ - wlmtk_container_t *container_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_container_t, super_element); - if (NULL == container_ptr->pointer_focus_element_ptr) return; - - wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); - container_ptr->pointer_focus_element_ptr = NULL; -} - -/* ------------------------------------------------------------------------- */ bool element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) @@ -364,6 +356,23 @@ bool element_pointer_button( button_event_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's leave method: Forwards it to the element + * currently having pointer focus, and clears that. + * + * @param element_ptr + */ +void element_pointer_leave(wlmtk_element_t *element_ptr) +{ + wlmtk_container_t *container_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_container_t, super_element); + if (NULL == container_ptr->pointer_focus_element_ptr) return; + + wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); + container_ptr->pointer_focus_element_ptr = NULL; +} + /* ------------------------------------------------------------------------- */ /** * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. @@ -533,6 +542,7 @@ static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); static void test_pointer_motion(bs_test_t *test_ptr); static void test_pointer_focus(bs_test_t *test_ptr); static void test_pointer_focus_layered(bs_test_t *test_ptr); +static void test_pointer_button(bs_test_t *test_ptr); const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, @@ -541,6 +551,7 @@ const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "pointer_motion", test_pointer_motion }, { 1, "pointer_focus", test_pointer_focus }, { 1, "pointer_focus_layered", test_pointer_focus_layered }, + { 1, "pointer_button", test_pointer_button }, { 0, NULL, NULL } }; @@ -940,4 +951,35 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) wlmtk_container_fini(&container1); } +/* ------------------------------------------------------------------------- */ +/** Tests that pointer button is forwarded to element with pointer focus. */ +void test_pointer_button(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + + wlmtk_fake_element_t *elem_ptr = wlmtk_fake_element_create(); + elem_ptr->pointer_motion_return_value = &elem_ptr->element; + wlmtk_element_set_visible(&elem_ptr->element, true); + wlmtk_container_add_element(&container, &elem_ptr->element); + + wlmtk_button_event_t button = {}; + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + + BS_TEST_VERIFY_NEQ( + test_ptr, + NULL, + wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_TRUE( + test_ptr, elem_ptr->pointer_button_called); + + wlmtk_container_remove_element(&container, &elem_ptr->element); + wlmtk_container_fini(&container); +} + /* == End of container.c =================================================== */ From 8b9cecb5fca6ba61b88e19091e9f18f5c9b66803 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 17 Oct 2023 17:24:49 +0200 Subject: [PATCH 097/390] Changes return value of wlmtk_pointer_motion() to a bool. --- src/toolkit/container.c | 64 ++++++++++++++++++++--------------------- src/toolkit/content.c | 12 ++++---- src/toolkit/element.c | 10 +++---- src/toolkit/element.h | 15 ++++++---- src/toolkit/workspace.c | 3 +- 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index d81990d3..98c33a33 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -44,7 +44,7 @@ static void element_get_pointer_area( int *top_ptr, int *right_ptr, int *bottom_ptr); -static wlmtk_element_t *element_pointer_motion( +static bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); @@ -57,7 +57,7 @@ static void element_pointer_leave( static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr); -static wlmtk_element_t *update_pointer_focus_at( +static bool update_pointer_focus_at( wlmtk_container_t *container_ptr, double x, double y, @@ -318,10 +318,9 @@ void element_get_pointer_area( * @param y * @param time_msec * - * @return Pointer to the (non-container) element handling the motion, or NULL - * if the motion wasn't handled. + * @return Whether this container has an element that accepts the emotion. */ -wlmtk_element_t *element_pointer_motion( +bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -413,9 +412,9 @@ void handle_wlr_scene_tree_node_destroy( * @param y * @param time_msec * - * @return The leave element at position (x, y). + * @return Whether there was an element acception the motion at (x, y). */ -wlmtk_element_t *update_pointer_focus_at( +bool update_pointer_focus_at( wlmtk_container_t *container_ptr, double x, double y, @@ -434,9 +433,10 @@ wlmtk_element_t *update_pointer_focus_at( wlmtk_element_get_pointer_area(element_ptr, &x1, &y1, &x2, &y2); if (x_pos + x1 <= x && x < x_pos + x2 && y_pos + y1 <= y && y < y_pos + y2) { - wlmtk_element_t *motion_element_ptr = wlmtk_element_pointer_motion( - element_ptr, x - x_pos, y - y_pos, time_msec); - if (NULL == motion_element_ptr) continue; + if (!wlmtk_element_pointer_motion( + element_ptr, x - x_pos, y - y_pos, time_msec)) { + continue; + } if (NULL != container_ptr->pointer_focus_element_ptr && container_ptr->pointer_focus_element_ptr != element_ptr) { @@ -444,7 +444,7 @@ wlmtk_element_t *update_pointer_focus_at( container_ptr->pointer_focus_element_ptr); } container_ptr->pointer_focus_element_ptr = element_ptr; - return motion_element_ptr; + return true; } } @@ -455,7 +455,7 @@ wlmtk_element_t *update_pointer_focus_at( wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); container_ptr->pointer_focus_element_ptr = NULL; } - return NULL; + return false; } /* == Helper for unit test: A fake container =============================== */ @@ -656,7 +656,7 @@ void test_pointer_motion(bs_test_t *test_ptr) wlmtk_element_set_position(&elem1_ptr->element, -20, -40); elem1_ptr->width = 10; elem1_ptr->height = 5; - elem1_ptr->pointer_motion_return_value = &elem1_ptr->element; + elem1_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); @@ -664,7 +664,7 @@ void test_pointer_motion(bs_test_t *test_ptr) elem2_ptr->width = 10; elem2_ptr->height = 5; wlmtk_element_set_visible(&elem2_ptr->element, true); - elem2_ptr->pointer_motion_return_value = &elem2_ptr->element; + elem2_ptr->pointer_motion_return_value = true; wlmtk_container_add_element(&container, &elem2_ptr->element); // Verify 'dimensions' and 'pointer_area', derived from children. @@ -712,8 +712,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); // elem1 is at (-20, -40). - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_element_pointer_motion(&container.super_element, -20, -40, 7)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); elem1_ptr->pointer_motion_called = false; @@ -721,8 +721,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_x); BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_y); - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_element_pointer_motion( &parent_container.super_element, -20, -40, 7)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); @@ -732,8 +732,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, elem1_ptr->element.last_pointer_y); // elem2 is covering the area at (107, 302). - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_element_pointer_motion( &parent_container.super_element, 107, 203, 7)); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_leave_called); @@ -745,8 +745,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 3, elem2_ptr->element.last_pointer_y); // The pointer area of elem2 is covering the area at (112, 208). - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_element_pointer_motion( &parent_container.super_element, 112, 208, 7)); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_leave_called); @@ -757,8 +757,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 8, elem2_ptr->element.last_pointer_y); // The pointer area of elem2 does not include (113, 209). - BS_TEST_VERIFY_EQ( - test_ptr, NULL, + BS_TEST_VERIFY_FALSE( + test_ptr, wlmtk_element_pointer_motion( &parent_container.super_element, 113, 209, 7)); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); @@ -786,10 +786,10 @@ void test_pointer_focus(bs_test_t *test_ptr) BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); - elem1_ptr->pointer_motion_return_value = &elem1_ptr->element; + elem1_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); - elem2_ptr->pointer_motion_return_value = &elem2_ptr->element; + elem2_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem2_ptr->element, true); // Case 1: An empty container, will not have a pointer-focussed element. @@ -803,9 +803,8 @@ void test_pointer_focus(bs_test_t *test_ptr) // Case 3: Call motion() first, then add a visible element at (0, 0). Focus // should switch there. - BS_TEST_VERIFY_EQ( + BS_TEST_VERIFY_FALSE( test_ptr, - NULL, wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7)); wlmtk_container_add_element(&container, &elem1_ptr->element); BS_TEST_VERIFY_EQ( @@ -883,10 +882,10 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) wlmtk_element_set_visible(&container2.super_element, true); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); - elem1_ptr->pointer_motion_return_value = &elem1_ptr->element; + elem1_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); - elem2_ptr->pointer_motion_return_value = &elem2_ptr->element; + elem2_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem2_ptr->element, true); // Prepare: Motion was called, will not have any focus. @@ -959,7 +958,7 @@ void test_pointer_button(bs_test_t *test_ptr) BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); wlmtk_fake_element_t *elem_ptr = wlmtk_fake_element_create(); - elem_ptr->pointer_motion_return_value = &elem_ptr->element; + elem_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem_ptr->element, true); wlmtk_container_add_element(&container, &elem_ptr->element); @@ -968,9 +967,8 @@ void test_pointer_button(bs_test_t *test_ptr) test_ptr, wlmtk_element_pointer_button(&container.super_element, &button)); - BS_TEST_VERIFY_NEQ( + BS_TEST_VERIFY_TRUE( test_ptr, - NULL, wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7)); BS_TEST_VERIFY_TRUE( test_ptr, diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 48c88bd2..088d21ac 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -46,7 +46,7 @@ static void element_get_pointer_area( int *right_ptr, int *bottom_ptr); static void element_pointer_leave(wlmtk_element_t *element_ptr); -static wlmtk_element_t *element_pointer_motion( +static bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -250,9 +250,9 @@ void element_pointer_leave(wlmtk_element_t *element_ptr) * element's node. * @param time_msec * - * @return Pointer to this element, if the motion is within the area. + * @return Whether if the motion is within the area. */ -wlmtk_element_t *element_pointer_motion( +bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -267,7 +267,7 @@ wlmtk_element_t *element_pointer_motion( content_ptr->super_element.wlr_scene_node_ptr, x, y, &node_x, &node_y); if (NULL == wlr_scene_node_ptr || WLR_SCENE_NODE_BUFFER != wlr_scene_node_ptr->type) { - return NULL; + return false; } struct wlr_scene_buffer *wlr_scene_buffer_ptr = @@ -275,7 +275,7 @@ wlmtk_element_t *element_pointer_motion( struct wlr_scene_surface *wlr_scene_surface_ptr = wlr_scene_surface_try_from_buffer(wlr_scene_buffer_ptr); if (NULL == wlr_scene_surface_ptr) { - return NULL; + return false; } BS_ASSERT(content_ptr->wlr_surface_ptr == @@ -288,7 +288,7 @@ wlmtk_element_t *element_pointer_motion( content_ptr->wlr_seat_ptr, time_msec, node_x, node_y); - return element_ptr; + return true; } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index a5e23a7b..3bc85fa8 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -205,7 +205,7 @@ void wlmtk_element_get_pointer_area( } /* ------------------------------------------------------------------------- */ -wlmtk_element_t *wlmtk_element_pointer_motion( +bool wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -216,9 +216,9 @@ wlmtk_element_t *wlmtk_element_pointer_motion( element_ptr->last_pointer_time_msec = time_msec; // Guard clause: No implementation for `pointer_motion`. - if (NULL == element_ptr->impl_ptr->pointer_motion) return NULL; + if (NULL == element_ptr->impl_ptr->pointer_motion) return false; - return element_ptr->impl_ptr->pointer_motion( + return element_ptr->impl_ptr->pointer_motion( element_ptr, x, y, time_msec); } @@ -272,7 +272,7 @@ static void fake_get_pointer_area( int *top_ptr, int *right_ptr, int *bottom_ptr); -static wlmtk_element_t *fake_pointer_motion( +static bool fake_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); @@ -365,7 +365,7 @@ void fake_get_pointer_area( /* ------------------------------------------------------------------------- */ /** Handles 'motion' events for the fake element. */ -wlmtk_element_t *fake_pointer_motion( +bool fake_pointer_motion( wlmtk_element_t *element_ptr, __UNUSED__ double x, __UNUSED__ double y, diff --git a/src/toolkit/element.h b/src/toolkit/element.h index f8cbb292..7cf7a0a8 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -116,10 +116,11 @@ struct _wlmtk_element_impl_t { * @param y * @param time_msec * - * @return A pointer to the element handling the motion. - * FIXME: Or just a bool? + * @return Whether the motion is considered within the element's pointer + * area. If it returns true, the caller should consider this element + * as having pointer focus. */ - wlmtk_element_t *(*pointer_motion)(wlmtk_element_t *element_ptr, + bool (*pointer_motion)(wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); /** Indicates pointer button event. */ @@ -271,8 +272,12 @@ void wlmtk_element_get_pointer_area( * @param x * @param y * @param time_msec + * + * @return Whether the coordinates are within this element's area that accepts + * pointer events. May be a subset of @ref wlmtk_element_get_pointer_area. + * */ -wlmtk_element_t *wlmtk_element_pointer_motion( +bool wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -321,7 +326,7 @@ typedef struct { /** Indicates that Element::pointer_motion() was called. */ bool pointer_motion_called; /** Return value to pass when pointer_motion is called. */ - wlmtk_element_t *pointer_motion_return_value; + bool pointer_motion_return_value; /** Indicates that Element::pointer_leave() was called. */ bool pointer_leave_called; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index fab9ff01..f794bbce 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -127,9 +127,8 @@ bool wlmtk_workspace_motion( double y, uint32_t time_msec) { - wlmtk_element_t *element_ptr = wlmtk_element_pointer_motion( + return wlmtk_element_pointer_motion( &workspace_ptr->super_container.super_element, x, y, time_msec); - return element_ptr != NULL; } /* ------------------------------------------------------------------------- */ From e98da27a4503e0586e9e9c00e534f6a1cc22f06f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 18 Oct 2023 12:42:16 +0200 Subject: [PATCH 098/390] Adds testcase for wlmtk_workspace_button, and fixes handling of fake parent in workspace. --- src/toolkit/container.c | 17 ++++++++++++ src/toolkit/container.h | 14 ++++++++++ src/toolkit/workspace.c | 61 +++++++++++++++++++++++++---------------- 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 98c33a33..c5db9787 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -95,6 +95,23 @@ bool wlmtk_container_init( return true; } +/* ------------------------------------------------------------------------- */ +bool wlmtk_container_init_attached( + wlmtk_container_t *container_ptr, + const wlmtk_container_impl_t *container_impl_ptr, + struct wlr_scene_tree *root_wlr_scene_tree_ptr) +{ + if (!wlmtk_container_init(container_ptr, container_impl_ptr)) return false; + + if (NULL == element_create_scene_node( + &container_ptr->super_element, root_wlr_scene_tree_ptr)) { + wlmtk_container_fini(container_ptr); + return false; + } + + return true; +} + /* ------------------------------------------------------------------------- */ void wlmtk_container_fini(wlmtk_container_t *container_ptr) { diff --git a/src/toolkit/container.h b/src/toolkit/container.h index d8a543a3..b1ae3181 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -73,6 +73,20 @@ bool wlmtk_container_init( wlmtk_container_t *container_ptr, const wlmtk_container_impl_t *container_impl_ptr); +/** + * Initializes the container, and attach to WLR sene graph. + * + * @param container_ptr + * @param container_impl_ptr + * @param root_wlr_scene_tree_ptr + * + * @return true on success. + */ +bool wlmtk_container_init_attached( + wlmtk_container_t *container_ptr, + const wlmtk_container_impl_t *container_impl_ptr, + struct wlr_scene_tree *root_wlr_scene_tree_ptr); + /** * Un-initializes the container. * diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index f794bbce..0f2ba380 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -31,16 +31,6 @@ struct _wlmtk_workspace_t { /** Superclass: Container. */ wlmtk_container_t super_container; - - /** - * The workspace's element map() method will expect a parent from where to - * retrieve the wlroots scene graph tree from. As a toplevel construct, - * there is not really a parent, so we use this fake class instead. - * - * TODO(kaeser@gubbe.ch): This should live in wlmaker_server_t; ultimately - * that is the "container" that holds all workspaces. - */ - wlmtk_container_t fake_parent; }; static void workspace_container_destroy(wlmtk_container_t *container_ptr); @@ -60,29 +50,19 @@ wlmtk_workspace_t *wlmtk_workspace_create( logged_calloc(1, sizeof(wlmtk_workspace_t)); if (NULL == workspace_ptr) return NULL; - if (!wlmtk_container_init(&workspace_ptr->super_container, - &workspace_container_impl)) { + if (!wlmtk_container_init_attached(&workspace_ptr->super_container, + &workspace_container_impl, + wlr_scene_tree_ptr)) { wlmtk_workspace_destroy(workspace_ptr); return NULL; } - workspace_ptr->fake_parent.wlr_scene_tree_ptr = wlr_scene_tree_ptr; - wlmtk_container_add_element( - &workspace_ptr->fake_parent, - &workspace_ptr->super_container.super_element); - wlmtk_element_set_visible( - &workspace_ptr->super_container.super_element, true); - return workspace_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) { - wlmtk_container_remove_element( - &workspace_ptr->fake_parent, - &workspace_ptr->super_container.super_element); - wlmtk_container_fini(&workspace_ptr->super_container); free(workspace_ptr); } @@ -127,7 +107,7 @@ bool wlmtk_workspace_motion( double y, uint32_t time_msec) { - return wlmtk_element_pointer_motion( + return wlmtk_element_pointer_motion( &workspace_ptr->super_container.super_element, x, y, time_msec); } @@ -180,10 +160,12 @@ void workspace_container_destroy(wlmtk_container_t *container_ptr) static void test_create_destroy(bs_test_t *test_ptr); static void test_map_unmap(bs_test_t *test_ptr); +static void test_button(bs_test_t *test_ptr); const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "create_destroy", test_create_destroy }, { 1, "map_unmap", test_map_unmap }, + { 1, "button", test_button }, { 0, NULL, NULL } }; @@ -251,4 +233,35 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +void test_button(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + fake_parent_ptr->wlr_scene_tree_ptr); + BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&fake_element_ptr->element, true); + BS_ASSERT(NULL != fake_element_ptr); + + wlmtk_container_add_element( + &workspace_ptr->super_container, &fake_element_ptr->element); + + fake_element_ptr->pointer_motion_return_value = true; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_workspace_motion(workspace_ptr, 0, 0, 1234)); + BS_TEST_VERIFY_TRUE( + test_ptr, + fake_element_ptr->pointer_motion_called); + + wlmtk_container_remove_element( + &workspace_ptr->super_container, &fake_element_ptr->element); + + wlmtk_element_destroy(&fake_element_ptr->element); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy(fake_parent_ptr); +} + /* == End of workspace.c =================================================== */ From 0d68038175fc9b57d32a4f5440648105dcd222ed Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 18 Oct 2023 13:00:30 +0200 Subject: [PATCH 099/390] Adds the actual test for wlmtk_workspace_button. --- src/toolkit/workspace.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 0f2ba380..f311a262 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -112,7 +112,7 @@ bool wlmtk_workspace_motion( } /* ------------------------------------------------------------------------- */ -// FIXME : Add tests for button. +// TODO(kaeser@gubbe.ch): Improe this, and add tests to tatch UP to CLICK. void wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, const struct wlr_pointer_button_event *event_ptr) @@ -126,6 +126,7 @@ void wlmtk_workspace_button( if (NULL == focused_element_ptr) return; event.button = event_ptr->button; + event.time_msec = event_ptr->time_msec; if (WLR_BUTTON_PRESSED == event_ptr->state) { event.type = WLMTK_BUTTON_DOWN; wlmtk_element_pointer_button(focused_element_ptr, &event); @@ -256,6 +257,34 @@ void test_button(bs_test_t *test_ptr) test_ptr, fake_element_ptr->pointer_motion_called); + // Verify that a button down event is passed. + struct wlr_pointer_button_event wlr_pointer_button_event = { + .button = 42, + .state = WLR_BUTTON_PRESSED, + .time_msec = 4321, + }; + wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); + wlmtk_button_event_t expected_event = { + .button = 42, + .type = WLMTK_BUTTON_DOWN, + .time_msec = 4321, + }; + BS_TEST_VERIFY_EQ( + test_ptr, + 0, + memcmp(&expected_event, &fake_element_ptr->pointer_button_event, + sizeof(wlmtk_button_event_t))); + + // The button up event should trigger a click. + wlr_pointer_button_event.state = WLR_BUTTON_RELEASED; + wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); + expected_event.type = WLMTK_BUTTON_CLICK; + BS_TEST_VERIFY_EQ( + test_ptr, + 0, + memcmp(&expected_event, &fake_element_ptr->pointer_button_event, + sizeof(wlmtk_button_event_t))); + wlmtk_container_remove_element( &workspace_ptr->super_container, &fake_element_ptr->element); From 0acb4d6f1b994ac79f62820f045546dbd84fff56 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 18 Oct 2023 15:08:36 +0200 Subject: [PATCH 100/390] Fixes handling of scene tree in fake parent. --- src/toolkit/container.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index c5db9787..7dc55705 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -103,12 +103,15 @@ bool wlmtk_container_init_attached( { if (!wlmtk_container_init(container_ptr, container_impl_ptr)) return false; - if (NULL == element_create_scene_node( - &container_ptr->super_element, root_wlr_scene_tree_ptr)) { + container_ptr->super_element.wlr_scene_node_ptr = + element_create_scene_node( + &container_ptr->super_element, root_wlr_scene_tree_ptr); + if (NULL == container_ptr->super_element.wlr_scene_node_ptr) { wlmtk_container_fini(container_ptr); return false; } + BS_ASSERT(NULL != container_ptr->super_element.wlr_scene_node_ptr); return true; } @@ -123,6 +126,15 @@ void wlmtk_container_fini(wlmtk_container_t *container_ptr) wlmtk_element_destroy(element_ptr); } + // For containers created with wlmtk_container_init_attached(): We also + // need to remove references to the WLR scene tree. + if (NULL != container_ptr->wlr_scene_tree_ptr) { + BS_ASSERT(NULL == container_ptr->super_element.parent_container_ptr); + wlr_scene_node_destroy(&container_ptr->wlr_scene_tree_ptr->node); + container_ptr->wlr_scene_tree_ptr = NULL; + container_ptr->super_element.wlr_scene_node_ptr = NULL; + } + wlmtk_element_fini(&container_ptr->super_element); container_ptr->impl_ptr = NULL; } @@ -133,6 +145,7 @@ void wlmtk_container_add_element( wlmtk_element_t *element_ptr) { BS_ASSERT(NULL == element_ptr->parent_container_ptr); + BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); bs_dllist_push_front( &container_ptr->elements, @@ -514,20 +527,19 @@ wlmtk_container_t *wlmtk_container_create_fake_parent(void) 1, sizeof(fake_parent_container_t)); if (NULL == fake_parent_container_ptr) return NULL; - if (!wlmtk_container_init( - &fake_parent_container_ptr->container, - &fake_parent_impl)) { + fake_parent_container_ptr->wlr_scene_ptr = wlr_scene_create(); + if (NULL == fake_parent_container_ptr->wlr_scene_ptr) { fake_parent_destroy(&fake_parent_container_ptr->container); return NULL; } - fake_parent_container_ptr->wlr_scene_ptr = wlr_scene_create(); - if (NULL == fake_parent_container_ptr->wlr_scene_ptr) { + if (!wlmtk_container_init_attached( + &fake_parent_container_ptr->container, + &fake_parent_impl, + &fake_parent_container_ptr->wlr_scene_ptr->tree)) { fake_parent_destroy(&fake_parent_container_ptr->container); return NULL; } - fake_parent_container_ptr->container.wlr_scene_tree_ptr = - &fake_parent_container_ptr->wlr_scene_ptr->tree; return &fake_parent_container_ptr->container; } @@ -539,6 +551,8 @@ void fake_parent_destroy(wlmtk_container_t *container_ptr) fake_parent_container_t *fake_parent_container_ptr = BS_CONTAINER_OF( container_ptr, fake_parent_container_t, container); + wlmtk_container_fini(&fake_parent_container_ptr->container); + if (NULL != fake_parent_container_ptr->wlr_scene_ptr) { // Note: There is no "wlr_scene_destroy()" method; as of 2023-09-02, // this is just a flat allocated struct. @@ -546,8 +560,6 @@ void fake_parent_destroy(wlmtk_container_t *container_ptr) fake_parent_container_ptr->wlr_scene_ptr = NULL; } - wlmtk_container_fini(&fake_parent_container_ptr->container); - free(fake_parent_container_ptr); } From 3feb61f49aac6372c4989ecaa2f9593065dbd27d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 18 Oct 2023 15:11:25 +0200 Subject: [PATCH 101/390] Fixes a few memory leaks in tests. --- src/toolkit/container.c | 1 + src/toolkit/element.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 7dc55705..22c722ee 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -1006,6 +1006,7 @@ void test_pointer_button(bs_test_t *test_ptr) test_ptr, elem_ptr->pointer_button_called); wlmtk_container_remove_element(&container, &elem_ptr->element); + wlmtk_element_destroy(&elem_ptr->element); wlmtk_container_fini(&container); } diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 3bc85fa8..be23b6a1 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -547,6 +547,8 @@ void test_get_dimensions(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, left); BS_TEST_VERIFY_EQ(test_ptr, 42, right); BS_TEST_VERIFY_EQ(test_ptr, 21, bottom); + + wlmtk_element_destroy(&fake_element_ptr->element); } /* ------------------------------------------------------------------------- */ @@ -568,6 +570,8 @@ void test_get_pointer_area(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, -2, left); BS_TEST_VERIFY_EQ(test_ptr, 45, right); BS_TEST_VERIFY_EQ(test_ptr, 25, bottom); + + wlmtk_element_destroy(&fake_element_ptr->element); } /* ------------------------------------------------------------------------- */ @@ -620,6 +624,8 @@ void test_pointer_button(bs_test_t *test_ptr) test_ptr, wlmtk_element_pointer_button(&fake_element_ptr->element, &event)); BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_button_called); + + wlmtk_element_destroy(&fake_element_ptr->element); } /* == End of toolkit.c ===================================================== */ From 2977a24b078313bc7a28c65e7305e99c760978af Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 18 Oct 2023 15:23:54 +0200 Subject: [PATCH 102/390] Adds a few doxygen fixes. --- src/toolkit/content.c | 6 ++++++ src/toolkit/element.h | 1 + src/toolkit/workspace.c | 1 + src/toolkit/workspace.h | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 088d21ac..0de9c3cf 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -220,6 +220,12 @@ void element_get_pointer_area( } /* ------------------------------------------------------------------------- */ +/** + * Implements the element's leave method: If there's a WLR (sub)surface + * currently holding focus, that will be cleared. + * + * @param element_ptr + */ void element_pointer_leave(wlmtk_element_t *element_ptr) { wlmtk_content_t *content_ptr = BS_CONTAINER_OF( diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 7cf7a0a8..1ab55411 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -333,6 +333,7 @@ typedef struct { /** Indicates that Element::pointer_button() was called. */ bool pointer_button_called; + /** Last button event reveiced. */ wlmtk_button_event_t pointer_button_event; } wlmtk_fake_element_t; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index f311a262..35273b96 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -235,6 +235,7 @@ void test_map_unmap(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ +/** Tests wlmtk_workspace_button. */ void test_button(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index bdbfefb1..a24932b6 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -104,7 +104,7 @@ bool wlmtk_workspace_motion( * TODO(kaeser@gubbe.ch): Implement DOUBLE_CLICK and DRAG events. * * @param workspace_ptr - * @paran event_ptr + * @param event_ptr */ void wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, From 9f3dd02230fe0c3cac25b49a3c2b3b257bc4de34 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 18 Oct 2023 15:33:41 +0200 Subject: [PATCH 103/390] Minor cleanup: Removes pointer_motion_return_value. No longer needed. --- src/toolkit/container.c | 7 ------- src/toolkit/element.c | 7 ++++--- src/toolkit/element.h | 2 -- src/toolkit/workspace.c | 1 - 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 22c722ee..e3d6f609 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -685,7 +685,6 @@ void test_pointer_motion(bs_test_t *test_ptr) wlmtk_element_set_position(&elem1_ptr->element, -20, -40); elem1_ptr->width = 10; elem1_ptr->height = 5; - elem1_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); @@ -693,7 +692,6 @@ void test_pointer_motion(bs_test_t *test_ptr) elem2_ptr->width = 10; elem2_ptr->height = 5; wlmtk_element_set_visible(&elem2_ptr->element, true); - elem2_ptr->pointer_motion_return_value = true; wlmtk_container_add_element(&container, &elem2_ptr->element); // Verify 'dimensions' and 'pointer_area', derived from children. @@ -815,10 +813,8 @@ void test_pointer_focus(bs_test_t *test_ptr) BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); - elem1_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); - elem2_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem2_ptr->element, true); // Case 1: An empty container, will not have a pointer-focussed element. @@ -911,10 +907,8 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) wlmtk_element_set_visible(&container2.super_element, true); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); - elem1_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); - elem2_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem2_ptr->element, true); // Prepare: Motion was called, will not have any focus. @@ -987,7 +981,6 @@ void test_pointer_button(bs_test_t *test_ptr) BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); wlmtk_fake_element_t *elem_ptr = wlmtk_fake_element_create(); - elem_ptr->pointer_motion_return_value = true; wlmtk_element_set_visible(&elem_ptr->element, true); wlmtk_container_add_element(&container, &elem_ptr->element); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index be23b6a1..e054ff6e 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -367,14 +367,15 @@ void fake_get_pointer_area( /** Handles 'motion' events for the fake element. */ bool fake_pointer_motion( wlmtk_element_t *element_ptr, - __UNUSED__ double x, - __UNUSED__ double y, + double x, + double y, __UNUSED__ uint32_t time_msec) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); fake_element_ptr->pointer_motion_called = true; - return fake_element_ptr->pointer_motion_return_value; + return (-1 <= x && x < fake_element_ptr->width + 3 && + -2 < y && y < fake_element_ptr->height + 4); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 1ab55411..b9ad7f00 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -325,8 +325,6 @@ typedef struct { /** Indicates that Element::pointer_motion() was called. */ bool pointer_motion_called; - /** Return value to pass when pointer_motion is called. */ - bool pointer_motion_return_value; /** Indicates that Element::pointer_leave() was called. */ bool pointer_leave_called; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 35273b96..0a8716e7 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -250,7 +250,6 @@ void test_button(bs_test_t *test_ptr) wlmtk_container_add_element( &workspace_ptr->super_container, &fake_element_ptr->element); - fake_element_ptr->pointer_motion_return_value = true; BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_workspace_motion(workspace_ptr, 0, 0, 1234)); From 5c6096b98ba75093660b18b0d10713b8b6940d66 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 19 Oct 2023 11:55:48 +0200 Subject: [PATCH 104/390] Merges libbase HEAD and makes use of BS_TEST_VERIFY_MEMEQ. --- src/toolkit/workspace.c | 16 ++++++++-------- submodules/libbase | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 0a8716e7..69b4fb66 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -269,21 +269,21 @@ void test_button(bs_test_t *test_ptr) .type = WLMTK_BUTTON_DOWN, .time_msec = 4321, }; - BS_TEST_VERIFY_EQ( + BS_TEST_VERIFY_MEMEQ( test_ptr, - 0, - memcmp(&expected_event, &fake_element_ptr->pointer_button_event, - sizeof(wlmtk_button_event_t))); + &expected_event, + &fake_element_ptr->pointer_button_event, + sizeof(wlmtk_button_event_t)); // The button up event should trigger a click. wlr_pointer_button_event.state = WLR_BUTTON_RELEASED; wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); expected_event.type = WLMTK_BUTTON_CLICK; - BS_TEST_VERIFY_EQ( + BS_TEST_VERIFY_MEMEQ( test_ptr, - 0, - memcmp(&expected_event, &fake_element_ptr->pointer_button_event, - sizeof(wlmtk_button_event_t))); + &expected_event, + &fake_element_ptr->pointer_button_event, + sizeof(wlmtk_button_event_t)); wlmtk_container_remove_element( &workspace_ptr->super_container, &fake_element_ptr->element); diff --git a/submodules/libbase b/submodules/libbase index cde45d59..8de293a0 160000 --- a/submodules/libbase +++ b/submodules/libbase @@ -1 +1 @@ -Subproject commit cde45d596a2349eb90c7023dcda79b2b2b1e03d1 +Subproject commit 8de293a0edc6896c71eadb2b8abe0d12209a69a5 From d79cfc558cb05110c051047fe744f4a93794bdd0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 19 Oct 2023 19:37:58 +0200 Subject: [PATCH 105/390] removes obsolete no-op statement. --- src/toolkit/workspace.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 69b4fb66..bcc42308 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -142,8 +142,6 @@ void wlmtk_workspace_button( "Workspace %p: Unhandled state 0x%x for button 0x%x", workspace_ptr, event_ptr->state, event_ptr->button); } - - event = event; } /* == Local (static) methods =============================================== */ From 127e9284dd6e795aafb5b72602668100dc1b6123 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 14:26:18 +0200 Subject: [PATCH 106/390] Fixes incorrect node coordinates in wlmtk_conent_t::element_pointer_motion(). --- src/toolkit/content.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 0de9c3cf..8d191987 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -267,10 +267,19 @@ bool element_pointer_motion( wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); + // Get the layout local coordinates of the node, so we can adjust the + // node-local (x, y) for the `wlr_scene_node_at` call. + int lx, ly; + if (!wlr_scene_node_coords( + content_ptr->super_element.wlr_scene_node_ptr, &lx, &ly)) { + return false; + } // Get the node below the cursor. Return if there's no buffer node. double node_x, node_y; struct wlr_scene_node *wlr_scene_node_ptr = wlr_scene_node_at( - content_ptr->super_element.wlr_scene_node_ptr, x, y, &node_x, &node_y); + content_ptr->super_element.wlr_scene_node_ptr, + x + lx, y + ly, &node_x, &node_y); + if (NULL == wlr_scene_node_ptr || WLR_SCENE_NODE_BUFFER != wlr_scene_node_ptr->type) { return false; From c3b1b5b771e7a61f2555c742a376789708d53cc7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 14:57:53 +0200 Subject: [PATCH 107/390] Wires up window moves and adds a state machine for move/resize in workspace. --- src/toolkit/window.c | 11 +++ src/toolkit/window.h | 10 +++ src/toolkit/workspace.c | 150 ++++++++++++++++++++++++++++++++++++++- src/toolkit/workspace.h | 10 +++ src/wlmtk_xdg_toplevel.c | 4 +- 5 files changed, 181 insertions(+), 4 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 0117b34b..f9f6aa81 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -21,6 +21,7 @@ #include "window.h" #include "container.h" +#include "workspace.h" /* == Declarations ========================================================= */ @@ -106,6 +107,16 @@ void wlmtk_window_set_server_side_decorated( window_ptr, decorated); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_move(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(NULL != + window_ptr->super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_container.super_element.parent_container_ptr); + wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 33bd07e5..8118047b 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -83,6 +83,16 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); +/** + * Requests a move for the window. + * + * Requires the window to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_window_move. + * + * @param window_ptr + */ +void wlmtk_window_request_move(wlmtk_window_t *window_ptr); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index bcc42308..b7fb9006 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -27,10 +27,40 @@ /* == Declarations ========================================================= */ +/** States of the pointer FSM. */ +typedef enum { + POINTER_STATE_PASSTHROUGH, + POINTER_STATE_MOVE, + POINTER_STATE_RESIZE +} pointer_state_t; + +/** Events for the pointer FSM. */ +typedef enum { + POINTER_STATE_EVENT_BEGIN_MOVE, + POINTER_STATE_EVENT_BEGIN_RESIZE, + POINTER_STATE_EVENT_BTN_RELEASED, + POINTER_STATE_EVENT_RESET, + POINTER_STATE_EVENT_MOTION, +} pointer_state_event_t; + /** State of the workspace. */ struct _wlmtk_workspace_t { /** Superclass: Container. */ wlmtk_container_t super_container; + + /** Current FSM state. */ + pointer_state_t current_state; + + /** The grabbed window. */ + wlmtk_window_t *grabbed_window_ptr; + /** Motion X */ + int motion_x; + /** Motion Y */ + int motion_y; + /** Element's X position when initiating a move or resize. */ + int initial_x; + /** Element's Y position when initiating a move or resize. */ + int initial_y; }; static void workspace_container_destroy(wlmtk_container_t *container_ptr); @@ -40,6 +70,49 @@ const wlmtk_container_impl_t workspace_container_impl = { .destroy = workspace_container_destroy }; +/** State machine definition. */ +typedef struct { + /** Starting state. */ + pointer_state_t state; + /** Event. */ + pointer_state_event_t event; + /** Updated state. */ + pointer_state_t new_state; + /** Handler invoked by the (state, event) match. */ + void (*handler)(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); +} state_transition_t; + +static void begin_move(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); +static void move_motion(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); +static void move_end(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); +static void handle_state(wlmtk_workspace_t *workspace_ptr, + pointer_state_event_t event, + void *ud_ptr); + +/* == Data ================================================================= */ + +/** Finite state machine definition for pointer events. */ +static const state_transition_t pointer_states[] = { + { + POINTER_STATE_PASSTHROUGH, + POINTER_STATE_EVENT_BEGIN_MOVE, + POINTER_STATE_MOVE, + begin_move }, + { + POINTER_STATE_MOVE, + POINTER_STATE_EVENT_MOTION, + POINTER_STATE_MOVE, + move_motion + }, + { + POINTER_STATE_MOVE, + POINTER_STATE_EVENT_BTN_RELEASED, + POINTER_STATE_PASSTHROUGH, + move_end, + }, + { 0, 0, 0, NULL } // sentinel. +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -107,8 +180,10 @@ bool wlmtk_workspace_motion( double y, uint32_t time_msec) { - return wlmtk_element_pointer_motion( + bool rv = wlmtk_element_pointer_motion( &workspace_ptr->super_container.super_element, x, y, time_msec); + handle_state(workspace_ptr, POINTER_STATE_EVENT_MOTION, NULL); + return rv; } /* ------------------------------------------------------------------------- */ @@ -120,6 +195,12 @@ void wlmtk_workspace_button( wlmtk_button_event_t event; wlmtk_element_t *focused_element_ptr; + if (WLR_BUTTON_RELEASED == event_ptr->state) { + handle_state(workspace_ptr, + POINTER_STATE_EVENT_BTN_RELEASED, + NULL); + } + // Guard clause: nothing to pass on if no element has the focus. focused_element_ptr = workspace_ptr->super_container.pointer_focus_element_ptr; @@ -144,6 +225,14 @@ void wlmtk_workspace_button( } } +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_begin_window_move( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) +{ + handle_state(workspace_ptr, POINTER_STATE_EVENT_BEGIN_MOVE, window_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -155,6 +244,65 @@ void workspace_container_destroy(wlmtk_container_t *container_ptr) wlmtk_workspace_destroy(workspace_ptr); } +/* ------------------------------------------------------------------------- */ +/** State machine handler. */ +void handle_state(wlmtk_workspace_t *workspace_ptr, + pointer_state_event_t event, + void *ud_ptr) +{ + for (const state_transition_t *transition_ptr = &pointer_states[0]; + NULL != transition_ptr->handler; + transition_ptr++) { + if (transition_ptr->state == workspace_ptr->current_state && + transition_ptr->event == event) { + transition_ptr->handler(workspace_ptr, ud_ptr); + workspace_ptr->current_state = transition_ptr->new_state; + return; + } + } +} + + +/* ------------------------------------------------------------------------- */ +/** Initiates a move. */ +void begin_move(wlmtk_workspace_t *workspace_ptr, void *ud_ptr) +{ + workspace_ptr->grabbed_window_ptr = ud_ptr; + workspace_ptr->motion_x = + workspace_ptr->super_container.super_element.last_pointer_x; + workspace_ptr->motion_y = + workspace_ptr->super_container.super_element.last_pointer_y; + + wlmtk_element_get_position( + wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + &workspace_ptr->initial_x, + &workspace_ptr->initial_y); +} + +/* ------------------------------------------------------------------------- */ +/** Handles motion during a move. */ +void move_motion(wlmtk_workspace_t *workspace_ptr, + __UNUSED__ void *ud_ptr) +{ + double rel_x = workspace_ptr->super_container.super_element.last_pointer_x - + workspace_ptr->motion_x; + double rel_y = workspace_ptr->super_container.super_element.last_pointer_y - + workspace_ptr->motion_y; + + wlmtk_element_set_position( + wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + workspace_ptr->initial_x + rel_x, + workspace_ptr->initial_y + rel_y); +} + +/* ------------------------------------------------------------------------- */ +/** Ends the move. */ +void move_end(__UNUSED__ wlmtk_workspace_t *workspace_ptr, + __UNUSED__ void *ud_ptr) +{ + // Nothing to do. +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index a24932b6..5c805355 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -110,6 +110,16 @@ void wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, const struct wlr_pointer_button_event *event_ptr); +/** + * Initiates a 'move' for the window. + * + * @param workspace_ptr + * @param window_ptr + */ +void wlmtk_workspace_begin_window_move( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 839674df..de766ce9 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -328,9 +328,7 @@ void handle_toplevel_request_move( listener_ptr, wlmtk_xdg_toplevel_content_t, toplevel_request_move_listener); - - bs_log(BS_INFO, "XDG toplevel content %p: Request move", - xdg_tl_content_ptr); + wlmtk_window_request_move(xdg_tl_content_ptr->super_content.window_ptr); } /* == End of xdg_toplevel.c ================================================ */ From c74c9dff065a2d7b4aec422a0386062fed37ace5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 15:11:05 +0200 Subject: [PATCH 108/390] Makes the virtual method table part of the element, so methods can be overwritten. --- src/toolkit/container.c | 4 +- src/toolkit/element.c | 27 ++++++------ src/toolkit/element.h | 94 ++++++++++++++++++++--------------------- 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index e3d6f609..de5710c9 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -592,13 +592,13 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( &container, &wlmtk_container_fake_impl)); // Also expect the super element to be initialized. - BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.impl_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.impl.destroy); BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl_ptr); wlmtk_container_destroy(&container); // Also expect the super element to be un-initialized. - BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.impl_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.impl.destroy); BS_TEST_VERIFY_EQ(test_ptr, NULL, container.impl_ptr); } diff --git a/src/toolkit/element.c b/src/toolkit/element.c index e054ff6e..0b2f90f5 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -41,13 +41,12 @@ bool wlmtk_element_init( const wlmtk_element_impl_t *element_impl_ptr) { BS_ASSERT(NULL != element_ptr); + memset(element_ptr, 0, sizeof(wlmtk_element_t)); BS_ASSERT(NULL != element_impl_ptr); BS_ASSERT(NULL != element_impl_ptr->destroy); BS_ASSERT(NULL != element_impl_ptr->create_scene_node); BS_ASSERT(NULL != element_impl_ptr->get_dimensions); - memset(element_ptr, 0, sizeof(wlmtk_element_t)); - - element_ptr->impl_ptr = element_impl_ptr; + memcpy(&element_ptr->impl, element_impl_ptr, sizeof(wlmtk_element_impl_t)); element_ptr->last_pointer_x = NAN; element_ptr->last_pointer_y = NAN; @@ -63,7 +62,7 @@ void wlmtk_element_fini( BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); BS_ASSERT(NULL == element_ptr->parent_container_ptr); - element_ptr->impl_ptr = NULL; + memset(element_ptr, 0, sizeof(wlmtk_element_t)); } /* ------------------------------------------------------------------------- */ @@ -110,7 +109,7 @@ void wlmtk_element_attach_to_scene_graph( } if (NULL == element_ptr->wlr_scene_node_ptr) { - element_ptr->wlr_scene_node_ptr = element_ptr->impl_ptr->create_scene_node( + element_ptr->wlr_scene_node_ptr = element_ptr->impl.create_scene_node( element_ptr, parent_wlr_scene_tree_ptr); wlmtk_util_connect_listener_signal( &element_ptr->wlr_scene_node_ptr->events.destroy, @@ -183,7 +182,7 @@ void wlmtk_element_get_dimensions( int *right_ptr, int *bottom_ptr) { - element_ptr->impl_ptr->get_dimensions( + element_ptr->impl.get_dimensions( element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } @@ -195,8 +194,8 @@ void wlmtk_element_get_pointer_area( int *right_ptr, int *bottom_ptr) { - if (NULL != element_ptr->impl_ptr->get_pointer_area) { - element_ptr->impl_ptr->get_pointer_area( + if (NULL != element_ptr->impl.get_pointer_area) { + element_ptr->impl.get_pointer_area( element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } else { wlmtk_element_get_dimensions( @@ -216,9 +215,9 @@ bool wlmtk_element_pointer_motion( element_ptr->last_pointer_time_msec = time_msec; // Guard clause: No implementation for `pointer_motion`. - if (NULL == element_ptr->impl_ptr->pointer_motion) return false; + if (NULL == element_ptr->impl.pointer_motion) return false; - return element_ptr->impl_ptr->pointer_motion( + return element_ptr->impl.pointer_motion( element_ptr, x, y, time_msec); } @@ -226,8 +225,8 @@ bool wlmtk_element_pointer_motion( void wlmtk_element_pointer_leave( wlmtk_element_t *element_ptr) { - if (NULL != element_ptr->impl_ptr->pointer_leave) { - element_ptr->impl_ptr->pointer_leave(element_ptr); + if (NULL != element_ptr->impl.pointer_leave) { + element_ptr->impl.pointer_leave(element_ptr); } element_ptr->last_pointer_x = NAN; element_ptr->last_pointer_y = NAN; @@ -434,10 +433,10 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_init(&element, &wlmtk_fake_element_impl)); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl.destroy); wlmtk_element_fini(&element); - BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl.destroy); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/element.h b/src/toolkit/element.h index b9ad7f00..6353b930 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -38,50 +38,6 @@ struct wlr_scene_tree; extern "C" { #endif // __cplusplus -/** State of an element. */ -struct _wlmtk_element_t { - /** X position of the element, relative to the container. */ - int x; - /** Y position of the element, relative to the container. */ - int y; - - /** The container this element belongs to, if any. */ - wlmtk_container_t *parent_container_ptr; - /** The node of elements. */ - bs_dllist_node_t dlnode; - - /** Implementation of abstract virtual methods. */ - const wlmtk_element_impl_t *impl_ptr; - - /** Points to the wlroots scene graph API node, if attached. */ - struct wlr_scene_node *wlr_scene_node_ptr; - - /** Whether the element is visible (drawn, when part of a scene graph). */ - bool visible; - - /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ - struct wl_listener wlr_scene_node_destroy_listener; - - /** - * Horizontal pointer position from last @ref wlmtk_element_pointer_motion - * call. NAN if there was no motion call yet, or if @ref - * wlmtk_element_pointer_leave was called since. - * - * Does not imply that the element has pointer focus. - */ - double last_pointer_x; - /** - * Vertical pointer position from last @ref wlmtk_element_pointer_motion - * call. NAN if there was no motion call yet, or if @ref - * wlmtk_element_pointer_leave was called since. - * - * Does not imply that the element has pointer focus. - */ - double last_pointer_y; - /** Time of last @ref wlmtk_element_pointer_motion call, 0 otherwise. */ - uint32_t last_pointer_time_msec; -}; - /** Pointers to the implementation of Element's virtual methods. */ struct _wlmtk_element_impl_t { /** Destroys the implementation of the element. */ @@ -131,6 +87,50 @@ struct _wlmtk_element_impl_t { void (*pointer_leave)(wlmtk_element_t *element_ptr); }; +/** State of an element. */ +struct _wlmtk_element_t { + /** X position of the element, relative to the container. */ + int x; + /** Y position of the element, relative to the container. */ + int y; + + /** The container this element belongs to, if any. */ + wlmtk_container_t *parent_container_ptr; + /** The node of elements. */ + bs_dllist_node_t dlnode; + + /** Implementation of abstract virtual methods. */ + wlmtk_element_impl_t impl; + + /** Points to the wlroots scene graph API node, if attached. */ + struct wlr_scene_node *wlr_scene_node_ptr; + + /** Whether the element is visible (drawn, when part of a scene graph). */ + bool visible; + + /** Listener for the `destroy` signal of `wlr_scene_node_ptr`. */ + struct wl_listener wlr_scene_node_destroy_listener; + + /** + * Horizontal pointer position from last @ref wlmtk_element_pointer_motion + * call. NAN if there was no motion call yet, or if @ref + * wlmtk_element_pointer_leave was called since. + * + * Does not imply that the element has pointer focus. + */ + double last_pointer_x; + /** + * Vertical pointer position from last @ref wlmtk_element_pointer_motion + * call. NAN if there was no motion call yet, or if @ref + * wlmtk_element_pointer_leave was called since. + * + * Does not imply that the element has pointer focus. + */ + double last_pointer_y; + /** Time of last @ref wlmtk_element_pointer_motion call, 0 otherwise. */ + uint32_t last_pointer_time_msec; +}; + /** * Initializes the element. * @@ -294,8 +294,8 @@ static inline bool wlmtk_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { - if (NULL == element_ptr->impl_ptr->pointer_button) return false; - return element_ptr->impl_ptr->pointer_button( + if (NULL == element_ptr->impl.pointer_button) return false; + return element_ptr->impl.pointer_button( element_ptr, button_event_ptr); } @@ -308,7 +308,7 @@ static inline bool wlmtk_element_pointer_button( */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { - element_ptr->impl_ptr->destroy(element_ptr); + element_ptr->impl.destroy(element_ptr); } /** Unit tests for the element. */ From 523098f3afec1f34ebd144b19909accb35233096 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 15:11:11 +0200 Subject: [PATCH 109/390] Makes the virtual method table part of the element, so methods can be overwritten. --- src/toolkit/content.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 8d191987..60c1f427 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -383,7 +383,7 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) return NULL; } - BS_ASSERT(NULL != fake_content_ptr->content.super_element.impl_ptr); + BS_ASSERT(NULL != fake_content_ptr->content.super_element.impl.destroy); BS_ASSERT(NULL != fake_content_ptr->content.impl_ptr); return fake_content_ptr; } @@ -398,7 +398,7 @@ void fake_content_destroy(wlmtk_content_t *content_ptr) wlmtk_content_fini(&fake_content_ptr->content); // Also expect the super element to be un-initialized. - BS_ASSERT(NULL == fake_content_ptr->content.super_element.impl_ptr); + BS_ASSERT(NULL == fake_content_ptr->content.super_element.impl.destroy); BS_ASSERT(NULL == fake_content_ptr->content.impl_ptr); free(fake_content_ptr); } @@ -458,7 +458,7 @@ void test_init_fini(bs_test_t *test_ptr) // Also expect the super element to be initialized. BS_TEST_VERIFY_NEQ( test_ptr, NULL, - fake_content_ptr->content.super_element.impl_ptr); + fake_content_ptr->content.super_element.impl.destroy); BS_TEST_VERIFY_NEQ( test_ptr, NULL, fake_content_ptr->content.impl_ptr); From 71a41d2223d70ab9db6e71acdb9830b2ad1ee3b6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 15:16:38 +0200 Subject: [PATCH 110/390] Makes the virtual method table part fo the container, also to make methods overwritable there. --- src/toolkit/container.c | 14 ++++++++------ src/toolkit/container.h | 16 ++++++++-------- src/toolkit/workspace.c | 5 ++++- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index de5710c9..15ba9848 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -82,16 +82,18 @@ bool wlmtk_container_init( const wlmtk_container_impl_t *container_impl_ptr) { BS_ASSERT(NULL != container_ptr); + memset(container_ptr, 0, sizeof(wlmtk_container_t)); BS_ASSERT(NULL != container_impl_ptr); BS_ASSERT(NULL != container_impl_ptr->destroy); - memset(container_ptr, 0, sizeof(wlmtk_container_t)); if (!wlmtk_element_init(&container_ptr->super_element, &super_element_impl)) { return false; } - container_ptr->impl_ptr = container_impl_ptr; + memcpy(&container_ptr->impl, + container_impl_ptr, + sizeof(wlmtk_container_impl_t)); return true; } @@ -136,7 +138,7 @@ void wlmtk_container_fini(wlmtk_container_t *container_ptr) } wlmtk_element_fini(&container_ptr->super_element); - container_ptr->impl_ptr = NULL; + memset(container_ptr, 0, sizeof(wlmtk_container_t)); } /* ------------------------------------------------------------------------- */ @@ -213,7 +215,7 @@ void element_destroy(wlmtk_element_t *element_ptr) { wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); - container_ptr->impl_ptr->destroy(container_ptr); + container_ptr->impl.destroy(container_ptr); } /* ------------------------------------------------------------------------- */ @@ -593,13 +595,13 @@ void test_init_fini(bs_test_t *test_ptr) &container, &wlmtk_container_fake_impl)); // Also expect the super element to be initialized. BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.impl.destroy); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl.destroy); wlmtk_container_destroy(&container); // Also expect the super element to be un-initialized. BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.impl.destroy); - BS_TEST_VERIFY_EQ(test_ptr, NULL, container.impl_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.impl.destroy); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/container.h b/src/toolkit/container.h index b1ae3181..3fbd4705 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -34,6 +34,12 @@ typedef struct _wlmtk_container_impl_t wlmtk_container_impl_t; extern "C" { #endif // __cplusplus +/** Virtual method table of the container. */ +struct _wlmtk_container_impl_t { + /** dtor. */ + void (*destroy)(wlmtk_container_t *container_ptr); +}; + /** State of the container. */ struct _wlmtk_container_t { /** Super class of the container. */ @@ -43,7 +49,7 @@ struct _wlmtk_container_t { bs_dllist_t elements; /** Implementation of the container's virtual methods. */ - const wlmtk_container_impl_t *impl_ptr; + wlmtk_container_impl_t impl; /** Scene tree. */ struct wlr_scene_tree *wlr_scene_tree_ptr; @@ -55,12 +61,6 @@ struct _wlmtk_container_t { wlmtk_element_t *pointer_focus_element_ptr; }; -/** Virtual method table of the container. */ -struct _wlmtk_container_impl_t { - /** dtor. */ - void (*destroy)(wlmtk_container_t *container_ptr); -}; - /** * Initializes the container with the provided virtual method table. * @@ -148,7 +148,7 @@ struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( /** Virtual method: Calls the dtor of the container's implementation. */ static inline void wlmtk_container_destroy( wlmtk_container_t *container_ptr) { - container_ptr->impl_ptr->destroy(container_ptr); + container_ptr->impl.destroy(container_ptr); } /** Unit tests for the container. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index b7fb9006..61fb0cfd 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -169,7 +169,10 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_workspace_t *wlmtk_workspace_from_container( wlmtk_container_t *container_ptr) { - BS_ASSERT(container_ptr->impl_ptr == &workspace_container_impl); + BS_ASSERT(0 == memcmp( + &container_ptr->impl, + &workspace_container_impl, + sizeof(wlmtk_container_impl_t))); return BS_CONTAINER_OF(container_ptr, wlmtk_workspace_t, super_container); } From 2bf3fc34c93dca4e92fe89e89277e36cfd476d45 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 15:19:38 +0200 Subject: [PATCH 111/390] Makes the virtual method table part of the content, also to make methods overwritable there. --- src/toolkit/content.c | 20 +++++++++----------- src/toolkit/content.h | 38 +++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 60c1f427..798a2f68 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -79,31 +79,29 @@ bool wlmtk_content_init( struct wlr_seat *wlr_seat_ptr) { BS_ASSERT(NULL != content_ptr); + memset(content_ptr, 0, sizeof(wlmtk_content_t)); BS_ASSERT(NULL != content_impl_ptr); BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); BS_ASSERT(NULL != content_impl_ptr->get_size); BS_ASSERT(NULL != content_impl_ptr->set_activated); - memset(content_ptr, 0, sizeof(wlmtk_content_t)); - if (!wlmtk_element_init(&content_ptr->super_element, &super_element_impl)) { return false; } content_ptr->wlr_seat_ptr = wlr_seat_ptr; - - content_ptr->impl_ptr = content_impl_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; - return true; + + memcpy(&content_ptr->impl, content_impl_ptr, sizeof(wlmtk_content_impl_t)); return true; } /* ------------------------------------------------------------------------- */ void wlmtk_content_fini(wlmtk_content_t *content_ptr) { wlmtk_element_fini(&content_ptr->super_element); - content_ptr->impl_ptr = NULL; + memset(content_ptr, 0, sizeof(wlmtk_content_t)); } /* ------------------------------------------------------------------------- */ @@ -134,7 +132,7 @@ void element_destroy(wlmtk_element_t *element_ptr) { wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); - content_ptr->impl_ptr->destroy(content_ptr); + content_ptr->impl.destroy(content_ptr); } /* ------------------------------------------------------------------------- */ @@ -152,7 +150,7 @@ struct wlr_scene_node *element_create_scene_node( { wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); - return content_ptr->impl_ptr->create_scene_node( + return content_ptr->impl.create_scene_node( content_ptr, wlr_scene_tree_ptr); } @@ -384,7 +382,7 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) } BS_ASSERT(NULL != fake_content_ptr->content.super_element.impl.destroy); - BS_ASSERT(NULL != fake_content_ptr->content.impl_ptr); + BS_ASSERT(NULL != fake_content_ptr->content.impl.destroy); return fake_content_ptr; } @@ -399,7 +397,7 @@ void fake_content_destroy(wlmtk_content_t *content_ptr) // Also expect the super element to be un-initialized. BS_ASSERT(NULL == fake_content_ptr->content.super_element.impl.destroy); - BS_ASSERT(NULL == fake_content_ptr->content.impl_ptr); + BS_ASSERT(NULL == fake_content_ptr->content.impl.destroy); free(fake_content_ptr); } @@ -461,7 +459,7 @@ void test_init_fini(bs_test_t *test_ptr) fake_content_ptr->content.super_element.impl.destroy); BS_TEST_VERIFY_NEQ( test_ptr, NULL, - fake_content_ptr->content.impl_ptr); + fake_content_ptr->content.impl.destroy); int l, t, r, b; fake_content_ptr->width = 42; diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 23388861..6434abab 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -32,6 +32,21 @@ typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; extern "C" { #endif // __cplusplus +/** Method table of the content. */ +struct _wlmtk_content_impl_t { + /** Destroys the implementation of the content. */ + void (*destroy)(wlmtk_content_t *content_ptr); + /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ + struct wlr_scene_node *(*create_scene_node)( + wlmtk_content_t *content_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); + /** Gets width and height of the content. */ + void (*get_size)(wlmtk_content_t *content_ptr, + int *width_ptr, int *height_ptr); + /** Sets whether the content is activated (has keyboard focus). */ + void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); +}; + /** State of the element. */ struct _wlmtk_content_t { /** Temporary: Identifier, to disambiguate from XDG nodes. */ @@ -41,7 +56,7 @@ struct _wlmtk_content_t { wlmtk_element_t super_element; /** Implementation of abstract virtual methods. */ - const wlmtk_content_impl_t *impl_ptr; + wlmtk_content_impl_t impl; /** * The window this content belongs to. Will be set when creating @@ -60,21 +75,6 @@ struct _wlmtk_content_t { struct wlr_surface *wlr_surface_ptr; }; -/** Method table of the content. */ -struct _wlmtk_content_impl_t { - /** Destroys the implementation of the content. */ - void (*destroy)(wlmtk_content_t *content_ptr); - /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ - struct wlr_scene_node *(*create_scene_node)( - wlmtk_content_t *content_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); - /** Gets width and height of the content. */ - void (*get_size)(wlmtk_content_t *content_ptr, - int *width_ptr, int *height_ptr); - /** Sets whether the content is activated (has keyboard focus). */ - void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); -}; - /** * Initializes the content. * @@ -119,19 +119,19 @@ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); /** Wraps to @ref wlmtk_content_impl_t::destroy. */ static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { - content_ptr->impl_ptr->destroy(content_ptr); + content_ptr->impl.destroy(content_ptr); } /** Wraps to @ref wlmtk_content_impl_t::get_size. */ static inline void wlmtk_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr) { - content_ptr->impl_ptr->get_size(content_ptr, width_ptr, height_ptr); + content_ptr->impl.get_size(content_ptr, width_ptr, height_ptr); } /** Wraps to @ref wlmtk_content_impl_t::set_activated. */ static inline void wlmtk_content_set_activated( wlmtk_content_t *content_ptr, bool activated) { - content_ptr->impl_ptr->set_activated(content_ptr, activated); + content_ptr->impl.set_activated(content_ptr, activated); } /** From 1d9544a0ee87616632e6dc8355c6a3f2fbee99f9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 15:49:23 +0200 Subject: [PATCH 112/390] Moves the pointer FSM into the element's extended pointer handlers. --- src/toolkit/workspace.c | 119 +++++++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 19 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 61fb0cfd..d43e6e7a 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -47,6 +47,8 @@ typedef enum { struct _wlmtk_workspace_t { /** Superclass: Container. */ wlmtk_container_t super_container; + /** Original virtual method table. We're overwriting parts. */ + wlmtk_element_impl_t parent_element_impl; /** Current FSM state. */ pointer_state_t current_state; @@ -61,10 +63,21 @@ struct _wlmtk_workspace_t { int initial_x; /** Element's Y position when initiating a move or resize. */ int initial_y; + }; static void workspace_container_destroy(wlmtk_container_t *container_ptr); +static bool element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + uint32_t time_msec); +static bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void element_pointer_leave( + wlmtk_element_t *element_ptr); + /** Method table for the container's virtual methods. */ const wlmtk_container_impl_t workspace_container_impl = { .destroy = workspace_container_destroy @@ -129,7 +142,15 @@ wlmtk_workspace_t *wlmtk_workspace_create( wlmtk_workspace_destroy(workspace_ptr); return NULL; } - + memcpy(&workspace_ptr->parent_element_impl, + &workspace_ptr->super_container.super_element.impl, + sizeof(wlmtk_element_impl_t)); + workspace_ptr->super_container.super_element.impl.pointer_motion = + element_pointer_motion; + workspace_ptr->super_container.super_element.impl.pointer_button = + element_pointer_button; + workspace_ptr->super_container.super_element.impl.pointer_leave = + element_pointer_leave; return workspace_ptr; } @@ -183,43 +204,33 @@ bool wlmtk_workspace_motion( double y, uint32_t time_msec) { - bool rv = wlmtk_element_pointer_motion( + return wlmtk_element_pointer_motion( &workspace_ptr->super_container.super_element, x, y, time_msec); - handle_state(workspace_ptr, POINTER_STATE_EVENT_MOTION, NULL); - return rv; } /* ------------------------------------------------------------------------- */ -// TODO(kaeser@gubbe.ch): Improe this, and add tests to tatch UP to CLICK. +// TODO(kaeser@gubbe.ch): Improve this, and add tests to tatch UP to CLICK. void wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, const struct wlr_pointer_button_event *event_ptr) { wlmtk_button_event_t event; - wlmtk_element_t *focused_element_ptr; - - if (WLR_BUTTON_RELEASED == event_ptr->state) { - handle_state(workspace_ptr, - POINTER_STATE_EVENT_BTN_RELEASED, - NULL); - } // Guard clause: nothing to pass on if no element has the focus. - focused_element_ptr = - workspace_ptr->super_container.pointer_focus_element_ptr; - if (NULL == focused_element_ptr) return; - event.button = event_ptr->button; event.time_msec = event_ptr->time_msec; if (WLR_BUTTON_PRESSED == event_ptr->state) { event.type = WLMTK_BUTTON_DOWN; - wlmtk_element_pointer_button(focused_element_ptr, &event); + wlmtk_element_pointer_button( + &workspace_ptr->super_container.super_element, &event); } else if (WLR_BUTTON_RELEASED == event_ptr->state) { event.type = WLMTK_BUTTON_UP; - wlmtk_element_pointer_button(focused_element_ptr, &event); + wlmtk_element_pointer_button( + &workspace_ptr->super_container.super_element, &event); event.type = WLMTK_BUTTON_CLICK; - wlmtk_element_pointer_button(focused_element_ptr, &event); + wlmtk_element_pointer_button( + &workspace_ptr->super_container.super_element, &event); } else { bs_log(BS_WARNING, @@ -247,6 +258,76 @@ void workspace_container_destroy(wlmtk_container_t *container_ptr) wlmtk_workspace_destroy(workspace_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Extends wlmtk_container_t::pointer_button: Feeds the motion into the + * workspace's pointer state machine, and only passes it to the container's + * handler if the event isn't consumed yet. + * + * @param element_ptr + * @param x + * @param y + * @param time_msec + * + * @return Whether the motion encountered an active element. + */ +bool element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + uint32_t time_msec) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_workspace_t, super_container.super_element); + + handle_state(workspace_ptr, POINTER_STATE_EVENT_MOTION, NULL); + + return workspace_ptr->parent_element_impl.pointer_motion( + element_ptr, x, y, time_msec); +} + +/* ------------------------------------------------------------------------- */ +/** + * Extends wlmtk_container_t::pointer_button. + * + * @param element_ptr + * @param button_event_ptr + * + * @return Whether the button event was consumed. + */ +bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_workspace_t, super_container.super_element); + + if (button_event_ptr->type == WLMTK_BUTTON_UP) { + handle_state(workspace_ptr, + POINTER_STATE_EVENT_BTN_RELEASED, + NULL); + } + + return workspace_ptr->parent_element_impl.pointer_button( + element_ptr, button_event_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Extends wlmtk_container_t::leave. + * + * @param element_ptr + */ +void element_pointer_leave( + wlmtk_element_t *element_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_workspace_t, super_container.super_element); + + handle_state(workspace_ptr, POINTER_STATE_EVENT_RESET, NULL); + + workspace_ptr->parent_element_impl.pointer_leave(element_ptr); +} + /* ------------------------------------------------------------------------- */ /** State machine handler. */ void handle_state(wlmtk_workspace_t *workspace_ptr, From c91518d4ed1a9eed7fd4f1f1dff0528b49ed5c43 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 16:11:46 +0200 Subject: [PATCH 113/390] Adds an abstracted finite-state machine handler. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/fsm.c | 59 +++++++++++++++++++++++ src/toolkit/fsm.h | 98 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 src/toolkit/fsm.c create mode 100644 src/toolkit/fsm.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 29299073..e571fd24 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -24,6 +24,7 @@ SET(PUBLIC_HEADER_FILES container.h content.h element.h + fsm.h window.h workspace.h) @@ -32,6 +33,7 @@ TARGET_SOURCES(toolkit PRIVATE element.c container.c content.c + fsm.c gfxbuf.c primitives.c util.c diff --git a/src/toolkit/fsm.c b/src/toolkit/fsm.c new file mode 100644 index 00000000..87fe48f3 --- /dev/null +++ b/src/toolkit/fsm.c @@ -0,0 +1,59 @@ +/* ========================================================================= */ +/** + * @file fsm.c + * Event-driven finite state machine. + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fsm.h" + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +void wlmtk_fsm_init( + wlmtk_fsm_t *fsm_ptr, + const wlmtk_fsm_transition_t *transitions, + int initial_state) +{ + fsm_ptr->transitions = transitions; + fsm_ptr->state = initial_state; +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_fsm_event( + wlmtk_fsm_t *fsm_ptr, + int event, + void *ud_ptr) +{ + for (const wlmtk_fsm_transition_t *transition_ptr = fsm_ptr->transitions; + 0 <= transition_ptr->state; + ++transition_ptr) { + if (transition_ptr->state == fsm_ptr->state && + transition_ptr->event == event) { + if (NULL != transition_ptr->handler) { + bool rv = transition_ptr->handler(fsm_ptr, ud_ptr); + fsm_ptr->state = transition_ptr->to_state; + return rv; + } else { + return true; + } + } + } + return false; +} + +/* == End of fsm.c ========================================================= */ diff --git a/src/toolkit/fsm.h b/src/toolkit/fsm.h new file mode 100644 index 00000000..a9361e54 --- /dev/null +++ b/src/toolkit/fsm.h @@ -0,0 +1,98 @@ +/* ========================================================================= */ +/** + * @file fsm.h + * Event-driven finite state machine. + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLTMK_FSM_H__ +#define __WLTMK_FSM_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Forward declaration. */ +typedef struct _wlmtk_fsm_t wlmtk_fsm_t; + +/** State machine definition. */ +typedef struct { + /** State before receiving the event. */ + int state; + /** Event. */ + int event; + /** Upon having (state, event): State to transition to. */ + int to_state; + /** Handler for the activity at (state, event). */ + bool (*handler)(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); +} wlmtk_fsm_transition_t; + +/** Finite state machine. State. */ +struct _wlmtk_fsm_t { + /** The transitions table. */ + const wlmtk_fsm_transition_t *transitions; + /** Current state. */ + int state; +}; + +/** Sentinel element for state transition table. */ +#define WLMTK_FSM_TRANSITION_SENTINEL { \ + .state = -1, \ + .event = -1, \ + .to_state = -1, \ + .handler = NULL, \ + } + +/** + * Initializes the finite-state machine. + * + * @param fsm_ptr + * @param transitions + * @param initial_state + */ +void wlmtk_fsm_init( + wlmtk_fsm_t *fsm_ptr, + const wlmtk_fsm_transition_t *transitions, + int initial_state); + +/** + * Handles an event for the finite-state machine. + * + * Will search for the transition matching (current state, event) and call the + * associate handler. + * + * @param fsm_ptr + * @param event + * @param ud_ptr + * + * @return If a matching transition was found: The return value of the + * associated handler (or true, if no handler was given). Otherwise, + * returns false. + */ +bool wlmtk_fsm_event( + wlmtk_fsm_t *fsm_ptr, + int event, + void *ud_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLTMK_FSM_H__ */ +/* == End of fsm.h ====================================================== */ From 8a6e4e85e153c834034c7ff3e37d13516e61a280 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 16:31:57 +0200 Subject: [PATCH 114/390] Makes use of FSM in workspace for pointer motion. --- src/toolkit/button.h | 3 ++ src/toolkit/fsm.c | 9 ++-- src/toolkit/workspace.c | 110 +++++++++++++++------------------------- 3 files changed, 48 insertions(+), 74 deletions(-) diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 019bfe58..da773ed4 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -20,6 +20,9 @@ #ifndef __WLMTK_BUTTON_H__ #define __WLMTK_BUTTON_H__ +// BTN_LEFT, BTN_RIGHT, ... +#include + /** Forward declaration: Button event. */ typedef struct _wlmtk_button_event_t wlmtk_button_event_t; diff --git a/src/toolkit/fsm.c b/src/toolkit/fsm.c index 87fe48f3..f156edb1 100644 --- a/src/toolkit/fsm.c +++ b/src/toolkit/fsm.c @@ -44,13 +44,12 @@ bool wlmtk_fsm_event( ++transition_ptr) { if (transition_ptr->state == fsm_ptr->state && transition_ptr->event == event) { + bool rv = true; if (NULL != transition_ptr->handler) { - bool rv = transition_ptr->handler(fsm_ptr, ud_ptr); - fsm_ptr->state = transition_ptr->to_state; - return rv; - } else { - return true; + rv = transition_ptr->handler(fsm_ptr, ud_ptr); } + fsm_ptr->state = transition_ptr->to_state; + return rv; } } return false; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index d43e6e7a..54466285 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -20,6 +20,8 @@ #include "workspace.h" +#include "fsm.h" + #define WLR_USE_UNSTABLE #include #include @@ -29,18 +31,17 @@ /** States of the pointer FSM. */ typedef enum { - POINTER_STATE_PASSTHROUGH, - POINTER_STATE_MOVE, - POINTER_STATE_RESIZE + PFSMS_PASSTHROUGH, + PFSMS_MOVE, + PFSMS_RESIZE } pointer_state_t; /** Events for the pointer FSM. */ typedef enum { - POINTER_STATE_EVENT_BEGIN_MOVE, - POINTER_STATE_EVENT_BEGIN_RESIZE, - POINTER_STATE_EVENT_BTN_RELEASED, - POINTER_STATE_EVENT_RESET, - POINTER_STATE_EVENT_MOTION, + PFSME_BEGIN_MOVE, + PFSME_RELEASED, + PFSME_MOTION, + PFSME_RESET, } pointer_state_event_t; /** State of the workspace. */ @@ -51,7 +52,7 @@ struct _wlmtk_workspace_t { wlmtk_element_impl_t parent_element_impl; /** Current FSM state. */ - pointer_state_t current_state; + wlmtk_fsm_t fsm; /** The grabbed window. */ wlmtk_window_t *grabbed_window_ptr; @@ -63,7 +64,6 @@ struct _wlmtk_workspace_t { int initial_x; /** Element's Y position when initiating a move or resize. */ int initial_y; - }; static void workspace_container_destroy(wlmtk_container_t *container_ptr); @@ -95,35 +95,18 @@ typedef struct { void (*handler)(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); } state_transition_t; -static void begin_move(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); -static void move_motion(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); -static void move_end(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); -static void handle_state(wlmtk_workspace_t *workspace_ptr, - pointer_state_event_t event, - void *ud_ptr); +static bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); +static bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); /* == Data ================================================================= */ /** Finite state machine definition for pointer events. */ -static const state_transition_t pointer_states[] = { - { - POINTER_STATE_PASSTHROUGH, - POINTER_STATE_EVENT_BEGIN_MOVE, - POINTER_STATE_MOVE, - begin_move }, - { - POINTER_STATE_MOVE, - POINTER_STATE_EVENT_MOTION, - POINTER_STATE_MOVE, - move_motion - }, - { - POINTER_STATE_MOVE, - POINTER_STATE_EVENT_BTN_RELEASED, - POINTER_STATE_PASSTHROUGH, - move_end, - }, - { 0, 0, 0, NULL } // sentinel. +static const wlmtk_fsm_transition_t pfsm_transitions[] = { + { PFSMS_PASSTHROUGH, PFSME_BEGIN_MOVE, PFSMS_MOVE, pfsm_move_begin }, + { PFSMS_MOVE, PFSME_MOTION, PFSMS_MOVE, pfsm_move_motion }, + { PFSMS_MOVE, PFSME_RELEASED, PFSMS_PASSTHROUGH, NULL }, + { PFSMS_MOVE, PFSME_RESET, PFSMS_PASSTHROUGH, NULL }, + WLMTK_FSM_TRANSITION_SENTINEL, }; /* == Exported methods ===================================================== */ @@ -151,6 +134,8 @@ wlmtk_workspace_t *wlmtk_workspace_create( element_pointer_button; workspace_ptr->super_container.super_element.impl.pointer_leave = element_pointer_leave; + + wlmtk_fsm_init(&workspace_ptr->fsm, pfsm_transitions, PFSMS_PASSTHROUGH); return workspace_ptr; } @@ -244,7 +229,7 @@ void wlmtk_workspace_begin_window_move( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { - handle_state(workspace_ptr, POINTER_STATE_EVENT_BEGIN_MOVE, window_ptr); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_MOVE, window_ptr); } /* == Local (static) methods =============================================== */ @@ -279,7 +264,7 @@ bool element_pointer_motion( wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); - handle_state(workspace_ptr, POINTER_STATE_EVENT_MOTION, NULL); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_MOTION, NULL); return workspace_ptr->parent_element_impl.pointer_motion( element_ptr, x, y, time_msec); @@ -301,10 +286,13 @@ bool element_pointer_button( wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); - if (button_event_ptr->type == WLMTK_BUTTON_UP) { - handle_state(workspace_ptr, - POINTER_STATE_EVENT_BTN_RELEASED, - NULL); + // TODO(kaeser@gubbe.ch): We should retract as to which event had triggered + // the move, and then figure out the exit condition (button up? key? ...) + // from there. + // See xdg_toplevel::move doc at https://wayland.app/protocols/xdg-shell. + if (button_event_ptr->button == BTN_LEFT && + button_event_ptr->type == WLMTK_BUTTON_UP) { + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RELEASED, NULL); } return workspace_ptr->parent_element_impl.pointer_button( @@ -323,34 +311,20 @@ void element_pointer_leave( wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); - handle_state(workspace_ptr, POINTER_STATE_EVENT_RESET, NULL); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); workspace_ptr->parent_element_impl.pointer_leave(element_ptr); } -/* ------------------------------------------------------------------------- */ -/** State machine handler. */ -void handle_state(wlmtk_workspace_t *workspace_ptr, - pointer_state_event_t event, - void *ud_ptr) -{ - for (const state_transition_t *transition_ptr = &pointer_states[0]; - NULL != transition_ptr->handler; - transition_ptr++) { - if (transition_ptr->state == workspace_ptr->current_state && - transition_ptr->event == event) { - transition_ptr->handler(workspace_ptr, ud_ptr); - workspace_ptr->current_state = transition_ptr->new_state; - return; - } - } -} /* ------------------------------------------------------------------------- */ /** Initiates a move. */ -void begin_move(wlmtk_workspace_t *workspace_ptr, void *ud_ptr) +bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) { + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + fsm_ptr, wlmtk_workspace_t, fsm); + workspace_ptr->grabbed_window_ptr = ud_ptr; workspace_ptr->motion_x = workspace_ptr->super_container.super_element.last_pointer_x; @@ -361,13 +335,17 @@ void begin_move(wlmtk_workspace_t *workspace_ptr, void *ud_ptr) wlmtk_window_element(workspace_ptr->grabbed_window_ptr), &workspace_ptr->initial_x, &workspace_ptr->initial_y); + + return true; } /* ------------------------------------------------------------------------- */ /** Handles motion during a move. */ -void move_motion(wlmtk_workspace_t *workspace_ptr, - __UNUSED__ void *ud_ptr) +bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) { + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + fsm_ptr, wlmtk_workspace_t, fsm); + double rel_x = workspace_ptr->super_container.super_element.last_pointer_x - workspace_ptr->motion_x; double rel_y = workspace_ptr->super_container.super_element.last_pointer_y - @@ -377,14 +355,8 @@ void move_motion(wlmtk_workspace_t *workspace_ptr, wlmtk_window_element(workspace_ptr->grabbed_window_ptr), workspace_ptr->initial_x + rel_x, workspace_ptr->initial_y + rel_y); -} -/* ------------------------------------------------------------------------- */ -/** Ends the move. */ -void move_end(__UNUSED__ wlmtk_workspace_t *workspace_ptr, - __UNUSED__ void *ud_ptr) -{ - // Nothing to do. + return true; } /* == Unit tests =========================================================== */ From 25395656e1f267da99339b1f20fb602c928c4d22 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 16:50:02 +0200 Subject: [PATCH 115/390] Adds method to reset the pointer state machine, and handles unmap during move. --- src/toolkit/workspace.c | 43 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 54466285..6f5cbc2d 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -78,34 +78,23 @@ static bool element_pointer_button( static void element_pointer_leave( wlmtk_element_t *element_ptr); -/** Method table for the container's virtual methods. */ -const wlmtk_container_impl_t workspace_container_impl = { - .destroy = workspace_container_destroy -}; - -/** State machine definition. */ -typedef struct { - /** Starting state. */ - pointer_state_t state; - /** Event. */ - pointer_state_event_t event; - /** Updated state. */ - pointer_state_t new_state; - /** Handler invoked by the (state, event) match. */ - void (*handler)(wlmtk_workspace_t *workspace_ptr, void *ud_ptr); -} state_transition_t; - static bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); +static bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); /* == Data ================================================================= */ +/** Method table for the container's virtual methods. */ +const wlmtk_container_impl_t workspace_container_impl = { + .destroy = workspace_container_destroy +}; + /** Finite state machine definition for pointer events. */ static const wlmtk_fsm_transition_t pfsm_transitions[] = { { PFSMS_PASSTHROUGH, PFSME_BEGIN_MOVE, PFSMS_MOVE, pfsm_move_begin }, { PFSMS_MOVE, PFSME_MOTION, PFSMS_MOVE, pfsm_move_motion }, - { PFSMS_MOVE, PFSME_RELEASED, PFSMS_PASSTHROUGH, NULL }, - { PFSMS_MOVE, PFSME_RESET, PFSMS_PASSTHROUGH, NULL }, + { PFSMS_MOVE, PFSME_RELEASED, PFSMS_PASSTHROUGH, pfsm_reset }, + { PFSMS_MOVE, PFSME_RESET, PFSMS_PASSTHROUGH, pfsm_reset }, WLMTK_FSM_TRANSITION_SENTINEL, }; @@ -165,6 +154,12 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, { BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( wlmtk_window_element(window_ptr)->parent_container_ptr)); + + if (workspace_ptr->grabbed_window_ptr == window_ptr) { + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); + BS_ASSERT(NULL == workspace_ptr->grabbed_window_ptr); + } + wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); wlmtk_container_remove_element( &workspace_ptr->super_container, @@ -359,6 +354,16 @@ bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) return true; } +/* ------------------------------------------------------------------------- */ +/** Resets the state machine. */ +bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + fsm_ptr, wlmtk_workspace_t, fsm); + workspace_ptr->grabbed_window_ptr = NULL; + return true; +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); From 073caefd088af6bef43690aa83717860d8065377 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 16:50:58 +0200 Subject: [PATCH 116/390] Moves enum definitions to data section. --- src/toolkit/workspace.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 6f5cbc2d..414692fe 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -29,21 +29,6 @@ /* == Declarations ========================================================= */ -/** States of the pointer FSM. */ -typedef enum { - PFSMS_PASSTHROUGH, - PFSMS_MOVE, - PFSMS_RESIZE -} pointer_state_t; - -/** Events for the pointer FSM. */ -typedef enum { - PFSME_BEGIN_MOVE, - PFSME_RELEASED, - PFSME_MOTION, - PFSME_RESET, -} pointer_state_event_t; - /** State of the workspace. */ struct _wlmtk_workspace_t { /** Superclass: Container. */ @@ -84,6 +69,21 @@ static bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); /* == Data ================================================================= */ +/** States of the pointer FSM. */ +typedef enum { + PFSMS_PASSTHROUGH, + PFSMS_MOVE, + PFSMS_RESIZE +} pointer_state_t; + +/** Events for the pointer FSM. */ +typedef enum { + PFSME_BEGIN_MOVE, + PFSME_RELEASED, + PFSME_MOTION, + PFSME_RESET, +} pointer_state_event_t; + /** Method table for the container's virtual methods. */ const wlmtk_container_impl_t workspace_container_impl = { .destroy = workspace_container_destroy From 7d2c54ea6f0515a99924226aadd5e7ec295e31c2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 17:18:16 +0200 Subject: [PATCH 117/390] Adds two testcases for moving windows. --- src/toolkit/workspace.c | 97 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 414692fe..8da08e5f 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -369,12 +369,15 @@ bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) static void test_create_destroy(bs_test_t *test_ptr); static void test_map_unmap(bs_test_t *test_ptr); static void test_button(bs_test_t *test_ptr); - +static void test_move(bs_test_t *test_ptr); +static void test_unmap_during_move(bs_test_t *test_ptr); const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "create_destroy", test_create_destroy }, { 1, "map_unmap", test_map_unmap }, { 1, "button", test_button }, - { 0, NULL, NULL } + { 1, "move", test_move }, + { 1, "unmap_during_move", test_unmap_during_move }, +{ 0, NULL, NULL } }; /* ------------------------------------------------------------------------- */ @@ -500,4 +503,94 @@ void test_button(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests moving a window. */ +void test_move(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + fake_parent_ptr->wlr_scene_tree_ptr); + BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + &fake_content_ptr->content); + BS_ASSERT(NULL != window_ptr); + wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); + + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + + // Starts a move for the window. Will move it... + wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); + wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + + // Releases the button. Should end the move. + struct wlr_pointer_button_event wlr_pointer_button_event = { + .button = BTN_LEFT, + .state = WLR_BUTTON_RELEASED, + .time_msec = 44, + }; + wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + + // More motion, no longer updates the position. + wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + + wlmtk_window_destroy(window_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy(fake_parent_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests moving a window that unmaps during the move. */ +void test_unmap_during_move(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + fake_parent_ptr->wlr_scene_tree_ptr); + BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + &fake_content_ptr->content); + BS_ASSERT(NULL != window_ptr); + wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); + + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + + // Starts a move for the window. Will move it... + wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); + wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + + // More motion, no longer updates the position. + wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + + + // More motion, no longer updates the position. + wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + + wlmtk_window_destroy(window_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy(fake_parent_ptr); +} + /* == End of workspace.c =================================================== */ From 35e880a25bc2768fc735a588b5151acbb76765ef Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 17:30:00 +0200 Subject: [PATCH 118/390] Adds unit tests for finite state machine. --- src/toolkit/fsm.c | 45 ++++++++++++++++++++++++++++++++++++++ src/toolkit/fsm.h | 4 ++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + src/toolkit/workspace.c | 3 ++- 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/toolkit/fsm.c b/src/toolkit/fsm.c index f156edb1..3dac125a 100644 --- a/src/toolkit/fsm.c +++ b/src/toolkit/fsm.c @@ -55,4 +55,49 @@ bool wlmtk_fsm_event( return false; } +/* == Unit tests =========================================================== */ + +static void test_event(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_fsm_test_cases[] = { + { 1, "event", test_event }, + { 0, NULL, NULL } +}; + +static bool test_fsm_handler(__UNUSED__ wlmtk_fsm_t *fsm_ptr, void *ud_ptr) { + *((bool*)ud_ptr) = true; + return true; +} + +static const wlmtk_fsm_transition_t test_transitions[] = { + { 1, 100, 2, test_fsm_handler }, + { 2, 101, 3, NULL }, + WLMTK_FSM_TRANSITION_SENTINEL +}; + +/* ------------------------------------------------------------------------- */ +/** Tests FSM. */ +void test_event(bs_test_t *test_ptr) +{ + wlmtk_fsm_t fsm; + bool called = false; + + wlmtk_fsm_init(&fsm, test_transitions, 1); + BS_TEST_VERIFY_EQ(test_ptr, 1, fsm.state); + + // (1, 100) should trigger call to handler and move to (2). + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_fsm_event(&fsm, 100, &called)); + BS_TEST_VERIFY_EQ(test_ptr, 2, fsm.state); + BS_TEST_VERIFY_TRUE(test_ptr, called); + called = false; + + // (2, 100) is not defined. return false. + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_fsm_event(&fsm, 100, &called)); + + // (2, 101) is defined. No handler == no crash. moves to (3). + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_fsm_event(&fsm, 101, &called)); + BS_TEST_VERIFY_EQ(test_ptr, 3, fsm.state); + BS_TEST_VERIFY_FALSE(test_ptr, called); +} + /* == End of fsm.c ========================================================= */ diff --git a/src/toolkit/fsm.h b/src/toolkit/fsm.h index a9361e54..31f5f143 100644 --- a/src/toolkit/fsm.h +++ b/src/toolkit/fsm.h @@ -23,6 +23,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -90,6 +91,9 @@ bool wlmtk_fsm_event( int event, void *ud_ptr); +/** Unit tests for the finite-state machine. */ +extern const bs_test_case_t wlmtk_fsm_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 12408465..6fb81caa 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -33,6 +33,7 @@ #include "container.h" #include "content.h" #include "element.h" +#include "fsm.h" #include "window.h" #include "workspace.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index b3018578..fa080c22 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -25,6 +25,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "container", wlmtk_container_test_cases }, { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, + { 1, "fsm", wlmtk_fsm_test_cases }, { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 8da08e5f..078ebc01 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -371,13 +371,14 @@ static void test_map_unmap(bs_test_t *test_ptr); static void test_button(bs_test_t *test_ptr); static void test_move(bs_test_t *test_ptr); static void test_unmap_during_move(bs_test_t *test_ptr); + const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "create_destroy", test_create_destroy }, { 1, "map_unmap", test_map_unmap }, { 1, "button", test_button }, { 1, "move", test_move }, { 1, "unmap_during_move", test_unmap_during_move }, -{ 0, NULL, NULL } + { 0, NULL, NULL } }; /* ------------------------------------------------------------------------- */ From 87c60dab5acd082f5fa29cb3ad4969ec1040bc93 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 20 Oct 2023 17:31:30 +0200 Subject: [PATCH 119/390] Adds some missing doxygen comments. --- src/toolkit/fsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/toolkit/fsm.c b/src/toolkit/fsm.c index 3dac125a..20661522 100644 --- a/src/toolkit/fsm.c +++ b/src/toolkit/fsm.c @@ -64,11 +64,12 @@ const bs_test_case_t wlmtk_fsm_test_cases[] = { { 0, NULL, NULL } }; +/** Test handler for the FSM unit test: Sets the bool to true. */ static bool test_fsm_handler(__UNUSED__ wlmtk_fsm_t *fsm_ptr, void *ud_ptr) { *((bool*)ud_ptr) = true; return true; } - +/** Test transition table for the FSM unit test. */ static const wlmtk_fsm_transition_t test_transitions[] = { { 1, 100, 2, test_fsm_handler }, { 2, 101, 3, NULL }, From 1a921c39f188b33d4a3ed681d059bacbc93ddbd1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 12:59:13 +0200 Subject: [PATCH 120/390] Wires up client-initiated resizes. --- src/toolkit/content.c | 21 ++++++++- src/toolkit/content.h | 9 ++++ src/toolkit/window.c | 30 +++++++++++++ src/toolkit/window.h | 35 +++++++++++++++ src/toolkit/workspace.c | 92 ++++++++++++++++++++++++++++++++++++++++ src/toolkit/workspace.h | 12 ++++++ src/wlmtk_xdg_toplevel.c | 63 +++++++++++++++++++++++++-- 7 files changed, 257 insertions(+), 5 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 798a2f68..03aabc7a 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -84,6 +84,7 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); BS_ASSERT(NULL != content_impl_ptr->get_size); + BS_ASSERT(NULL != content_impl_ptr->set_size); BS_ASSERT(NULL != content_impl_ptr->set_activated); if (!wlmtk_element_init(&content_ptr->super_element, @@ -355,6 +356,10 @@ static void fake_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); +static void fake_content_set_size( + wlmtk_content_t *content_ptr, + int width, + int height); static void fake_content_set_activated( wlmtk_content_t *content_ptr, bool activated); @@ -364,6 +369,7 @@ static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, .create_scene_node = fake_content_create_scene_node, .get_size = fake_content_get_size, + .set_size = fake_content_set_size, .set_activated = fake_content_set_activated, }; @@ -424,6 +430,18 @@ void fake_content_get_size( if (NULL != height_ptr) *height_ptr = fake_content_ptr->height; } +/* ------------------------------------------------------------------------- */ +/** Sets the size of the fake content. */ +void fake_content_set_size( + wlmtk_content_t *content_ptr, + int width, int height) +{ + wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_fake_content_t, content); + fake_content_ptr->width = width; + fake_content_ptr->height = height; +} + /* ------------------------------------------------------------------------- */ /** Sets the content's activated status. */ void fake_content_set_activated( @@ -462,8 +480,7 @@ void test_init_fini(bs_test_t *test_ptr) fake_content_ptr->content.impl.destroy); int l, t, r, b; - fake_content_ptr->width = 42; - fake_content_ptr->height = 21; + wlmtk_content_set_size(&fake_content_ptr->content, 42, 21); wlmtk_element_get_dimensions( &fake_content_ptr->content.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, 0, l); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 6434abab..f666b688 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -43,6 +43,9 @@ struct _wlmtk_content_impl_t { /** Gets width and height of the content. */ void (*get_size)(wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); + /** Sets width and height of the content. */ + void (*set_size)(wlmtk_content_t *content_ptr, + int width, int height); /** Sets whether the content is activated (has keyboard focus). */ void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); }; @@ -127,6 +130,12 @@ static inline void wlmtk_content_get_size( int *width_ptr, int *height_ptr) { content_ptr->impl.get_size(content_ptr, width_ptr, height_ptr); } +/** Wraps to @ref wlmtk_content_impl_t::set_size. */ +static inline void wlmtk_content_set_size( + wlmtk_content_t *content_ptr, + int width, int height) { + content_ptr->impl.set_size(content_ptr, width, height); +} /** Wraps to @ref wlmtk_content_impl_t::set_activated. */ static inline void wlmtk_content_set_activated( wlmtk_content_t *content_ptr, diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f9f6aa81..44653fe5 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -107,6 +107,26 @@ void wlmtk_window_set_server_side_decorated( window_ptr, decorated); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr) +{ + // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. + wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_size( + wlmtk_window_t *window_ptr, + int width, + int height) +{ + // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. + wlmtk_content_set_size(window_ptr->content_ptr, width, height); +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { @@ -117,6 +137,16 @@ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) +{ + BS_ASSERT(NULL != + window_ptr->super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_container.super_element.parent_container_ptr); + wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 8118047b..b913aa1c 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -83,6 +83,30 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); +/** + * Obtains the size of the window, including potential decorations. + * + * @param window_ptr + * @param width_ptr May be NULL. + * @param height_ptr May be NULL. + */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr); + +/** + * Sets the size of the window, including potential decorations. + * + * @param window_ptr + * @param width + * @param height + */ +void wlmtk_window_set_size( + wlmtk_window_t *window_ptr, + int width, + int height); + /** * Requests a move for the window. * @@ -93,6 +117,17 @@ void wlmtk_window_set_server_side_decorated( */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr); +/** + * Requests the window to be resized. + * + * Requires the window to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_window_resize. + * + * @param window_ptr + * @param edges + */ +void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 078ebc01..e0ebd151 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -25,6 +25,7 @@ #define WLR_USE_UNSTABLE #include #include +#include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -49,6 +50,12 @@ struct _wlmtk_workspace_t { int initial_x; /** Element's Y position when initiating a move or resize. */ int initial_y; + /** Window's width when initiazing the resize. */ + int initial_width; + /** Window's height when initiazing the resize. */ + int initial_height; + /** Edges currently active for resizing: `enum wlr_edges`. */ + uint32_t resize_edges; }; static void workspace_container_destroy(wlmtk_container_t *container_ptr); @@ -65,6 +72,8 @@ static void element_pointer_leave( static bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); +static bool pfsm_resize_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); +static bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); /* == Data ================================================================= */ @@ -79,6 +88,7 @@ typedef enum { /** Events for the pointer FSM. */ typedef enum { PFSME_BEGIN_MOVE, + PFSME_BEGIN_RESIZE, PFSME_RELEASED, PFSME_MOTION, PFSME_RESET, @@ -95,6 +105,10 @@ static const wlmtk_fsm_transition_t pfsm_transitions[] = { { PFSMS_MOVE, PFSME_MOTION, PFSMS_MOVE, pfsm_move_motion }, { PFSMS_MOVE, PFSME_RELEASED, PFSMS_PASSTHROUGH, pfsm_reset }, { PFSMS_MOVE, PFSME_RESET, PFSMS_PASSTHROUGH, pfsm_reset }, + { PFSMS_PASSTHROUGH, PFSME_BEGIN_RESIZE, PFSMS_RESIZE, pfsm_resize_begin }, + { PFSMS_RESIZE, PFSME_MOTION, PFSMS_RESIZE, pfsm_resize_motion }, + { PFSMS_RESIZE, PFSME_RELEASED, PFSMS_PASSTHROUGH, pfsm_reset }, + { PFSMS_RESIZE, PFSME_RESET, PFSMS_PASSTHROUGH, pfsm_reset }, WLMTK_FSM_TRANSITION_SENTINEL, }; @@ -227,6 +241,16 @@ void wlmtk_workspace_begin_window_move( wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_MOVE, window_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_begin_window_resize( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr, + uint32_t edges) +{ + workspace_ptr->resize_edges = edges; + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_RESIZE, window_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -354,6 +378,74 @@ bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) return true; } +/* ------------------------------------------------------------------------- */ +/** Initiates a resize. */ +bool pfsm_resize_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + fsm_ptr, wlmtk_workspace_t, fsm); + + workspace_ptr->grabbed_window_ptr = ud_ptr; + workspace_ptr->motion_x = + workspace_ptr->super_container.super_element.last_pointer_x; + workspace_ptr->motion_y = + workspace_ptr->super_container.super_element.last_pointer_y; + + wlmtk_element_get_position( + wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + &workspace_ptr->initial_x, + &workspace_ptr->initial_y); + + wlmtk_window_get_size( + workspace_ptr->grabbed_window_ptr, + &workspace_ptr->initial_width, + &workspace_ptr->initial_height); + + return true; +} + +/* ------------------------------------------------------------------------- */ +/** Handles motion during a resize. */ +bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + fsm_ptr, wlmtk_workspace_t, fsm); + + double rel_x = workspace_ptr->super_container.super_element.last_pointer_x - + workspace_ptr->motion_x; + double rel_y = workspace_ptr->super_container.super_element.last_pointer_y - + workspace_ptr->motion_y; + + // Update new boundaries by the relative movement. + int top = workspace_ptr->initial_y; + int bottom = workspace_ptr->initial_y + workspace_ptr->initial_height; + if (workspace_ptr->resize_edges & WLR_EDGE_TOP) { + top += rel_y; + if (top >= bottom) top = bottom - 1; + } else if (workspace_ptr->resize_edges & WLR_EDGE_BOTTOM) { + bottom += rel_y; + if (bottom <= top) bottom = top + 1; + } + + int left = workspace_ptr->initial_x; + int right = workspace_ptr->initial_x + workspace_ptr->initial_width; + if (workspace_ptr->resize_edges & WLR_EDGE_LEFT) { + left += rel_x; + if (left >= right) left = right - 1 ; + } else if (workspace_ptr->resize_edges & WLR_EDGE_RIGHT) { + right += rel_x; + if (right <= left) right = left + 1; + } + + wlmtk_element_set_position( + wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + left, top); + wlmtk_window_set_size( + workspace_ptr->grabbed_window_ptr, + right - left, bottom - top); + return true; +} + /* ------------------------------------------------------------------------- */ /** Resets the state machine. */ bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 5c805355..d5799e60 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -120,6 +120,18 @@ void wlmtk_workspace_begin_window_move( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); +/** + * Initiates a 'resize' for the window. + * + * @param workspace_ptr + * @param window_ptr + * @param edges + */ +void wlmtk_workspace_begin_window_resize( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr, + uint32_t edges); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index de766ce9..b90739b7 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -40,8 +40,10 @@ typedef struct { /** Listener for the `unmap` signal of the `wlr_surface`. */ struct wl_listener surface_unmap_listener; - /** Listener for the `move` signal of the `wlr_xdg_toplevel`. */ + /** Listener for `request_move` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_move_listener; + /** Listener for `request_resize` signal of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_request_resize_listener; } wlmtk_xdg_toplevel_content_t; static wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( @@ -60,6 +62,9 @@ static void handle_surface_unmap( static void handle_toplevel_request_move( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_request_resize( + struct wl_listener *listener_ptr, + void *data_ptr); static void content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *content_create_scene_node( @@ -69,6 +74,10 @@ static void content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); +static void content_set_size( + wlmtk_content_t *content_ptr, + int width, + int height); static void content_set_activated( wlmtk_content_t *content_ptr, bool activated); @@ -80,6 +89,7 @@ const wlmtk_content_impl_t content_impl = { .destroy = content_destroy, .create_scene_node = content_create_scene_node, .get_size = content_get_size, + .set_size = content_set_size, .set_activated = content_set_activated, }; @@ -138,6 +148,10 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &wlr_xdg_surface_ptr->toplevel->events.request_move, &xdg_tl_content_ptr->toplevel_request_move_listener, handle_toplevel_request_move); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.request_resize, + &xdg_tl_content_ptr->toplevel_request_resize_listener, + handle_toplevel_request_resize); xdg_tl_content_ptr->wlr_xdg_surface_ptr->data = &xdg_tl_content_ptr->super_content; @@ -153,6 +167,7 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( void xdg_toplevel_content_destroy( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) { + wl_list_remove(&xdg_tl_content_ptr->toplevel_request_resize_listener.link); wl_list_remove(&xdg_tl_content_ptr->toplevel_request_move_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); @@ -200,7 +215,7 @@ struct wlr_scene_node *content_create_scene_node( /* ------------------------------------------------------------------------- */ /** - * Gets the dimensions of the element in pixels, relative to the position. + * Gets the dimensions of the element in pixels. * * @param content_ptr * @param width_ptr Width of content. May be NULL. @@ -223,6 +238,27 @@ void content_get_size( if (NULL != height_ptr) *height_ptr = geo_box.height; } +/* ------------------------------------------------------------------------- */ +/** + * Sets the dimensions of the element in pixels. + * + * @param content_ptr + * @param width Width of content. + * @param height Height of content. + */ +void content_set_size( + wlmtk_content_t *content_ptr, + int width, + int height) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + // FIXME: Catch serial. + wlr_xdg_toplevel_set_size( + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, width, height); +} + /* ------------------------------------------------------------------------- */ /** * Sets the keyboard activation status for the surface. @@ -315,7 +351,7 @@ void handle_surface_unmap( /* ------------------------------------------------------------------------- */ /** - * Handler for the `reuqest_move` signal. + * Handler for the `request_move` signal. * * @param listener_ptr * @param data_ptr @@ -331,4 +367,25 @@ void handle_toplevel_request_move( wlmtk_window_request_move(xdg_tl_content_ptr->super_content.window_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `requestp_resize` signal. + * + * @param listener_ptr + * @param data_ptr Points to a struct wlr_xdg_toplevel_resize_event. + */ +void handle_toplevel_request_resize( + struct wl_listener *listener_ptr, + void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_content_t, + toplevel_request_resize_listener); + struct wlr_xdg_toplevel_resize_event *resize_event_ptr = data_ptr; + wlmtk_window_request_resize( + xdg_tl_content_ptr->super_content.window_ptr, + resize_event_ptr->edges); +} + /* == End of xdg_toplevel.c ================================================ */ From 20fbb737a9bc65d33418eefa9ee4da5c52696348 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 13:25:12 +0200 Subject: [PATCH 121/390] Adds unit tests for window resizing. --- src/toolkit/workspace.c | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index e0ebd151..6e974db4 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -463,6 +463,7 @@ static void test_map_unmap(bs_test_t *test_ptr); static void test_button(bs_test_t *test_ptr); static void test_move(bs_test_t *test_ptr); static void test_unmap_during_move(bs_test_t *test_ptr); +static void test_resize(bs_test_t *test_ptr); const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "create_destroy", test_create_destroy }, @@ -470,6 +471,7 @@ const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "button", test_button }, { 1, "move", test_move }, { 1, "unmap_during_move", test_unmap_during_move }, + { 1, "resize", test_resize }, { 0, NULL, NULL } }; @@ -686,4 +688,53 @@ void test_unmap_during_move(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests resizing a window. */ +void test_resize(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + fake_parent_ptr->wlr_scene_tree_ptr); + BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_content_set_size(&fake_content_ptr->content, 40, 20); + wlmtk_window_t *window_ptr = wlmtk_window_create( + &fake_content_ptr->content); + BS_ASSERT(NULL != window_ptr); + wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); + + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + int width, height; + wlmtk_window_get_size(window_ptr, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 40, width); + BS_TEST_VERIFY_EQ(test_ptr, 20, height); + + // Starts a resize for the window. Will resize & move it... + wlmtk_workspace_begin_window_resize( + workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); + wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + wlmtk_window_get_size(window_ptr, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 39, width); + BS_TEST_VERIFY_EQ(test_ptr, 18, height); + + // Releases the button. Should end the move. + struct wlr_pointer_button_event wlr_pointer_button_event = { + .button = BTN_LEFT, + .state = WLR_BUTTON_RELEASED, + .time_msec = 44, + }; + wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_window_destroy(window_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy(fake_parent_ptr); +} + /* == End of workspace.c =================================================== */ From fb0878b50305ea283b2df5d9e57106613d174ff1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 13:42:07 +0200 Subject: [PATCH 122/390] Improves documentations and adds TODOs at various shortcomings. --- src/toolkit/window.c | 8 +++++++- src/toolkit/workspace.c | 9 ++++----- src/toolkit/workspace.h | 13 ++++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 44653fe5..769b4107 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -125,6 +125,13 @@ void wlmtk_window_set_size( { // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. wlmtk_content_set_size(window_ptr->content_ptr, width, height); + + // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting + // the size is an asynchronous operation and should be handled as such. + // Meaning: In example of resizing at the top-left corner, we'll want to + // request the content to adjust size, but wait with adjusting the + // content position until the size adjustment is applied. This implies we + // may need to combine the set_size and set_position methods for window. } /* ------------------------------------------------------------------------- */ @@ -200,5 +207,4 @@ void test_set_activated(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); } - /* == End of window.c ====================================================== */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 6e974db4..31d7c592 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -203,7 +203,8 @@ bool wlmtk_workspace_motion( } /* ------------------------------------------------------------------------- */ -// TODO(kaeser@gubbe.ch): Improve this, and add tests to tatch UP to CLICK. +// TODO(kaeser@gubbe.ch): Improve this, has multiple bugs: It won't keep +// different buttons apart, and there's currently no test associated. void wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, const struct wlr_pointer_button_event *event_ptr) @@ -329,14 +330,10 @@ void element_pointer_leave( { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); - wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); - workspace_ptr->parent_element_impl.pointer_leave(element_ptr); } - - /* ------------------------------------------------------------------------- */ /** Initiates a move. */ bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) @@ -355,6 +352,8 @@ bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) &workspace_ptr->initial_x, &workspace_ptr->initial_y); + // TODO(kaeser@gubbe.ch): When in move mode, set (and keep) a corresponding + // cursor image. return true; } diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index d5799e60..f7cf09c0 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -85,6 +85,16 @@ wlmtk_workspace_t *wlmtk_workspace_from_container( /** * Handles a motion event. + * + * TODO(kaeser@gubbe.ch): Move this to the server, and have the workspace's + * motion handling dealt with the element's pointer_motion method. + * + * @param workspace_ptr + * @param x + * @param y + * @param time_msec + * + * @return Whether there was an element under the pointer. */ bool wlmtk_workspace_motion( wlmtk_workspace_t *workspace_ptr, @@ -101,7 +111,8 @@ bool wlmtk_workspace_motion( * DRAG event. * These events will be forwarded to the event currently having pointer focus. * - * TODO(kaeser@gubbe.ch): Implement DOUBLE_CLICK and DRAG events. + * TODO(kaeser@gubbe.ch): Implement DOUBLE_CLICK and DRAG events. Also, move + * this code into the server and make it well tested. * * @param workspace_ptr * @param event_ptr From 8d20a41164b44b8c9326afc967850a42c613c5ee Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 13:53:46 +0200 Subject: [PATCH 123/390] Adds 'Cursor' class to diagram, as proposal. --- src/toolkit/toolkit.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index dcf5c5a2..cf295c66 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -184,6 +184,14 @@ class MenuItem { } Buffer <|-- MenuItem + +class Cursor { + Cursor *create() + void destroy() + + attach_input_device(struct wlr_input_device*) + set_image(const char * +} ``` ### Pending work From 32de4e4f70b1525bbcdf453391aca76197ffe3e8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 13:58:02 +0200 Subject: [PATCH 124/390] Cleans up some of the toolkit documentation. --- src/toolkit/toolkit.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index cf295c66..9815e185 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -29,6 +29,7 @@ class Element { Container *parent_container_ptr bool init(handlers) + bool init_attached(handlers, struct wlr_scene_tree *) void fini() -void set_parent_container(Container*) -void attach_to_scene_graph() @@ -64,10 +65,6 @@ class Container { -struct wlr_scene_tree *wlr_scene_tree() {abstract}#void destroy() - - void motion(double, double) - void leave() - void click() } Element <|-- Container note right of Element::"add_element(Element*)" @@ -113,12 +110,11 @@ abstract class Content { Element *element() -set_window(Window*) + {abstract}#void get_size(int *, int *) + {abstract}#void set_size(int, int) {abstract}#void set_activated(bool) {abstract}#void set_maximized(bool) {abstract}#void set_fullscreen(bool) - {abstract}#void motion(double, double) - {abstract}#void leave() - {abstract}#void click() } Element <|-- Content note right of Content @@ -130,10 +126,6 @@ end note class LayerElement { Element parent - {abstract}#void motion(double, double) - {abstract}#void leave() - {abstract}#void click() - {abstract}#configure() } Element <|-- LayerElement @@ -167,6 +159,8 @@ class Window { set_activated(bool) set_server_side_decorated(bool) + get_size(int *, int *) + set_size(int, int) } VBox *-- Window From 22396d9c991b93e0dcc91cf86e81933841a2c89e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 15:19:48 +0200 Subject: [PATCH 125/390] Tiny whitespace cleanup. --- src/toolkit/content.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolkit/content.h b/src/toolkit/content.h index f666b688..5b66f727 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -91,6 +91,7 @@ bool wlmtk_content_init( wlmtk_content_t *content_ptr, const wlmtk_content_impl_t *content_impl_ptr, struct wlr_seat *wlr_seat_ptr); + /** * Cleans up the content. * From 26722c9437ff3d561e78481849ce8215a90769ad Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 15:20:12 +0200 Subject: [PATCH 126/390] Minor formatting cleanup, and keep super_element_impl static in content. --- src/toolkit/content.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 03aabc7a..750648f1 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -58,7 +58,7 @@ static bool element_pointer_button( /* == Data ================================================================= */ /** Method table for the container's virtual methods. */ -const wlmtk_element_impl_t super_element_impl = { +static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, @@ -95,7 +95,8 @@ bool wlmtk_content_init( content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; - memcpy(&content_ptr->impl, content_impl_ptr, sizeof(wlmtk_content_impl_t)); return true; + memcpy(&content_ptr->impl, content_impl_ptr, sizeof(wlmtk_content_impl_t)); + return true; } /* ------------------------------------------------------------------------- */ From d7286c2a740dad853364ed69933e020312b887b3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 15:21:50 +0200 Subject: [PATCH 127/390] Adds wlmtk_buffer_t as class for showing a WLR buffer as a toolkit element. --- src/toolkit/CMakeLists.txt | 4 +- src/toolkit/buffer.c | 172 +++++++++++++++++++++++++++++++++++++ src/toolkit/buffer.h | 100 +++++++++++++++++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit.md | 26 ++++-- 5 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 src/toolkit/buffer.c create mode 100644 src/toolkit/buffer.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index e571fd24..179be571 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -21,6 +21,7 @@ SET(PUBLIC_HEADER_FILES toolkit.h util.h + buffer.h container.h content.h element.h @@ -30,9 +31,10 @@ SET(PUBLIC_HEADER_FILES ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE - element.c + buffer.c container.c content.c + element.c fsm.c gfxbuf.c primitives.c diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c new file mode 100644 index 00000000..d36f2c06 --- /dev/null +++ b/src/toolkit/buffer.c @@ -0,0 +1,172 @@ +/* ========================================================================= */ +/** + * @file buffer.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "buffer.h" + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +static void element_destroy(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +static void element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); + +/* == Data ================================================================= */ + +/** Method table for the buffer's virtual methods. */ +static const wlmtk_element_impl_t super_element_impl = { + .destroy = element_destroy, + .create_scene_node = element_create_scene_node, + .get_dimensions = element_get_dimensions, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_buffer_init( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_buffer_impl_t *buffer_impl_ptr, + struct wlr_buffer *wlr_buffer_ptr) +{ + BS_ASSERT(NULL != buffer_ptr); + memset(buffer_ptr, 0, sizeof(wlmtk_buffer_t)); + BS_ASSERT(NULL != buffer_impl_ptr); + BS_ASSERT(NULL != buffer_impl_ptr->destroy); + + if (!wlmtk_element_init( + &buffer_ptr->super_element, &super_element_impl)) { + return false; + } + + wlmtk_buffer_set(buffer_ptr, wlr_buffer_ptr); + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_buffer_fini(wlmtk_buffer_t *buffer_ptr) +{ + if (NULL != buffer_ptr->wlr_buffer_ptr) { + wlr_buffer_unlock(buffer_ptr->wlr_buffer_ptr); + buffer_ptr->wlr_buffer_ptr = NULL; + } + + if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { + wlr_scene_node_destroy(&buffer_ptr->wlr_scene_buffer_ptr->node); + buffer_ptr->wlr_scene_buffer_ptr = NULL; + } + + wlmtk_element_fini(&buffer_ptr->super_element); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_buffer_set( + wlmtk_buffer_t *buffer_ptr, + struct wlr_buffer *wlr_buffer_ptr) +{ + if (NULL != buffer_ptr->wlr_buffer_ptr) { + wlr_buffer_unlock(buffer_ptr->wlr_buffer_ptr); + } + buffer_ptr->wlr_buffer_ptr = wlr_buffer_lock(wlr_buffer_ptr); + + if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { + wlr_scene_buffer_set_buffer( + buffer_ptr->wlr_scene_buffer_ptr, + buffer_ptr->wlr_buffer_ptr); + } +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::destroy method. + * + * Forwards the call to the wlmtk_buffer_t::destroy method. + * + * @param element_ptr + */ +void element_destroy(wlmtk_element_t *element_ptr) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_buffer_t, super_element); + buffer_ptr->impl.destroy(buffer_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::create_scene_node method. + * + * Creates a `struct wlr_scene_buffer` attached to `wlr_scene_tree_ptr`. + * + * @param element_ptr + * @param wlr_scene_tree_ptr + */ +struct wlr_scene_node *element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_buffer_t, super_element); + + BS_ASSERT(NULL == buffer_ptr->wlr_scene_buffer_ptr); + buffer_ptr->wlr_scene_buffer_ptr = wlr_scene_buffer_create( + wlr_scene_tree_ptr, + buffer_ptr->wlr_buffer_ptr); + BS_ASSERT(NULL != buffer_ptr->wlr_scene_buffer_ptr); + + return &buffer_ptr->wlr_scene_buffer_ptr->node; +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's get_dimensions method: Return dimensions. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_buffer_t, super_element); + + if (NULL != left_ptr) *left_ptr = 0; + if (NULL != top_ptr) *top_ptr = 0; + if (NULL != right_ptr) *right_ptr = buffer_ptr->wlr_buffer_ptr->width; + if (NULL != bottom_ptr) *bottom_ptr = buffer_ptr->wlr_buffer_ptr->height; +} + +/* == End of buffer.c ====================================================== */ diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h new file mode 100644 index 00000000..87a78c3b --- /dev/null +++ b/src/toolkit/buffer.h @@ -0,0 +1,100 @@ +/* ========================================================================= */ +/** + * @file buffer.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_BUFFER_H__ +#define __WLMTK_BUFFER_H__ + +#include + +/** Forward declaration: Buffer state. */ +typedef struct _wlmtk_buffer_t wlmtk_buffer_t; +/** Forward declaration: Buffer implementation. */ +typedef struct _wlmtk_buffer_impl_t wlmtk_buffer_impl_t; + +#include "element.h" + +/** Forward declaration. */ +struct wlr_buffer; +/** Forward declaration. */ +struct wlr_scene_buffer; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +/** Method table of the content. */ +struct _wlmtk_buffer_impl_t { + /** Destroys the implementation of the buffer. */ + void (*destroy)(wlmtk_buffer_t *buffer_ptr); +}; + +/** State of a texture-backed buffer. */ +struct _wlmtk_buffer_t { + /** Super class of the buffer: An element. */ + wlmtk_element_t super_element; + + /** Implementation of abstract virtual methods. */ + wlmtk_buffer_impl_t impl; + + /** WLR buffer holding the contents. */ + struct wlr_buffer *wlr_buffer_ptr; + /** Scene graph API node. Only set after calling `create_scene_node`. */ + struct wlr_scene_buffer *wlr_scene_buffer_ptr; +}; + +/** + * Initializes the buffer. + * + * @param buffer_ptr + * @param buffer_impl_ptr + * @param wlr_buffer_ptr + * + * @return true on success. + */ +bool wlmtk_buffer_init( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_buffer_impl_t *buffer_impl_ptr, + struct wlr_buffer *wlr_buffer_ptr); + +/** + * Cleans up the buffer. + * + * @param buffer_ptr + */ +void wlmtk_buffer_fini(wlmtk_buffer_t *buffer_ptr); + +/** + * Sets (or updates) buffer contents. + * + * @param buffer_ptr + * @param wlr_buffer_ptr A WLR buffer to use for the update. That buffer + * will get locked by @ref wlmtk_buffer_t for the + * duration of it's use. + */ +void wlmtk_buffer_set( + wlmtk_buffer_t *buffer_ptr, + struct wlr_buffer *wlr_buffer_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_BUFFER_H__ */ +/* == End of buffer.h ====================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 6fb81caa..68ce7e58 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,6 +30,7 @@ #include #include +#include "buffer.h" #include "container.h" #include "content.h" #include "element.h" diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 9815e185..75a8dd7b 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -92,17 +92,17 @@ class Workspace { Container *-- Workspace class HBox { - Container parent + Container super_container } Container <|-- HBox class VBox { - Container parent + Container super_container } Container <|-- VBox abstract class Content { - Element parent + Element super_element init(handlers) fini() @@ -140,18 +140,24 @@ Content <|-- XdgToplevelSurface class Buffer { Element parent + + init(handlers, struct wlr_buffer *) + set(struct wlr_buffer *) } Element <|-- Buffer class Button { + Buffer super_buffer + init(handlers, texture_up, texture_down, texture_blurred) + update(texture_up, texture_down, texture_blurred) } Buffer <|-- Button class Window { VBox super_container Content *content - TitleBar title_bar + TitleBar *title_bar Window *create(Content*) destroy() @@ -165,10 +171,20 @@ class Window { VBox *-- Window class TitleBar { - HBox parent + HBox super_hbox } HBox *-- TitleBar +class TitleBarButton { + Button super_button + + init(handlers, overlay_texture, texture, posx, posy) + redraw(texture, posx, posy) + + get_width(int *) + set_width(int) +} + class Menu { VBox parent } From 93788df8c302da857615a4fc543645fb5f8f34de Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 17:25:37 +0200 Subject: [PATCH 128/390] Makes window_container_impl static. --- src/toolkit/window.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 769b4107..25160f4a 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -36,8 +36,10 @@ struct _wlmtk_window_t { static void window_container_destroy(wlmtk_container_t *container_ptr); +/* == Data ================================================================= */ + /** Method table for the container's virtual methods. */ -const wlmtk_container_impl_t window_container_impl = { +static const wlmtk_container_impl_t window_container_impl = { .destroy = window_container_destroy }; From 22573e9df4fe977423e759f72a246505fa784a97 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 21 Oct 2023 17:25:54 +0200 Subject: [PATCH 129/390] Adds boilerplate for box. --- src/toolkit/CMakeLists.txt | 2 ++ src/toolkit/box.c | 65 +++++++++++++++++++++++++++++++++++ src/toolkit/box.h | 70 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 src/toolkit/box.c create mode 100644 src/toolkit/box.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 179be571..37ce6881 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -21,6 +21,7 @@ SET(PUBLIC_HEADER_FILES toolkit.h util.h + box.h buffer.h container.h content.h @@ -31,6 +32,7 @@ SET(PUBLIC_HEADER_FILES ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE + box.c buffer.c container.c content.c diff --git a/src/toolkit/box.c b/src/toolkit/box.c new file mode 100644 index 00000000..4b2380a1 --- /dev/null +++ b/src/toolkit/box.c @@ -0,0 +1,65 @@ +/* ========================================================================= */ +/** + * @file box.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "box.h" + +/* == Declarations ========================================================= */ + +static void container_destroy(wlmtk_container_t *container_ptr); + +/* == Data ================================================================= */ + +/** Method table for the box's virtual methods. */ +static const wlmtk_container_impl_t container_impl = { + .destroy = container_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_box_init( + wlmtk_box_t *box_ptr, + __UNUSED__ const wlmtk_box_impl_t *box_impl_ptr) +{ + if (!wlmtk_container_init(&box_ptr->super_container, &container_impl)) { + return false; + } + + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_box_fini(__UNUSED__ wlmtk_box_t *box_ptr) +{ + // nothing to do. +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, in case called from container. Wraps to our dtor. */ +void container_destroy(wlmtk_container_t *container_ptr) +{ + wlmtk_box_t *box_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_box_t, super_container); + wlmtk_box_fini(box_ptr); +} + +/* == End of box.c ========================================================= */ diff --git a/src/toolkit/box.h b/src/toolkit/box.h new file mode 100644 index 00000000..7c5ee6fb --- /dev/null +++ b/src/toolkit/box.h @@ -0,0 +1,70 @@ +/* ========================================================================= */ +/** + * @file box.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_BOX_H__ +#define __WLMTK_BOX_H__ + +/** Forward declaration: Box. */ +typedef struct _wlmtk_box_t wlmtk_box_t; +/** Forward declaration: Box virtual method implementations. */ +typedef struct _wlmtk_box_impl_t wlmtk_box_impl_t; + +#include "container.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Virtual method table of the box. */ +struct _wlmtk_box_impl_t { + /** dtor. */ + void (*destroy)(wlmtk_box_t *box_ptr); +}; + +/** State of the box. */ +struct _wlmtk_box_t { + /** Super class of the box. */ + wlmtk_container_t super_container; +}; + +/** + * Initializes the box with the provided virtual method table. + * + * @param box_ptr + * @param box_impl_ptr + * + * @return true on success. + */ +bool wlmtk_box_init( + wlmtk_box_t *box_ptr, + const wlmtk_box_impl_t *box_impl_ptr); + +/** + * Un-initializes the box. + * + * @param box_ptr + */ +void wlmtk_box_fini(wlmtk_box_t *box_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_BOX_H__ */ +/* == End of box.h ========================================================= */ From 663b83f7c7eeb7c9793d0f11ce7d9ccbb711757c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 22 Oct 2023 14:36:11 +0200 Subject: [PATCH 130/390] Replaces refocus_tree with update_layout, and adds layout tests for the box. --- src/toolkit/box.c | 121 ++++++++++++++++++++++++++++++++++++- src/toolkit/box.h | 5 ++ src/toolkit/container.c | 53 ++++++++-------- src/toolkit/container.h | 17 +++--- src/toolkit/element.c | 3 +- src/toolkit/toolkit.h | 1 + src/toolkit/toolkit.md | 1 + src/toolkit/toolkit_test.c | 1 + src/toolkit/workspace.c | 5 +- 9 files changed, 167 insertions(+), 40 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 4b2380a1..e8d6019b 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -23,12 +23,14 @@ /* == Declarations ========================================================= */ static void container_destroy(wlmtk_container_t *container_ptr); +static void container_update_layout(wlmtk_container_t *container_ptr); /* == Data ================================================================= */ /** Method table for the box's virtual methods. */ static const wlmtk_container_impl_t container_impl = { - .destroy = container_destroy + .destroy = container_destroy, + .update_layout = container_update_layout, }; /* == Exported methods ===================================================== */ @@ -36,11 +38,15 @@ static const wlmtk_container_impl_t container_impl = { /* ------------------------------------------------------------------------- */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - __UNUSED__ const wlmtk_box_impl_t *box_impl_ptr) + const wlmtk_box_impl_t *box_impl_ptr) { + BS_ASSERT(NULL != box_ptr); + BS_ASSERT(NULL != box_impl_ptr); + BS_ASSERT(NULL != box_impl_ptr->destroy); if (!wlmtk_container_init(&box_ptr->super_container, &container_impl)) { return false; } + memcpy(&box_ptr->impl, box_impl_ptr, sizeof(wlmtk_box_impl_t)); return true; } @@ -62,4 +68,115 @@ void container_destroy(wlmtk_container_t *container_ptr) wlmtk_box_fini(box_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Updates the layout of the box. + * + * Steps through all visible elements, and sets their position to be + * left-to-right. + * + * @param container_ptr + */ +void container_update_layout(wlmtk_container_t *container_ptr) +{ + int position = 0; + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + if (!element_ptr->visible) continue; + + + int left, top, right, bottom; + wlmtk_element_get_dimensions(element_ptr, &left, &top, &right, &bottom); + int x, y; + wlmtk_element_get_position(element_ptr, &x, &y); + + x = position - left; + wlmtk_element_set_position(element_ptr, position - left, y); + position += right - left; + } + + // configure parent container. + wlmtk_container_update_layout( + container_ptr->super_element.parent_container_ptr); +} + +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); +static void test_layout(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_box_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 1, "layout", test_layout }, + { 0, NULL, NULL } +}; + +/** dtor for the testcase. */ +static void test_box_destroy(wlmtk_box_t *box_ptr) { + wlmtk_box_fini(box_ptr); +} +/** A testcase box implementation. */ +static const wlmtk_box_impl_t test_box_impl = { + .destroy = test_box_destroy, +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises setup and teardown. */ +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_box_t box; + wlmtk_box_init(&box, &test_box_impl); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, box.impl.destroy); + box.impl.destroy(&box); +} + +/* ------------------------------------------------------------------------- */ +/** Tests layouting. */ +void test_layout(bs_test_t *test_ptr) +{ + wlmtk_box_t box; + wlmtk_box_init(&box, &test_box_impl); + + wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&e1_ptr->element, true); + e1_ptr->width = 10; + wlmtk_fake_element_t *e2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&e2_ptr->element, false); + e2_ptr->width = 20; + wlmtk_fake_element_t *e3_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&e3_ptr->element, true); + e3_ptr->width = 40; + + // Note: Elements are added "in front" == left. + wlmtk_container_add_element(&box.super_container, &e1_ptr->element); + wlmtk_container_add_element(&box.super_container, &e2_ptr->element); + wlmtk_container_add_element(&box.super_container, &e3_ptr->element); + + // Layout: e3 | e1 (e2 is invisible). + BS_TEST_VERIFY_EQ(test_ptr, 40, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e3_ptr->element.x); + + // Make e2 visible, now we should have: e3 | e2 | e1. + wlmtk_element_set_visible(&e2_ptr->element, true); + BS_TEST_VERIFY_EQ(test_ptr, 60, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 40, e2_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e3_ptr->element.x); + + // Remove elements. Must update each. + wlmtk_container_remove_element(&box.super_container, &e3_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, 20, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); + wlmtk_container_remove_element(&box.super_container, &e2_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, 00, e1_ptr->element.x); + wlmtk_container_remove_element(&box.super_container, &e1_ptr->element); + + wlmtk_element_destroy(&e3_ptr->element); + wlmtk_element_destroy(&e2_ptr->element); + wlmtk_element_destroy(&e1_ptr->element); + box.impl.destroy(&box); +} + /* == End of box.c ========================================================= */ diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 7c5ee6fb..3ebee533 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -41,6 +41,8 @@ struct _wlmtk_box_impl_t { struct _wlmtk_box_t { /** Super class of the box. */ wlmtk_container_t super_container; + /** Virtual method table of the box. */ + wlmtk_box_impl_t impl; }; /** @@ -62,6 +64,9 @@ bool wlmtk_box_init( */ void wlmtk_box_fini(wlmtk_box_t *box_ptr); +/** Unit tests. */ +extern const bs_test_case_t wlmtk_box_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 15ba9848..18bb5b1e 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -62,6 +62,7 @@ static bool update_pointer_focus_at( double x, double y, uint32_t time_msec); +static void base_container_update_layout(wlmtk_container_t *container_ptr); /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_impl_t super_element_impl = { @@ -94,6 +95,9 @@ bool wlmtk_container_init( memcpy(&container_ptr->impl, container_impl_ptr, sizeof(wlmtk_container_impl_t)); + if (NULL == container_ptr->impl.update_layout) { + container_ptr->impl.update_layout = base_container_update_layout; + } return true; } @@ -154,9 +158,7 @@ void wlmtk_container_add_element( wlmtk_dlnode_from_element(element_ptr)); wlmtk_element_set_parent_container(element_ptr, container_ptr); - // Need to re-compute pointer focus, since we might have added an element - // below the current cursor position. - wlmtk_container_pointer_refocus_tree(container_ptr); + wlmtk_container_update_layout(container_ptr); } /* ------------------------------------------------------------------------- */ @@ -171,11 +173,7 @@ void wlmtk_container_remove_element( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); - // We can be more lenient in asking for re-focus: If the removed element - // is NOT having pointer focus, we won't have to bother. - if (element_ptr == container_ptr->pointer_focus_element_ptr) { - wlmtk_container_pointer_refocus_tree(container_ptr); - } + wlmtk_container_update_layout(container_ptr); BS_ASSERT(element_ptr != container_ptr->pointer_focus_element_ptr); } @@ -186,23 +184,6 @@ struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( return container_ptr->wlr_scene_tree_ptr; } -/* ------------------------------------------------------------------------- */ -void wlmtk_container_pointer_refocus_tree(wlmtk_container_t *container_ptr) -{ - // Guard clause: Don't throw over if there's no container. - if (NULL == container_ptr) return; - - while (NULL != container_ptr->super_element.parent_container_ptr) { - container_ptr = container_ptr->super_element.parent_container_ptr; - } - - update_pointer_focus_at( - container_ptr, - container_ptr->super_element.last_pointer_x, - container_ptr->super_element.last_pointer_y, - container_ptr->super_element.last_pointer_time_msec); -} - /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -490,6 +471,28 @@ bool update_pointer_focus_at( return false; } +/* ------------------------------------------------------------------------- */ +/** + * Base implementation of wlmtk_container_impl_t::update_layout. If there's + * a paraent, will call @ref wlmtk_container_update_layout. Otherwise, will + * update the pointer focus. + * + * @param container_ptr + */ +void base_container_update_layout(wlmtk_container_t *container_ptr) +{ + if (NULL != container_ptr->super_element.parent_container_ptr) { + wlmtk_container_update_layout( + container_ptr->super_element.parent_container_ptr); + } else { + update_pointer_focus_at( + container_ptr, + container_ptr->super_element.last_pointer_x, + container_ptr->super_element.last_pointer_y, + container_ptr->super_element.last_pointer_time_msec); + } +} + /* == Helper for unit test: A fake container =============================== */ static void fake_destroy(wlmtk_container_t *container_ptr); diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 3fbd4705..201dff87 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -38,6 +38,8 @@ extern "C" { struct _wlmtk_container_impl_t { /** dtor. */ void (*destroy)(wlmtk_container_t *container_ptr); + /** Updates the layout of the container elements. */ + void (*update_layout)(wlmtk_container_t *container_ptr); }; /** State of the container. */ @@ -123,15 +125,16 @@ void wlmtk_container_remove_element( wlmtk_element_t *element_ptr); /** - * Re-computes pointer focus for the entire container tree. + * Updates the layout of the container. * - * Will retract to the top of parent containers, and then (re)compute the - * pointer focus from there. - * - * @param container_ptr + * @param container_ptr Container to update. NULL implies a no-op. */ -void wlmtk_container_pointer_refocus_tree( - wlmtk_container_t *container_ptr); +static inline void wlmtk_container_update_layout( + wlmtk_container_t *container_ptr) { + if (NULL != container_ptr) { + container_ptr->impl.update_layout(container_ptr); + } +} /** * Returns the wlroots scene graph tree for this node. diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 0b2f90f5..ee611c91 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -144,8 +144,7 @@ void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible) wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, visible); } - // Changing visibility may lose or re-gain focus. Re-compute thta. - wlmtk_container_pointer_refocus_tree(element_ptr->parent_container_ptr); + wlmtk_container_update_layout(element_ptr->parent_container_ptr); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 68ce7e58..dae37b16 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,6 +30,7 @@ #include #include +#include "box.h" #include "buffer.h" #include "container.h" #include "content.h" diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 75a8dd7b..a7103fa2 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -65,6 +65,7 @@ class Container { -struct wlr_scene_tree *wlr_scene_tree() {abstract}#void destroy() + #void configure() } Element <|-- Container note right of Element::"add_element(Element*)" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index fa080c22..abbd7d88 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -22,6 +22,7 @@ /** Toolkit unit tests. */ const bs_test_set_t toolkit_tests[] = { + { 1, "box", wlmtk_box_test_cases }, { 1, "container", wlmtk_container_test_cases }, { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 31d7c592..a3477df9 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -184,10 +184,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_workspace_t *wlmtk_workspace_from_container( wlmtk_container_t *container_ptr) { - BS_ASSERT(0 == memcmp( - &container_ptr->impl, - &workspace_container_impl, - sizeof(wlmtk_container_impl_t))); + BS_ASSERT(container_ptr->impl.destroy == workspace_container_impl.destroy); return BS_CONTAINER_OF(container_ptr, wlmtk_workspace_t, super_container); } From 06191df46def669027b63f9b68eedcccb43053bd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 22 Oct 2023 14:43:42 +0200 Subject: [PATCH 131/390] Adds (not-yet-wired) parameter to set orientation for wlmtk_box_t. --- src/toolkit/box.c | 16 +++++++++------- src/toolkit/box.h | 12 +++++++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index e8d6019b..4cfba790 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -38,7 +38,8 @@ static const wlmtk_container_impl_t container_impl = { /* ------------------------------------------------------------------------- */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - const wlmtk_box_impl_t *box_impl_ptr) + const wlmtk_box_impl_t *box_impl_ptr, + wlmtk_box_orientation_t orientation) { BS_ASSERT(NULL != box_ptr); BS_ASSERT(NULL != box_impl_ptr); @@ -47,6 +48,7 @@ bool wlmtk_box_init( return false; } memcpy(&box_ptr->impl, box_impl_ptr, sizeof(wlmtk_box_impl_t)); + box_ptr->orientation = orientation; return true; } @@ -105,11 +107,11 @@ void container_update_layout(wlmtk_container_t *container_ptr) /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); -static void test_layout(bs_test_t *test_ptr); +static void test_layout_horizontal(bs_test_t *test_ptr); const bs_test_case_t wlmtk_box_test_cases[] = { { 1, "init_fini", test_init_fini }, - { 1, "layout", test_layout }, + { 1, "layout_horizontal", test_layout_horizontal }, { 0, NULL, NULL } }; @@ -127,17 +129,17 @@ static const wlmtk_box_impl_t test_box_impl = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, &test_box_impl); + wlmtk_box_init(&box, &test_box_impl, WLMTK_BOX_HORIZONTAL); BS_TEST_VERIFY_NEQ(test_ptr, NULL, box.impl.destroy); box.impl.destroy(&box); } /* ------------------------------------------------------------------------- */ -/** Tests layouting. */ -void test_layout(bs_test_t *test_ptr) +/** Tests layouting horizontally */ +void test_layout_horizontal(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, &test_box_impl); + wlmtk_box_init(&box, &test_box_impl, WLMTK_BOX_HORIZONTAL); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 3ebee533..4d9ce40b 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -37,12 +37,20 @@ struct _wlmtk_box_impl_t { void (*destroy)(wlmtk_box_t *box_ptr); }; +/** Orientation of the box. */ +typedef enum { + WLMTK_BOX_HORIZONTAL, + WLMTK_BOX_VERTICAL, +} wlmtk_box_orientation_t; + /** State of the box. */ struct _wlmtk_box_t { /** Super class of the box. */ wlmtk_container_t super_container; /** Virtual method table of the box. */ wlmtk_box_impl_t impl; + /** Orientation of the box. */ + wlmtk_box_orientation_t orientation; }; /** @@ -50,12 +58,14 @@ struct _wlmtk_box_t { * * @param box_ptr * @param box_impl_ptr + * @param orientation * * @return true on success. */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - const wlmtk_box_impl_t *box_impl_ptr); + const wlmtk_box_impl_t *box_impl_ptr, + wlmtk_box_orientation_t orientation); /** * Un-initializes the box. From 7673bee94dfab02785c862fca22f2164d997bc9b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 22 Oct 2023 14:52:24 +0200 Subject: [PATCH 132/390] Wires up vertical arrangement for wlmtk_box_t and adds unit test for it. --- src/toolkit/box.c | 67 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 4cfba790..ac3fac28 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -81,6 +81,9 @@ void container_destroy(wlmtk_container_t *container_ptr) */ void container_update_layout(wlmtk_container_t *container_ptr) { + wlmtk_box_t *box_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_box_t, super_container); + int position = 0; for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; dlnode_ptr != NULL; @@ -94,9 +97,21 @@ void container_update_layout(wlmtk_container_t *container_ptr) int x, y; wlmtk_element_get_position(element_ptr, &x, &y); - x = position - left; - wlmtk_element_set_position(element_ptr, position - left, y); - position += right - left; + switch (box_ptr->orientation) { + case WLMTK_BOX_HORIZONTAL: + x = position - left; + position += right - left; + break; + + case WLMTK_BOX_VERTICAL: + y = position - top; + position += bottom - top; + break; + + default: + bs_log(BS_FATAL, "Weird orientatin %d.", box_ptr->orientation); + } + wlmtk_element_set_position(element_ptr, x, y); } // configure parent container. @@ -108,10 +123,12 @@ void container_update_layout(wlmtk_container_t *container_ptr) static void test_init_fini(bs_test_t *test_ptr); static void test_layout_horizontal(bs_test_t *test_ptr); +static void test_layout_vertical(bs_test_t *test_ptr); const bs_test_case_t wlmtk_box_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "layout_horizontal", test_layout_horizontal }, + { 1, "layout_vertical", test_layout_vertical }, { 0, NULL, NULL } }; @@ -144,12 +161,15 @@ void test_layout_horizontal(bs_test_t *test_ptr) wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); e1_ptr->width = 10; + e1_ptr->height = 1; wlmtk_fake_element_t *e2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e2_ptr->element, false); e2_ptr->width = 20; + e1_ptr->height = 2; wlmtk_fake_element_t *e3_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e3_ptr->element, true); e3_ptr->width = 40; + e3_ptr->height = 4; // Note: Elements are added "in front" == left. wlmtk_container_add_element(&box.super_container, &e1_ptr->element); @@ -158,8 +178,11 @@ void test_layout_horizontal(bs_test_t *test_ptr) // Layout: e3 | e1 (e2 is invisible). BS_TEST_VERIFY_EQ(test_ptr, 40, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.y); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.y); BS_TEST_VERIFY_EQ(test_ptr, 0, e3_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e3_ptr->element.y); // Make e2 visible, now we should have: e3 | e2 | e1. wlmtk_element_set_visible(&e2_ptr->element, true); @@ -172,7 +195,7 @@ void test_layout_horizontal(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 20, e1_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); wlmtk_container_remove_element(&box.super_container, &e2_ptr->element); - BS_TEST_VERIFY_EQ(test_ptr, 00, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.x); wlmtk_container_remove_element(&box.super_container, &e1_ptr->element); wlmtk_element_destroy(&e3_ptr->element); @@ -181,4 +204,40 @@ void test_layout_horizontal(bs_test_t *test_ptr) box.impl.destroy(&box); } +/* ------------------------------------------------------------------------- */ +/** Tests layouting vertically */ +void test_layout_vertical(bs_test_t *test_ptr) +{ + wlmtk_box_t box; + wlmtk_box_init(&box, &test_box_impl, WLMTK_BOX_VERTICAL); + + wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&e1_ptr->element, true); + e1_ptr->width = 10; + e1_ptr->height = 1; + wlmtk_fake_element_t *e2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&e2_ptr->element, true); + e2_ptr->width = 20; + e2_ptr->height = 2; + + // Note: Elements are added "in front" == left. + wlmtk_container_add_element(&box.super_container, &e1_ptr->element); + wlmtk_container_add_element(&box.super_container, &e2_ptr->element); + + // Layout: e2 | e1. + BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 2, e1_ptr->element.y); + BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.y); + + // Remove elements. Must update each. + wlmtk_container_remove_element(&box.super_container, &e2_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.y); + wlmtk_container_remove_element(&box.super_container, &e1_ptr->element); + + wlmtk_element_destroy(&e2_ptr->element); + wlmtk_element_destroy(&e1_ptr->element); + box.impl.destroy(&box); +} + /* == End of box.c ========================================================= */ From 24ac7e0cf3765e99d758ae903085592a5feb2930 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 23 Oct 2023 20:55:48 +0200 Subject: [PATCH 133/390] Uses Box as base class for workspace. --- src/toolkit/toolkit.md | 21 ++++++++----------- src/toolkit/window.c | 47 ++++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index a7103fa2..46906daf 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -92,15 +92,12 @@ class Workspace { } Container *-- Workspace -class HBox { +class Box { Container super_container -} -Container <|-- HBox -class VBox { - Container super_container + bool init(handlers, wlmtk_box_orientation_t) } -Container <|-- VBox +Container <|-- Box abstract class Content { Element super_element @@ -156,7 +153,7 @@ class Button { Buffer <|-- Button class Window { - VBox super_container + Box super_box Content *content TitleBar *title_bar @@ -169,12 +166,12 @@ class Window { get_size(int *, int *) set_size(int, int) } -VBox *-- Window +Box *-- Window class TitleBar { - HBox super_hbox + Box super_box } -HBox *-- TitleBar +Box *-- TitleBar class TitleBarButton { Button super_button @@ -187,9 +184,9 @@ class TitleBarButton { } class Menu { - VBox parent + Box super_box } -VBox *-- Menu +Box *-- Menu class MenuItem { diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 25160f4a..4ed33f39 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -20,27 +20,27 @@ #include "window.h" -#include "container.h" +#include "box.h" #include "workspace.h" /* == Declarations ========================================================= */ /** State of the window. */ struct _wlmtk_window_t { - /** Superclass: Container. */ - wlmtk_container_t super_container; + /** Superclass: Box. */ + wlmtk_box_t super_box; /** Content of this window. */ wlmtk_content_t *content_ptr; }; -static void window_container_destroy(wlmtk_container_t *container_ptr); +static void window_box_destroy(wlmtk_box_t *box_ptr); /* == Data ================================================================= */ -/** Method table for the container's virtual methods. */ -static const wlmtk_container_impl_t window_container_impl = { - .destroy = window_container_destroy +/** Method table for the box's virtual methods. */ +static const wlmtk_box_impl_t window_box_impl = { + .destroy = window_box_destroy }; /* == Exported methods ===================================================== */ @@ -51,14 +51,15 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!wlmtk_container_init(&window_ptr->super_container, - &window_container_impl)) { + if (!wlmtk_box_init(&window_ptr->super_box, + &window_box_impl, + WLMTK_BOX_VERTICAL)) { wlmtk_window_destroy(window_ptr); return NULL; } wlmtk_container_add_element( - &window_ptr->super_container, + &window_ptr->super_box.super_container, wlmtk_content_element(content_ptr)); window_ptr->content_ptr = content_ptr; wlmtk_content_set_window(content_ptr, window_ptr); @@ -70,7 +71,7 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { wlmtk_container_remove_element( - &window_ptr->super_container, + &window_ptr->super_box.super_container, wlmtk_content_element(window_ptr->content_ptr)); wlmtk_element_set_visible( wlmtk_content_element(window_ptr->content_ptr), false); @@ -81,14 +82,14 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) window_ptr->content_ptr = NULL; } - wlmtk_container_fini(&window_ptr->super_container); + wlmtk_box_fini(&window_ptr->super_box); free(window_ptr); } /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) { - return &window_ptr->super_container.super_element; + return &window_ptr->super_box.super_container.super_element; } /* ------------------------------------------------------------------------- */ @@ -139,31 +140,33 @@ void wlmtk_window_set_size( /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { - BS_ASSERT(NULL != - window_ptr->super_container.super_element.parent_container_ptr); + BS_ASSERT( + NULL != + window_ptr->super_box.super_container.super_element.parent_container_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_container.super_element.parent_container_ptr); + window_ptr->super_box.super_container.super_element.parent_container_ptr); wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); } /* ------------------------------------------------------------------------- */ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) { - BS_ASSERT(NULL != - window_ptr->super_container.super_element.parent_container_ptr); + BS_ASSERT( + NULL != + window_ptr->super_box.super_container.super_element.parent_container_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_container.super_element.parent_container_ptr); + window_ptr->super_box.super_container.super_element.parent_container_ptr); wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); } /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Virtual destructor, in case called from container. Wraps to our dtor. */ -void window_container_destroy(wlmtk_container_t *container_ptr) +/** Virtual destructor, in case called from box. Wraps to our dtor. */ +void window_box_destroy(wlmtk_box_t *box_ptr) { wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_window_t, super_container); + box_ptr, wlmtk_window_t, super_box); wlmtk_window_destroy(window_ptr); } From 932e2d03f1d7fc25429846cbd98377e2f8338903 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 23 Oct 2023 21:15:34 +0200 Subject: [PATCH 134/390] Adds boilerplate for titlebar element. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/titlebar.c | 104 +++++++++++++++++++++++++++++++++++++ src/toolkit/titlebar.h | 65 +++++++++++++++++++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 5 files changed, 173 insertions(+) create mode 100644 src/toolkit/titlebar.c create mode 100644 src/toolkit/titlebar.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 37ce6881..81a30127 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(PUBLIC_HEADER_FILES content.h element.h fsm.h + titlebar.h window.h workspace.h) @@ -40,6 +41,7 @@ TARGET_SOURCES(toolkit PRIVATE fsm.c gfxbuf.c primitives.c + titlebar.c util.c window.c workspace.c) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c new file mode 100644 index 00000000..c990e3b9 --- /dev/null +++ b/src/toolkit/titlebar.c @@ -0,0 +1,104 @@ +/* ========================================================================= */ +/** + * @file titlebar.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "titlebar.h" + +#include "box.h" + +/* == Declarations ========================================================= */ + +/** State of the title bar. */ +struct _wlmtk_titlebar_t { + /** Superclass: Box. */ + wlmtk_box_t super_box; +}; + +static void titlebar_box_destroy(wlmtk_box_t *box_ptr); + +/* == Data ================================================================= */ + +/** Method table for the box's virtual methods. */ +static const wlmtk_box_impl_t titlebar_box_impl = { + .destroy = titlebar_box_destroy +}; + + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_titlebar_t *wlmtk_titlebar_create(void) +{ + wlmtk_titlebar_t *titlebar_ptr = logged_calloc( + 1, sizeof(wlmtk_titlebar_t)); + if (NULL == titlebar_ptr) return NULL; + + if (!wlmtk_box_init(&titlebar_ptr->super_box, + &titlebar_box_impl, + WLMTK_BOX_HORIZONTAL)) { + wlmtk_titlebar_destroy(titlebar_ptr); + return NULL; + } + + return titlebar_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) +{ + wlmtk_box_fini(&titlebar_ptr->super_box); + free(titlebar_ptr); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_titlebar_element(wlmtk_titlebar_t *titlebar_ptr) +{ + return &titlebar_ptr->super_box.super_container.super_element; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, in case called from box. Wraps to our dtor. */ +void titlebar_box_destroy(wlmtk_box_t *box_ptr) +{ + wlmtk_titlebar_t *titlebar_ptr = BS_CONTAINER_OF( + box_ptr, wlmtk_titlebar_t, super_box); + wlmtk_titlebar_destroy(titlebar_ptr); +} + +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_titlebar_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); + wlmtk_titlebar_destroy(titlebar_ptr); +} + +/* == End of titlebar.c ==================================================== */ diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h new file mode 100644 index 00000000..5ba29ab8 --- /dev/null +++ b/src/toolkit/titlebar.h @@ -0,0 +1,65 @@ +/* ========================================================================= */ +/** + * @file titlebar.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_TITLEBAR_H__ +#define __WLMTK_TITLEBAR_H__ + +/** Forward declaration: Title bar. */ +typedef struct _wlmtk_titlebar_t wlmtk_titlebar_t; + +#include "element.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a title bar, suitable as a window title. + * + * @return Pointer to the title bar state, or NULL on error. Must be free'd + * by calling @ref wlmtk_titlebar_destroy. + */ +wlmtk_titlebar_t *wlmtk_titlebar_create(void); + +/** + * Destroys the title bar. + * + * @param titlebar_ptr + */ +void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr); + +/** + * Returns the super Element of the titlebar. + * + * @param titlebar_ptr + * + * @return Pointer to the @ref wlmtk_element_t base instantiation to + * titlebar_ptr. + */ +wlmtk_element_t *wlmtk_titlebar_element(wlmtk_titlebar_t *titlebar_ptr); + +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_titlebar_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_TITLEBAR_H__ */ +/* == End of titlebar.h ==================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index dae37b16..4e5b4982 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -38,6 +38,7 @@ #include "fsm.h" #include "window.h" #include "workspace.h" +#include "titlebar.h" #ifdef __cplusplus extern "C" { diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index abbd7d88..b87012d1 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -27,6 +27,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, + { 1, "titlebar", wlmtk_titlebar_test_cases }, { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, From 51073fa41f1548c15c67ac07a8876d40e9dc8b30 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 23 Oct 2023 21:23:34 +0200 Subject: [PATCH 135/390] Fixes potential memory leak when using titlebar_box_create and destroy using wlmtk_element_destroy on it. --- src/toolkit/box.c | 2 +- src/toolkit/titlebar.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index ac3fac28..83bc192e 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -67,7 +67,7 @@ void container_destroy(wlmtk_container_t *container_ptr) { wlmtk_box_t *box_ptr = BS_CONTAINER_OF( container_ptr, wlmtk_box_t, super_container); - wlmtk_box_fini(box_ptr); + box_ptr->impl.destroy(box_ptr); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index c990e3b9..f750c95a 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -98,7 +98,8 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); - wlmtk_titlebar_destroy(titlebar_ptr); + + wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); } /* == End of titlebar.c ==================================================== */ From c44057b0f4cf31bdf009a2ada6283d0b7be5fe03 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 26 Oct 2023 21:50:18 +0200 Subject: [PATCH 136/390] Renames wlmaker_style to wlmtk_style. --- src/config.c | 18 +++++++++--------- src/config.h | 18 +++++++++--------- src/decorations.c | 34 +++++++++++++++++----------------- src/decorations.h | 14 +++++++------- src/iconified.c | 4 ++-- src/menu_item.c | 6 +++--- src/toolkit/primitives.c | 22 +++++++++++----------- src/toolkit/primitives.h | 4 ++-- src/toolkit/style.h | 28 ++++++++++++++-------------- 9 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/config.c b/src/config.c index 890d5b8f..32de7f12 100644 --- a/src/config.c +++ b/src/config.c @@ -73,30 +73,30 @@ const wlmaker_config_theme_t wlmaker_config_theme = { .window_margin_width = 1, .titlebar_focussed_fill = { - .type = WLMAKER_STYLE_COLOR_HGRADIENT, + .type = WLMTK_STYLE_COLOR_HGRADIENT, .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} }, .titlebar_focussed_text_color = 0xffffffff, .titlebar_blurred_fill = { - .type = WLMAKER_STYLE_COLOR_HGRADIENT, + .type = WLMTK_STYLE_COLOR_HGRADIENT, .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} }, .titlebar_blurred_text_color = 0xff000000, .resizebar_fill = { - .type = WLMAKER_STYLE_COLOR_SOLID, + .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xffc2c0c5 }} }, .tile_fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} }, .iconified_title_fill = { - .type = WLMAKER_STYLE_COLOR_SOLID, + .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xff404040 }} }, .iconified_title_color = 0xffffffff, // White. .menu_fill = { - .type = WLMAKER_STYLE_COLOR_HGRADIENT, + .type = WLMTK_STYLE_COLOR_HGRADIENT, .param = { .hgradient = { .from = 0xffc2c0c5, .to = 0xff828085 }} }, .menu_margin_color = 0xff000000, // Pitch black, opaque. @@ -104,18 +104,18 @@ const wlmaker_config_theme_t wlmaker_config_theme = { .menu_padding_width = 1, .menu_item_enabled_fill = { - .type = WLMAKER_STYLE_COLOR_SOLID, + .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0x00000000 }} // Transparent. }, .menu_item_enabled_text_color = 0xff000000, // Black, opaque. .menu_item_selected_fill = { - .type = WLMAKER_STYLE_COLOR_SOLID, + .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xffffffff }} // White, opaque.. }, .menu_item_selected_text_color = 0xff000000, // Black, opaque. .task_list_fill = { - .type = WLMAKER_STYLE_COLOR_SOLID, + .type = WLMTK_STYLE_COLOR_SOLID, .param.solid.color = 0xc0202020 // Dark grey, partly transparent. }, .task_list_text_color = 0xffffffff, diff --git a/src/config.h b/src/config.h index 0b70c9c6..53076032 100644 --- a/src/config.h +++ b/src/config.h @@ -57,21 +57,21 @@ typedef struct { uint32_t titlebar_blurred_text_color; /** Fill style of the title bar, when focussed. Including buttons. */ - wlmaker_style_fill_t titlebar_focussed_fill; + wlmtk_style_fill_t titlebar_focussed_fill; /** Fill style of the title bar, when blurred. Including buttons. */ - wlmaker_style_fill_t titlebar_blurred_fill; + wlmtk_style_fill_t titlebar_blurred_fill; /** Fill style of the resize bar. */ - wlmaker_style_fill_t resizebar_fill; + wlmtk_style_fill_t resizebar_fill; /** Fill style of a tile. */ - wlmaker_style_fill_t tile_fill; + wlmtk_style_fill_t tile_fill; /** File style of the title element of an iconified. */ - wlmaker_style_fill_t iconified_title_fill; + wlmtk_style_fill_t iconified_title_fill; /** Color of the iconified's title. */ uint32_t iconified_title_color; /** Fill style of the menu's background. */ - wlmaker_style_fill_t menu_fill; + wlmtk_style_fill_t menu_fill; /** Color of the menu's margin and padding. */ uint32_t menu_margin_color; /** Width of the menu's margin. */ @@ -80,16 +80,16 @@ typedef struct { uint32_t menu_padding_width; /** Fill style of a menu item when enabled. */ - wlmaker_style_fill_t menu_item_enabled_fill; + wlmtk_style_fill_t menu_item_enabled_fill; /** Text color of menu item when enabled. */ uint32_t menu_item_enabled_text_color; /** Fill style of a menu item when selected. */ - wlmaker_style_fill_t menu_item_selected_fill; + wlmtk_style_fill_t menu_item_selected_fill; /** Text color of menu item when selected. */ uint32_t menu_item_selected_text_color; /** Fill style of the task list. */ - wlmaker_style_fill_t task_list_fill; + wlmtk_style_fill_t task_list_fill; /** Color of the text describing tasks in the task list. */ uint32_t task_list_text_color; } wlmaker_config_theme_t; diff --git a/src/decorations.c b/src/decorations.c index 1a3fe70f..56be9fd7 100644 --- a/src/decorations.c +++ b/src/decorations.c @@ -39,7 +39,7 @@ const uint32_t wlmaker_decorations_clip_button_size = 22; static cairo_surface_t *create_background( unsigned width, unsigned height, - const wlmaker_style_fill_t *fill_ptr); + const wlmtk_style_fill_t *fill_ptr); /** Lookup paths for icons. */ const char *lookup_paths[] = { @@ -57,7 +57,7 @@ const char *lookup_paths[] = { /* ------------------------------------------------------------------------- */ void wlmaker_decorations_draw_tile( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed) { wlmaker_primitives_cairo_fill(cairo_ptr, fill_ptr); @@ -112,7 +112,7 @@ bool wlmaker_decorations_draw_tile_icon( /* ------------------------------------------------------------------------- */ void wlmaker_decorations_draw_iconified( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, uint32_t font_color, const char *title_ptr) { @@ -144,7 +144,7 @@ void wlmaker_decorations_draw_iconified( /* ------------------------------------------------------------------------- */ bool wlmaker_decorations_draw_clip( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed) { // For readability. @@ -227,7 +227,7 @@ bool wlmaker_decorations_draw_clip( /* ------------------------------------------------------------------------- */ bool wlmaker_decorations_draw_clip_button_next( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed) { BS_ASSERT((int)wlmaker_decorations_clip_button_size == @@ -322,7 +322,7 @@ bool wlmaker_decorations_draw_clip_button_next( /* ------------------------------------------------------------------------- */ bool wlmaker_decorations_draw_clip_button_prev( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed) { BS_ASSERT((int)wlmaker_decorations_clip_button_size == @@ -429,7 +429,7 @@ bool wlmaker_decorations_draw_clip_button_prev( static cairo_surface_t *create_background( unsigned width, unsigned height, - const wlmaker_style_fill_t *fill_ptr) + const wlmtk_style_fill_t *fill_ptr) { cairo_surface_t *surface_ptr = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height); @@ -477,8 +477,8 @@ void test_tile(bs_test_t *test_ptr) { } cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, cairo_ptr); - wlmaker_style_fill_t fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + wlmtk_style_fill_t fill = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} }; wlmaker_decorations_draw_tile(cairo_ptr, &fill, false); @@ -497,8 +497,8 @@ void test_iconified(bs_test_t *test_ptr) { } cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, cairo_ptr); - wlmaker_style_fill_t fill = { - .type = WLMAKER_STYLE_COLOR_SOLID, + wlmtk_style_fill_t fill = { + .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xff808080 }} }; wlmaker_decorations_draw_iconified(cairo_ptr, &fill, 0xffffffff, "Title"); @@ -516,8 +516,8 @@ void test_clip(bs_test_t *test_ptr) { return; } cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); - wlmaker_style_fill_t fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + wlmtk_style_fill_t fill = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} }; BS_TEST_VERIFY_NEQ(test_ptr, NULL, cairo_ptr); @@ -542,8 +542,8 @@ void test_clip_button_next(bs_test_t *test_ptr) { return; } cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); - wlmaker_style_fill_t fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + wlmtk_style_fill_t fill = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} }; BS_TEST_VERIFY_NEQ(test_ptr, NULL, cairo_ptr); @@ -570,8 +570,8 @@ void test_clip_button_prev(bs_test_t *test_ptr) { return; } cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); - wlmaker_style_fill_t fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + wlmtk_style_fill_t fill = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} }; BS_TEST_VERIFY_NEQ(test_ptr, NULL, cairo_ptr); diff --git a/src/decorations.h b/src/decorations.h index cb58ca18..b40f79e1 100644 --- a/src/decorations.h +++ b/src/decorations.h @@ -50,7 +50,7 @@ extern const uint32_t wlmaker_decorations_clip_button_size; * @return a `cairo_surface_t` image target, filled as specificed. */ cairo_surface_t *wlmaker_decorations_titlebar_create_background( - uint32_t width, const wlmaker_style_fill_t *fill_ptr); + uint32_t width, const wlmtk_style_fill_t *fill_ptr); /** * Creates a cairo image surface for the background of the resize bar. @@ -63,7 +63,7 @@ cairo_surface_t *wlmaker_decorations_titlebar_create_background( * @return a `cairo_surface_t` image target, filled as specificed. */ cairo_surface_t *wlmaker_decorations_resizebar_create_background( - uint32_t width, const wlmaker_style_fill_t *fill_ptr); + uint32_t width, const wlmtk_style_fill_t *fill_ptr); /** * Draws a tile into the `cairo_t`. @@ -74,7 +74,7 @@ cairo_surface_t *wlmaker_decorations_resizebar_create_background( */ void wlmaker_decorations_draw_tile( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed); /** @@ -99,7 +99,7 @@ bool wlmaker_decorations_draw_tile_icon( */ void wlmaker_decorations_draw_iconified( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, uint32_t font_color, const char *title_ptr); @@ -117,7 +117,7 @@ void wlmaker_decorations_draw_iconified( */ bool wlmaker_decorations_draw_clip( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed); /** @@ -131,7 +131,7 @@ bool wlmaker_decorations_draw_clip( */ bool wlmaker_decorations_draw_clip_button_next( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed); /** @@ -145,7 +145,7 @@ bool wlmaker_decorations_draw_clip_button_next( */ bool wlmaker_decorations_draw_clip_button_prev( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr, + const wlmtk_style_fill_t *fill_ptr, bool pressed); /** Unit tests. */ diff --git a/src/iconified.c b/src/iconified.c index 951e053b..cb3caedd 100644 --- a/src/iconified.c +++ b/src/iconified.c @@ -118,8 +118,8 @@ wlmaker_dockapp_iconified_t *wlmaker_dockapp_iconified_create( return NULL; } - const wlmaker_style_fill_t fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + const wlmtk_style_fill_t fill = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xff767686,.to = 0xff313541 }} }; wlmaker_decorations_draw_tile(cairo_ptr, &fill, false); diff --git a/src/menu_item.c b/src/menu_item.c index 45ddc552..b22de976 100644 --- a/src/menu_item.c +++ b/src/menu_item.c @@ -128,7 +128,7 @@ void wlmaker_menu_item_draw( cairo_ptr, menu_item_ptr->x, menu_item_ptr->y, menu_item_ptr->width, menu_item_ptr->height, 1.0, true); - const wlmaker_style_fill_t *fill_ptr = NULL; + const wlmtk_style_fill_t *fill_ptr = NULL; uint32_t text_color = 0; switch (menu_item_ptr->state) { case WLMAKER_MENU_ITEM_STATE_ENABLED: @@ -244,8 +244,8 @@ static const wlmaker_menu_item_descriptor_t test_descriptor = { }; /** Properties of the fill, used for the unit test. */ -static const wlmaker_style_fill_t test_fill = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, +static const wlmtk_style_fill_t test_fill = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} }; diff --git a/src/toolkit/primitives.c b/src/toolkit/primitives.c index d52ef5d6..92bffbe5 100644 --- a/src/toolkit/primitives.c +++ b/src/toolkit/primitives.c @@ -27,7 +27,7 @@ /* ------------------------------------------------------------------------- */ void wlmaker_primitives_cairo_fill( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr) + const wlmtk_style_fill_t *fill_ptr) { cairo_surface_t *surface_ptr = cairo_get_target(cairo_ptr); uint32_t width = cairo_image_surface_get_width(surface_ptr); @@ -42,18 +42,18 @@ void wlmaker_primitives_cairo_fill_at( int y, unsigned width, unsigned height, - const wlmaker_style_fill_t *fill_ptr) + const wlmtk_style_fill_t *fill_ptr) { cairo_pattern_t *cairo_pattern_ptr; float r, g, b, alpha; switch (fill_ptr->type) { - case WLMAKER_STYLE_COLOR_SOLID: + case WLMTK_STYLE_COLOR_SOLID: bs_gfxbuf_argb8888_to_floats( fill_ptr->param.solid.color, &r, &g, &b, &alpha); cairo_pattern_ptr = cairo_pattern_create_rgba(r, g, b, alpha); break; - case WLMAKER_STYLE_COLOR_HGRADIENT: + case WLMTK_STYLE_COLOR_HGRADIENT: cairo_pattern_ptr = cairo_pattern_create_linear(0, 0, width, 0); bs_gfxbuf_argb8888_to_floats( fill_ptr->param.hgradient.from, &r, &g, &b, &alpha); @@ -65,7 +65,7 @@ void wlmaker_primitives_cairo_fill_at( cairo_pattern_ptr, 1, r, g, b, alpha); break; - case WLMAKER_STYLE_COLOR_DGRADIENT: + case WLMTK_STYLE_COLOR_DGRADIENT: cairo_pattern_ptr = cairo_pattern_create_linear(0, 0, width, height); bs_gfxbuf_argb8888_to_floats( fill_ptr->param.dgradient.from, &r, &g, &b, &alpha); @@ -240,8 +240,8 @@ void test_fill(bs_test_t *test_ptr) cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); // Solid fill. - wlmaker_style_fill_t fill_solid = { - .type = WLMAKER_STYLE_COLOR_SOLID, + wlmtk_style_fill_t fill_solid = { + .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xff4080c0} } }; wlmaker_primitives_cairo_fill(cairo_ptr, &fill_solid); @@ -249,8 +249,8 @@ void test_fill(bs_test_t *test_ptr) test_ptr, gfxbuf_ptr, "toolkit/primitive_fill_solid.png"); // Horizontal fill. - wlmaker_style_fill_t fill_hgradient = { - .type = WLMAKER_STYLE_COLOR_HGRADIENT, + wlmtk_style_fill_t fill_hgradient = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, .param = { .hgradient = { .from = 0xff102040, .to = 0xff4080ff }} }; wlmaker_primitives_cairo_fill(cairo_ptr, &fill_hgradient); @@ -258,8 +258,8 @@ void test_fill(bs_test_t *test_ptr) test_ptr, gfxbuf_ptr, "toolkit/primitive_fill_hgradient.png"); // Diagonal fill. - wlmaker_style_fill_t fill_dgradient = { - .type = WLMAKER_STYLE_COLOR_DGRADIENT, + wlmtk_style_fill_t fill_dgradient = { + .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .dgradient = { .from = 0xff102040, .to = 0xff4080ff }} }; wlmaker_primitives_cairo_fill(cairo_ptr, &fill_dgradient); diff --git a/src/toolkit/primitives.h b/src/toolkit/primitives.h index 8355608c..e33ae418 100644 --- a/src/toolkit/primitives.h +++ b/src/toolkit/primitives.h @@ -37,7 +37,7 @@ extern "C" { */ void wlmaker_primitives_cairo_fill( cairo_t *cairo_ptr, - const wlmaker_style_fill_t *fill_ptr); + const wlmtk_style_fill_t *fill_ptr); /** * Fills the cairo with the specified style at the specified rectangle. @@ -55,7 +55,7 @@ void wlmaker_primitives_cairo_fill_at( int y, unsigned width, unsigned height, - const wlmaker_style_fill_t *fill_ptr); + const wlmtk_style_fill_t *fill_ptr); /** * Sets the bezel color. diff --git a/src/toolkit/style.h b/src/toolkit/style.h index 3b87aeba..659ae9d3 100644 --- a/src/toolkit/style.h +++ b/src/toolkit/style.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __STYLE_H__ -#define __STYLE_H__ +#ifndef __WLMTK_STYLE_H__ +#define __WLMTK_STYLE_H__ #include @@ -29,19 +29,19 @@ extern "C" { /** Specifies the type of coloring to use for the fill. */ typedef enum { /** Horizontal color gradient. */ - WLMAKER_STYLE_COLOR_SOLID, + WLMTK_STYLE_COLOR_SOLID, /** Horizontal color gradient. */ - WLMAKER_STYLE_COLOR_HGRADIENT, + WLMTK_STYLE_COLOR_HGRADIENT, /** Diagonal color gradient, top-left to bottom-right. */ - WLMAKER_STYLE_COLOR_DGRADIENT + WLMTK_STYLE_COLOR_DGRADIENT // TODO(kaeser@gubbe.ch): Add VGRADIENT. -} wlmaker_style_fill_type_t; +} wlmtk_style_fill_type_t; /** Specifies the color for a solid fill. */ typedef struct { /** Color to start from, as ARGB 8888. Left, for the HGRADIENT type. */ uint32_t color; -} wlmaker_style_color_solid_data_t; +} wlmtk_style_color_solid_data_t; /** Specifies the two colors to span a gradient between. */ typedef struct { @@ -49,26 +49,26 @@ typedef struct { uint32_t from; /** Color to end with, as ARGB 8888. Right, for the HGRADIENT type. */ uint32_t to; -} wlmaker_style_color_gradient_data_t; +} wlmtk_style_color_gradient_data_t; /** Specification for the fill of the titlebar. */ typedef struct { /** The type of fill to apply. */ - wlmaker_style_fill_type_t type; + wlmtk_style_fill_type_t type; /** Parameters for the fill. */ union { /** Solid color. */ - wlmaker_style_color_solid_data_t solid; + wlmtk_style_color_solid_data_t solid; /** Horizontal color gradient. */ - wlmaker_style_color_gradient_data_t hgradient; + wlmtk_style_color_gradient_data_t hgradient; /** Diagonal color gradient. */ - wlmaker_style_color_gradient_data_t dgradient; + wlmtk_style_color_gradient_data_t dgradient; } param; -} wlmaker_style_fill_t; +} wlmtk_style_fill_t; #ifdef __cplusplus } // extern "C" #endif // __cplusplus -#endif /* __STYLE_H__ */ +#endif /* __WLMTK_STYLE_H__ */ /* == End of style.h ================================================== */ From 2464b03b4b09fcb0e6f817f73695ef43f3562a48 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 26 Oct 2023 22:00:14 +0200 Subject: [PATCH 137/390] Adds method for redrawing the titlebar background. --- src/toolkit/titlebar.c | 59 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index f750c95a..936fbb22 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -28,9 +28,15 @@ struct _wlmtk_titlebar_t { /** Superclass: Box. */ wlmtk_box_t super_box; + + /** Titlebar background, when focussed. */ + bs_gfxbuf_t *focussed_gfxbuf_ptr; + /** Titlebar background, when blurred. */ + bs_gfxbuf_t *blurred_gfxbuf_ptr; }; static void titlebar_box_destroy(wlmtk_box_t *box_ptr); +static bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr); /* == Data ================================================================= */ @@ -56,6 +62,11 @@ wlmtk_titlebar_t *wlmtk_titlebar_create(void) return NULL; } + if (!redraw_buffers(titlebar_ptr)) { + wlmtk_titlebar_destroy(titlebar_ptr); + return NULL; + } + return titlebar_ptr; } @@ -63,6 +74,16 @@ wlmtk_titlebar_t *wlmtk_titlebar_create(void) void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) { wlmtk_box_fini(&titlebar_ptr->super_box); + + if (NULL != titlebar_ptr->blurred_gfxbuf_ptr) { + bs_gfxbuf_destroy(titlebar_ptr->blurred_gfxbuf_ptr); + titlebar_ptr->blurred_gfxbuf_ptr = NULL; + } + if (NULL != titlebar_ptr->focussed_gfxbuf_ptr) { + bs_gfxbuf_destroy(titlebar_ptr->focussed_gfxbuf_ptr); + titlebar_ptr->focussed_gfxbuf_ptr = NULL; + } + free(titlebar_ptr); } @@ -83,6 +104,44 @@ void titlebar_box_destroy(wlmtk_box_t *box_ptr) wlmtk_titlebar_destroy(titlebar_ptr); } +/* ------------------------------------------------------------------------- */ +/** Redraws the titlebar's background in appropriate size. */ +bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) +{ + cairo_t *cairo_ptr; + int width = 120; + int height = 22; + + bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(width, height); + if (NULL == focussed_gfxbuf_ptr) return false; + cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_gfxbuf_ptr); + if (NULL == cairo_ptr) { + bs_gfxbuf_destroy(focussed_gfxbuf_ptr); + return false; + } + cairo_destroy(cairo_ptr); + + bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(width, height); + if (NULL == blurred_gfxbuf_ptr) return false; + cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_gfxbuf_ptr); + if (NULL == cairo_ptr) { + bs_gfxbuf_destroy(blurred_gfxbuf_ptr); + bs_gfxbuf_destroy(focussed_gfxbuf_ptr); + return false; + } + cairo_destroy(cairo_ptr); + + if (NULL != titlebar_ptr->focussed_gfxbuf_ptr) { + bs_gfxbuf_destroy(titlebar_ptr->focussed_gfxbuf_ptr); + } + titlebar_ptr->focussed_gfxbuf_ptr = focussed_gfxbuf_ptr; + if (NULL != titlebar_ptr->blurred_gfxbuf_ptr) { + bs_gfxbuf_destroy(titlebar_ptr->blurred_gfxbuf_ptr); + } + titlebar_ptr->blurred_gfxbuf_ptr = blurred_gfxbuf_ptr; + return true; +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); From 1586024540f55a3358977a5a4bdb9abf08dd5ed4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 16:58:53 +0200 Subject: [PATCH 138/390] Fixes missing setup of buffer virtual method table. --- src/toolkit/buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index d36f2c06..358f52d8 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -58,6 +58,7 @@ bool wlmtk_buffer_init( memset(buffer_ptr, 0, sizeof(wlmtk_buffer_t)); BS_ASSERT(NULL != buffer_impl_ptr); BS_ASSERT(NULL != buffer_impl_ptr->destroy); + memcpy(&buffer_ptr->impl, buffer_impl_ptr, sizeof(wlmtk_buffer_impl_t)); if (!wlmtk_element_init( &buffer_ptr->super_element, &super_element_impl)) { From b10e6878a8986bff3306f28127159c5720e9e90c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 17:01:03 +0200 Subject: [PATCH 139/390] Adds titlebar title element implementation and test. --- src/toolkit/titlebar.c | 237 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 234 insertions(+), 3 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 936fbb22..33b4ba3b 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -21,6 +21,13 @@ #include "titlebar.h" #include "box.h" +#include "buffer.h" +#include "gfxbuf.h" +#include "primitives.h" + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -35,11 +42,33 @@ struct _wlmtk_titlebar_t { bs_gfxbuf_t *blurred_gfxbuf_ptr; }; +/** State of the title bar's title. */ +typedef struct { + /** Superclass; Buffer. */ + wlmtk_buffer_t super_buffer; + + /** The drawn title, when focussed. */ + struct wlr_buffer *focussed_wlr_buffer_ptr; + /** The drawn title, when blurred. */ + struct wlr_buffer *blurred_wlr_buffer_ptr; +} wlmtk_titlebar_title_t; + +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + int width, + bool activated); +void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr); + static void titlebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr); /* == Data ================================================================= */ +/** Hardcoded: Height of the titlebar, in pixels. */ +static const unsigned titlebar_height = 22; + /** Method table for the box's virtual methods. */ static const wlmtk_box_impl_t titlebar_box_impl = { .destroy = titlebar_box_destroy @@ -110,9 +139,9 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) { cairo_t *cairo_ptr; int width = 120; - int height = 22; - bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(width, height); + bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create( + width, titlebar_height); if (NULL == focussed_gfxbuf_ptr) return false; cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_gfxbuf_ptr); if (NULL == cairo_ptr) { @@ -121,7 +150,8 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) } cairo_destroy(cairo_ptr); - bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(width, height); + bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create( + width, titlebar_height); if (NULL == blurred_gfxbuf_ptr) return false; cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_gfxbuf_ptr); if (NULL == cairo_ptr) { @@ -142,12 +172,185 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) return true; } +/* == Title buffer methods ================================================= */ + +static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); +bool title_redraw_buffers( + wlmtk_titlebar_title_t *title_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + unsigned position, + unsigned width); + +/** Buffer implementation for title of the title bar. */ +static const wlmtk_buffer_impl_t title_buffer_impl = { + .destroy = title_buffer_destroy +}; + +/* ------------------------------------------------------------------------- */ +/** + * Creates a title bar title. + * + * @param focussed_gfxbuf_ptr Titlebar background when focussed. + * @param blurred_gfxbuf_ptr Titlebar background when blurred. + * @param position Position of title telative to titlebar. + * @param width Width of title. + * @param activated Whether the title bar should start focussed. + * + * @return Title handle. + */ +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + int width, + bool activated) +{ + wlmtk_titlebar_title_t *title_ptr = logged_calloc( + 1, sizeof(wlmtk_titlebar_title_t)); + if (NULL == title_ptr) return NULL; + + if (!title_redraw_buffers( + title_ptr, + focussed_gfxbuf_ptr, + blurred_gfxbuf_ptr, + position, width)) { + wlmtk_titlebar_title_destroy(title_ptr); + return NULL; + } + + if (!wlmtk_buffer_init( + &title_ptr->super_buffer, + &title_buffer_impl, + title_ptr->focussed_wlr_buffer_ptr)) { + wlmtk_titlebar_title_destroy(title_ptr); + return NULL; + } + + wlmtk_buffer_set( + &title_ptr->super_buffer, + activated ? title_ptr->focussed_wlr_buffer_ptr : title_ptr->blurred_wlr_buffer_ptr); + return title_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** + * Destroys the titlebar title. + * + * @param title_ptr + */ +void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr) +{ + if (NULL != title_ptr->focussed_wlr_buffer_ptr) { + wlr_buffer_drop(title_ptr->focussed_wlr_buffer_ptr); + title_ptr->focussed_wlr_buffer_ptr = NULL; + } + if (NULL != title_ptr->blurred_wlr_buffer_ptr) { + wlr_buffer_drop(title_ptr->blurred_wlr_buffer_ptr); + title_ptr->blurred_wlr_buffer_ptr = NULL; + } + + wlmtk_buffer_fini(&title_ptr->super_buffer); + free(title_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Dtor. Forwards to @ref wlmtk_titlebar_title_destroy. */ +void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +{ + wlmtk_titlebar_title_t *title_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_titlebar_title_t, super_buffer); + wlmtk_titlebar_title_destroy(title_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Redraws the title buffers. */ +bool title_redraw_buffers( + wlmtk_titlebar_title_t *title_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + unsigned position, + unsigned width) +{ + cairo_t *cairo_ptr; + + BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); + BS_ASSERT(titlebar_height == focussed_gfxbuf_ptr->height); + BS_ASSERT(titlebar_height == blurred_gfxbuf_ptr->height); + BS_ASSERT(position < focussed_gfxbuf_ptr->width); + BS_ASSERT(position + width < focussed_gfxbuf_ptr->width); + + struct wlr_buffer *focussed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + width, titlebar_height); + if (NULL == focussed_wlr_buffer_ptr) return false; + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(focussed_wlr_buffer_ptr), + 0, 0, + focussed_gfxbuf_ptr, + position, 0, + width, titlebar_height); + + cairo_ptr = cairo_create_from_wlr_buffer(focussed_wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(focussed_wlr_buffer_ptr); + return false; + } + + wlmaker_primitives_draw_bezel_at( + cairo_ptr, 0, 0, width, titlebar_height, 1.0, true); + wlmaker_primitives_draw_window_title( + cairo_ptr, "Title", 0xffc0c0c0); + + cairo_destroy(cairo_ptr); + + struct wlr_buffer *blurred_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + width, titlebar_height); + if (NULL == blurred_wlr_buffer_ptr) { + wlr_buffer_drop(focussed_wlr_buffer_ptr); + return false; + } + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(blurred_wlr_buffer_ptr), + 0, 0, + blurred_gfxbuf_ptr, + position, 0, + width, titlebar_height); + + cairo_ptr = cairo_create_from_wlr_buffer(blurred_wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(blurred_wlr_buffer_ptr); + return false; + } + + wlmaker_primitives_draw_bezel_at( + cairo_ptr, 0, 0, width, titlebar_height, 1.0, true); + wlmaker_primitives_draw_window_title( + cairo_ptr, "Title", 0xff808080); + + cairo_destroy(cairo_ptr); + + if (NULL == title_ptr->focussed_wlr_buffer_ptr) { + wlr_buffer_drop(title_ptr->focussed_wlr_buffer_ptr); + } + title_ptr->focussed_wlr_buffer_ptr = focussed_wlr_buffer_ptr; + if (NULL == title_ptr->blurred_wlr_buffer_ptr) { + wlr_buffer_drop(title_ptr->blurred_wlr_buffer_ptr); + } + title_ptr->blurred_wlr_buffer_ptr = blurred_wlr_buffer_ptr; + return true; +} + + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_title(bs_test_t *test_ptr); const bs_test_case_t wlmtk_titlebar_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "title", test_title }, { 0, NULL, NULL } }; @@ -161,4 +364,32 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); } +/* ------------------------------------------------------------------------- */ +/** Tests title drawing. */ +void test_title(bs_test_t *test_ptr) +{ + bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(120, titlebar_height); + bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(120, titlebar_height); + bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); + bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); + + wlmtk_titlebar_title_t *title_ptr = wlmtk_titlebar_title_create( + focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, title_ptr); + + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(title_ptr->focussed_wlr_buffer_ptr), + "toolkit/title_focussed.png"); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(title_ptr->blurred_wlr_buffer_ptr), + "toolkit/title_blurred.png"); + + wlmtk_element_destroy(&title_ptr->super_buffer.super_element); + + bs_gfxbuf_destroy(focussed_gfxbuf_ptr); + bs_gfxbuf_destroy(blurred_gfxbuf_ptr); +} + /* == End of titlebar.c ==================================================== */ From 37bd3da93494fc69e818bb7e04d3c44d0da877a9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 17:01:24 +0200 Subject: [PATCH 140/390] Adds the test data files for the title ... --- testdata/toolkit/title_blurred.png | Bin 0 -> 559 bytes testdata/toolkit/title_focussed.png | Bin 0 -> 549 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 testdata/toolkit/title_blurred.png create mode 100644 testdata/toolkit/title_focussed.png diff --git a/testdata/toolkit/title_blurred.png b/testdata/toolkit/title_blurred.png new file mode 100644 index 0000000000000000000000000000000000000000..52c3009aa87c849b15ed1fe18590c8f92c868629 GIT binary patch literal 559 zcmV+~0?_@5P))Hsz4OR*Y+Pw5@LxMMH0~iR4>pA_9}JZ8*~xfWL-p; zArS*oA*oQBj{9Ojj_o*{bIMbD9LI4SA%tF!5CQ;~%LM?EBmn?bRV7JsU6pDUR0BW^b5Ck`N@I2pcw`Eyo zS=M#k&1U2K{*yH4$iKJJ`Fwslod96HUR#!xIh0{~y`H9NK@j-9U#V2O-EOH=dQj_s zAeYIaX&OT4a5$Kzxm+%HyB*82x~}Ju>$&`OvHS^iFe!>cD~lqEVjj7kOD=ZMxwGHz z9mh$7aUAE7>$yCkSQzH^5ZX19B*7SCjKeVe7L5ZQ{5qm20)R%NalKxT$733|ZM)fQ zs;VjoLKH>SYLyUT+xDYk^XDNuw%e^JiU=V(aZ}grF&K5ElueAp}Dt18ERDI!ef24IRmqM0I!mhyvZMXZFjyEm6c{=b7&;V~zm~#bW@o!xTCcOU#nBPK_BKyX z1OiMGpo@-!1NpGF z#`-$NB71wC?#_;U@Ol{^2k>}!c=#tqy6E_xkBtZh5d?sxB}DPF4!fO=4LlyKR`PjH zPr1L>BCpQ;{ZSeYb9)PLct|p-Xjv?TLil`CtCUL2&l3tUHKi_TPtfJf;`bv6TwM`~ zu)oj61!H5ZuIe#LV}89XKVfDD!0VMa>z(OoJw|DaE;`z6fXhp6ZaT$UO^;C;qrtM6 zOrI;I5pUr|Rx_c>!2n=J}cH>rOqBVP%EIMH~)lHRk4MwTQ*k zCG82Sbex~#bRq~$PAclJuSBD4ZsK-hv5?D=NKh=Q3fdb+;_sIdE literal 0 HcmV?d00001 From 3d8d7e97a5d923586f38bd66fb32accf76a84803 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 17:15:41 +0200 Subject: [PATCH 141/390] Adds code & tests to redraw title depending on activation. --- src/toolkit/titlebar.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 33b4ba3b..527362e8 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -175,7 +175,10 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) /* == Title buffer methods ================================================= */ static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); -bool title_redraw_buffers( +static void title_set_activated( + wlmtk_titlebar_title_t *title_ptr, + bool activated); +static bool title_redraw_buffers( wlmtk_titlebar_title_t *title_ptr, bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, @@ -227,9 +230,7 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( return NULL; } - wlmtk_buffer_set( - &title_ptr->super_buffer, - activated ? title_ptr->focussed_wlr_buffer_ptr : title_ptr->blurred_wlr_buffer_ptr); + title_set_activated(title_ptr, activated); return title_ptr; } @@ -263,6 +264,22 @@ void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) wlmtk_titlebar_title_destroy(title_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Sets whether the title is drawn focussed (activated) or blurred. + * + * @param title_ptr + * @param activated + */ +void title_set_activated(wlmtk_titlebar_title_t *title_ptr, bool activated) +{ + wlmtk_buffer_set( + &title_ptr->super_buffer, + activated ? + title_ptr->focussed_wlr_buffer_ptr : + title_ptr->blurred_wlr_buffer_ptr); +} + /* ------------------------------------------------------------------------- */ /** Redraws the title buffers. */ bool title_redraw_buffers( @@ -386,6 +403,19 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(title_ptr->blurred_wlr_buffer_ptr), "toolkit/title_blurred.png"); + // We had started as "activated", verify that's correct. + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), + "toolkit/title_focussed.png"); + + // De-activated the title. Verify that was propagated. + title_set_activated(title_ptr, false); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), + "toolkit/title_blurred.png"); + wlmtk_element_destroy(&title_ptr->super_buffer.super_element); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); From d98037fb06d15d93795837a9201d5c275f936db0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 17:23:04 +0200 Subject: [PATCH 142/390] Wires up the title element in the titlebar. --- src/toolkit/titlebar.c | 51 +++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 527362e8..5b7f726c 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -31,17 +31,6 @@ /* == Declarations ========================================================= */ -/** State of the title bar. */ -struct _wlmtk_titlebar_t { - /** Superclass: Box. */ - wlmtk_box_t super_box; - - /** Titlebar background, when focussed. */ - bs_gfxbuf_t *focussed_gfxbuf_ptr; - /** Titlebar background, when blurred. */ - bs_gfxbuf_t *blurred_gfxbuf_ptr; -}; - /** State of the title bar's title. */ typedef struct { /** Superclass; Buffer. */ @@ -53,6 +42,20 @@ typedef struct { struct wlr_buffer *blurred_wlr_buffer_ptr; } wlmtk_titlebar_title_t; +/** State of the title bar. */ +struct _wlmtk_titlebar_t { + /** Superclass: Box. */ + wlmtk_box_t super_box; + + /** Title element of the title bar. */ + wlmtk_titlebar_title_t *title_ptr; + + /** Titlebar background, when focussed. */ + bs_gfxbuf_t *focussed_gfxbuf_ptr; + /** Titlebar background, when blurred. */ + bs_gfxbuf_t *blurred_gfxbuf_ptr; +}; + wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, @@ -96,13 +99,32 @@ wlmtk_titlebar_t *wlmtk_titlebar_create(void) return NULL; } + titlebar_ptr->title_ptr = wlmtk_titlebar_title_create( + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + 0, 120, + true); + if (NULL == titlebar_ptr->title_ptr) { + wlmtk_titlebar_destroy(titlebar_ptr); + return NULL; + } + wlmtk_container_add_element( + &titlebar_ptr->super_box.super_container, + &titlebar_ptr->title_ptr->super_buffer.super_element); + return titlebar_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) { - wlmtk_box_fini(&titlebar_ptr->super_box); + if (NULL != titlebar_ptr->title_ptr) { + wlmtk_container_remove_element( + &titlebar_ptr->super_box.super_container, + &titlebar_ptr->title_ptr->super_buffer.super_element); + wlmtk_titlebar_title_destroy(titlebar_ptr->title_ptr); + titlebar_ptr->title_ptr = NULL; + } if (NULL != titlebar_ptr->blurred_gfxbuf_ptr) { bs_gfxbuf_destroy(titlebar_ptr->blurred_gfxbuf_ptr); @@ -113,6 +135,8 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) titlebar_ptr->focussed_gfxbuf_ptr = NULL; } + wlmtk_box_fini(&titlebar_ptr->super_box); + free(titlebar_ptr); } @@ -295,7 +319,8 @@ bool title_redraw_buffers( BS_ASSERT(titlebar_height == focussed_gfxbuf_ptr->height); BS_ASSERT(titlebar_height == blurred_gfxbuf_ptr->height); BS_ASSERT(position < focussed_gfxbuf_ptr->width); - BS_ASSERT(position + width < focussed_gfxbuf_ptr->width); + BS_ASSERT(0 < width); + BS_ASSERT(position + width <= focussed_gfxbuf_ptr->width); struct wlr_buffer *focussed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( width, titlebar_height); From 659703a24ec2d4e35fba548432e091d5e65497ec Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 17:46:42 +0200 Subject: [PATCH 143/390] Wires up titlebar in window. --- src/toolkit/titlebar.c | 2 ++ src/toolkit/window.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 5b7f726c..cfdb7194 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -108,6 +108,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create(void) wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } + wlmtk_element_set_visible( + &titlebar_ptr->title_ptr->super_buffer.super_element, true); wlmtk_container_add_element( &titlebar_ptr->super_box.super_container, &titlebar_ptr->title_ptr->super_buffer.super_element); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 4ed33f39..973518ec 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -21,6 +21,7 @@ #include "window.h" #include "box.h" +#include "titlebar.h" #include "workspace.h" /* == Declarations ========================================================= */ @@ -32,6 +33,8 @@ struct _wlmtk_window_t { /** Content of this window. */ wlmtk_content_t *content_ptr; + /** Titlebar. */ + wlmtk_titlebar_t *titlebar_ptr; }; static void window_box_destroy(wlmtk_box_t *box_ptr); @@ -64,12 +67,32 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) window_ptr->content_ptr = content_ptr; wlmtk_content_set_window(content_ptr, window_ptr); wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + + window_ptr->titlebar_ptr = wlmtk_titlebar_create(); + if (NULL == window_ptr->titlebar_ptr) { + wlmtk_window_destroy(window_ptr); + return NULL; + } + wlmtk_container_add_element( + &window_ptr->super_box.super_container, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_element_set_visible( + wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + return window_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_container_remove_element( + &window_ptr->super_box.super_container, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); + window_ptr->titlebar_ptr = NULL; + } + wlmtk_container_remove_element( &window_ptr->super_box.super_container, wlmtk_content_element(window_ptr->content_ptr)); From 4d3d74f0413d7c6154e84e29f10eac604242d6bc Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 17:52:02 +0200 Subject: [PATCH 144/390] Evades the crash on cleanup in wlmtk_buffer_fini. Temporary fix. --- src/toolkit/buffer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index 358f52d8..a8ba1ccb 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -77,7 +77,9 @@ void wlmtk_buffer_fini(wlmtk_buffer_t *buffer_ptr) buffer_ptr->wlr_buffer_ptr = NULL; } - if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { + if (NULL != buffer_ptr->super_element.wlr_scene_node_ptr) { + // TODO: Wire up a destry listener, and clear the local pointer + // if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { wlr_scene_node_destroy(&buffer_ptr->wlr_scene_buffer_ptr->node); buffer_ptr->wlr_scene_buffer_ptr = NULL; } From 883b0122510c9638f3f041ba419af90e35c76015 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 19:56:37 +0200 Subject: [PATCH 145/390] Adds a readability comment regarding the detachment of child nodes. --- src/toolkit/container.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 18bb5b1e..31f91655 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -406,6 +406,7 @@ void handle_wlr_scene_tree_node_destroy( dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + // Will read the parent container's wlr_scene_tree_ptr == NULL. wlmtk_element_attach_to_scene_graph(element_ptr); } From d5c3351f55099d5508c7c38d49900e2df0cac17e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 19:57:05 +0200 Subject: [PATCH 146/390] Fixes the call flow of the deletion of wlr_scene_buffer_ptr in wltmk_buffer. --- src/toolkit/buffer.c | 34 +++++++++++++++++++++++++++++++--- src/toolkit/buffer.h | 3 +++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index a8ba1ccb..9694f8c3 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -20,6 +20,8 @@ #include "buffer.h" +#include "util.h" + #define WLR_USE_UNSTABLE #include #undef WLR_USE_UNSTABLE @@ -36,6 +38,9 @@ static void element_get_dimensions( int *top_ptr, int *right_ptr, int *bottom_ptr); +static void handle_wlr_scene_buffer_node_destroy( + struct wl_listener *listener_ptr, + void *data_ptr); /* == Data ================================================================= */ @@ -77,9 +82,7 @@ void wlmtk_buffer_fini(wlmtk_buffer_t *buffer_ptr) buffer_ptr->wlr_buffer_ptr = NULL; } - if (NULL != buffer_ptr->super_element.wlr_scene_node_ptr) { - // TODO: Wire up a destry listener, and clear the local pointer - // if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { + if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { wlr_scene_node_destroy(&buffer_ptr->wlr_scene_buffer_ptr->node); buffer_ptr->wlr_scene_buffer_ptr = NULL; } @@ -143,6 +146,10 @@ struct wlr_scene_node *element_create_scene_node( buffer_ptr->wlr_buffer_ptr); BS_ASSERT(NULL != buffer_ptr->wlr_scene_buffer_ptr); + wlmtk_util_connect_listener_signal( + &buffer_ptr->wlr_scene_buffer_ptr->node.events.destroy, + &buffer_ptr->wlr_scene_buffer_node_destroy_listener, + handle_wlr_scene_buffer_node_destroy); return &buffer_ptr->wlr_scene_buffer_ptr->node; } @@ -172,4 +179,25 @@ void element_get_dimensions( if (NULL != bottom_ptr) *bottom_ptr = buffer_ptr->wlr_buffer_ptr->height; } +/* ------------------------------------------------------------------------- */ +/** + * Handles the 'destroy' callback of wlr_scene_buffer_ptr->node. + * + * Will reset the wlr_scene_buffer_ptr value. Destruction of the node had + * been triggered (hence the callback). + * + * @param listener_ptr + * @param data_ptr + */ +void handle_wlr_scene_buffer_node_destroy( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_buffer_t, wlr_scene_buffer_node_destroy_listener); + + buffer_ptr->wlr_scene_buffer_ptr = NULL; + wl_list_remove(&buffer_ptr->wlr_scene_buffer_node_destroy_listener.link); +} + /* == End of buffer.c ====================================================== */ diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index 87a78c3b..4bf264b6 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -57,6 +57,9 @@ struct _wlmtk_buffer_t { struct wlr_buffer *wlr_buffer_ptr; /** Scene graph API node. Only set after calling `create_scene_node`. */ struct wlr_scene_buffer *wlr_scene_buffer_ptr; + + /** Listener for the `destroy` signal of `wlr_scene_buffer_ptr->node`. */ + struct wl_listener wlr_scene_buffer_node_destroy_listener; }; /** From 39cc566c37a3c2f193465c73bd7a9fb3560df359 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 20:37:34 +0200 Subject: [PATCH 147/390] Makes the title bar style configurable. --- src/toolkit/titlebar.c | 72 ++++++++++++++++++++++++++---------------- src/toolkit/titlebar.h | 21 +++++++++++- src/toolkit/window.c | 18 ++++++++++- 3 files changed, 82 insertions(+), 29 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index cfdb7194..29cf0269 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -54,6 +54,9 @@ struct _wlmtk_titlebar_t { bs_gfxbuf_t *focussed_gfxbuf_ptr; /** Titlebar background, when blurred. */ bs_gfxbuf_t *blurred_gfxbuf_ptr; + + /** Title bar style. */ + wlmtk_titlebar_style_t style; }; wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( @@ -61,7 +64,8 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( bs_gfxbuf_t *blurred_gfxbuf_ptr, int position, int width, - bool activated); + bool activated, + const wlmtk_titlebar_style_t *style_ptr); void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr); static void titlebar_box_destroy(wlmtk_box_t *box_ptr); @@ -69,9 +73,6 @@ static bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr); /* == Data ================================================================= */ -/** Hardcoded: Height of the titlebar, in pixels. */ -static const unsigned titlebar_height = 22; - /** Method table for the box's virtual methods. */ static const wlmtk_box_impl_t titlebar_box_impl = { .destroy = titlebar_box_destroy @@ -81,11 +82,13 @@ static const wlmtk_box_impl_t titlebar_box_impl = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_titlebar_t *wlmtk_titlebar_create(void) +wlmtk_titlebar_t *wlmtk_titlebar_create( + const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_t *titlebar_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_t)); if (NULL == titlebar_ptr) return NULL; + memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); if (!wlmtk_box_init(&titlebar_ptr->super_box, &titlebar_box_impl, @@ -103,7 +106,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create(void) titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, 0, 120, - true); + true, + &titlebar_ptr->style); if (NULL == titlebar_ptr->title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -167,24 +171,28 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) int width = 120; bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create( - width, titlebar_height); + width, titlebar_ptr->style.height); if (NULL == focussed_gfxbuf_ptr) return false; cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_gfxbuf_ptr); if (NULL == cairo_ptr) { bs_gfxbuf_destroy(focussed_gfxbuf_ptr); return false; } + wlmaker_primitives_cairo_fill( + cairo_ptr, &titlebar_ptr->style.focussed_fill); cairo_destroy(cairo_ptr); bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create( - width, titlebar_height); + width, titlebar_ptr->style.height); if (NULL == blurred_gfxbuf_ptr) return false; - cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_gfxbuf_ptr); + cairo_ptr = cairo_create_from_bs_gfxbuf(blurred_gfxbuf_ptr); if (NULL == cairo_ptr) { bs_gfxbuf_destroy(blurred_gfxbuf_ptr); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); return false; } + wlmaker_primitives_cairo_fill( + cairo_ptr, &titlebar_ptr->style.blurred_fill); cairo_destroy(cairo_ptr); if (NULL != titlebar_ptr->focussed_gfxbuf_ptr) { @@ -209,7 +217,8 @@ static bool title_redraw_buffers( bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, unsigned position, - unsigned width); + unsigned width, + const wlmtk_titlebar_style_t *style_ptr); /** Buffer implementation for title of the title bar. */ static const wlmtk_buffer_impl_t title_buffer_impl = { @@ -225,6 +234,7 @@ static const wlmtk_buffer_impl_t title_buffer_impl = { * @param position Position of title telative to titlebar. * @param width Width of title. * @param activated Whether the title bar should start focussed. + * @param style_ptr * * @return Title handle. */ @@ -233,7 +243,8 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( bs_gfxbuf_t *blurred_gfxbuf_ptr, int position, int width, - bool activated) + bool activated, + const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_title_t *title_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_title_t)); @@ -243,7 +254,7 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, - position, width)) { + position, width, style_ptr)) { wlmtk_titlebar_title_destroy(title_ptr); return NULL; } @@ -313,19 +324,20 @@ bool title_redraw_buffers( bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, unsigned position, - unsigned width) + unsigned width, + const wlmtk_titlebar_style_t *style_ptr) { cairo_t *cairo_ptr; BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); - BS_ASSERT(titlebar_height == focussed_gfxbuf_ptr->height); - BS_ASSERT(titlebar_height == blurred_gfxbuf_ptr->height); + BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); + BS_ASSERT(style_ptr->height == blurred_gfxbuf_ptr->height); BS_ASSERT(position < focussed_gfxbuf_ptr->width); BS_ASSERT(0 < width); BS_ASSERT(position + width <= focussed_gfxbuf_ptr->width); struct wlr_buffer *focussed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - width, titlebar_height); + width, style_ptr->height); if (NULL == focussed_wlr_buffer_ptr) return false; bs_gfxbuf_copy_area( @@ -333,7 +345,7 @@ bool title_redraw_buffers( 0, 0, focussed_gfxbuf_ptr, position, 0, - width, titlebar_height); + width, style_ptr->height); cairo_ptr = cairo_create_from_wlr_buffer(focussed_wlr_buffer_ptr); if (NULL == cairo_ptr) { @@ -342,14 +354,14 @@ bool title_redraw_buffers( } wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, titlebar_height, 1.0, true); + cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); wlmaker_primitives_draw_window_title( - cairo_ptr, "Title", 0xffc0c0c0); + cairo_ptr, "Title", style_ptr->focussed_text_color); cairo_destroy(cairo_ptr); struct wlr_buffer *blurred_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - width, titlebar_height); + width, style_ptr->height); if (NULL == blurred_wlr_buffer_ptr) { wlr_buffer_drop(focussed_wlr_buffer_ptr); return false; @@ -360,7 +372,7 @@ bool title_redraw_buffers( 0, 0, blurred_gfxbuf_ptr, position, 0, - width, titlebar_height); + width, style_ptr->height); cairo_ptr = cairo_create_from_wlr_buffer(blurred_wlr_buffer_ptr); if (NULL == cairo_ptr) { @@ -369,9 +381,9 @@ bool title_redraw_buffers( } wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, titlebar_height, 1.0, true); + cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); wlmaker_primitives_draw_window_title( - cairo_ptr, "Title", 0xff808080); + cairo_ptr, "Title", style_ptr->blurred_text_color); cairo_destroy(cairo_ptr); @@ -402,7 +414,8 @@ const bs_test_case_t wlmtk_titlebar_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(); + wlmtk_titlebar_style_t style = {}; + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(&style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); @@ -412,13 +425,18 @@ void test_create_destroy(bs_test_t *test_ptr) /** Tests title drawing. */ void test_title(bs_test_t *test_ptr) { - bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(120, titlebar_height); - bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(120, titlebar_height); + const wlmtk_titlebar_style_t style = { + .focussed_text_color = 0xffc0c0c0, + .blurred_text_color = 0xff808080, + .height = 22, + }; + bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(120, 22); + bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(120, 22); bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); wlmtk_titlebar_title_t *title_ptr = wlmtk_titlebar_title_create( - focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true); + focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, title_ptr); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 5ba29ab8..fc76cbda 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -25,17 +25,36 @@ typedef struct _wlmtk_titlebar_t wlmtk_titlebar_t; #include "element.h" +#include "primitives.h" + #ifdef __cplusplus extern "C" { #endif // __cplusplus +/** Style options for the titlebar. */ +typedef struct { + /** Fill style for when the titlebar is focussed (activated). */ + wlmtk_style_fill_t focussed_fill; + /** Fill style for when the titlebar is blurred (not activated). */ + wlmtk_style_fill_t blurred_fill; + /** Color of the title text when focussed. */ + uint32_t focussed_text_color; + /** Color of the title text when blurred. */ + uint32_t blurred_text_color; + /** Height of the title bar, in pixels. */ + uint32_t height; +} wlmtk_titlebar_style_t; + /** * Creates a title bar, suitable as a window title. * * @return Pointer to the title bar state, or NULL on error. Must be free'd * by calling @ref wlmtk_titlebar_destroy. + * + * @param style_ptr */ -wlmtk_titlebar_t *wlmtk_titlebar_create(void); +wlmtk_titlebar_t *wlmtk_titlebar_create( + const wlmtk_titlebar_style_t *style_ptr); /** * Destroys the title bar. diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 973518ec..70029030 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -46,6 +46,22 @@ static const wlmtk_box_impl_t window_box_impl = { .destroy = window_box_destroy }; +/** Style of the title bar. */ +// TODO(kaeser@gubbe.ch): Move to central config. */ +static const wlmtk_titlebar_style_t titlebar_style = { + .focussed_fill = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, + .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} + }, + .blurred_fill = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, + .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} + }, + .focussed_text_color = 0xffffffff, + .blurred_text_color = 0xff000000, + .height = 22, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -68,7 +84,7 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_content_set_window(content_ptr, window_ptr); wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - window_ptr->titlebar_ptr = wlmtk_titlebar_create(); + window_ptr->titlebar_ptr = wlmtk_titlebar_create(&titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_destroy(window_ptr); return NULL; From 68cdbaf41669acd4da59709fc918f17d68302df4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 21:28:40 +0200 Subject: [PATCH 148/390] Makes title bar width configurable. --- src/toolkit/titlebar.c | 130 ++++++++++++++++++++++++++++++++++------- src/toolkit/titlebar.h | 10 ++++ src/toolkit/window.c | 4 ++ 3 files changed, 122 insertions(+), 22 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 29cf0269..721e135c 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -31,16 +31,8 @@ /* == Declarations ========================================================= */ -/** State of the title bar's title. */ -typedef struct { - /** Superclass; Buffer. */ - wlmtk_buffer_t super_buffer; - - /** The drawn title, when focussed. */ - struct wlr_buffer *focussed_wlr_buffer_ptr; - /** The drawn title, when blurred. */ - struct wlr_buffer *blurred_wlr_buffer_ptr; -} wlmtk_titlebar_title_t; +/** Forward declaration. */ +typedef struct _wlmtk_titlebar_title_t wlmtk_titlebar_title_t; /** State of the title bar. */ struct _wlmtk_titlebar_t { @@ -55,21 +47,47 @@ struct _wlmtk_titlebar_t { /** Titlebar background, when blurred. */ bs_gfxbuf_t *blurred_gfxbuf_ptr; + /** Current width of the title bar. */ + unsigned width; + /** Whether the title bar is currently displayed as activated. */ + bool activated; + /** Title bar style. */ wlmtk_titlebar_style_t style; }; -wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( +/** State of the title bar's title. */ +struct _wlmtk_titlebar_title_t { + /** Superclass; Buffer. */ + wlmtk_buffer_t super_buffer; + + /** The drawn title, when focussed. */ + struct wlr_buffer *focussed_wlr_buffer_ptr; + /** The drawn title, when blurred. */ + struct wlr_buffer *blurred_wlr_buffer_ptr; +} ; + +static wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + int width, + bool activated, + const wlmtk_titlebar_style_t *style_ptr); +static void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr); +static bool wlmtk_titlebar_title_redraw( + wlmtk_titlebar_title_t *title_ptr, bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, int position, int width, bool activated, const wlmtk_titlebar_style_t *style_ptr); -void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr); static void titlebar_box_destroy(wlmtk_box_t *box_ptr); -static bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr); +static bool redraw_buffers( + wlmtk_titlebar_t *titlebar_ptr, + unsigned width); /* == Data ================================================================= */ @@ -78,7 +96,6 @@ static const wlmtk_box_impl_t titlebar_box_impl = { .destroy = titlebar_box_destroy }; - /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -97,7 +114,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } - if (!redraw_buffers(titlebar_ptr)) { + if (!redraw_buffers(titlebar_ptr, 120)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } @@ -105,8 +122,9 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->title_ptr = wlmtk_titlebar_title_create( titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, - 0, 120, - true, + 0, + titlebar_ptr->width, + titlebar_ptr->activated, &titlebar_ptr->style); if (NULL == titlebar_ptr->title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -146,6 +164,32 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) free(titlebar_ptr); } +/* ------------------------------------------------------------------------- */ +bool wlmtk_titlebar_set_width( + wlmtk_titlebar_t *titlebar_ptr, + unsigned width) +{ + if (titlebar_ptr->width == width) return true; + redraw_buffers(titlebar_ptr, width); + BS_ASSERT(width == titlebar_ptr->width); + + if (!wlmtk_titlebar_title_redraw( + titlebar_ptr->title_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + 0, + titlebar_ptr->width, + titlebar_ptr->activated, + &titlebar_ptr->style)) { + return false; + } + + + // Don't forget to re-position the elements. + wlmtk_container_update_layout(&titlebar_ptr->super_box.super_container); + return true; +} + /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_titlebar_element(wlmtk_titlebar_t *titlebar_ptr) { @@ -165,10 +209,9 @@ void titlebar_box_destroy(wlmtk_box_t *box_ptr) /* ------------------------------------------------------------------------- */ /** Redraws the titlebar's background in appropriate size. */ -bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) +bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) { cairo_t *cairo_ptr; - int width = 120; bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create( width, titlebar_ptr->style.height); @@ -203,6 +246,7 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr) bs_gfxbuf_destroy(titlebar_ptr->blurred_gfxbuf_ptr); } titlebar_ptr->blurred_gfxbuf_ptr = blurred_gfxbuf_ptr; + titlebar_ptr->width = width; return true; } @@ -271,6 +315,40 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( return title_ptr; } +/* ------------------------------------------------------------------------- */ +/** + * Redraws the title section of the title bar. + * + * @param title_ptr + * @param focussed_gfxbuf_ptr Titlebar background when focussed. + * @param blurred_gfxbuf_ptr Titlebar background when blurred. + * @param position Position of title telative to titlebar. + * @param width Width of title. + * @param activated Whether the title bar should start focussed. + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_titlebar_title_redraw( + wlmtk_titlebar_title_t *title_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + int width, + bool activated, + const wlmtk_titlebar_style_t *style_ptr) +{ + if (!title_redraw_buffers( + title_ptr, + focussed_gfxbuf_ptr, + blurred_gfxbuf_ptr, + position, width, style_ptr)) { + return false; + } + title_set_activated(title_ptr, activated); + return true; +} + /* ------------------------------------------------------------------------- */ /** * Destroys the titlebar title. @@ -387,11 +465,11 @@ bool title_redraw_buffers( cairo_destroy(cairo_ptr); - if (NULL == title_ptr->focussed_wlr_buffer_ptr) { + if (NULL != title_ptr->focussed_wlr_buffer_ptr) { wlr_buffer_drop(title_ptr->focussed_wlr_buffer_ptr); } title_ptr->focussed_wlr_buffer_ptr = focussed_wlr_buffer_ptr; - if (NULL == title_ptr->blurred_wlr_buffer_ptr) { + if (NULL != title_ptr->blurred_wlr_buffer_ptr) { wlr_buffer_drop(title_ptr->blurred_wlr_buffer_ptr); } title_ptr->blurred_wlr_buffer_ptr = blurred_wlr_buffer_ptr; @@ -461,8 +539,16 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), "toolkit/title_blurred.png"); - wlmtk_element_destroy(&title_ptr->super_buffer.super_element); + // Redraw with shorter width. Verify that's still correct. + wlmtk_titlebar_title_redraw( + title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, + 10, 70, false, &style); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), + "toolkit/title_blurred_short.png"); + wlmtk_element_destroy(&title_ptr->super_buffer.super_element); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); } diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index fc76cbda..b3150b34 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -63,6 +63,16 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( */ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr); +/** + * Sets the width of the title bar. + * + * @param titlebar_ptr + * @param width + * + * @return Whether the operation was successful. + */ +bool wlmtk_titlebar_set_width(wlmtk_titlebar_t *titlebar_ptr, unsigned width); + /** * Returns the super Element of the titlebar. * diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 70029030..e9a8d356 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -168,6 +168,10 @@ void wlmtk_window_set_size( // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. wlmtk_content_set_size(window_ptr->content_ptr, width, height); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); + } + // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting // the size is an asynchronous operation and should be handled as such. // Meaning: In example of resizing at the top-left corner, we'll want to From 4f1978f81b9e5552d77af0002c6dee4fb127bfd0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 21:34:19 +0200 Subject: [PATCH 149/390] Makes titlebar width configurable. --- src/toolkit/titlebar.c | 21 +++++++++++++++++---- src/toolkit/titlebar.h | 6 ++++-- src/toolkit/window.c | 4 +++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 721e135c..8dc75b25 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -100,6 +100,7 @@ static const wlmtk_box_impl_t titlebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( + unsigned width, const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_t *titlebar_ptr = logged_calloc( @@ -114,7 +115,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } - if (!redraw_buffers(titlebar_ptr, 120)) { + if (!redraw_buffers(titlebar_ptr, width)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } @@ -410,8 +411,7 @@ bool title_redraw_buffers( BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); BS_ASSERT(style_ptr->height == blurred_gfxbuf_ptr->height); - BS_ASSERT(position < focussed_gfxbuf_ptr->width); - BS_ASSERT(0 < width); + BS_ASSERT(position <= focussed_gfxbuf_ptr->width); BS_ASSERT(position + width <= focussed_gfxbuf_ptr->width); struct wlr_buffer *focussed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( @@ -480,10 +480,12 @@ bool title_redraw_buffers( /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_create_empty(bs_test_t *test_ptr); static void test_title(bs_test_t *test_ptr); const bs_test_case_t wlmtk_titlebar_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "create_empty", test_create_empty }, { 1, "title", test_title }, { 0, NULL, NULL } }; @@ -493,7 +495,18 @@ const bs_test_case_t wlmtk_titlebar_test_cases[] = { void test_create_destroy(bs_test_t *test_ptr) { wlmtk_titlebar_style_t style = {}; - wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(&style); + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(120, &style); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); + + wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); +} + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown. */ +void test_create_empty(bs_test_t *test_ptr) +{ + wlmtk_titlebar_style_t style = {}; + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(0, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index b3150b34..4fb22d0b 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -48,12 +48,14 @@ typedef struct { /** * Creates a title bar, suitable as a window title. * + * @param width + * @param style_ptr + * * @return Pointer to the title bar state, or NULL on error. Must be free'd * by calling @ref wlmtk_titlebar_destroy. - * - * @param style_ptr */ wlmtk_titlebar_t *wlmtk_titlebar_create( + unsigned width, const wlmtk_titlebar_style_t *style_ptr); /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index e9a8d356..5827709f 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -84,7 +84,9 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_content_set_window(content_ptr, window_ptr); wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - window_ptr->titlebar_ptr = wlmtk_titlebar_create(&titlebar_style); + int width; + wlmtk_content_get_size(content_ptr, &width, NULL); + window_ptr->titlebar_ptr = wlmtk_titlebar_create(width, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_destroy(window_ptr); return NULL; From 1625778dcf2f04035288864c84d3740fc8907eb1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 21:39:21 +0200 Subject: [PATCH 150/390] Adds 'set_activated' to titlebar and wires it up with the window. --- src/toolkit/titlebar.c | 45 +++++++++++++++++++++++++----------------- src/toolkit/titlebar.h | 14 ++++++++++++- src/toolkit/window.c | 3 +++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 8dc75b25..a3726519 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -89,6 +89,18 @@ static bool redraw_buffers( wlmtk_titlebar_t *titlebar_ptr, unsigned width); +static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static void title_set_activated( + wlmtk_titlebar_title_t *title_ptr, + bool activated); +static bool title_redraw_buffers( + wlmtk_titlebar_title_t *title_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_titlebar_style_t *style_ptr); + /* == Data ================================================================= */ /** Method table for the box's virtual methods. */ @@ -96,6 +108,11 @@ static const wlmtk_box_impl_t titlebar_box_impl = { .destroy = titlebar_box_destroy }; +/** Buffer implementation for title of the title bar. */ +static const wlmtk_buffer_impl_t title_buffer_impl = { + .destroy = title_buffer_destroy +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -185,12 +202,21 @@ bool wlmtk_titlebar_set_width( return false; } - // Don't forget to re-position the elements. wlmtk_container_update_layout(&titlebar_ptr->super_box.super_container); return true; } +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_set_activated( + wlmtk_titlebar_t *titlebar_ptr, + bool activated) +{ + if (titlebar_ptr->activated == activated) return; + titlebar_ptr->activated = activated; + title_set_activated(titlebar_ptr->title_ptr, titlebar_ptr->activated); +} + /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_titlebar_element(wlmtk_titlebar_t *titlebar_ptr) { @@ -253,23 +279,6 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) /* == Title buffer methods ================================================= */ -static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); -static void title_set_activated( - wlmtk_titlebar_title_t *title_ptr, - bool activated); -static bool title_redraw_buffers( - wlmtk_titlebar_title_t *title_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - unsigned position, - unsigned width, - const wlmtk_titlebar_style_t *style_ptr); - -/** Buffer implementation for title of the title bar. */ -static const wlmtk_buffer_impl_t title_buffer_impl = { - .destroy = title_buffer_destroy -}; - /* ------------------------------------------------------------------------- */ /** * Creates a title bar title. diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 4fb22d0b..dfdfdd9d 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -73,7 +73,19 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr); * * @return Whether the operation was successful. */ -bool wlmtk_titlebar_set_width(wlmtk_titlebar_t *titlebar_ptr, unsigned width); +bool wlmtk_titlebar_set_width( + wlmtk_titlebar_t *titlebar_ptr, + unsigned width); + +/** + * Sets whether the title bar is activated. + * + * @param titlebar_ptr + * @param activated + */ +void wlmtk_titlebar_set_activated( + wlmtk_titlebar_t *titlebar_ptr, + bool activated); /** * Returns the super Element of the titlebar. diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 5827709f..a5ab0cc0 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -139,6 +139,9 @@ void wlmtk_window_set_activated( bool activated) { wlmtk_content_set_activated(window_ptr->content_ptr, activated); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); + } } /* ------------------------------------------------------------------------- */ From 77c379d0e1ee3afcf8ee5769cb4c5f903d6e3966 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 27 Oct 2023 21:44:12 +0200 Subject: [PATCH 151/390] Adds a handler for the surface commit. --- src/wlmtk_xdg_toplevel.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index b90739b7..43d29a40 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -39,6 +39,8 @@ typedef struct { struct wl_listener surface_map_listener; /** Listener for the `unmap` signal of the `wlr_surface`. */ struct wl_listener surface_unmap_listener; + /** Listener for the `commit` signal of the `wlr_surface`. */ + struct wl_listener surface_commit_listener; /** Listener for `request_move` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_move_listener; @@ -59,6 +61,9 @@ static void handle_surface_map( static void handle_surface_unmap( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_surface_commit( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_toplevel_request_move( struct wl_listener *listener_ptr, void *data_ptr); @@ -143,6 +148,10 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &wlr_xdg_surface_ptr->surface->events.unmap, &xdg_tl_content_ptr->surface_unmap_listener, handle_surface_unmap); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->surface->events.commit, + &xdg_tl_content_ptr->surface_commit_listener, + handle_surface_commit); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_move, @@ -170,6 +179,7 @@ void xdg_toplevel_content_destroy( wl_list_remove(&xdg_tl_content_ptr->toplevel_request_resize_listener.link); wl_list_remove(&xdg_tl_content_ptr->toplevel_request_move_listener.link); + wl_list_remove(&xdg_tl_content_ptr->surface_commit_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); @@ -349,6 +359,23 @@ void handle_surface_unmap( window_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `commit` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_surface_commit( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, surface_commit_listener); + + bs_log(BS_INFO, "Commit %p", xdg_tl_content_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `request_move` signal. From a3392fab88753ec5b50d8824527bfcdaa45f8c56 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 29 Oct 2023 20:53:49 +0100 Subject: [PATCH 152/390] Adds testdata, needed for earlier commit... --- testdata/toolkit/title_blurred_short.png | Bin 0 -> 544 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 testdata/toolkit/title_blurred_short.png diff --git a/testdata/toolkit/title_blurred_short.png b/testdata/toolkit/title_blurred_short.png new file mode 100644 index 0000000000000000000000000000000000000000..24017c225591bed72a0331013804d19a63447f80 GIT binary patch literal 544 zcmV+*0^j|KP)pA_9}JZ8*~xfWL-p; zArS*oA*oQBj^|=P&e_I3?OpELn|@cr8kqHcxcr8BGYkWM5re^i1Au)a`bQ#bUNj2pNq=yF;P063ja0FWdJ0H~@eNs{Zj)Y6l1!O~)}pbK5s8;yqNd9&Fp z-JMJ(bfGAUAP4{;%kuGfd>&U9EPYHmUAnF#gaDvYsRTjr&Jxe_&1O@UWtL@K*Ilhv zzVF{j^MCkyJWQw4!{Gn`%jMFttbYz=m`;!N>LO6K&@6gpU?aKKCRofU9ZdM%0~LWrh$N*u?gX|`G|Ns<_baU938tZ%!x-VDQdy_cSym!+Qo iHyjQz#*db9PyPT8!Nxo*QD~ Date: Sun, 29 Oct 2023 21:06:34 +0100 Subject: [PATCH 153/390] Changes wlmtk_content::set_size to wlmtk_content::request_size. --- src/toolkit/content.c | 10 +++++----- src/toolkit/content.h | 8 ++++---- src/toolkit/window.c | 2 +- src/toolkit/workspace.c | 2 +- src/wlmtk_xdg_toplevel.c | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 750648f1..15bd71e4 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -84,7 +84,7 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); BS_ASSERT(NULL != content_impl_ptr->get_size); - BS_ASSERT(NULL != content_impl_ptr->set_size); + BS_ASSERT(NULL != content_impl_ptr->request_size); BS_ASSERT(NULL != content_impl_ptr->set_activated); if (!wlmtk_element_init(&content_ptr->super_element, @@ -357,7 +357,7 @@ static void fake_content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); -static void fake_content_set_size( +static void fake_content_request_size( wlmtk_content_t *content_ptr, int width, int height); @@ -370,7 +370,7 @@ static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, .create_scene_node = fake_content_create_scene_node, .get_size = fake_content_get_size, - .set_size = fake_content_set_size, + .request_size = fake_content_request_size, .set_activated = fake_content_set_activated, }; @@ -433,7 +433,7 @@ void fake_content_get_size( /* ------------------------------------------------------------------------- */ /** Sets the size of the fake content. */ -void fake_content_set_size( +void fake_content_request_size( wlmtk_content_t *content_ptr, int width, int height) { @@ -481,7 +481,7 @@ void test_init_fini(bs_test_t *test_ptr) fake_content_ptr->content.impl.destroy); int l, t, r, b; - wlmtk_content_set_size(&fake_content_ptr->content, 42, 21); + wlmtk_content_request_size(&fake_content_ptr->content, 42, 21); wlmtk_element_get_dimensions( &fake_content_ptr->content.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, 0, l); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 5b66f727..773cb108 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -44,7 +44,7 @@ struct _wlmtk_content_impl_t { void (*get_size)(wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); /** Sets width and height of the content. */ - void (*set_size)(wlmtk_content_t *content_ptr, + void (*request_size)(wlmtk_content_t *content_ptr, int width, int height); /** Sets whether the content is activated (has keyboard focus). */ void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); @@ -131,11 +131,11 @@ static inline void wlmtk_content_get_size( int *width_ptr, int *height_ptr) { content_ptr->impl.get_size(content_ptr, width_ptr, height_ptr); } -/** Wraps to @ref wlmtk_content_impl_t::set_size. */ -static inline void wlmtk_content_set_size( +/** Wraps to @ref wlmtk_content_impl_t::request_size. */ +static inline void wlmtk_content_request_size( wlmtk_content_t *content_ptr, int width, int height) { - content_ptr->impl.set_size(content_ptr, width, height); + content_ptr->impl.request_size(content_ptr, width, height); } /** Wraps to @ref wlmtk_content_impl_t::set_activated. */ static inline void wlmtk_content_set_activated( diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a5ab0cc0..ad14eb97 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -171,7 +171,7 @@ void wlmtk_window_set_size( int height) { // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_content_set_size(window_ptr->content_ptr, width, height); + wlmtk_content_request_size(window_ptr->content_ptr, width, height); if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index a3477df9..6f08b8c7 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -694,7 +694,7 @@ void test_resize(bs_test_t *test_ptr) fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_content_set_size(&fake_content_ptr->content, 40, 20); + wlmtk_content_request_size(&fake_content_ptr->content, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 43d29a40..af30167c 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -79,7 +79,7 @@ static void content_get_size( wlmtk_content_t *content_ptr, int *width_ptr, int *height_ptr); -static void content_set_size( +static void content_request_size( wlmtk_content_t *content_ptr, int width, int height); @@ -94,7 +94,7 @@ const wlmtk_content_impl_t content_impl = { .destroy = content_destroy, .create_scene_node = content_create_scene_node, .get_size = content_get_size, - .set_size = content_set_size, + .request_size = content_request_size, .set_activated = content_set_activated, }; @@ -256,7 +256,7 @@ void content_get_size( * @param width Width of content. * @param height Height of content. */ -void content_set_size( +void content_request_size( wlmtk_content_t *content_ptr, int width, int height) @@ -265,7 +265,7 @@ void content_set_size( content_ptr, wlmtk_xdg_toplevel_content_t, super_content); // FIXME: Catch serial. - wlr_xdg_toplevel_set_size( + wlr_xdg_toplevel_request_size( xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, width, height); } From cf234695bb7fe36c480ddda6d957273875734b69 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 30 Oct 2023 22:08:05 +0100 Subject: [PATCH 154/390] Updates the flow for changing a window size to support asynchronous sizing for surfaces. --- src/toolkit/box.c | 5 +++ src/toolkit/box.h | 11 +++++++ src/toolkit/container.h | 12 ++++++- src/toolkit/content.c | 70 +++++++++++++++++++++++++++------------- src/toolkit/content.h | 52 +++++++++++++++++++++-------- src/toolkit/window.c | 35 ++++++++++++++++---- src/toolkit/workspace.c | 5 ++- src/wlmtk_xdg_toplevel.c | 39 ++++------------------ 8 files changed, 154 insertions(+), 75 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 83bc192e..dfc9d225 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -114,6 +114,11 @@ void container_update_layout(wlmtk_container_t *container_ptr) wlmtk_element_set_position(element_ptr, x, y); } + // Forward to virtual methods, if any. + if (NULL != box_ptr->impl.update_layout) { + box_ptr->impl.update_layout(box_ptr); + } + // configure parent container. wlmtk_container_update_layout( container_ptr->super_element.parent_container_ptr); diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 4d9ce40b..62935be1 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -35,6 +35,17 @@ extern "C" { struct _wlmtk_box_impl_t { /** dtor. */ void (*destroy)(wlmtk_box_t *box_ptr); + /** + * Updates the layout of the elements. + * + * The box's @ref container_update_layout method will invoke this optional + * method when a contained element changes visibility, dimensions or was + * added or removed. + * A derived class (eg. a window) can use this eg. to recompute dimensions + * of window decorations, when eg. a call to @ref wlmtk_content_commit_size + * had committed an update to the window content's dimensions. + */ + void (*update_layout)(wlmtk_box_t *box_ptr); }; /** Orientation of the box. */ diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 201dff87..45d1adde 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -38,7 +38,17 @@ extern "C" { struct _wlmtk_container_impl_t { /** dtor. */ void (*destroy)(wlmtk_container_t *container_ptr); - /** Updates the layout of the container elements. */ + /** + * Updates the layout of the container elements. + * + * Will be called by this, when an element is added or removed. + * Additionally, this should be invoked by contained elements when + * the visibility or dimensions change. + * + * Each container will propagate a wlmtk_container_impl::update_layout call + * upwards to it's parent container. The root container will then trigger + * an update to pointer focus (since by then, the layout is updated). + */ void (*update_layout)(wlmtk_container_t *container_ptr); }; diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 15bd71e4..a1468175 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -21,6 +21,8 @@ #include "content.h" +#include "container.h" + #define WLR_USE_UNSTABLE #include #include @@ -83,7 +85,6 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr); BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); - BS_ASSERT(NULL != content_impl_ptr->get_size); BS_ASSERT(NULL != content_impl_ptr->request_size); BS_ASSERT(NULL != content_impl_ptr->set_activated); @@ -114,6 +115,33 @@ void wlmtk_content_set_window( content_ptr->window_ptr = window_ptr; } +/* ------------------------------------------------------------------------- */ +void wlmtk_content_commit_size( + wlmtk_content_t *content_ptr, + unsigned width, + unsigned height) +{ + if (content_ptr->committed_width == width && + content_ptr->committed_height == height) return; + + content_ptr->committed_width = width; + content_ptr->committed_height = height; + if (NULL != content_ptr->super_element.parent_container_ptr) { + wlmtk_container_update_layout( + content_ptr->super_element.parent_container_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr) +{ + if (NULL != width_ptr) *width_ptr = content_ptr->committed_width; + if (NULL != height_ptr) *height_ptr = content_ptr->committed_height; +} + /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr) { @@ -178,7 +206,9 @@ void element_get_dimensions( wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); - wlmtk_content_get_size(content_ptr, right_ptr, bottom_ptr); + + if (NULL != right_ptr) *right_ptr = content_ptr->committed_width; + if (NULL != bottom_ptr) *bottom_ptr = content_ptr->committed_height; } /* ------------------------------------------------------------------------- */ @@ -353,10 +383,6 @@ static void fake_content_destroy( static struct wlr_scene_node *fake_content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void fake_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, - int *height_ptr); static void fake_content_request_size( wlmtk_content_t *content_ptr, int width, @@ -369,7 +395,6 @@ static void fake_content_set_activated( static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, .create_scene_node = fake_content_create_scene_node, - .get_size = fake_content_get_size, .request_size = fake_content_request_size, .set_activated = fake_content_set_activated, }; @@ -419,28 +444,17 @@ struct wlr_scene_node *fake_content_create_scene_node( return &wlr_scene_buffer_ptr->node; } -/* ------------------------------------------------------------------------- */ -/** Gets the size of the fake content. */ -void fake_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, int *height_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_fake_content_t, content); - if (NULL != width_ptr) *width_ptr = fake_content_ptr->width; - if (NULL != height_ptr) *height_ptr = fake_content_ptr->height; -} - /* ------------------------------------------------------------------------- */ /** Sets the size of the fake content. */ void fake_content_request_size( wlmtk_content_t *content_ptr, - int width, int height) + int width, + int height) { wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( content_ptr, wlmtk_fake_content_t, content); - fake_content_ptr->width = width; - fake_content_ptr->height = height; + fake_content_ptr->requested_width = width; + fake_content_ptr->requested_height = height; } /* ------------------------------------------------------------------------- */ @@ -482,6 +496,18 @@ void test_init_fini(bs_test_t *test_ptr) int l, t, r, b; wlmtk_content_request_size(&fake_content_ptr->content, 42, 21); + wlmtk_element_get_dimensions( + &fake_content_ptr->content.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, 0, l); + BS_TEST_VERIFY_EQ(test_ptr, 0, t); + BS_TEST_VERIFY_EQ(test_ptr, 0, r); + BS_TEST_VERIFY_EQ(test_ptr, 0, b); + + wlmtk_content_commit_size(&fake_content_ptr->content, 42, 21); + wlmtk_content_get_size(&fake_content_ptr->content, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, 42, r); + BS_TEST_VERIFY_EQ(test_ptr, 21, b); + wlmtk_element_get_dimensions( &fake_content_ptr->content.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, 0, l); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 773cb108..71ec9aa8 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -40,9 +40,6 @@ struct _wlmtk_content_impl_t { struct wlr_scene_node *(*create_scene_node)( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); - /** Gets width and height of the content. */ - void (*get_size)(wlmtk_content_t *content_ptr, - int *width_ptr, int *height_ptr); /** Sets width and height of the content. */ void (*request_size)(wlmtk_content_t *content_ptr, int width, int height); @@ -76,6 +73,11 @@ struct _wlmtk_content_t { * elements (eg. buffer), this should be abstracted away. */ struct wlr_surface *wlr_surface_ptr; + + /** Committed width of the content. See @ref wlmtk_content_commit_size. */ + unsigned committed_width; + /** Committed height of the content. See @ref wlmtk_content_commit_size. */ + unsigned committed_height; }; /** @@ -111,6 +113,36 @@ void wlmtk_content_set_window( wlmtk_content_t *content_ptr, wlmtk_window_t *window_ptr); +/** + * Sets the committed size of the content. + * + * Size operations on Wayland content are (often) asynchronous. The server + * should call @ref wlmtk_content_request_size, which (as a virtual method) + * forwards the request to the content (eg. the Wayland client surface). The + * client then configures it's surface and commits it. The content needs to + * catch that commit and call @ref wlmtk_content_commit_size accordingly. + * This will then update the parent container's (and window's) layout. + * + * @param content_ptr + * @param width + * @param height + */ +void wlmtk_content_commit_size( + wlmtk_content_t *content_ptr, + unsigned width, + unsigned height); + +/** + * Returns committed size of the content. + * + * @param content_ptr + * @param width_ptr + * @param height_ptr + */ +void wlmtk_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, int *height_ptr); + /** * Returns the super Element of the content. * @@ -125,12 +157,6 @@ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { content_ptr->impl.destroy(content_ptr); } -/** Wraps to @ref wlmtk_content_impl_t::get_size. */ -static inline void wlmtk_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, int *height_ptr) { - content_ptr->impl.get_size(content_ptr, width_ptr, height_ptr); -} /** Wraps to @ref wlmtk_content_impl_t::request_size. */ static inline void wlmtk_content_request_size( wlmtk_content_t *content_ptr, @@ -158,10 +184,10 @@ extern const bs_test_case_t wlmtk_content_test_cases[]; typedef struct { /** State of the content. */ wlmtk_content_t content; - /** Width to return on a wlmtk_content_impl_t::get_size call. */ - int width; - /** Height to return on a wlmtk_content_impl_t::get_size call. */ - int height; + /** `width` argument eof last @ref wlmtk_content_request_size call. */ + int requested_width; + /** `height` argument of last @ref wlmtk_content_request_size call. */ + int requested_height; /** Argument of last @ref wlmtk_content_set_activated call. */ bool activated; } wlmtk_fake_content_t; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index ad14eb97..c1f262f1 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -37,13 +37,15 @@ struct _wlmtk_window_t { wlmtk_titlebar_t *titlebar_ptr; }; +static void box_update_layout(wlmtk_box_t *box_ptr); static void window_box_destroy(wlmtk_box_t *box_ptr); /* == Data ================================================================= */ /** Method table for the box's virtual methods. */ static const wlmtk_box_impl_t window_box_impl = { - .destroy = window_box_destroy + .destroy = window_box_destroy, + .update_layout = box_update_layout, }; /** Style of the title bar. */ @@ -86,7 +88,8 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) int width; wlmtk_content_get_size(content_ptr, &width, NULL); - window_ptr->titlebar_ptr = wlmtk_titlebar_create(width, &titlebar_style); + window_ptr->titlebar_ptr = wlmtk_titlebar_create( + width, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_destroy(window_ptr); return NULL; @@ -173,10 +176,6 @@ void wlmtk_window_set_size( // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. wlmtk_content_request_size(window_ptr->content_ptr, width, height); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); - } - // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting // the size is an asynchronous operation and should be handled as such. // Meaning: In example of resizing at the top-left corner, we'll want to @@ -209,6 +208,30 @@ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) /* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** + * Implementation of @ref wlmtk_box_impl_t::update_layout. + * + * Invoked when the window's contained elements triggered a layout update, + * and will use this to trigger (potential) size updates to the window + * decorations. + * + * @param box_ptr + */ +void box_update_layout(wlmtk_box_t *box_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + box_ptr, wlmtk_window_t, super_box); + + if (NULL != window_ptr->content_ptr) { + int width; + wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); + } + } +} + /* ------------------------------------------------------------------------- */ /** Virtual destructor, in case called from box. Wraps to our dtor. */ void window_box_destroy(wlmtk_box_t *box_ptr) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 6f08b8c7..a187c77b 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -694,7 +694,7 @@ void test_resize(bs_test_t *test_ptr) fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_content_request_size(&fake_content_ptr->content, 40, 20); + wlmtk_content_commit_size(&fake_content_ptr->content, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); @@ -714,6 +714,9 @@ void test_resize(bs_test_t *test_ptr) wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 39, fake_content_ptr->requested_width); + BS_TEST_VERIFY_EQ(test_ptr, 18, fake_content_ptr->requested_height); + wlmtk_content_commit_size(&fake_content_ptr->content, 39, 18); wlmtk_window_get_size(window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 39, width); BS_TEST_VERIFY_EQ(test_ptr, 18, height); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index af30167c..a14e61a9 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -75,10 +75,6 @@ static void content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, - int *height_ptr); static void content_request_size( wlmtk_content_t *content_ptr, int width, @@ -93,7 +89,6 @@ static void content_set_activated( const wlmtk_content_impl_t content_impl = { .destroy = content_destroy, .create_scene_node = content_create_scene_node, - .get_size = content_get_size, .request_size = content_request_size, .set_activated = content_set_activated, }; @@ -223,31 +218,6 @@ struct wlr_scene_node *content_create_scene_node( return &surface_wlr_scene_tree_ptr->node; } -/* ------------------------------------------------------------------------- */ -/** - * Gets the dimensions of the element in pixels. - * - * @param content_ptr - * @param width_ptr Width of content. May be NULL. - * @param height_ptr Height of content. May be NULL. - */ -void content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, - int *height_ptr) -{ - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); - - // FIXME -> this should be get_pointer_area ! - struct wlr_box geo_box; - wlr_xdg_surface_get_geometry( - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->base, &geo_box); - // FIXME -- WARNING: THIS HAS A x AND y WITH RELATIVE POSITION!! - if (NULL != width_ptr) *width_ptr = geo_box.width; - if (NULL != height_ptr) *height_ptr = geo_box.height; -} - /* ------------------------------------------------------------------------- */ /** * Sets the dimensions of the element in pixels. @@ -265,7 +235,7 @@ void content_request_size( content_ptr, wlmtk_xdg_toplevel_content_t, super_content); // FIXME: Catch serial. - wlr_xdg_toplevel_request_size( + wlr_xdg_toplevel_set_size( xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, width, height); } @@ -373,7 +343,12 @@ void handle_surface_commit( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_content_t, surface_commit_listener); - bs_log(BS_INFO, "Commit %p", xdg_tl_content_ptr); + if (NULL == xdg_tl_content_ptr->wlr_xdg_surface_ptr) return; + + wlmtk_content_commit_size( + &xdg_tl_content_ptr->super_content, + xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.width, + xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.height); } /* ------------------------------------------------------------------------- */ From d2268ed469c38fb057f9a5db95c06add2da097d9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 3 Nov 2023 21:11:55 +0100 Subject: [PATCH 155/390] Passes the serial from wlroots up to content, via request and commit size. --- src/toolkit/content.c | 16 ++++++++++++---- src/toolkit/content.h | 17 +++++++++++------ src/toolkit/workspace.c | 4 ++-- src/wlmtk_xdg_toplevel.c | 12 +++++++----- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index a1468175..7900d3cf 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -118,9 +118,12 @@ void wlmtk_content_set_window( /* ------------------------------------------------------------------------- */ void wlmtk_content_commit_size( wlmtk_content_t *content_ptr, + uint32_t serial, unsigned width, unsigned height) { + serial = serial; + if (content_ptr->committed_width == width && content_ptr->committed_height == height) return; @@ -383,7 +386,7 @@ static void fake_content_destroy( static struct wlr_scene_node *fake_content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void fake_content_request_size( +static uint32_t fake_content_request_size( wlmtk_content_t *content_ptr, int width, int height); @@ -446,7 +449,7 @@ struct wlr_scene_node *fake_content_create_scene_node( /* ------------------------------------------------------------------------- */ /** Sets the size of the fake content. */ -void fake_content_request_size( +uint32_t fake_content_request_size( wlmtk_content_t *content_ptr, int width, int height) @@ -455,6 +458,7 @@ void fake_content_request_size( content_ptr, wlmtk_fake_content_t, content); fake_content_ptr->requested_width = width; fake_content_ptr->requested_height = height; + return fake_content_ptr->return_request_size; } /* ------------------------------------------------------------------------- */ @@ -495,7 +499,11 @@ void test_init_fini(bs_test_t *test_ptr) fake_content_ptr->content.impl.destroy); int l, t, r, b; - wlmtk_content_request_size(&fake_content_ptr->content, 42, 21); + fake_content_ptr->return_request_size = 42; + BS_TEST_VERIFY_EQ( + test_ptr, + 42, + wlmtk_content_request_size(&fake_content_ptr->content, 42, 21)); wlmtk_element_get_dimensions( &fake_content_ptr->content.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, 0, l); @@ -503,7 +511,7 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, r); BS_TEST_VERIFY_EQ(test_ptr, 0, b); - wlmtk_content_commit_size(&fake_content_ptr->content, 42, 21); + wlmtk_content_commit_size(&fake_content_ptr->content, 1, 42, 21); wlmtk_content_get_size(&fake_content_ptr->content, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, 42, r); BS_TEST_VERIFY_EQ(test_ptr, 21, b); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 71ec9aa8..58ec4adf 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -40,9 +40,9 @@ struct _wlmtk_content_impl_t { struct wlr_scene_node *(*create_scene_node)( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); - /** Sets width and height of the content. */ - void (*request_size)(wlmtk_content_t *content_ptr, - int width, int height); + /** Sets width and height of the content. Returns serial. */ + uint32_t (*request_size)(wlmtk_content_t *content_ptr, + int width, int height); /** Sets whether the content is activated (has keyboard focus). */ void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); }; @@ -124,11 +124,13 @@ void wlmtk_content_set_window( * This will then update the parent container's (and window's) layout. * * @param content_ptr + * @param serial * @param width * @param height */ void wlmtk_content_commit_size( wlmtk_content_t *content_ptr, + uint32_t serial, unsigned width, unsigned height); @@ -158,10 +160,11 @@ static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { content_ptr->impl.destroy(content_ptr); } /** Wraps to @ref wlmtk_content_impl_t::request_size. */ -static inline void wlmtk_content_request_size( +static inline uint32_t wlmtk_content_request_size( wlmtk_content_t *content_ptr, - int width, int height) { - content_ptr->impl.request_size(content_ptr, width, height); + int width, + int height) { + return content_ptr->impl.request_size(content_ptr, width, height); } /** Wraps to @ref wlmtk_content_impl_t::set_activated. */ static inline void wlmtk_content_set_activated( @@ -188,6 +191,8 @@ typedef struct { int requested_width; /** `height` argument of last @ref wlmtk_content_request_size call. */ int requested_height; + /** Return value of @ref wlmtk_content_request_size call. */ + uint32_t return_request_size; /** Argument of last @ref wlmtk_content_set_activated call. */ bool activated; } wlmtk_fake_content_t; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index a187c77b..e3b0901b 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -694,7 +694,7 @@ void test_resize(bs_test_t *test_ptr) fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_content_commit_size(&fake_content_ptr->content, 40, 20); + wlmtk_content_commit_size(&fake_content_ptr->content, 1, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); @@ -716,7 +716,7 @@ void test_resize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 39, fake_content_ptr->requested_width); BS_TEST_VERIFY_EQ(test_ptr, 18, fake_content_ptr->requested_height); - wlmtk_content_commit_size(&fake_content_ptr->content, 39, 18); + wlmtk_content_commit_size(&fake_content_ptr->content, 1, 39, 18); wlmtk_window_get_size(window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 39, width); BS_TEST_VERIFY_EQ(test_ptr, 18, height); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index a14e61a9..25d91642 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -75,7 +75,7 @@ static void content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void content_request_size( +static uint32_t content_request_size( wlmtk_content_t *content_ptr, int width, int height); @@ -225,8 +225,10 @@ struct wlr_scene_node *content_create_scene_node( * @param content_ptr * @param width Width of content. * @param height Height of content. + * + * @return The serial. */ -void content_request_size( +uint32_t content_request_size( wlmtk_content_t *content_ptr, int width, int height) @@ -234,8 +236,7 @@ void content_request_size( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( content_ptr, wlmtk_xdg_toplevel_content_t, super_content); - // FIXME: Catch serial. - wlr_xdg_toplevel_set_size( + return wlr_xdg_toplevel_set_size( xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, width, height); } @@ -334,7 +335,7 @@ void handle_surface_unmap( * Handler for the `commit` signal. * * @param listener_ptr - * @param data_ptr + * @param data_ptr Points to the const struct wlr_surface. */ void handle_surface_commit( struct wl_listener *listener_ptr, @@ -347,6 +348,7 @@ void handle_surface_commit( wlmtk_content_commit_size( &xdg_tl_content_ptr->super_content, + xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.configure_serial, xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.width, xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.height); } From 6c2221d75440e5bf273901d1c3a9324b896219b4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 4 Nov 2023 14:29:15 +0100 Subject: [PATCH 156/390] s/wlmtk_window_set_size/wlmtk_window_request_size/ --- src/toolkit/window.c | 4 ++-- src/toolkit/window.h | 6 ++++-- src/toolkit/workspace.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index c1f262f1..0cc133c0 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -168,7 +168,7 @@ void wlmtk_window_get_size( } /* ------------------------------------------------------------------------- */ -void wlmtk_window_set_size( +void wlmtk_window_request_size( wlmtk_window_t *window_ptr, int width, int height) @@ -181,7 +181,7 @@ void wlmtk_window_set_size( // Meaning: In example of resizing at the top-left corner, we'll want to // request the content to adjust size, but wait with adjusting the // content position until the size adjustment is applied. This implies we - // may need to combine the set_size and set_position methods for window. + // may need to combine the request_size and set_position methods for window. } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index b913aa1c..f87d4020 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -96,13 +96,15 @@ void wlmtk_window_get_size( int *height_ptr); /** - * Sets the size of the window, including potential decorations. + * Requesta a new size for the window, including potential decorations. + * + * This may be implemented as an asynchronous operation.x * * @param window_ptr * @param width * @param height */ -void wlmtk_window_set_size( +void wlmtk_window_request_size( wlmtk_window_t *window_ptr, int width, int height); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index e3b0901b..c8a96c78 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -436,7 +436,7 @@ bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) wlmtk_element_set_position( wlmtk_window_element(workspace_ptr->grabbed_window_ptr), left, top); - wlmtk_window_set_size( + wlmtk_window_request_size( workspace_ptr->grabbed_window_ptr, right - left, bottom - top); return true; From a87b57e3d45cb8e7fa848d1d53de92921412d8a3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 4 Nov 2023 16:06:22 +0100 Subject: [PATCH 157/390] Updates to current wlroots version. --- src/button.c | 8 ++++---- src/cursor.c | 13 +++++++------ src/menu.c | 6 +++--- src/output.c | 2 +- src/resizebar.c | 8 ++++---- src/server.c | 18 ++++++++++++++---- src/server.h | 2 ++ src/titlebar.c | 20 ++++++++++---------- src/xdg_decoration.c | 7 ++++--- 9 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/button.c b/src/button.c index a9d33153..b83f3175 100644 --- a/src/button.c +++ b/src/button.c @@ -25,7 +25,7 @@ #define WLR_USE_UNSTABLE #include -#include +#include #undef WLR_USE_UNSTABLE /* == Definitions ========================================================== */ @@ -215,10 +215,10 @@ void _button_enter(wlmaker_interactive_t *interactive_ptr) wlmaker_button_t *button_ptr = button_from_interactive(interactive_ptr); if (button_ptr->activated) button_press(button_ptr, true); - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + interactive_ptr->cursor_ptr->wlr_cursor_ptr, interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - "left_ptr", - interactive_ptr->cursor_ptr->wlr_cursor_ptr); + "left_ptr"); } /* ------------------------------------------------------------------------- */ diff --git a/src/cursor.c b/src/cursor.c index 2de99830..ae50e0e3 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -28,6 +28,7 @@ #define WLR_USE_UNSTABLE #include #include +#include #include #undef WLR_USE_UNSTABLE @@ -488,10 +489,10 @@ void process_motion(wlmaker_cursor_t *cursor_ptr, uint32_t time_msec) time_msec); if (!rv) { // FIXME - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + cursor_ptr->wlr_cursor_ptr, cursor_ptr->wlr_xcursor_manager_ptr, - "left_ptr", - cursor_ptr->wlr_cursor_ptr); + "left_ptr"); } if (true) return; @@ -553,10 +554,10 @@ void process_motion(wlmaker_cursor_t *cursor_ptr, uint32_t time_msec) &rel_y); update_under_cursor_view(cursor_ptr, view_ptr); if (NULL == view_ptr) { - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + cursor_ptr->wlr_cursor_ptr, cursor_ptr->wlr_xcursor_manager_ptr, - "left_ptr", - cursor_ptr->wlr_cursor_ptr); + "left_ptr"); } else { wlmaker_view_handle_motion( view_ptr, diff --git a/src/menu.c b/src/menu.c index abe8161f..e7a1dd35 100644 --- a/src/menu.c +++ b/src/menu.c @@ -181,10 +181,10 @@ wlmaker_menu_t *menu_from_interactive( void _menu_enter( wlmaker_interactive_t *interactive_ptr) { - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + interactive_ptr->cursor_ptr->wlr_cursor_ptr, interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - "left_ptr", - interactive_ptr->cursor_ptr->wlr_cursor_ptr); + "left_ptr"); } /* ------------------------------------------------------------------------- */ diff --git a/src/output.c b/src/output.c index d482d351..07c0832a 100644 --- a/src/output.c +++ b/src/output.c @@ -140,7 +140,7 @@ void handle_output_frame(struct wl_listener *listener_ptr, struct wlr_scene_output *wlr_scene_output_ptr = wlr_scene_get_scene_output( output_ptr->wlr_scene_ptr, output_ptr->wlr_output_ptr); - wlr_scene_output_commit(wlr_scene_output_ptr); + wlr_scene_output_commit(wlr_scene_output_ptr, NULL); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); diff --git a/src/resizebar.c b/src/resizebar.c index 845ab543..1fc71a06 100644 --- a/src/resizebar.c +++ b/src/resizebar.c @@ -24,7 +24,7 @@ #include #define WLR_USE_UNSTABLE -#include +#include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -171,10 +171,10 @@ void _resizebar_enter( xcursor_name_ptr = "sw-resize"; } - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + interactive_ptr->cursor_ptr->wlr_cursor_ptr, interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - xcursor_name_ptr, - interactive_ptr->cursor_ptr->wlr_cursor_ptr); + xcursor_name_ptr); } /* ------------------------------------------------------------------------- */ diff --git a/src/server.c b/src/server.c index 03b2e5a4..c390ab38 100644 --- a/src/server.c +++ b/src/server.c @@ -193,8 +193,10 @@ wlmaker_server_t *wlmaker_server_create(void) wlmaker_server_destroy(server_ptr); return NULL; } - if (!wlr_scene_attach_output_layout(server_ptr->wlr_scene_ptr, - server_ptr->wlr_output_layout_ptr)) { + server_ptr->wlr_scene_output_layout_ptr = wlr_scene_attach_output_layout( + server_ptr->wlr_scene_ptr, + server_ptr->wlr_output_layout_ptr); + if (NULL == server_ptr->wlr_scene_output_layout_ptr) { bs_log(BS_ERROR, "Failed wlr_scene_attach_output_layout()"); wlmaker_server_destroy(server_ptr); return NULL; @@ -402,8 +404,16 @@ void wlmaker_server_output_add(wlmaker_server_t *server_ptr, // outputs from left-to-right in the order they appear. A sophisticated // compositor would let the user configure the arrangement of outputs in // the layout. - wlr_output_layout_add_auto(server_ptr->wlr_output_layout_ptr, - output_ptr->wlr_output_ptr); + struct wlr_output_layout_output *wlr_output_layout_output_ptr = + wlr_output_layout_add_auto(server_ptr->wlr_output_layout_ptr, + output_ptr->wlr_output_ptr); + struct wlr_scene_output *wlr_scene_output_ptr = + wlr_scene_output_create(server_ptr->wlr_scene_ptr, + output_ptr->wlr_output_ptr); + wlr_scene_output_layout_add_output( + server_ptr->wlr_scene_output_layout_ptr, + wlr_output_layout_output_ptr, + wlr_scene_output_ptr); bs_dllist_push_back(&server_ptr->outputs, &output_ptr->node); } diff --git a/src/server.h b/src/server.h index a1b14081..0b7f7b92 100644 --- a/src/server.h +++ b/src/server.h @@ -72,6 +72,8 @@ struct _wlmaker_server_t { struct wlr_seat *wlr_seat_ptr; /** The scene graph API. */ struct wlr_scene *wlr_scene_ptr; + /** The scene output layout. */ + struct wlr_scene_output_layout *wlr_scene_output_layout_ptr; /** * Another scene graph, not connected to any output. * diff --git a/src/titlebar.c b/src/titlebar.c index 41c63ca3..b1f55a0c 100644 --- a/src/titlebar.c +++ b/src/titlebar.c @@ -26,7 +26,7 @@ #define WLR_USE_UNSTABLE #include -#include +#include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -187,10 +187,10 @@ void _titlebar_enter(wlmaker_interactive_t *interactive_ptr) cursor_name_ptr = xcursor_name_move; } - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + interactive_ptr->cursor_ptr->wlr_cursor_ptr, interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - cursor_name_ptr, - interactive_ptr->cursor_ptr->wlr_cursor_ptr); + cursor_name_ptr); } /* ------------------------------------------------------------------------- */ @@ -227,10 +227,10 @@ void _titlebar_motion( titlebar_ptr->interactive.cursor_ptr, titlebar_ptr->view_ptr); - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + interactive_ptr->cursor_ptr->wlr_cursor_ptr, interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - xcursor_name_move, - interactive_ptr->cursor_ptr->wlr_cursor_ptr); + xcursor_name_move); } } @@ -304,10 +304,10 @@ void _titlebar_button( titlebar_ptr->state = TITLEBAR_IDLE; // Reset cursor to default, if it is within our bounds. if (wlmaker_interactive_contains(&titlebar_ptr->interactive, x, y)) { - wlr_xcursor_manager_set_cursor_image( + wlr_cursor_set_xcursor( + interactive_ptr->cursor_ptr->wlr_cursor_ptr, interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - xcursor_name_default, - interactive_ptr->cursor_ptr->wlr_cursor_ptr); + xcursor_name_default); } break; diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 78260740..d12e6eeb 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -217,11 +217,12 @@ void handle_decoration_request_mode( { wlmaker_xdg_decoration_t *decoration_ptr = wl_container_of( listener_ptr, decoration_ptr, request_mode_listener); + struct wlr_scene_tree *wlr_scene_tree_ptr = (struct wlr_scene_tree*) - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->surface->data; + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; wlmtk_content_t *content_ptr = (wlmtk_content_t*) - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->surface->data; + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; if (NULL != content_ptr && content_ptr->identifier_ptr == wlmtk_content_identifier_ptr) { bs_log(BS_WARNING, @@ -273,7 +274,7 @@ void handle_decoration_request_mode( bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, view %p: " "Current %d, pending %d, scheduled %d, requested %d. Set: %d", - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->surface, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, view_ptr, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, From a5add1900625e02b129900c7ff464bd145a32668 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 11:39:11 +0100 Subject: [PATCH 158/390] Adds initial implementation of asynchronous window resizes. --- src/toolkit/content.c | 15 +++++---- src/toolkit/window.c | 74 +++++++++++++++++++++++++++++++++++++++++ src/toolkit/window.h | 39 ++++++++++++++++++++-- src/toolkit/workspace.c | 14 ++++---- 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 7900d3cf..04603bef 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -122,16 +122,19 @@ void wlmtk_content_commit_size( unsigned width, unsigned height) { - serial = serial; + if (content_ptr->committed_width != width || + content_ptr->committed_height != height) { + content_ptr->committed_width = width; + content_ptr->committed_height = height; + } - if (content_ptr->committed_width == width && - content_ptr->committed_height == height) return; + if (NULL != content_ptr->window_ptr) { + wlmtk_window_serial(content_ptr->window_ptr, serial); + } - content_ptr->committed_width = width; - content_ptr->committed_height = height; if (NULL != content_ptr->super_element.parent_container_ptr) { wlmtk_container_update_layout( - content_ptr->super_element.parent_container_ptr); + content_ptr->super_element.parent_container_ptr); } } diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 0cc133c0..4f8890bb 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -35,8 +35,27 @@ struct _wlmtk_window_t { wlmtk_content_t *content_ptr; /** Titlebar. */ wlmtk_titlebar_t *titlebar_ptr; + + /** Pending states. */ + bs_dllist_t ps; }; +/** Pending positional updates. */ +typedef struct { + /** Node within wlmtk_window_t::ps. */ + bs_dllist_node_t dlnode; + /** Serial of the update. */ + uint32_t serial; + /** Pending X position. */ + int x; + /** Pending Y position. */ + int y; + /** Width that is to be committed at serial. */ + unsigned width; + /** Height that is to be committed at serial. */ + unsigned height; +} wlmtk_pending_t; + static void box_update_layout(wlmtk_box_t *box_ptr); static void window_box_destroy(wlmtk_box_t *box_ptr); @@ -184,6 +203,61 @@ void wlmtk_window_request_size( // may need to combine the request_size and set_position methods for window. } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height) +{ + uint32_t serial = wlmtk_content_request_size( + window_ptr->content_ptr, width, height); + + // TODO(kaeser@gubbe.ch): Use a pre-allocated array, and apply pending + // states when in risk of overflow. + wlmtk_pending_t *pending_ptr = logged_calloc(1, sizeof(wlmtk_pending_t)); + BS_ASSERT(NULL != pending_ptr); + pending_ptr->serial = serial; + pending_ptr->x = x; + pending_ptr->y = y; + pending_ptr->width = width; + pending_ptr->height = height; + bs_dllist_push_back(&window_ptr->ps, &pending_ptr->dlnode); + + // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial + // may have been called early, so we should check if serial had just been + // called before (or is below the last @wlmt_window_serial). In that case, + // the pending state should be applied right away. +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) +{ + while (!bs_dllist_empty(&window_ptr->ps)) { + bs_dllist_node_t *dlnode_ptr = window_ptr->ps.head_ptr; + wlmtk_pending_t *pending_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_t, dlnode); + + if (pending_ptr->serial > serial) { + break; + } + + BS_ASSERT(dlnode_ptr == bs_dllist_pop_front(&window_ptr->ps)); + if (pending_ptr->serial < serial) { + free(pending_ptr); + continue; + } + + BS_ASSERT(pending_ptr->serial == serial); + wlmtk_element_set_position( + wlmtk_window_element(window_ptr), + pending_ptr->x, + pending_ptr->y); + free(pending_ptr); + } +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { diff --git a/src/toolkit/window.h b/src/toolkit/window.h index f87d4020..6389e1b8 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -96,9 +96,9 @@ void wlmtk_window_get_size( int *height_ptr); /** - * Requesta a new size for the window, including potential decorations. + * Requests a new size for the window, including potential decorations. * - * This may be implemented as an asynchronous operation.x + * This may be implemented as an asynchronous operation. * * @param window_ptr * @param width @@ -109,6 +109,26 @@ void wlmtk_window_request_size( int width, int height); +/** + * Requests an updated position and size for the window, including potential + * decorations. + * + * This may be implemented as an asynchronous operation. The re-positioning + * will be applied only once the size change has been committed by the client. + * + * @param window_ptr + * @param x + * @param y + * @param width + * @param height + */ +void wlmtk_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); + /** * Requests a move for the window. * @@ -130,6 +150,21 @@ void wlmtk_window_request_move(wlmtk_window_t *window_ptr); */ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges); +/** + * Updates the window state to what was requested at the `serial`. + * + * Used for example when resizing a window from the top or left edges. In that + * case, @ref wlmtk_content_request_size may be asynchronous and returns a + * serial. The content is expected to call @ref wlmtk_window_serial with the + * returned serial when the size is committed. + * Only then, the corresponding positional update on the top/left edges are + * supposed to be applied. + * + * @param window_ptr + * @param serial + */ +void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index c8a96c78..706ebe66 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -433,11 +433,9 @@ bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) if (right <= left) right = left + 1; } - wlmtk_element_set_position( - wlmtk_window_element(workspace_ptr->grabbed_window_ptr), - left, top); - wlmtk_window_request_size( + wlmtk_window_request_position_and_size( workspace_ptr->grabbed_window_ptr, + left, top, right - left, bottom - top); return true; } @@ -711,13 +709,17 @@ void test_resize(bs_test_t *test_ptr) // Starts a resize for the window. Will resize & move it... wlmtk_workspace_begin_window_resize( workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); + fake_content_ptr->return_request_size = 1; // The serial. wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 39, fake_content_ptr->requested_width); BS_TEST_VERIFY_EQ(test_ptr, 18, fake_content_ptr->requested_height); + // This updates for the given serial. wlmtk_content_commit_size(&fake_content_ptr->content, 1, 39, 18); wlmtk_window_get_size(window_ptr, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 39, width); BS_TEST_VERIFY_EQ(test_ptr, 18, height); From 9cb0f840418481ab72313aa4d479a5a4e58d28ee Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 11:39:49 +0100 Subject: [PATCH 159/390] Updates for new commits in wlroots. --- dependencies/wlroots | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/wlroots b/dependencies/wlroots index fffa1908..47bf87ad 160000 --- a/dependencies/wlroots +++ b/dependencies/wlroots @@ -1 +1 @@ -Subproject commit fffa1908af47d7cb1691425a0b6d9dccb01f1365 +Subproject commit 47bf87ade2bd32395615a385ebde1fefbcdf79a2 From 58e094802c778485595274a36616dab6dcbcddcd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 11:42:12 +0100 Subject: [PATCH 160/390] Updates to new commits in other dependencies. --- dependencies/drm | 2 +- dependencies/hwdata | 2 +- dependencies/libdisplay-info | 2 +- dependencies/pixman | 2 +- dependencies/seatd | 2 +- dependencies/wayland | 2 +- dependencies/wayland-protocols | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dependencies/drm b/dependencies/drm index 98e1db50..5254fd11 160000 --- a/dependencies/drm +++ b/dependencies/drm @@ -1 +1 @@ -Subproject commit 98e1db501173303e58ef6a1def94ab7a2d84afc1 +Subproject commit 5254fd1146b95a86fef1bb8e950d0146d829f3c4 diff --git a/dependencies/hwdata b/dependencies/hwdata index 2726a2e3..b9ba5bc9 160000 --- a/dependencies/hwdata +++ b/dependencies/hwdata @@ -1 +1 @@ -Subproject commit 2726a2e35ebe11681da6091a99ed304c9f707c90 +Subproject commit b9ba5bc9eecbeeff441806695b227c3c3de4755c diff --git a/dependencies/libdisplay-info b/dependencies/libdisplay-info index 49af17a3..8829bab6 160000 --- a/dependencies/libdisplay-info +++ b/dependencies/libdisplay-info @@ -1 +1 @@ -Subproject commit 49af17a3e653b6e07a0f508da0c83c4ee3cd9077 +Subproject commit 8829bab67a1a9264bf8404b76f9f7813cfb9c174 diff --git a/dependencies/pixman b/dependencies/pixman index e4c878d1..47a1c3d3 160000 --- a/dependencies/pixman +++ b/dependencies/pixman @@ -1 +1 @@ -Subproject commit e4c878d17942346dce5f54b25d7624440ef47de6 +Subproject commit 47a1c3d330cc7ea6ba2fa96eb288f4b2291d011c diff --git a/dependencies/seatd b/dependencies/seatd index 1bd042e5..3e9ef69f 160000 --- a/dependencies/seatd +++ b/dependencies/seatd @@ -1 +1 @@ -Subproject commit 1bd042e5b0a524fb7d30953179474e60974aa6ee +Subproject commit 3e9ef69f14f630a719dd464f3c90a7932f1c8296 diff --git a/dependencies/wayland b/dependencies/wayland index 4a7348e4..edb943dc 160000 --- a/dependencies/wayland +++ b/dependencies/wayland @@ -1 +1 @@ -Subproject commit 4a7348e48c05962c7ca5a92f055622263a40242c +Subproject commit edb943dc6464697ba13d7df277aef277721764b7 diff --git a/dependencies/wayland-protocols b/dependencies/wayland-protocols index bbe9298e..479580db 160000 --- a/dependencies/wayland-protocols +++ b/dependencies/wayland-protocols @@ -1 +1 @@ -Subproject commit bbe9298e85220d8cd40ef802671ec575ba81367f +Subproject commit 479580dbe39bdb9b0bd60e52187b0e6c58366ee0 From 7c43369f982b5d3f77c47bae5e93fb19fb40a495 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 15:44:26 +0100 Subject: [PATCH 161/390] Improves naming of pending updates. --- src/toolkit/window.c | 56 +++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 4f8890bb..85780dec 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -26,6 +26,9 @@ /* == Declarations ========================================================= */ +/** Maximum number of pending state updates. */ +#define WLMTK_WINDOW_MAX_PENDING 64 + /** State of the window. */ struct _wlmtk_window_t { /** Superclass: Box. */ @@ -36,13 +39,15 @@ struct _wlmtk_window_t { /** Titlebar. */ wlmtk_titlebar_t *titlebar_ptr; - /** Pending states. */ - bs_dllist_t ps; + /** Pending updates. */ + bs_dllist_t pending_updates; + /** Set of pre-allocated updates. */ + bs_dllist_t updates_available; }; /** Pending positional updates. */ typedef struct { - /** Node within wlmtk_window_t::ps. */ + /** Node within @ref wlmtk_window_t::pending_updates. */ bs_dllist_node_t dlnode; /** Serial of the update. */ uint32_t serial; @@ -54,7 +59,7 @@ typedef struct { unsigned width; /** Height that is to be committed at serial. */ unsigned height; -} wlmtk_pending_t; +} wlmtk_pending_update_t; static void box_update_layout(wlmtk_box_t *box_ptr); static void window_box_destroy(wlmtk_box_t *box_ptr); @@ -216,14 +221,16 @@ void wlmtk_window_request_position_and_size( // TODO(kaeser@gubbe.ch): Use a pre-allocated array, and apply pending // states when in risk of overflow. - wlmtk_pending_t *pending_ptr = logged_calloc(1, sizeof(wlmtk_pending_t)); - BS_ASSERT(NULL != pending_ptr); - pending_ptr->serial = serial; - pending_ptr->x = x; - pending_ptr->y = y; - pending_ptr->width = width; - pending_ptr->height = height; - bs_dllist_push_back(&window_ptr->ps, &pending_ptr->dlnode); + wlmtk_pending_update_t *pending_update_ptr = logged_calloc( + 1, sizeof(wlmtk_pending_update_t)); + BS_ASSERT(NULL != pending_update_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = x; + pending_update_ptr->y = y; + pending_update_ptr->width = width; + pending_update_ptr->height = height; + bs_dllist_push_back(&window_ptr->pending_updates, + &pending_update_ptr->dlnode); // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial // may have been called early, so we should check if serial had just been @@ -234,27 +241,28 @@ void wlmtk_window_request_position_and_size( /* ------------------------------------------------------------------------- */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) { - while (!bs_dllist_empty(&window_ptr->ps)) { - bs_dllist_node_t *dlnode_ptr = window_ptr->ps.head_ptr; - wlmtk_pending_t *pending_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_t, dlnode); + while (!bs_dllist_empty(&window_ptr->pending_updates)) { + bs_dllist_node_t *dlnode_ptr = window_ptr->pending_updates.head_ptr; + wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); - if (pending_ptr->serial > serial) { + if (pending_update_ptr->serial > serial) { break; } - BS_ASSERT(dlnode_ptr == bs_dllist_pop_front(&window_ptr->ps)); - if (pending_ptr->serial < serial) { - free(pending_ptr); + BS_ASSERT(dlnode_ptr == bs_dllist_pop_front( + &window_ptr->pending_updates)); + if (pending_update_ptr->serial < serial) { + free(pending_update_ptr); continue; } - BS_ASSERT(pending_ptr->serial == serial); + BS_ASSERT(pending_update_ptr->serial == serial); wlmtk_element_set_position( wlmtk_window_element(window_ptr), - pending_ptr->x, - pending_ptr->y); - free(pending_ptr); + pending_update_ptr->x, + pending_update_ptr->y); + free(pending_update_ptr); } } From 804f98ea8a1707b35f9d64e307091739188f30ca Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 16:13:10 +0100 Subject: [PATCH 162/390] Uses a pre-allocated set of updates, reducing the allocations needed. --- src/toolkit/window.c | 56 ++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 85780dec..598acd3c 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -29,22 +29,6 @@ /** Maximum number of pending state updates. */ #define WLMTK_WINDOW_MAX_PENDING 64 -/** State of the window. */ -struct _wlmtk_window_t { - /** Superclass: Box. */ - wlmtk_box_t super_box; - - /** Content of this window. */ - wlmtk_content_t *content_ptr; - /** Titlebar. */ - wlmtk_titlebar_t *titlebar_ptr; - - /** Pending updates. */ - bs_dllist_t pending_updates; - /** Set of pre-allocated updates. */ - bs_dllist_t updates_available; -}; - /** Pending positional updates. */ typedef struct { /** Node within @ref wlmtk_window_t::pending_updates. */ @@ -61,6 +45,25 @@ typedef struct { unsigned height; } wlmtk_pending_update_t; +/** State of the window. */ +struct _wlmtk_window_t { + /** Superclass: Box. */ + wlmtk_box_t super_box; + + /** Content of this window. */ + wlmtk_content_t *content_ptr; + /** Titlebar. */ + wlmtk_titlebar_t *titlebar_ptr; + + /** Pending updates. */ + bs_dllist_t pending_updates; + /** List of udpates currently available. */ + bs_dllist_t available_updates; + /** Pre-alloocated updates. */ + wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; +}; + + static void box_update_layout(wlmtk_box_t *box_ptr); static void window_box_destroy(wlmtk_box_t *box_ptr); @@ -95,6 +98,10 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) { wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; + for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { + bs_dllist_push_back(&window_ptr->available_updates, + &window_ptr->pre_allocated_updates[i].dlnode); + } if (!wlmtk_box_init(&window_ptr->super_box, &window_box_impl, @@ -219,11 +226,12 @@ void wlmtk_window_request_position_and_size( uint32_t serial = wlmtk_content_request_size( window_ptr->content_ptr, width, height); - // TODO(kaeser@gubbe.ch): Use a pre-allocated array, and apply pending - // states when in risk of overflow. - wlmtk_pending_update_t *pending_update_ptr = logged_calloc( - 1, sizeof(wlmtk_pending_update_t)); - BS_ASSERT(NULL != pending_update_ptr); + // TODO(kaeser@gubbe.ch): Handle case of not having a node. + bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( + &window_ptr->available_updates); + BS_ASSERT(NULL != dlnode_ptr); + wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); pending_update_ptr->serial = serial; pending_update_ptr->x = x; pending_update_ptr->y = y; @@ -253,7 +261,8 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) BS_ASSERT(dlnode_ptr == bs_dllist_pop_front( &window_ptr->pending_updates)); if (pending_update_ptr->serial < serial) { - free(pending_update_ptr); + bs_dllist_push_front(&window_ptr->available_updates, + &pending_update_ptr->dlnode); continue; } @@ -262,7 +271,8 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) wlmtk_window_element(window_ptr), pending_update_ptr->x, pending_update_ptr->y); - free(pending_update_ptr); + bs_dllist_push_front(&window_ptr->available_updates, + &pending_update_ptr->dlnode); } } From 4c845899947028f3225a825490a2bf30273d1e66 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 17:21:46 +0100 Subject: [PATCH 163/390] Updates to most recent libbase. --- src/tile_container.c | 1 - submodules/libbase | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tile_container.c b/src/tile_container.c index 9cf5f853..075dd833 100644 --- a/src/tile_container.c +++ b/src/tile_container.c @@ -120,7 +120,6 @@ void wlmaker_tile_container_add( wlmaker_iconified_t *iconified_ptr) { bs_dllist_node_t *dlnode_ptr = wlmaker_dlnode_from_iconified(iconified_ptr); - BS_ASSERT(bs_dllist_node_orphaned(dlnode_ptr)); bs_dllist_push_back(&tile_container_ptr->tiles, dlnode_ptr); struct wlr_scene_node *wlr_scene_node_ptr = diff --git a/submodules/libbase b/submodules/libbase index 8de293a0..c215f7db 160000 --- a/submodules/libbase +++ b/submodules/libbase @@ -1 +1 @@ -Subproject commit 8de293a0edc6896c71eadb2b8abe0d12209a69a5 +Subproject commit c215f7dbedc624ff29808882c2e0015d4a584b77 From 04b9dd32f4fa7d68a05d5ac5f4beb4f86e091c0a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 17:25:49 +0100 Subject: [PATCH 164/390] Uses a pre-allocated set of updates. --- src/toolkit/window.c | 78 ++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 598acd3c..7a7154da 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -63,6 +63,11 @@ struct _wlmtk_window_t { wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; }; +static wlmtk_pending_update_t *prepare_update( + wlmtk_window_t *window_ptr); +static void release_update( + wlmtk_window_t *window_ptr, + wlmtk_pending_update_t *update_ptr); static void box_update_layout(wlmtk_box_t *box_ptr); static void window_box_destroy(wlmtk_box_t *box_ptr); @@ -226,19 +231,12 @@ void wlmtk_window_request_position_and_size( uint32_t serial = wlmtk_content_request_size( window_ptr->content_ptr, width, height); - // TODO(kaeser@gubbe.ch): Handle case of not having a node. - bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( - &window_ptr->available_updates); - BS_ASSERT(NULL != dlnode_ptr); - wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); + wlmtk_pending_update_t *pending_update_ptr = prepare_update(window_ptr); pending_update_ptr->serial = serial; pending_update_ptr->x = x; pending_update_ptr->y = y; pending_update_ptr->width = width; pending_update_ptr->height = height; - bs_dllist_push_back(&window_ptr->pending_updates, - &pending_update_ptr->dlnode); // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial // may have been called early, so we should check if serial had just been @@ -249,30 +247,20 @@ void wlmtk_window_request_position_and_size( /* ------------------------------------------------------------------------- */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) { - while (!bs_dllist_empty(&window_ptr->pending_updates)) { - bs_dllist_node_t *dlnode_ptr = window_ptr->pending_updates.head_ptr; + bs_dllist_node_t *dlnode_ptr; + while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( dlnode_ptr, wlmtk_pending_update_t, dlnode); - if (pending_update_ptr->serial > serial) { - break; - } - - BS_ASSERT(dlnode_ptr == bs_dllist_pop_front( - &window_ptr->pending_updates)); - if (pending_update_ptr->serial < serial) { - bs_dllist_push_front(&window_ptr->available_updates, - &pending_update_ptr->dlnode); - continue; - } + int32_t delta = pending_update_ptr->serial - serial; + if (0 < delta) break; + // if (pending_update_ptr->serial > serial) break; - BS_ASSERT(pending_update_ptr->serial == serial); wlmtk_element_set_position( wlmtk_window_element(window_ptr), pending_update_ptr->x, pending_update_ptr->y); - bs_dllist_push_front(&window_ptr->available_updates, - &pending_update_ptr->dlnode); + release_update(window_ptr, pending_update_ptr); } } @@ -300,6 +288,48 @@ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) /* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** + * Prepares a positional update: Allocates an item and attach it to the end + * of the list of pending updates. + * + * @param window_ptr + * + * @return A pointer to a @ref wlmtk_pending_update_t, already positioned at the + * back of @ref wlmtk_window_t::pending_updates. + */ +wlmtk_pending_update_t *prepare_update( + wlmtk_window_t *window_ptr) +{ + bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( + &window_ptr->available_updates); + if (NULL == dlnode_ptr) { + dlnode_ptr = bs_dllist_pop_front(&window_ptr->pending_updates); + bs_log(BS_WARNING, "Window %p: No updates available.", window_ptr); + // TODO(kaeser@gubbe.ch): Hm, should we apply this (old) update? + } + wlmtk_pending_update_t *update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); + bs_dllist_push_back(&window_ptr->pending_updates, &update_ptr->dlnode); + return update_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** + * Releases a pending positional update. Moves it to the list of + * @ref wlmtk_window_t::available_updates. + * + * @param window_ptr + * @param update_ptr + */ +void release_update( + wlmtk_window_t *window_ptr, + wlmtk_pending_update_t *update_ptr) +{ + bs_dllist_remove(&window_ptr->pending_updates, &update_ptr->dlnode); + bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); +} + /* ------------------------------------------------------------------------- */ /** * Implementation of @ref wlmtk_box_impl_t::update_layout. From 7a014c2e417b3f869460764552ef1f7fb95ea095 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 17:26:58 +0100 Subject: [PATCH 165/390] Removes obsolete commented code. --- src/toolkit/window.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7a7154da..dc97da2b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -254,7 +254,6 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) int32_t delta = pending_update_ptr->serial - serial; if (0 < delta) break; - // if (pending_update_ptr->serial > serial) break; wlmtk_element_set_position( wlmtk_window_element(window_ptr), From 2fd947d29a90553a37b6427972ef0362c9b2d640 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 17:49:50 +0100 Subject: [PATCH 166/390] Adds log statements when committed size doesn't match desired size. --- src/toolkit/window.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index dc97da2b..2169e8a4 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -255,6 +255,17 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) int32_t delta = pending_update_ptr->serial - serial; if (0 < delta) break; + if (pending_update_ptr->serial == serial) { + if (window_ptr->content_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (window_ptr->content_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } + } + wlmtk_element_set_position( wlmtk_window_element(window_ptr), pending_update_ptr->x, From 67abdc7336f8ee5a51eeadc71db92fa892ed813d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 21:14:19 +0100 Subject: [PATCH 167/390] Adds boilerplate code for the resizebar class. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/resizebar.c | 92 ++++++++++++++++++++++++++++++++++++++ src/toolkit/resizebar.h | 68 ++++++++++++++++++++++++++++ src/toolkit/toolkit.h | 3 +- 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/toolkit/resizebar.c create mode 100644 src/toolkit/resizebar.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 81a30127..d22d62fa 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(PUBLIC_HEADER_FILES content.h element.h fsm.h + resizebar.h titlebar.h window.h workspace.h) @@ -41,6 +42,7 @@ TARGET_SOURCES(toolkit PRIVATE fsm.c gfxbuf.c primitives.c + resizebar.c titlebar.c util.c window.c diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c new file mode 100644 index 00000000..8a852423 --- /dev/null +++ b/src/toolkit/resizebar.c @@ -0,0 +1,92 @@ +/* ========================================================================= */ +/** + * @file resizebar.c + * Copyright (c) 2023 by Philipp Kaeser + */ + +#include "resizebar.h" + +#include "box.h" + +#include + +/* == Declarations ========================================================= */ + +/** State of the title bar. */ +struct _wlmtk_resizebar_t { + /** Superclass: Box. */ + wlmtk_box_t super_box; + + /** Current width of the resize bar. */ + unsigned width; + /** Style of the resize bar. */ + wlmtk_resizebar_style_t style; +}; + +static void resizebar_box_destroy(wlmtk_box_t *box_ptr); + +/* == Data ================================================================= */ + +/** Method table for the box's virtual methods. */ +static const wlmtk_box_impl_t resizebar_box_impl = { + .destroy = resizebar_box_destroy +}; + + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_resizebar_t *wlmtk_resizebar_create( + unsigned width, + const wlmtk_resizebar_style_t *style_ptr) +{ + wlmtk_resizebar_t *resizebar_ptr = logged_calloc( + 1, sizeof(wlmtk_resizebar_t)); + if (NULL == resizebar_ptr) return NULL; + memcpy(&resizebar_ptr->style, style_ptr, sizeof(wlmtk_resizebar_style_t)); + + if (!wlmtk_box_init(&resizebar_ptr->super_box, + &resizebar_box_impl, + WLMTK_BOX_HORIZONTAL)) { + wlmtk_resizebar_destroy(resizebar_ptr); + return NULL; + } + + resizebar_ptr->width = width; + + return resizebar_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) +{ + wlmtk_box_fini(&resizebar_ptr->super_box); + free(resizebar_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_resizebar_set_width( + wlmtk_resizebar_t * resizebar_ptr, + unsigned width) +{ + resizebar_ptr->width = width; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) +{ + return &resizebar_ptr->super_box.super_container.super_element; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, in case called from box. Wraps to our dtor. */ +void resizebar_box_destroy(wlmtk_box_t *box_ptr) +{ + wlmtk_resizebar_t *resizebar_ptr = BS_CONTAINER_OF( + box_ptr, wlmtk_resizebar_t, super_box); + wlmtk_resizebar_destroy(resizebar_ptr); +} + +/* == End of resizebar.c =================================================== */ diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h new file mode 100644 index 00000000..263550a9 --- /dev/null +++ b/src/toolkit/resizebar.h @@ -0,0 +1,68 @@ +/* ========================================================================= */ +/** + * @file resizebar.h + * Copyright (c) 2023 by Philipp Kaeser + */ +#ifndef __WLMTK_RESIZEBAR_H__ +#define __WLMTK_RESIZEBAR_H__ + +/** Forward declaration: Title bar. */ +typedef struct _wlmtk_resizebar_t wlmtk_resizebar_t; + +#include "element.h" +#include "primitives.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Style options for the resizebar. */ +typedef struct { + /** Fill style for the complete resizebar. */ + wlmtk_style_fill_t fill; +} wlmtk_resizebar_style_t; + +/** + * Creates the resize bar. + * + * @param width + * @param style_ptr + * + * @return Pointer to the resizebar state, or NULL on error. + */ +wlmtk_resizebar_t *wlmtk_resizebar_create( + unsigned width, + const wlmtk_resizebar_style_t *style_ptr); + +/** + * Destroys the resize bar. + * + * @param resizebar_ptr + */ +void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr); + +/** + * Sets the width of the resize bar. + * + * @param resizebar_ptr + * @param width + */ +void wlmtk_resizebar_set_width( + wlmtk_resizebar_t * resizebar_ptr, + unsigned width); + +/** + * Returns the super Element of the resizebar. + * + * @param resizebar_ptr + * + * @return Pointer to the element. + */ +wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_RESIZEBAR_H__ */ +/* == End of resizebar.h ================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 4e5b4982..3533820a 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -36,9 +36,10 @@ #include "content.h" #include "element.h" #include "fsm.h" +#include "resizebar.h" +#include "titlebar.h" #include "window.h" #include "workspace.h" -#include "titlebar.h" #ifdef __cplusplus extern "C" { From 496ddd6306b663dea19186ebea35ca429fc1036c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 21:39:18 +0100 Subject: [PATCH 168/390] Adds resizebar unit tests. --- src/toolkit/resizebar.c | 20 ++++++++++++++++++++ src/toolkit/resizebar.h | 3 +++ src/toolkit/toolkit_test.c | 1 + 3 files changed, 24 insertions(+) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 8a852423..34b68b83 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -89,4 +89,24 @@ void resizebar_box_destroy(wlmtk_box_t *box_ptr) wlmtk_resizebar_destroy(resizebar_ptr); } +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_resizebar_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises @ref wlmtk_resizebar_create and @ref wlmtk_resizebar_destroy. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + wlmtk_resizebar_style_t style = {}; + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create(120, &style); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); + + wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); +} + /* == End of resizebar.c =================================================== */ diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 263550a9..870f393b 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -60,6 +60,9 @@ void wlmtk_resizebar_set_width( */ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr); +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_resizebar_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index b87012d1..a6e71f5b 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -27,6 +27,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, + { 1, "resizebar", wlmtk_resizebar_test_cases }, { 1, "titlebar", wlmtk_titlebar_test_cases }, { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, From ee49c8d99ccb04d8dec18f7af2813ecbe638fb82 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 5 Nov 2023 21:46:05 +0100 Subject: [PATCH 169/390] Handles return value of redraw_buffers. --- src/toolkit/titlebar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index a3726519..7f6752f7 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -188,7 +188,7 @@ bool wlmtk_titlebar_set_width( unsigned width) { if (titlebar_ptr->width == width) return true; - redraw_buffers(titlebar_ptr, width); + if (!redraw_buffers(titlebar_ptr, width)) return false; BS_ASSERT(width == titlebar_ptr->width); if (!wlmtk_titlebar_title_redraw( From 998e39409929964edb14b483965a5634c1eb637d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 6 Nov 2023 21:15:37 +0100 Subject: [PATCH 170/390] Adds a primitive for the resizebar. --- src/toolkit/resizebar.c | 231 +++++++++++++++++++++++++++++++++++++++- src/toolkit/resizebar.h | 6 +- src/toolkit/window.c | 36 +++++++ 3 files changed, 269 insertions(+), 4 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 34b68b83..7878f921 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -7,11 +7,21 @@ #include "resizebar.h" #include "box.h" +#include "buffer.h" +#include "gfxbuf.h" +#include "primitives.h" #include +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + /* == Declarations ========================================================= */ +/** Forward declaration: Element of the resizebar. */ +typedef struct _wlmtk_resizebar_element_t wlmtk_resizebar_element_t ; + /** State of the title bar. */ struct _wlmtk_resizebar_t { /** Superclass: Box. */ @@ -21,9 +31,39 @@ struct _wlmtk_resizebar_t { unsigned width; /** Style of the resize bar. */ wlmtk_resizebar_style_t style; + + /** Background. */ + bs_gfxbuf_t *gfxbuf_ptr; + + /** Element of the resizebar. */ + wlmtk_resizebar_element_t *element_ptr; +}; + +/** State of an element of the resize bar. */ +struct _wlmtk_resizebar_element_t { + /** Superclass: Buffer. */ + wlmtk_buffer_t super_buffer; + /** The buffer. */ + struct wlr_buffer *wlr_buffer_ptr; }; +static wlmtk_resizebar_element_t *wlmtk_resizebar_element_create( + bs_gfxbuf_t *gfxbuf_ptr, + int width, + const wlmtk_resizebar_style_t *style_ptr); +static void wlmtk_resizebar_element_destroy( + wlmtk_resizebar_element_t *element_ptr); +static bool wlmtk_resizebar_element_redraw( + wlmtk_resizebar_element_t *element_ptr, + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr); + static void resizebar_box_destroy(wlmtk_box_t *box_ptr); +static bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width); + +static void element_buffer_destroy(wlmtk_buffer_t *buffer_ptr); /* == Data ================================================================= */ @@ -32,6 +72,10 @@ static const wlmtk_box_impl_t resizebar_box_impl = { .destroy = resizebar_box_destroy }; +/** Buffer implementation for title of the title bar. */ +static const wlmtk_buffer_impl_t element_buffer_impl = { + .destroy = element_buffer_destroy +}; /* == Exported methods ===================================================== */ @@ -52,7 +96,22 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } - resizebar_ptr->width = width; + if (!redraw_buffers(resizebar_ptr, width)) { + wlmtk_resizebar_destroy(resizebar_ptr); + return NULL; + } + + resizebar_ptr->element_ptr = wlmtk_resizebar_element_create( + resizebar_ptr->gfxbuf_ptr, width, &resizebar_ptr->style); + if (NULL == resizebar_ptr->element_ptr) { + wlmtk_resizebar_destroy(resizebar_ptr); + return NULL; + } + wlmtk_element_set_visible( + &resizebar_ptr->element_ptr->super_buffer.super_element, true); + wlmtk_container_add_element( + &resizebar_ptr->super_box.super_container, + &resizebar_ptr->element_ptr->super_buffer.super_element); return resizebar_ptr; } @@ -60,16 +119,41 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( /* ------------------------------------------------------------------------- */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) { + if (NULL != resizebar_ptr->element_ptr) { + wlmtk_container_remove_element( + &resizebar_ptr->super_box.super_container, + &resizebar_ptr->element_ptr->super_buffer.super_element); + wlmtk_resizebar_element_destroy(resizebar_ptr->element_ptr); + resizebar_ptr->element_ptr = NULL; + } + + if (NULL != resizebar_ptr->gfxbuf_ptr) { + bs_gfxbuf_destroy(resizebar_ptr->gfxbuf_ptr); + resizebar_ptr->gfxbuf_ptr = NULL; + } + wlmtk_box_fini(&resizebar_ptr->super_box); free(resizebar_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_resizebar_set_width( +bool wlmtk_resizebar_set_width( wlmtk_resizebar_t * resizebar_ptr, unsigned width) { - resizebar_ptr->width = width; + if (resizebar_ptr->width == width) return true; + if (!redraw_buffers(resizebar_ptr, width)) return false; + BS_ASSERT(width == resizebar_ptr->width); + + if (!wlmtk_resizebar_element_redraw( + resizebar_ptr->element_ptr, + resizebar_ptr->gfxbuf_ptr, + 0, width, + &resizebar_ptr->style)) { + return false; + } + + return true; } /* ------------------------------------------------------------------------- */ @@ -78,6 +162,113 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) return &resizebar_ptr->super_box.super_container.super_element; } +/* == Resizebar element methods ============================================ */ + +/* ------------------------------------------------------------------------- */ +/** + * Creates a resizebar element. + * + * @param gfxbuf_ptr + * @param width + * @param style_ptr + * + * @return Pointer to the element. + */ +wlmtk_resizebar_element_t *wlmtk_resizebar_element_create( + bs_gfxbuf_t *gfxbuf_ptr, + int width, + const wlmtk_resizebar_style_t *style_ptr) +{ + wlmtk_resizebar_element_t *element_ptr = logged_calloc( + 1, sizeof(wlmtk_resizebar_element_t)); + if (NULL == element_ptr) return NULL; + + if (!wlmtk_resizebar_element_redraw( + element_ptr, + gfxbuf_ptr, + 0, + width, + style_ptr)) { + wlmtk_resizebar_element_destroy(element_ptr); + return NULL; + } + + if (!wlmtk_buffer_init( + &element_ptr->super_buffer, + &element_buffer_impl, + element_ptr->wlr_buffer_ptr)) { + wlmtk_resizebar_element_destroy(element_ptr); + return NULL; + } + + return element_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** + * Destroys the resizebar element. + * + * @param element_ptr + */ +void wlmtk_resizebar_element_destroy( + wlmtk_resizebar_element_t *element_ptr) +{ + if (NULL != element_ptr->wlr_buffer_ptr) { + wlr_buffer_drop(element_ptr->wlr_buffer_ptr); + element_ptr->wlr_buffer_ptr = NULL; + } + + wlmtk_buffer_fini(&element_ptr->super_buffer); + free(element_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Redraws the element, with updated position and width. + * + * @param element_ptr + * @param gfxbuf_ptr + * @param position + * @param width + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_resizebar_element_redraw( + wlmtk_resizebar_element_t *element_ptr, + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr) +{ + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + width, style_ptr->height); + if (NULL == wlr_buffer_ptr) return false; + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), + 0, 0, + gfxbuf_ptr, + position, 0, + width, style_ptr->height); + + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(wlr_buffer_ptr); + return false; + } + wlmaker_primitives_draw_bezel_at( + cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); + cairo_destroy(cairo_ptr); + + if (NULL != element_ptr->wlr_buffer_ptr) { + wlr_buffer_drop(element_ptr->wlr_buffer_ptr); + } + element_ptr->wlr_buffer_ptr = wlr_buffer_ptr; + wlmtk_buffer_set(&element_ptr->super_buffer, element_ptr->wlr_buffer_ptr); + return true; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -89,6 +280,40 @@ void resizebar_box_destroy(wlmtk_box_t *box_ptr) wlmtk_resizebar_destroy(resizebar_ptr); } +/* ------------------------------------------------------------------------- */ +/** Redraws the resizebar's background in appropriate size. */ +bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width) +{ + cairo_t *cairo_ptr; + + bs_gfxbuf_t *gfxbuf_ptr = bs_gfxbuf_create( + width, resizebar_ptr->style.height); + if (NULL == gfxbuf_ptr) return false; + cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); + if (NULL == cairo_ptr) { + bs_gfxbuf_destroy(gfxbuf_ptr); + return false; + } + wlmaker_primitives_cairo_fill(cairo_ptr, &resizebar_ptr->style.fill); + cairo_destroy(cairo_ptr); + + if (NULL != resizebar_ptr->gfxbuf_ptr) { + bs_gfxbuf_destroy(resizebar_ptr->gfxbuf_ptr); + } + resizebar_ptr->gfxbuf_ptr = gfxbuf_ptr; + resizebar_ptr->width = width; + return true; +} + +/* ------------------------------------------------------------------------- */ +/** Dtor. Forwards to @ref wlmtk_resizebar_element_destroy. */ +void element_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +{ + wlmtk_resizebar_element_t *element_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_resizebar_element_t, super_buffer); + wlmtk_resizebar_element_destroy(element_ptr); +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 870f393b..048fb98b 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -20,6 +20,8 @@ extern "C" { typedef struct { /** Fill style for the complete resizebar. */ wlmtk_style_fill_t fill; + /** Height of the resize bar. */ + unsigned height; } wlmtk_resizebar_style_t; /** @@ -46,8 +48,10 @@ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr); * * @param resizebar_ptr * @param width + * + * @return true on success. */ -void wlmtk_resizebar_set_width( +bool wlmtk_resizebar_set_width( wlmtk_resizebar_t * resizebar_ptr, unsigned width); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 2169e8a4..f277bca2 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -21,6 +21,7 @@ #include "window.h" #include "box.h" +#include "resizebar.h" #include "titlebar.h" #include "workspace.h" @@ -54,6 +55,8 @@ struct _wlmtk_window_t { wlmtk_content_t *content_ptr; /** Titlebar. */ wlmtk_titlebar_t *titlebar_ptr; + /** Resizebar. */ + wlmtk_resizebar_t *resizebar_ptr; /** Pending updates. */ bs_dllist_t pending_updates; @@ -96,6 +99,16 @@ static const wlmtk_titlebar_style_t titlebar_style = { .height = 22, }; +/** Style of the resize bar. */ +// TODO(kaeser@gubbe.ch): Move to central config. */ +static const wlmtk_resizebar_style_t resizebar_style = { + .fill = { + .type = WLMTK_STYLE_COLOR_SOLID, + .param = { .solid = { .color = 0xffc2c0c5 }} + }, + .height = 8, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -136,12 +149,32 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + window_ptr->resizebar_ptr = wlmtk_resizebar_create( + width, &resizebar_style); + if (NULL == window_ptr->resizebar_ptr) { + wlmtk_window_destroy(window_ptr); + return NULL; + } + wlmtk_container_add_element( + &window_ptr->super_box.super_container, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_element_set_visible( + wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); + return window_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_container_remove_element( + &window_ptr->super_box.super_container, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); + window_ptr->resizebar_ptr = NULL; + } + if (NULL != window_ptr->titlebar_ptr) { wlmtk_container_remove_element( &window_ptr->super_box.super_container, @@ -361,6 +394,9 @@ void box_update_layout(wlmtk_box_t *box_ptr) if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); } + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); + } } } From 9ff007e80d44d94523bbd5316ffabbedd3b46d2f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 6 Nov 2023 21:15:56 +0100 Subject: [PATCH 171/390] Fixes some comments and layout. --- src/toolkit/titlebar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 7f6752f7..ec48530d 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -58,14 +58,14 @@ struct _wlmtk_titlebar_t { /** State of the title bar's title. */ struct _wlmtk_titlebar_title_t { - /** Superclass; Buffer. */ + /** Superclass: Buffer. */ wlmtk_buffer_t super_buffer; /** The drawn title, when focussed. */ struct wlr_buffer *focussed_wlr_buffer_ptr; /** The drawn title, when blurred. */ struct wlr_buffer *blurred_wlr_buffer_ptr; -} ; +}; static wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( bs_gfxbuf_t *focussed_gfxbuf_ptr, From e1beb95990ae38f0dadf7dd5b625240b02655515 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 6 Nov 2023 21:45:59 +0100 Subject: [PATCH 172/390] Adds wlmtk_container_add_element_before. --- src/toolkit/container.c | 52 ++++++++++++++++++++++++++++++++++++++--- src/toolkit/container.h | 14 +++++++++++ src/toolkit/window.c | 3 ++- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 31f91655..b11f24b4 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -161,6 +161,33 @@ void wlmtk_container_add_element( wlmtk_container_update_layout(container_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_container_add_element_before( + wlmtk_container_t *container_ptr, + wlmtk_element_t *reference_element_ptr, + wlmtk_element_t *element_ptr) +{ + BS_ASSERT(NULL == element_ptr->parent_container_ptr); + BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + BS_ASSERT( + NULL == reference_element_ptr || + container_ptr == reference_element_ptr->parent_container_ptr); + + if (NULL == reference_element_ptr) { + bs_dllist_push_back( + &container_ptr->elements, + wlmtk_dlnode_from_element(element_ptr)); + } else { + bs_dllist_insert_node_before( + &container_ptr->elements, + wlmtk_dlnode_from_element(reference_element_ptr), + wlmtk_dlnode_from_element(element_ptr)); + } + + wlmtk_element_set_parent_container(element_ptr, container_ptr); + wlmtk_container_update_layout(container_ptr); +} + /* ------------------------------------------------------------------------- */ void wlmtk_container_remove_element( wlmtk_container_t *container_ptr, @@ -624,18 +651,37 @@ void test_add_remove(bs_test_t *test_ptr) elem3_ptr = wlmtk_fake_element_create(); BS_ASSERT(NULL != elem3_ptr); + // Build sequence: 3 -> 2 -> 1. wlmtk_container_add_element(&container, &elem1_ptr->element); BS_TEST_VERIFY_EQ( - test_ptr, elem1_ptr->element.parent_container_ptr, &container); + test_ptr, &container, elem1_ptr->element.parent_container_ptr); wlmtk_container_add_element(&container, &elem2_ptr->element); BS_TEST_VERIFY_EQ( - test_ptr, elem2_ptr->element.parent_container_ptr, &container); + test_ptr, &container, elem2_ptr->element.parent_container_ptr); wlmtk_container_add_element(&container, &elem3_ptr->element); BS_TEST_VERIFY_EQ( - test_ptr, elem3_ptr->element.parent_container_ptr, &container); + test_ptr, &container, elem3_ptr->element.parent_container_ptr); + // Remove 2, then add at the end: 3 -> 1 -> 2. wlmtk_container_remove_element(&container, &elem2_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, NULL, elem2_ptr->element.parent_container_ptr); + wlmtk_container_add_element_before(&container, NULL, &elem2_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, &container, elem2_ptr->element.parent_container_ptr); + BS_TEST_VERIFY_EQ( + test_ptr, + wlmtk_dlnode_from_element(&elem1_ptr->element)->next_ptr, + wlmtk_dlnode_from_element(&elem2_ptr->element)); + + // Remove elem3 and add before elem2: 1 -> 3 -> 2. + wlmtk_container_remove_element(&container, &elem3_ptr->element); + wlmtk_container_add_element_before( + &container, &elem2_ptr->element, &elem3_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + wlmtk_dlnode_from_element(&elem3_ptr->element)->next_ptr, + wlmtk_dlnode_from_element(&elem2_ptr->element)); + + wlmtk_container_remove_element(&container, &elem2_ptr->element); wlmtk_element_destroy(&elem2_ptr->element); // Will destroy contained elements. diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 45d1adde..05a3ae49 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -122,6 +122,20 @@ void wlmtk_container_add_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr); +/** + * Adds `element_ptr` to the container at (before) the reference's position. + * + * If reference_element_ptr is NULL, the element will be added at the back. + * + * @param container_ptr + * @param reference_element_ptr Must be an element of this container. + * @param element_ptr + */ +void wlmtk_container_add_element_before( + wlmtk_container_t *container_ptr, + wlmtk_element_t *reference_element_ptr, + wlmtk_element_t *element_ptr); + /** * Removes `element_ptr` from the container. * diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f277bca2..7588304e 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -155,8 +155,9 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_window_destroy(window_ptr); return NULL; } - wlmtk_container_add_element( + wlmtk_container_add_element_before( &window_ptr->super_box.super_container, + NULL, wlmtk_resizebar_element(window_ptr->resizebar_ptr)); wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); From c33fdb2b29ee7d038c4d366231180288c5af4f64 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 8 Nov 2023 20:48:30 +0100 Subject: [PATCH 173/390] Moves the pointer button definition into input.h --- src/toolkit/CMakeLists.txt | 1 + src/toolkit/button.h | 24 ---------------- src/toolkit/element.h | 2 +- src/toolkit/input.h | 56 ++++++++++++++++++++++++++++++++++++++ src/toolkit/toolkit.h | 2 ++ 5 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 src/toolkit/input.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index d22d62fa..31a45714 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(PUBLIC_HEADER_FILES content.h element.h fsm.h + input.h resizebar.h titlebar.h window.h diff --git a/src/toolkit/button.h b/src/toolkit/button.h index da773ed4..9a01acd7 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -20,35 +20,11 @@ #ifndef __WLMTK_BUTTON_H__ #define __WLMTK_BUTTON_H__ -// BTN_LEFT, BTN_RIGHT, ... -#include - -/** Forward declaration: Button event. */ -typedef struct _wlmtk_button_event_t wlmtk_button_event_t; - #ifdef __cplusplus extern "C" { #endif // __cplusplus -/** Button state. */ -typedef enum { - WLMTK_BUTTON_DOWN, - WLMTK_BUTTON_UP, - WLMTK_BUTTON_CLICK, - WLMTK_BUTTON_DOUBLE_CLICK, -} wlmtk_button_event_type_t; - -/** Button events. */ -struct _wlmtk_button_event_t { - /** Button for which the event applies: linux/input-event-codes.h */ - uint32_t button; - /** Type of the event: DOWN, UP, ... */ - wlmtk_button_event_type_t type; - /** Time of the button event, in milliseconds. */ - uint32_t time_msec; -}; - #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 6353b930..66babc94 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -32,7 +32,7 @@ typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; typedef struct _wlmtk_container_t wlmtk_container_t; struct wlr_scene_tree; -#include "button.h" +#include "input.h" #ifdef __cplusplus extern "C" { diff --git a/src/toolkit/input.h b/src/toolkit/input.h new file mode 100644 index 00000000..fbf18ef2 --- /dev/null +++ b/src/toolkit/input.h @@ -0,0 +1,56 @@ +/* ========================================================================= */ +/** + * @file input.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_INPUT_H__ +#define __WLMTK_INPUT_H__ + +// BTN_LEFT, BTN_RIGHT, ... +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Forward declaration: Button event. */ +typedef struct _wlmtk_button_event_t wlmtk_button_event_t; + +/** Button state. */ +typedef enum { + WLMTK_BUTTON_DOWN, + WLMTK_BUTTON_UP, + WLMTK_BUTTON_CLICK, + WLMTK_BUTTON_DOUBLE_CLICK, +} wlmtk_button_event_type_t; + +/** Button events. */ +struct _wlmtk_button_event_t { + /** Button for which the event applies: linux/input-event-codes.h */ + uint32_t button; + /** Type of the event: DOWN, UP, ... */ + wlmtk_button_event_type_t type; + /** Time of the button event, in milliseconds. */ + uint32_t time_msec; +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_INPUT_H__ */ +/* == End of input.h ======================================================= */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 3533820a..39b82031 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,12 +30,14 @@ #include #include + #include "box.h" #include "buffer.h" #include "container.h" #include "content.h" #include "element.h" #include "fsm.h" +#include "input.h" #include "resizebar.h" #include "titlebar.h" #include "window.h" From 8517616ef30b22345dcab728e7907de2f618c97b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 8 Nov 2023 21:36:00 +0100 Subject: [PATCH 174/390] Adds boilerplate for a button element. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/buffer.h | 3 +- src/toolkit/button.c | 141 +++++++++++++++++++++++++++++++++++++ src/toolkit/button.h | 63 +++++++++++++++++ src/toolkit/toolkit.h | 2 +- src/toolkit/toolkit_test.c | 1 + 6 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 src/toolkit/button.c diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 31a45714..309778af 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -23,6 +23,7 @@ SET(PUBLIC_HEADER_FILES box.h buffer.h + button.h container.h content.h element.h @@ -37,6 +38,7 @@ ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE box.c buffer.c + button.c container.c content.c element.c diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index 4bf264b6..fcd42115 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -38,8 +38,7 @@ struct wlr_scene_buffer; extern "C" { #endif // __cplusplus - -/** Method table of the content. */ +/** Method table of the buffer. */ struct _wlmtk_buffer_impl_t { /** Destroys the implementation of the buffer. */ void (*destroy)(wlmtk_buffer_t *buffer_ptr); diff --git a/src/toolkit/button.c b/src/toolkit/button.c new file mode 100644 index 00000000..e74b96ad --- /dev/null +++ b/src/toolkit/button.c @@ -0,0 +1,141 @@ +/* ========================================================================= */ +/** + * @file button.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "button.h" + +#include "gfxbuf.h" + +#include + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +static void button_buffer_destroy(wlmtk_buffer_t *buffer_ptr); + +/* == Data ================================================================= */ + +/** Virtual method table for @ref wlmtk_button_t::super_buffer. */ +static const wlmtk_buffer_impl_t button_buffer_impl = { + .destroy = button_buffer_destroy, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_button_init( + wlmtk_button_t *button_ptr, + const wlmtk_button_impl_t *button_impl_ptr, + struct wlr_buffer *released_wlr_buffer_ptr, + struct wlr_buffer *pressed_wlr_buffer_ptr) +{ + BS_ASSERT(NULL != button_ptr); + memset(button_ptr, 0, sizeof(wlmtk_button_t)); + BS_ASSERT(NULL != button_impl_ptr); + BS_ASSERT(NULL != button_impl_ptr->destroy); + memcpy(&button_ptr->impl, button_impl_ptr, sizeof(wlmtk_button_impl_t)); + + button_ptr->released_wlr_buffer_ptr = wlr_buffer_lock( + released_wlr_buffer_ptr); + button_ptr->pressed_wlr_buffer_ptr = wlr_buffer_lock( + pressed_wlr_buffer_ptr); + + if (!wlmtk_buffer_init( + &button_ptr->super_buffer, + &button_buffer_impl, + released_wlr_buffer_ptr)) { + wlmtk_button_fini(button_ptr); + return false; + } + + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_button_fini(wlmtk_button_t *button_ptr) +{ + if (NULL != button_ptr->pressed_wlr_buffer_ptr) { + wlr_buffer_unlock(button_ptr->pressed_wlr_buffer_ptr); + button_ptr->pressed_wlr_buffer_ptr = NULL; + } + if (NULL != button_ptr->released_wlr_buffer_ptr) { + wlr_buffer_unlock(button_ptr->released_wlr_buffer_ptr); + button_ptr->released_wlr_buffer_ptr = NULL; + } + + wlmtk_buffer_fini(&button_ptr->super_buffer); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_button_set( + __UNUSED__ wlmtk_button_t *button_ptr, + __UNUSED__ struct wlr_buffer *pressed_wlr_buffer_ptr, + __UNUSED__ struct wlr_buffer *released_wlr_buffer_ptr) +{ + // FIXME. +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Destructor: Wraps to @ref wlmtk_button_impl_t::destroy. */ +void button_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +{ + wlmtk_button_t *button_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_button_t, super_buffer); + button_ptr->impl.destroy(button_ptr); +} + +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); + +/** Test case definition. */ +const bs_test_case_t wlmtk_button_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 0, NULL, NULL } +}; + +/** Fake destructor. */ +static void fake_button_destroy(__UNUSED__ wlmtk_button_t *button_ptr) {} + +/** Virtual method table of fake button. */ +const wlmtk_button_impl_t fake_button_impl = { + .destroy = fake_button_destroy, +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises @ref wlmtk_button_init and @ref wlmtk_button_fini. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + wlmtk_button_t button; + + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_button_init(&button, &fake_button_impl, wlr_buffer_ptr, wlr_buffer_ptr)); + wlr_buffer_drop(wlr_buffer_ptr); + + wlmtk_element_destroy(&button.super_buffer.super_element); +} + +/* == End of button.c ====================================================== */ diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 9a01acd7..c412f82b 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -20,11 +20,74 @@ #ifndef __WLMTK_BUTTON_H__ #define __WLMTK_BUTTON_H__ +#include "buffer.h" +#include "element.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus +/** Forward declaration: State of a button. */ +typedef struct _wlmtk_button_t wlmtk_button_t; + +/** Method table of the button. */ +typedef struct { + /** Destroys the implementation of the button. */ + void (*destroy)(wlmtk_button_t *button_ptr); +} wlmtk_button_impl_t; + +/** State of a button. */ +struct _wlmtk_button_t { + /** Super class of the button: A buffer. */ + wlmtk_buffer_t super_buffer; + + /** Implementation of abstract virtual methods. */ + wlmtk_button_impl_t impl; + + /** WLR buffer holding the button in released state. */ + struct wlr_buffer *released_wlr_buffer_ptr; + /** WLR buffer holding the button in pressed state. */ + struct wlr_buffer *pressed_wlr_buffer_ptr; +}; + +/** + * Initializes the button. + * + * @param button_ptr + * @param button_impl_ptr + * @param released_wlr_buffer_ptr + * @param pressed_wlr_buffer_ptr + * + * @return true on success. + */ +bool wlmtk_button_init( + wlmtk_button_t *button_ptr, + const wlmtk_button_impl_t *button_impl_ptr, + struct wlr_buffer *released_wlr_buffer_ptr, + struct wlr_buffer *pressed_wlr_buffer_ptr); + +/** + * Cleans up the button. + * + * @param button_ptr + */ +void wlmtk_button_fini(wlmtk_button_t *button_ptr); + +/** + * Sets (or updates) the button textures. + * + * @param button_ptr + * @param released_wlr_buffer_ptr + * @param pressed_wlr_buffer_ptr + */ +void wlmtk_button_set( + wlmtk_button_t *button_ptr, + struct wlr_buffer *released_wlr_buffer_ptr, + struct wlr_buffer *pressed_wlr_buffer_ptr); + +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_button_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 39b82031..2c519550 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,9 +30,9 @@ #include #include - #include "box.h" #include "buffer.h" +#include "button.h" #include "container.h" #include "content.h" #include "element.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index a6e71f5b..d42de3b0 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -23,6 +23,7 @@ /** Toolkit unit tests. */ const bs_test_set_t toolkit_tests[] = { { 1, "box", wlmtk_box_test_cases }, + { 1, "button", wlmtk_button_test_cases }, { 1, "container", wlmtk_container_test_cases }, { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, From a0b48c21e237f75cfbbafb9cb05b655bb050dc13 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 8 Nov 2023 21:42:49 +0100 Subject: [PATCH 175/390] Adds implementation of wlmtk_button_set. --- src/toolkit/button.c | 42 ++++++++++++++++++++++++++++++------------ src/toolkit/button.h | 3 +++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index e74b96ad..01a8fb9b 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -54,11 +54,6 @@ bool wlmtk_button_init( BS_ASSERT(NULL != button_impl_ptr->destroy); memcpy(&button_ptr->impl, button_impl_ptr, sizeof(wlmtk_button_impl_t)); - button_ptr->released_wlr_buffer_ptr = wlr_buffer_lock( - released_wlr_buffer_ptr); - button_ptr->pressed_wlr_buffer_ptr = wlr_buffer_lock( - pressed_wlr_buffer_ptr); - if (!wlmtk_buffer_init( &button_ptr->super_buffer, &button_buffer_impl, @@ -67,6 +62,9 @@ bool wlmtk_button_init( return false; } + wlmtk_button_set( + button_ptr, released_wlr_buffer_ptr, pressed_wlr_buffer_ptr); + return true; } @@ -87,11 +85,31 @@ void wlmtk_button_fini(wlmtk_button_t *button_ptr) /* ------------------------------------------------------------------------- */ void wlmtk_button_set( - __UNUSED__ wlmtk_button_t *button_ptr, - __UNUSED__ struct wlr_buffer *pressed_wlr_buffer_ptr, - __UNUSED__ struct wlr_buffer *released_wlr_buffer_ptr) + wlmtk_button_t *button_ptr, + struct wlr_buffer *released_wlr_buffer_ptr, + struct wlr_buffer *pressed_wlr_buffer_ptr) { - // FIXME. + if (NULL != button_ptr->released_wlr_buffer_ptr) { + wlr_buffer_unlock(button_ptr->released_wlr_buffer_ptr); + } + button_ptr->released_wlr_buffer_ptr = wlr_buffer_lock( + released_wlr_buffer_ptr); + + if (NULL != button_ptr->pressed_wlr_buffer_ptr) { + wlr_buffer_unlock(button_ptr->pressed_wlr_buffer_ptr); + } + button_ptr->pressed_wlr_buffer_ptr = wlr_buffer_lock( + pressed_wlr_buffer_ptr); + + if (button_ptr->pressed) { + wlmtk_buffer_set( + &button_ptr->super_buffer, + button_ptr->pressed_wlr_buffer_ptr); + } else { + wlmtk_buffer_set( + &button_ptr->super_buffer, + button_ptr->released_wlr_buffer_ptr); + } } /* == Local (static) methods =============================================== */ @@ -127,13 +145,13 @@ const wlmtk_button_impl_t fake_button_impl = { /** Exercises @ref wlmtk_button_init and @ref wlmtk_button_fini. */ void test_create_destroy(bs_test_t *test_ptr) { - struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + struct wlr_buffer *buf_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); wlmtk_button_t button; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_button_init(&button, &fake_button_impl, wlr_buffer_ptr, wlr_buffer_ptr)); - wlr_buffer_drop(wlr_buffer_ptr); + wlmtk_button_init(&button, &fake_button_impl, buf_ptr, buf_ptr)); + wlr_buffer_drop(buf_ptr); wlmtk_element_destroy(&button.super_buffer.super_element); } diff --git a/src/toolkit/button.h b/src/toolkit/button.h index c412f82b..c926c13c 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -48,6 +48,9 @@ struct _wlmtk_button_t { struct wlr_buffer *released_wlr_buffer_ptr; /** WLR buffer holding the button in pressed state. */ struct wlr_buffer *pressed_wlr_buffer_ptr; + + /** Whether the button is currently pressed. */ + bool pressed; }; /** From 1df3b52b8fc4e948e00c530203b5d3b7a24c1cfd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 8 Nov 2023 21:44:35 +0100 Subject: [PATCH 176/390] Updates dependencies. --- dependencies/drm | 2 +- dependencies/hwdata | 2 +- dependencies/libdisplay-info | 2 +- dependencies/pixman | 2 +- dependencies/seatd | 2 +- dependencies/wayland | 2 +- dependencies/wayland-protocols | 2 +- dependencies/wlroots | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dependencies/drm b/dependencies/drm index 5254fd11..a0b01143 160000 --- a/dependencies/drm +++ b/dependencies/drm @@ -1 +1 @@ -Subproject commit 5254fd1146b95a86fef1bb8e950d0146d829f3c4 +Subproject commit a0b011439d44e7d79ffed6dd2d372e60dc7f3b1b diff --git a/dependencies/hwdata b/dependencies/hwdata index b9ba5bc9..e27f08bd 160000 --- a/dependencies/hwdata +++ b/dependencies/hwdata @@ -1 +1 @@ -Subproject commit b9ba5bc9eecbeeff441806695b227c3c3de4755c +Subproject commit e27f08bda517100746000dacdd882b6a7e7ce19a diff --git a/dependencies/libdisplay-info b/dependencies/libdisplay-info index 8829bab6..ae6cb524 160000 --- a/dependencies/libdisplay-info +++ b/dependencies/libdisplay-info @@ -1 +1 @@ -Subproject commit 8829bab67a1a9264bf8404b76f9f7813cfb9c174 +Subproject commit ae6cb5242e40563bbea0048690e432a223f6f452 diff --git a/dependencies/pixman b/dependencies/pixman index 47a1c3d3..b4b789df 160000 --- a/dependencies/pixman +++ b/dependencies/pixman @@ -1 +1 @@ -Subproject commit 47a1c3d330cc7ea6ba2fa96eb288f4b2291d011c +Subproject commit b4b789df5b39cecdb598b35a3aa2ca9637029564 diff --git a/dependencies/seatd b/dependencies/seatd index 3e9ef69f..0746edbe 160000 --- a/dependencies/seatd +++ b/dependencies/seatd @@ -1 +1 @@ -Subproject commit 3e9ef69f14f630a719dd464f3c90a7932f1c8296 +Subproject commit 0746edbeaeb1c94a54bf833f6167b4a6b8237cbf diff --git a/dependencies/wayland b/dependencies/wayland index edb943dc..50ea9c5b 160000 --- a/dependencies/wayland +++ b/dependencies/wayland @@ -1 +1 @@ -Subproject commit edb943dc6464697ba13d7df277aef277721764b7 +Subproject commit 50ea9c5b1c08bac30be365dca05716a97ea65a92 diff --git a/dependencies/wayland-protocols b/dependencies/wayland-protocols index 479580db..87e0ce44 160000 --- a/dependencies/wayland-protocols +++ b/dependencies/wayland-protocols @@ -1 +1 @@ -Subproject commit 479580dbe39bdb9b0bd60e52187b0e6c58366ee0 +Subproject commit 87e0ce44f32e7bd00c9c609010204d794945b663 diff --git a/dependencies/wlroots b/dependencies/wlroots index 47bf87ad..5de9e1a9 160000 --- a/dependencies/wlroots +++ b/dependencies/wlroots @@ -1 +1 @@ -Subproject commit 47bf87ade2bd32395615a385ebde1fefbcdf79a2 +Subproject commit 5de9e1a99d6642c2d09d589aa37ff0a8945dcee1 From bdb1bfb854cb54f7f26f44544b1af42f62464e0a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 9 Nov 2023 20:32:53 +0100 Subject: [PATCH 177/390] Adds pointer handlers to wlmtk_buffer_t. --- src/toolkit/buffer.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ src/toolkit/buffer.h | 10 +++++++++ 2 files changed, 62 insertions(+) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index 9694f8c3..d789280b 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -42,6 +42,16 @@ static void handle_wlr_scene_buffer_node_destroy( struct wl_listener *listener_ptr, void *data_ptr); +static bool element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + uint32_t time_msec); +static bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void element_pointer_leave( + wlmtk_element_t *element_ptr); + /* == Data ================================================================= */ /** Method table for the buffer's virtual methods. */ @@ -49,6 +59,9 @@ static const wlmtk_element_impl_t super_element_impl = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, + .pointer_motion = element_pointer_motion, + .pointer_button = element_pointer_button, + .pointer_leave = element_pointer_leave, }; /* == Exported methods ===================================================== */ @@ -200,4 +213,43 @@ void handle_wlr_scene_buffer_node_destroy( wl_list_remove(&buffer_ptr->wlr_scene_buffer_node_destroy_listener.link); } +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_element_impl_t::pointer_motion. */ +bool element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + uint32_t time_msec) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_buffer_t, super_element); + if (NULL == buffer_ptr->impl.pointer_motion) return false; + + return buffer_ptr->impl.pointer_motion(buffer_ptr, x, y, time_msec); +} + +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_element_impl_t::pointer_button. */ +bool element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_buffer_t, super_element); + if (NULL == buffer_ptr->impl.pointer_button) return false; + + return buffer_ptr->impl.pointer_button(buffer_ptr, button_event_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_element_impl_t::pointer_leave. */ +void element_pointer_leave( + wlmtk_element_t *element_ptr) +{ + wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_buffer_t, super_element); + if (NULL == buffer_ptr->impl.pointer_leave) return; + + buffer_ptr->impl.pointer_leave(buffer_ptr); +} + /* == End of buffer.c ====================================================== */ diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index fcd42115..e5d7b23c 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -42,6 +42,16 @@ extern "C" { struct _wlmtk_buffer_impl_t { /** Destroys the implementation of the buffer. */ void (*destroy)(wlmtk_buffer_t *buffer_ptr); + + /** Optional. See @ref wlmtk_element_impl_t::pointer_motion. */ + bool (*pointer_motion)(wlmtk_buffer_t *buffer_ptr, + double x, double y, + uint32_t time_msec); + /** Optional. See @ref wlmtk_element_impl_t::pointer_button. */ + bool (*pointer_button)(wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr); + /** Optional. See @ref wlmtk_element_impl_t::pointer_leave. */ + void (*pointer_leave)(wlmtk_buffer_t *buffer_ptr); }; /** State of a texture-backed buffer. */ From 89078d63f14262286b0253c1949f60cdbe884af5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 9 Nov 2023 21:23:58 +0100 Subject: [PATCH 178/390] Adds pointer handlers and simplifies the button setup. --- src/toolkit/buffer.c | 19 +++-- src/toolkit/buffer.h | 4 +- src/toolkit/button.c | 72 +++++++++++++++--- src/toolkit/button.h | 9 +-- src/toolkit/element.h | 19 ++++- src/toolkit/resizebar.c | 162 +++++++++++++++++++++++----------------- src/toolkit/titlebar.c | 15 ++-- 7 files changed, 194 insertions(+), 106 deletions(-) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index d789280b..a9679bd0 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -69,8 +69,7 @@ static const wlmtk_element_impl_t super_element_impl = { /* ------------------------------------------------------------------------- */ bool wlmtk_buffer_init( wlmtk_buffer_t *buffer_ptr, - const wlmtk_buffer_impl_t *buffer_impl_ptr, - struct wlr_buffer *wlr_buffer_ptr) + const wlmtk_buffer_impl_t *buffer_impl_ptr) { BS_ASSERT(NULL != buffer_ptr); memset(buffer_ptr, 0, sizeof(wlmtk_buffer_t)); @@ -82,8 +81,6 @@ bool wlmtk_buffer_init( &buffer_ptr->super_element, &super_element_impl)) { return false; } - - wlmtk_buffer_set(buffer_ptr, wlr_buffer_ptr); return true; } @@ -111,7 +108,12 @@ void wlmtk_buffer_set( if (NULL != buffer_ptr->wlr_buffer_ptr) { wlr_buffer_unlock(buffer_ptr->wlr_buffer_ptr); } - buffer_ptr->wlr_buffer_ptr = wlr_buffer_lock(wlr_buffer_ptr); + + if (NULL != wlr_buffer_ptr) { + buffer_ptr->wlr_buffer_ptr = wlr_buffer_lock(wlr_buffer_ptr); + } else { + buffer_ptr->wlr_buffer_ptr = NULL; + } if (NULL != buffer_ptr->wlr_scene_buffer_ptr) { wlr_scene_buffer_set_buffer( @@ -188,6 +190,13 @@ void element_get_dimensions( if (NULL != left_ptr) *left_ptr = 0; if (NULL != top_ptr) *top_ptr = 0; + + if (NULL == buffer_ptr->wlr_buffer_ptr) { + if (NULL != right_ptr) *right_ptr = 0; + if (NULL != bottom_ptr) *bottom_ptr = 0; + return; + } + if (NULL != right_ptr) *right_ptr = buffer_ptr->wlr_buffer_ptr->width; if (NULL != bottom_ptr) *bottom_ptr = buffer_ptr->wlr_buffer_ptr->height; } diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index e5d7b23c..e4c942bc 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -76,14 +76,12 @@ struct _wlmtk_buffer_t { * * @param buffer_ptr * @param buffer_impl_ptr - * @param wlr_buffer_ptr * * @return true on success. */ bool wlmtk_buffer_init( wlmtk_buffer_t *buffer_ptr, - const wlmtk_buffer_impl_t *buffer_impl_ptr, - struct wlr_buffer *wlr_buffer_ptr); + const wlmtk_buffer_impl_t *buffer_impl_ptr); /** * Cleans up the buffer. diff --git a/src/toolkit/button.c b/src/toolkit/button.c index 01a8fb9b..a739c4af 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -31,12 +31,24 @@ /* == Declarations ========================================================= */ static void button_buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static bool buffer_pointer_motion( + wlmtk_buffer_t *buffer_ptr, + double x, double y, + uint32_t time_msec); +static bool buffer_pointer_button( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void buffer_pointer_leave( + wlmtk_buffer_t *buffer_ptr); /* == Data ================================================================= */ /** Virtual method table for @ref wlmtk_button_t::super_buffer. */ static const wlmtk_buffer_impl_t button_buffer_impl = { .destroy = button_buffer_destroy, + .pointer_motion = buffer_pointer_motion, + .pointer_button = buffer_pointer_button, + .pointer_leave = buffer_pointer_leave, }; /* == Exported methods ===================================================== */ @@ -44,9 +56,7 @@ static const wlmtk_buffer_impl_t button_buffer_impl = { /* ------------------------------------------------------------------------- */ bool wlmtk_button_init( wlmtk_button_t *button_ptr, - const wlmtk_button_impl_t *button_impl_ptr, - struct wlr_buffer *released_wlr_buffer_ptr, - struct wlr_buffer *pressed_wlr_buffer_ptr) + const wlmtk_button_impl_t *button_impl_ptr) { BS_ASSERT(NULL != button_ptr); memset(button_ptr, 0, sizeof(wlmtk_button_t)); @@ -56,15 +66,11 @@ bool wlmtk_button_init( if (!wlmtk_buffer_init( &button_ptr->super_buffer, - &button_buffer_impl, - released_wlr_buffer_ptr)) { + &button_buffer_impl)) { wlmtk_button_fini(button_ptr); return false; } - wlmtk_button_set( - button_ptr, released_wlr_buffer_ptr, pressed_wlr_buffer_ptr); - return true; } @@ -123,6 +129,51 @@ void button_buffer_destroy(wlmtk_buffer_t *buffer_ptr) button_ptr->impl.destroy(button_ptr); } +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_buffer_impl_t::pointer_motion. */ +bool buffer_pointer_motion( + wlmtk_buffer_t *buffer_ptr, + __UNUSED__ double x, + __UNUSED__ double y, + __UNUSED__ uint32_t time_msec) +{ + wlmtk_button_t *button_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_button_t, super_buffer); + + if (!button_ptr->pointer_inside) { + bs_log(BS_INFO, "FIXME: enter."); + } + button_ptr->pointer_inside = true; + return true; +} + +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_buffer_impl_t::pointer_button. */ +bool buffer_pointer_button( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_button_t *button_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_button_t, super_buffer); + + bs_log(BS_INFO, "FIXME: event %p for %p", button_event_ptr, button_ptr); + return true; +} + +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_buffer_impl_t::pointer_leave. */ +void buffer_pointer_leave( + wlmtk_buffer_t *buffer_ptr) +{ + wlmtk_button_t *button_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_button_t, super_buffer); + + if (button_ptr->pointer_inside) { + bs_log(BS_INFO, "FIXME: leave."); + } + button_ptr->pointer_inside = false; +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); @@ -145,14 +196,11 @@ const wlmtk_button_impl_t fake_button_impl = { /** Exercises @ref wlmtk_button_init and @ref wlmtk_button_fini. */ void test_create_destroy(bs_test_t *test_ptr) { - struct wlr_buffer *buf_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); wlmtk_button_t button; BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_button_init(&button, &fake_button_impl, buf_ptr, buf_ptr)); - wlr_buffer_drop(buf_ptr); - + wlmtk_button_init(&button, &fake_button_impl)); wlmtk_element_destroy(&button.super_buffer.super_element); } diff --git a/src/toolkit/button.h b/src/toolkit/button.h index c926c13c..2640245f 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -51,6 +51,9 @@ struct _wlmtk_button_t { /** Whether the button is currently pressed. */ bool pressed; + + /** Whether the pointer is currently inside. */ + bool pointer_inside; }; /** @@ -58,16 +61,12 @@ struct _wlmtk_button_t { * * @param button_ptr * @param button_impl_ptr - * @param released_wlr_buffer_ptr - * @param pressed_wlr_buffer_ptr * * @return true on success. */ bool wlmtk_button_init( wlmtk_button_t *button_ptr, - const wlmtk_button_impl_t *button_impl_ptr, - struct wlr_buffer *released_wlr_buffer_ptr, - struct wlr_buffer *pressed_wlr_buffer_ptr); + const wlmtk_button_impl_t *button_impl_ptr); /** * Cleans up the button. diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 66babc94..b4f1ee44 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -77,13 +77,24 @@ struct _wlmtk_element_impl_t { * as having pointer focus. */ bool (*pointer_motion)(wlmtk_element_t *element_ptr, - double x, double y, - uint32_t time_msec); - /** Indicates pointer button event. */ + double x, double y, + uint32_t time_msec); + /** + * Indicates pointer button event. + * + * @param element_ptr + * @param button_event_ptr + * + * @return true If the button event was consumed. + */ bool (*pointer_button)(wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); - /** Indicates the pointer has left the element's area. */ + /** + * Indicates the pointer has left the element's area. + * + * @param element_ptr + */ void (*pointer_leave)(wlmtk_element_t *element_ptr); }; diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 7878f921..d6e1ebc4 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -8,6 +8,7 @@ #include "box.h" #include "buffer.h" +#include "button.h" #include "gfxbuf.h" #include "primitives.h" @@ -20,7 +21,7 @@ /* == Declarations ========================================================= */ /** Forward declaration: Element of the resizebar. */ -typedef struct _wlmtk_resizebar_element_t wlmtk_resizebar_element_t ; +typedef struct _wlmtk_resizebar_button_t wlmtk_resizebar_button_t ; /** State of the title bar. */ struct _wlmtk_resizebar_t { @@ -36,25 +37,23 @@ struct _wlmtk_resizebar_t { bs_gfxbuf_t *gfxbuf_ptr; /** Element of the resizebar. */ - wlmtk_resizebar_element_t *element_ptr; + wlmtk_resizebar_button_t *button_ptr; }; /** State of an element of the resize bar. */ -struct _wlmtk_resizebar_element_t { +struct _wlmtk_resizebar_button_t { /** Superclass: Buffer. */ - wlmtk_buffer_t super_buffer; - /** The buffer. */ - struct wlr_buffer *wlr_buffer_ptr; + wlmtk_button_t super_button; }; -static wlmtk_resizebar_element_t *wlmtk_resizebar_element_create( +static wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( bs_gfxbuf_t *gfxbuf_ptr, int width, const wlmtk_resizebar_style_t *style_ptr); -static void wlmtk_resizebar_element_destroy( - wlmtk_resizebar_element_t *element_ptr); -static bool wlmtk_resizebar_element_redraw( - wlmtk_resizebar_element_t *element_ptr, +static void wlmtk_resizebar_button_destroy( + wlmtk_resizebar_button_t *resizebar_button_ptr); +static bool wlmtk_resizebar_button_redraw( + wlmtk_resizebar_button_t *resizebar_button_ptr, bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, @@ -63,7 +62,7 @@ static bool wlmtk_resizebar_element_redraw( static void resizebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width); -static void element_buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static void button_destroy(wlmtk_button_t *button_ptr); /* == Data ================================================================= */ @@ -73,8 +72,8 @@ static const wlmtk_box_impl_t resizebar_box_impl = { }; /** Buffer implementation for title of the title bar. */ -static const wlmtk_buffer_impl_t element_buffer_impl = { - .destroy = element_buffer_destroy +static const wlmtk_button_impl_t element_button_impl = { + .destroy = button_destroy }; /* == Exported methods ===================================================== */ @@ -101,17 +100,17 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } - resizebar_ptr->element_ptr = wlmtk_resizebar_element_create( + resizebar_ptr->button_ptr = wlmtk_resizebar_button_create( resizebar_ptr->gfxbuf_ptr, width, &resizebar_ptr->style); - if (NULL == resizebar_ptr->element_ptr) { + if (NULL == resizebar_ptr->button_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } wlmtk_element_set_visible( - &resizebar_ptr->element_ptr->super_buffer.super_element, true); + &resizebar_ptr->button_ptr->super_button.super_buffer.super_element, true); wlmtk_container_add_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->element_ptr->super_buffer.super_element); + &resizebar_ptr->button_ptr->super_button.super_buffer.super_element); return resizebar_ptr; } @@ -119,12 +118,12 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( /* ------------------------------------------------------------------------- */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) { - if (NULL != resizebar_ptr->element_ptr) { + if (NULL != resizebar_ptr->button_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->element_ptr->super_buffer.super_element); - wlmtk_resizebar_element_destroy(resizebar_ptr->element_ptr); - resizebar_ptr->element_ptr = NULL; + &resizebar_ptr->button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_destroy(resizebar_ptr->button_ptr); + resizebar_ptr->button_ptr = NULL; } if (NULL != resizebar_ptr->gfxbuf_ptr) { @@ -145,8 +144,8 @@ bool wlmtk_resizebar_set_width( if (!redraw_buffers(resizebar_ptr, width)) return false; BS_ASSERT(width == resizebar_ptr->width); - if (!wlmtk_resizebar_element_redraw( - resizebar_ptr->element_ptr, + if (!wlmtk_resizebar_button_redraw( + resizebar_ptr->button_ptr, resizebar_ptr->gfxbuf_ptr, 0, width, &resizebar_ptr->style)) { @@ -166,67 +165,61 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) /* ------------------------------------------------------------------------- */ /** - * Creates a resizebar element. + * Creates a resizebar button. * * @param gfxbuf_ptr * @param width * @param style_ptr * - * @return Pointer to the element. + * @return Pointer to the resizebar button. */ -wlmtk_resizebar_element_t *wlmtk_resizebar_element_create( +wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( bs_gfxbuf_t *gfxbuf_ptr, int width, const wlmtk_resizebar_style_t *style_ptr) { - wlmtk_resizebar_element_t *element_ptr = logged_calloc( - 1, sizeof(wlmtk_resizebar_element_t)); - if (NULL == element_ptr) return NULL; + wlmtk_resizebar_button_t *resizebar_button = logged_calloc( + 1, sizeof(wlmtk_resizebar_button_t)); + if (NULL == resizebar_button) return NULL; + + if (!wlmtk_button_init( + &resizebar_button->super_button, + &element_button_impl)) { + wlmtk_resizebar_button_destroy(resizebar_button); + return NULL; + } - if (!wlmtk_resizebar_element_redraw( - element_ptr, + if (!wlmtk_resizebar_button_redraw( + resizebar_button, gfxbuf_ptr, 0, width, style_ptr)) { - wlmtk_resizebar_element_destroy(element_ptr); + wlmtk_resizebar_button_destroy(resizebar_button); return NULL; } - if (!wlmtk_buffer_init( - &element_ptr->super_buffer, - &element_buffer_impl, - element_ptr->wlr_buffer_ptr)) { - wlmtk_resizebar_element_destroy(element_ptr); - return NULL; - } - - return element_ptr; + return resizebar_button; } /* ------------------------------------------------------------------------- */ /** * Destroys the resizebar element. * - * @param element_ptr + * @param resizebar_button_ptr */ -void wlmtk_resizebar_element_destroy( - wlmtk_resizebar_element_t *element_ptr) +void wlmtk_resizebar_button_destroy( + wlmtk_resizebar_button_t *resizebar_button_ptr) { - if (NULL != element_ptr->wlr_buffer_ptr) { - wlr_buffer_drop(element_ptr->wlr_buffer_ptr); - element_ptr->wlr_buffer_ptr = NULL; - } - - wlmtk_buffer_fini(&element_ptr->super_buffer); - free(element_ptr); + wlmtk_button_fini(&resizebar_button_ptr->super_button); + free(resizebar_button_ptr); } /* ------------------------------------------------------------------------- */ /** * Redraws the element, with updated position and width. * - * @param element_ptr + * @param resizebar_button_ptr * @param gfxbuf_ptr * @param position * @param width @@ -234,38 +227,69 @@ void wlmtk_resizebar_element_destroy( * * @return true on success. */ -bool wlmtk_resizebar_element_redraw( - wlmtk_resizebar_element_t *element_ptr, +bool wlmtk_resizebar_button_redraw( + wlmtk_resizebar_button_t *resizebar_button_ptr, bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, const wlmtk_resizebar_style_t *style_ptr) { - struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + struct wlr_buffer *released_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( width, style_ptr->height); - if (NULL == wlr_buffer_ptr) return false; + if (NULL == released_wlr_buffer_ptr) return false; bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(released_wlr_buffer_ptr), 0, 0, gfxbuf_ptr, position, 0, width, style_ptr->height); - cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(released_wlr_buffer_ptr); if (NULL == cairo_ptr) { - wlr_buffer_drop(wlr_buffer_ptr); + wlr_buffer_drop(released_wlr_buffer_ptr); return false; } wlmaker_primitives_draw_bezel_at( cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); cairo_destroy(cairo_ptr); - if (NULL != element_ptr->wlr_buffer_ptr) { - wlr_buffer_drop(element_ptr->wlr_buffer_ptr); + + + + + struct wlr_buffer *pressed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + width, style_ptr->height); + if (NULL == pressed_wlr_buffer_ptr) { + wlr_buffer_drop(released_wlr_buffer_ptr); + return false; + } + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(pressed_wlr_buffer_ptr), + 0, 0, + gfxbuf_ptr, + position, 0, + width, style_ptr->height); + + cairo_ptr = cairo_create_from_wlr_buffer(pressed_wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(released_wlr_buffer_ptr); + wlr_buffer_drop(pressed_wlr_buffer_ptr); + return false; } - element_ptr->wlr_buffer_ptr = wlr_buffer_ptr; - wlmtk_buffer_set(&element_ptr->super_buffer, element_ptr->wlr_buffer_ptr); + wlmaker_primitives_draw_bezel_at( + cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); + cairo_destroy(cairo_ptr); + + // Will take ownershp of the buffers. + wlmtk_button_set( + &resizebar_button_ptr->super_button, + pressed_wlr_buffer_ptr, + released_wlr_buffer_ptr); + + wlr_buffer_drop(released_wlr_buffer_ptr); + wlr_buffer_drop(pressed_wlr_buffer_ptr); return true; } @@ -306,12 +330,12 @@ bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width) } /* ------------------------------------------------------------------------- */ -/** Dtor. Forwards to @ref wlmtk_resizebar_element_destroy. */ -void element_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +/** Dtor. Forwards to @ref wlmtk_resizebar_button_destroy. */ +void button_destroy(wlmtk_button_t *button_ptr) { - wlmtk_resizebar_element_t *element_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_resizebar_element_t, super_buffer); - wlmtk_resizebar_element_destroy(element_ptr); + wlmtk_resizebar_button_t *resizebar_button_ptr = BS_CONTAINER_OF( + button_ptr, wlmtk_resizebar_button_t, super_button); + wlmtk_resizebar_button_destroy(resizebar_button_ptr); } /* == Unit tests =========================================================== */ diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index ec48530d..7d458c60 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -304,6 +304,13 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( 1, sizeof(wlmtk_titlebar_title_t)); if (NULL == title_ptr) return NULL; + if (!wlmtk_buffer_init( + &title_ptr->super_buffer, + &title_buffer_impl)) { + wlmtk_titlebar_title_destroy(title_ptr); + return NULL; + } + if (!title_redraw_buffers( title_ptr, focussed_gfxbuf_ptr, @@ -313,14 +320,6 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( return NULL; } - if (!wlmtk_buffer_init( - &title_ptr->super_buffer, - &title_buffer_impl, - title_ptr->focussed_wlr_buffer_ptr)) { - wlmtk_titlebar_title_destroy(title_ptr); - return NULL; - } - title_set_activated(title_ptr, activated); return title_ptr; } From cc470f7758f15c480cd30a793332c50ed2a77b62 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 9 Nov 2023 21:31:43 +0100 Subject: [PATCH 179/390] Updates button state based on pointer event. Won't handle leave/re-entry correctly. --- src/toolkit/button.c | 56 ++++++++++++++++++++++++++++------------- src/toolkit/resizebar.c | 6 +---- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index a739c4af..cfc0cdc6 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -40,6 +40,7 @@ static bool buffer_pointer_button( const wlmtk_button_event_t *button_event_ptr); static void buffer_pointer_leave( wlmtk_buffer_t *buffer_ptr); +static void apply_state(wlmtk_button_t *button_ptr); /* == Data ================================================================= */ @@ -107,15 +108,7 @@ void wlmtk_button_set( button_ptr->pressed_wlr_buffer_ptr = wlr_buffer_lock( pressed_wlr_buffer_ptr); - if (button_ptr->pressed) { - wlmtk_buffer_set( - &button_ptr->super_buffer, - button_ptr->pressed_wlr_buffer_ptr); - } else { - wlmtk_buffer_set( - &button_ptr->super_buffer, - button_ptr->released_wlr_buffer_ptr); - } + apply_state(button_ptr); } /* == Local (static) methods =============================================== */ @@ -139,10 +132,6 @@ bool buffer_pointer_motion( { wlmtk_button_t *button_ptr = BS_CONTAINER_OF( buffer_ptr, wlmtk_button_t, super_buffer); - - if (!button_ptr->pointer_inside) { - bs_log(BS_INFO, "FIXME: enter."); - } button_ptr->pointer_inside = true; return true; } @@ -156,7 +145,26 @@ bool buffer_pointer_button( wlmtk_button_t *button_ptr = BS_CONTAINER_OF( buffer_ptr, wlmtk_button_t, super_buffer); - bs_log(BS_INFO, "FIXME: event %p for %p", button_event_ptr, button_ptr); + if (button_event_ptr->button != BTN_LEFT) return false; + + switch (button_event_ptr->type) { + case WLMTK_BUTTON_DOWN: + button_ptr->pressed = true; + apply_state(button_ptr); + break; + + case WLMTK_BUTTON_UP: + button_ptr->pressed = false; + apply_state(button_ptr); + break; + + case WLMTK_BUTTON_CLICK: + bs_log(BS_INFO, "FIXME: Click!"); + break; + default: + break; + } + return true; } @@ -168,10 +176,24 @@ void buffer_pointer_leave( wlmtk_button_t *button_ptr = BS_CONTAINER_OF( buffer_ptr, wlmtk_button_t, super_buffer); - if (button_ptr->pointer_inside) { - bs_log(BS_INFO, "FIXME: leave."); - } button_ptr->pointer_inside = false; + button_ptr->pressed = false; + apply_state(button_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Sets the appropriate texture for the button. */ +void apply_state(wlmtk_button_t *button_ptr) +{ + if (button_ptr->pressed) { + wlmtk_buffer_set( + &button_ptr->super_buffer, + button_ptr->pressed_wlr_buffer_ptr); + } else { + wlmtk_buffer_set( + &button_ptr->super_buffer, + button_ptr->released_wlr_buffer_ptr); + } } /* == Unit tests =========================================================== */ diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index d6e1ebc4..f7472c1e 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -251,13 +251,9 @@ bool wlmtk_resizebar_button_redraw( return false; } wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); + cairo_ptr, 0, 0, width, style_ptr->height, 1.0, false); cairo_destroy(cairo_ptr); - - - - struct wlr_buffer *pressed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( width, style_ptr->height); if (NULL == pressed_wlr_buffer_ptr) { From 806ed26430deb96bb04bfc9136b4b47fbdf61c5c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 16:04:30 +0100 Subject: [PATCH 180/390] Adds test cases for button. --- src/toolkit/button.c | 151 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 3 deletions(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index cfc0cdc6..bfcc2431 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -94,8 +94,17 @@ void wlmtk_button_fini(wlmtk_button_t *button_ptr) void wlmtk_button_set( wlmtk_button_t *button_ptr, struct wlr_buffer *released_wlr_buffer_ptr, - struct wlr_buffer *pressed_wlr_buffer_ptr) + struct wlr_buffer *pressed_wlr_buffer_ptr ) { + if (NULL == released_wlr_buffer_ptr) { + BS_ASSERT(NULL == pressed_wlr_buffer_ptr); + } else { + BS_ASSERT(released_wlr_buffer_ptr->width == + pressed_wlr_buffer_ptr->width); + BS_ASSERT(released_wlr_buffer_ptr->height == + pressed_wlr_buffer_ptr->height); + } + if (NULL != button_ptr->released_wlr_buffer_ptr) { wlr_buffer_unlock(button_ptr->released_wlr_buffer_ptr); } @@ -133,6 +142,7 @@ bool buffer_pointer_motion( wlmtk_button_t *button_ptr = BS_CONTAINER_OF( buffer_ptr, wlmtk_button_t, super_buffer); button_ptr->pointer_inside = true; + apply_state(button_ptr); return true; } @@ -177,7 +187,6 @@ void buffer_pointer_leave( buffer_ptr, wlmtk_button_t, super_buffer); button_ptr->pointer_inside = false; - button_ptr->pressed = false; apply_state(button_ptr); } @@ -185,7 +194,7 @@ void buffer_pointer_leave( /** Sets the appropriate texture for the button. */ void apply_state(wlmtk_button_t *button_ptr) { - if (button_ptr->pressed) { + if (button_ptr->pointer_inside && button_ptr->pressed) { wlmtk_buffer_set( &button_ptr->super_buffer, button_ptr->pressed_wlr_buffer_ptr); @@ -199,10 +208,16 @@ void apply_state(wlmtk_button_t *button_ptr) /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_press_release(bs_test_t *test_ptr); +static void test_press_release_outside(bs_test_t *test_ptr); +static void test_press_right(bs_test_t *test_ptr); /** Test case definition. */ const bs_test_case_t wlmtk_button_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "press_release", test_press_release }, + { 1, "press_release_outside", test_press_release_outside }, + { 1, "press_right", test_press_right }, { 0, NULL, NULL } }; @@ -226,4 +241,134 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_element_destroy(&button.super_buffer.super_element); } +/* ------------------------------------------------------------------------- */ +/** Tests button pressing & releasing. */ +void test_press_release(bs_test_t *test_ptr) +{ + wlmtk_button_t button; + BS_ASSERT(wlmtk_button_init(&button, &fake_button_impl)); + + struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + wlmtk_button_set(&button, r_ptr, p_ptr); + + wlmtk_button_event_t event = { .button = BTN_LEFT, .time_msec = 42 }; + wlmtk_element_t *element_ptr = &button.super_buffer.super_element; + + // Initial state: released. + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 0, 0, 41)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + // Button down: pressed. + event.type = WLMTK_BUTTON_DOWN; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &event)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, p_ptr); + + // Pointer leaves the area: released. + wlmtk_element_pointer_leave(element_ptr); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + // Pointer re-enters the area: pressed. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 0, 0, 41)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, p_ptr); + + // Button up: released. + event.type = WLMTK_BUTTON_UP; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &event)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + wlr_buffer_drop(r_ptr); + wlr_buffer_drop(p_ptr); + wlmtk_button_fini(&button); +} + +/* ------------------------------------------------------------------------- */ +/** Tests button when releasing outside the pointer focus. */ +void test_press_release_outside(bs_test_t *test_ptr) +{ + wlmtk_button_t button; + BS_ASSERT(wlmtk_button_init(&button, &fake_button_impl)); + + struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + wlmtk_button_set(&button, r_ptr, p_ptr); + + wlmtk_button_event_t event = { .button = BTN_LEFT, .time_msec = 42 }; + wlmtk_element_t *element_ptr = &button.super_buffer.super_element; + + // Enter the ara. Released. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 0, 0, 41)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + // Button down: pressed. + event.type = WLMTK_BUTTON_DOWN; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &event)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, p_ptr); + + // Pointer leaves the area: released. + wlmtk_element_pointer_leave(element_ptr); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + // Button up, outside the area. Then, re-enter: Still released. + event.type = WLMTK_BUTTON_UP; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &event)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 0, 0, 41)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + wlr_buffer_drop(r_ptr); + wlr_buffer_drop(p_ptr); + wlmtk_button_fini(&button); +} + +/* ------------------------------------------------------------------------- */ +/** Tests button when releasing outside the pointer focus. */ +void test_press_right(bs_test_t *test_ptr) +{ + wlmtk_button_t button; + BS_ASSERT(wlmtk_button_init(&button, &fake_button_impl)); + + struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); + wlmtk_button_set(&button, r_ptr, p_ptr); + + wlmtk_button_event_t event = { + .button = BTN_RIGHT, .type = WLMTK_BUTTON_DOWN, .time_msec = 42, + }; + wlmtk_element_t *element_ptr = &button.super_buffer.super_element; + + // Enter the ara. Released. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 0, 0, 41)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + // Right button down: Not claimed, and remains released. + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &event)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + + wlr_buffer_drop(r_ptr); + wlr_buffer_drop(p_ptr); + wlmtk_button_fini(&button); +} + /* == End of button.c ====================================================== */ From 163cc1ed2063daf475c71aa06dbde30859ebc3dd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 17:04:11 +0100 Subject: [PATCH 181/390] Ensures UP, CLICK and DOUBLE_CLICK events are sent to the preceding DOWN receiver. At least for BTN_LEFT clicks, for now... --- src/toolkit/button.c | 1 + src/toolkit/container.c | 124 +++++++++++++++++++++++++++++++++++++--- src/toolkit/container.h | 2 + 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index bfcc2431..4643772b 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -171,6 +171,7 @@ bool buffer_pointer_button( case WLMTK_BUTTON_CLICK: bs_log(BS_INFO, "FIXME: Click!"); break; + default: break; } diff --git a/src/toolkit/container.c b/src/toolkit/container.c index b11f24b4..912f8840 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -200,6 +200,10 @@ void wlmtk_container_remove_element( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); + if (container_ptr->left_button_element_ptr == element_ptr) { + container_ptr->left_button_element_ptr = NULL; + } + wlmtk_container_update_layout(container_ptr); BS_ASSERT(element_ptr != container_ptr->pointer_focus_element_ptr); } @@ -388,6 +392,48 @@ bool element_pointer_button( { wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); + bool accepted = false; + + // TODO: Generalize this for non-LEFT buttons. + if (BTN_LEFT == button_event_ptr->button) { + + switch (button_event_ptr->type) { + case WLMTK_BUTTON_DOWN: + // Forward to the pointer focus element, if any. If it + // was accepted: remember the element. + if (NULL != container_ptr->pointer_focus_element_ptr) { + accepted = wlmtk_element_pointer_button( + container_ptr->pointer_focus_element_ptr, + button_event_ptr); + if (accepted) { + container_ptr->left_button_element_ptr = + container_ptr->pointer_focus_element_ptr; + } else { + container_ptr->left_button_element_ptr = NULL; + } + } + break; + + case WLMTK_BUTTON_UP: + case WLMTK_BUTTON_CLICK: + case WLMTK_BUTTON_DOUBLE_CLICK: + // Forward to the element that received the DOWN, if any. + if (NULL != container_ptr->left_button_element_ptr) { + accepted = wlmtk_element_pointer_button( + container_ptr->left_button_element_ptr, + button_event_ptr); + } + break; + + default: // Uh, don't know about this... + bs_log(BS_FATAL, "Unhandled button type %d", + button_event_ptr->type); + } + + return accepted; + } + + if (NULL == container_ptr->pointer_focus_element_ptr) return false; return wlmtk_element_pointer_button( @@ -490,7 +536,7 @@ bool update_pointer_focus_at( } // Getting here implies we didn't have an element catching the motion, - // so it must have happened outside our araea. We also should free + // so it must have happened outside our araea. We also should reset // pointer focus element now. if (NULL != container_ptr->pointer_focus_element_ptr) { wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); @@ -1026,33 +1072,93 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests that pointer button is forwarded to element with pointer focus. */ +/** Tests that pointer DOWN is forwarded to element with pointer focus. */ void test_pointer_button(bs_test_t *test_ptr) { wlmtk_container_t container; BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); - wlmtk_fake_element_t *elem_ptr = wlmtk_fake_element_create(); - wlmtk_element_set_visible(&elem_ptr->element, true); - wlmtk_container_add_element(&container, &elem_ptr->element); + wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&elem1_ptr->element, true); + elem1_ptr->width = 1; + elem1_ptr->height = 1; + wlmtk_container_add_element(&container, &elem1_ptr->element); - wlmtk_button_event_t button = {}; + wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_position(&elem2_ptr->element, 10, 10); + wlmtk_element_set_visible(&elem2_ptr->element, true); + wlmtk_container_add_element_before(&container, NULL, &elem2_ptr->element); + + wlmtk_button_event_t button = { + .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN + }; BS_TEST_VERIFY_FALSE( test_ptr, wlmtk_element_pointer_button(&container.super_element, &button)); + // DOWN events go to the focussed element. BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7)); BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container.left_button_element_ptr); BS_TEST_VERIFY_TRUE( - test_ptr, elem_ptr->pointer_button_called); + test_ptr, elem1_ptr->pointer_button_called); - wlmtk_container_remove_element(&container, &elem_ptr->element); - wlmtk_element_destroy(&elem_ptr->element); + // Moves, pointer focus is now on elem2. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(&container.super_element, 10, 10, 7)); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem2_ptr->element, + container.pointer_focus_element_ptr); + + // The UP event is still received by elem1. + elem1_ptr->pointer_button_called = false; + button.type = WLMTK_BUTTON_UP; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_TRUE( + test_ptr, elem1_ptr->pointer_button_called); + + // New DOWN event goes to elem2, though. + elem2_ptr->pointer_button_called = false; + button.type = WLMTK_BUTTON_DOWN; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_TRUE( + test_ptr, elem2_ptr->pointer_button_called); + + // And UP event now goes to elem2. + elem2_ptr->pointer_button_called = false; + button.type = WLMTK_BUTTON_UP; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_TRUE( + test_ptr, elem2_ptr->pointer_button_called); + + // After removing, further UP events won't be accidentally sent there. + wlmtk_container_remove_element(&container, &elem1_ptr->element); + wlmtk_container_remove_element(&container, &elem2_ptr->element); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + container.left_button_element_ptr); + wlmtk_element_destroy(&elem1_ptr->element); wlmtk_container_fini(&container); } + /* == End of container.c =================================================== */ diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 05a3ae49..960142a3 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -71,6 +71,8 @@ struct _wlmtk_container_t { /** Stores the element with current pointer focus. May be NULL. */ wlmtk_element_t *pointer_focus_element_ptr; + /** Stores the element which received WLMTK_BUTTON_DOWN for BTN_LEFT. */ + wlmtk_element_t *left_button_element_ptr; }; /** From 644f11fa0b52d635347c41966ab69375e1c12e67 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 17:06:11 +0100 Subject: [PATCH 182/390] Permits positioning the resizebar button. --- src/toolkit/resizebar.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index f7472c1e..596490c3 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -48,6 +48,7 @@ struct _wlmtk_resizebar_button_t { static wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( bs_gfxbuf_t *gfxbuf_ptr, + int position, int width, const wlmtk_resizebar_style_t *style_ptr); static void wlmtk_resizebar_button_destroy( @@ -101,7 +102,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( } resizebar_ptr->button_ptr = wlmtk_resizebar_button_create( - resizebar_ptr->gfxbuf_ptr, width, &resizebar_ptr->style); + resizebar_ptr->gfxbuf_ptr, 0, width, &resizebar_ptr->style); if (NULL == resizebar_ptr->button_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -168,6 +169,7 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) * Creates a resizebar button. * * @param gfxbuf_ptr + * @param position * @param width * @param style_ptr * @@ -175,6 +177,7 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) */ wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( bs_gfxbuf_t *gfxbuf_ptr, + int position, int width, const wlmtk_resizebar_style_t *style_ptr) { @@ -192,7 +195,7 @@ wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( if (!wlmtk_resizebar_button_redraw( resizebar_button, gfxbuf_ptr, - 0, + position, width, style_ptr)) { wlmtk_resizebar_button_destroy(resizebar_button); From 40abee0d47c6b73cc1bd783e824338e6bde6b2fb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 17:34:47 +0100 Subject: [PATCH 183/390] Makes resizebar elements of adaptable size. --- src/toolkit/resizebar.c | 72 ++++++++++++++++++----------------------- src/toolkit/resizebar.h | 2 ++ src/toolkit/window.c | 3 +- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 596490c3..77441e0c 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -36,8 +36,8 @@ struct _wlmtk_resizebar_t { /** Background. */ bs_gfxbuf_t *gfxbuf_ptr; - /** Element of the resizebar. */ - wlmtk_resizebar_button_t *button_ptr; + /** Center element of the resizebar. */ + wlmtk_resizebar_button_t *center_button_ptr; }; /** State of an element of the resize bar. */ @@ -46,11 +46,7 @@ struct _wlmtk_resizebar_button_t { wlmtk_button_t super_button; }; -static wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( - bs_gfxbuf_t *gfxbuf_ptr, - int position, - int width, - const wlmtk_resizebar_style_t *style_ptr); +static wlmtk_resizebar_button_t *wlmtk_resizebar_button_create(void); static void wlmtk_resizebar_button_destroy( wlmtk_resizebar_button_t *resizebar_button_ptr); static bool wlmtk_resizebar_button_redraw( @@ -101,17 +97,19 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } - resizebar_ptr->button_ptr = wlmtk_resizebar_button_create( - resizebar_ptr->gfxbuf_ptr, 0, width, &resizebar_ptr->style); - if (NULL == resizebar_ptr->button_ptr) { + resizebar_ptr->center_button_ptr = wlmtk_resizebar_button_create(); + if (NULL == resizebar_ptr->center_button_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_element_set_visible( - &resizebar_ptr->button_ptr->super_button.super_buffer.super_element, true); wlmtk_container_add_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->button_ptr->super_button.super_buffer.super_element); + &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element); + + if (!wlmtk_resizebar_set_width(resizebar_ptr, width)) { + wlmtk_resizebar_destroy(resizebar_ptr); + return NULL; + } return resizebar_ptr; } @@ -119,12 +117,12 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( /* ------------------------------------------------------------------------- */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) { - if (NULL != resizebar_ptr->button_ptr) { + if (NULL != resizebar_ptr->center_button_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->button_ptr->super_button.super_buffer.super_element); - wlmtk_resizebar_button_destroy(resizebar_ptr->button_ptr); - resizebar_ptr->button_ptr = NULL; + &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_destroy(resizebar_ptr->center_button_ptr); + resizebar_ptr->center_button_ptr = NULL; } if (NULL != resizebar_ptr->gfxbuf_ptr) { @@ -138,17 +136,30 @@ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) /* ------------------------------------------------------------------------- */ bool wlmtk_resizebar_set_width( - wlmtk_resizebar_t * resizebar_ptr, + wlmtk_resizebar_t *resizebar_ptr, unsigned width) { if (resizebar_ptr->width == width) return true; if (!redraw_buffers(resizebar_ptr, width)) return false; BS_ASSERT(width == resizebar_ptr->width); + BS_ASSERT(width == resizebar_ptr->gfxbuf_ptr->width); + + int right_corner_width = BS_MIN( + (int)width, (int)resizebar_ptr->style.corner_width); + int left_corner_width = BS_MAX( + 0, BS_MIN((int)width - right_corner_width, + (int)resizebar_ptr->style.corner_width)); + int center_width = BS_MAX( + 0, (int)width - right_corner_width - left_corner_width); + + wlmtk_element_set_visible( + &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element, + 0 < center_width); if (!wlmtk_resizebar_button_redraw( - resizebar_ptr->button_ptr, + resizebar_ptr->center_button_ptr, resizebar_ptr->gfxbuf_ptr, - 0, width, + left_corner_width, center_width, &resizebar_ptr->style)) { return false; } @@ -168,18 +179,9 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) /** * Creates a resizebar button. * - * @param gfxbuf_ptr - * @param position - * @param width - * @param style_ptr - * * @return Pointer to the resizebar button. */ -wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( - bs_gfxbuf_t *gfxbuf_ptr, - int position, - int width, - const wlmtk_resizebar_style_t *style_ptr) +wlmtk_resizebar_button_t *wlmtk_resizebar_button_create() { wlmtk_resizebar_button_t *resizebar_button = logged_calloc( 1, sizeof(wlmtk_resizebar_button_t)); @@ -192,16 +194,6 @@ wlmtk_resizebar_button_t *wlmtk_resizebar_button_create( return NULL; } - if (!wlmtk_resizebar_button_redraw( - resizebar_button, - gfxbuf_ptr, - position, - width, - style_ptr)) { - wlmtk_resizebar_button_destroy(resizebar_button); - return NULL; - } - return resizebar_button; } diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 048fb98b..8334bbd7 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -22,6 +22,8 @@ typedef struct { wlmtk_style_fill_t fill; /** Height of the resize bar. */ unsigned height; + /** Width of the corners. */ + unsigned corner_width; } wlmtk_resizebar_style_t; /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7588304e..cd548063 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -106,7 +106,8 @@ static const wlmtk_resizebar_style_t resizebar_style = { .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xffc2c0c5 }} }, - .height = 8, + .height = 20, // FIXME: 7 + .corner_width = 29, }; /* == Exported methods ===================================================== */ From 379562959eaf3c14b53a76eefa41603b349cfbd3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 17:40:12 +0100 Subject: [PATCH 184/390] Adds left and right corners of resizebar. --- src/toolkit/resizebar.c | 61 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 77441e0c..d6a85413 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -36,8 +36,12 @@ struct _wlmtk_resizebar_t { /** Background. */ bs_gfxbuf_t *gfxbuf_ptr; + /** Left element of the resizebar. */ + wlmtk_resizebar_button_t *left_button_ptr; /** Center element of the resizebar. */ wlmtk_resizebar_button_t *center_button_ptr; + /** Right element of the resizebar. */ + wlmtk_resizebar_button_t *right_button_ptr; }; /** State of an element of the resize bar. */ @@ -97,15 +101,35 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } + resizebar_ptr->left_button_ptr = wlmtk_resizebar_button_create(); + if (NULL == resizebar_ptr->left_button_ptr) { + wlmtk_resizebar_destroy(resizebar_ptr); + return NULL; + } + wlmtk_container_add_element( + &resizebar_ptr->super_box.super_container, + &resizebar_ptr->left_button_ptr->super_button.super_buffer.super_element); + resizebar_ptr->center_button_ptr = wlmtk_resizebar_button_create(); if (NULL == resizebar_ptr->center_button_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_container_add_element( + wlmtk_container_add_element_before( &resizebar_ptr->super_box.super_container, + NULL, &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element); + resizebar_ptr->right_button_ptr = wlmtk_resizebar_button_create(); + if (NULL == resizebar_ptr->right_button_ptr) { + wlmtk_resizebar_destroy(resizebar_ptr); + return NULL; + } + wlmtk_container_add_element_before( + &resizebar_ptr->super_box.super_container, + NULL, + &resizebar_ptr->right_button_ptr->super_button.super_buffer.super_element); + if (!wlmtk_resizebar_set_width(resizebar_ptr, width)) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -117,6 +141,13 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( /* ------------------------------------------------------------------------- */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) { + if (NULL != resizebar_ptr->right_button_ptr) { + wlmtk_container_remove_element( + &resizebar_ptr->super_box.super_container, + &resizebar_ptr->right_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_destroy(resizebar_ptr->right_button_ptr); + resizebar_ptr->right_button_ptr = NULL; + } if (NULL != resizebar_ptr->center_button_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, @@ -124,6 +155,13 @@ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) wlmtk_resizebar_button_destroy(resizebar_ptr->center_button_ptr); resizebar_ptr->center_button_ptr = NULL; } + if (NULL != resizebar_ptr->left_button_ptr) { + wlmtk_container_remove_element( + &resizebar_ptr->super_box.super_container, + &resizebar_ptr->left_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_destroy(resizebar_ptr->left_button_ptr); + resizebar_ptr->left_button_ptr = NULL; + } if (NULL != resizebar_ptr->gfxbuf_ptr) { bs_gfxbuf_destroy(resizebar_ptr->gfxbuf_ptr); @@ -152,10 +190,23 @@ bool wlmtk_resizebar_set_width( int center_width = BS_MAX( 0, (int)width - right_corner_width - left_corner_width); + wlmtk_element_set_visible( + &resizebar_ptr->left_button_ptr->super_button.super_buffer.super_element, + 0 < left_corner_width); wlmtk_element_set_visible( &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element, 0 < center_width); + wlmtk_element_set_visible( + &resizebar_ptr->right_button_ptr->super_button.super_buffer.super_element, + 0 < right_corner_width); + if (!wlmtk_resizebar_button_redraw( + resizebar_ptr->left_button_ptr, + resizebar_ptr->gfxbuf_ptr, + 0, left_corner_width, + &resizebar_ptr->style)) { + return false; + } if (!wlmtk_resizebar_button_redraw( resizebar_ptr->center_button_ptr, resizebar_ptr->gfxbuf_ptr, @@ -163,7 +214,15 @@ bool wlmtk_resizebar_set_width( &resizebar_ptr->style)) { return false; } + if (!wlmtk_resizebar_button_redraw( + resizebar_ptr->right_button_ptr, + resizebar_ptr->gfxbuf_ptr, + left_corner_width + center_width, right_corner_width, + &resizebar_ptr->style)) { + return false; + } + wlmtk_container_update_layout(&resizebar_ptr->super_box.super_container); return true; } From 0e31394949af654707e726513aed4d878c58f5e0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 17:44:46 +0100 Subject: [PATCH 185/390] Adds method for getting the resizebar button's super elemnt address. --- src/toolkit/resizebar.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index d6a85413..f71e3dcf 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -59,6 +59,8 @@ static bool wlmtk_resizebar_button_redraw( unsigned position, unsigned width, const wlmtk_resizebar_style_t *style_ptr); +static wlmtk_element_t *wlmtk_resizebar_button_element( + wlmtk_resizebar_button_t *resizebar_button_ptr); static void resizebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width); @@ -108,7 +110,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( } wlmtk_container_add_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->left_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_element(resizebar_ptr->left_button_ptr)); resizebar_ptr->center_button_ptr = wlmtk_resizebar_button_create(); if (NULL == resizebar_ptr->center_button_ptr) { @@ -118,7 +120,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_container_add_element_before( &resizebar_ptr->super_box.super_container, NULL, - &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_element(resizebar_ptr->center_button_ptr)); resizebar_ptr->right_button_ptr = wlmtk_resizebar_button_create(); if (NULL == resizebar_ptr->right_button_ptr) { @@ -128,7 +130,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_container_add_element_before( &resizebar_ptr->super_box.super_container, NULL, - &resizebar_ptr->right_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_element(resizebar_ptr->right_button_ptr)); if (!wlmtk_resizebar_set_width(resizebar_ptr, width)) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -144,21 +146,22 @@ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) if (NULL != resizebar_ptr->right_button_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->right_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_element(resizebar_ptr->right_button_ptr)); wlmtk_resizebar_button_destroy(resizebar_ptr->right_button_ptr); resizebar_ptr->right_button_ptr = NULL; } if (NULL != resizebar_ptr->center_button_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_element(resizebar_ptr->center_button_ptr)); wlmtk_resizebar_button_destroy(resizebar_ptr->center_button_ptr); resizebar_ptr->center_button_ptr = NULL; } if (NULL != resizebar_ptr->left_button_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - &resizebar_ptr->left_button_ptr->super_button.super_buffer.super_element); + wlmtk_resizebar_button_element(resizebar_ptr->left_button_ptr)); + wlmtk_resizebar_button_destroy(resizebar_ptr->left_button_ptr); resizebar_ptr->left_button_ptr = NULL; } @@ -191,13 +194,13 @@ bool wlmtk_resizebar_set_width( 0, (int)width - right_corner_width - left_corner_width); wlmtk_element_set_visible( - &resizebar_ptr->left_button_ptr->super_button.super_buffer.super_element, + wlmtk_resizebar_button_element(resizebar_ptr->left_button_ptr), 0 < left_corner_width); wlmtk_element_set_visible( - &resizebar_ptr->center_button_ptr->super_button.super_buffer.super_element, + wlmtk_resizebar_button_element(resizebar_ptr->center_button_ptr), 0 < center_width); wlmtk_element_set_visible( - &resizebar_ptr->right_button_ptr->super_button.super_buffer.super_element, + wlmtk_resizebar_button_element(resizebar_ptr->right_button_ptr), 0 < right_corner_width); if (!wlmtk_resizebar_button_redraw( @@ -343,6 +346,14 @@ bool wlmtk_resizebar_button_redraw( return true; } +/* ------------------------------------------------------------------------- */ +/** Returns the button's super_buffer.super_element address. */ +wlmtk_element_t *wlmtk_resizebar_button_element( + wlmtk_resizebar_button_t *resizebar_button_ptr) +{ + return &resizebar_button_ptr->super_button.super_buffer.super_element; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ From 11c2e2dfcfc5caba8625ef9e89da3261cf967ab4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 17:49:50 +0100 Subject: [PATCH 186/390] Only send CLICK events when the element did receive UP and has pointer focus. --- src/toolkit/container.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 912f8840..6ac4df1f 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -415,8 +415,6 @@ bool element_pointer_button( break; case WLMTK_BUTTON_UP: - case WLMTK_BUTTON_CLICK: - case WLMTK_BUTTON_DOUBLE_CLICK: // Forward to the element that received the DOWN, if any. if (NULL != container_ptr->left_button_element_ptr) { accepted = wlmtk_element_pointer_button( @@ -425,6 +423,20 @@ bool element_pointer_button( } break; + case WLMTK_BUTTON_CLICK: + case WLMTK_BUTTON_DOUBLE_CLICK: + // Will only be forwarded, if the element still (or again) + // has pointer focus. + if (NULL != container_ptr->left_button_element_ptr && + container_ptr->left_button_element_ptr == + container_ptr->pointer_focus_element_ptr) { + accepted = wlmtk_element_pointer_button( + container_ptr->left_button_element_ptr, + button_event_ptr); + } + break; + + default: // Uh, don't know about this... bs_log(BS_FATAL, "Unhandled button type %d", button_event_ptr->type); @@ -1128,6 +1140,12 @@ void test_pointer_button(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE( test_ptr, elem1_ptr->pointer_button_called); + // Click will be ignored + button.type = WLMTK_BUTTON_CLICK; + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + // New DOWN event goes to elem2, though. elem2_ptr->pointer_button_called = false; button.type = WLMTK_BUTTON_DOWN; @@ -1146,9 +1164,19 @@ void test_pointer_button(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE( test_ptr, elem2_ptr->pointer_button_called); + // Here, CLICK goes to elem2. + elem2_ptr->pointer_button_called = false; + button.type = WLMTK_BUTTON_CLICK; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(&container.super_element, &button)); + BS_TEST_VERIFY_TRUE( + test_ptr, elem2_ptr->pointer_button_called); + // After removing, further UP events won't be accidentally sent there. wlmtk_container_remove_element(&container, &elem1_ptr->element); wlmtk_container_remove_element(&container, &elem2_ptr->element); + button.type = WLMTK_BUTTON_UP; BS_TEST_VERIFY_FALSE( test_ptr, wlmtk_element_pointer_button(&container.super_element, &button)); From 656d11753ed05a2b69ed07467b3ccc1d695ef4da Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 20:45:31 +0100 Subject: [PATCH 187/390] Adds a 'clicked' handler to the button. --- src/toolkit/button.c | 18 +++++++++++++++++- src/toolkit/button.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index 4643772b..1c923a94 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -169,7 +169,9 @@ bool buffer_pointer_button( break; case WLMTK_BUTTON_CLICK: - bs_log(BS_INFO, "FIXME: Click!"); + if (NULL != button_ptr->impl.clicked) { + button_ptr->impl.clicked(button_ptr); + } break; default: @@ -222,12 +224,18 @@ const bs_test_case_t wlmtk_button_test_cases[] = { { 0, NULL, NULL } }; +static bool fake_button_got_clicked = false; + /** Fake destructor. */ static void fake_button_destroy(__UNUSED__ wlmtk_button_t *button_ptr) {} +static void fake_button_clicked(__UNUSED__ wlmtk_button_t *button_ptr) { + fake_button_got_clicked = true; +} /** Virtual method table of fake button. */ const wlmtk_button_impl_t fake_button_impl = { .destroy = fake_button_destroy, + .clicked = fake_button_clicked, }; /* ------------------------------------------------------------------------- */ @@ -255,6 +263,7 @@ void test_press_release(bs_test_t *test_ptr) wlmtk_button_event_t event = { .button = BTN_LEFT, .time_msec = 42 }; wlmtk_element_t *element_ptr = &button.super_buffer.super_element; + fake_button_got_clicked = false; // Initial state: released. BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); @@ -287,6 +296,13 @@ void test_press_release(bs_test_t *test_ptr) wlmtk_element_pointer_button(element_ptr, &event)); BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + event.type = WLMTK_BUTTON_CLICK; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &event)); + BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fake_button_got_clicked); + wlr_buffer_drop(r_ptr); wlr_buffer_drop(p_ptr); wlmtk_button_fini(&button); diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 2640245f..a2f42699 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -34,6 +34,9 @@ typedef struct _wlmtk_button_t wlmtk_button_t; typedef struct { /** Destroys the implementation of the button. */ void (*destroy)(wlmtk_button_t *button_ptr); + + /** Optional: Called when the button has been clicked. */ + void (*clicked)(wlmtk_button_t *button_ptr); } wlmtk_button_impl_t; /** State of a button. */ From fcb8c4815e42908d22b455657827fc7959df575a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:06:13 +0100 Subject: [PATCH 188/390] Fixes a memory leak in test. --- src/toolkit/container.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 6ac4df1f..e29bc6af 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -1184,6 +1184,7 @@ void test_pointer_button(bs_test_t *test_ptr) test_ptr, NULL, container.left_button_element_ptr); + wlmtk_element_destroy(&elem2_ptr->element); wlmtk_element_destroy(&elem1_ptr->element); wlmtk_container_fini(&container); } From d2634e1bd1d916c01fb456ba75df24b06607b64b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:06:54 +0100 Subject: [PATCH 189/390] Configures bezel width for the title bar. --- src/toolkit/titlebar.h | 2 ++ src/toolkit/window.c | 1 + 2 files changed, 3 insertions(+) diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index dfdfdd9d..0d6acbc0 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -43,6 +43,8 @@ typedef struct { uint32_t blurred_text_color; /** Height of the title bar, in pixels. */ uint32_t height; + /** Width of the bezel. */ + uint32_t bezel_width; } wlmtk_titlebar_style_t; /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index cd548063..a328c350 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -97,6 +97,7 @@ static const wlmtk_titlebar_style_t titlebar_style = { .focussed_text_color = 0xffffffff, .blurred_text_color = 0xff000000, .height = 22, + .bezel_width = 1, }; /** Style of the resize bar. */ From 29e6c01395ee8dc766e857d18a8826c4e291f8b5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:07:17 +0100 Subject: [PATCH 190/390] Adds some doxygen comments. --- src/toolkit/button.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index 1c923a94..c7d16b0d 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -224,10 +224,12 @@ const bs_test_case_t wlmtk_button_test_cases[] = { { 0, NULL, NULL } }; +/** Test outcome: Whether 'clicked' was called. */ static bool fake_button_got_clicked = false; /** Fake destructor. */ static void fake_button_destroy(__UNUSED__ wlmtk_button_t *button_ptr) {} +/** Fake 'clicked' handler. */ static void fake_button_clicked(__UNUSED__ wlmtk_button_t *button_ptr) { fake_button_got_clicked = true; } From ce9bff33c3965cb09c04532aff098243ffe54d00 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:07:37 +0100 Subject: [PATCH 191/390] Adds wlr_buffer_drop_nullify as convenience method. --- src/toolkit/gfxbuf.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/toolkit/gfxbuf.h b/src/toolkit/gfxbuf.h index ff46c5ee..5836b4ff 100644 --- a/src/toolkit/gfxbuf.h +++ b/src/toolkit/gfxbuf.h @@ -45,6 +45,15 @@ struct wlr_buffer *bs_gfxbuf_create_wlr_buffer( unsigned width, unsigned height); +/** + * Drops a WLR buffer, and sets the pointer to NULL. + * + * @param wlr_buffer_ptr_ptr Points to a pointer to a WLR buffer. The pointer + * to the WLR buffer may be NULL; in that case, the + * call is a no-op. + */ +void wlr_buffer_drop_nullify(struct wlr_buffer **wlr_buffer_ptr_ptr); + /** * Returns the libbase graphics buffer for the `struct wlr_buffer`. * From c669b0189c58f6c9380eb7e959ea512671b3a547 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:08:07 +0100 Subject: [PATCH 192/390] Adds initial implementation of toolkit titlebar buttons. --- src/toolkit/gfxbuf.c | 10 +- src/toolkit/titlebar.c | 247 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+), 2 deletions(-) diff --git a/src/toolkit/gfxbuf.c b/src/toolkit/gfxbuf.c index c8a2b528..d3fb84a5 100644 --- a/src/toolkit/gfxbuf.c +++ b/src/toolkit/gfxbuf.c @@ -51,8 +51,6 @@ static bool wlmaker_gfxbuf_impl_begin_data_ptr_access( static void wlmaker_gfxbuf_impl_end_data_ptr_access( struct wlr_buffer *wlr_buffer_ptr); - - /** Implementation callbacks for wlroots' `struct wlr_buffer`. */ static const struct wlr_buffer_impl wlmaker_gfxbuf_impl = { .destroy = wlmaker_gfxbuf_impl_destroy, @@ -85,6 +83,14 @@ struct wlr_buffer *bs_gfxbuf_create_wlr_buffer( return &gfxbuf_ptr->wlr_buffer; } +/* ------------------------------------------------------------------------- */ +void wlr_buffer_drop_nullify(struct wlr_buffer **wlr_buffer_ptr_ptr) +{ + if (NULL == *wlr_buffer_ptr_ptr) return; + wlr_buffer_drop(*wlr_buffer_ptr_ptr); + *wlr_buffer_ptr_ptr = NULL; +} + /* ------------------------------------------------------------------------- */ bs_gfxbuf_t *bs_gfxbuf_from_wlr_buffer( struct wlr_buffer *wlr_buffer_ptr) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 7d458c60..589b69c2 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -21,6 +21,7 @@ #include "titlebar.h" #include "box.h" +#include "button.h" #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" @@ -33,6 +34,8 @@ /** Forward declaration. */ typedef struct _wlmtk_titlebar_title_t wlmtk_titlebar_title_t; +/** Forward declaration. */ +typedef struct _wlmtk_titlebar_button_t wlmtk_titlebar_button_t; /** State of the title bar. */ struct _wlmtk_titlebar_t { @@ -42,6 +45,9 @@ struct _wlmtk_titlebar_t { /** Title element of the title bar. */ wlmtk_titlebar_title_t *title_ptr; + /** Minimize button. */ + wlmtk_titlebar_button_t *minimize_button_ptr; + /** Titlebar background, when focussed. */ bs_gfxbuf_t *focussed_gfxbuf_ptr; /** Titlebar background, when blurred. */ @@ -84,6 +90,39 @@ static bool wlmtk_titlebar_title_redraw( bool activated, const wlmtk_titlebar_style_t *style_ptr); +/** Function pointer to method for drawing the button contents. */ +typedef void (*wlmtk_titlebar_button_draw_t)( + cairo_t *cairo_ptr, uint32_t color); + +/** State of a titlebar button. */ +struct _wlmtk_titlebar_button_t { + /** Superclass: Button. */ + wlmtk_button_t super_button; + + /** For drawing the button contents. */ + wlmtk_titlebar_button_draw_t draw; + + /** WLR buffer of the button when focussed & released. */ + struct wlr_buffer *focussed_released_wlr_buffer_ptr; + /** WLR buffer of the button when focussed & pressed. */ + struct wlr_buffer *focussed_pressed_wlr_buffer_ptr; + /** WLR buffer of the button when blurred. */ + struct wlr_buffer *blurred_wlr_buffer_ptr; +}; + +static wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_titlebar_button_draw_t draw); +static void wlmtk_titlebar_button_destroy( + wlmtk_titlebar_button_t *titlebar_button_ptr); +static bool wlmtk_titlebar_button_redraw( + wlmtk_titlebar_button_t *titlebar_button_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + const wlmtk_titlebar_style_t *style_ptr); +wlmtk_element_t *wlmtk_titlebar_button_element( + wlmtk_titlebar_button_t *titlebar_button_ptr); + static void titlebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers( wlmtk_titlebar_t *titlebar_ptr, @@ -154,12 +193,33 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( &titlebar_ptr->super_box.super_container, &titlebar_ptr->title_ptr->super_buffer.super_element); + titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( + wlmaker_primitives_draw_minimize_icon); + if (NULL == titlebar_ptr->minimize_button_ptr) { + wlmtk_titlebar_destroy(titlebar_ptr); + return NULL; + } + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), + true); + wlmtk_container_add_element( + &titlebar_ptr->super_box.super_container, + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); + return titlebar_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) { + if (NULL != titlebar_ptr->minimize_button_ptr) { + wlmtk_container_remove_element( + &titlebar_ptr->super_box.super_container, + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); + wlmtk_titlebar_button_destroy(titlebar_ptr->minimize_button_ptr); + titlebar_ptr->minimize_button_ptr = NULL; + } + if (NULL != titlebar_ptr->title_ptr) { wlmtk_container_remove_element( &titlebar_ptr->super_box.super_container, @@ -202,6 +262,15 @@ bool wlmtk_titlebar_set_width( return false; } + if (!wlmtk_titlebar_button_redraw( + titlebar_ptr->minimize_button_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + 0, + &titlebar_ptr->style)) { + return false; + } + // Don't forget to re-position the elements. wlmtk_container_update_layout(&titlebar_ptr->super_box.super_container); return true; @@ -484,6 +553,184 @@ bool title_redraw_buffers( return true; } +/* == Title bar button ===================================================== */ + +static void titlebar_button_destroy(wlmtk_button_t *button_ptr); +static struct wlr_buffer *create_buf( + bs_gfxbuf_t *gfxbuf_ptr, + int position, + bool pressed, + const wlmtk_titlebar_style_t *style_ptr, + wlmtk_titlebar_button_draw_t draw); + +/** Buffer implementation for title of the title bar. */ +static const wlmtk_button_impl_t titlebar_button_impl = { + .destroy = titlebar_button_destroy +}; + +/* ------------------------------------------------------------------------- */ +/** + * Creates a button for the titlebar. + * + * @param draw + * + * @return Pointer to the titlebar button, or NULL on error. + */ +wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_titlebar_button_draw_t draw) +{ + wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( + 1, sizeof(wlmtk_titlebar_button_t)); + if (NULL == titlebar_button_ptr) return NULL; + titlebar_button_ptr->draw = draw; + + if (!wlmtk_button_init( + &titlebar_button_ptr->super_button, + &titlebar_button_impl)) { + wlmtk_titlebar_button_destroy(titlebar_button_ptr); + return NULL; + } + + return titlebar_button_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** + * Destroys the titlebar button. + * + * @param titlebar_button_ptr + */ +void wlmtk_titlebar_button_destroy( + wlmtk_titlebar_button_t *titlebar_button_ptr) +{ + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_released_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->blurred_wlr_buffer_ptr); + + wlmtk_button_fini(&titlebar_button_ptr->super_button); + free(titlebar_button_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Redraws the titlebar button for given textures, position and style. + * + * @param titlebar_button_ptr + * @param focussed_gfxbuf_ptr + * @param blurred_gfxbuf_ptr + * @param position + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_titlebar_button_redraw( + wlmtk_titlebar_button_t *titlebar_button_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + const wlmtk_titlebar_style_t *style_ptr) +{ + BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); + BS_ASSERT(focussed_gfxbuf_ptr->height == blurred_gfxbuf_ptr->height); + BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); + BS_ASSERT(position + style_ptr->height <= focussed_gfxbuf_ptr->width); + + struct wlr_buffer *focussed_released_ptr = create_buf( + focussed_gfxbuf_ptr, 0, false, style_ptr, + titlebar_button_ptr->draw); + struct wlr_buffer *focussed_pressed_ptr = create_buf( + focussed_gfxbuf_ptr, 0, true, style_ptr, + titlebar_button_ptr->draw); + struct wlr_buffer *blurred_ptr = create_buf( + blurred_gfxbuf_ptr, 0, false, style_ptr, + titlebar_button_ptr->draw); + + if (NULL != focussed_released_ptr && + NULL != focussed_pressed_ptr && + NULL != blurred_ptr) { + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_released_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->blurred_wlr_buffer_ptr); + + titlebar_button_ptr->focussed_released_wlr_buffer_ptr = + focussed_released_ptr; + titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr = + focussed_pressed_ptr; + titlebar_button_ptr->blurred_wlr_buffer_ptr = blurred_ptr; + + // FIXME: Depend on focus/blur. + wlmtk_button_set( + &titlebar_button_ptr->super_button, + titlebar_button_ptr->focussed_released_wlr_buffer_ptr, + titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + + return true; + } + + wlr_buffer_drop_nullify(&focussed_released_ptr); + wlr_buffer_drop_nullify(&focussed_pressed_ptr); + wlr_buffer_drop_nullify(&blurred_ptr); + return false; +} + +/* ------------------------------------------------------------------------- */ +/** + * Returns the titlebar button's super element. + * + * @param titlebar_button_ptr + * + * @return Pointer to the superclass @ref wlmtk_element_t. + */ +wlmtk_element_t *wlmtk_titlebar_button_element( + wlmtk_titlebar_button_t *titlebar_button_ptr) +{ + return &titlebar_button_ptr->super_button.super_buffer.super_element; +} + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, wraps to @ref wlmtk_titlebar_button_destroy. */ +void titlebar_button_destroy(wlmtk_button_t *button_ptr) +{ + wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( + button_ptr, wlmtk_titlebar_button_t, super_button); + wlmtk_titlebar_button_destroy(titlebar_button_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Helper: Creates a WLR buffer for the button. */ +struct wlr_buffer *create_buf( + bs_gfxbuf_t *gfxbuf_ptr, + int position, + bool pressed, + const wlmtk_titlebar_style_t *style_ptr, + void (*draw)(cairo_t *cairo_ptr, uint32_t color)) +{ + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + style_ptr->height, style_ptr->height); + if (NULL == wlr_buffer_ptr) return NULL; + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, + gfxbuf_ptr, position, 0, style_ptr->height, style_ptr->height); + + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(wlr_buffer_ptr); + return NULL; + } + wlmaker_primitives_draw_bezel( + cairo_ptr, style_ptr->bezel_width, !pressed); + draw(cairo_ptr, style_ptr->focussed_text_color); + cairo_destroy(cairo_ptr); + + return wlr_buffer_ptr; +} /* == Unit tests =========================================================== */ From eea11eee7fb102eb8faf15f0e0c51abba03e173c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:11:06 +0100 Subject: [PATCH 193/390] Adds close button, although in wrong color. --- src/toolkit/titlebar.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 589b69c2..2473e17f 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -47,6 +47,8 @@ struct _wlmtk_titlebar_t { /** Minimize button. */ wlmtk_titlebar_button_t *minimize_button_ptr; + /** Close button. */ + wlmtk_titlebar_button_t *close_button_ptr; /** Titlebar background, when focussed. */ bs_gfxbuf_t *focussed_gfxbuf_ptr; @@ -206,12 +208,33 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( &titlebar_ptr->super_box.super_container, wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); + titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( + wlmaker_primitives_draw_close_icon); + if (NULL == titlebar_ptr->close_button_ptr) { + wlmtk_titlebar_destroy(titlebar_ptr); + return NULL; + } + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), + true); + wlmtk_container_add_element_before( + &titlebar_ptr->super_box.super_container, NULL, + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr)); + return titlebar_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) { + if (NULL != titlebar_ptr->close_button_ptr) { + wlmtk_container_remove_element( + &titlebar_ptr->super_box.super_container, + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr)); + wlmtk_titlebar_button_destroy(titlebar_ptr->close_button_ptr); + titlebar_ptr->close_button_ptr = NULL; + } + if (NULL != titlebar_ptr->minimize_button_ptr) { wlmtk_container_remove_element( &titlebar_ptr->super_box.super_container, @@ -271,6 +294,15 @@ bool wlmtk_titlebar_set_width( return false; } + if (!wlmtk_titlebar_button_redraw( + titlebar_ptr->close_button_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + 0, + &titlebar_ptr->style)) { + return false; + } + // Don't forget to re-position the elements. wlmtk_container_update_layout(&titlebar_ptr->super_box.super_container); return true; From 576f4fceaf2ca3fe59ece6369410e0a1d3ae92ee Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:13:20 +0100 Subject: [PATCH 194/390] Uses wlr_buffer_drop_nullify in toolkit titlebar. --- src/toolkit/titlebar.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 2473e17f..02264aff 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -467,15 +467,8 @@ bool wlmtk_titlebar_title_redraw( */ void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr) { - if (NULL != title_ptr->focussed_wlr_buffer_ptr) { - wlr_buffer_drop(title_ptr->focussed_wlr_buffer_ptr); - title_ptr->focussed_wlr_buffer_ptr = NULL; - } - if (NULL != title_ptr->blurred_wlr_buffer_ptr) { - wlr_buffer_drop(title_ptr->blurred_wlr_buffer_ptr); - title_ptr->blurred_wlr_buffer_ptr = NULL; - } - + wlr_buffer_drop_nullify(&title_ptr->focussed_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&title_ptr->blurred_wlr_buffer_ptr); wlmtk_buffer_fini(&title_ptr->super_buffer); free(title_ptr); } From 1d3adb7b09c43cac286bf5e299f76346b35a8f22 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 10 Nov 2023 22:19:22 +0100 Subject: [PATCH 195/390] Prevents crash on small windows. Toolkit titlebar positioning not correct yet. --- src/toolkit/titlebar.c | 60 ++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 02264aff..510a8210 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -201,9 +201,6 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_element_set_visible( - wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), - true); wlmtk_container_add_element( &titlebar_ptr->super_box.super_container, wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); @@ -214,9 +211,6 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_element_set_visible( - wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), - true); wlmtk_container_add_element_before( &titlebar_ptr->super_box.super_container, NULL, wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr)); @@ -274,6 +268,8 @@ bool wlmtk_titlebar_set_width( if (!redraw_buffers(titlebar_ptr, width)) return false; BS_ASSERT(width == titlebar_ptr->width); + int close_position = width - titlebar_ptr->style.height; + if (!wlmtk_titlebar_title_redraw( titlebar_ptr->title_ptr, titlebar_ptr->focussed_gfxbuf_ptr, @@ -285,22 +281,40 @@ bool wlmtk_titlebar_set_width( return false; } - if (!wlmtk_titlebar_button_redraw( - titlebar_ptr->minimize_button_ptr, - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - 0, - &titlebar_ptr->style)) { - return false; + if (titlebar_ptr->style.height <= width) { + if (!wlmtk_titlebar_button_redraw( + titlebar_ptr->minimize_button_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + 0, + &titlebar_ptr->style)) { + return false; + } + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), + true); + } else { + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), + false); } - if (!wlmtk_titlebar_button_redraw( - titlebar_ptr->close_button_ptr, - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - 0, - &titlebar_ptr->style)) { - return false; + if ((int)titlebar_ptr->style.height <= close_position) { + if (!wlmtk_titlebar_button_redraw( + titlebar_ptr->close_button_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + close_position, + &titlebar_ptr->style)) { + return false; + } + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), + true); + } else { + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), + false); } // Don't forget to re-position the elements. @@ -664,13 +678,13 @@ bool wlmtk_titlebar_button_redraw( BS_ASSERT(position + style_ptr->height <= focussed_gfxbuf_ptr->width); struct wlr_buffer *focussed_released_ptr = create_buf( - focussed_gfxbuf_ptr, 0, false, style_ptr, + focussed_gfxbuf_ptr, position, false, style_ptr, titlebar_button_ptr->draw); struct wlr_buffer *focussed_pressed_ptr = create_buf( - focussed_gfxbuf_ptr, 0, true, style_ptr, + focussed_gfxbuf_ptr, position, true, style_ptr, titlebar_button_ptr->draw); struct wlr_buffer *blurred_ptr = create_buf( - blurred_gfxbuf_ptr, 0, false, style_ptr, + blurred_gfxbuf_ptr, position, false, style_ptr, titlebar_button_ptr->draw); if (NULL != focussed_released_ptr && From c2cffaf5e13e84e4597efe38e5a18d9310025aff Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 15:59:34 +0100 Subject: [PATCH 196/390] Use titlebar_title_ptr throughout. --- src/toolkit/titlebar.c | 82 ++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 510a8210..608ccd93 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -82,9 +82,10 @@ static wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( int width, bool activated, const wlmtk_titlebar_style_t *style_ptr); -static void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr); +static void wlmtk_titlebar_title_destroy( + wlmtk_titlebar_title_t *titlebar_title_ptr); static bool wlmtk_titlebar_title_redraw( - wlmtk_titlebar_title_t *title_ptr, + wlmtk_titlebar_title_t *titlebar_title_ptr, bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, int position, @@ -132,10 +133,10 @@ static bool redraw_buffers( static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); static void title_set_activated( - wlmtk_titlebar_title_t *title_ptr, + wlmtk_titlebar_title_t *titlebar_title_ptr, bool activated); static bool title_redraw_buffers( - wlmtk_titlebar_title_t *title_ptr, + wlmtk_titlebar_title_t *titlebar_title_ptr, bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, unsigned position, @@ -415,35 +416,35 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( bool activated, const wlmtk_titlebar_style_t *style_ptr) { - wlmtk_titlebar_title_t *title_ptr = logged_calloc( + wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_title_t)); - if (NULL == title_ptr) return NULL; + if (NULL == titlebar_title_ptr) return NULL; if (!wlmtk_buffer_init( - &title_ptr->super_buffer, + &titlebar_title_ptr->super_buffer, &title_buffer_impl)) { - wlmtk_titlebar_title_destroy(title_ptr); + wlmtk_titlebar_title_destroy(titlebar_title_ptr); return NULL; } if (!title_redraw_buffers( - title_ptr, + titlebar_title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, position, width, style_ptr)) { - wlmtk_titlebar_title_destroy(title_ptr); + wlmtk_titlebar_title_destroy(titlebar_title_ptr); return NULL; } - title_set_activated(title_ptr, activated); - return title_ptr; + title_set_activated(titlebar_title_ptr, activated); + return titlebar_title_ptr; } /* ------------------------------------------------------------------------- */ /** * Redraws the title section of the title bar. * - * @param title_ptr + * @param titlebar_title_ptr * @param focussed_gfxbuf_ptr Titlebar background when focussed. * @param blurred_gfxbuf_ptr Titlebar background when blurred. * @param position Position of title telative to titlebar. @@ -454,7 +455,7 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( * @return true on success. */ bool wlmtk_titlebar_title_redraw( - wlmtk_titlebar_title_t *title_ptr, + wlmtk_titlebar_title_t *titlebar_title_ptr, bs_gfxbuf_t *focussed_gfxbuf_ptr, bs_gfxbuf_t *blurred_gfxbuf_ptr, int position, @@ -463,13 +464,13 @@ bool wlmtk_titlebar_title_redraw( const wlmtk_titlebar_style_t *style_ptr) { if (!title_redraw_buffers( - title_ptr, + titlebar_title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, position, width, style_ptr)) { return false; } - title_set_activated(title_ptr, activated); + title_set_activated(titlebar_title_ptr, activated); return true; } @@ -477,39 +478,41 @@ bool wlmtk_titlebar_title_redraw( /** * Destroys the titlebar title. * - * @param title_ptr + * @param titlebar_title_ptr */ -void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *title_ptr) +void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *titlebar_title_ptr) { - wlr_buffer_drop_nullify(&title_ptr->focussed_wlr_buffer_ptr); - wlr_buffer_drop_nullify(&title_ptr->blurred_wlr_buffer_ptr); - wlmtk_buffer_fini(&title_ptr->super_buffer); - free(title_ptr); + wlr_buffer_drop_nullify(&titlebar_title_ptr->focussed_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&titlebar_title_ptr->blurred_wlr_buffer_ptr); + wlmtk_buffer_fini(&titlebar_title_ptr->super_buffer); + free(titlebar_title_ptr); } /* ------------------------------------------------------------------------- */ /** Dtor. Forwards to @ref wlmtk_titlebar_title_destroy. */ void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) { - wlmtk_titlebar_title_t *title_ptr = BS_CONTAINER_OF( + wlmtk_titlebar_title_t *titlebar_title_ptr = BS_CONTAINER_OF( buffer_ptr, wlmtk_titlebar_title_t, super_buffer); - wlmtk_titlebar_title_destroy(title_ptr); + wlmtk_titlebar_title_destroy(titlebar_title_ptr); } /* ------------------------------------------------------------------------- */ /** * Sets whether the title is drawn focussed (activated) or blurred. * - * @param title_ptr + * @param titlebar_title_ptr * @param activated */ -void title_set_activated(wlmtk_titlebar_title_t *title_ptr, bool activated) +void title_set_activated( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bool activated) { wlmtk_buffer_set( - &title_ptr->super_buffer, + &titlebar_title_ptr->super_buffer, activated ? - title_ptr->focussed_wlr_buffer_ptr : - title_ptr->blurred_wlr_buffer_ptr); + titlebar_title_ptr->focussed_wlr_buffer_ptr : + titlebar_title_ptr->blurred_wlr_buffer_ptr); } /* ------------------------------------------------------------------------- */ @@ -820,42 +823,43 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); - wlmtk_titlebar_title_t *title_ptr = wlmtk_titlebar_title_create( + wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, title_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, - bs_gfxbuf_from_wlr_buffer(title_ptr->focussed_wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(titlebar_title_ptr->focussed_wlr_buffer_ptr), "toolkit/title_focussed.png"); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, - bs_gfxbuf_from_wlr_buffer(title_ptr->blurred_wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(titlebar_title_ptr->blurred_wlr_buffer_ptr), "toolkit/title_blurred.png"); // We had started as "activated", verify that's correct. + wlmtk_buffer_t *super_buffer_ptr = &titlebar_title_ptr->super_buffer; BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, - bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_focussed.png"); // De-activated the title. Verify that was propagated. - title_set_activated(title_ptr, false); + title_set_activated(titlebar_title_ptr, false); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, - bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_blurred.png"); // Redraw with shorter width. Verify that's still correct. wlmtk_titlebar_title_redraw( - title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, + titlebar_title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 70, false, &style); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, - bs_gfxbuf_from_wlr_buffer(title_ptr->super_buffer.wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_blurred_short.png"); - wlmtk_element_destroy(&title_ptr->super_buffer.super_element); + wlmtk_element_destroy(&titlebar_title_ptr->super_buffer.super_element); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); } From 7019800f48bf24e40d3f3bc072dd60cf294c5c16 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 16:02:27 +0100 Subject: [PATCH 197/390] Adds wlmtk_titlebar_title_element. --- src/toolkit/titlebar.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 608ccd93..2053b845 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -92,6 +92,8 @@ static bool wlmtk_titlebar_title_redraw( int width, bool activated, const wlmtk_titlebar_style_t *style_ptr); +static wlmtk_element_t *wlmtk_titlebar_title_element( + wlmtk_titlebar_title_t *titlebar_title_ptr); /** Function pointer to method for drawing the button contents. */ typedef void (*wlmtk_titlebar_button_draw_t)( @@ -191,10 +193,10 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } wlmtk_element_set_visible( - &titlebar_ptr->title_ptr->super_buffer.super_element, true); + wlmtk_titlebar_title_element(titlebar_ptr->title_ptr), true); wlmtk_container_add_element( &titlebar_ptr->super_box.super_container, - &titlebar_ptr->title_ptr->super_buffer.super_element); + wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( wlmaker_primitives_draw_minimize_icon); @@ -241,7 +243,7 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) if (NULL != titlebar_ptr->title_ptr) { wlmtk_container_remove_element( &titlebar_ptr->super_box.super_container, - &titlebar_ptr->title_ptr->super_buffer.super_element); + wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); wlmtk_titlebar_title_destroy(titlebar_ptr->title_ptr); titlebar_ptr->title_ptr = NULL; } @@ -474,6 +476,20 @@ bool wlmtk_titlebar_title_redraw( return true; } +/* ------------------------------------------------------------------------- */ +/** + * Returns the superclass @ref wlmtk_element_t for the titlebar title. + * + * @param tittlebar_title_ptr + * + * @return Pointer to the super element. + */ +wlmtk_element_t *wlmtk_titlebar_title_element( + wlmtk_titlebar_title_t *titlebar_title_ptr) +{ + return &titlebar_title_ptr->super_buffer.super_element; +} + /* ------------------------------------------------------------------------- */ /** * Destroys the titlebar title. @@ -859,7 +875,7 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_blurred_short.png"); - wlmtk_element_destroy(&titlebar_title_ptr->super_buffer.super_element); + wlmtk_element_destroy(wlmtk_titlebar_title_element(titlebar_title_ptr)); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); } From 01b5e6b911869da0d310a5da48c3bc8c32fc1924 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 16:18:00 +0100 Subject: [PATCH 198/390] Simplifies wlmtk_titlebar_title_t ctor. --- src/toolkit/titlebar.c | 55 +++++++++--------------------------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 2053b845..1cce116e 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -75,13 +75,7 @@ struct _wlmtk_titlebar_title_t { struct wlr_buffer *blurred_wlr_buffer_ptr; }; -static wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - int position, - int width, - bool activated, - const wlmtk_titlebar_style_t *style_ptr); +static wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void); static void wlmtk_titlebar_title_destroy( wlmtk_titlebar_title_t *titlebar_title_ptr); static bool wlmtk_titlebar_title_redraw( @@ -181,19 +175,11 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } - titlebar_ptr->title_ptr = wlmtk_titlebar_title_create( - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - 0, - titlebar_ptr->width, - titlebar_ptr->activated, - &titlebar_ptr->style); + titlebar_ptr->title_ptr = wlmtk_titlebar_title_create(); if (NULL == titlebar_ptr->title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_element_set_visible( - wlmtk_titlebar_title_element(titlebar_ptr->title_ptr), true); wlmtk_container_add_element( &titlebar_ptr->super_box.super_container, wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); @@ -283,6 +269,8 @@ bool wlmtk_titlebar_set_width( &titlebar_ptr->style)) { return false; } + wlmtk_element_set_visible( + wlmtk_titlebar_title_element(titlebar_ptr->title_ptr), true); if (titlebar_ptr->style.height <= width) { if (!wlmtk_titlebar_button_redraw( @@ -401,22 +389,9 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) /** * Creates a title bar title. * - * @param focussed_gfxbuf_ptr Titlebar background when focussed. - * @param blurred_gfxbuf_ptr Titlebar background when blurred. - * @param position Position of title telative to titlebar. - * @param width Width of title. - * @param activated Whether the title bar should start focussed. - * @param style_ptr - * * @return Title handle. */ -wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - int position, - int width, - bool activated, - const wlmtk_titlebar_style_t *style_ptr) +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void) { wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_title_t)); @@ -429,16 +404,6 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( return NULL; } - if (!title_redraw_buffers( - titlebar_title_ptr, - focussed_gfxbuf_ptr, - blurred_gfxbuf_ptr, - position, width, style_ptr)) { - wlmtk_titlebar_title_destroy(titlebar_title_ptr); - return NULL; - } - - title_set_activated(titlebar_title_ptr, activated); return titlebar_title_ptr; } @@ -480,7 +445,7 @@ bool wlmtk_titlebar_title_redraw( /** * Returns the superclass @ref wlmtk_element_t for the titlebar title. * - * @param tittlebar_title_ptr + * @param titlebar_title_ptr * * @return Pointer to the super element. */ @@ -839,9 +804,13 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); - wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( - focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style); + wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create(); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_titlebar_title_redraw( + titlebar_title_ptr, + focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style)); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, From 03a912b677fc4df530a747c279971cd9fe37a8f7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 16:32:00 +0100 Subject: [PATCH 199/390] Cleans up the buffer drawing in wlmtk_titlebar_title_redraw. --- src/toolkit/titlebar.c | 117 +++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 1cce116e..8150690e 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -131,12 +131,11 @@ static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); static void title_set_activated( wlmtk_titlebar_title_t *titlebar_title_ptr, bool activated); -static bool title_redraw_buffers( - wlmtk_titlebar_title_t *titlebar_title_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, +struct wlr_buffer *title_create_buffer( + bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, + uint32_t text_color, const wlmtk_titlebar_style_t *style_ptr); /* == Data ================================================================= */ @@ -430,13 +429,31 @@ bool wlmtk_titlebar_title_redraw( bool activated, const wlmtk_titlebar_style_t *style_ptr) { - if (!title_redraw_buffers( - titlebar_title_ptr, - focussed_gfxbuf_ptr, - blurred_gfxbuf_ptr, - position, width, style_ptr)) { + BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); + BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); + BS_ASSERT(style_ptr->height == blurred_gfxbuf_ptr->height); + BS_ASSERT(position <= (int)focussed_gfxbuf_ptr->width); + BS_ASSERT(position + width <= (int)focussed_gfxbuf_ptr->width); + + struct wlr_buffer *focussed_wlr_buffer_ptr = title_create_buffer( + focussed_gfxbuf_ptr, position, width, + style_ptr->focussed_text_color, style_ptr); + struct wlr_buffer *blurred_wlr_buffer_ptr = title_create_buffer( + blurred_gfxbuf_ptr, position, width, + style_ptr->blurred_text_color, style_ptr); + + if (NULL == focussed_wlr_buffer_ptr || + NULL == blurred_wlr_buffer_ptr) { + wlr_buffer_drop_nullify(&focussed_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&blurred_wlr_buffer_ptr); return false; } + + wlr_buffer_drop_nullify(&titlebar_title_ptr->focussed_wlr_buffer_ptr); + titlebar_title_ptr->focussed_wlr_buffer_ptr = focussed_wlr_buffer_ptr; + wlr_buffer_drop_nullify(&titlebar_title_ptr->blurred_wlr_buffer_ptr); + titlebar_title_ptr->blurred_wlr_buffer_ptr = blurred_wlr_buffer_ptr; + title_set_activated(titlebar_title_ptr, activated); return true; } @@ -497,83 +514,47 @@ void title_set_activated( } /* ------------------------------------------------------------------------- */ -/** Redraws the title buffers. */ -bool title_redraw_buffers( - wlmtk_titlebar_title_t *title_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, +/** + * Creates a WLR buffer with the title's texture, as specified. + * + * @param gfxbuf_ptr + * @param position + * @param width + * @param text_color + * @param style_ptr + * + * @return A pointer to a `struct wlr_buffer` with the texture. + */ +struct wlr_buffer *title_create_buffer( + bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, + uint32_t text_color, const wlmtk_titlebar_style_t *style_ptr) { - cairo_t *cairo_ptr; - - BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); - BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); - BS_ASSERT(style_ptr->height == blurred_gfxbuf_ptr->height); - BS_ASSERT(position <= focussed_gfxbuf_ptr->width); - BS_ASSERT(position + width <= focussed_gfxbuf_ptr->width); - - struct wlr_buffer *focussed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - width, style_ptr->height); - if (NULL == focussed_wlr_buffer_ptr) return false; - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(focussed_wlr_buffer_ptr), - 0, 0, - focussed_gfxbuf_ptr, - position, 0, - width, style_ptr->height); - - cairo_ptr = cairo_create_from_wlr_buffer(focussed_wlr_buffer_ptr); - if (NULL == cairo_ptr) { - wlr_buffer_drop(focussed_wlr_buffer_ptr); - return false; - } - - wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); - wlmaker_primitives_draw_window_title( - cairo_ptr, "Title", style_ptr->focussed_text_color); - - cairo_destroy(cairo_ptr); - - struct wlr_buffer *blurred_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( width, style_ptr->height); - if (NULL == blurred_wlr_buffer_ptr) { - wlr_buffer_drop(focussed_wlr_buffer_ptr); - return false; - } + if (NULL == wlr_buffer_ptr) return NULL; bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(blurred_wlr_buffer_ptr), + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, - blurred_gfxbuf_ptr, + gfxbuf_ptr, position, 0, width, style_ptr->height); - cairo_ptr = cairo_create_from_wlr_buffer(blurred_wlr_buffer_ptr); + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); if (NULL == cairo_ptr) { - wlr_buffer_drop(blurred_wlr_buffer_ptr); - return false; + wlr_buffer_drop(wlr_buffer_ptr); + return NULL; } - wlmaker_primitives_draw_bezel_at( cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); wlmaker_primitives_draw_window_title( - cairo_ptr, "Title", style_ptr->blurred_text_color); - + cairo_ptr, "Title", text_color); cairo_destroy(cairo_ptr); - if (NULL != title_ptr->focussed_wlr_buffer_ptr) { - wlr_buffer_drop(title_ptr->focussed_wlr_buffer_ptr); - } - title_ptr->focussed_wlr_buffer_ptr = focussed_wlr_buffer_ptr; - if (NULL != title_ptr->blurred_wlr_buffer_ptr) { - wlr_buffer_drop(title_ptr->blurred_wlr_buffer_ptr); - } - title_ptr->blurred_wlr_buffer_ptr = blurred_wlr_buffer_ptr; - return true; + return wlr_buffer_ptr; } /* == Title bar button ===================================================== */ From d36c5cfd1cba80870404a945b9910d0d15fe0362 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 16:44:28 +0100 Subject: [PATCH 200/390] Simplifies buffer drawing for resizebar button. --- src/toolkit/resizebar.c | 84 ++++++++++++++++++++++------------------- src/toolkit/resizebar.h | 2 + src/toolkit/window.c | 1 + 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index f71e3dcf..5326bf91 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -274,72 +274,80 @@ void wlmtk_resizebar_button_destroy( /* ------------------------------------------------------------------------- */ /** - * Redraws the element, with updated position and width. + * Creates a resizebar button texture. * - * @param resizebar_button_ptr * @param gfxbuf_ptr * @param position * @param width * @param style_ptr + * @param pressed * - * @return true on success. + * @return A pointer to a newly allocated `struct wlr_buffer`. */ -bool wlmtk_resizebar_button_redraw( - wlmtk_resizebar_button_t *resizebar_button_ptr, +struct wlr_buffer *create_buffer( bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, - const wlmtk_resizebar_style_t *style_ptr) + const wlmtk_resizebar_style_t *style_ptr, + bool pressed) { - struct wlr_buffer *released_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( width, style_ptr->height); - if (NULL == released_wlr_buffer_ptr) return false; + if (NULL == wlr_buffer_ptr) return NULL; bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(released_wlr_buffer_ptr), - 0, 0, - gfxbuf_ptr, - position, 0, - width, style_ptr->height); + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, + gfxbuf_ptr, position, 0, width, style_ptr->height); - cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(released_wlr_buffer_ptr); + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); if (NULL == cairo_ptr) { - wlr_buffer_drop(released_wlr_buffer_ptr); + wlr_buffer_drop(wlr_buffer_ptr); return false; } wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, style_ptr->height, 1.0, false); + cairo_ptr, 0, 0, width, + style_ptr->height, style_ptr->bezel_width, !pressed); cairo_destroy(cairo_ptr); - struct wlr_buffer *pressed_wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - width, style_ptr->height); - if (NULL == pressed_wlr_buffer_ptr) { - wlr_buffer_drop(released_wlr_buffer_ptr); - return false; - } - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(pressed_wlr_buffer_ptr), - 0, 0, - gfxbuf_ptr, - position, 0, - width, style_ptr->height); + return wlr_buffer_ptr; +} - cairo_ptr = cairo_create_from_wlr_buffer(pressed_wlr_buffer_ptr); - if (NULL == cairo_ptr) { - wlr_buffer_drop(released_wlr_buffer_ptr); - wlr_buffer_drop(pressed_wlr_buffer_ptr); +/* ------------------------------------------------------------------------- */ +/** + * Redraws the element, with updated position and width. + * + * @param resizebar_button_ptr + * @param gfxbuf_ptr + * @param position + * @param width + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_resizebar_button_redraw( + wlmtk_resizebar_button_t *resizebar_button_ptr, + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr) +{ + struct wlr_buffer *released_wlr_buffer_ptr = create_buffer( + gfxbuf_ptr, position, width, style_ptr, false); + struct wlr_buffer *pressed_wlr_buffer_ptr = create_buffer( + gfxbuf_ptr, position, width, style_ptr, true); + + if (NULL == released_wlr_buffer_ptr || + NULL == pressed_wlr_buffer_ptr) { + wlr_buffer_drop_nullify(&released_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&pressed_wlr_buffer_ptr); return false; } - wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); - cairo_destroy(cairo_ptr); // Will take ownershp of the buffers. wlmtk_button_set( &resizebar_button_ptr->super_button, - pressed_wlr_buffer_ptr, - released_wlr_buffer_ptr); + released_wlr_buffer_ptr, + pressed_wlr_buffer_ptr); wlr_buffer_drop(released_wlr_buffer_ptr); wlr_buffer_drop(pressed_wlr_buffer_ptr); diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 8334bbd7..287f28db 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -24,6 +24,8 @@ typedef struct { unsigned height; /** Width of the corners. */ unsigned corner_width; + /** Width of the bezel. */ + uint32_t bezel_width; } wlmtk_resizebar_style_t; /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a328c350..26f8db2a 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -109,6 +109,7 @@ static const wlmtk_resizebar_style_t resizebar_style = { }, .height = 20, // FIXME: 7 .corner_width = 29, + .bezel_width = 1, }; /* == Exported methods ===================================================== */ From 9372fb24f07258656a5edc1d38975268a5fbc72f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 16:56:28 +0100 Subject: [PATCH 201/390] Moves the titlebar title element code into a separate file. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/titlebar.c | 283 +---------------------------------- src/toolkit/titlebar_title.c | 271 +++++++++++++++++++++++++++++++++ src/toolkit/titlebar_title.h | 100 +++++++++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 6 files changed, 378 insertions(+), 280 deletions(-) create mode 100644 src/toolkit/titlebar_title.c create mode 100644 src/toolkit/titlebar_title.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 309778af..98d254d9 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -31,6 +31,7 @@ SET(PUBLIC_HEADER_FILES input.h resizebar.h titlebar.h + titlebar_title.h window.h workspace.h) @@ -47,6 +48,7 @@ TARGET_SOURCES(toolkit PRIVATE primitives.c resizebar.c titlebar.c + titlebar_title.c util.c window.c workspace.c) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 8150690e..21c789ef 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -25,6 +25,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" +#include "titlebar_title.h" #define WLR_USE_UNSTABLE #include @@ -32,8 +33,6 @@ /* == Declarations ========================================================= */ -/** Forward declaration. */ -typedef struct _wlmtk_titlebar_title_t wlmtk_titlebar_title_t; /** Forward declaration. */ typedef struct _wlmtk_titlebar_button_t wlmtk_titlebar_button_t; @@ -64,31 +63,6 @@ struct _wlmtk_titlebar_t { wlmtk_titlebar_style_t style; }; -/** State of the title bar's title. */ -struct _wlmtk_titlebar_title_t { - /** Superclass: Buffer. */ - wlmtk_buffer_t super_buffer; - - /** The drawn title, when focussed. */ - struct wlr_buffer *focussed_wlr_buffer_ptr; - /** The drawn title, when blurred. */ - struct wlr_buffer *blurred_wlr_buffer_ptr; -}; - -static wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void); -static void wlmtk_titlebar_title_destroy( - wlmtk_titlebar_title_t *titlebar_title_ptr); -static bool wlmtk_titlebar_title_redraw( - wlmtk_titlebar_title_t *titlebar_title_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - int position, - int width, - bool activated, - const wlmtk_titlebar_style_t *style_ptr); -static wlmtk_element_t *wlmtk_titlebar_title_element( - wlmtk_titlebar_title_t *titlebar_title_ptr); - /** Function pointer to method for drawing the button contents. */ typedef void (*wlmtk_titlebar_button_draw_t)( cairo_t *cairo_ptr, uint32_t color); @@ -127,17 +101,6 @@ static bool redraw_buffers( wlmtk_titlebar_t *titlebar_ptr, unsigned width); -static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); -static void title_set_activated( - wlmtk_titlebar_title_t *titlebar_title_ptr, - bool activated); -struct wlr_buffer *title_create_buffer( - bs_gfxbuf_t *gfxbuf_ptr, - unsigned position, - unsigned width, - uint32_t text_color, - const wlmtk_titlebar_style_t *style_ptr); - /* == Data ================================================================= */ /** Method table for the box's virtual methods. */ @@ -145,11 +108,6 @@ static const wlmtk_box_impl_t titlebar_box_impl = { .destroy = titlebar_box_destroy }; -/** Buffer implementation for title of the title bar. */ -static const wlmtk_buffer_impl_t title_buffer_impl = { - .destroy = title_buffer_destroy -}; - /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -319,7 +277,8 @@ void wlmtk_titlebar_set_activated( { if (titlebar_ptr->activated == activated) return; titlebar_ptr->activated = activated; - title_set_activated(titlebar_ptr->title_ptr, titlebar_ptr->activated); + wlmtk_titlebar_title_set_activated( + titlebar_ptr->title_ptr, titlebar_ptr->activated); } /* ------------------------------------------------------------------------- */ @@ -382,181 +341,6 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) return true; } -/* == Title buffer methods ================================================= */ - -/* ------------------------------------------------------------------------- */ -/** - * Creates a title bar title. - * - * @return Title handle. - */ -wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void) -{ - wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( - 1, sizeof(wlmtk_titlebar_title_t)); - if (NULL == titlebar_title_ptr) return NULL; - - if (!wlmtk_buffer_init( - &titlebar_title_ptr->super_buffer, - &title_buffer_impl)) { - wlmtk_titlebar_title_destroy(titlebar_title_ptr); - return NULL; - } - - return titlebar_title_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Redraws the title section of the title bar. - * - * @param titlebar_title_ptr - * @param focussed_gfxbuf_ptr Titlebar background when focussed. - * @param blurred_gfxbuf_ptr Titlebar background when blurred. - * @param position Position of title telative to titlebar. - * @param width Width of title. - * @param activated Whether the title bar should start focussed. - * @param style_ptr - * - * @return true on success. - */ -bool wlmtk_titlebar_title_redraw( - wlmtk_titlebar_title_t *titlebar_title_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - int position, - int width, - bool activated, - const wlmtk_titlebar_style_t *style_ptr) -{ - BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); - BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); - BS_ASSERT(style_ptr->height == blurred_gfxbuf_ptr->height); - BS_ASSERT(position <= (int)focussed_gfxbuf_ptr->width); - BS_ASSERT(position + width <= (int)focussed_gfxbuf_ptr->width); - - struct wlr_buffer *focussed_wlr_buffer_ptr = title_create_buffer( - focussed_gfxbuf_ptr, position, width, - style_ptr->focussed_text_color, style_ptr); - struct wlr_buffer *blurred_wlr_buffer_ptr = title_create_buffer( - blurred_gfxbuf_ptr, position, width, - style_ptr->blurred_text_color, style_ptr); - - if (NULL == focussed_wlr_buffer_ptr || - NULL == blurred_wlr_buffer_ptr) { - wlr_buffer_drop_nullify(&focussed_wlr_buffer_ptr); - wlr_buffer_drop_nullify(&blurred_wlr_buffer_ptr); - return false; - } - - wlr_buffer_drop_nullify(&titlebar_title_ptr->focussed_wlr_buffer_ptr); - titlebar_title_ptr->focussed_wlr_buffer_ptr = focussed_wlr_buffer_ptr; - wlr_buffer_drop_nullify(&titlebar_title_ptr->blurred_wlr_buffer_ptr); - titlebar_title_ptr->blurred_wlr_buffer_ptr = blurred_wlr_buffer_ptr; - - title_set_activated(titlebar_title_ptr, activated); - return true; -} - -/* ------------------------------------------------------------------------- */ -/** - * Returns the superclass @ref wlmtk_element_t for the titlebar title. - * - * @param titlebar_title_ptr - * - * @return Pointer to the super element. - */ -wlmtk_element_t *wlmtk_titlebar_title_element( - wlmtk_titlebar_title_t *titlebar_title_ptr) -{ - return &titlebar_title_ptr->super_buffer.super_element; -} - -/* ------------------------------------------------------------------------- */ -/** - * Destroys the titlebar title. - * - * @param titlebar_title_ptr - */ -void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *titlebar_title_ptr) -{ - wlr_buffer_drop_nullify(&titlebar_title_ptr->focussed_wlr_buffer_ptr); - wlr_buffer_drop_nullify(&titlebar_title_ptr->blurred_wlr_buffer_ptr); - wlmtk_buffer_fini(&titlebar_title_ptr->super_buffer); - free(titlebar_title_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Dtor. Forwards to @ref wlmtk_titlebar_title_destroy. */ -void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) -{ - wlmtk_titlebar_title_t *titlebar_title_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_titlebar_title_t, super_buffer); - wlmtk_titlebar_title_destroy(titlebar_title_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Sets whether the title is drawn focussed (activated) or blurred. - * - * @param titlebar_title_ptr - * @param activated - */ -void title_set_activated( - wlmtk_titlebar_title_t *titlebar_title_ptr, - bool activated) -{ - wlmtk_buffer_set( - &titlebar_title_ptr->super_buffer, - activated ? - titlebar_title_ptr->focussed_wlr_buffer_ptr : - titlebar_title_ptr->blurred_wlr_buffer_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Creates a WLR buffer with the title's texture, as specified. - * - * @param gfxbuf_ptr - * @param position - * @param width - * @param text_color - * @param style_ptr - * - * @return A pointer to a `struct wlr_buffer` with the texture. - */ -struct wlr_buffer *title_create_buffer( - bs_gfxbuf_t *gfxbuf_ptr, - unsigned position, - unsigned width, - uint32_t text_color, - const wlmtk_titlebar_style_t *style_ptr) -{ - struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - width, style_ptr->height); - if (NULL == wlr_buffer_ptr) return NULL; - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), - 0, 0, - gfxbuf_ptr, - position, 0, - width, style_ptr->height); - - cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); - if (NULL == cairo_ptr) { - wlr_buffer_drop(wlr_buffer_ptr); - return NULL; - } - wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); - wlmaker_primitives_draw_window_title( - cairo_ptr, "Title", text_color); - cairo_destroy(cairo_ptr); - - return wlr_buffer_ptr; -} - /* == Title bar button ===================================================== */ static void titlebar_button_destroy(wlmtk_button_t *button_ptr); @@ -740,12 +524,10 @@ struct wlr_buffer *create_buf( static void test_create_destroy(bs_test_t *test_ptr); static void test_create_empty(bs_test_t *test_ptr); -static void test_title(bs_test_t *test_ptr); const bs_test_case_t wlmtk_titlebar_test_cases[] = { { 1, "create_destroy", test_create_destroy }, { 1, "create_empty", test_create_empty }, - { 1, "title", test_title }, { 0, NULL, NULL } }; @@ -771,63 +553,4 @@ void test_create_empty(bs_test_t *test_ptr) wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); } -/* ------------------------------------------------------------------------- */ -/** Tests title drawing. */ -void test_title(bs_test_t *test_ptr) -{ - const wlmtk_titlebar_style_t style = { - .focussed_text_color = 0xffc0c0c0, - .blurred_text_color = 0xff808080, - .height = 22, - }; - bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(120, 22); - bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(120, 22); - bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); - bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); - - wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create(); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_titlebar_title_redraw( - titlebar_title_ptr, - focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style)); - - BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( - test_ptr, - bs_gfxbuf_from_wlr_buffer(titlebar_title_ptr->focussed_wlr_buffer_ptr), - "toolkit/title_focussed.png"); - BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( - test_ptr, - bs_gfxbuf_from_wlr_buffer(titlebar_title_ptr->blurred_wlr_buffer_ptr), - "toolkit/title_blurred.png"); - - // We had started as "activated", verify that's correct. - wlmtk_buffer_t *super_buffer_ptr = &titlebar_title_ptr->super_buffer; - BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( - test_ptr, - bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), - "toolkit/title_focussed.png"); - - // De-activated the title. Verify that was propagated. - title_set_activated(titlebar_title_ptr, false); - BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( - test_ptr, - bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), - "toolkit/title_blurred.png"); - - // Redraw with shorter width. Verify that's still correct. - wlmtk_titlebar_title_redraw( - titlebar_title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, - 10, 70, false, &style); - BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( - test_ptr, - bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), - "toolkit/title_blurred_short.png"); - - wlmtk_element_destroy(wlmtk_titlebar_title_element(titlebar_title_ptr)); - bs_gfxbuf_destroy(focussed_gfxbuf_ptr); - bs_gfxbuf_destroy(blurred_gfxbuf_ptr); -} - /* == End of titlebar.c ==================================================== */ diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c new file mode 100644 index 00000000..82f9dba9 --- /dev/null +++ b/src/toolkit/titlebar_title.c @@ -0,0 +1,271 @@ +/* ========================================================================= */ +/** + * @file titlebar_title.c + * Copyright (c) 2023 by Philipp Kaeser + */ + +#include "titlebar_title.h" + +#include "buffer.h" +#include "gfxbuf.h" +#include "primitives.h" + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +/** State of the title bar's title. */ +struct _wlmtk_titlebar_title_t { + /** Superclass: Buffer. */ + wlmtk_buffer_t super_buffer; + + /** The drawn title, when focussed. */ + struct wlr_buffer *focussed_wlr_buffer_ptr; + /** The drawn title, when blurred. */ + struct wlr_buffer *blurred_wlr_buffer_ptr; +}; + +static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static void title_set_activated( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bool activated); +struct wlr_buffer *title_create_buffer( + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + uint32_t text_color, + const wlmtk_titlebar_style_t *style_ptr); + +/* == Data ================================================================= */ + +/** Buffer implementation for title of the title bar. */ +static const wlmtk_buffer_impl_t title_buffer_impl = { + .destroy = title_buffer_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void) +{ + wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( + 1, sizeof(wlmtk_titlebar_title_t)); + if (NULL == titlebar_title_ptr) return NULL; + + if (!wlmtk_buffer_init( + &titlebar_title_ptr->super_buffer, + &title_buffer_impl)) { + wlmtk_titlebar_title_destroy(titlebar_title_ptr); + return NULL; + } + + return titlebar_title_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_title_destroy(wlmtk_titlebar_title_t *titlebar_title_ptr) +{ + wlr_buffer_drop_nullify(&titlebar_title_ptr->focussed_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&titlebar_title_ptr->blurred_wlr_buffer_ptr); + wlmtk_buffer_fini(&titlebar_title_ptr->super_buffer); + free(titlebar_title_ptr); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_titlebar_title_redraw( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + int width, + bool activated, + const wlmtk_titlebar_style_t *style_ptr) +{ + BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); + BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); + BS_ASSERT(style_ptr->height == blurred_gfxbuf_ptr->height); + BS_ASSERT(position <= (int)focussed_gfxbuf_ptr->width); + BS_ASSERT(position + width <= (int)focussed_gfxbuf_ptr->width); + + struct wlr_buffer *focussed_wlr_buffer_ptr = title_create_buffer( + focussed_gfxbuf_ptr, position, width, + style_ptr->focussed_text_color, style_ptr); + struct wlr_buffer *blurred_wlr_buffer_ptr = title_create_buffer( + blurred_gfxbuf_ptr, position, width, + style_ptr->blurred_text_color, style_ptr); + + if (NULL == focussed_wlr_buffer_ptr || + NULL == blurred_wlr_buffer_ptr) { + wlr_buffer_drop_nullify(&focussed_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&blurred_wlr_buffer_ptr); + return false; + } + + wlr_buffer_drop_nullify(&titlebar_title_ptr->focussed_wlr_buffer_ptr); + titlebar_title_ptr->focussed_wlr_buffer_ptr = focussed_wlr_buffer_ptr; + wlr_buffer_drop_nullify(&titlebar_title_ptr->blurred_wlr_buffer_ptr); + titlebar_title_ptr->blurred_wlr_buffer_ptr = blurred_wlr_buffer_ptr; + + title_set_activated(titlebar_title_ptr, activated); + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_title_set_activated( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bool activated) +{ + title_set_activated(titlebar_title_ptr, activated); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_titlebar_title_element( + wlmtk_titlebar_title_t *titlebar_title_ptr) +{ + return &titlebar_title_ptr->super_buffer.super_element; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Dtor. Forwards to @ref wlmtk_titlebar_title_destroy. */ +void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +{ + wlmtk_titlebar_title_t *titlebar_title_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_titlebar_title_t, super_buffer); + wlmtk_titlebar_title_destroy(titlebar_title_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Sets whether the title is drawn focussed (activated) or blurred. + * + * @param titlebar_title_ptr + * @param activated + */ +void title_set_activated( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bool activated) +{ + wlmtk_buffer_set( + &titlebar_title_ptr->super_buffer, + activated ? + titlebar_title_ptr->focussed_wlr_buffer_ptr : + titlebar_title_ptr->blurred_wlr_buffer_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Creates a WLR buffer with the title's texture, as specified. + * + * @param gfxbuf_ptr + * @param position + * @param width + * @param text_color + * @param style_ptr + * + * @return A pointer to a `struct wlr_buffer` with the texture. + */ +struct wlr_buffer *title_create_buffer( + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + uint32_t text_color, + const wlmtk_titlebar_style_t *style_ptr) +{ + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + width, style_ptr->height); + if (NULL == wlr_buffer_ptr) return NULL; + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), + 0, 0, + gfxbuf_ptr, + position, 0, + width, style_ptr->height); + + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(wlr_buffer_ptr); + return NULL; + } + wlmaker_primitives_draw_bezel_at( + cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); + wlmaker_primitives_draw_window_title( + cairo_ptr, "Title", text_color); + cairo_destroy(cairo_ptr); + + return wlr_buffer_ptr; +} + +/* == Unit tests =========================================================== */ + +static void test_title(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_titlebar_title_test_cases[] = { + { 1, "title", test_title }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests title drawing. */ +void test_title(bs_test_t *test_ptr) +{ + const wlmtk_titlebar_style_t style = { + .focussed_text_color = 0xffc0c0c0, + .blurred_text_color = 0xff808080, + .height = 22, + }; + bs_gfxbuf_t *focussed_gfxbuf_ptr = bs_gfxbuf_create(120, 22); + bs_gfxbuf_t *blurred_gfxbuf_ptr = bs_gfxbuf_create(120, 22); + bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); + bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); + + wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_titlebar_title_redraw( + titlebar_title_ptr, + focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style)); + + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(titlebar_title_ptr->focussed_wlr_buffer_ptr), + "toolkit/title_focussed.png"); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(titlebar_title_ptr->blurred_wlr_buffer_ptr), + "toolkit/title_blurred.png"); + + // We had started as "activated", verify that's correct. + wlmtk_buffer_t *super_buffer_ptr = &titlebar_title_ptr->super_buffer; + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_focussed.png"); + + // De-activated the title. Verify that was propagated. + title_set_activated(titlebar_title_ptr, false); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_blurred.png"); + + // Redraw with shorter width. Verify that's still correct. + wlmtk_titlebar_title_redraw( + titlebar_title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, + 10, 70, false, &style); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_blurred_short.png"); + + wlmtk_element_destroy(wlmtk_titlebar_title_element(titlebar_title_ptr)); + bs_gfxbuf_destroy(focussed_gfxbuf_ptr); + bs_gfxbuf_destroy(blurred_gfxbuf_ptr); +} + +/* == End of titlebar_title.c ============================================== */ diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h new file mode 100644 index 00000000..d80853a6 --- /dev/null +++ b/src/toolkit/titlebar_title.h @@ -0,0 +1,100 @@ +/* ========================================================================= */ +/** + * @file titlebar_title.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_TITLEBAR_TITLE_H__ +#define __WLMTK_TITLEBAR_TITLE_H__ + +/** Forward declaration. */ +typedef struct _wlmtk_titlebar_title_t wlmtk_titlebar_title_t; + +#include +#include + +#include "titlebar.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a title bar title. + * + * @return Title handle. + */ +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void); + +/** + * Destroys the titlebar title. + * + * @param titlebar_title_ptr + */ +void wlmtk_titlebar_title_destroy( + wlmtk_titlebar_title_t *titlebar_title_ptr); + +/** + * Redraws the title section of the title bar. + * + * @param titlebar_title_ptr + * @param focussed_gfxbuf_ptr Titlebar background when focussed. + * @param blurred_gfxbuf_ptr Titlebar background when blurred. + * @param position Position of title telative to titlebar. + * @param width Width of title. + * @param activated Whether the title bar should start focussed. + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_titlebar_title_redraw( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + int width, + bool activated, + const wlmtk_titlebar_style_t *style_ptr); + +/** + * Sets activation status of the titlebar's title. + * + * @param titlebar_title_ptr + * @param activated + */ +void wlmtk_titlebar_title_set_activated( + wlmtk_titlebar_title_t *titlebar_title_ptr, + bool activated); + +/** + * Returns the superclass @ref wlmtk_element_t for the titlebar title. + * + * @param titlebar_title_ptr + * + * @return Pointer to the super element. + */ +wlmtk_element_t *wlmtk_titlebar_title_element( + wlmtk_titlebar_title_t *titlebar_title_ptr); + +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_titlebar_title_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_TITLEBAR_TITLE_H__ */ +/* == End of titlebar_title.h ============================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 2c519550..00a2d9d6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -40,6 +40,7 @@ #include "input.h" #include "resizebar.h" #include "titlebar.h" +#include "titlebar_title.h" #include "window.h" #include "workspace.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index d42de3b0..53ff48f2 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -30,6 +30,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "fsm", wlmtk_fsm_test_cases }, { 1, "resizebar", wlmtk_resizebar_test_cases }, { 1, "titlebar", wlmtk_titlebar_test_cases }, + { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, From 6b224831378dfc5e1def470515c09baecb6c4b7b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 11 Nov 2023 17:01:31 +0100 Subject: [PATCH 202/390] Refactors wlmtk_titlebar_button_t out into a separate file. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/titlebar.c | 216 +--------------------------------- src/toolkit/titlebar_button.c | 202 +++++++++++++++++++++++++++++++ src/toolkit/titlebar_button.h | 90 ++++++++++++++ 4 files changed, 295 insertions(+), 215 deletions(-) create mode 100644 src/toolkit/titlebar_button.c create mode 100644 src/toolkit/titlebar_button.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 98d254d9..4ae7226a 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -31,6 +31,7 @@ SET(PUBLIC_HEADER_FILES input.h resizebar.h titlebar.h + titlebar_button.h titlebar_title.h window.h workspace.h) @@ -48,6 +49,7 @@ TARGET_SOURCES(toolkit PRIVATE primitives.c resizebar.c titlebar.c + titlebar_button.c titlebar_title.c util.c window.c diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 21c789ef..fc70e183 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -25,6 +25,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" +#include "titlebar_button.h" #include "titlebar_title.h" #define WLR_USE_UNSTABLE @@ -33,9 +34,6 @@ /* == Declarations ========================================================= */ -/** Forward declaration. */ -typedef struct _wlmtk_titlebar_button_t wlmtk_titlebar_button_t; - /** State of the title bar. */ struct _wlmtk_titlebar_t { /** Superclass: Box. */ @@ -63,39 +61,6 @@ struct _wlmtk_titlebar_t { wlmtk_titlebar_style_t style; }; -/** Function pointer to method for drawing the button contents. */ -typedef void (*wlmtk_titlebar_button_draw_t)( - cairo_t *cairo_ptr, uint32_t color); - -/** State of a titlebar button. */ -struct _wlmtk_titlebar_button_t { - /** Superclass: Button. */ - wlmtk_button_t super_button; - - /** For drawing the button contents. */ - wlmtk_titlebar_button_draw_t draw; - - /** WLR buffer of the button when focussed & released. */ - struct wlr_buffer *focussed_released_wlr_buffer_ptr; - /** WLR buffer of the button when focussed & pressed. */ - struct wlr_buffer *focussed_pressed_wlr_buffer_ptr; - /** WLR buffer of the button when blurred. */ - struct wlr_buffer *blurred_wlr_buffer_ptr; -}; - -static wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( - wlmtk_titlebar_button_draw_t draw); -static void wlmtk_titlebar_button_destroy( - wlmtk_titlebar_button_t *titlebar_button_ptr); -static bool wlmtk_titlebar_button_redraw( - wlmtk_titlebar_button_t *titlebar_button_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - int position, - const wlmtk_titlebar_style_t *style_ptr); -wlmtk_element_t *wlmtk_titlebar_button_element( - wlmtk_titlebar_button_t *titlebar_button_ptr); - static void titlebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers( wlmtk_titlebar_t *titlebar_ptr, @@ -341,185 +306,6 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) return true; } -/* == Title bar button ===================================================== */ - -static void titlebar_button_destroy(wlmtk_button_t *button_ptr); -static struct wlr_buffer *create_buf( - bs_gfxbuf_t *gfxbuf_ptr, - int position, - bool pressed, - const wlmtk_titlebar_style_t *style_ptr, - wlmtk_titlebar_button_draw_t draw); - -/** Buffer implementation for title of the title bar. */ -static const wlmtk_button_impl_t titlebar_button_impl = { - .destroy = titlebar_button_destroy -}; - -/* ------------------------------------------------------------------------- */ -/** - * Creates a button for the titlebar. - * - * @param draw - * - * @return Pointer to the titlebar button, or NULL on error. - */ -wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( - wlmtk_titlebar_button_draw_t draw) -{ - wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( - 1, sizeof(wlmtk_titlebar_button_t)); - if (NULL == titlebar_button_ptr) return NULL; - titlebar_button_ptr->draw = draw; - - if (!wlmtk_button_init( - &titlebar_button_ptr->super_button, - &titlebar_button_impl)) { - wlmtk_titlebar_button_destroy(titlebar_button_ptr); - return NULL; - } - - return titlebar_button_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Destroys the titlebar button. - * - * @param titlebar_button_ptr - */ -void wlmtk_titlebar_button_destroy( - wlmtk_titlebar_button_t *titlebar_button_ptr) -{ - wlr_buffer_drop_nullify( - &titlebar_button_ptr->focussed_released_wlr_buffer_ptr); - wlr_buffer_drop_nullify( - &titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); - wlr_buffer_drop_nullify( - &titlebar_button_ptr->blurred_wlr_buffer_ptr); - - wlmtk_button_fini(&titlebar_button_ptr->super_button); - free(titlebar_button_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Redraws the titlebar button for given textures, position and style. - * - * @param titlebar_button_ptr - * @param focussed_gfxbuf_ptr - * @param blurred_gfxbuf_ptr - * @param position - * @param style_ptr - * - * @return true on success. - */ -bool wlmtk_titlebar_button_redraw( - wlmtk_titlebar_button_t *titlebar_button_ptr, - bs_gfxbuf_t *focussed_gfxbuf_ptr, - bs_gfxbuf_t *blurred_gfxbuf_ptr, - int position, - const wlmtk_titlebar_style_t *style_ptr) -{ - BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); - BS_ASSERT(focussed_gfxbuf_ptr->height == blurred_gfxbuf_ptr->height); - BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); - BS_ASSERT(position + style_ptr->height <= focussed_gfxbuf_ptr->width); - - struct wlr_buffer *focussed_released_ptr = create_buf( - focussed_gfxbuf_ptr, position, false, style_ptr, - titlebar_button_ptr->draw); - struct wlr_buffer *focussed_pressed_ptr = create_buf( - focussed_gfxbuf_ptr, position, true, style_ptr, - titlebar_button_ptr->draw); - struct wlr_buffer *blurred_ptr = create_buf( - blurred_gfxbuf_ptr, position, false, style_ptr, - titlebar_button_ptr->draw); - - if (NULL != focussed_released_ptr && - NULL != focussed_pressed_ptr && - NULL != blurred_ptr) { - wlr_buffer_drop_nullify( - &titlebar_button_ptr->focussed_released_wlr_buffer_ptr); - wlr_buffer_drop_nullify( - &titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); - wlr_buffer_drop_nullify( - &titlebar_button_ptr->blurred_wlr_buffer_ptr); - - titlebar_button_ptr->focussed_released_wlr_buffer_ptr = - focussed_released_ptr; - titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr = - focussed_pressed_ptr; - titlebar_button_ptr->blurred_wlr_buffer_ptr = blurred_ptr; - - // FIXME: Depend on focus/blur. - wlmtk_button_set( - &titlebar_button_ptr->super_button, - titlebar_button_ptr->focussed_released_wlr_buffer_ptr, - titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); - - return true; - } - - wlr_buffer_drop_nullify(&focussed_released_ptr); - wlr_buffer_drop_nullify(&focussed_pressed_ptr); - wlr_buffer_drop_nullify(&blurred_ptr); - return false; -} - -/* ------------------------------------------------------------------------- */ -/** - * Returns the titlebar button's super element. - * - * @param titlebar_button_ptr - * - * @return Pointer to the superclass @ref wlmtk_element_t. - */ -wlmtk_element_t *wlmtk_titlebar_button_element( - wlmtk_titlebar_button_t *titlebar_button_ptr) -{ - return &titlebar_button_ptr->super_button.super_buffer.super_element; -} - -/* ------------------------------------------------------------------------- */ -/** Virtual destructor, wraps to @ref wlmtk_titlebar_button_destroy. */ -void titlebar_button_destroy(wlmtk_button_t *button_ptr) -{ - wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( - button_ptr, wlmtk_titlebar_button_t, super_button); - wlmtk_titlebar_button_destroy(titlebar_button_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Helper: Creates a WLR buffer for the button. */ -struct wlr_buffer *create_buf( - bs_gfxbuf_t *gfxbuf_ptr, - int position, - bool pressed, - const wlmtk_titlebar_style_t *style_ptr, - void (*draw)(cairo_t *cairo_ptr, uint32_t color)) -{ - struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - style_ptr->height, style_ptr->height); - if (NULL == wlr_buffer_ptr) return NULL; - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, - gfxbuf_ptr, position, 0, style_ptr->height, style_ptr->height); - - cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); - if (NULL == cairo_ptr) { - wlr_buffer_drop(wlr_buffer_ptr); - return NULL; - } - wlmaker_primitives_draw_bezel( - cairo_ptr, style_ptr->bezel_width, !pressed); - draw(cairo_ptr, style_ptr->focussed_text_color); - cairo_destroy(cairo_ptr); - - return wlr_buffer_ptr; -} - /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c new file mode 100644 index 00000000..a8965470 --- /dev/null +++ b/src/toolkit/titlebar_button.c @@ -0,0 +1,202 @@ +/* ========================================================================= */ +/** + * @file titlebar_button.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "titlebar_button.h" + +#include "button.h" +#include "gfxbuf.h" +#include "primitives.h" + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +/** State of a titlebar button. */ +struct _wlmtk_titlebar_button_t { + /** Superclass: Button. */ + wlmtk_button_t super_button; + + /** For drawing the button contents. */ + wlmtk_titlebar_button_draw_t draw; + + /** WLR buffer of the button when focussed & released. */ + struct wlr_buffer *focussed_released_wlr_buffer_ptr; + /** WLR buffer of the button when focussed & pressed. */ + struct wlr_buffer *focussed_pressed_wlr_buffer_ptr; + /** WLR buffer of the button when blurred. */ + struct wlr_buffer *blurred_wlr_buffer_ptr; +}; + +static void titlebar_button_destroy(wlmtk_button_t *button_ptr); +static struct wlr_buffer *create_buf( + bs_gfxbuf_t *gfxbuf_ptr, + int position, + bool pressed, + const wlmtk_titlebar_style_t *style_ptr, + wlmtk_titlebar_button_draw_t draw); + +/* == Data ================================================================= */ + +/** Buffer implementation for title of the title bar. */ +static const wlmtk_button_impl_t titlebar_button_impl = { + .destroy = titlebar_button_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_titlebar_button_draw_t draw) +{ + wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( + 1, sizeof(wlmtk_titlebar_button_t)); + if (NULL == titlebar_button_ptr) return NULL; + titlebar_button_ptr->draw = draw; + + if (!wlmtk_button_init( + &titlebar_button_ptr->super_button, + &titlebar_button_impl)) { + wlmtk_titlebar_button_destroy(titlebar_button_ptr); + return NULL; + } + + return titlebar_button_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_button_destroy( + wlmtk_titlebar_button_t *titlebar_button_ptr) +{ + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_released_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->blurred_wlr_buffer_ptr); + + wlmtk_button_fini(&titlebar_button_ptr->super_button); + free(titlebar_button_ptr); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_titlebar_button_redraw( + wlmtk_titlebar_button_t *titlebar_button_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + const wlmtk_titlebar_style_t *style_ptr) +{ + BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); + BS_ASSERT(focussed_gfxbuf_ptr->height == blurred_gfxbuf_ptr->height); + BS_ASSERT(style_ptr->height == focussed_gfxbuf_ptr->height); + BS_ASSERT(position + style_ptr->height <= focussed_gfxbuf_ptr->width); + + struct wlr_buffer *focussed_released_ptr = create_buf( + focussed_gfxbuf_ptr, position, false, style_ptr, + titlebar_button_ptr->draw); + struct wlr_buffer *focussed_pressed_ptr = create_buf( + focussed_gfxbuf_ptr, position, true, style_ptr, + titlebar_button_ptr->draw); + struct wlr_buffer *blurred_ptr = create_buf( + blurred_gfxbuf_ptr, position, false, style_ptr, + titlebar_button_ptr->draw); + + if (NULL != focussed_released_ptr && + NULL != focussed_pressed_ptr && + NULL != blurred_ptr) { + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_released_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &titlebar_button_ptr->blurred_wlr_buffer_ptr); + + titlebar_button_ptr->focussed_released_wlr_buffer_ptr = + focussed_released_ptr; + titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr = + focussed_pressed_ptr; + titlebar_button_ptr->blurred_wlr_buffer_ptr = blurred_ptr; + + // FIXME: Depend on focus/blur. + wlmtk_button_set( + &titlebar_button_ptr->super_button, + titlebar_button_ptr->focussed_released_wlr_buffer_ptr, + titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + + return true; + } + + wlr_buffer_drop_nullify(&focussed_released_ptr); + wlr_buffer_drop_nullify(&focussed_pressed_ptr); + wlr_buffer_drop_nullify(&blurred_ptr); + return false; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_titlebar_button_element( + wlmtk_titlebar_button_t *titlebar_button_ptr) +{ + return &titlebar_button_ptr->super_button.super_buffer.super_element; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual destructor, wraps to @ref wlmtk_titlebar_button_destroy. */ +void titlebar_button_destroy(wlmtk_button_t *button_ptr) +{ + wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( + button_ptr, wlmtk_titlebar_button_t, super_button); + wlmtk_titlebar_button_destroy(titlebar_button_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Helper: Creates a WLR buffer for the button. */ +struct wlr_buffer *create_buf( + bs_gfxbuf_t *gfxbuf_ptr, + int position, + bool pressed, + const wlmtk_titlebar_style_t *style_ptr, + void (*draw)(cairo_t *cairo_ptr, uint32_t color)) +{ + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + style_ptr->height, style_ptr->height); + if (NULL == wlr_buffer_ptr) return NULL; + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, + gfxbuf_ptr, position, 0, style_ptr->height, style_ptr->height); + + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(wlr_buffer_ptr); + return NULL; + } + wlmaker_primitives_draw_bezel( + cairo_ptr, style_ptr->bezel_width, !pressed); + draw(cairo_ptr, style_ptr->focussed_text_color); + cairo_destroy(cairo_ptr); + + return wlr_buffer_ptr; +} + +/* == End of titlebar_button.c ============================================= */ diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h new file mode 100644 index 00000000..1de2c4b3 --- /dev/null +++ b/src/toolkit/titlebar_button.h @@ -0,0 +1,90 @@ +/* ========================================================================= */ +/** + * @file titlebar_button.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_TITLEBAR_BUTTON_H__ +#define __WLMTK_TITLEBAR_BUTTON_H__ + +#include +#include + +/** Forward declaration. */ +typedef struct _wlmtk_titlebar_button_t wlmtk_titlebar_button_t; + +#include "titlebar.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Function pointer to method for drawing the button contents. */ +typedef void (*wlmtk_titlebar_button_draw_t)( + cairo_t *cairo_ptr, uint32_t color); + +/** + * Creates a button for the titlebar. + * + * @param draw + * + * @return Pointer to the titlebar button, or NULL on error. + */ +wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_titlebar_button_draw_t draw); + +/** + * Destroys the titlebar button. + * + * @param titlebar_button_ptr + */ +void wlmtk_titlebar_button_destroy( + wlmtk_titlebar_button_t *titlebar_button_ptr); + +/** + * Redraws the titlebar button for given textures, position and style. + * + * @param titlebar_button_ptr + * @param focussed_gfxbuf_ptr + * @param blurred_gfxbuf_ptr + * @param position + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_titlebar_button_redraw( + wlmtk_titlebar_button_t *titlebar_button_ptr, + bs_gfxbuf_t *focussed_gfxbuf_ptr, + bs_gfxbuf_t *blurred_gfxbuf_ptr, + int position, + const wlmtk_titlebar_style_t *style_ptr); + +/** + * Returns the titlebar button's super element. + * + * @param titlebar_button_ptr + * + * @return Pointer to the superclass @ref wlmtk_element_t. + */ +wlmtk_element_t *wlmtk_titlebar_button_element( + wlmtk_titlebar_button_t *titlebar_button_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_TITLEBAR_BUTTON_H__ */ +/* == End of titlebar_button.h ============================================= */ From 53507374a587d83a3dcaed12a2da256d5640d47a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 17:06:59 +0100 Subject: [PATCH 203/390] Refactors wlmtk_resizebar_button_t into a separate file. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/resizebar.c | 182 +++-------------------------------- src/toolkit/resizebar_area.c | 160 ++++++++++++++++++++++++++++++ src/toolkit/resizebar_area.h | 76 +++++++++++++++ 4 files changed, 254 insertions(+), 166 deletions(-) create mode 100644 src/toolkit/resizebar_area.c create mode 100644 src/toolkit/resizebar_area.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 4ae7226a..afaedc25 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -30,6 +30,7 @@ SET(PUBLIC_HEADER_FILES fsm.h input.h resizebar.h + resizebar_area.h titlebar.h titlebar_button.h titlebar_title.h @@ -48,6 +49,7 @@ TARGET_SOURCES(toolkit PRIVATE gfxbuf.c primitives.c resizebar.c + resizebar_area.c titlebar.c titlebar_button.c titlebar_title.c diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 5326bf91..8e5729b8 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -1,16 +1,30 @@ /* ========================================================================= */ /** * @file resizebar.c - * Copyright (c) 2023 by Philipp Kaeser + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "resizebar.h" #include "box.h" #include "buffer.h" -#include "button.h" #include "gfxbuf.h" #include "primitives.h" +#include "resizebar_area.h" #include @@ -20,9 +34,6 @@ /* == Declarations ========================================================= */ -/** Forward declaration: Element of the resizebar. */ -typedef struct _wlmtk_resizebar_button_t wlmtk_resizebar_button_t ; - /** State of the title bar. */ struct _wlmtk_resizebar_t { /** Superclass: Box. */ @@ -44,29 +55,9 @@ struct _wlmtk_resizebar_t { wlmtk_resizebar_button_t *right_button_ptr; }; -/** State of an element of the resize bar. */ -struct _wlmtk_resizebar_button_t { - /** Superclass: Buffer. */ - wlmtk_button_t super_button; -}; - -static wlmtk_resizebar_button_t *wlmtk_resizebar_button_create(void); -static void wlmtk_resizebar_button_destroy( - wlmtk_resizebar_button_t *resizebar_button_ptr); -static bool wlmtk_resizebar_button_redraw( - wlmtk_resizebar_button_t *resizebar_button_ptr, - bs_gfxbuf_t *gfxbuf_ptr, - unsigned position, - unsigned width, - const wlmtk_resizebar_style_t *style_ptr); -static wlmtk_element_t *wlmtk_resizebar_button_element( - wlmtk_resizebar_button_t *resizebar_button_ptr); - static void resizebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width); -static void button_destroy(wlmtk_button_t *button_ptr); - /* == Data ================================================================= */ /** Method table for the box's virtual methods. */ @@ -74,11 +65,6 @@ static const wlmtk_box_impl_t resizebar_box_impl = { .destroy = resizebar_box_destroy }; -/** Buffer implementation for title of the title bar. */ -static const wlmtk_button_impl_t element_button_impl = { - .destroy = button_destroy -}; - /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -235,133 +221,6 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) return &resizebar_ptr->super_box.super_container.super_element; } -/* == Resizebar element methods ============================================ */ - -/* ------------------------------------------------------------------------- */ -/** - * Creates a resizebar button. - * - * @return Pointer to the resizebar button. - */ -wlmtk_resizebar_button_t *wlmtk_resizebar_button_create() -{ - wlmtk_resizebar_button_t *resizebar_button = logged_calloc( - 1, sizeof(wlmtk_resizebar_button_t)); - if (NULL == resizebar_button) return NULL; - - if (!wlmtk_button_init( - &resizebar_button->super_button, - &element_button_impl)) { - wlmtk_resizebar_button_destroy(resizebar_button); - return NULL; - } - - return resizebar_button; -} - -/* ------------------------------------------------------------------------- */ -/** - * Destroys the resizebar element. - * - * @param resizebar_button_ptr - */ -void wlmtk_resizebar_button_destroy( - wlmtk_resizebar_button_t *resizebar_button_ptr) -{ - wlmtk_button_fini(&resizebar_button_ptr->super_button); - free(resizebar_button_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Creates a resizebar button texture. - * - * @param gfxbuf_ptr - * @param position - * @param width - * @param style_ptr - * @param pressed - * - * @return A pointer to a newly allocated `struct wlr_buffer`. - */ -struct wlr_buffer *create_buffer( - bs_gfxbuf_t *gfxbuf_ptr, - unsigned position, - unsigned width, - const wlmtk_resizebar_style_t *style_ptr, - bool pressed) -{ - struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( - width, style_ptr->height); - if (NULL == wlr_buffer_ptr) return NULL; - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, - gfxbuf_ptr, position, 0, width, style_ptr->height); - - cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); - if (NULL == cairo_ptr) { - wlr_buffer_drop(wlr_buffer_ptr); - return false; - } - wlmaker_primitives_draw_bezel_at( - cairo_ptr, 0, 0, width, - style_ptr->height, style_ptr->bezel_width, !pressed); - cairo_destroy(cairo_ptr); - - return wlr_buffer_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Redraws the element, with updated position and width. - * - * @param resizebar_button_ptr - * @param gfxbuf_ptr - * @param position - * @param width - * @param style_ptr - * - * @return true on success. - */ -bool wlmtk_resizebar_button_redraw( - wlmtk_resizebar_button_t *resizebar_button_ptr, - bs_gfxbuf_t *gfxbuf_ptr, - unsigned position, - unsigned width, - const wlmtk_resizebar_style_t *style_ptr) -{ - struct wlr_buffer *released_wlr_buffer_ptr = create_buffer( - gfxbuf_ptr, position, width, style_ptr, false); - struct wlr_buffer *pressed_wlr_buffer_ptr = create_buffer( - gfxbuf_ptr, position, width, style_ptr, true); - - if (NULL == released_wlr_buffer_ptr || - NULL == pressed_wlr_buffer_ptr) { - wlr_buffer_drop_nullify(&released_wlr_buffer_ptr); - wlr_buffer_drop_nullify(&pressed_wlr_buffer_ptr); - return false; - } - - // Will take ownershp of the buffers. - wlmtk_button_set( - &resizebar_button_ptr->super_button, - released_wlr_buffer_ptr, - pressed_wlr_buffer_ptr); - - wlr_buffer_drop(released_wlr_buffer_ptr); - wlr_buffer_drop(pressed_wlr_buffer_ptr); - return true; -} - -/* ------------------------------------------------------------------------- */ -/** Returns the button's super_buffer.super_element address. */ -wlmtk_element_t *wlmtk_resizebar_button_element( - wlmtk_resizebar_button_t *resizebar_button_ptr) -{ - return &resizebar_button_ptr->super_button.super_buffer.super_element; -} - /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -398,15 +257,6 @@ bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width) return true; } -/* ------------------------------------------------------------------------- */ -/** Dtor. Forwards to @ref wlmtk_resizebar_button_destroy. */ -void button_destroy(wlmtk_button_t *button_ptr) -{ - wlmtk_resizebar_button_t *resizebar_button_ptr = BS_CONTAINER_OF( - button_ptr, wlmtk_resizebar_button_t, super_button); - wlmtk_resizebar_button_destroy(resizebar_button_ptr); -} - /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c new file mode 100644 index 00000000..78f17d9b --- /dev/null +++ b/src/toolkit/resizebar_area.c @@ -0,0 +1,160 @@ +/* ========================================================================= */ +/** + * @file resizebar_area.c + * Copyright (c) 2023 by Philipp Kaeser + */ + +#include "resizebar_area.h" + +#include "box.h" +#include "buffer.h" +#include "button.h" +#include "gfxbuf.h" +#include "primitives.h" + +#include + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +/** State of an element of the resize bar. */ +struct _wlmtk_resizebar_button_t { + /** Superclass: Buffer. */ + wlmtk_button_t super_button; +}; + +static void button_destroy(wlmtk_button_t *button_ptr); +static struct wlr_buffer *create_buffer( + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr, + bool pressed); + +/* == Data ================================================================= */ + +/** Buffer implementation for title of the title bar. */ +static const wlmtk_button_impl_t element_button_impl = { + .destroy = button_destroy +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_resizebar_button_t *wlmtk_resizebar_button_create() +{ + wlmtk_resizebar_button_t *resizebar_button = logged_calloc( + 1, sizeof(wlmtk_resizebar_button_t)); + if (NULL == resizebar_button) return NULL; + + if (!wlmtk_button_init( + &resizebar_button->super_button, + &element_button_impl)) { + wlmtk_resizebar_button_destroy(resizebar_button); + return NULL; + } + + return resizebar_button; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_resizebar_button_destroy( + wlmtk_resizebar_button_t *resizebar_button_ptr) +{ + wlmtk_button_fini(&resizebar_button_ptr->super_button); + free(resizebar_button_ptr); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_resizebar_button_redraw( + wlmtk_resizebar_button_t *resizebar_button_ptr, + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr) +{ + struct wlr_buffer *released_wlr_buffer_ptr = create_buffer( + gfxbuf_ptr, position, width, style_ptr, false); + struct wlr_buffer *pressed_wlr_buffer_ptr = create_buffer( + gfxbuf_ptr, position, width, style_ptr, true); + + if (NULL == released_wlr_buffer_ptr || + NULL == pressed_wlr_buffer_ptr) { + wlr_buffer_drop_nullify(&released_wlr_buffer_ptr); + wlr_buffer_drop_nullify(&pressed_wlr_buffer_ptr); + return false; + } + + // Will take ownershp of the buffers. + wlmtk_button_set( + &resizebar_button_ptr->super_button, + released_wlr_buffer_ptr, + pressed_wlr_buffer_ptr); + + wlr_buffer_drop(released_wlr_buffer_ptr); + wlr_buffer_drop(pressed_wlr_buffer_ptr); + return true; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_resizebar_button_element( + wlmtk_resizebar_button_t *resizebar_button_ptr) +{ + return &resizebar_button_ptr->super_button.super_buffer.super_element; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Dtor. Forwards to @ref wlmtk_resizebar_button_destroy. */ +void button_destroy(wlmtk_button_t *button_ptr) +{ + wlmtk_resizebar_button_t *resizebar_button_ptr = BS_CONTAINER_OF( + button_ptr, wlmtk_resizebar_button_t, super_button); + wlmtk_resizebar_button_destroy(resizebar_button_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Creates a resizebar button texture. + * + * @param gfxbuf_ptr + * @param position + * @param width + * @param style_ptr + * @param pressed + * + * @return A pointer to a newly allocated `struct wlr_buffer`. + */ +struct wlr_buffer *create_buffer( + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr, + bool pressed) +{ + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + width, style_ptr->height); + if (NULL == wlr_buffer_ptr) return NULL; + + bs_gfxbuf_copy_area( + bs_gfxbuf_from_wlr_buffer(wlr_buffer_ptr), 0, 0, + gfxbuf_ptr, position, 0, width, style_ptr->height); + + cairo_t *cairo_ptr = cairo_create_from_wlr_buffer(wlr_buffer_ptr); + if (NULL == cairo_ptr) { + wlr_buffer_drop(wlr_buffer_ptr); + return false; + } + wlmaker_primitives_draw_bezel_at( + cairo_ptr, 0, 0, width, + style_ptr->height, style_ptr->bezel_width, !pressed); + cairo_destroy(cairo_ptr); + + return wlr_buffer_ptr; +} + +/* == End of resizebar_area.c ============================================== */ diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h new file mode 100644 index 00000000..4035dd4f --- /dev/null +++ b/src/toolkit/resizebar_area.h @@ -0,0 +1,76 @@ +/* ========================================================================= */ +/** + * @file resizebar_area.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_RESIZEBAR_AREA_H__ +#define __WLMTK_RESIZEBAR_AREA_H__ + +#include + +/** Forward declaration: Element of the resizebar. */ +typedef struct _wlmtk_resizebar_button_t wlmtk_resizebar_button_t ; + +#include "resizebar.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a resizebar button. + * + * @return Pointer to the resizebar button. + */ +wlmtk_resizebar_button_t *wlmtk_resizebar_button_create(void); + +/** + * Destroys the resizebar element. + * + * @param resizebar_button_ptr + */ +void wlmtk_resizebar_button_destroy( + wlmtk_resizebar_button_t *resizebar_button_ptr); + +/** + * Redraws the element, with updated position and width. + * + * @param resizebar_button_ptr + * @param gfxbuf_ptr + * @param position + * @param width + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_resizebar_button_redraw( + wlmtk_resizebar_button_t *resizebar_button_ptr, + bs_gfxbuf_t *gfxbuf_ptr, + unsigned position, + unsigned width, + const wlmtk_resizebar_style_t *style_ptr); + +/** Returns the button's super_buffer.super_element address. */ +wlmtk_element_t *wlmtk_resizebar_button_element( + wlmtk_resizebar_button_t *resizebar_button_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_RESIZEBAR_AREA_H__ */ +/* == End of resizebar_area.h ============================================== */ From a2acc41e1e11e3425c31f66f92d709ad098ef669 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 17:08:37 +0100 Subject: [PATCH 204/390] s/wlmtk_resizebar_button_t/wlmtk_resizebar_area_t/ --- src/toolkit/resizebar.c | 66 ++++++++++++++++++------------------ src/toolkit/resizebar_area.c | 44 ++++++++++++------------ src/toolkit/resizebar_area.h | 20 +++++------ 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 8e5729b8..1bb36367 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -48,11 +48,11 @@ struct _wlmtk_resizebar_t { bs_gfxbuf_t *gfxbuf_ptr; /** Left element of the resizebar. */ - wlmtk_resizebar_button_t *left_button_ptr; + wlmtk_resizebar_area_t *left_area_ptr; /** Center element of the resizebar. */ - wlmtk_resizebar_button_t *center_button_ptr; + wlmtk_resizebar_area_t *center_area_ptr; /** Right element of the resizebar. */ - wlmtk_resizebar_button_t *right_button_ptr; + wlmtk_resizebar_area_t *right_area_ptr; }; static void resizebar_box_destroy(wlmtk_box_t *box_ptr); @@ -89,34 +89,34 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } - resizebar_ptr->left_button_ptr = wlmtk_resizebar_button_create(); - if (NULL == resizebar_ptr->left_button_ptr) { + resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create(); + if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } wlmtk_container_add_element( &resizebar_ptr->super_box.super_container, - wlmtk_resizebar_button_element(resizebar_ptr->left_button_ptr)); + wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); - resizebar_ptr->center_button_ptr = wlmtk_resizebar_button_create(); - if (NULL == resizebar_ptr->center_button_ptr) { + resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create(); + if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } wlmtk_container_add_element_before( &resizebar_ptr->super_box.super_container, NULL, - wlmtk_resizebar_button_element(resizebar_ptr->center_button_ptr)); + wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); - resizebar_ptr->right_button_ptr = wlmtk_resizebar_button_create(); - if (NULL == resizebar_ptr->right_button_ptr) { + resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create(); + if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } wlmtk_container_add_element_before( &resizebar_ptr->super_box.super_container, NULL, - wlmtk_resizebar_button_element(resizebar_ptr->right_button_ptr)); + wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr)); if (!wlmtk_resizebar_set_width(resizebar_ptr, width)) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -129,27 +129,27 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( /* ------------------------------------------------------------------------- */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) { - if (NULL != resizebar_ptr->right_button_ptr) { + if (NULL != resizebar_ptr->right_area_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - wlmtk_resizebar_button_element(resizebar_ptr->right_button_ptr)); - wlmtk_resizebar_button_destroy(resizebar_ptr->right_button_ptr); - resizebar_ptr->right_button_ptr = NULL; + wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr)); + wlmtk_resizebar_area_destroy(resizebar_ptr->right_area_ptr); + resizebar_ptr->right_area_ptr = NULL; } - if (NULL != resizebar_ptr->center_button_ptr) { + if (NULL != resizebar_ptr->center_area_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - wlmtk_resizebar_button_element(resizebar_ptr->center_button_ptr)); - wlmtk_resizebar_button_destroy(resizebar_ptr->center_button_ptr); - resizebar_ptr->center_button_ptr = NULL; + wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); + wlmtk_resizebar_area_destroy(resizebar_ptr->center_area_ptr); + resizebar_ptr->center_area_ptr = NULL; } - if (NULL != resizebar_ptr->left_button_ptr) { + if (NULL != resizebar_ptr->left_area_ptr) { wlmtk_container_remove_element( &resizebar_ptr->super_box.super_container, - wlmtk_resizebar_button_element(resizebar_ptr->left_button_ptr)); + wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); - wlmtk_resizebar_button_destroy(resizebar_ptr->left_button_ptr); - resizebar_ptr->left_button_ptr = NULL; + wlmtk_resizebar_area_destroy(resizebar_ptr->left_area_ptr); + resizebar_ptr->left_area_ptr = NULL; } if (NULL != resizebar_ptr->gfxbuf_ptr) { @@ -180,31 +180,31 @@ bool wlmtk_resizebar_set_width( 0, (int)width - right_corner_width - left_corner_width); wlmtk_element_set_visible( - wlmtk_resizebar_button_element(resizebar_ptr->left_button_ptr), + wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr), 0 < left_corner_width); wlmtk_element_set_visible( - wlmtk_resizebar_button_element(resizebar_ptr->center_button_ptr), + wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr), 0 < center_width); wlmtk_element_set_visible( - wlmtk_resizebar_button_element(resizebar_ptr->right_button_ptr), + wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr), 0 < right_corner_width); - if (!wlmtk_resizebar_button_redraw( - resizebar_ptr->left_button_ptr, + if (!wlmtk_resizebar_area_redraw( + resizebar_ptr->left_area_ptr, resizebar_ptr->gfxbuf_ptr, 0, left_corner_width, &resizebar_ptr->style)) { return false; } - if (!wlmtk_resizebar_button_redraw( - resizebar_ptr->center_button_ptr, + if (!wlmtk_resizebar_area_redraw( + resizebar_ptr->center_area_ptr, resizebar_ptr->gfxbuf_ptr, left_corner_width, center_width, &resizebar_ptr->style)) { return false; } - if (!wlmtk_resizebar_button_redraw( - resizebar_ptr->right_button_ptr, + if (!wlmtk_resizebar_area_redraw( + resizebar_ptr->right_area_ptr, resizebar_ptr->gfxbuf_ptr, left_corner_width + center_width, right_corner_width, &resizebar_ptr->style)) { diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 78f17d9b..4c7c1fe0 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -21,7 +21,7 @@ /* == Declarations ========================================================= */ /** State of an element of the resize bar. */ -struct _wlmtk_resizebar_button_t { +struct _wlmtk_resizebar_area_t { /** Superclass: Buffer. */ wlmtk_button_t super_button; }; @@ -44,33 +44,33 @@ static const wlmtk_button_impl_t element_button_impl = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_resizebar_button_t *wlmtk_resizebar_button_create() +wlmtk_resizebar_area_t *wlmtk_resizebar_area_create() { - wlmtk_resizebar_button_t *resizebar_button = logged_calloc( - 1, sizeof(wlmtk_resizebar_button_t)); - if (NULL == resizebar_button) return NULL; + wlmtk_resizebar_area_t *resizebar_area = logged_calloc( + 1, sizeof(wlmtk_resizebar_area_t)); + if (NULL == resizebar_area) return NULL; if (!wlmtk_button_init( - &resizebar_button->super_button, + &resizebar_area->super_button, &element_button_impl)) { - wlmtk_resizebar_button_destroy(resizebar_button); + wlmtk_resizebar_area_destroy(resizebar_area); return NULL; } - return resizebar_button; + return resizebar_area; } /* ------------------------------------------------------------------------- */ -void wlmtk_resizebar_button_destroy( - wlmtk_resizebar_button_t *resizebar_button_ptr) +void wlmtk_resizebar_area_destroy( + wlmtk_resizebar_area_t *resizebar_area_ptr) { - wlmtk_button_fini(&resizebar_button_ptr->super_button); - free(resizebar_button_ptr); + wlmtk_button_fini(&resizebar_area_ptr->super_button); + free(resizebar_area_ptr); } /* ------------------------------------------------------------------------- */ -bool wlmtk_resizebar_button_redraw( - wlmtk_resizebar_button_t *resizebar_button_ptr, +bool wlmtk_resizebar_area_redraw( + wlmtk_resizebar_area_t *resizebar_area_ptr, bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, @@ -90,7 +90,7 @@ bool wlmtk_resizebar_button_redraw( // Will take ownershp of the buffers. wlmtk_button_set( - &resizebar_button_ptr->super_button, + &resizebar_area_ptr->super_button, released_wlr_buffer_ptr, pressed_wlr_buffer_ptr); @@ -100,21 +100,21 @@ bool wlmtk_resizebar_button_redraw( } /* ------------------------------------------------------------------------- */ -wlmtk_element_t *wlmtk_resizebar_button_element( - wlmtk_resizebar_button_t *resizebar_button_ptr) +wlmtk_element_t *wlmtk_resizebar_area_element( + wlmtk_resizebar_area_t *resizebar_area_ptr) { - return &resizebar_button_ptr->super_button.super_buffer.super_element; + return &resizebar_area_ptr->super_button.super_buffer.super_element; } /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Dtor. Forwards to @ref wlmtk_resizebar_button_destroy. */ +/** Dtor. Forwards to @ref wlmtk_resizebar_area_destroy. */ void button_destroy(wlmtk_button_t *button_ptr) { - wlmtk_resizebar_button_t *resizebar_button_ptr = BS_CONTAINER_OF( - button_ptr, wlmtk_resizebar_button_t, super_button); - wlmtk_resizebar_button_destroy(resizebar_button_ptr); + wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( + button_ptr, wlmtk_resizebar_area_t, super_button); + wlmtk_resizebar_area_destroy(resizebar_area_ptr); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index 4035dd4f..625ab5fb 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -23,7 +23,7 @@ #include /** Forward declaration: Element of the resizebar. */ -typedef struct _wlmtk_resizebar_button_t wlmtk_resizebar_button_t ; +typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; #include "resizebar.h" @@ -36,20 +36,20 @@ extern "C" { * * @return Pointer to the resizebar button. */ -wlmtk_resizebar_button_t *wlmtk_resizebar_button_create(void); +wlmtk_resizebar_area_t *wlmtk_resizebar_area_create(void); /** * Destroys the resizebar element. * - * @param resizebar_button_ptr + * @param resizebar_area_ptr */ -void wlmtk_resizebar_button_destroy( - wlmtk_resizebar_button_t *resizebar_button_ptr); +void wlmtk_resizebar_area_destroy( + wlmtk_resizebar_area_t *resizebar_area_ptr); /** * Redraws the element, with updated position and width. * - * @param resizebar_button_ptr + * @param resizebar_area_ptr * @param gfxbuf_ptr * @param position * @param width @@ -57,16 +57,16 @@ void wlmtk_resizebar_button_destroy( * * @return true on success. */ -bool wlmtk_resizebar_button_redraw( - wlmtk_resizebar_button_t *resizebar_button_ptr, +bool wlmtk_resizebar_area_redraw( + wlmtk_resizebar_area_t *resizebar_area_ptr, bs_gfxbuf_t *gfxbuf_ptr, unsigned position, unsigned width, const wlmtk_resizebar_style_t *style_ptr); /** Returns the button's super_buffer.super_element address. */ -wlmtk_element_t *wlmtk_resizebar_button_element( - wlmtk_resizebar_button_t *resizebar_button_ptr); +wlmtk_element_t *wlmtk_resizebar_area_element( + wlmtk_resizebar_area_t *resizebar_area_ptr); #ifdef __cplusplus } // extern "C" From 94e5c6f89855d6c064f5046cc90d0c349e12fbf8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 17:35:44 +0100 Subject: [PATCH 205/390] Removes a copyright artefact, shouldn't have been there.. --- src/toolkit/content.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 04603bef..b0af5af8 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -1,7 +1,6 @@ /* ========================================================================= */ /** * @file content.c - * Copyright (c) 2023 by Philipp Kaeser * * @copyright * Copyright 2023 Google LLC From 0c1b226409139f7fd86474de9df3c9577645b07f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 17:36:04 +0100 Subject: [PATCH 206/390] Fixes copyright notice in resizebar.h --- src/toolkit/resizebar.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 287f28db..f0c8b7a1 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -1,7 +1,21 @@ /* ========================================================================= */ /** * @file resizebar.h - * Copyright (c) 2023 by Philipp Kaeser + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef __WLMTK_RESIZEBAR_H__ #define __WLMTK_RESIZEBAR_H__ From 0073725b7abdfd2f8f1178ae3bddb86bc754c1e5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 17:43:57 +0100 Subject: [PATCH 207/390] Bases the resizebar area on buffer, not on button. --- src/toolkit/buffer.c | 2 +- src/toolkit/fsm.h | 6 +- src/toolkit/gfxbuf.h | 6 +- src/toolkit/primitives.h | 6 +- src/toolkit/resizebar_area.c | 133 ++++++++++++++++++++++++++++------- src/toolkit/titlebar_title.c | 16 ++++- src/toolkit/toolkit.h | 6 +- src/toolkit/util.h | 6 +- 8 files changed, 139 insertions(+), 42 deletions(-) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index a9679bd0..28e30530 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -231,7 +231,7 @@ bool element_pointer_motion( { wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_buffer_t, super_element); - if (NULL == buffer_ptr->impl.pointer_motion) return false; + if (NULL == buffer_ptr->impl.pointer_motion) return true; return buffer_ptr->impl.pointer_motion(buffer_ptr, x, y, time_msec); } diff --git a/src/toolkit/fsm.h b/src/toolkit/fsm.h index 31f5f143..f43b7cc9 100644 --- a/src/toolkit/fsm.h +++ b/src/toolkit/fsm.h @@ -18,8 +18,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __WLTMK_FSM_H__ -#define __WLTMK_FSM_H__ +#ifndef __WLMTK_FSM_H__ +#define __WLMTK_FSM_H__ #include #include @@ -98,5 +98,5 @@ extern const bs_test_case_t wlmtk_fsm_test_cases[]; } // extern "C" #endif // __cplusplus -#endif /* __WLTMK_FSM_H__ */ +#endif /* __WLMTK_FSM_H__ */ /* == End of fsm.h ====================================================== */ diff --git a/src/toolkit/gfxbuf.h b/src/toolkit/gfxbuf.h index 5836b4ff..fd96ff70 100644 --- a/src/toolkit/gfxbuf.h +++ b/src/toolkit/gfxbuf.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __GFXBUF_H__ -#define __GFXBUF_H__ +#ifndef __WLMTK_GFXBUF_H__ +#define __WLMTK_GFXBUF_H__ #include #include @@ -81,5 +81,5 @@ cairo_t *cairo_create_from_wlr_buffer(struct wlr_buffer *wlr_buffer_ptr); } // extern "C" #endif // __cplusplus -#endif /* __GFXBUF_H__ */ +#endif /* __WLMTK_GFXBUF_H__ */ /* == End of gfxbuf.h ====================================================== */ diff --git a/src/toolkit/primitives.h b/src/toolkit/primitives.h index e33ae418..9125c146 100644 --- a/src/toolkit/primitives.h +++ b/src/toolkit/primitives.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __PRIMITIVES_H__ -#define __PRIMITIVES_H__ +#ifndef __WLMTK_PRIMITIVES_H__ +#define __WLMTK_PRIMITIVES_H__ #include #include @@ -146,5 +146,5 @@ extern const bs_test_case_t wlmaker_primitives_test_cases[]; } // extern "C" #endif // __cplusplus -#endif /* __PRIMITIVES_H__ */ +#endif /* __WLMTK_PRIMITIVES_H__ */ /* == End of primitives.h ================================================== */ diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 4c7c1fe0..f81d6a72 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -1,14 +1,27 @@ /* ========================================================================= */ /** * @file resizebar_area.c - * Copyright (c) 2023 by Philipp Kaeser + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "resizebar_area.h" #include "box.h" #include "buffer.h" -#include "button.h" #include "gfxbuf.h" #include "primitives.h" @@ -23,10 +36,23 @@ /** State of an element of the resize bar. */ struct _wlmtk_resizebar_area_t { /** Superclass: Buffer. */ - wlmtk_button_t super_button; + wlmtk_buffer_t super_buffer; + + /** WLR buffer holding the buffer in released state. */ + struct wlr_buffer *released_wlr_buffer_ptr; + /** WLR buffer holding the buffer in pressed state. */ + struct wlr_buffer *pressed_wlr_buffer_ptr; + + /** Whether the area is currently pressed or not. */ + bool pressed; }; -static void button_destroy(wlmtk_button_t *button_ptr); +static void buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static bool buffer_pointer_button( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr); + +static void draw_state(wlmtk_resizebar_area_t *resizebar_area_ptr); static struct wlr_buffer *create_buffer( bs_gfxbuf_t *gfxbuf_ptr, unsigned position, @@ -37,8 +63,9 @@ static struct wlr_buffer *create_buffer( /* == Data ================================================================= */ /** Buffer implementation for title of the title bar. */ -static const wlmtk_button_impl_t element_button_impl = { - .destroy = button_destroy +static const wlmtk_buffer_impl_t area_buffer_impl = { + .destroy = buffer_destroy, + .pointer_button = buffer_pointer_button, }; /* == Exported methods ===================================================== */ @@ -46,25 +73,31 @@ static const wlmtk_button_impl_t element_button_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create() { - wlmtk_resizebar_area_t *resizebar_area = logged_calloc( + wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); - if (NULL == resizebar_area) return NULL; + if (NULL == resizebar_area_ptr) return NULL; - if (!wlmtk_button_init( - &resizebar_area->super_button, - &element_button_impl)) { - wlmtk_resizebar_area_destroy(resizebar_area); + if (!wlmtk_buffer_init( + &resizebar_area_ptr->super_buffer, + &area_buffer_impl)) { + wlmtk_resizebar_area_destroy(resizebar_area_ptr); return NULL; } - return resizebar_area; + draw_state(resizebar_area_ptr); + return resizebar_area_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_resizebar_area_destroy( wlmtk_resizebar_area_t *resizebar_area_ptr) { - wlmtk_button_fini(&resizebar_area_ptr->super_button); + wlr_buffer_drop_nullify( + &resizebar_area_ptr->released_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &resizebar_area_ptr->pressed_wlr_buffer_ptr); + + wlmtk_buffer_fini(&resizebar_area_ptr->super_buffer); free(resizebar_area_ptr); } @@ -88,14 +121,14 @@ bool wlmtk_resizebar_area_redraw( return false; } - // Will take ownershp of the buffers. - wlmtk_button_set( - &resizebar_area_ptr->super_button, - released_wlr_buffer_ptr, - pressed_wlr_buffer_ptr); + wlr_buffer_drop_nullify( + &resizebar_area_ptr->released_wlr_buffer_ptr); + resizebar_area_ptr->released_wlr_buffer_ptr = released_wlr_buffer_ptr; + wlr_buffer_drop_nullify( + &resizebar_area_ptr->pressed_wlr_buffer_ptr); + resizebar_area_ptr->pressed_wlr_buffer_ptr = pressed_wlr_buffer_ptr; - wlr_buffer_drop(released_wlr_buffer_ptr); - wlr_buffer_drop(pressed_wlr_buffer_ptr); + draw_state(resizebar_area_ptr); return true; } @@ -103,23 +136,73 @@ bool wlmtk_resizebar_area_redraw( wlmtk_element_t *wlmtk_resizebar_area_element( wlmtk_resizebar_area_t *resizebar_area_ptr) { - return &resizebar_area_ptr->super_button.super_buffer.super_element; + return &resizebar_area_ptr->super_buffer.super_element; } /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ /** Dtor. Forwards to @ref wlmtk_resizebar_area_destroy. */ -void button_destroy(wlmtk_button_t *button_ptr) +void buffer_destroy(wlmtk_buffer_t *buffer_ptr) { wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( - button_ptr, wlmtk_resizebar_area_t, super_button); + buffer_ptr, wlmtk_resizebar_area_t, super_buffer); wlmtk_resizebar_area_destroy(resizebar_area_ptr); } +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_buffer_impl_t::pointer_button. */ +bool buffer_pointer_button( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_resizebar_area_t, super_buffer); + + if (button_event_ptr->button != BTN_LEFT) return false; + + switch (button_event_ptr->type) { + case WLMTK_BUTTON_DOWN: + resizebar_area_ptr->pressed = true; + bs_log(BS_INFO, "FIXME: Down!"); + draw_state(resizebar_area_ptr); + break; + + case WLMTK_BUTTON_UP: + resizebar_area_ptr->pressed = false; + bs_log(BS_INFO, "FIXME: Up!"); + draw_state(resizebar_area_ptr); + break; + + default: + break; + } + + return true; +} + +/* ------------------------------------------------------------------------- */ +/** + * Draws the buffer in current state (released or pressed). + * + * @param resizebar_area_ptr + */ +void draw_state(wlmtk_resizebar_area_t *resizebar_area_ptr) +{ + if (!resizebar_area_ptr->pressed) { + wlmtk_buffer_set( + &resizebar_area_ptr->super_buffer, + resizebar_area_ptr->released_wlr_buffer_ptr); + } else { + wlmtk_buffer_set( + &resizebar_area_ptr->super_buffer, + resizebar_area_ptr->pressed_wlr_buffer_ptr); + } +} + /* ------------------------------------------------------------------------- */ /** - * Creates a resizebar button texture. + * Creates a resizebar area texture. * * @param gfxbuf_ptr * @param position diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index 82f9dba9..cdf320f6 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -1,7 +1,21 @@ /* ========================================================================= */ /** * @file titlebar_title.c - * Copyright (c) 2023 by Philipp Kaeser + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "titlebar_title.h" diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 00a2d9d6..03080c9b 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -19,8 +19,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __TOOLKIT_H__ -#define __TOOLKIT_H__ +#ifndef __WLMTK_TOOLKIT_H__ +#define __WLMTK_TOOLKIT_H__ #include "gfxbuf.h" #include "primitives.h" @@ -53,5 +53,5 @@ extern "C" { } // extern "C" #endif // __cplusplus -#endif /* __TOOLKIT_H__ */ +#endif /* __WLMTK_TOOLKIT_H__ */ /* == End of toolkit.h ===================================================== */ diff --git a/src/toolkit/util.h b/src/toolkit/util.h index 2af9823e..3a58aad8 100644 --- a/src/toolkit/util.h +++ b/src/toolkit/util.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __WLMAKER_UTIL_H__ -#define __WLMAKER_UTIL_H__ +#ifndef __WLMTK_UTIL_H__ +#define __WLMTK_UTIL_H__ #include @@ -47,5 +47,5 @@ void wlmtk_util_connect_listener_signal( } // extern "C" #endif // __cplusplus -#endif /* __WLMAKER_UTIL_H__ */ +#endif /* __WLMTK_UTIL_H__ */ /* == End of util.h ======================================================== */ From 85d012c452203881831028a254e9e045e00900e0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 17:54:51 +0100 Subject: [PATCH 208/390] Wires up the resize bar area with window's resizing. --- src/toolkit/resizebar.c | 14 ++++++++++---- src/toolkit/resizebar.h | 3 +++ src/toolkit/resizebar_area.c | 18 +++++++++++++++--- src/toolkit/resizebar_area.h | 8 +++++++- src/toolkit/window.c | 4 ++-- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 1bb36367..b446609a 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -30,6 +30,7 @@ #define WLR_USE_UNSTABLE #include +#include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -69,6 +70,7 @@ static const wlmtk_box_impl_t resizebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( + wlmtk_window_t *window_ptr, unsigned width, const wlmtk_resizebar_style_t *style_ptr) { @@ -89,7 +91,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } - resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create(); + resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( + window_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -98,7 +101,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( &resizebar_ptr->super_box.super_container, wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); - resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create(); + resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( + window_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -108,7 +112,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( NULL, wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); - resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create(); + resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( + window_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -271,7 +276,8 @@ const bs_test_case_t wlmtk_resizebar_test_cases[] = { void test_create_destroy(bs_test_t *test_ptr) { wlmtk_resizebar_style_t style = {}; - wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create(120, &style); + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( + NULL, 120, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index f0c8b7a1..6ad9895b 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -25,6 +25,7 @@ typedef struct _wlmtk_resizebar_t wlmtk_resizebar_t; #include "element.h" #include "primitives.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -45,12 +46,14 @@ typedef struct { /** * Creates the resize bar. * + * @param window_ptr * @param width * @param style_ptr * * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( + wlmtk_window_t *window_ptr, unsigned width, const wlmtk_resizebar_style_t *style_ptr); diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index f81d6a72..9f7b1787 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -45,6 +45,12 @@ struct _wlmtk_resizebar_area_t { /** Whether the area is currently pressed or not. */ bool pressed; + + /** Window to which the resize bar area belongs. To initiate resizing. */ + wlmtk_window_t *window_ptr; + /** Edges that the resizebar area controls. */ + uint32_t edges; + }; static void buffer_destroy(wlmtk_buffer_t *buffer_ptr); @@ -71,11 +77,15 @@ static const wlmtk_buffer_impl_t area_buffer_impl = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_resizebar_area_t *wlmtk_resizebar_area_create() +wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( + wlmtk_window_t *window_ptr, + uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); if (NULL == resizebar_area_ptr) return NULL; + resizebar_area_ptr->window_ptr = window_ptr; + resizebar_area_ptr->edges = edges; if (!wlmtk_buffer_init( &resizebar_area_ptr->super_buffer, @@ -164,13 +174,15 @@ bool buffer_pointer_button( switch (button_event_ptr->type) { case WLMTK_BUTTON_DOWN: resizebar_area_ptr->pressed = true; - bs_log(BS_INFO, "FIXME: Down!"); + + wlmtk_window_request_resize( + resizebar_area_ptr->window_ptr, + resizebar_area_ptr->edges); draw_state(resizebar_area_ptr); break; case WLMTK_BUTTON_UP: resizebar_area_ptr->pressed = false; - bs_log(BS_INFO, "FIXME: Up!"); draw_state(resizebar_area_ptr); break; diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index 625ab5fb..ce93ecb9 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -26,6 +26,7 @@ typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; #include "resizebar.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -34,9 +35,14 @@ extern "C" { /** * Creates a resizebar button. * + * @param window_ptr + * @param edges + * * @return Pointer to the resizebar button. */ -wlmtk_resizebar_area_t *wlmtk_resizebar_area_create(void); +wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( + wlmtk_window_t *window_ptr, + uint32_t edges); /** * Destroys the resizebar element. diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 26f8db2a..90b00a4a 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -107,7 +107,7 @@ static const wlmtk_resizebar_style_t resizebar_style = { .type = WLMTK_STYLE_COLOR_SOLID, .param = { .solid = { .color = 0xffc2c0c5 }} }, - .height = 20, // FIXME: 7 + .height = 7, .corner_width = 29, .bezel_width = 1, }; @@ -153,7 +153,7 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); window_ptr->resizebar_ptr = wlmtk_resizebar_create( - width, &resizebar_style); + window_ptr, width, &resizebar_style); if (NULL == window_ptr->resizebar_ptr) { wlmtk_window_destroy(window_ptr); return NULL; From b658ddd07b06ec8ed0a134d47be53be6f8156fe5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 18:26:17 +0100 Subject: [PATCH 209/390] Shows correct cursor on mouse hover for resizebar. --- src/toolkit/resizebar.c | 7 +++++- src/toolkit/resizebar.h | 4 +++ src/toolkit/resizebar_area.c | 49 ++++++++++++++++++++++++++++++++++++ src/toolkit/resizebar_area.h | 10 ++++++++ src/toolkit/window.c | 10 +++++--- src/toolkit/window.h | 12 ++++++++- src/toolkit/workspace.c | 8 +++--- src/wlmtk_xdg_toplevel.c | 2 ++ 8 files changed, 93 insertions(+), 9 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index b446609a..69537478 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -70,6 +70,8 @@ static const wlmtk_box_impl_t resizebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, unsigned width, const wlmtk_resizebar_style_t *style_ptr) @@ -92,6 +94,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( } resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( + wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -102,6 +105,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( + wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -113,6 +117,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( + wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -277,7 +282,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_resizebar_style_t style = {}; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, 120, &style); + NULL, NULL, NULL, 120, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 6ad9895b..c4766b71 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -46,6 +46,8 @@ typedef struct { /** * Creates the resize bar. * + * @param wlr_cursor_ptr + * @param wlr_xcursor_manager_ptr * @param window_ptr * @param width * @param style_ptr @@ -53,6 +55,8 @@ typedef struct { * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, unsigned width, const wlmtk_resizebar_style_t *style_ptr); diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 9f7b1787..3cdb7b11 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -29,6 +29,8 @@ #define WLR_USE_UNSTABLE #include +#include +#include #undef WLR_USE_UNSTABLE /* == Declarations ========================================================= */ @@ -51,9 +53,19 @@ struct _wlmtk_resizebar_area_t { /** Edges that the resizebar area controls. */ uint32_t edges; + /** Points to a `wlr_cursor`. */ + struct wlr_cursor *wlr_cursor_ptr; + /** Points to a `wlr_xcursor_manager`. */ + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr; + /** Name of the cursor to show when having pointer focus. */ + const char *xcursor_name_ptr; }; static void buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static bool buffer_pointer_motion( + wlmtk_buffer_t *buffer_ptr, + double x, double y, + uint32_t time_msec); static bool buffer_pointer_button( wlmtk_buffer_t *buffer_ptr, const wlmtk_button_event_t *button_event_ptr); @@ -71,6 +83,7 @@ static struct wlr_buffer *create_buffer( /** Buffer implementation for title of the title bar. */ static const wlmtk_buffer_impl_t area_buffer_impl = { .destroy = buffer_destroy, + .pointer_motion = buffer_pointer_motion, .pointer_button = buffer_pointer_button, }; @@ -78,15 +91,34 @@ static const wlmtk_buffer_impl_t area_buffer_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); if (NULL == resizebar_area_ptr) return NULL; + resizebar_area_ptr->wlr_cursor_ptr = wlr_cursor_ptr; + resizebar_area_ptr->wlr_xcursor_manager_ptr = wlr_xcursor_manager_ptr; resizebar_area_ptr->window_ptr = window_ptr; resizebar_area_ptr->edges = edges; + resizebar_area_ptr->xcursor_name_ptr = "default"; // Fail-safe value. + switch (resizebar_area_ptr->edges) { + case WLR_EDGE_BOTTOM: + resizebar_area_ptr->xcursor_name_ptr = "s-resize"; + break; + case WLR_EDGE_BOTTOM | WLR_EDGE_LEFT: + resizebar_area_ptr->xcursor_name_ptr = "sw-resize"; + break; + case WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT: + resizebar_area_ptr->xcursor_name_ptr = "se-resize"; + break; + default: + bs_log(BS_ERROR, "Unsupported edge %"PRIx32, edges); + } + if (!wlmtk_buffer_init( &resizebar_area_ptr->super_buffer, &area_buffer_impl)) { @@ -160,6 +192,23 @@ void buffer_destroy(wlmtk_buffer_t *buffer_ptr) wlmtk_resizebar_area_destroy(resizebar_area_ptr); } +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_buffer_impl_t::pointer_motion. */ +bool buffer_pointer_motion( + wlmtk_buffer_t *buffer_ptr, + __UNUSED__ double x, __UNUSED__ double y, + __UNUSED__ uint32_t time_msec) +{ + wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_resizebar_area_t, super_buffer); + // + wlr_cursor_set_xcursor( + resizebar_area_ptr->wlr_cursor_ptr, + resizebar_area_ptr->wlr_xcursor_manager_ptr, + resizebar_area_ptr->xcursor_name_ptr); + return true; +} + /* ------------------------------------------------------------------------- */ /** See @ref wlmtk_buffer_impl_t::pointer_button. */ bool buffer_pointer_button( diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index ce93ecb9..a57f22b3 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -25,6 +25,7 @@ /** Forward declaration: Element of the resizebar. */ typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; + #include "resizebar.h" #include "window.h" @@ -32,15 +33,24 @@ typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; extern "C" { #endif // __cplusplus +/** Forward declaration. */ +struct wlr_cursor; +/** Forward declaration. */ +struct wlr_xcursor_manager; + /** * Creates a resizebar button. * + * @param wlr_cursor_ptr + * @param wlr_xcursor_manager_ptr * @param window_ptr * @param edges * * @return Pointer to the resizebar button. */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, uint32_t edges); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 90b00a4a..8f6a60ad 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -115,7 +115,10 @@ static const wlmtk_resizebar_style_t resizebar_style = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) +wlmtk_window_t *wlmtk_window_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + wlmtk_content_t *content_ptr) { wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; @@ -153,6 +156,7 @@ wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr) wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); window_ptr->resizebar_ptr = wlmtk_resizebar_create( + wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, width, &resizebar_style); if (NULL == window_ptr->resizebar_ptr) { wlmtk_window_destroy(window_ptr); @@ -430,7 +434,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - &fake_content_ptr->content); + NULL, NULL, &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, window_ptr, fake_content_ptr->content.window_ptr); @@ -444,7 +448,7 @@ void test_set_activated(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - &fake_content_ptr->content); + NULL, NULL, &fake_content_ptr->content); wlmtk_window_set_activated(window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 6389e1b8..8f49379f 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -30,15 +30,25 @@ typedef struct _wlmtk_window_t wlmtk_window_t; extern "C" { #endif // __cplusplus +/** Forward declaration. */ +struct wlr_cursor; +/** Forward declaration. */ +struct wlr_xcursor_manager; + /** * Creates a window for the given content. * + * @param wlr_cursor_ptr + * @param wlr_xcursor_manager_ptr * @param content_ptr Will take ownership of content_ptr. * * @return Pointer to the window state, or NULL on error. Must be free'd * by calling @ref wlmtk_window_destroy. */ -wlmtk_window_t *wlmtk_window_create(wlmtk_content_t *content_ptr); +wlmtk_window_t *wlmtk_window_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + wlmtk_content_t *content_ptr); /** * Destroys the window. diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 706ebe66..6bcb04ee 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -502,7 +502,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - &fake_content_ptr->content); + NULL, NULL, &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -603,7 +603,7 @@ void test_move(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - &fake_content_ptr->content); + NULL, NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -649,7 +649,7 @@ void test_unmap_during_move(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - &fake_content_ptr->content); + NULL, NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -694,7 +694,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_content_commit_size(&fake_content_ptr->content, 1, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( - &fake_content_ptr->content); + NULL, NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 25d91642..93e866e7 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -106,6 +106,8 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( if (NULL == content_ptr) return NULL; wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( + server_ptr->cursor_ptr->wlr_cursor_ptr, + server_ptr->cursor_ptr->wlr_xcursor_manager_ptr, &content_ptr->super_content); if (NULL == wlmtk_window_ptr) { wlmtk_content_destroy(&content_ptr->super_content); From 901bb4c644c5ee1d8519487e442bffe3ffccca7d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 12 Nov 2023 19:00:36 +0100 Subject: [PATCH 210/390] Positions the titlebar elements correctly and hides on narrow windows. --- src/toolkit/titlebar.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index fc70e183..ea790156 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -179,14 +179,21 @@ bool wlmtk_titlebar_set_width( if (!redraw_buffers(titlebar_ptr, width)) return false; BS_ASSERT(width == titlebar_ptr->width); - int close_position = width - titlebar_ptr->style.height; + int close_position = width; + if (3 * titlebar_ptr->style.height < width) { + close_position = width - titlebar_ptr->style.height; + } + int title_position = 0; + if (4 * titlebar_ptr->style.height < width) { + title_position = titlebar_ptr->style.height; + } if (!wlmtk_titlebar_title_redraw( titlebar_ptr->title_ptr, titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, - 0, - titlebar_ptr->width, + title_position, + close_position - title_position, titlebar_ptr->activated, &titlebar_ptr->style)) { return false; @@ -194,7 +201,7 @@ bool wlmtk_titlebar_set_width( wlmtk_element_set_visible( wlmtk_titlebar_title_element(titlebar_ptr->title_ptr), true); - if (titlebar_ptr->style.height <= width) { + if (0 < title_position) { if (!wlmtk_titlebar_button_redraw( titlebar_ptr->minimize_button_ptr, titlebar_ptr->focussed_gfxbuf_ptr, @@ -212,7 +219,7 @@ bool wlmtk_titlebar_set_width( false); } - if ((int)titlebar_ptr->style.height <= close_position) { + if (close_position < (int)width) { if (!wlmtk_titlebar_button_redraw( titlebar_ptr->close_button_ptr, titlebar_ptr->focussed_gfxbuf_ptr, From c5666e992e88a58e5db753d3ff2983bc32401668 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 15 Nov 2023 21:05:41 +0100 Subject: [PATCH 211/390] Adds basic test for titlebar button. --- src/toolkit/titlebar_button.c | 38 +++++++++++++++++++++++++++++++++++ src/toolkit/titlebar_button.h | 3 +++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 4 files changed, 43 insertions(+) diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index a8965470..41a62191 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -199,4 +199,42 @@ struct wlr_buffer *create_buf( return wlr_buffer_ptr; } +/* == Unit tests =========================================================== */ + +static void test_button(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_titlebar_button_test_cases[] = { + { 1, "button", test_button }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests button visualization. */ +void test_button(bs_test_t *test_ptr) +{ + wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( + wlmaker_primitives_draw_close_icon); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); + + wlmtk_titlebar_style_t style = { + .height = 22, + .bezel_width = 1 + }; + bs_gfxbuf_t *f_ptr = bs_gfxbuf_create(100, 22); + bs_gfxbuf_clear(f_ptr, 0xff4040c0); + bs_gfxbuf_t *b_ptr = bs_gfxbuf_create(100, 22); + bs_gfxbuf_clear(f_ptr, 0xff303030); + + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_titlebar_button_redraw(button_ptr, f_ptr, b_ptr, 30, &style)); + + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(button_ptr->super_button.super_buffer.wlr_buffer_ptr), + "toolkit/title_button_focussed.png"); + + wlmtk_element_destroy(wlmtk_titlebar_button_element(button_ptr)); +} + /* == End of titlebar_button.c ============================================= */ diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index 1de2c4b3..43cb4be4 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -82,6 +82,9 @@ bool wlmtk_titlebar_button_redraw( wlmtk_element_t *wlmtk_titlebar_button_element( wlmtk_titlebar_button_t *titlebar_button_ptr); +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_titlebar_button_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 03080c9b..a536b71a 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -40,6 +40,7 @@ #include "input.h" #include "resizebar.h" #include "titlebar.h" +#include "titlebar_button.h" #include "titlebar_title.h" #include "window.h" #include "workspace.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 53ff48f2..322494ee 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -30,6 +30,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "fsm", wlmtk_fsm_test_cases }, { 1, "resizebar", wlmtk_resizebar_test_cases }, { 1, "titlebar", wlmtk_titlebar_test_cases }, + { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, From 8e868b656520845bfdeda27533e904d2195d7982 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 15 Nov 2023 21:20:32 +0100 Subject: [PATCH 212/390] Adds test case for released and pressed titlebar button. --- src/toolkit/titlebar_button.c | 36 ++++++++++++++++-- .../toolkit/title_button_focussed_pressed.png | Bin 0 -> 436 bytes .../title_button_focussed_released.png | Bin 0 -> 389 bytes 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 testdata/toolkit/title_button_focussed_pressed.png create mode 100644 testdata/toolkit/title_button_focussed_released.png diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 41a62191..439e7d34 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -218,23 +218,51 @@ void test_button(bs_test_t *test_ptr) wlmtk_titlebar_style_t style = { .height = 22, + .focussed_text_color = 0xffffffff, .bezel_width = 1 }; bs_gfxbuf_t *f_ptr = bs_gfxbuf_create(100, 22); bs_gfxbuf_clear(f_ptr, 0xff4040c0); bs_gfxbuf_t *b_ptr = bs_gfxbuf_create(100, 22); - bs_gfxbuf_clear(f_ptr, 0xff303030); + bs_gfxbuf_clear(b_ptr, 0xff303030); + + // For improved readability. + wlmtk_buffer_t *super_buffer_ptr = &button_ptr->super_button.super_buffer; + wlmtk_element_t *element_ptr = wlmtk_titlebar_button_element(button_ptr); BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_titlebar_button_redraw(button_ptr, f_ptr, b_ptr, 30, &style)); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_button_focussed_released.png"); + // Pointer must be inside the button for accepting DOWN. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 11, 11, 0)); + + // Button down: pressed. + wlmtk_button_event_t button = { .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN }; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &button)); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_button_focussed_pressed.png"); + + button.type = WLMTK_BUTTON_UP; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &button)); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, - bs_gfxbuf_from_wlr_buffer(button_ptr->super_button.super_buffer.wlr_buffer_ptr), - "toolkit/title_button_focussed.png"); + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_button_focussed_released.png"); - wlmtk_element_destroy(wlmtk_titlebar_button_element(button_ptr)); + wlmtk_element_destroy(element_ptr); } /* == End of titlebar_button.c ============================================= */ diff --git a/testdata/toolkit/title_button_focussed_pressed.png b/testdata/toolkit/title_button_focussed_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..caa63909a80553eab1db8d8d81f94b5923021711 GIT binary patch literal 436 zcmV;l0ZaagP)U1 zA!@DmT2UD;^w}qr zlF6i<`%jXT=Q-P!D>J%;P?V?fSVriS-*C8y;}jw2x@}cuP#E{Zbx-dfjTX~sG@rj& zR+xLSEcvQ?k!2u`f8>{^8^>vpPFZ|qzuSEd2J?JTt_MNX?=$KQ1oNTG^}GGq|0>=v edb%#%g7^k@UX;FL5dHlC0000MaYi; literal 0 HcmV?d00001 diff --git a/testdata/toolkit/title_button_focussed_released.png b/testdata/toolkit/title_button_focussed_released.png new file mode 100644 index 0000000000000000000000000000000000000000..3554ccefe019bae9ba425bea5a89641fa90ba5dc GIT binary patch literal 389 zcmV;00eb$4P)_>{VRpHjCd{5<#XDI;A#2y7drsduGN>ZYk@+X%uZ4$?GT5S)cj7^5s( zESIkDeAF}hrIlGIJp4NI0KzrPozEXGJm1pqLMFsvDC2Rk`0$0x#A8-}%%3S%_! z{lhGbl+s%NwhAG7JpJ)El)BsP!nTo=N=ju}Fpj;!jHVF%{NlLYY;My18$pPZWk2DKGYEc!lU?P@jRk03@jP5W>A jv%f0qa5!>a%|Uzv7HXhSp1G{#00000NkvXXu0mjf5dE)0 literal 0 HcmV?d00001 From 6857044c3f4ce76532442cbc24c82282524a819d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 15 Nov 2023 21:22:18 +0100 Subject: [PATCH 213/390] Fixes a leak in the title bar button testcase. --- src/toolkit/titlebar_button.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 439e7d34..ad0dff27 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -216,6 +216,11 @@ void test_button(bs_test_t *test_ptr) wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); + // For improved readability. + wlmtk_buffer_t *super_buffer_ptr = &button_ptr->super_button.super_buffer; + wlmtk_element_t *element_ptr = wlmtk_titlebar_button_element(button_ptr); + + // Draw contents. wlmtk_titlebar_style_t style = { .height = 22, .focussed_text_color = 0xffffffff, @@ -225,14 +230,11 @@ void test_button(bs_test_t *test_ptr) bs_gfxbuf_clear(f_ptr, 0xff4040c0); bs_gfxbuf_t *b_ptr = bs_gfxbuf_create(100, 22); bs_gfxbuf_clear(b_ptr, 0xff303030); - - // For improved readability. - wlmtk_buffer_t *super_buffer_ptr = &button_ptr->super_button.super_buffer; - wlmtk_element_t *element_ptr = wlmtk_titlebar_button_element(button_ptr); - BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_titlebar_button_redraw(button_ptr, f_ptr, b_ptr, 30, &style)); + bs_gfxbuf_destroy(b_ptr); + bs_gfxbuf_destroy(f_ptr); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), From c6d98512163843932759145aa9c8c68d7e3d6ead Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 15 Nov 2023 21:41:14 +0100 Subject: [PATCH 214/390] Adds testcase for variable width of the titlebar. --- src/toolkit/titlebar.c | 52 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index ea790156..01d0112f 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -316,11 +316,11 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); -static void test_create_empty(bs_test_t *test_ptr); +static void test_variable_width(bs_test_t *test_ptr); const bs_test_case_t wlmtk_titlebar_test_cases[] = { { 1, "create_destroy", test_create_destroy }, - { 1, "create_empty", test_create_empty }, + { 1, "variable_width", test_variable_width }, { 0, NULL, NULL } }; @@ -336,13 +336,55 @@ void test_create_destroy(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests setup and teardown. */ -void test_create_empty(bs_test_t *test_ptr) +/** Tests titlebar with variable width. */ +void test_variable_width(bs_test_t *test_ptr) { - wlmtk_titlebar_style_t style = {}; + wlmtk_titlebar_style_t style = { .height = 22 }; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(0, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); + // Short names, for improved readability. + wlmtk_element_t *title_elem_ptr = wlmtk_titlebar_title_element( + titlebar_ptr->title_ptr); + wlmtk_element_t *minimize_elem_ptr = wlmtk_titlebar_button_element( + titlebar_ptr->minimize_button_ptr); + wlmtk_element_t *close_elem_ptr = wlmtk_titlebar_button_element( + titlebar_ptr->close_button_ptr); + int width; + + // Created with zero width: All invisible. */ + BS_TEST_VERIFY_FALSE(test_ptr, title_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, minimize_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, close_elem_ptr->visible); + + // Width sufficient for all: All elements visible and placed. + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_titlebar_set_width(titlebar_ptr, 89)); + BS_TEST_VERIFY_TRUE(test_ptr, title_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, minimize_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, close_elem_ptr->visible); + BS_TEST_VERIFY_EQ(test_ptr, 22, title_elem_ptr->x); + wlmtk_element_get_dimensions(title_elem_ptr, NULL, NULL, &width, NULL); + BS_TEST_VERIFY_EQ(test_ptr, 45, width); + BS_TEST_VERIFY_EQ(test_ptr, 67, close_elem_ptr->x); + + // Width sufficient only for 1 button. + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_titlebar_set_width(titlebar_ptr, 67)); + BS_TEST_VERIFY_TRUE(test_ptr, title_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, minimize_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, close_elem_ptr->visible); + BS_TEST_VERIFY_EQ(test_ptr, 0, title_elem_ptr->x); + wlmtk_element_get_dimensions(title_elem_ptr, NULL, NULL, &width, NULL); + BS_TEST_VERIFY_EQ(test_ptr, 45, width); + + // Width doesn't permit any button. + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_titlebar_set_width(titlebar_ptr, 66)); + BS_TEST_VERIFY_TRUE(test_ptr, title_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, minimize_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, close_elem_ptr->visible); + BS_TEST_VERIFY_EQ(test_ptr, 0, title_elem_ptr->x); + wlmtk_element_get_dimensions(title_elem_ptr, NULL, NULL, &width, NULL); + BS_TEST_VERIFY_EQ(test_ptr, 66, width); + wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); } From 2305d25990dfb9a3e44ac578db7a13228e4cf576 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 15 Nov 2023 21:55:54 +0100 Subject: [PATCH 215/390] Adds a testcase for handling variable width of the resize bar. --- src/toolkit/resizebar.c | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 69537478..e4f05da0 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -270,9 +270,11 @@ bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width) /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_variable_width(bs_test_t *test_ptr); const bs_test_case_t wlmtk_resizebar_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "variable_width", test_variable_width }, { 0, NULL, NULL } }; @@ -288,4 +290,53 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); } +/* ------------------------------------------------------------------------- */ +/** Performs resizing and verifies the elements are shown as expected. */ +void test_variable_width(bs_test_t *test_ptr) +{ + wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( + NULL, NULL, NULL, 0, &style); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); + + wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( + resizebar_ptr->left_area_ptr); + wlmtk_element_t *center_elem_ptr = wlmtk_resizebar_area_element( + resizebar_ptr->center_area_ptr); + wlmtk_element_t *right_elem_ptr = wlmtk_resizebar_area_element( + resizebar_ptr->right_area_ptr); + + // Zero width. Zero visibility. + BS_TEST_VERIFY_FALSE(test_ptr, left_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, center_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, right_elem_ptr->visible); + + // Sufficient space for all the elements. + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_resizebar_set_width(resizebar_ptr, 33)); + BS_TEST_VERIFY_TRUE(test_ptr, left_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, center_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, right_elem_ptr->visible); + BS_TEST_VERIFY_EQ(test_ptr, 16, center_elem_ptr->x); + BS_TEST_VERIFY_EQ(test_ptr, 17, right_elem_ptr->x); + + // Not enough space for the center element. + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_resizebar_set_width(resizebar_ptr, 32)); + BS_TEST_VERIFY_TRUE(test_ptr, left_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, center_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, right_elem_ptr->visible); + BS_TEST_VERIFY_EQ(test_ptr, 16, right_elem_ptr->x); + + // Not enough space for center and left element. + BS_TEST_VERIFY_TRUE( + test_ptr, wlmtk_resizebar_set_width(resizebar_ptr, 16)); + BS_TEST_VERIFY_FALSE(test_ptr, left_elem_ptr->visible); + BS_TEST_VERIFY_FALSE(test_ptr, center_elem_ptr->visible); + BS_TEST_VERIFY_TRUE(test_ptr, right_elem_ptr->visible); + BS_TEST_VERIFY_EQ(test_ptr, 0, right_elem_ptr->x); + + wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); +} + /* == End of resizebar.c =================================================== */ From 8237bb64da6be6e2541eef9c512c2d647c25c7f6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 15 Nov 2023 22:09:43 +0100 Subject: [PATCH 216/390] Adds basic test for resizebar area. --- src/toolkit/resizebar_area.c | 75 +++++++++++++++++-- src/toolkit/resizebar_area.h | 3 + src/toolkit/titlebar_button.c | 4 +- src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + testdata/toolkit/resizebar_area_pressed.png | Bin 0 -> 121 bytes testdata/toolkit/resizebar_area_released.png | Bin 0 -> 123 bytes 7 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 testdata/toolkit/resizebar_area_pressed.png create mode 100644 testdata/toolkit/resizebar_area_released.png diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 3cdb7b11..05e689df 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -201,11 +201,15 @@ bool buffer_pointer_motion( { wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( buffer_ptr, wlmtk_resizebar_area_t, super_buffer); - // - wlr_cursor_set_xcursor( - resizebar_area_ptr->wlr_cursor_ptr, - resizebar_area_ptr->wlr_xcursor_manager_ptr, - resizebar_area_ptr->xcursor_name_ptr); + + // TODO(kaeser@gubbe.ch): Inject something testable here. + if (NULL != resizebar_area_ptr->wlr_cursor_ptr && + NULL != resizebar_area_ptr->wlr_xcursor_manager_ptr) { + wlr_cursor_set_xcursor( + resizebar_area_ptr->wlr_cursor_ptr, + resizebar_area_ptr->wlr_xcursor_manager_ptr, + resizebar_area_ptr->xcursor_name_ptr); + } return true; } @@ -224,9 +228,11 @@ bool buffer_pointer_button( case WLMTK_BUTTON_DOWN: resizebar_area_ptr->pressed = true; - wlmtk_window_request_resize( - resizebar_area_ptr->window_ptr, - resizebar_area_ptr->edges); + if (NULL != resizebar_area_ptr->window_ptr) { + wlmtk_window_request_resize( + resizebar_area_ptr->window_ptr, + resizebar_area_ptr->edges); + } draw_state(resizebar_area_ptr); break; @@ -301,4 +307,57 @@ struct wlr_buffer *create_buffer( return wlr_buffer_ptr; } +/* == Unit tests =========================================================== */ + +static void test_area(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_resizebar_area_test_cases[] = { + { 1, "area", test_area }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests the area behaviour. */ +void test_area(bs_test_t *test_ptr) +{ + wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( + NULL, NULL, NULL, WLR_EDGE_BOTTOM); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); + wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); + + // Draw and verify release state. + wlmtk_resizebar_style_t style = { .height = 7, .bezel_width = 1.0 }; + bs_gfxbuf_t *gfxbuf_ptr = bs_gfxbuf_create(30, 7); + bs_gfxbuf_clear(gfxbuf_ptr, 0xff604020); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_resizebar_area_redraw(area_ptr, gfxbuf_ptr, 10, 12, &style)); + bs_gfxbuf_destroy(gfxbuf_ptr); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(area_ptr->super_buffer.wlr_buffer_ptr), + "toolkit/resizebar_area_released.png"); + + // Pointer must be inside the button for accepting DOWN. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 1, 1, 0)); + // Button down: pressed. + wlmtk_button_event_t button = { + .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN + }; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &button)); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(area_ptr->super_buffer.wlr_buffer_ptr), + "toolkit/resizebar_area_pressed.png"); + + // TODO(kaeser@gubbe.ch): Should verify call to wlmtk_window_request_resize + // and for setting the cursor. + + wlmtk_element_destroy(element_ptr); +} + /* == End of resizebar_area.c ============================================== */ diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index a57f22b3..b2460504 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -84,6 +84,9 @@ bool wlmtk_resizebar_area_redraw( wlmtk_element_t *wlmtk_resizebar_area_element( wlmtk_resizebar_area_t *resizebar_area_ptr); +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_resizebar_area_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index ad0dff27..8d6ea801 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -246,7 +246,9 @@ void test_button(bs_test_t *test_ptr) wlmtk_element_pointer_motion(element_ptr, 11, 11, 0)); // Button down: pressed. - wlmtk_button_event_t button = { .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN }; + wlmtk_button_event_t button = { + .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN + }; BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_pointer_button(element_ptr, &button)); diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index a536b71a..287de098 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -39,6 +39,7 @@ #include "fsm.h" #include "input.h" #include "resizebar.h" +#include "resizebar_area.h" #include "titlebar.h" #include "titlebar_button.h" #include "titlebar_title.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 322494ee..c8c38d28 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -29,6 +29,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, { 1, "resizebar", wlmtk_resizebar_test_cases }, + { 1, "resizebar_area", wlmtk_resizebar_area_test_cases }, { 1, "titlebar", wlmtk_titlebar_test_cases }, { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, diff --git a/testdata/toolkit/resizebar_area_pressed.png b/testdata/toolkit/resizebar_area_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4257ee740172ea5eb7795c093686a662018bdfac GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!2~2XU$8C)Qfx`y?k)`fL2$v|<&%LTdY&$h zAre!Qw*(2N9pJXvTN@!EA#r6%#Yc@zg+=Ly@_AS;L<)8<-`?Ll*}Be^!ONaSX3a~p Q2|%3;p00i_>zopr0ELYt$^ZZW literal 0 HcmV?d00001 diff --git a/testdata/toolkit/resizebar_area_released.png b/testdata/toolkit/resizebar_area_released.png new file mode 100644 index 0000000000000000000000000000000000000000..9724ecca6d15864d2f5e9d795615cec548b0fce7 GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!2~2XU$8C)Qfx`y?k)`fL2$v|<&%LT2A(dC zAre!Q@9eLXWRBZVd6!F!jjgS9Z)k Date: Wed, 15 Nov 2023 22:27:45 +0100 Subject: [PATCH 217/390] Updates roadmap to reflect current work on toolkit. --- doc/ROADMAP.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index a9b71844..1ec73213 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -76,6 +76,49 @@ Support for visual effects to improve usability, but not for pure show. * Configurable keyboard map (in code or commandline arg) +* Support `xdg_shell`, based on toolkit. + +* Support `layer_shell`, based on toolkit. + +* Support window decoration protocol, based on toolkit. + * [done] Style of title bar, iconify and close buttons similar to Window Maker. + * Window menu, with basic window actions (not required to adapt to state). + +* Multiple workspaces, based on toolkit. + * Navigate via keys (ctrl-window-alt-arrows, hardcoded). + +* Dock, visible across workspaces, based on toolkit. + * Style similar to Window Maker. + * With application launchers (hardcoded). + +* Clip, based on toolkit. + * Display the current workspace. + * Buttons to switch between workspaces. + +* Application launchers, based on toolkit. + * Display an icon. + * Display application status (*starting*, *running*). + * Configurable (in code). + +* Window actions, based on toolkit. + * Move (drag via title bar, or window-alt-click) + * Resize windows, including a resize bar. + * Fullscreen windows. + * Maximize windows. + * Minimize (*iconify*) windows. + * Roll up (*shade*) windows. + * Raise window when activated. + +* Visualization of iconified applications, based on toolkit. + +* Task list (window-alt-esc), cycling through windows, based on toolkit. + +### Internals and code organization + +* [done] Design a toolkit and re-factor the codebase to make use of it. + * Ensure the main features (eg. all explicit actions and features above) are + tested. + ## Pending Features for further versions, not ordered by priority nor timeline. From 303a48f400b78e3f4f3046ad0b785e510d22d9dc Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 16 Nov 2023 21:03:43 +0100 Subject: [PATCH 218/390] Virtualizes many of wlmtk_window_t methods virtual, to support mocking. --- src/toolkit/window.c | 241 ++++++++++++++++++++++++++++++++----------- src/toolkit/window.h | 57 +++++----- 2 files changed, 207 insertions(+), 91 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 8f6a60ad..9f536173 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -46,10 +46,35 @@ typedef struct { unsigned height; } wlmtk_pending_update_t; +/** Virtual method table for @ref wlmtk_window_t. */ +typedef struct { + /** See @ref wlmtk_window_set_activated. */ + void (*set_activated)(wlmtk_window_t *window_ptr, + bool activated); + /** See @ref wlmtk_window_set_server_side_decorated. */ + void (*set_server_side_decorated)(wlmtk_window_t *window_ptr, + bool decorated); + + /** See @ref wlmtk_window_request_move. */ + void (*request_move)(wlmtk_window_t *window_ptr); + /** See @ref wlmtk_window_request_resize. */ + void (*request_resize)(wlmtk_window_t *window_ptr, + uint32_t edges); + + /** See @ref wlmtk_window_request_size. */ + void (*request_size)(wlmtk_window_t *window_ptr, + int x, int y); + /** See @ref wlmtk_window_request_position_and_size. */ + void (*request_position_and_size)(wlmtk_window_t *window_ptr, + int x, int y, int width, int height); +} wlmtk_window_impl_t; + /** State of the window. */ struct _wlmtk_window_t { /** Superclass: Box. */ wlmtk_box_t super_box; + /** Virtual method table. */ + wlmtk_window_impl_t impl; /** Content of this window. */ wlmtk_content_t *content_ptr; @@ -66,6 +91,27 @@ struct _wlmtk_window_t { wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; }; +static void wlmtk_window_set_activated_impl( + wlmtk_window_t *window_ptr, + bool activated); +static void wlmtk_window_set_server_side_decorated_impl( + wlmtk_window_t *window_ptr, + bool decorated); +static void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr); +static void wlmtk_window_request_resize_impl( + wlmtk_window_t *window_ptr, + uint32_t edges); +static void wlmtk_window_request_size_impl( + wlmtk_window_t *window_ptr, + int width, + int height); +static void wlmtk_window_request_position_and_size_impl( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); + static wlmtk_pending_update_t *prepare_update( wlmtk_window_t *window_ptr); static void release_update( @@ -83,6 +129,16 @@ static const wlmtk_box_impl_t window_box_impl = { .update_layout = box_update_layout, }; +/** Default methods of @ref wlmtk_window_t. To override for a mock. */ +static const wlmtk_window_impl_t window_default_impl = { + .set_activated = wlmtk_window_set_activated_impl, + .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, + .request_move = wlmtk_window_request_move_impl, + .request_resize = wlmtk_window_request_resize_impl, + .request_size = wlmtk_window_request_size_impl, + .request_position_and_size = wlmtk_window_request_position_and_size_impl, +}; + /** Style of the title bar. */ // TODO(kaeser@gubbe.ch): Move to central config. */ static const wlmtk_titlebar_style_t titlebar_style = { @@ -126,6 +182,9 @@ wlmtk_window_t *wlmtk_window_create( bs_dllist_push_back(&window_ptr->available_updates, &window_ptr->pre_allocated_updates[i].dlnode); } + memcpy(&window_ptr->impl, + &window_default_impl, + sizeof(wlmtk_window_impl_t)); if (!wlmtk_box_init(&window_ptr->super_box, &window_box_impl, @@ -213,15 +272,52 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) return &window_ptr->super_box.super_container.super_element; } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr) +{ + // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. + wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) +{ + bs_dllist_node_t *dlnode_ptr; + while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { + wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); + + int32_t delta = pending_update_ptr->serial - serial; + if (0 < delta) break; + + if (pending_update_ptr->serial == serial) { + if (window_ptr->content_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (window_ptr->content_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } + } + + wlmtk_element_set_position( + wlmtk_window_element(window_ptr), + pending_update_ptr->x, + pending_update_ptr->y); + release_update(window_ptr, pending_update_ptr); + } +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { - wlmtk_content_set_activated(window_ptr->content_ptr, activated); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); - } + window_ptr->impl.set_activated(window_ptr, activated); } /* ------------------------------------------------------------------------- */ @@ -229,19 +325,20 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated) { - // TODO(kaeser@gubbe.ch): Implement. - bs_log(BS_INFO, "Set server side decoration for window %p: %d", - window_ptr, decorated); + window_ptr->impl.set_server_side_decorated(window_ptr, decorated); } /* ------------------------------------------------------------------------- */ -void wlmtk_window_get_size( - wlmtk_window_t *window_ptr, - int *width_ptr, - int *height_ptr) +void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { - // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); + window_ptr->impl.request_move(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, + uint32_t edges) +{ + window_ptr->impl.request_resize(window_ptr, edges); } /* ------------------------------------------------------------------------- */ @@ -250,15 +347,7 @@ void wlmtk_window_request_size( int width, int height) { - // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_content_request_size(window_ptr->content_ptr, width, height); - - // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting - // the size is an asynchronous operation and should be handled as such. - // Meaning: In example of resizing at the top-left corner, we'll want to - // request the content to adjust size, but wait with adjusting the - // content position until the size adjustment is applied. This implies we - // may need to combine the request_size and set_position methods for window. + window_ptr->impl.request_size(window_ptr, width, height); } /* ------------------------------------------------------------------------- */ @@ -269,54 +358,38 @@ void wlmtk_window_request_position_and_size( int width, int height) { - uint32_t serial = wlmtk_content_request_size( - window_ptr->content_ptr, width, height); + window_ptr->impl.request_position_and_size( + window_ptr, x, y, width, height); +} - wlmtk_pending_update_t *pending_update_ptr = prepare_update(window_ptr); - pending_update_ptr->serial = serial; - pending_update_ptr->x = x; - pending_update_ptr->y = y; - pending_update_ptr->width = width; - pending_update_ptr->height = height; +/* == Local (static) methods =============================================== */ - // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial - // may have been called early, so we should check if serial had just been - // called before (or is below the last @wlmt_window_serial). In that case, - // the pending state should be applied right away. +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_set_activated. */ +void wlmtk_window_set_activated_impl( + wlmtk_window_t *window_ptr, + bool activated) +{ + wlmtk_content_set_activated(window_ptr->content_ptr, activated); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); + } } /* ------------------------------------------------------------------------- */ -void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) +/** Default implementation of @ref wlmtk_window_set_server_side_decorated. */ +void wlmtk_window_set_server_side_decorated_impl( + wlmtk_window_t *window_ptr, + bool decorated) { - bs_dllist_node_t *dlnode_ptr; - while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { - wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); - - int32_t delta = pending_update_ptr->serial - serial; - if (0 < delta) break; - - if (pending_update_ptr->serial == serial) { - if (window_ptr->content_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (window_ptr->content_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); - } - } - - wlmtk_element_set_position( - wlmtk_window_element(window_ptr), - pending_update_ptr->x, - pending_update_ptr->y); - release_update(window_ptr, pending_update_ptr); - } + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_INFO, "Set server side decoration for window %p: %d", + window_ptr, decorated); } /* ------------------------------------------------------------------------- */ -void wlmtk_window_request_move(wlmtk_window_t *window_ptr) +/** Default implementation of @ref wlmtk_window_request_move. */ +void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) { BS_ASSERT( NULL != @@ -327,7 +400,8 @@ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) } /* ------------------------------------------------------------------------- */ -void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) +/** Default implementation of @ref wlmtk_window_request_resize. */ +void wlmtk_window_request_resize_impl(wlmtk_window_t *window_ptr, uint32_t edges) { BS_ASSERT( NULL != @@ -337,7 +411,48 @@ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); } -/* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_size. */ +void wlmtk_window_request_size_impl( + wlmtk_window_t *window_ptr, + int width, + int height) +{ + // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. + wlmtk_content_request_size(window_ptr->content_ptr, width, height); + + // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting + // the size is an asynchronous operation and should be handled as such. + // Meaning: In example of resizing at the top-left corner, we'll want to + // request the content to adjust size, but wait with adjusting the + // content position until the size adjustment is applied. This implies we + // may need to combine the request_size and set_position methods for window. +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_position_and_size. */ +void wlmtk_window_request_position_and_size_impl( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height) +{ + uint32_t serial = wlmtk_content_request_size( + window_ptr->content_ptr, width, height); + + wlmtk_pending_update_t *pending_update_ptr = prepare_update(window_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = x; + pending_update_ptr->y = y; + pending_update_ptr->width = width; + pending_update_ptr->height = height; + + // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial + // may have been called early, so we should check if serial had just been + // called before (or is below the last @wlmt_window_serial). In that case, + // the pending state should be applied right away. +} /* ------------------------------------------------------------------------- */ /** diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 8f49379f..fb92f185 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -70,6 +70,18 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); */ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); +/** + * Obtains the size of the window, including potential decorations. + * + * @param window_ptr + * @param width_ptr May be NULL. + * @param height_ptr May be NULL. + */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr); + /** * Sets the window as activated, depending on the argument's value. * @@ -94,16 +106,26 @@ void wlmtk_window_set_server_side_decorated( bool decorated); /** - * Obtains the size of the window, including potential decorations. + * Requests a move for the window. + * + * Requires the window to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_window_move. * * @param window_ptr - * @param width_ptr May be NULL. - * @param height_ptr May be NULL. */ -void wlmtk_window_get_size( - wlmtk_window_t *window_ptr, - int *width_ptr, - int *height_ptr); +void wlmtk_window_request_move(wlmtk_window_t *window_ptr); + +/** + * Requests the window to be resized. + * + * Requires the window to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_window_resize. + * + * @param window_ptr + * @param edges + */ +void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, + uint32_t edges); /** * Requests a new size for the window, including potential decorations. @@ -139,27 +161,6 @@ void wlmtk_window_request_position_and_size( int width, int height); -/** - * Requests a move for the window. - * - * Requires the window to be mapped (to a workspace), and forwards the call to - * @ref wlmtk_workspace_begin_window_move. - * - * @param window_ptr - */ -void wlmtk_window_request_move(wlmtk_window_t *window_ptr); - -/** - * Requests the window to be resized. - * - * Requires the window to be mapped (to a workspace), and forwards the call to - * @ref wlmtk_workspace_begin_window_resize. - * - * @param window_ptr - * @param edges - */ -void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges); - /** * Updates the window state to what was requested at the `serial`. * From 0aca131bd7902a950b2474e32d3f54b893afb424 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 16 Nov 2023 21:33:05 +0100 Subject: [PATCH 219/390] Abstracts initialization of wlmtk_window_t. --- src/toolkit/resizebar.c | 29 ++++++-- src/toolkit/resizebar.h | 18 +++-- src/toolkit/resizebar_area.c | 16 +++-- src/toolkit/resizebar_area.h | 18 +++-- src/toolkit/window.c | 135 ++++++++++++++++++++++++----------- 5 files changed, 153 insertions(+), 63 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index e4f05da0..3ddcab57 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -70,8 +70,6 @@ static const wlmtk_box_impl_t resizebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, unsigned width, const wlmtk_resizebar_style_t *style_ptr) @@ -94,7 +92,6 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( } resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( - wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -105,7 +102,6 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( - wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -117,7 +113,6 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( - wlr_cursor_ptr, wlr_xcursor_manager_ptr, window_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); @@ -171,6 +166,26 @@ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) free(resizebar_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_resizebar_set_cursor( + wlmtk_resizebar_t *resizebar_ptr, + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr) +{ + wlmtk_resizebar_area_set_cursor( + resizebar_ptr->left_area_ptr, + wlr_cursor_ptr, + wlr_xcursor_manager_ptr); + wlmtk_resizebar_area_set_cursor( + resizebar_ptr->center_area_ptr, + wlr_cursor_ptr, + wlr_xcursor_manager_ptr); + wlmtk_resizebar_area_set_cursor( + resizebar_ptr->right_area_ptr, + wlr_cursor_ptr, + wlr_xcursor_manager_ptr); +} + /* ------------------------------------------------------------------------- */ bool wlmtk_resizebar_set_width( wlmtk_resizebar_t *resizebar_ptr, @@ -284,7 +299,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_resizebar_style_t style = {}; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, NULL, NULL, 120, &style); + NULL, 120, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); @@ -296,7 +311,7 @@ void test_variable_width(bs_test_t *test_ptr) { wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, NULL, NULL, 0, &style); + NULL, 0, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index c4766b71..533ba304 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -46,8 +46,6 @@ typedef struct { /** * Creates the resize bar. * - * @param wlr_cursor_ptr - * @param wlr_xcursor_manager_ptr * @param window_ptr * @param width * @param style_ptr @@ -55,8 +53,6 @@ typedef struct { * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, unsigned width, const wlmtk_resizebar_style_t *style_ptr); @@ -68,6 +64,20 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr); +/** + * Sets cursor pointers. + * + * TODO(kaeser@gubbe.ch): Abstract this away. + * + * @param resizebar_ptr + * @param wlr_cursor_ptr + * @param wlr_xcursor_manager_ptr + */ +void wlmtk_resizebar_set_cursor( + wlmtk_resizebar_t *resizebar_ptr, + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr); + /** * Sets the width of the resize bar. * diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 05e689df..deea4085 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -91,16 +91,12 @@ static const wlmtk_buffer_impl_t area_buffer_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); if (NULL == resizebar_area_ptr) return NULL; - resizebar_area_ptr->wlr_cursor_ptr = wlr_cursor_ptr; - resizebar_area_ptr->wlr_xcursor_manager_ptr = wlr_xcursor_manager_ptr; resizebar_area_ptr->window_ptr = window_ptr; resizebar_area_ptr->edges = edges; @@ -143,6 +139,16 @@ void wlmtk_resizebar_area_destroy( free(resizebar_area_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_resizebar_area_set_cursor( + wlmtk_resizebar_area_t *resizebar_area_ptr, + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr) +{ + resizebar_area_ptr->wlr_cursor_ptr = wlr_cursor_ptr; + resizebar_area_ptr->wlr_xcursor_manager_ptr = wlr_xcursor_manager_ptr; +} + /* ------------------------------------------------------------------------- */ bool wlmtk_resizebar_area_redraw( wlmtk_resizebar_area_t *resizebar_area_ptr, @@ -321,7 +327,7 @@ const bs_test_case_t wlmtk_resizebar_area_test_cases[] = { void test_area(bs_test_t *test_ptr) { wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( - NULL, NULL, NULL, WLR_EDGE_BOTTOM); + NULL, WLR_EDGE_BOTTOM); BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index b2460504..472756de 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -41,16 +41,12 @@ struct wlr_xcursor_manager; /** * Creates a resizebar button. * - * @param wlr_cursor_ptr - * @param wlr_xcursor_manager_ptr * @param window_ptr * @param edges * * @return Pointer to the resizebar button. */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_window_t *window_ptr, uint32_t edges); @@ -62,6 +58,20 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( void wlmtk_resizebar_area_destroy( wlmtk_resizebar_area_t *resizebar_area_ptr); +/** + * Sets cursor pointers. + * + * TODO(kaeser@gubbe.ch): Abstract this away. + * + * @param resizebar_area_ptr + * @param wlr_cursor_ptr + * @param wlr_xcursor_manager_ptr + */ +void wlmtk_resizebar_area_set_cursor( + wlmtk_resizebar_area_t *resizebar_area_ptr, + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr); + /** * Redraws the element, with updated position and width. * diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 9f536173..d968f19b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -48,6 +48,8 @@ typedef struct { /** Virtual method table for @ref wlmtk_window_t. */ typedef struct { + /** Destructor. */ + void (*destroy)(wlmtk_window_t *window_ptr); /** See @ref wlmtk_window_set_activated. */ void (*set_activated)(wlmtk_window_t *window_ptr, bool activated); @@ -91,6 +93,10 @@ struct _wlmtk_window_t { wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; }; +bool wlmtk_window_init(wlmtk_window_t *window_ptr, + const wlmtk_window_impl_t *impl_ptr); +void wlmtk_window_fini(wlmtk_window_t *window_ptr); + static void wlmtk_window_set_activated_impl( wlmtk_window_t *window_ptr, bool activated); @@ -131,6 +137,7 @@ static const wlmtk_box_impl_t window_box_impl = { /** Default methods of @ref wlmtk_window_t. To override for a mock. */ static const wlmtk_window_impl_t window_default_impl = { + .destroy = wlmtk_window_destroy, .set_activated = wlmtk_window_set_activated_impl, .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, .request_move = wlmtk_window_request_move_impl, @@ -171,42 +178,57 @@ static const wlmtk_resizebar_style_t resizebar_style = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, - wlmtk_content_t *content_ptr) +/** + * Initializes the window. + * + * @param window_ptr + * @param impl_ptr + * + * @return true on success. + */ +bool wlmtk_window_init(wlmtk_window_t *window_ptr, + const wlmtk_window_impl_t *impl_ptr) { - wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); - if (NULL == window_ptr) return NULL; + BS_ASSERT(NULL != window_ptr); + BS_ASSERT(NULL != impl_ptr); + BS_ASSERT(NULL != impl_ptr->destroy); + BS_ASSERT(NULL != impl_ptr->set_activated); + BS_ASSERT(NULL != impl_ptr->set_server_side_decorated); + BS_ASSERT(NULL != impl_ptr->request_move); + BS_ASSERT(NULL != impl_ptr->request_resize); + BS_ASSERT(NULL != impl_ptr->request_size); + BS_ASSERT(NULL != impl_ptr->request_position_and_size); + memcpy(&window_ptr->impl, impl_ptr, sizeof(wlmtk_window_impl_t)); + for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { bs_dllist_push_back(&window_ptr->available_updates, &window_ptr->pre_allocated_updates[i].dlnode); } - memcpy(&window_ptr->impl, - &window_default_impl, - sizeof(wlmtk_window_impl_t)); if (!wlmtk_box_init(&window_ptr->super_box, &window_box_impl, WLMTK_BOX_VERTICAL)) { - wlmtk_window_destroy(window_ptr); - return NULL; + wlmtk_window_fini(window_ptr); + return false; } + window_ptr->resizebar_ptr = wlmtk_resizebar_create( + window_ptr, 0 /* FIXME: width */, &resizebar_style); + if (NULL == window_ptr->resizebar_ptr) { + wlmtk_window_fini(window_ptr); + return false; + } wlmtk_container_add_element( &window_ptr->super_box.super_container, - wlmtk_content_element(content_ptr)); - window_ptr->content_ptr = content_ptr; - wlmtk_content_set_window(content_ptr, window_ptr); - wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_element_set_visible( + wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - int width; - wlmtk_content_get_size(content_ptr, &width, NULL); window_ptr->titlebar_ptr = wlmtk_titlebar_create( - width, &titlebar_style); + 0 /* FIXME: width */, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { - wlmtk_window_destroy(window_ptr); - return NULL; + wlmtk_window_fini(window_ptr); + return false; } wlmtk_container_add_element( &window_ptr->super_box.super_container, @@ -214,26 +236,25 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - window_ptr->resizebar_ptr = wlmtk_resizebar_create( - wlr_cursor_ptr, wlr_xcursor_manager_ptr, - window_ptr, width, &resizebar_style); - if (NULL == window_ptr->resizebar_ptr) { - wlmtk_window_destroy(window_ptr); - return NULL; - } - wlmtk_container_add_element_before( - &window_ptr->super_box.super_container, - NULL, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_element_set_visible( - wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - - return window_ptr; + return true; } /* ------------------------------------------------------------------------- */ -void wlmtk_window_destroy(wlmtk_window_t *window_ptr) +/** + * Uninitializes the winodw. + * + * @param window_ptr + */ +void wlmtk_window_fini(wlmtk_window_t *window_ptr) { + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_container_remove_element( + &window_ptr->super_box.super_container, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); + window_ptr->titlebar_ptr = NULL; + } + if (NULL != window_ptr->resizebar_ptr) { wlmtk_container_remove_element( &window_ptr->super_box.super_container, @@ -242,14 +263,42 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) window_ptr->resizebar_ptr = NULL; } - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_container_remove_element( - &window_ptr->super_box.super_container, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); - window_ptr->titlebar_ptr = NULL; + wlmtk_box_fini(&window_ptr->super_box); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_window_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + wlmtk_content_t *content_ptr) +{ + wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); + if (NULL == window_ptr) return NULL; + + if (!wlmtk_window_init(window_ptr, &window_default_impl)) { + wlmtk_window_destroy(window_ptr); + return NULL; } + wlmtk_resizebar_set_cursor( + window_ptr->resizebar_ptr, + wlr_cursor_ptr, + wlr_xcursor_manager_ptr); + + wlmtk_container_add_element_before( + &window_ptr->super_box.super_container, + wlmtk_resizebar_element(window_ptr->resizebar_ptr), + wlmtk_content_element(content_ptr)); + window_ptr->content_ptr = content_ptr; + wlmtk_content_set_window(content_ptr, window_ptr); + wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + + return window_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_destroy(wlmtk_window_t *window_ptr) +{ wlmtk_container_remove_element( &window_ptr->super_box.super_container, wlmtk_content_element(window_ptr->content_ptr)); @@ -262,7 +311,7 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) window_ptr->content_ptr = NULL; } - wlmtk_box_fini(&window_ptr->super_box); + wlmtk_window_fini(window_ptr); free(window_ptr); } From 9c4781a22a4888257a77bf91b18bfead2af8e9d3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 16 Nov 2023 21:36:23 +0100 Subject: [PATCH 220/390] Moves the sizing away from the ctor of resizebar and titlebar. --- src/toolkit/resizebar.c | 17 ++--------------- src/toolkit/resizebar.h | 2 -- src/toolkit/titlebar.c | 10 ++-------- src/toolkit/titlebar.h | 2 -- src/toolkit/window.c | 5 ++--- 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 3ddcab57..b440f633 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -71,7 +71,6 @@ static const wlmtk_box_impl_t resizebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_window_t *window_ptr, - unsigned width, const wlmtk_resizebar_style_t *style_ptr) { wlmtk_resizebar_t *resizebar_ptr = logged_calloc( @@ -86,11 +85,6 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( return NULL; } - if (!redraw_buffers(resizebar_ptr, width)) { - wlmtk_resizebar_destroy(resizebar_ptr); - return NULL; - } - resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( window_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { @@ -123,11 +117,6 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( NULL, wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr)); - if (!wlmtk_resizebar_set_width(resizebar_ptr, width)) { - wlmtk_resizebar_destroy(resizebar_ptr); - return NULL; - } - return resizebar_ptr; } @@ -298,8 +287,7 @@ const bs_test_case_t wlmtk_resizebar_test_cases[] = { void test_create_destroy(bs_test_t *test_ptr) { wlmtk_resizebar_style_t style = {}; - wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, 120, &style); + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create(NULL, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); @@ -310,8 +298,7 @@ void test_create_destroy(bs_test_t *test_ptr) void test_variable_width(bs_test_t *test_ptr) { wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; - wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, 0, &style); + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create(NULL, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 533ba304..014174f1 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -47,14 +47,12 @@ typedef struct { * Creates the resize bar. * * @param window_ptr - * @param width * @param style_ptr * * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_window_t *window_ptr, - unsigned width, const wlmtk_resizebar_style_t *style_ptr); /** diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 01d0112f..82d43363 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -77,7 +77,6 @@ static const wlmtk_box_impl_t titlebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( - unsigned width, const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_t *titlebar_ptr = logged_calloc( @@ -92,11 +91,6 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } - if (!redraw_buffers(titlebar_ptr, width)) { - wlmtk_titlebar_destroy(titlebar_ptr); - return NULL; - } - titlebar_ptr->title_ptr = wlmtk_titlebar_title_create(); if (NULL == titlebar_ptr->title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -329,7 +323,7 @@ const bs_test_case_t wlmtk_titlebar_test_cases[] = { void test_create_destroy(bs_test_t *test_ptr) { wlmtk_titlebar_style_t style = {}; - wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(120, &style); + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(&style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); @@ -340,7 +334,7 @@ void test_create_destroy(bs_test_t *test_ptr) void test_variable_width(bs_test_t *test_ptr) { wlmtk_titlebar_style_t style = { .height = 22 }; - wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(0, &style); + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(&style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); // Short names, for improved readability. diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 0d6acbc0..4bd079c9 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -50,14 +50,12 @@ typedef struct { /** * Creates a title bar, suitable as a window title. * - * @param width * @param style_ptr * * @return Pointer to the title bar state, or NULL on error. Must be free'd * by calling @ref wlmtk_titlebar_destroy. */ wlmtk_titlebar_t *wlmtk_titlebar_create( - unsigned width, const wlmtk_titlebar_style_t *style_ptr); /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d968f19b..c2e53a4d 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -213,7 +213,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, } window_ptr->resizebar_ptr = wlmtk_resizebar_create( - window_ptr, 0 /* FIXME: width */, &resizebar_style); + window_ptr, &resizebar_style); if (NULL == window_ptr->resizebar_ptr) { wlmtk_window_fini(window_ptr); return false; @@ -224,8 +224,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - window_ptr->titlebar_ptr = wlmtk_titlebar_create( - 0 /* FIXME: width */, &titlebar_style); + window_ptr->titlebar_ptr = wlmtk_titlebar_create(&titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_fini(window_ptr); return false; From 375220fe8de8c7aa7a9bd4d955f61072a974b788 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 16 Nov 2023 22:01:04 +0100 Subject: [PATCH 221/390] Adds a fake implementation for wlmtk_window_t. --- src/toolkit/resizebar.h | 5 + src/toolkit/window.c | 222 +++++++++++++++++++++++++++------------- src/toolkit/window.h | 104 ++++++++++++++++++- 3 files changed, 261 insertions(+), 70 deletions(-) diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 014174f1..f52766f3 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -22,6 +22,11 @@ /** Forward declaration: Title bar. */ typedef struct _wlmtk_resizebar_t wlmtk_resizebar_t; +/** Forward declaration. */ +struct wlr_cursor; +/** Forward declaration. */ +struct wlr_xcursor_manager; + #include "element.h" #include "primitives.h" diff --git a/src/toolkit/window.c b/src/toolkit/window.c index c2e53a4d..d9d4b932 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -20,79 +20,10 @@ #include "window.h" -#include "box.h" -#include "resizebar.h" -#include "titlebar.h" #include "workspace.h" /* == Declarations ========================================================= */ -/** Maximum number of pending state updates. */ -#define WLMTK_WINDOW_MAX_PENDING 64 - -/** Pending positional updates. */ -typedef struct { - /** Node within @ref wlmtk_window_t::pending_updates. */ - bs_dllist_node_t dlnode; - /** Serial of the update. */ - uint32_t serial; - /** Pending X position. */ - int x; - /** Pending Y position. */ - int y; - /** Width that is to be committed at serial. */ - unsigned width; - /** Height that is to be committed at serial. */ - unsigned height; -} wlmtk_pending_update_t; - -/** Virtual method table for @ref wlmtk_window_t. */ -typedef struct { - /** Destructor. */ - void (*destroy)(wlmtk_window_t *window_ptr); - /** See @ref wlmtk_window_set_activated. */ - void (*set_activated)(wlmtk_window_t *window_ptr, - bool activated); - /** See @ref wlmtk_window_set_server_side_decorated. */ - void (*set_server_side_decorated)(wlmtk_window_t *window_ptr, - bool decorated); - - /** See @ref wlmtk_window_request_move. */ - void (*request_move)(wlmtk_window_t *window_ptr); - /** See @ref wlmtk_window_request_resize. */ - void (*request_resize)(wlmtk_window_t *window_ptr, - uint32_t edges); - - /** See @ref wlmtk_window_request_size. */ - void (*request_size)(wlmtk_window_t *window_ptr, - int x, int y); - /** See @ref wlmtk_window_request_position_and_size. */ - void (*request_position_and_size)(wlmtk_window_t *window_ptr, - int x, int y, int width, int height); -} wlmtk_window_impl_t; - -/** State of the window. */ -struct _wlmtk_window_t { - /** Superclass: Box. */ - wlmtk_box_t super_box; - /** Virtual method table. */ - wlmtk_window_impl_t impl; - - /** Content of this window. */ - wlmtk_content_t *content_ptr; - /** Titlebar. */ - wlmtk_titlebar_t *titlebar_ptr; - /** Resizebar. */ - wlmtk_resizebar_t *resizebar_ptr; - - /** Pending updates. */ - bs_dllist_t pending_updates; - /** List of udpates currently available. */ - bs_dllist_t available_updates; - /** Pre-alloocated updates. */ - wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; -}; - bool wlmtk_window_init(wlmtk_window_t *window_ptr, const wlmtk_window_impl_t *impl_ptr); void wlmtk_window_fini(wlmtk_window_t *window_ptr); @@ -118,6 +49,28 @@ static void wlmtk_window_request_position_and_size_impl( int width, int height); +static void fake_window_destroy(wlmtk_window_t *window_ptr); +static void fake_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated); +static void fake_window_set_server_side_decorated( + wlmtk_window_t *window_ptr, + bool decorated); +static void fake_window_request_move(wlmtk_window_t *window_ptr); +static void fake_window_request_resize( + wlmtk_window_t *window_ptr, + uint32_t edges); +static void fake_window_request_size( + wlmtk_window_t *window_ptr, + int width, + int height); +static void fake_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); + static wlmtk_pending_update_t *prepare_update( wlmtk_window_t *window_ptr); static void release_update( @@ -146,6 +99,17 @@ static const wlmtk_window_impl_t window_default_impl = { .request_position_and_size = wlmtk_window_request_position_and_size_impl, }; +/** Default methods of @ref wlmtk_window_t. To override for a mock. */ +static const wlmtk_window_impl_t fake_window_impl = { + .destroy = fake_window_destroy, + .set_activated = fake_window_set_activated, + .set_server_side_decorated = fake_window_set_server_side_decorated, + .request_move = fake_window_request_move, + .request_resize = fake_window_request_resize, + .request_size = fake_window_request_size, + .request_position_and_size = fake_window_request_position_and_size, +}; + /** Style of the title bar. */ // TODO(kaeser@gubbe.ch): Move to central config. */ static const wlmtk_titlebar_style_t titlebar_style = { @@ -410,6 +374,28 @@ void wlmtk_window_request_position_and_size( window_ptr, x, y, width, height); } +/* ------------------------------------------------------------------------- */ +wlmtk_fake_window_t *wlmtk_fake_window_create(void) +{ + wlmtk_fake_window_t *fake_window_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_window_t)); + if (NULL == fake_window_ptr) return NULL; + + if (!wlmtk_window_init(&fake_window_ptr->window, &fake_window_impl)) { + wlmtk_fake_window_destroy(fake_window_ptr); + return NULL; + } + + return fake_window_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) +{ + wlmtk_window_fini(&fake_window_ptr->window); + free(fake_window_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -580,14 +566,103 @@ void window_box_destroy(wlmtk_box_t *box_ptr) wlmtk_window_destroy(window_ptr); } +/* == Virtual method implementation for the fake window ==================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual dtor, wraps to @ref wlmtk_fake_window_destroy. */ +void fake_window_destroy(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + wlmtk_fake_window_destroy(fake_window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_set_activated. */ +void fake_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->activated = activated; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_set_server_side_decorated. */ +void fake_window_set_server_side_decorated( + wlmtk_window_t *window_ptr, + bool decorated) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->decorated = decorated; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_move. */ +void fake_window_request_move(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->request_move_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_resize. */ +void fake_window_request_resize( + wlmtk_window_t *window_ptr, + uint32_t edges) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->request_resize_called = true; + fake_window_ptr->request_resize_edges = edges; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_size. */ +void fake_window_request_size( + wlmtk_window_t *window_ptr, + int width, + int height) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->request_size_called = true; + fake_window_ptr->width = width; + fake_window_ptr->height = height; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_position_and_size. */ +void fake_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->request_position_and_size_called = true; + fake_window_ptr->x = x; + fake_window_ptr->y = y; + fake_window_ptr->width = width; + fake_window_ptr->height = height; +} + + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); static void test_set_activated(bs_test_t *test_ptr); +static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "create_destroy", test_create_destroy }, { 1, "set_activated", test_set_activated }, + { 1, "fake", test_fake }, { 0, NULL, NULL } }; @@ -622,4 +697,13 @@ void test_set_activated(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests fake window ctor and dtor. */ +void test_fake(bs_test_t *test_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_window_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); +} + /* == End of window.c ====================================================== */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index fb92f185..eb527a2b 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -23,8 +23,11 @@ /** Forward declaration: Window. */ typedef struct _wlmtk_window_t wlmtk_window_t; -#include "element.h" +#include "box.h" #include "content.h" +#include "element.h" +#include "resizebar.h" +#include "titlebar.h" #ifdef __cplusplus extern "C" { @@ -35,6 +38,72 @@ struct wlr_cursor; /** Forward declaration. */ struct wlr_xcursor_manager; +/** Maximum number of pending state updates. */ +#define WLMTK_WINDOW_MAX_PENDING 64 + +/** Pending positional updates. */ +typedef struct { + /** Node within @ref wlmtk_window_t::pending_updates. */ + bs_dllist_node_t dlnode; + /** Serial of the update. */ + uint32_t serial; + /** Pending X position. */ + int x; + /** Pending Y position. */ + int y; + /** Width that is to be committed at serial. */ + unsigned width; + /** Height that is to be committed at serial. */ + unsigned height; +} wlmtk_pending_update_t; + +/** Virtual method table for @ref wlmtk_window_t. */ +typedef struct { + /** Destructor. */ + void (*destroy)(wlmtk_window_t *window_ptr); + /** See @ref wlmtk_window_set_activated. */ + void (*set_activated)(wlmtk_window_t *window_ptr, + bool activated); + /** See @ref wlmtk_window_set_server_side_decorated. */ + void (*set_server_side_decorated)(wlmtk_window_t *window_ptr, + bool decorated); + + /** See @ref wlmtk_window_request_move. */ + void (*request_move)(wlmtk_window_t *window_ptr); + /** See @ref wlmtk_window_request_resize. */ + void (*request_resize)(wlmtk_window_t *window_ptr, + uint32_t edges); + + /** See @ref wlmtk_window_request_size. */ + void (*request_size)(wlmtk_window_t *window_ptr, + int x, int y); + /** See @ref wlmtk_window_request_position_and_size. */ + void (*request_position_and_size)(wlmtk_window_t *window_ptr, + int x, int y, int width, int height); +} wlmtk_window_impl_t; + +/** State of the window. */ +struct _wlmtk_window_t { + /** Superclass: Box. */ + wlmtk_box_t super_box; + /** Virtual method table. */ + wlmtk_window_impl_t impl; + + /** Content of this window. */ + wlmtk_content_t *content_ptr; + /** Titlebar. */ + wlmtk_titlebar_t *titlebar_ptr; + /** Resizebar. */ + wlmtk_resizebar_t *resizebar_ptr; + + /** Pending updates. */ + bs_dllist_t pending_updates; + /** List of udpates currently available. */ + bs_dllist_t available_updates; + /** Pre-alloocated updates. */ + wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; +}; + /** * Creates a window for the given content. * @@ -176,6 +245,39 @@ void wlmtk_window_request_position_and_size( */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); +/** State of the fake window, for tests. */ +typedef struct { + /** Window state. */ + wlmtk_window_t window; + /** Argument to last @ref wlmtk_window_set_activated call. */ + bool activated; + /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ + bool decorated; + /** Whether @ref wlmtk_window_request_move was called. */ + bool request_move_called; + /** Whether @ref wlmtk_window_request_resize was called. */ + bool request_resize_called; + /** Argument to last @ref wlmtk_window_request_resize call. */ + uint32_t request_resize_edges; + /** Whether @ref wlmtk_window_request_size was called. */ + bool request_size_called; + /** Whether @ref wlmtk_window_request_position_and_size was called. */ + bool request_position_and_size_called; + /** Argument to last @ref wlmtk_window_request_size call. */ + int x; + /** Argument to last @ref wlmtk_window_request_size call. */ + int y; + /** Argument to last @ref wlmtk_window_request_size call. */ + int width; + /** Argument to last @ref wlmtk_window_request_size call. */ + int height; +} wlmtk_fake_window_t; + +/** Ctor. */ +wlmtk_fake_window_t *wlmtk_fake_window_create(void); +/** Dtor. */ +void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr); + /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; From 06018163a74c33a95571d8852578097ed1bd2050 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 17 Nov 2023 16:44:56 +0100 Subject: [PATCH 222/390] Wraps the wlmtk_window_t virtual dtor the correct route. --- src/toolkit/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d9d4b932..f4c5330f 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -563,7 +563,7 @@ void window_box_destroy(wlmtk_box_t *box_ptr) { wlmtk_window_t *window_ptr = BS_CONTAINER_OF( box_ptr, wlmtk_window_t, super_box); - wlmtk_window_destroy(window_ptr); + window_ptr->impl.destroy(window_ptr); } /* == Virtual method implementation for the fake window ==================== */ From edbe99beccfef1ff786f11d6f1819f98f4921c04 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 17 Nov 2023 16:58:06 +0100 Subject: [PATCH 223/390] Adds test on resizebar for calling wlmtk_winodw_request_resize. --- src/toolkit/resizebar_area.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index deea4085..681acf48 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -24,6 +24,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" +#include "window.h" #include @@ -326,8 +327,10 @@ const bs_test_case_t wlmtk_resizebar_area_test_cases[] = { /** Tests the area behaviour. */ void test_area(bs_test_t *test_ptr) { + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( - NULL, WLR_EDGE_BOTTOM); + &fake_window_ptr->window, WLR_EDGE_BOTTOM); BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); @@ -343,6 +346,7 @@ void test_area(bs_test_t *test_ptr) test_ptr, bs_gfxbuf_from_wlr_buffer(area_ptr->super_buffer.wlr_buffer_ptr), "toolkit/resizebar_area_released.png"); + BS_TEST_VERIFY_FALSE(test_ptr, fake_window_ptr->request_resize_called); // Pointer must be inside the button for accepting DOWN. BS_TEST_VERIFY_TRUE( @@ -360,10 +364,16 @@ void test_area(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(area_ptr->super_buffer.wlr_buffer_ptr), "toolkit/resizebar_area_pressed.png"); - // TODO(kaeser@gubbe.ch): Should verify call to wlmtk_window_request_resize - // and for setting the cursor. + // TODO(kaeser@gubbe.ch): Should verify setting the cursor. + BS_TEST_VERIFY_TRUE(test_ptr, fake_window_ptr->request_resize_called); + BS_TEST_VERIFY_EQ( + test_ptr, + WLR_EDGE_BOTTOM, + fake_window_ptr->request_resize_edges); + wlmtk_element_destroy(element_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of resizebar_area.c ============================================== */ From 58c62e86e9bc619aaf5177902f83a2197eec29d0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 17 Nov 2023 17:01:23 +0100 Subject: [PATCH 224/390] Enforces validity of the wlmtk_window_t passed to resizebar. --- src/toolkit/resizebar.c | 11 +++++++++-- src/toolkit/resizebar_area.c | 10 ++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index b440f633..95bee006 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -286,19 +286,25 @@ const bs_test_case_t wlmtk_resizebar_test_cases[] = { /** Exercises @ref wlmtk_resizebar_create and @ref wlmtk_resizebar_destroy. */ void test_create_destroy(bs_test_t *test_ptr) { + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = {}; - wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create(NULL, &style); + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( + &fake_window_ptr->window, &style); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); + wlmtk_fake_window_destroy(fake_window_ptr); } /* ------------------------------------------------------------------------- */ /** Performs resizing and verifies the elements are shown as expected. */ void test_variable_width(bs_test_t *test_ptr) { + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; - wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create(NULL, &style); + wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( + &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( @@ -339,6 +345,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, right_elem_ptr->x); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of resizebar.c =================================================== */ diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 681acf48..9222b663 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -98,6 +98,7 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); if (NULL == resizebar_area_ptr) return NULL; + BS_ASSERT(NULL != window_ptr); resizebar_area_ptr->window_ptr = window_ptr; resizebar_area_ptr->edges = edges; @@ -235,11 +236,9 @@ bool buffer_pointer_button( case WLMTK_BUTTON_DOWN: resizebar_area_ptr->pressed = true; - if (NULL != resizebar_area_ptr->window_ptr) { - wlmtk_window_request_resize( - resizebar_area_ptr->window_ptr, - resizebar_area_ptr->edges); - } + wlmtk_window_request_resize( + resizebar_area_ptr->window_ptr, + resizebar_area_ptr->edges); draw_state(resizebar_area_ptr); break; @@ -371,7 +370,6 @@ void test_area(bs_test_t *test_ptr) WLR_EDGE_BOTTOM, fake_window_ptr->request_resize_edges); - wlmtk_element_destroy(element_ptr); wlmtk_fake_window_destroy(fake_window_ptr); } From 571d3e30732e9d318e78346c00b7308c908f2bf6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 17 Nov 2023 17:18:25 +0100 Subject: [PATCH 225/390] Adds window as argument to titlebar ctor. --- src/toolkit/titlebar.c | 14 +++++++++--- src/toolkit/titlebar.h | 3 +++ src/toolkit/titlebar_title.c | 42 +++++++++++++++++++++++++++++++++--- src/toolkit/titlebar_title.h | 5 ++++- src/toolkit/window.c | 3 ++- 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 82d43363..050f762c 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -27,6 +27,7 @@ #include "primitives.h" #include "titlebar_button.h" #include "titlebar_title.h" +#include "window.h" #define WLR_USE_UNSTABLE #include @@ -77,6 +78,7 @@ static const wlmtk_box_impl_t titlebar_box_impl = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( + wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_t *titlebar_ptr = logged_calloc( @@ -91,7 +93,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } - titlebar_ptr->title_ptr = wlmtk_titlebar_title_create(); + titlebar_ptr->title_ptr = wlmtk_titlebar_title_create(window_ptr); if (NULL == titlebar_ptr->title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -322,19 +324,24 @@ const bs_test_case_t wlmtk_titlebar_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = {}; - wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(&style); + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( + &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); + wlmtk_fake_window_destroy(fake_window_ptr); } /* ------------------------------------------------------------------------- */ /** Tests titlebar with variable width. */ void test_variable_width(bs_test_t *test_ptr) { + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = { .height = 22 }; - wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create(&style); + wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( + &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); // Short names, for improved readability. @@ -380,6 +387,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 66, width); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of titlebar.c ==================================================== */ diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 4bd079c9..8b013d42 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -26,6 +26,7 @@ typedef struct _wlmtk_titlebar_t wlmtk_titlebar_t; #include "element.h" #include "primitives.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -50,12 +51,14 @@ typedef struct { /** * Creates a title bar, suitable as a window title. * + * @param window_ptr * @param style_ptr * * @return Pointer to the title bar state, or NULL on error. Must be free'd * by calling @ref wlmtk_titlebar_destroy. */ wlmtk_titlebar_t *wlmtk_titlebar_create( + wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr); /** diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index cdf320f6..a0307f9d 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -23,6 +23,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" +#include "window.h" #define WLR_USE_UNSTABLE #include @@ -34,6 +35,8 @@ struct _wlmtk_titlebar_title_t { /** Superclass: Buffer. */ wlmtk_buffer_t super_buffer; + /** Pointer to the window the title element belongs to. */ + wlmtk_window_t *window_ptr; /** The drawn title, when focussed. */ struct wlr_buffer *focussed_wlr_buffer_ptr; @@ -42,6 +45,9 @@ struct _wlmtk_titlebar_title_t { }; static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); +static bool title_buffer_pointer_button( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr); static void title_set_activated( wlmtk_titlebar_title_t *titlebar_title_ptr, bool activated); @@ -56,17 +62,20 @@ struct wlr_buffer *title_create_buffer( /** Buffer implementation for title of the title bar. */ static const wlmtk_buffer_impl_t title_buffer_impl = { - .destroy = title_buffer_destroy + .destroy = title_buffer_destroy, + .pointer_button = title_buffer_pointer_button, }; /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void) +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + wlmtk_window_t *window_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_title_t)); if (NULL == titlebar_title_ptr) return NULL; + titlebar_title_ptr->window_ptr = window_ptr; if (!wlmtk_buffer_init( &titlebar_title_ptr->super_buffer, @@ -152,6 +161,30 @@ void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) wlmtk_titlebar_title_destroy(titlebar_title_ptr); } +/* ------------------------------------------------------------------------- */ +/** See @ref wlmtk_buffer_impl_t::pointer_button. */ +bool title_buffer_pointer_button( + wlmtk_buffer_t *buffer_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_titlebar_title_t *titlebar_title_ptr = BS_CONTAINER_OF( + buffer_ptr, wlmtk_titlebar_title_t, super_buffer); + + if (button_event_ptr->button != BTN_LEFT) return false; + + switch (button_event_ptr->type) { + case WLMTK_BUTTON_DOWN: + bs_log(BS_INFO, "FIXME: %p", titlebar_title_ptr); + break; + + default: // Can be ignored. + break; + } + + return true; + +} + /* ------------------------------------------------------------------------- */ /** * Sets whether the title is drawn focussed (activated) or blurred. @@ -237,7 +270,9 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); - wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( + &fake_window_ptr->window); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); BS_TEST_VERIFY_TRUE( test_ptr, @@ -278,6 +313,7 @@ void test_title(bs_test_t *test_ptr) "toolkit/title_blurred_short.png"); wlmtk_element_destroy(wlmtk_titlebar_title_element(titlebar_title_ptr)); + wlmtk_fake_window_destroy(fake_window_ptr); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); } diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h index d80853a6..0e994114 100644 --- a/src/toolkit/titlebar_title.h +++ b/src/toolkit/titlebar_title.h @@ -35,9 +35,12 @@ extern "C" { /** * Creates a title bar title. * + * @param window_ptr + * * @return Title handle. */ -wlmtk_titlebar_title_t *wlmtk_titlebar_title_create(void); +wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + wlmtk_window_t *window_ptr); /** * Destroys the titlebar title. diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f4c5330f..44685388 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -188,7 +188,8 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - window_ptr->titlebar_ptr = wlmtk_titlebar_create(&titlebar_style); + window_ptr->titlebar_ptr = wlmtk_titlebar_create( + window_ptr, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_fini(window_ptr); return false; From 6a1064a0ee0084246b0b734206aad20e4e2df9ce Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 17 Nov 2023 17:23:10 +0100 Subject: [PATCH 226/390] Wires up title bar title to trigger a move. --- src/toolkit/titlebar_title.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index a0307f9d..6478c702 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -174,7 +174,7 @@ bool title_buffer_pointer_button( switch (button_event_ptr->type) { case WLMTK_BUTTON_DOWN: - bs_log(BS_INFO, "FIXME: %p", titlebar_title_ptr); + wlmtk_window_request_move(titlebar_title_ptr->window_ptr); break; default: // Can be ignored. @@ -273,6 +273,8 @@ void test_title(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( &fake_window_ptr->window); + wlmtk_element_t *element_ptr = wlmtk_titlebar_title_element( + titlebar_title_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); BS_TEST_VERIFY_TRUE( test_ptr, @@ -312,7 +314,17 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_blurred_short.png"); - wlmtk_element_destroy(wlmtk_titlebar_title_element(titlebar_title_ptr)); + // Pressing a button should trigger a move. + BS_TEST_VERIFY_FALSE(test_ptr, fake_window_ptr->request_move_called); + wlmtk_button_event_t button = { + .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN + }; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &button)); + BS_TEST_VERIFY_TRUE(test_ptr, fake_window_ptr->request_move_called); + + wlmtk_element_destroy(element_ptr); wlmtk_fake_window_destroy(fake_window_ptr); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); From 7b034242ec0cafe5633230dca935fdc75a262583 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 10:31:17 +0100 Subject: [PATCH 227/390] Passes the pointer to the window to titlebar buttons. --- src/toolkit/titlebar.c | 2 ++ src/toolkit/titlebar_button.c | 7 +++++++ src/toolkit/titlebar_button.h | 2 ++ src/toolkit/window.c | 27 +++++++++++++++++++++++++++ src/toolkit/window.h | 11 +++++++++++ 5 files changed, 49 insertions(+) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 050f762c..3508aa52 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -103,6 +103,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( + window_ptr, wlmaker_primitives_draw_minimize_icon); if (NULL == titlebar_ptr->minimize_button_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -113,6 +114,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( + window_ptr, wlmaker_primitives_draw_close_icon); if (NULL == titlebar_ptr->close_button_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 8d6ea801..e2ed0aef 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -35,6 +35,8 @@ struct _wlmtk_titlebar_button_t { /** Superclass: Button. */ wlmtk_button_t super_button; + /** Points to the @ref wlmtk_window_t that carries this titlebar. */ + wlmtk_window_t *window_ptr; /** For drawing the button contents. */ wlmtk_titlebar_button_draw_t draw; @@ -65,11 +67,13 @@ static const wlmtk_button_impl_t titlebar_button_impl = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw) { wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_button_t)); if (NULL == titlebar_button_ptr) return NULL; + titlebar_button_ptr->window_ptr = window_ptr; titlebar_button_ptr->draw = draw; if (!wlmtk_button_init( @@ -212,7 +216,9 @@ const bs_test_case_t wlmtk_titlebar_button_test_cases[] = { /** Tests button visualization. */ void test_button(bs_test_t *test_ptr) { + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( + &fake_window_ptr->window, wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); @@ -267,6 +273,7 @@ void test_button(bs_test_t *test_ptr) "toolkit/title_button_focussed_released.png"); wlmtk_element_destroy(element_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of titlebar_button.c ============================================= */ diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index 43cb4be4..75c3c8e0 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -39,11 +39,13 @@ typedef void (*wlmtk_titlebar_button_draw_t)( /** * Creates a button for the titlebar. * + * @param window_ptr * @param draw * * @return Pointer to the titlebar button, or NULL on error. */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw); /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 44685388..b7f2e1e6 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -34,6 +34,7 @@ static void wlmtk_window_set_activated_impl( static void wlmtk_window_set_server_side_decorated_impl( wlmtk_window_t *window_ptr, bool decorated); +static void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr); static void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr); static void wlmtk_window_request_resize_impl( wlmtk_window_t *window_ptr, @@ -56,6 +57,7 @@ static void fake_window_set_activated( static void fake_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); +static void fake_window_request_close(wlmtk_window_t *window_ptr); static void fake_window_request_move(wlmtk_window_t *window_ptr); static void fake_window_request_resize( wlmtk_window_t *window_ptr, @@ -93,6 +95,7 @@ static const wlmtk_window_impl_t window_default_impl = { .destroy = wlmtk_window_destroy, .set_activated = wlmtk_window_set_activated_impl, .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, + .request_close = wlmtk_window_request_close_impl, .request_move = wlmtk_window_request_move_impl, .request_resize = wlmtk_window_request_resize_impl, .request_size = wlmtk_window_request_size_impl, @@ -104,6 +107,7 @@ static const wlmtk_window_impl_t fake_window_impl = { .destroy = fake_window_destroy, .set_activated = fake_window_set_activated, .set_server_side_decorated = fake_window_set_server_side_decorated, + .request_close = fake_window_request_close, .request_move = fake_window_request_move, .request_resize = fake_window_request_resize, .request_size = fake_window_request_size, @@ -158,6 +162,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, BS_ASSERT(NULL != impl_ptr->destroy); BS_ASSERT(NULL != impl_ptr->set_activated); BS_ASSERT(NULL != impl_ptr->set_server_side_decorated); + BS_ASSERT(NULL != impl_ptr->request_close); BS_ASSERT(NULL != impl_ptr->request_move); BS_ASSERT(NULL != impl_ptr->request_resize); BS_ASSERT(NULL != impl_ptr->request_size); @@ -341,6 +346,12 @@ void wlmtk_window_set_server_side_decorated( window_ptr->impl.set_server_side_decorated(window_ptr, decorated); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_close(wlmtk_window_t *window_ptr) +{ + window_ptr->impl.request_close(window_ptr); +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { @@ -422,6 +433,13 @@ void wlmtk_window_set_server_side_decorated_impl( window_ptr, decorated); } +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_close. */ +void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr) +{ + bs_log(BS_INFO, "Requesting window %p to close.", window_ptr); +} + /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_move. */ void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) @@ -600,6 +618,15 @@ void fake_window_set_server_side_decorated( fake_window_ptr->decorated = decorated; } +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_close. */ +void fake_window_request_close(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->request_close_called = true; +} + /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_move. */ void fake_window_request_move(wlmtk_window_t *window_ptr) diff --git a/src/toolkit/window.h b/src/toolkit/window.h index eb527a2b..76b4dfcc 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -68,6 +68,8 @@ typedef struct { void (*set_server_side_decorated)(wlmtk_window_t *window_ptr, bool decorated); + /** See @ref wlmtk_window_request_close. */ + void (*request_close)(wlmtk_window_t *window_ptr); /** See @ref wlmtk_window_request_move. */ void (*request_move)(wlmtk_window_t *window_ptr); /** See @ref wlmtk_window_request_resize. */ @@ -174,6 +176,13 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); +/** + * Requests to close the window. + * + * @param window_ptr + */ +void wlmtk_window_request_close(wlmtk_window_t *window_ptr); + /** * Requests a move for the window. * @@ -253,6 +262,8 @@ typedef struct { bool activated; /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ bool decorated; + /** Whether @ref wlmtk_window_request_close was called. */ + bool request_close_called; /** Whether @ref wlmtk_window_request_move was called. */ bool request_move_called; /** Whether @ref wlmtk_window_request_resize was called. */ From 0aace9710f413959b5586795047f49c808a3c194 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 10:36:42 +0100 Subject: [PATCH 228/390] Wires up the button click with the window request. Currently, just with close. --- src/toolkit/titlebar_button.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index e2ed0aef..bc0df3c6 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -49,6 +49,7 @@ struct _wlmtk_titlebar_button_t { }; static void titlebar_button_destroy(wlmtk_button_t *button_ptr); +static void titlebar_button_clicked(wlmtk_button_t *button_ptr); static struct wlr_buffer *create_buf( bs_gfxbuf_t *gfxbuf_ptr, int position, @@ -60,7 +61,8 @@ static struct wlr_buffer *create_buf( /** Buffer implementation for title of the title bar. */ static const wlmtk_button_impl_t titlebar_button_impl = { - .destroy = titlebar_button_destroy + .destroy = titlebar_button_destroy, + .clicked = titlebar_button_clicked, }; /* == Exported methods ===================================================== */ @@ -173,6 +175,16 @@ void titlebar_button_destroy(wlmtk_button_t *button_ptr) wlmtk_titlebar_button_destroy(titlebar_button_ptr); } +/* ------------------------------------------------------------------------- */ +/** Handles button clicks: Passes the request to the window. */ +void titlebar_button_clicked(wlmtk_button_t *button_ptr) +{ + wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( + button_ptr, wlmtk_titlebar_button_t, super_button); + + wlmtk_window_request_close(titlebar_button_ptr->window_ptr); +} + /* ------------------------------------------------------------------------- */ /** Helper: Creates a WLR buffer for the button. */ struct wlr_buffer *create_buf( @@ -272,6 +284,21 @@ void test_button(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_button_focussed_released.png"); + BS_TEST_VERIFY_FALSE( + test_ptr, + fake_window_ptr->request_close_called); + button.type = WLMTK_BUTTON_CLICK; + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_button(element_ptr, &button)); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_button_focussed_released.png"); + BS_TEST_VERIFY_TRUE( + test_ptr, + fake_window_ptr->request_close_called); + wlmtk_element_destroy(element_ptr); wlmtk_fake_window_destroy(fake_window_ptr); } From 366ae761feebcfcaa644ed5e122e25e8e22a4693 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 10:50:00 +0100 Subject: [PATCH 229/390] Makes the button click handler configurable. --- src/toolkit/titlebar.c | 2 ++ src/toolkit/titlebar_button.c | 11 +++++++++-- src/toolkit/titlebar_button.h | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 3508aa52..b3befdef 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -103,6 +103,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( + wlmtk_window_request_close, window_ptr, wlmaker_primitives_draw_minimize_icon); if (NULL == titlebar_ptr->minimize_button_ptr) { @@ -114,6 +115,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( + wlmtk_window_request_close, window_ptr, wlmaker_primitives_draw_close_icon); if (NULL == titlebar_ptr->close_button_ptr) { diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index bc0df3c6..08806fcc 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -35,6 +35,8 @@ struct _wlmtk_titlebar_button_t { /** Superclass: Button. */ wlmtk_button_t super_button; + /** Callback for when the button is clicked. */ + void (*click_handler)(wlmtk_window_t *window_ptr); /** Points to the @ref wlmtk_window_t that carries this titlebar. */ wlmtk_window_t *window_ptr; /** For drawing the button contents. */ @@ -69,12 +71,17 @@ static const wlmtk_button_impl_t titlebar_button_impl = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + void (*click_handler)(wlmtk_window_t *window_ptr), wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw) { + BS_ASSERT(NULL != window_ptr); + BS_ASSERT(NULL != click_handler); + BS_ASSERT(NULL != draw); wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_button_t)); if (NULL == titlebar_button_ptr) return NULL; + titlebar_button_ptr->click_handler = click_handler; titlebar_button_ptr->window_ptr = window_ptr; titlebar_button_ptr->draw = draw; @@ -181,8 +188,7 @@ void titlebar_button_clicked(wlmtk_button_t *button_ptr) { wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( button_ptr, wlmtk_titlebar_button_t, super_button); - - wlmtk_window_request_close(titlebar_button_ptr->window_ptr); + titlebar_button_ptr->click_handler(titlebar_button_ptr->window_ptr); } /* ------------------------------------------------------------------------- */ @@ -230,6 +236,7 @@ void test_button(bs_test_t *test_ptr) { wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( + wlmtk_window_request_close, &fake_window_ptr->window, wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index 75c3c8e0..908742e6 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -39,12 +39,14 @@ typedef void (*wlmtk_titlebar_button_draw_t)( /** * Creates a button for the titlebar. * + * @param click_handler * @param window_ptr * @param draw * * @return Pointer to the titlebar button, or NULL on error. */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + void (*click_handler)(wlmtk_window_t *window_ptr), wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw); From 229ceb7f4e32d4de7c5925ac42e05dd722da8455 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 10:53:23 +0100 Subject: [PATCH 230/390] Adds wlmtk_window_request_minimize and wires it up in the titlebar button. --- src/toolkit/titlebar.c | 2 +- src/toolkit/window.c | 27 +++++++++++++++++++++++++++ src/toolkit/window.h | 13 ++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index b3befdef..0ba67352 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -103,7 +103,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( - wlmtk_window_request_close, + wlmtk_window_request_minimize, window_ptr, wlmaker_primitives_draw_minimize_icon); if (NULL == titlebar_ptr->minimize_button_ptr) { diff --git a/src/toolkit/window.c b/src/toolkit/window.c index b7f2e1e6..9c4a45f0 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -35,6 +35,7 @@ static void wlmtk_window_set_server_side_decorated_impl( wlmtk_window_t *window_ptr, bool decorated); static void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr); +static void wlmtk_window_request_minimize_impl(wlmtk_window_t *window_ptr); static void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr); static void wlmtk_window_request_resize_impl( wlmtk_window_t *window_ptr, @@ -58,6 +59,7 @@ static void fake_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); static void fake_window_request_close(wlmtk_window_t *window_ptr); +static void fake_window_request_minimize(wlmtk_window_t *window_ptr); static void fake_window_request_move(wlmtk_window_t *window_ptr); static void fake_window_request_resize( wlmtk_window_t *window_ptr, @@ -96,6 +98,7 @@ static const wlmtk_window_impl_t window_default_impl = { .set_activated = wlmtk_window_set_activated_impl, .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, .request_close = wlmtk_window_request_close_impl, + .request_minimize = wlmtk_window_request_minimize_impl, .request_move = wlmtk_window_request_move_impl, .request_resize = wlmtk_window_request_resize_impl, .request_size = wlmtk_window_request_size_impl, @@ -108,6 +111,7 @@ static const wlmtk_window_impl_t fake_window_impl = { .set_activated = fake_window_set_activated, .set_server_side_decorated = fake_window_set_server_side_decorated, .request_close = fake_window_request_close, + .request_minimize = fake_window_request_minimize, .request_move = fake_window_request_move, .request_resize = fake_window_request_resize, .request_size = fake_window_request_size, @@ -163,6 +167,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, BS_ASSERT(NULL != impl_ptr->set_activated); BS_ASSERT(NULL != impl_ptr->set_server_side_decorated); BS_ASSERT(NULL != impl_ptr->request_close); + BS_ASSERT(NULL != impl_ptr->request_minimize); BS_ASSERT(NULL != impl_ptr->request_move); BS_ASSERT(NULL != impl_ptr->request_resize); BS_ASSERT(NULL != impl_ptr->request_size); @@ -352,6 +357,12 @@ void wlmtk_window_request_close(wlmtk_window_t *window_ptr) window_ptr->impl.request_close(window_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) +{ + window_ptr->impl.request_minimize(window_ptr); +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { @@ -440,6 +451,13 @@ void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr) bs_log(BS_INFO, "Requesting window %p to close.", window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_minimize. */ +void wlmtk_window_request_minimize_impl(wlmtk_window_t *window_ptr) +{ + bs_log(BS_INFO, "Requesting window %p to minimize.", window_ptr); +} + /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_move. */ void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) @@ -627,6 +645,15 @@ void fake_window_request_close(wlmtk_window_t *window_ptr) fake_window_ptr->request_close_called = true; } +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_minimize. */ +void fake_window_request_minimize(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->request_minimize_called = true; +} + /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_move. */ void fake_window_request_move(wlmtk_window_t *window_ptr) diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 76b4dfcc..d04277c9 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -70,6 +70,8 @@ typedef struct { /** See @ref wlmtk_window_request_close. */ void (*request_close)(wlmtk_window_t *window_ptr); + /** See @ref wlmtk_window_request_minimize. */ + void (*request_minimize)(wlmtk_window_t *window_ptr); /** See @ref wlmtk_window_request_move. */ void (*request_move)(wlmtk_window_t *window_ptr); /** See @ref wlmtk_window_request_resize. */ @@ -183,6 +185,13 @@ void wlmtk_window_set_server_side_decorated( */ void wlmtk_window_request_close(wlmtk_window_t *window_ptr); +/** + * Requests to minimize (iconify) the window. + * + * @param window_ptr + */ +void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); + /** * Requests a move for the window. * @@ -264,7 +273,9 @@ typedef struct { bool decorated; /** Whether @ref wlmtk_window_request_close was called. */ bool request_close_called; - /** Whether @ref wlmtk_window_request_move was called. */ + /** Whether @ref wlmtk_window_request_minimize was called. */ + bool request_minimize_called; + /** Whether @ref wlmtk_window_request_move was called. */ bool request_move_called; /** Whether @ref wlmtk_window_request_resize was called. */ bool request_resize_called; From c87461643f943c36a89926da95449e32ce3a6ea5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 16:28:38 +0100 Subject: [PATCH 231/390] Implements wlmtk_content_request_close. --- src/toolkit/content.c | 16 ++++++++++++++++ src/toolkit/content.h | 8 ++++++++ src/toolkit/window.c | 20 ++++++++++++++++++-- src/wlmtk_xdg_toplevel.c | 19 +++++++++++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index b0af5af8..d9c95bdf 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -84,6 +84,7 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr); BS_ASSERT(NULL != content_impl_ptr->destroy); BS_ASSERT(NULL != content_impl_ptr->create_scene_node); + BS_ASSERT(NULL != content_impl_ptr->request_close); BS_ASSERT(NULL != content_impl_ptr->request_size); BS_ASSERT(NULL != content_impl_ptr->set_activated); @@ -388,6 +389,8 @@ static void fake_content_destroy( static struct wlr_scene_node *fake_content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void fake_content_request_close( + wlmtk_content_t *content_ptr); static uint32_t fake_content_request_size( wlmtk_content_t *content_ptr, int width, @@ -400,6 +403,7 @@ static void fake_content_set_activated( static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, .create_scene_node = fake_content_create_scene_node, + .request_close = fake_content_request_close, .request_size = fake_content_request_size, .set_activated = fake_content_set_activated, }; @@ -449,6 +453,15 @@ struct wlr_scene_node *fake_content_create_scene_node( return &wlr_scene_buffer_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** Records that @ref wlmtk_content_request_close was called. */ +void fake_content_request_close(wlmtk_content_t *content_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_fake_content_t, content); + fake_content_ptr->request_close_called = true; +} + /* ------------------------------------------------------------------------- */ /** Sets the size of the fake content. */ uint32_t fake_content_request_size( @@ -500,6 +513,9 @@ void test_init_fini(bs_test_t *test_ptr) test_ptr, NULL, fake_content_ptr->content.impl.destroy); + wlmtk_content_request_close(&fake_content_ptr->content); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); + int l, t, r, b; fake_content_ptr->return_request_size = 42; BS_TEST_VERIFY_EQ( diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 58ec4adf..6546821f 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -40,6 +40,8 @@ struct _wlmtk_content_impl_t { struct wlr_scene_node *(*create_scene_node)( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); + /** Requests the content to close. */ + void (*request_close)(wlmtk_content_t *content_ptr); /** Sets width and height of the content. Returns serial. */ uint32_t (*request_size)(wlmtk_content_t *content_ptr, int width, int height); @@ -159,6 +161,10 @@ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { content_ptr->impl.destroy(content_ptr); } +/** Wraps to @ref wlmtk_content_impl_t::request_close. */ +static inline void wlmtk_content_request_close(wlmtk_content_t *content_ptr) { + content_ptr->impl.request_close(content_ptr); +} /** Wraps to @ref wlmtk_content_impl_t::request_size. */ static inline uint32_t wlmtk_content_request_size( wlmtk_content_t *content_ptr, @@ -187,6 +193,8 @@ extern const bs_test_case_t wlmtk_content_test_cases[]; typedef struct { /** State of the content. */ wlmtk_content_t content; + /** Whether @ref wlmtk_content_request_close was called. */ + bool request_close_called; /** `width` argument eof last @ref wlmtk_content_request_size call. */ int requested_width; /** `height` argument of last @ref wlmtk_content_request_size call. */ diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 9c4a45f0..0bff15a2 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -445,10 +445,10 @@ void wlmtk_window_set_server_side_decorated_impl( } /* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_close. */ +/** Implements @ref wlmtk_window_request_close. Requests content closure. */ void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr) { - bs_log(BS_INFO, "Requesting window %p to close.", window_ptr); + wlmtk_content_request_close(window_ptr->content_ptr); } /* ------------------------------------------------------------------------- */ @@ -711,11 +711,13 @@ void fake_window_request_position_and_size( /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_request_close(bs_test_t *test_ptr); static void test_set_activated(bs_test_t *test_ptr); static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "request_close", test_request_close }, { 1, "set_activated", test_set_activated }, { 1, "fake", test_fake }, { 0, NULL, NULL } @@ -735,6 +737,20 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests activation. */ +void test_request_close(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, NULL, &fake_content_ptr->content); + + wlmtk_window_request_close(window_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); + + wlmtk_window_destroy(window_ptr); +} + /* ------------------------------------------------------------------------- */ /** Tests activation. */ void test_set_activated(bs_test_t *test_ptr) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 93e866e7..3afc26f9 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -75,6 +75,8 @@ static void content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *content_create_scene_node( wlmtk_content_t *content_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static void content_request_close( + wlmtk_content_t *content_ptr); static uint32_t content_request_size( wlmtk_content_t *content_ptr, int width, @@ -89,6 +91,7 @@ static void content_set_activated( const wlmtk_content_impl_t content_impl = { .destroy = content_destroy, .create_scene_node = content_create_scene_node, + .request_close = content_request_close, .request_size = content_request_size, .set_activated = content_set_activated, }; @@ -220,6 +223,22 @@ struct wlr_scene_node *content_create_scene_node( return &surface_wlr_scene_tree_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** + * Requests the content to close: Sends a 'close' message to the toplevel. + * + * @param content_ptr + */ +void content_request_close(wlmtk_content_t *content_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + + wlr_xdg_toplevel_send_close( + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel); +} + + /* ------------------------------------------------------------------------- */ /** * Sets the dimensions of the element in pixels. From b5019b2f3d4b315387d71bb88ff62157d9e5b51d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 16:49:27 +0100 Subject: [PATCH 232/390] Adds boilerplate code for wlmtk_window_set_title. --- src/toolkit/window.c | 58 ++++++++++++++++++++++++++++++++++++++++ src/toolkit/window.h | 14 ++++++++++ src/wlmtk_xdg_toplevel.c | 34 ++++++++++++++++++++++- 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 0bff15a2..f68b1837 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -31,6 +31,9 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr); static void wlmtk_window_set_activated_impl( wlmtk_window_t *window_ptr, bool activated); +static void wlmtk_window_set_title_impl( + wlmtk_window_t *window_ptr, + const char *title_ptr); static void wlmtk_window_set_server_side_decorated_impl( wlmtk_window_t *window_ptr, bool decorated); @@ -55,6 +58,9 @@ static void fake_window_destroy(wlmtk_window_t *window_ptr); static void fake_window_set_activated( wlmtk_window_t *window_ptr, bool activated); +static void fake_window_set_title( + wlmtk_window_t *window_ptr, + const char *title_ptr); static void fake_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); @@ -96,6 +102,7 @@ static const wlmtk_box_impl_t window_box_impl = { static const wlmtk_window_impl_t window_default_impl = { .destroy = wlmtk_window_destroy, .set_activated = wlmtk_window_set_activated_impl, + .set_title = wlmtk_window_set_title_impl, .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, .request_close = wlmtk_window_request_close_impl, .request_minimize = wlmtk_window_request_minimize_impl, @@ -109,6 +116,7 @@ static const wlmtk_window_impl_t window_default_impl = { static const wlmtk_window_impl_t fake_window_impl = { .destroy = fake_window_destroy, .set_activated = fake_window_set_activated, + .set_title = fake_window_set_title, .set_server_side_decorated = fake_window_set_server_side_decorated, .request_close = fake_window_request_close, .request_minimize = fake_window_request_minimize, @@ -165,6 +173,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, BS_ASSERT(NULL != impl_ptr); BS_ASSERT(NULL != impl_ptr->destroy); BS_ASSERT(NULL != impl_ptr->set_activated); + BS_ASSERT(NULL != impl_ptr->set_title); BS_ASSERT(NULL != impl_ptr->set_server_side_decorated); BS_ASSERT(NULL != impl_ptr->request_close); BS_ASSERT(NULL != impl_ptr->request_minimize); @@ -343,6 +352,14 @@ void wlmtk_window_set_activated( window_ptr->impl.set_activated(window_ptr, activated); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_title( + wlmtk_window_t *window_ptr, + const char *title_ptr) +{ + window_ptr->impl.set_title(window_ptr, title_ptr); +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, @@ -433,6 +450,17 @@ void wlmtk_window_set_activated_impl( } } +/* ------------------------------------------------------------------------- */ +/** Sets the window title: Passes it on to the titlebar. */ +void wlmtk_window_set_title_impl( + wlmtk_window_t *window_ptr, + const char *title_ptr) +{ + // FIXME + window_ptr = window_ptr; + title_ptr = title_ptr; +} + /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_set_server_side_decorated. */ void wlmtk_window_set_server_side_decorated_impl( @@ -625,6 +653,17 @@ void fake_window_set_activated( fake_window_ptr->activated = activated; } +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_set_title. */ +void fake_window_set_title( + wlmtk_window_t *window_ptr, + const char *title_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + fake_window_ptr->title_ptr = title_ptr; +} + /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_set_server_side_decorated. */ void fake_window_set_server_side_decorated( @@ -711,12 +750,14 @@ void fake_window_request_position_and_size( /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); +static void test_set_title(bs_test_t *test_ptr); static void test_request_close(bs_test_t *test_ptr); static void test_set_activated(bs_test_t *test_ptr); static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "create_destroy", test_create_destroy }, + { 1, "set_title", test_set_title }, { 1, "request_close", test_request_close }, { 1, "set_activated", test_set_activated }, { 1, "fake", test_fake }, @@ -737,6 +778,23 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests title. */ +void test_set_title(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, NULL, &fake_content_ptr->content); + + wlmtk_window_set_title(window_ptr, "Title"); + // FIXME + test_ptr = test_ptr; + wlmtk_window_set_title(window_ptr, NULL); + // FIXME + + wlmtk_window_destroy(window_ptr); +} + /* ------------------------------------------------------------------------- */ /** Tests activation. */ void test_request_close(bs_test_t *test_ptr) diff --git a/src/toolkit/window.h b/src/toolkit/window.h index d04277c9..b011a7fa 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -67,6 +67,8 @@ typedef struct { /** See @ref wlmtk_window_set_server_side_decorated. */ void (*set_server_side_decorated)(wlmtk_window_t *window_ptr, bool decorated); + /** See @ref wlmtk_window_set_title. */ + void (*set_title)(wlmtk_window_t *window_ptr, const char *title_ptr); /** See @ref wlmtk_window_request_close. */ void (*request_close)(wlmtk_window_t *window_ptr); @@ -178,6 +180,16 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); +/** + * Sets the title for the window. + * + * @param window_ptr + * @param title_ptr May be NULL. + */ +void wlmtk_window_set_title( + wlmtk_window_t *window_ptr, + const char *title_ptr); + /** * Requests to close the window. * @@ -271,6 +283,8 @@ typedef struct { bool activated; /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ bool decorated; + /** Argument to last call of @ref wlmtk_window_set_title. */ + const char *title_ptr; /** Whether @ref wlmtk_window_request_close was called. */ bool request_close_called; /** Whether @ref wlmtk_window_request_minimize was called. */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 3afc26f9..b4c3c465 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -46,6 +46,8 @@ typedef struct { struct wl_listener toplevel_request_move_listener; /** Listener for `request_resize` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_resize_listener; + /** Listener for the `set_title` signal of the `wlr_xdg_toplevel`. */ + struct wl_listener toplevel_set_title_listener; } wlmtk_xdg_toplevel_content_t; static wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( @@ -70,6 +72,9 @@ static void handle_toplevel_request_move( static void handle_toplevel_request_resize( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_set_title( + struct wl_listener *listener_ptr, + void *data_ptr); static void content_destroy(wlmtk_content_t *content_ptr); static struct wlr_scene_node *content_create_scene_node( @@ -161,6 +166,10 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &wlr_xdg_surface_ptr->toplevel->events.request_resize, &xdg_tl_content_ptr->toplevel_request_resize_listener, handle_toplevel_request_resize); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.set_title, + &xdg_tl_content_ptr->toplevel_set_title_listener, + handle_toplevel_set_title); xdg_tl_content_ptr->wlr_xdg_surface_ptr->data = &xdg_tl_content_ptr->super_content; @@ -176,6 +185,8 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( void xdg_toplevel_content_destroy( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) { + wl_list_remove( + &xdg_tl_content_ptr->toplevel_set_title_listener.link); wl_list_remove(&xdg_tl_content_ptr->toplevel_request_resize_listener.link); wl_list_remove(&xdg_tl_content_ptr->toplevel_request_move_listener.link); @@ -394,7 +405,7 @@ void handle_toplevel_request_move( /* ------------------------------------------------------------------------- */ /** - * Handler for the `requestp_resize` signal. + * Handler for the `request_resize` signal. * * @param listener_ptr * @param data_ptr Points to a struct wlr_xdg_toplevel_resize_event. @@ -413,4 +424,25 @@ void handle_toplevel_request_resize( resize_event_ptr->edges); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `set_title` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_set_title( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_content_t, + toplevel_set_title_listener); + + wlmtk_window_set_title( + xdg_tl_content_ptr->super_content.window_ptr, + xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->title); +} + /* == End of xdg_toplevel.c ================================================ */ From e80b141be967007a709add886ad54c759abdf10f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 17:04:15 +0100 Subject: [PATCH 233/390] Passes a window title down to wlmtk_titlebar_t. --- src/toolkit/titlebar.c | 58 +++++++++++++++++++++++++++++++++--------- src/toolkit/titlebar.h | 20 +++++++++++++++ src/toolkit/window.c | 18 ++++++++----- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 0ba67352..f0722c3f 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -41,7 +41,7 @@ struct _wlmtk_titlebar_t { wlmtk_box_t super_box; /** Title element of the title bar. */ - wlmtk_titlebar_title_t *title_ptr; + wlmtk_titlebar_title_t *titlebar_title_ptr; /** Minimize button. */ wlmtk_titlebar_button_t *minimize_button_ptr; @@ -58,6 +58,9 @@ struct _wlmtk_titlebar_t { /** Whether the title bar is currently displayed as activated. */ bool activated; + /** Points to the title of the bar. May be NULL. */ + char *title_ptr; + /** Title bar style. */ wlmtk_titlebar_style_t style; }; @@ -93,14 +96,14 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( return NULL; } - titlebar_ptr->title_ptr = wlmtk_titlebar_title_create(window_ptr); - if (NULL == titlebar_ptr->title_ptr) { + titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create(window_ptr); + if (NULL == titlebar_ptr->titlebar_title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } wlmtk_container_add_element( &titlebar_ptr->super_box.super_container, - wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); + wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( wlmtk_window_request_minimize, @@ -148,12 +151,12 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) titlebar_ptr->minimize_button_ptr = NULL; } - if (NULL != titlebar_ptr->title_ptr) { + if (NULL != titlebar_ptr->titlebar_title_ptr) { wlmtk_container_remove_element( &titlebar_ptr->super_box.super_container, - wlmtk_titlebar_title_element(titlebar_ptr->title_ptr)); - wlmtk_titlebar_title_destroy(titlebar_ptr->title_ptr); - titlebar_ptr->title_ptr = NULL; + wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr)); + wlmtk_titlebar_title_destroy(titlebar_ptr->titlebar_title_ptr); + titlebar_ptr->titlebar_title_ptr = NULL; } if (NULL != titlebar_ptr->blurred_gfxbuf_ptr) { @@ -165,6 +168,11 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) titlebar_ptr->focussed_gfxbuf_ptr = NULL; } + if (NULL != titlebar_ptr->title_ptr) { + free(titlebar_ptr->title_ptr); + titlebar_ptr->title_ptr = NULL; + } + wlmtk_box_fini(&titlebar_ptr->super_box); free(titlebar_ptr); @@ -189,7 +197,7 @@ bool wlmtk_titlebar_set_width( } if (!wlmtk_titlebar_title_redraw( - titlebar_ptr->title_ptr, + titlebar_ptr->titlebar_title_ptr, titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, title_position, @@ -199,7 +207,7 @@ bool wlmtk_titlebar_set_width( return false; } wlmtk_element_set_visible( - wlmtk_titlebar_title_element(titlebar_ptr->title_ptr), true); + wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr), true); if (0 < title_position) { if (!wlmtk_titlebar_button_redraw( @@ -242,6 +250,32 @@ bool wlmtk_titlebar_set_width( return true; } +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_set_title( + wlmtk_titlebar_t *titlebar_ptr, + const char *title_ptr) +{ + if (NULL != titlebar_ptr->title_ptr) { + free(titlebar_ptr->title_ptr); + titlebar_ptr->title_ptr = NULL; + } + + if (NULL != title_ptr) { + titlebar_ptr->title_ptr = logged_strdup(title_ptr); + // That will be an error, but... well. + if (NULL != titlebar_ptr->title_ptr) return; + } + + // FIXME: Redraw. +} + +/* ------------------------------------------------------------------------- */ +const char *wlmtk_titlebar_get_title( + wlmtk_titlebar_t *titlebar_ptr) +{ + return titlebar_ptr->title_ptr; +} + /* ------------------------------------------------------------------------- */ void wlmtk_titlebar_set_activated( wlmtk_titlebar_t *titlebar_ptr, @@ -250,7 +284,7 @@ void wlmtk_titlebar_set_activated( if (titlebar_ptr->activated == activated) return; titlebar_ptr->activated = activated; wlmtk_titlebar_title_set_activated( - titlebar_ptr->title_ptr, titlebar_ptr->activated); + titlebar_ptr->titlebar_title_ptr, titlebar_ptr->activated); } /* ------------------------------------------------------------------------- */ @@ -350,7 +384,7 @@ void test_variable_width(bs_test_t *test_ptr) // Short names, for improved readability. wlmtk_element_t *title_elem_ptr = wlmtk_titlebar_title_element( - titlebar_ptr->title_ptr); + titlebar_ptr->titlebar_title_ptr); wlmtk_element_t *minimize_elem_ptr = wlmtk_titlebar_button_element( titlebar_ptr->minimize_button_ptr); wlmtk_element_t *close_elem_ptr = wlmtk_titlebar_button_element( diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 8b013d42..5b231377 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -80,6 +80,26 @@ bool wlmtk_titlebar_set_width( wlmtk_titlebar_t *titlebar_ptr, unsigned width); +/** + * Sets the title for the titlebar. + * + * @param titlebar_ptr + * @param title_ptr + */ +void wlmtk_titlebar_set_title( + wlmtk_titlebar_t *titlebar_ptr, + const char *title_ptr); + +/** + * Returns the title of of the titlebar. + * + * @param titlebar_ptr + * + * @return Pointer to the title. + */ +const char *wlmtk_titlebar_get_title( + wlmtk_titlebar_t *titlebar_ptr); + /** * Sets whether the title bar is activated. * diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f68b1837..cc1a502b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -456,9 +456,9 @@ void wlmtk_window_set_title_impl( wlmtk_window_t *window_ptr, const char *title_ptr) { - // FIXME - window_ptr = window_ptr; - title_ptr = title_ptr; + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, title_ptr); + } } /* ------------------------------------------------------------------------- */ @@ -787,10 +787,16 @@ void test_set_title(bs_test_t *test_ptr) NULL, NULL, &fake_content_ptr->content); wlmtk_window_set_title(window_ptr, "Title"); - // FIXME - test_ptr = test_ptr; + BS_TEST_VERIFY_STREQ( + test_ptr, + "Title", + wlmtk_titlebar_get_title(window_ptr->titlebar_ptr)); + wlmtk_window_set_title(window_ptr, NULL); - // FIXME + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + wlmtk_titlebar_get_title(window_ptr->titlebar_ptr)); wlmtk_window_destroy(window_ptr); } From e2a29af0779939ad2d193dfaf4cb0dd6cebe6228 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 17:08:58 +0100 Subject: [PATCH 234/390] Passes the title down to the titlebar title element, and uses it for drawing. --- src/toolkit/titlebar.c | 1 + src/toolkit/titlebar_title.c | 18 +++++++++++++----- src/toolkit/titlebar_title.h | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index f0722c3f..63d8a838 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -203,6 +203,7 @@ bool wlmtk_titlebar_set_width( title_position, close_position - title_position, titlebar_ptr->activated, + titlebar_ptr->title_ptr, &titlebar_ptr->style)) { return false; } diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index 6478c702..b384b94d 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -56,6 +56,7 @@ struct wlr_buffer *title_create_buffer( unsigned position, unsigned width, uint32_t text_color, + const char *title_ptr, const wlmtk_titlebar_style_t *style_ptr); /* == Data ================================================================= */ @@ -104,6 +105,7 @@ bool wlmtk_titlebar_title_redraw( int position, int width, bool activated, + const char *title_ptr, const wlmtk_titlebar_style_t *style_ptr) { BS_ASSERT(focussed_gfxbuf_ptr->width == blurred_gfxbuf_ptr->width); @@ -112,12 +114,14 @@ bool wlmtk_titlebar_title_redraw( BS_ASSERT(position <= (int)focussed_gfxbuf_ptr->width); BS_ASSERT(position + width <= (int)focussed_gfxbuf_ptr->width); + if (NULL == title_ptr) title_ptr = ""; + struct wlr_buffer *focussed_wlr_buffer_ptr = title_create_buffer( focussed_gfxbuf_ptr, position, width, - style_ptr->focussed_text_color, style_ptr); + style_ptr->focussed_text_color, title_ptr, style_ptr); struct wlr_buffer *blurred_wlr_buffer_ptr = title_create_buffer( blurred_gfxbuf_ptr, position, width, - style_ptr->blurred_text_color, style_ptr); + style_ptr->blurred_text_color, title_ptr, style_ptr); if (NULL == focussed_wlr_buffer_ptr || NULL == blurred_wlr_buffer_ptr) { @@ -211,6 +215,7 @@ void title_set_activated( * @param position * @param width * @param text_color + * @param title_ptr * @param style_ptr * * @return A pointer to a `struct wlr_buffer` with the texture. @@ -220,8 +225,10 @@ struct wlr_buffer *title_create_buffer( unsigned position, unsigned width, uint32_t text_color, + const char *title_ptr, const wlmtk_titlebar_style_t *style_ptr) { + BS_ASSERT(NULL != title_ptr); struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( width, style_ptr->height); if (NULL == wlr_buffer_ptr) return NULL; @@ -241,7 +248,7 @@ struct wlr_buffer *title_create_buffer( wlmaker_primitives_draw_bezel_at( cairo_ptr, 0, 0, width, style_ptr->height, 1.0, true); wlmaker_primitives_draw_window_title( - cairo_ptr, "Title", text_color); + cairo_ptr, title_ptr, text_color); cairo_destroy(cairo_ptr); return wlr_buffer_ptr; @@ -280,7 +287,8 @@ void test_title(bs_test_t *test_ptr) test_ptr, wlmtk_titlebar_title_redraw( titlebar_title_ptr, - focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, 10, 90, true, &style)); + focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, + 10, 90, true, "Title", &style)); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, @@ -308,7 +316,7 @@ void test_title(bs_test_t *test_ptr) // Redraw with shorter width. Verify that's still correct. wlmtk_titlebar_title_redraw( titlebar_title_ptr, focussed_gfxbuf_ptr, blurred_gfxbuf_ptr, - 10, 70, false, &style); + 10, 70, false, "Title", &style); BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( test_ptr, bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h index 0e994114..2901746c 100644 --- a/src/toolkit/titlebar_title.h +++ b/src/toolkit/titlebar_title.h @@ -59,6 +59,7 @@ void wlmtk_titlebar_title_destroy( * @param position Position of title telative to titlebar. * @param width Width of title. * @param activated Whether the title bar should start focussed. + * @param title_ptr Title, or NULL. * @param style_ptr * * @return true on success. @@ -70,6 +71,7 @@ bool wlmtk_titlebar_title_redraw( int position, int width, bool activated, + const char *title_ptr, const wlmtk_titlebar_style_t *style_ptr); /** From e6b62b4a4ee3a81b8eb295d6cb08a6c96d9ab690 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 17:19:08 +0100 Subject: [PATCH 235/390] Triggers a redraw when setting the titlebar title. --- src/toolkit/titlebar.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 63d8a838..a3f235af 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -55,6 +55,8 @@ struct _wlmtk_titlebar_t { /** Current width of the title bar. */ unsigned width; + int close_position; + int title_position; /** Whether the title bar is currently displayed as activated. */ bool activated; @@ -187,21 +189,21 @@ bool wlmtk_titlebar_set_width( if (!redraw_buffers(titlebar_ptr, width)) return false; BS_ASSERT(width == titlebar_ptr->width); - int close_position = width; + titlebar_ptr->close_position = width; if (3 * titlebar_ptr->style.height < width) { - close_position = width - titlebar_ptr->style.height; + titlebar_ptr->close_position = width - titlebar_ptr->style.height; } - int title_position = 0; + titlebar_ptr->title_position = 0; if (4 * titlebar_ptr->style.height < width) { - title_position = titlebar_ptr->style.height; + titlebar_ptr->title_position = titlebar_ptr->style.height; } if (!wlmtk_titlebar_title_redraw( titlebar_ptr->titlebar_title_ptr, titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, - title_position, - close_position - title_position, + titlebar_ptr->title_position, + titlebar_ptr->close_position - titlebar_ptr->title_position, titlebar_ptr->activated, titlebar_ptr->title_ptr, &titlebar_ptr->style)) { @@ -210,7 +212,7 @@ bool wlmtk_titlebar_set_width( wlmtk_element_set_visible( wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr), true); - if (0 < title_position) { + if (0 < titlebar_ptr->title_position) { if (!wlmtk_titlebar_button_redraw( titlebar_ptr->minimize_button_ptr, titlebar_ptr->focussed_gfxbuf_ptr, @@ -228,12 +230,12 @@ bool wlmtk_titlebar_set_width( false); } - if (close_position < (int)width) { + if (titlebar_ptr->close_position < (int)width) { if (!wlmtk_titlebar_button_redraw( titlebar_ptr->close_button_ptr, titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, - close_position, + titlebar_ptr->close_position, &titlebar_ptr->style)) { return false; } @@ -267,7 +269,17 @@ void wlmtk_titlebar_set_title( if (NULL != titlebar_ptr->title_ptr) return; } - // FIXME: Redraw. + if (0 < titlebar_ptr->width) { + wlmtk_titlebar_title_redraw( + titlebar_ptr->titlebar_title_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + titlebar_ptr->title_position, + titlebar_ptr->close_position - titlebar_ptr->title_position, + titlebar_ptr->activated, + titlebar_ptr->title_ptr, + &titlebar_ptr->style); + } } /* ------------------------------------------------------------------------- */ From e37a6f08779f3953d3adf4ab3dbb872bb50fda3c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 18 Nov 2023 17:26:11 +0100 Subject: [PATCH 236/390] Fixes missing doxygen comments. --- src/toolkit/titlebar.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index a3f235af..89354868 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -55,7 +55,9 @@ struct _wlmtk_titlebar_t { /** Current width of the title bar. */ unsigned width; + /** Position of the close button. */ int close_position; + /** Position of the title element. */ int title_position; /** Whether the title bar is currently displayed as activated. */ bool activated; From d45e1e26c67449351d95e118a65cfb33bc96abf3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 19 Nov 2023 20:31:17 +0100 Subject: [PATCH 237/390] Moves the storage of window title to wlmtk_window_t and uses generated names if not set. --- src/toolkit/titlebar.c | 90 +++++++++++++++--------------------------- src/toolkit/titlebar.h | 27 +++++-------- src/toolkit/window.c | 76 ++++++++++++++++++----------------- src/toolkit/window.h | 18 ++++++++- 4 files changed, 96 insertions(+), 115 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 89354868..155e1291 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -39,6 +39,8 @@ struct _wlmtk_titlebar_t { /** Superclass: Box. */ wlmtk_box_t super_box; + /** Back-link to the window the title bar is for. */ + wlmtk_window_t *window_ptr; /** Title element of the title bar. */ wlmtk_titlebar_title_t *titlebar_title_ptr; @@ -62,9 +64,6 @@ struct _wlmtk_titlebar_t { /** Whether the title bar is currently displayed as activated. */ bool activated; - /** Points to the title of the bar. May be NULL. */ - char *title_ptr; - /** Title bar style. */ wlmtk_titlebar_style_t style; }; @@ -92,6 +91,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( 1, sizeof(wlmtk_titlebar_t)); if (NULL == titlebar_ptr) return NULL; memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); + titlebar_ptr->window_ptr = window_ptr; if (!wlmtk_box_init(&titlebar_ptr->super_box, &titlebar_box_impl, @@ -172,11 +172,6 @@ void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) titlebar_ptr->focussed_gfxbuf_ptr = NULL; } - if (NULL != titlebar_ptr->title_ptr) { - free(titlebar_ptr->title_ptr); - titlebar_ptr->title_ptr = NULL; - } - wlmtk_box_fini(&titlebar_ptr->super_box); free(titlebar_ptr); @@ -200,6 +195,32 @@ bool wlmtk_titlebar_set_width( titlebar_ptr->title_position = titlebar_ptr->style.height; } + if (!wlmtk_titlebar_redraw(titlebar_ptr)) { + return false; + } + + // Don't forget to re-position the elements. + wlmtk_container_update_layout(&titlebar_ptr->super_box.super_container); + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_set_activated( + wlmtk_titlebar_t *titlebar_ptr, + bool activated) +{ + if (titlebar_ptr->activated == activated) return; + titlebar_ptr->activated = activated; + wlmtk_titlebar_title_set_activated( + titlebar_ptr->titlebar_title_ptr, titlebar_ptr->activated); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_titlebar_redraw(wlmtk_titlebar_t *titlebar_ptr) +{ + // Guard clause: Nothing to do... yet. + if (0 >= titlebar_ptr->width) return true; + if (!wlmtk_titlebar_title_redraw( titlebar_ptr->titlebar_title_ptr, titlebar_ptr->focussed_gfxbuf_ptr, @@ -207,7 +228,7 @@ bool wlmtk_titlebar_set_width( titlebar_ptr->title_position, titlebar_ptr->close_position - titlebar_ptr->title_position, titlebar_ptr->activated, - titlebar_ptr->title_ptr, + wlmtk_window_get_title(titlebar_ptr->window_ptr), &titlebar_ptr->style)) { return false; } @@ -232,7 +253,7 @@ bool wlmtk_titlebar_set_width( false); } - if (titlebar_ptr->close_position < (int)width) { + if (titlebar_ptr->close_position < (int)titlebar_ptr->width) { if (!wlmtk_titlebar_button_redraw( titlebar_ptr->close_button_ptr, titlebar_ptr->focussed_gfxbuf_ptr, @@ -250,58 +271,9 @@ bool wlmtk_titlebar_set_width( false); } - // Don't forget to re-position the elements. - wlmtk_container_update_layout(&titlebar_ptr->super_box.super_container); return true; } -/* ------------------------------------------------------------------------- */ -void wlmtk_titlebar_set_title( - wlmtk_titlebar_t *titlebar_ptr, - const char *title_ptr) -{ - if (NULL != titlebar_ptr->title_ptr) { - free(titlebar_ptr->title_ptr); - titlebar_ptr->title_ptr = NULL; - } - - if (NULL != title_ptr) { - titlebar_ptr->title_ptr = logged_strdup(title_ptr); - // That will be an error, but... well. - if (NULL != titlebar_ptr->title_ptr) return; - } - - if (0 < titlebar_ptr->width) { - wlmtk_titlebar_title_redraw( - titlebar_ptr->titlebar_title_ptr, - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - titlebar_ptr->title_position, - titlebar_ptr->close_position - titlebar_ptr->title_position, - titlebar_ptr->activated, - titlebar_ptr->title_ptr, - &titlebar_ptr->style); - } -} - -/* ------------------------------------------------------------------------- */ -const char *wlmtk_titlebar_get_title( - wlmtk_titlebar_t *titlebar_ptr) -{ - return titlebar_ptr->title_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_titlebar_set_activated( - wlmtk_titlebar_t *titlebar_ptr, - bool activated) -{ - if (titlebar_ptr->activated == activated) return; - titlebar_ptr->activated = activated; - wlmtk_titlebar_title_set_activated( - titlebar_ptr->titlebar_title_ptr, titlebar_ptr->activated); -} - /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_titlebar_element(wlmtk_titlebar_t *titlebar_ptr) { diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 5b231377..b73487cf 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -81,34 +81,25 @@ bool wlmtk_titlebar_set_width( unsigned width); /** - * Sets the title for the titlebar. + * Sets whether the title bar is activated. * * @param titlebar_ptr - * @param title_ptr + * @param activated */ -void wlmtk_titlebar_set_title( +void wlmtk_titlebar_set_activated( wlmtk_titlebar_t *titlebar_ptr, - const char *title_ptr); + bool activated); /** - * Returns the title of of the titlebar. + * Redraws the title bar. * - * @param titlebar_ptr - * - * @return Pointer to the title. - */ -const char *wlmtk_titlebar_get_title( - wlmtk_titlebar_t *titlebar_ptr); - -/** - * Sets whether the title bar is activated. + * Should be triggered eg. by the parent window when the title changed. * * @param titlebar_ptr - * @param activated + * + * @return Whether redrawing succeeded. */ -void wlmtk_titlebar_set_activated( - wlmtk_titlebar_t *titlebar_ptr, - bool activated); +bool wlmtk_titlebar_redraw(wlmtk_titlebar_t *titlebar_ptr); /** * Returns the super Element of the titlebar. diff --git a/src/toolkit/window.c b/src/toolkit/window.c index cc1a502b..b0347bd3 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -31,9 +31,6 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr); static void wlmtk_window_set_activated_impl( wlmtk_window_t *window_ptr, bool activated); -static void wlmtk_window_set_title_impl( - wlmtk_window_t *window_ptr, - const char *title_ptr); static void wlmtk_window_set_server_side_decorated_impl( wlmtk_window_t *window_ptr, bool decorated); @@ -58,9 +55,6 @@ static void fake_window_destroy(wlmtk_window_t *window_ptr); static void fake_window_set_activated( wlmtk_window_t *window_ptr, bool activated); -static void fake_window_set_title( - wlmtk_window_t *window_ptr, - const char *title_ptr); static void fake_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated); @@ -102,7 +96,6 @@ static const wlmtk_box_impl_t window_box_impl = { static const wlmtk_window_impl_t window_default_impl = { .destroy = wlmtk_window_destroy, .set_activated = wlmtk_window_set_activated_impl, - .set_title = wlmtk_window_set_title_impl, .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, .request_close = wlmtk_window_request_close_impl, .request_minimize = wlmtk_window_request_minimize_impl, @@ -116,7 +109,6 @@ static const wlmtk_window_impl_t window_default_impl = { static const wlmtk_window_impl_t fake_window_impl = { .destroy = fake_window_destroy, .set_activated = fake_window_set_activated, - .set_title = fake_window_set_title, .set_server_side_decorated = fake_window_set_server_side_decorated, .request_close = fake_window_request_close, .request_minimize = fake_window_request_minimize, @@ -173,7 +165,6 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, BS_ASSERT(NULL != impl_ptr); BS_ASSERT(NULL != impl_ptr->destroy); BS_ASSERT(NULL != impl_ptr->set_activated); - BS_ASSERT(NULL != impl_ptr->set_title); BS_ASSERT(NULL != impl_ptr->set_server_side_decorated); BS_ASSERT(NULL != impl_ptr->request_close); BS_ASSERT(NULL != impl_ptr->request_minimize); @@ -219,6 +210,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + wlmtk_window_set_title(window_ptr, NULL); return true; } @@ -246,6 +238,11 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) window_ptr->resizebar_ptr = NULL; } + if (NULL != window_ptr->title_ptr) { + free(window_ptr->title_ptr); + window_ptr->title_ptr = NULL; + } + wlmtk_box_fini(&window_ptr->super_box); } @@ -357,7 +354,36 @@ void wlmtk_window_set_title( wlmtk_window_t *window_ptr, const char *title_ptr) { - window_ptr->impl.set_title(window_ptr, title_ptr); + char *new_title_ptr = NULL; + if (NULL != title_ptr) { + new_title_ptr = logged_strdup(title_ptr); + BS_ASSERT(NULL != new_title_ptr); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), "Unnamed window %p", window_ptr); + new_title_ptr = logged_strdup(buf); + BS_ASSERT(NULL != new_title_ptr); + } + + if (NULL != window_ptr->title_ptr) { + if (0 == strcmp(window_ptr->title_ptr, new_title_ptr)) { + free(new_title_ptr); + return; + } + free(window_ptr->title_ptr); + } + window_ptr->title_ptr = new_title_ptr; + + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_redraw(window_ptr->titlebar_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(NULL != window_ptr->title_ptr); + return window_ptr->title_ptr; } /* ------------------------------------------------------------------------- */ @@ -450,17 +476,6 @@ void wlmtk_window_set_activated_impl( } } -/* ------------------------------------------------------------------------- */ -/** Sets the window title: Passes it on to the titlebar. */ -void wlmtk_window_set_title_impl( - wlmtk_window_t *window_ptr, - const char *title_ptr) -{ - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, title_ptr); - } -} - /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_set_server_side_decorated. */ void wlmtk_window_set_server_side_decorated_impl( @@ -653,17 +668,6 @@ void fake_window_set_activated( fake_window_ptr->activated = activated; } -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_set_title. */ -void fake_window_set_title( - wlmtk_window_t *window_ptr, - const char *title_ptr) -{ - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->title_ptr = title_ptr; -} - /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_set_server_side_decorated. */ void fake_window_set_server_side_decorated( @@ -790,13 +794,13 @@ void test_set_title(bs_test_t *test_ptr) BS_TEST_VERIFY_STREQ( test_ptr, "Title", - wlmtk_titlebar_get_title(window_ptr->titlebar_ptr)); + wlmtk_window_get_title(window_ptr)); wlmtk_window_set_title(window_ptr, NULL); - BS_TEST_VERIFY_EQ( + BS_TEST_VERIFY_STRMATCH( test_ptr, - NULL, - wlmtk_titlebar_get_title(window_ptr->titlebar_ptr)); + wlmtk_window_get_title(window_ptr), + "Unnamed window .*"); wlmtk_window_destroy(window_ptr); } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index b011a7fa..b3e28ee6 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -102,6 +102,9 @@ struct _wlmtk_window_t { /** Resizebar. */ wlmtk_resizebar_t *resizebar_ptr; + /** Window title. */ + char *title_ptr; + /** Pending updates. */ bs_dllist_t pending_updates; /** List of udpates currently available. */ @@ -183,6 +186,8 @@ void wlmtk_window_set_server_side_decorated( /** * Sets the title for the window. * + * If `title_ptr` is NULL, a generic name is set. + * * @param window_ptr * @param title_ptr May be NULL. */ @@ -190,6 +195,17 @@ void wlmtk_window_set_title( wlmtk_window_t *window_ptr, const char *title_ptr); +/** + * Returns the title of the window. + * + * @param window_ptr + * + * @returns Pointer to the window title. Will remain valid until the next call + * to @ref wlmtk_window_set_title, or until the window is destroyed. Will + * never be NULL. + */ +const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr); + /** * Requests to close the window. * @@ -283,8 +299,6 @@ typedef struct { bool activated; /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ bool decorated; - /** Argument to last call of @ref wlmtk_window_set_title. */ - const char *title_ptr; /** Whether @ref wlmtk_window_request_close was called. */ bool request_close_called; /** Whether @ref wlmtk_window_request_minimize was called. */ From 3c01f91286f3c79207bc4699cf034ca49e5b63bd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 19 Nov 2023 20:32:47 +0100 Subject: [PATCH 238/390] Moves title initialization before decoration. --- src/toolkit/window.c | 2 +- src/toolkit/window.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index b0347bd3..0d09acbd 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -185,6 +185,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_fini(window_ptr); return false; } + wlmtk_window_set_title(window_ptr, NULL); window_ptr->resizebar_ptr = wlmtk_resizebar_create( window_ptr, &resizebar_style); @@ -210,7 +211,6 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - wlmtk_window_set_title(window_ptr, NULL); return true; } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index b3e28ee6..b870fdb1 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -102,7 +102,7 @@ struct _wlmtk_window_t { /** Resizebar. */ wlmtk_resizebar_t *resizebar_ptr; - /** Window title. */ + /** Window title. Set through @ref wlmtk_window_set_title. */ char *title_ptr; /** Pending updates. */ From 3d5d2427139ba2a9e9add8d6870dc1a4172ab742 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 19 Nov 2023 20:52:25 +0100 Subject: [PATCH 239/390] Changes titlebar API, to set title rather than request redraw: Moves state tracking into the titlebar. --- src/toolkit/titlebar.c | 128 ++++++++++++++++++++++------------------- src/toolkit/titlebar.h | 13 +++-- src/toolkit/window.c | 3 +- 3 files changed, 79 insertions(+), 65 deletions(-) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 155e1291..82566a38 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -39,8 +39,8 @@ struct _wlmtk_titlebar_t { /** Superclass: Box. */ wlmtk_box_t super_box; - /** Back-link to the window the title bar is for. */ - wlmtk_window_t *window_ptr; + /** Link to the titlebar's title. */ + const char *title_ptr; /** Title element of the title bar. */ wlmtk_titlebar_title_t *titlebar_title_ptr; @@ -72,6 +72,7 @@ static void titlebar_box_destroy(wlmtk_box_t *box_ptr); static bool redraw_buffers( wlmtk_titlebar_t *titlebar_ptr, unsigned width); +static bool redraw(wlmtk_titlebar_t *titlebar_ptr); /* == Data ================================================================= */ @@ -91,7 +92,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( 1, sizeof(wlmtk_titlebar_t)); if (NULL == titlebar_ptr) return NULL; memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); - titlebar_ptr->window_ptr = window_ptr; + titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); if (!wlmtk_box_init(&titlebar_ptr->super_box, &titlebar_box_impl, @@ -195,7 +196,7 @@ bool wlmtk_titlebar_set_width( titlebar_ptr->title_position = titlebar_ptr->style.height; } - if (!wlmtk_titlebar_redraw(titlebar_ptr)) { + if (!redraw(titlebar_ptr)) { return false; } @@ -216,62 +217,14 @@ void wlmtk_titlebar_set_activated( } /* ------------------------------------------------------------------------- */ -bool wlmtk_titlebar_redraw(wlmtk_titlebar_t *titlebar_ptr) +void wlmtk_titlebar_set_title( + wlmtk_titlebar_t *titlebar_ptr, + const char *title_ptr) { - // Guard clause: Nothing to do... yet. - if (0 >= titlebar_ptr->width) return true; - - if (!wlmtk_titlebar_title_redraw( - titlebar_ptr->titlebar_title_ptr, - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - titlebar_ptr->title_position, - titlebar_ptr->close_position - titlebar_ptr->title_position, - titlebar_ptr->activated, - wlmtk_window_get_title(titlebar_ptr->window_ptr), - &titlebar_ptr->style)) { - return false; - } - wlmtk_element_set_visible( - wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr), true); + if (titlebar_ptr->title_ptr == title_ptr) return; - if (0 < titlebar_ptr->title_position) { - if (!wlmtk_titlebar_button_redraw( - titlebar_ptr->minimize_button_ptr, - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - 0, - &titlebar_ptr->style)) { - return false; - } - wlmtk_element_set_visible( - wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), - true); - } else { - wlmtk_element_set_visible( - wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), - false); - } - - if (titlebar_ptr->close_position < (int)titlebar_ptr->width) { - if (!wlmtk_titlebar_button_redraw( - titlebar_ptr->close_button_ptr, - titlebar_ptr->focussed_gfxbuf_ptr, - titlebar_ptr->blurred_gfxbuf_ptr, - titlebar_ptr->close_position, - &titlebar_ptr->style)) { - return false; - } - wlmtk_element_set_visible( - wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), - true); - } else { - wlmtk_element_set_visible( - wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), - false); - } - - return true; + titlebar_ptr->title_ptr = title_ptr; + redraw(titlebar_ptr); } /* ------------------------------------------------------------------------- */ @@ -334,6 +287,65 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) return true; } +/* ------------------------------------------------------------------------- */ +bool redraw(wlmtk_titlebar_t *titlebar_ptr) +{ + // Guard clause: Nothing to do... yet. + if (0 >= titlebar_ptr->width) return true; + + if (!wlmtk_titlebar_title_redraw( + titlebar_ptr->titlebar_title_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + titlebar_ptr->title_position, + titlebar_ptr->close_position - titlebar_ptr->title_position, + titlebar_ptr->activated, + titlebar_ptr->title_ptr, + &titlebar_ptr->style)) { + return false; + } + wlmtk_element_set_visible( + wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr), true); + + if (0 < titlebar_ptr->title_position) { + if (!wlmtk_titlebar_button_redraw( + titlebar_ptr->minimize_button_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + 0, + &titlebar_ptr->style)) { + return false; + } + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), + true); + } else { + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr), + false); + } + + if (titlebar_ptr->close_position < (int)titlebar_ptr->width) { + if (!wlmtk_titlebar_button_redraw( + titlebar_ptr->close_button_ptr, + titlebar_ptr->focussed_gfxbuf_ptr, + titlebar_ptr->blurred_gfxbuf_ptr, + titlebar_ptr->close_position, + &titlebar_ptr->style)) { + return false; + } + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), + true); + } else { + wlmtk_element_set_visible( + wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr), + false); + } + + return true; +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index b73487cf..42b733ac 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -91,15 +91,16 @@ void wlmtk_titlebar_set_activated( bool activated); /** - * Redraws the title bar. - * - * Should be triggered eg. by the parent window when the title changed. + * Updates the title text of the titlebar. * * @param titlebar_ptr - * - * @return Whether redrawing succeeded. + * @param title_ptr Expected to remain valid until the next call of + * @ref wlmtk_titlebar_set_title or until the + * `titlebar_ptr` is destroyed. */ -bool wlmtk_titlebar_redraw(wlmtk_titlebar_t *titlebar_ptr); +void wlmtk_titlebar_set_title( + wlmtk_titlebar_t *titlebar_ptr, + const char *title_ptr); /** * Returns the super Element of the titlebar. diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 0d09acbd..55970715 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -375,7 +375,8 @@ void wlmtk_window_set_title( window_ptr->title_ptr = new_title_ptr; if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_redraw(window_ptr->titlebar_ptr); + wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, + window_ptr->title_ptr); } } From 30f6b4f55e4d5681b7d6580dfdb12d446f7d2fd0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 19 Nov 2023 21:08:37 +0100 Subject: [PATCH 240/390] Adds activation call to titlebar button, and wires it up. Includes tests. --- src/toolkit/titlebar.c | 5 +++ src/toolkit/titlebar_button.c | 51 +++++++++++++++++++--- src/toolkit/titlebar_button.h | 10 +++++ testdata/toolkit/title_button_blurred.png | Bin 0 -> 348 bytes 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 testdata/toolkit/title_button_blurred.png diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 82566a38..160caaeb 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -212,8 +212,12 @@ void wlmtk_titlebar_set_activated( { if (titlebar_ptr->activated == activated) return; titlebar_ptr->activated = activated; + wlmtk_titlebar_button_set_activated( + titlebar_ptr->minimize_button_ptr, titlebar_ptr->activated); wlmtk_titlebar_title_set_activated( titlebar_ptr->titlebar_title_ptr, titlebar_ptr->activated); + wlmtk_titlebar_button_set_activated( + titlebar_ptr->close_button_ptr, titlebar_ptr->activated); } /* ------------------------------------------------------------------------- */ @@ -288,6 +292,7 @@ bool redraw_buffers(wlmtk_titlebar_t *titlebar_ptr, unsigned width) } /* ------------------------------------------------------------------------- */ +/** Redraws the titlebar elements. */ bool redraw(wlmtk_titlebar_t *titlebar_ptr) { // Guard clause: Nothing to do... yet. diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 08806fcc..dca7bc02 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -34,6 +34,8 @@ struct _wlmtk_titlebar_button_t { /** Superclass: Button. */ wlmtk_button_t super_button; + /** Whether the titlebar button is activated (focussed). */ + bool activated; /** Callback for when the button is clicked. */ void (*click_handler)(wlmtk_window_t *window_ptr); @@ -52,6 +54,7 @@ struct _wlmtk_titlebar_button_t { static void titlebar_button_destroy(wlmtk_button_t *button_ptr); static void titlebar_button_clicked(wlmtk_button_t *button_ptr); +static void update_buffers(wlmtk_titlebar_button_t *titlebar_button_ptr); static struct wlr_buffer *create_buf( bs_gfxbuf_t *gfxbuf_ptr, int position, @@ -110,6 +113,16 @@ void wlmtk_titlebar_button_destroy( free(titlebar_button_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_titlebar_button_set_activated( + wlmtk_titlebar_button_t *titlebar_button_ptr, + bool activated) +{ + if (titlebar_button_ptr->activated == activated) return; + titlebar_button_ptr->activated = activated; + update_buffers(titlebar_button_ptr); +} + /* ------------------------------------------------------------------------- */ bool wlmtk_titlebar_button_redraw( wlmtk_titlebar_button_t *titlebar_button_ptr, @@ -149,12 +162,7 @@ bool wlmtk_titlebar_button_redraw( focussed_pressed_ptr; titlebar_button_ptr->blurred_wlr_buffer_ptr = blurred_ptr; - // FIXME: Depend on focus/blur. - wlmtk_button_set( - &titlebar_button_ptr->super_button, - titlebar_button_ptr->focussed_released_wlr_buffer_ptr, - titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); - + update_buffers(titlebar_button_ptr); return true; } @@ -191,6 +199,28 @@ void titlebar_button_clicked(wlmtk_button_t *button_ptr) titlebar_button_ptr->click_handler(titlebar_button_ptr->window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Updates the button's buffer depending on activation status. */ +void update_buffers(wlmtk_titlebar_button_t *titlebar_button_ptr) +{ + // No buffer: Nothing to update. + if (NULL == titlebar_button_ptr->focussed_released_wlr_buffer_ptr || + NULL == titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr || + NULL == titlebar_button_ptr->blurred_wlr_buffer_ptr) return; + + if (titlebar_button_ptr->activated) { + wlmtk_button_set( + &titlebar_button_ptr->super_button, + titlebar_button_ptr->focussed_released_wlr_buffer_ptr, + titlebar_button_ptr->focussed_pressed_wlr_buffer_ptr); + } else { + wlmtk_button_set( + &titlebar_button_ptr->super_button, + titlebar_button_ptr->blurred_wlr_buffer_ptr, + titlebar_button_ptr->blurred_wlr_buffer_ptr); + } +} + /* ------------------------------------------------------------------------- */ /** Helper: Creates a WLR buffer for the button. */ struct wlr_buffer *create_buf( @@ -240,6 +270,7 @@ void test_button(bs_test_t *test_ptr) &fake_window_ptr->window, wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); + wlmtk_titlebar_button_set_activated(button_ptr, true); // For improved readability. wlmtk_buffer_t *super_buffer_ptr = &button_ptr->super_button.super_buffer; @@ -291,6 +322,7 @@ void test_button(bs_test_t *test_ptr) bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), "toolkit/title_button_focussed_released.png"); + // Click: To be passed along, no change to visual. BS_TEST_VERIFY_FALSE( test_ptr, fake_window_ptr->request_close_called); @@ -306,6 +338,13 @@ void test_button(bs_test_t *test_ptr) test_ptr, fake_window_ptr->request_close_called); + // De-activate: Show as blurred. + wlmtk_titlebar_button_set_activated(button_ptr, false); + BS_TEST_VERIFY_GFXBUF_EQUALS_PNG( + test_ptr, + bs_gfxbuf_from_wlr_buffer(super_buffer_ptr->wlr_buffer_ptr), + "toolkit/title_button_blurred.png"); + wlmtk_element_destroy(element_ptr); wlmtk_fake_window_destroy(fake_window_ptr); } diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index 908742e6..e4596dd7 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -58,6 +58,16 @@ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( void wlmtk_titlebar_button_destroy( wlmtk_titlebar_button_t *titlebar_button_ptr); +/** + * Sets the activation status (focussed / blurred) of the titlebar button. + * + * @param titlebar_button_ptr + * @param activated + */ +void wlmtk_titlebar_button_set_activated( + wlmtk_titlebar_button_t *titlebar_button_ptr, + bool activated); + /** * Redraws the titlebar button for given textures, position and style. * diff --git a/testdata/toolkit/title_button_blurred.png b/testdata/toolkit/title_button_blurred.png new file mode 100644 index 0000000000000000000000000000000000000000..8376b597ea0f91516e98b394ecdf1cef21b42a0a GIT binary patch literal 348 zcmV-i0i*tjP)NI7wVF(!lvA$AG?2q6d|7~^{v*4nzRopXeczVC~o$n!kRuj|^jt+h59 zNsrWdo*83djB}0#; literal 0 HcmV?d00001 From 211176eaf31955c65f775962a1696689f2397b37 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 22 Nov 2023 22:18:01 +0100 Subject: [PATCH 241/390] Adds basic window activation and de-activation, including tests. --- src/toolkit/content.c | 55 +++++++++++++++++++- src/toolkit/content.h | 7 ++- src/toolkit/window.c | 70 ++++++++++++++++--------- src/toolkit/window.h | 13 +++++ src/toolkit/workspace.c | 111 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 225 insertions(+), 31 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index d9c95bdf..8a24a8be 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -243,8 +243,8 @@ void element_get_pointer_area( // DEBT: Should only get initialized with a valid surface. box.x = 0; box.y = 0; - box.width = 0; - box.height = 0; + box.width = content_ptr->committed_width; + box.height = content_ptr->committed_height; } else { wlr_surface_get_extends(content_ptr->wlr_surface_ptr, &box); } @@ -399,6 +399,17 @@ static void fake_content_set_activated( wlmtk_content_t *content_ptr, bool activated); +// Debt: Should separate content abstract implementation from surface. +static void fake_content_element_pointer_leave(wlmtk_element_t *element_ptr); +static bool fake_content_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec); +static bool fake_content_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); + /** Method table of the fake content. */ static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .destroy = fake_content_destroy, @@ -424,6 +435,14 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) BS_ASSERT(NULL != fake_content_ptr->content.super_element.impl.destroy); BS_ASSERT(NULL != fake_content_ptr->content.impl.destroy); + + fake_content_ptr->content.super_element.impl.pointer_leave = + fake_content_element_pointer_leave; + fake_content_ptr->content.super_element.impl.pointer_motion = + fake_content_element_pointer_motion; + fake_content_ptr->content.super_element.impl.pointer_button = + fake_content_element_pointer_button; + return fake_content_ptr; } @@ -487,6 +506,38 @@ void fake_content_set_activated( fake_content_ptr->activated = activated; } +/* ------------------------------------------------------------------------- */ +/** Does nothing. */ +void fake_content_element_pointer_leave( + __UNUSED__ wlmtk_element_t *element_ptr) +{ + // Nothing to do. +} + +/* ------------------------------------------------------------------------- */ +/** Returns (x, y) in [(0, committed_with), (0, committed_height)). */ +bool fake_content_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + __UNUSED__ uint32_t time_msec) +{ + wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_content_t, content.super_element); + + return (0 <= x && x < fake_content_ptr->content.committed_width && + 0 <= y && y < fake_content_ptr->content.committed_height); +} + +/* ------------------------------------------------------------------------- */ +/** Returns true. */ +bool fake_content_element_pointer_button( + __UNUSED__ wlmtk_element_t *element_ptr, + __UNUSED__ const wlmtk_button_event_t *button_event_ptr) +{ + return true; +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 6546821f..6eb6075d 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -25,6 +25,9 @@ typedef struct _wlmtk_content_t wlmtk_content_t; /** Forward declaration: Content virtual method implementations. */ typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; +/** Forward declaration: Fake content, for tests. */ +typedef struct _wlmtk_fake_content_t wlmtk_fake_content_t; + #include "window.h" @@ -190,7 +193,7 @@ extern void *wlmtk_content_identifier_ptr; extern const bs_test_case_t wlmtk_content_test_cases[]; /** Fake content, useful for unit test. */ -typedef struct { +struct _wlmtk_fake_content_t { /** State of the content. */ wlmtk_content_t content; /** Whether @ref wlmtk_content_request_close was called. */ @@ -203,7 +206,7 @@ typedef struct { uint32_t return_request_size; /** Argument of last @ref wlmtk_content_set_activated call. */ bool activated; -} wlmtk_fake_content_t; +}; /** Ctor for a fake content. */ wlmtk_fake_content_t *wlmtk_fake_content_create(void); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 55970715..0b7facaf 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -25,7 +25,8 @@ /* == Declarations ========================================================= */ bool wlmtk_window_init(wlmtk_window_t *window_ptr, - const wlmtk_window_impl_t *impl_ptr); + const wlmtk_window_impl_t *impl_ptr, + wlmtk_content_t *content_ptr); void wlmtk_window_fini(wlmtk_window_t *window_ptr); static void wlmtk_window_set_activated_impl( @@ -155,11 +156,13 @@ static const wlmtk_resizebar_style_t resizebar_style = { * * @param window_ptr * @param impl_ptr + * @param content_ptr Will take ownership of it. * * @return true on success. */ bool wlmtk_window_init(wlmtk_window_t *window_ptr, - const wlmtk_window_impl_t *impl_ptr) + const wlmtk_window_impl_t *impl_ptr, + wlmtk_content_t *content_ptr) { BS_ASSERT(NULL != window_ptr); BS_ASSERT(NULL != impl_ptr); @@ -199,6 +202,14 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); + wlmtk_container_add_element_before( + &window_ptr->super_box.super_container, + wlmtk_resizebar_element(window_ptr->resizebar_ptr), + wlmtk_content_element(content_ptr)); + window_ptr->content_ptr = content_ptr; + wlmtk_content_set_window(content_ptr, window_ptr); + wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + window_ptr->titlebar_ptr = wlmtk_titlebar_create( window_ptr, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { @@ -238,6 +249,18 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) window_ptr->resizebar_ptr = NULL; } + if (NULL != window_ptr->content_ptr) { + wlmtk_container_remove_element( + &window_ptr->super_box.super_container, + wlmtk_content_element(window_ptr->content_ptr)); + wlmtk_element_set_visible( + wlmtk_content_element(window_ptr->content_ptr), false); + wlmtk_content_set_window(window_ptr->content_ptr, NULL); + + wlmtk_content_destroy(window_ptr->content_ptr); + window_ptr->content_ptr = NULL; + } + if (NULL != window_ptr->title_ptr) { free(window_ptr->title_ptr); window_ptr->title_ptr = NULL; @@ -255,7 +278,7 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!wlmtk_window_init(window_ptr, &window_default_impl)) { + if (!wlmtk_window_init(window_ptr, &window_default_impl, content_ptr)) { wlmtk_window_destroy(window_ptr); return NULL; } @@ -265,32 +288,12 @@ wlmtk_window_t *wlmtk_window_create( wlr_cursor_ptr, wlr_xcursor_manager_ptr); - wlmtk_container_add_element_before( - &window_ptr->super_box.super_container, - wlmtk_resizebar_element(window_ptr->resizebar_ptr), - wlmtk_content_element(content_ptr)); - window_ptr->content_ptr = content_ptr; - wlmtk_content_set_window(content_ptr, window_ptr); - wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - return window_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { - wlmtk_container_remove_element( - &window_ptr->super_box.super_container, - wlmtk_content_element(window_ptr->content_ptr)); - wlmtk_element_set_visible( - wlmtk_content_element(window_ptr->content_ptr), false); - wlmtk_content_set_window(window_ptr->content_ptr, NULL); - - if (NULL != window_ptr->content_ptr) { - wlmtk_content_destroy(window_ptr->content_ptr); - window_ptr->content_ptr = NULL; - } - wlmtk_window_fini(window_ptr); free(window_ptr); } @@ -301,6 +304,17 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) return &window_ptr->super_box.super_container.super_element; } +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) +{ + // DEBT: FIXME - The assertion here is too lose. + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_window_t, super_box.super_container.super_element); + BS_ASSERT(window_box_destroy == window_ptr->super_box.impl.destroy); + return window_ptr; +} + + /* ------------------------------------------------------------------------- */ void wlmtk_window_get_size( wlmtk_window_t *window_ptr, @@ -448,7 +462,15 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) 1, sizeof(wlmtk_fake_window_t)); if (NULL == fake_window_ptr) return NULL; - if (!wlmtk_window_init(&fake_window_ptr->window, &fake_window_impl)) { + fake_window_ptr->fake_content_ptr = wlmtk_fake_content_create(); + if (NULL == fake_window_ptr->fake_content_ptr) { + wlmtk_fake_window_destroy(fake_window_ptr); + return NULL; + } + + if (!wlmtk_window_init(&fake_window_ptr->window, + &fake_window_impl, + &fake_window_ptr->fake_content_ptr->content)) { wlmtk_fake_window_destroy(fake_window_ptr); return NULL; } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index b870fdb1..56a7ed2c 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -148,6 +148,16 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr); */ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); +/** + * Returns the window from the super Element. + * + * @param element_ptr + * + * @return Pointer to the @ref wlmtk_window_t, for which `element_ptr` is + * the ancestor. + */ +wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr); + /** * Obtains the size of the window, including potential decorations. * @@ -321,6 +331,9 @@ typedef struct { int width; /** Argument to last @ref wlmtk_window_request_size call. */ int height; + + /** Fake content, to manipulate the fake window's content. */ + wlmtk_fake_content_t *fake_content_ptr; } wlmtk_fake_window_t; /** Ctor. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 6bcb04ee..b17441ec 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -40,6 +40,9 @@ struct _wlmtk_workspace_t { /** Current FSM state. */ wlmtk_fsm_t fsm; + /** The activated window. */ + wlmtk_window_t *activated_window_ptr; + /** The grabbed window. */ wlmtk_window_t *grabbed_window_ptr; /** Motion X */ @@ -76,6 +79,9 @@ static bool pfsm_resize_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); +static void activate_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + /* == Data ================================================================= */ /** States of the pointer FSM. */ @@ -158,14 +164,15 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); - // TODO(kaeser@gubbe.ch): Refine and test this. - wlmtk_window_set_activated(window_ptr, true); + activate_window(workspace_ptr, window_ptr); } /* ------------------------------------------------------------------------- */ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { + bool need_activation = false; + BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( wlmtk_window_element(window_ptr)->parent_container_ptr)); @@ -174,10 +181,26 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, BS_ASSERT(NULL == workspace_ptr->grabbed_window_ptr); } + if (workspace_ptr->activated_window_ptr == window_ptr) { + activate_window(workspace_ptr, NULL); + need_activation = true; + } + wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); wlmtk_container_remove_element( &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); + + if (need_activation) { + // FIXME + bs_dllist_node_t *dlnode_ptr = + workspace_ptr->super_container.elements.head_ptr; + if (NULL != dlnode_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + wlmtk_window_t *window_ptr = wlmtk_window_from_element(element_ptr); + activate_window(workspace_ptr, window_ptr); + } + } } /* ------------------------------------------------------------------------- */ @@ -450,6 +473,29 @@ bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) return true; } +/* ------------------------------------------------------------------------- */ +/** Acticates `window_ptr`. Will de-activate an earlier window. */ +void activate_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) +{ + // Nothing to do. + if (workspace_ptr->activated_window_ptr == window_ptr) return; + + if (NULL != workspace_ptr->activated_window_ptr) { + wlmtk_window_set_activated(workspace_ptr->activated_window_ptr, false); + workspace_ptr->activated_window_ptr = NULL; + } + + if (NULL != window_ptr) { + wlmtk_window_set_activated(window_ptr, true); + workspace_ptr->activated_window_ptr = window_ptr; + } + // set activated. + // keep track of activated. => so it can be deactivated. + + +} + /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); @@ -458,6 +504,7 @@ static void test_button(bs_test_t *test_ptr); static void test_move(bs_test_t *test_ptr); static void test_unmap_during_move(bs_test_t *test_ptr); static void test_resize(bs_test_t *test_ptr); +static void test_activate(bs_test_t *test_ptr); const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "create_destroy", test_create_destroy }, @@ -466,6 +513,7 @@ const bs_test_case_t wlmtk_workspace_test_cases[] = { { 1, "move", test_move }, { 1, "unmap_during_move", test_unmap_during_move }, { 1, "resize", test_resize }, + { 1, "activate", test_activate }, { 0, NULL, NULL } }; @@ -495,7 +543,6 @@ void test_map_unmap(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); @@ -738,4 +785,62 @@ void test_resize(bs_test_t *test_ptr) wlmtk_container_destroy(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests window activation. */ +void test_activate(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + fake_parent_ptr->wlr_scene_tree_ptr); + BS_ASSERT(NULL != workspace_ptr); + + wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); + wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); + BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); + + // Window 1 is mapped => it's activated. + wlmtk_workspace_map_window(workspace_ptr, &fw1_ptr->window); + BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); + + // Window 2 is mapped: Will get activated, and 1st one de-activated. + wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); + wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); + BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); + wlmtk_workspace_map_window(workspace_ptr, &fw2_ptr->window); + BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); + + // Pointer move. Nothing happens: We have click-to-focus. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_workspace_motion(workspace_ptr, 50, 50, 0)); + BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); + + // Click on 1st window: Gets activated. + struct wlr_pointer_button_event wlr_button_event = { + .button = BTN_RIGHT, .state = WLR_BUTTON_PRESSED + }; + wlmtk_workspace_button(workspace_ptr, &wlr_button_event); + + // FIXME: These are broken. + // BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); + // BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); + + // Unmap window. The other one gets activated. + wlmtk_workspace_unmap_window(workspace_ptr, &fw2_ptr->window); + BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); + + // Unmap the remaining window. Nothing is activated. + wlmtk_workspace_unmap_window(workspace_ptr, &fw1_ptr->window); + BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); + + wlmtk_fake_window_destroy(fw2_ptr); + wlmtk_fake_window_destroy(fw1_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy(fake_parent_ptr); +} + /* == End of workspace.c =================================================== */ From ca9802ac64a3733eb92429590b66166db3a5865b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 23 Nov 2023 22:20:53 +0100 Subject: [PATCH 242/390] Changes element's implemention to use a proper virtual method table, and adapts the code throughout. --- src/toolkit/buffer.c | 24 +++--- src/toolkit/buffer.h | 9 ++- src/toolkit/container.c | 19 +++-- src/toolkit/container.h | 2 + src/toolkit/content.c | 48 ++++++------ src/toolkit/content.h | 4 + src/toolkit/element.c | 164 +++++++++++++++++++++++++--------------- src/toolkit/element.h | 150 ++++++++++++++++++++---------------- src/toolkit/workspace.c | 32 ++++---- 9 files changed, 266 insertions(+), 186 deletions(-) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index 28e30530..ed394be0 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -55,7 +55,7 @@ static void element_pointer_leave( /* == Data ================================================================= */ /** Method table for the buffer's virtual methods. */ -static const wlmtk_element_impl_t super_element_impl = { +static const wlmtk_element_vmt_t buffer_element_vmt = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, @@ -77,10 +77,11 @@ bool wlmtk_buffer_init( BS_ASSERT(NULL != buffer_impl_ptr->destroy); memcpy(&buffer_ptr->impl, buffer_impl_ptr, sizeof(wlmtk_buffer_impl_t)); - if (!wlmtk_element_init( - &buffer_ptr->super_element, &super_element_impl)) { + if (!wlmtk_element_init(&buffer_ptr->super_element)) { return false; } + buffer_ptr->orig_super_element_vmt = wlmtk_element_extend( + &buffer_ptr->super_element, &buffer_element_vmt); return true; } @@ -223,7 +224,7 @@ void handle_wlr_scene_buffer_node_destroy( } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_impl_t::pointer_motion. */ +/** See @ref wlmtk_element_vmt_t::pointer_motion. */ bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -231,33 +232,38 @@ bool element_pointer_motion( { wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_buffer_t, super_element); - if (NULL == buffer_ptr->impl.pointer_motion) return true; + buffer_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); + if (NULL == buffer_ptr->impl.pointer_motion) return true; return buffer_ptr->impl.pointer_motion(buffer_ptr, x, y, time_msec); } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_impl_t::pointer_button. */ +/** See @ref wlmtk_element_vmt_t::pointer_button. */ bool element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_buffer_t, super_element); - if (NULL == buffer_ptr->impl.pointer_button) return false; + buffer_ptr->orig_super_element_vmt.pointer_button( + element_ptr, button_event_ptr); + if (NULL == buffer_ptr->impl.pointer_button) return false; return buffer_ptr->impl.pointer_button(buffer_ptr, button_event_ptr); } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_impl_t::pointer_leave. */ +/** See @ref wlmtk_element_vmt_t::pointer_leave. */ void element_pointer_leave( wlmtk_element_t *element_ptr) { wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_buffer_t, super_element); - if (NULL == buffer_ptr->impl.pointer_leave) return; + buffer_ptr->orig_super_element_vmt.pointer_leave(element_ptr); + if (NULL == buffer_ptr->impl.pointer_leave) return; buffer_ptr->impl.pointer_leave(buffer_ptr); } diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index e4c942bc..31f65950 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -39,18 +39,19 @@ extern "C" { #endif // __cplusplus /** Method table of the buffer. */ +// FIXME: Make this obsolete through extending element. struct _wlmtk_buffer_impl_t { /** Destroys the implementation of the buffer. */ void (*destroy)(wlmtk_buffer_t *buffer_ptr); - /** Optional. See @ref wlmtk_element_impl_t::pointer_motion. */ + /** Optional. See @ref wlmtk_element_vmt_t::pointer_motion. */ bool (*pointer_motion)(wlmtk_buffer_t *buffer_ptr, double x, double y, uint32_t time_msec); - /** Optional. See @ref wlmtk_element_impl_t::pointer_button. */ + /** Optional. See @ref wlmtk_element_vmt_t::pointer_button. */ bool (*pointer_button)(wlmtk_buffer_t *buffer_ptr, const wlmtk_button_event_t *button_event_ptr); - /** Optional. See @ref wlmtk_element_impl_t::pointer_leave. */ + /** Optional. See @ref wlmtk_element_vmt_t::pointer_leave. */ void (*pointer_leave)(wlmtk_buffer_t *buffer_ptr); }; @@ -58,6 +59,8 @@ struct _wlmtk_buffer_impl_t { struct _wlmtk_buffer_t { /** Super class of the buffer: An element. */ wlmtk_element_t super_element; + /** Virtual method table of the super element before extending it. */ + wlmtk_element_vmt_t orig_super_element_vmt; /** Implementation of abstract virtual methods. */ wlmtk_buffer_impl_t impl; diff --git a/src/toolkit/container.c b/src/toolkit/container.c index e29bc6af..0319ecbb 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -65,7 +65,7 @@ static bool update_pointer_focus_at( static void base_container_update_layout(wlmtk_container_t *container_ptr); /** Virtual method table for the container's super class: Element. */ -static const wlmtk_element_impl_t super_element_impl = { +static const wlmtk_element_vmt_t container_element_vmt = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, @@ -87,10 +87,11 @@ bool wlmtk_container_init( BS_ASSERT(NULL != container_impl_ptr); BS_ASSERT(NULL != container_impl_ptr->destroy); - if (!wlmtk_element_init(&container_ptr->super_element, - &super_element_impl)) { + if (!wlmtk_element_init(&container_ptr->super_element)) { return false; } + container_ptr->orig_super_element_vmt = wlmtk_element_extend( + &container_ptr->super_element, &container_element_vmt); memcpy(&container_ptr->impl, container_impl_ptr, @@ -372,6 +373,8 @@ bool element_pointer_motion( { wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); + container_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); return update_pointer_focus_at(container_ptr, x, y, time_msec); } @@ -683,13 +686,13 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( &container, &wlmtk_container_fake_impl)); // Also expect the super element to be initialized. - BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.impl.destroy); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.vmt.destroy); BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl.destroy); wlmtk_container_destroy(&container); // Also expect the super element to be un-initialized. - BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.impl.destroy); + BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.vmt.destroy); BS_TEST_VERIFY_EQ(test_ptr, NULL, container.impl.destroy); } @@ -764,10 +767,10 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, container.super_element.wlr_scene_node_ptr); + // FIXME: Should use fake_element! wlmtk_element_t element; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element, &wlmtk_fake_element_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + wlmtk_element_extend(&element, &fake_element_vmt); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); wlmtk_container_add_element(&container, &element); diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 960142a3..1bb99bb8 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -56,6 +56,8 @@ struct _wlmtk_container_impl_t { struct _wlmtk_container_t { /** Super class of the container. */ wlmtk_element_t super_element; + /** Virtual method table of the super element before extending it. */ + wlmtk_element_vmt_t orig_super_element_vmt; /** Elements contained here. */ bs_dllist_t elements; diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 8a24a8be..1d103500 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -59,7 +59,7 @@ static bool element_pointer_button( /* == Data ================================================================= */ /** Method table for the container's virtual methods. */ -static const wlmtk_element_impl_t super_element_impl = { +static const wlmtk_element_vmt_t content_element_vmt = { .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, @@ -88,10 +88,11 @@ bool wlmtk_content_init( BS_ASSERT(NULL != content_impl_ptr->request_size); BS_ASSERT(NULL != content_impl_ptr->set_activated); - if (!wlmtk_element_init(&content_ptr->super_element, - &super_element_impl)) { + if (!wlmtk_element_init(&content_ptr->super_element)) { return false; } + content_ptr->orig_super_element_vmt = wlmtk_element_extend( + &content_ptr->super_element, &content_element_vmt); content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; @@ -419,6 +420,13 @@ static const wlmtk_content_impl_t wlmtk_fake_content_impl = { .set_activated = fake_content_set_activated, }; +/** Extensions to the content's super elements virtual methods. */ +static const wlmtk_element_vmt_t fake_content_element_vmt = { + .pointer_motion = fake_content_element_pointer_motion, + .pointer_button = fake_content_element_pointer_button, + .pointer_leave = fake_content_element_pointer_leave, +}; + /* ------------------------------------------------------------------------- */ wlmtk_fake_content_t *wlmtk_fake_content_create(void) { @@ -433,16 +441,11 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) return NULL; } - BS_ASSERT(NULL != fake_content_ptr->content.super_element.impl.destroy); + BS_ASSERT(NULL != fake_content_ptr->content.super_element.vmt.destroy); BS_ASSERT(NULL != fake_content_ptr->content.impl.destroy); - fake_content_ptr->content.super_element.impl.pointer_leave = - fake_content_element_pointer_leave; - fake_content_ptr->content.super_element.impl.pointer_motion = - fake_content_element_pointer_motion; - fake_content_ptr->content.super_element.impl.pointer_button = - fake_content_element_pointer_button; - + fake_content_ptr->orig_super_element_vmt = wlmtk_element_extend( + &fake_content_ptr->content.super_element, &fake_content_element_vmt); return fake_content_ptr; } @@ -456,7 +459,6 @@ void fake_content_destroy(wlmtk_content_t *content_ptr) wlmtk_content_fini(&fake_content_ptr->content); // Also expect the super element to be un-initialized. - BS_ASSERT(NULL == fake_content_ptr->content.super_element.impl.destroy); BS_ASSERT(NULL == fake_content_ptr->content.impl.destroy); free(fake_content_ptr); } @@ -506,24 +508,18 @@ void fake_content_set_activated( fake_content_ptr->activated = activated; } -/* ------------------------------------------------------------------------- */ -/** Does nothing. */ -void fake_content_element_pointer_leave( - __UNUSED__ wlmtk_element_t *element_ptr) -{ - // Nothing to do. -} - /* ------------------------------------------------------------------------- */ /** Returns (x, y) in [(0, committed_with), (0, committed_height)). */ bool fake_content_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - __UNUSED__ uint32_t time_msec) + uint32_t time_msec) { wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_content_t, content.super_element); + fake_content_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); return (0 <= x && x < fake_content_ptr->content.committed_width && 0 <= y && y < fake_content_ptr->content.committed_height); @@ -538,6 +534,14 @@ bool fake_content_element_pointer_button( return true; } +/* ------------------------------------------------------------------------- */ +/** Does nothing. */ +void fake_content_element_pointer_leave( + __UNUSED__ wlmtk_element_t *element_ptr) +{ + // Nothing to do. +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); @@ -559,7 +563,7 @@ void test_init_fini(bs_test_t *test_ptr) // Also expect the super element to be initialized. BS_TEST_VERIFY_NEQ( test_ptr, NULL, - fake_content_ptr->content.super_element.impl.destroy); + fake_content_ptr->content.super_element.vmt.destroy); BS_TEST_VERIFY_NEQ( test_ptr, NULL, fake_content_ptr->content.impl.destroy); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 6eb6075d..5c28e8e5 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -59,6 +59,8 @@ struct _wlmtk_content_t { /** Super class of the content: An element. */ wlmtk_element_t super_element; + /** Virtual method table of the super element before extending it. */ + wlmtk_element_vmt_t orig_super_element_vmt; /** Implementation of abstract virtual methods. */ wlmtk_content_impl_t impl; @@ -196,6 +198,8 @@ extern const bs_test_case_t wlmtk_content_test_cases[]; struct _wlmtk_fake_content_t { /** State of the content. */ wlmtk_content_t content; + /** Original virtual method table of the content's super element. */ + wlmtk_element_vmt_t orig_super_element_vmt; /** Whether @ref wlmtk_content_request_close was called. */ bool request_close_called; /** `width` argument eof last @ref wlmtk_content_request_size call. */ diff --git a/src/toolkit/element.c b/src/toolkit/element.c index ee611c91..6a76e701 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -29,24 +29,45 @@ /* == Declarations ========================================================= */ -static void handle_wlr_scene_node_destroy( +static void _wlmtk_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr); +static bool _wlmtk_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec); +static bool _wlmtk_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_element_pointer_leave( + wlmtk_element_t *element_ptr); + + static void handle_wlr_scene_node_destroy( struct wl_listener *listener_ptr, void *data_ptr); +/* == Data ================================================================= */ + +/** Default virtual method table. Initializes the non-abstract methods. */ +static const wlmtk_element_vmt_t element_vmt = { + .get_pointer_area = _wlmtk_element_get_pointer_area, + .pointer_motion = _wlmtk_element_pointer_motion, + .pointer_button = _wlmtk_element_pointer_button, + .pointer_leave = _wlmtk_element_pointer_leave, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_element_init( - wlmtk_element_t *element_ptr, - const wlmtk_element_impl_t *element_impl_ptr) +bool wlmtk_element_init(wlmtk_element_t *element_ptr) { BS_ASSERT(NULL != element_ptr); memset(element_ptr, 0, sizeof(wlmtk_element_t)); - BS_ASSERT(NULL != element_impl_ptr); - BS_ASSERT(NULL != element_impl_ptr->destroy); - BS_ASSERT(NULL != element_impl_ptr->create_scene_node); - BS_ASSERT(NULL != element_impl_ptr->get_dimensions); - memcpy(&element_ptr->impl, element_impl_ptr, sizeof(wlmtk_element_impl_t)); + element_ptr->vmt = element_vmt; element_ptr->last_pointer_x = NAN; element_ptr->last_pointer_y = NAN; @@ -54,6 +75,39 @@ bool wlmtk_element_init( return true; } +/* ------------------------------------------------------------------------- */ +wlmtk_element_vmt_t wlmtk_element_extend( + wlmtk_element_t *element_ptr, + const wlmtk_element_vmt_t *element_vmt_ptr) +{ + wlmtk_element_vmt_t orig_vmt = element_ptr->vmt; + + // Only overwrite provided methods. + if (NULL != element_vmt_ptr->destroy) { + element_ptr->vmt.destroy = element_vmt_ptr->destroy; + } + if (NULL != element_vmt_ptr->create_scene_node) { + element_ptr->vmt.create_scene_node = element_vmt_ptr->create_scene_node; + } + if (NULL != element_vmt_ptr->get_dimensions) { + element_ptr->vmt.get_dimensions = element_vmt_ptr->get_dimensions; + } + if (NULL != element_vmt_ptr->get_pointer_area) { + element_ptr->vmt.get_pointer_area = element_vmt_ptr->get_pointer_area; + } + if (NULL != element_vmt_ptr->pointer_motion) { + element_ptr->vmt.pointer_motion = element_vmt_ptr->pointer_motion; + } + if (NULL != element_vmt_ptr->pointer_button) { + element_ptr->vmt.pointer_button = element_vmt_ptr->pointer_button; + } + if (NULL != element_vmt_ptr->pointer_leave) { + element_ptr->vmt.pointer_leave = element_vmt_ptr->pointer_leave; + } + + return orig_vmt; +} + /* ------------------------------------------------------------------------- */ void wlmtk_element_fini( wlmtk_element_t *element_ptr) @@ -109,7 +163,7 @@ void wlmtk_element_attach_to_scene_graph( } if (NULL == element_ptr->wlr_scene_node_ptr) { - element_ptr->wlr_scene_node_ptr = element_ptr->impl.create_scene_node( + element_ptr->wlr_scene_node_ptr = element_ptr->vmt.create_scene_node( element_ptr, parent_wlr_scene_tree_ptr); wlmtk_util_connect_listener_signal( &element_ptr->wlr_scene_node_ptr->events.destroy, @@ -173,37 +227,23 @@ void wlmtk_element_set_position( } } -/* ------------------------------------------------------------------------- */ -void wlmtk_element_get_dimensions( - wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr) -{ - element_ptr->impl.get_dimensions( - element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); -} +/* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -void wlmtk_element_get_pointer_area( +/** Wraps to wlmtk_element_vmt_t::get_dimensions as default implementation. */ +void _wlmtk_element_get_pointer_area( wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr) + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr) { - if (NULL != element_ptr->impl.get_pointer_area) { - element_ptr->impl.get_pointer_area( - element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); - } else { - wlmtk_element_get_dimensions( - element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); - } + wlmtk_element_get_dimensions(element_ptr, x1_ptr, y1_ptr, x2_ptr, y2_ptr); } /* ------------------------------------------------------------------------- */ -bool wlmtk_element_pointer_motion( +/** Stores the pointer coordinates and timestamp. Returns true. */ +bool _wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -212,28 +252,28 @@ bool wlmtk_element_pointer_motion( element_ptr->last_pointer_x = x; element_ptr->last_pointer_y = y; element_ptr->last_pointer_time_msec = time_msec; + return true; +} - // Guard clause: No implementation for `pointer_motion`. - if (NULL == element_ptr->impl.pointer_motion) return false; - - return element_ptr->impl.pointer_motion( - element_ptr, x, y, time_msec); +/* ------------------------------------------------------------------------- */ +/** Does nothing, returns false. */ +bool _wlmtk_element_pointer_button( + __UNUSED__ wlmtk_element_t *element_ptr, + __UNUSED__ const wlmtk_button_event_t *button_event_ptr) +{ + return false; } /* ------------------------------------------------------------------------- */ -void wlmtk_element_pointer_leave( +/** Resets the pointer coordinates. */ +void _wlmtk_element_pointer_leave( wlmtk_element_t *element_ptr) { - if (NULL != element_ptr->impl.pointer_leave) { - element_ptr->impl.pointer_leave(element_ptr); - } element_ptr->last_pointer_x = NAN; element_ptr->last_pointer_y = NAN; element_ptr->last_pointer_time_msec = 0; } -/* == Local (static) methods =============================================== */ - /* ------------------------------------------------------------------------- */ /** * Handles the 'destroy' callback of the wlr_scene_node. @@ -280,7 +320,8 @@ static bool fake_pointer_button( static void fake_pointer_leave( wlmtk_element_t *element_ptr); -const wlmtk_element_impl_t wlmtk_fake_element_impl = { +/** Virtual method table for the fake element. */ +const wlmtk_element_vmt_t fake_element_vmt = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, .get_dimensions = fake_get_dimensions, @@ -297,12 +338,14 @@ wlmtk_fake_element_t *wlmtk_fake_element_create(void) 1, sizeof(wlmtk_fake_element_t)); if (NULL == fake_element_ptr) return NULL; - if (!wlmtk_element_init(&fake_element_ptr->element, - &wlmtk_fake_element_impl)) { + if (!wlmtk_element_init(&fake_element_ptr->element)) { fake_destroy(&fake_element_ptr->element); return NULL; } + fake_element_ptr->orig_vmt = wlmtk_element_extend( + &fake_element_ptr->element, &fake_element_vmt); + return fake_element_ptr; } @@ -362,15 +405,16 @@ void fake_get_pointer_area( } /* ------------------------------------------------------------------------- */ -/** Handles 'motion' events for the fake element. */ +/** Handles 'motion' events for the fake element, updates last position. */ bool fake_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - __UNUSED__ uint32_t time_msec) + uint32_t time_msec) { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); + fake_element_ptr->orig_vmt.pointer_motion(element_ptr, x, y, time_msec); fake_element_ptr->pointer_motion_called = true; return (-1 <= x && x < fake_element_ptr->width + 3 && -2 < y && y < fake_element_ptr->height + 4); @@ -400,6 +444,7 @@ void fake_pointer_leave( { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); + fake_element_ptr->orig_vmt.pointer_leave(element_ptr); fake_element_ptr->pointer_leave_called = true; } @@ -429,13 +474,12 @@ const bs_test_case_t wlmtk_element_test_cases[] = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element, &wlmtk_fake_element_impl)); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.impl.destroy); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + wlmtk_element_extend(&element, &fake_element_vmt); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.vmt.destroy); wlmtk_element_fini(&element); - BS_TEST_VERIFY_EQ(test_ptr, NULL, element.impl.destroy); + BS_TEST_VERIFY_EQ(test_ptr, NULL, element.vmt.destroy); } /* ------------------------------------------------------------------------- */ @@ -443,9 +487,8 @@ void test_init_fini(bs_test_t *test_ptr) void test_set_parent_container(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element, &wlmtk_fake_element_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + wlmtk_element_extend(&element, &fake_element_vmt); // Setting a parent without a scene graph tree will not set a node. wlmtk_container_t parent_no_tree; @@ -494,9 +537,8 @@ void test_set_parent_container(bs_test_t *test_ptr) void test_set_get_position(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_element_init(&element, &wlmtk_fake_element_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + wlmtk_element_extend(&element, &fake_element_vmt); // Exercise, must not crash. wlmtk_element_get_position(&element, NULL, NULL); diff --git a/src/toolkit/element.h b/src/toolkit/element.h index b4f1ee44..ac5572ad 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -25,8 +25,8 @@ /** Forward declaration: Element. */ typedef struct _wlmtk_element_t wlmtk_element_t; -/** Forward declaration: Element virtual method implementations. */ -typedef struct _wlmtk_element_impl_t wlmtk_element_impl_t; +/** Forward declaration: Element virtual method table. */ +typedef struct _wlmtk_element_vmt_t wlmtk_element_vmt_t; /** Forward declaration: Container. */ typedef struct _wlmtk_container_t wlmtk_container_t; @@ -38,23 +38,23 @@ struct wlr_scene_tree; extern "C" { #endif // __cplusplus -/** Pointers to the implementation of Element's virtual methods. */ -struct _wlmtk_element_impl_t { - /** Destroys the implementation of the element. */ +/** Virtual method table for the element. */ +struct _wlmtk_element_vmt_t { + /** Abstract: Destroys the implementation of the element. */ void (*destroy)(wlmtk_element_t *element_ptr); - /** Creates element's scene graph API node, child to wlr_scene_tree_ptr. */ + /** Abstract: Creates element's scene graph API node, child to wlr_scene_tree_ptr. */ struct wlr_scene_node *(*create_scene_node)( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); - /** Gets dimensions of the element, relative to the position. */ + /** Abstract: Gets dimensions of the element, relative to the element's position. */ void (*get_dimensions)( wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr); + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr); /** Gets element area to accept pointer activity, relative to position. */ void (*get_pointer_area)( @@ -67,6 +67,14 @@ struct _wlmtk_element_impl_t { /** * Indicates pointer motion into or within the element area to (x,y). * + * The default implementation at @ref _wlmtk_element_pointer_motion updates + * @ref wlmtk_element_t::last_pointer_x, + * @ref wlmtk_element_t::last_pointer_y + * and @ref wlmtk_element_t::last_pointer_time_msec. + * + * Derived classes that overwrite this method are advised to call the + * initial implementation for keeping these internals updated. + * * @param element_ptr * @param x * @param y @@ -79,6 +87,7 @@ struct _wlmtk_element_impl_t { bool (*pointer_motion)(wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); + /** * Indicates pointer button event. * @@ -110,8 +119,8 @@ struct _wlmtk_element_t { /** The node of elements. */ bs_dllist_node_t dlnode; - /** Implementation of abstract virtual methods. */ - wlmtk_element_impl_t impl; + /** Virtual method table for the element. */ + wlmtk_element_vmt_t vmt; /** Points to the wlroots scene graph API node, if attached. */ struct wlr_scene_node *wlr_scene_node_ptr; @@ -146,13 +155,22 @@ struct _wlmtk_element_t { * Initializes the element. * * @param element_ptr - * @param element_impl_ptr * * @return true on success. */ -bool wlmtk_element_init( +bool wlmtk_element_init(wlmtk_element_t *element_ptr); + +/** + * Extends the element's virtual methods. + * + * @param element_ptr + * @param element_vmt_ptr + * + * @return The previous virtual method table. + */ +wlmtk_element_vmt_t wlmtk_element_extend( wlmtk_element_t *element_ptr, - const wlmtk_element_impl_t *element_impl_ptr); + const wlmtk_element_vmt_t *element_vmt_ptr); /** * Cleans up the element. @@ -191,7 +209,7 @@ void wlmtk_element_set_parent_container( * * If the element has a parent, and that parent is itself attached to the * wlroots scene tree, this will either re-parent an already existing node, - * or invoke wlmtk_element_impl_t::create_scene_node to create and attach a + * or invoke @ref wlmtk_element_vmt_t::create_scene_node to create and attach a * new node to the paren'ts tree. * Otherwise, it will clear any existing node. * @@ -237,22 +255,6 @@ void wlmtk_element_set_position( int x, int y); -/** - * Gets the dimensions of the element in pixels, relative to the position. - * - * @param element_ptr - * @param left_ptr Leftmost position. May be NULL. - * @param top_ptr Topmost position. May be NULL. - * @param right_ptr Rightmost position. Ma be NULL. - * @param bottom_ptr Bottommost position. May be NULL. - */ -void wlmtk_element_get_dimensions( - wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr); - /** * Gets the area that the element on which the element accepts pointer events. * @@ -261,53 +263,65 @@ void wlmtk_element_get_dimensions( * further-extending sub-surfaces) may differ. * * @param element_ptr - * @param left_ptr Leftmost position of pointer area. May be NULL. - * @param top_ptr Topmost position of pointer area. May be NULL. - * @param right_ptr Rightmost position of pointer area. May be NULL. - * @param bottom_ptr Bottommost position of pointer area. May be NULL. + * @param x1_ptr Leftmost position of pointer area. May be NULL. + * @param y1_ptr Topmost position of pointer area. May be NULL. + * @param x2_ptr Rightmost position of pointer area. May be NULL. + * @param y2_ptr Bottommost position of pointer area. May be NULL. */ -void wlmtk_element_get_pointer_area( +static inline void wlmtk_element_get_pointer_area( wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr); + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr) +{ + element_ptr->vmt.get_pointer_area( + element_ptr, x1_ptr, y1_ptr, x2_ptr, y2_ptr); +} /** - * Virtual method: Calls 'pointer_motion' for the element's implementation. - * - * Also updates wlmtk_element_t::last_pointer_x, - * wlmtk_element_t::last_pointer_y and wlmtk_element_t::last_pointer_time_msec. + * Gets the dimensions of the element in pixels, relative to the position. * * @param element_ptr - * @param x - * @param y - * @param time_msec - * - * @return Whether the coordinates are within this element's area that accepts - * pointer events. May be a subset of @ref wlmtk_element_get_pointer_area. - * + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. */ -bool wlmtk_element_pointer_motion( +static inline void wlmtk_element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + element_ptr->vmt.get_dimensions( + element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); +} + +/** Calls @ref wlmtk_element_vmt_t::pointer_button. */ +static inline bool wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - uint32_t time_msec); - -/** - * Virtual method: Calls 'pointer_leave' for the element's implementation. - */ -void wlmtk_element_pointer_leave( - wlmtk_element_t *element_ptr); + uint32_t time_msec) +{ + return element_ptr->vmt.pointer_motion(element_ptr, x, y, time_msec); +} -/** Virtual method: calls 'button' for the element's implementation. */ +/** Calls @ref wlmtk_element_vmt_t::pointer_button. */ static inline bool wlmtk_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { - if (NULL == element_ptr->impl.pointer_button) return false; - return element_ptr->impl.pointer_button( - element_ptr, button_event_ptr); + return element_ptr->vmt.pointer_button(element_ptr, button_event_ptr); +} + +/** Calls @ref wlmtk_element_vmt_t::pointer_leave. */ +static inline void wlmtk_element_pointer_leave( + wlmtk_element_t *element_ptr) +{ + element_ptr->vmt.pointer_leave(element_ptr); } /** @@ -319,7 +333,7 @@ static inline bool wlmtk_element_pointer_button( */ static inline void wlmtk_element_destroy( wlmtk_element_t *element_ptr) { - element_ptr->impl.destroy(element_ptr); + element_ptr->vmt.destroy(element_ptr); } /** Unit tests for the element. */ @@ -329,6 +343,8 @@ extern const bs_test_case_t wlmtk_element_test_cases[]; typedef struct { /** State of the element. */ wlmtk_element_t element; + /** Original VMT. */ + wlmtk_element_vmt_t orig_vmt; /** Width of the element, in pixels. */ int width; /** Height of the element, in pixels. */ @@ -350,7 +366,7 @@ typedef struct { wlmtk_fake_element_t *wlmtk_fake_element_create(void); /** Implementation table of a "fake" element for tests. */ -extern const wlmtk_element_impl_t wlmtk_fake_element_impl; +extern const wlmtk_element_vmt_t fake_element_vmt; #ifdef __cplusplus } // extern "C" diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index b17441ec..0e16cfc7 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -35,7 +35,7 @@ struct _wlmtk_workspace_t { /** Superclass: Container. */ wlmtk_container_t super_container; /** Original virtual method table. We're overwriting parts. */ - wlmtk_element_impl_t parent_element_impl; + wlmtk_element_vmt_t orig_super_element_vmt; /** Current FSM state. */ wlmtk_fsm_t fsm; @@ -105,6 +105,13 @@ const wlmtk_container_impl_t workspace_container_impl = { .destroy = workspace_container_destroy }; +/** Extensions to the workspace's super element's virtual methods. */ +const wlmtk_element_vmt_t workspace_element_vmt = { + .pointer_motion = element_pointer_motion, + .pointer_button = element_pointer_button, + .pointer_leave = element_pointer_leave, +}; + /** Finite state machine definition for pointer events. */ static const wlmtk_fsm_transition_t pfsm_transitions[] = { { PFSMS_PASSTHROUGH, PFSME_BEGIN_MOVE, PFSMS_MOVE, pfsm_move_begin }, @@ -134,15 +141,9 @@ wlmtk_workspace_t *wlmtk_workspace_create( wlmtk_workspace_destroy(workspace_ptr); return NULL; } - memcpy(&workspace_ptr->parent_element_impl, - &workspace_ptr->super_container.super_element.impl, - sizeof(wlmtk_element_impl_t)); - workspace_ptr->super_container.super_element.impl.pointer_motion = - element_pointer_motion; - workspace_ptr->super_container.super_element.impl.pointer_button = - element_pointer_button; - workspace_ptr->super_container.super_element.impl.pointer_leave = - element_pointer_leave; + workspace_ptr->orig_super_element_vmt = wlmtk_element_extend( + &workspace_ptr->super_container.super_element, + &workspace_element_vmt); wlmtk_fsm_init(&workspace_ptr->fsm, pfsm_transitions, PFSMS_PASSTHROUGH); return workspace_ptr; @@ -303,11 +304,10 @@ bool element_pointer_motion( { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); - - wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_MOTION, NULL); - - return workspace_ptr->parent_element_impl.pointer_motion( + bool rv = workspace_ptr->orig_super_element_vmt.pointer_motion( element_ptr, x, y, time_msec); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_MOTION, NULL); + return rv; } /* ------------------------------------------------------------------------- */ @@ -335,7 +335,7 @@ bool element_pointer_button( wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RELEASED, NULL); } - return workspace_ptr->parent_element_impl.pointer_button( + return workspace_ptr->orig_super_element_vmt.pointer_button( element_ptr, button_event_ptr); } @@ -351,7 +351,7 @@ void element_pointer_leave( wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); - workspace_ptr->parent_element_impl.pointer_leave(element_ptr); + workspace_ptr->orig_super_element_vmt.pointer_leave(element_ptr); } /* ------------------------------------------------------------------------- */ From 05d152e2165123be6a7c9dea8f65aa049919ee79 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 16:00:09 +0100 Subject: [PATCH 243/390] Refactors container to use virtual method table, and applies throughout. --- src/toolkit/box.c | 48 ++++++++-------- src/toolkit/box.h | 8 ++- src/toolkit/container.c | 124 +++++++++++++++------------------------- src/toolkit/container.h | 52 ++++++++--------- src/toolkit/content.c | 3 + src/toolkit/element.c | 14 ++--- src/toolkit/resizebar.c | 20 ++++--- src/toolkit/titlebar.c | 20 ++++--- src/toolkit/window.c | 38 ++++++++++++ src/toolkit/window.h | 3 + src/toolkit/workspace.c | 33 +++++------ 11 files changed, 189 insertions(+), 174 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index dfc9d225..c8c87c08 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -22,15 +22,14 @@ /* == Declarations ========================================================= */ -static void container_destroy(wlmtk_container_t *container_ptr); -static void container_update_layout(wlmtk_container_t *container_ptr); +static void _wlmtk_box_container_update_layout( + wlmtk_container_t *container_ptr); /* == Data ================================================================= */ -/** Method table for the box's virtual methods. */ -static const wlmtk_container_impl_t container_impl = { - .destroy = container_destroy, - .update_layout = container_update_layout, +/** Virtual method table: @ref wlmtk_container_t at @ref wlmtk_box_t level. */ +static const wlmtk_container_vmt_t box_container_vmt = { + .update_layout = _wlmtk_box_container_update_layout, }; /* == Exported methods ===================================================== */ @@ -42,12 +41,17 @@ bool wlmtk_box_init( wlmtk_box_orientation_t orientation) { BS_ASSERT(NULL != box_ptr); - BS_ASSERT(NULL != box_impl_ptr); - BS_ASSERT(NULL != box_impl_ptr->destroy); - if (!wlmtk_container_init(&box_ptr->super_container, &container_impl)) { + if (!wlmtk_container_init(&box_ptr->super_container)) { return false; } - memcpy(&box_ptr->impl, box_impl_ptr, sizeof(wlmtk_box_impl_t)); + box_ptr->orig_super_container_vmt = wlmtk_container_extend( + &box_ptr->super_container, &box_container_vmt); + + if (NULL != box_impl_ptr) { + BS_ASSERT(NULL != box_impl_ptr); + BS_ASSERT(NULL != box_impl_ptr->destroy); + memcpy(&box_ptr->impl, box_impl_ptr, sizeof(wlmtk_box_impl_t)); + } box_ptr->orientation = orientation; return true; @@ -61,15 +65,6 @@ void wlmtk_box_fini(__UNUSED__ wlmtk_box_t *box_ptr) /* == Local (static) methods =============================================== */ -/* ------------------------------------------------------------------------- */ -/** Virtual destructor, in case called from container. Wraps to our dtor. */ -void container_destroy(wlmtk_container_t *container_ptr) -{ - wlmtk_box_t *box_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_box_t, super_container); - box_ptr->impl.destroy(box_ptr); -} - /* ------------------------------------------------------------------------- */ /** * Updates the layout of the box. @@ -79,7 +74,8 @@ void container_destroy(wlmtk_container_t *container_ptr) * * @param container_ptr */ -void container_update_layout(wlmtk_container_t *container_ptr) +void _wlmtk_box_container_update_layout( + wlmtk_container_t *container_ptr) { wlmtk_box_t *box_ptr = BS_CONTAINER_OF( container_ptr, wlmtk_box_t, super_container); @@ -109,19 +105,25 @@ void container_update_layout(wlmtk_container_t *container_ptr) break; default: - bs_log(BS_FATAL, "Weird orientatin %d.", box_ptr->orientation); + bs_log(BS_FATAL, "Weird orientation %d.", box_ptr->orientation); } wlmtk_element_set_position(element_ptr, x, y); } + // Run the base class' update layout; may update pointer focus. + // We do this only after having updated the position of the elements. + box_ptr->orig_super_container_vmt.update_layout(container_ptr); + // Forward to virtual methods, if any. if (NULL != box_ptr->impl.update_layout) { box_ptr->impl.update_layout(box_ptr); } // configure parent container. - wlmtk_container_update_layout( - container_ptr->super_element.parent_container_ptr); + if (NULL != container_ptr->super_element.parent_container_ptr) { + wlmtk_container_update_layout( + container_ptr->super_element.parent_container_ptr); + } } /* == Unit tests =========================================================== */ diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 62935be1..d1553af5 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -38,9 +38,9 @@ struct _wlmtk_box_impl_t { /** * Updates the layout of the elements. * - * The box's @ref container_update_layout method will invoke this optional - * method when a contained element changes visibility, dimensions or was - * added or removed. + * The box's @ref _wlmtk_box_container_update_layout method will invoke + * this optional method when a contained element changes visibility, + * dimensions or was added or removed. * A derived class (eg. a window) can use this eg. to recompute dimensions * of window decorations, when eg. a call to @ref wlmtk_content_commit_size * had committed an update to the window content's dimensions. @@ -58,6 +58,8 @@ typedef enum { struct _wlmtk_box_t { /** Super class of the box. */ wlmtk_container_t super_container; + /** Virtual method table of the superclass' container. */ + wlmtk_container_vmt_t orig_super_container_vmt; /** Virtual method table of the box. */ wlmtk_box_impl_t impl; /** Orientation of the box. */ diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 0319ecbb..b3ccf5a6 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -28,7 +28,6 @@ /* == Declarations ========================================================= */ -static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); @@ -62,11 +61,10 @@ static bool update_pointer_focus_at( double x, double y, uint32_t time_msec); -static void base_container_update_layout(wlmtk_container_t *container_ptr); +static void _wlmtk_container_update_layout(wlmtk_container_t *container_ptr); /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_vmt_t container_element_vmt = { - .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, .get_pointer_area = element_get_pointer_area, @@ -75,17 +73,19 @@ static const wlmtk_element_vmt_t container_element_vmt = { .pointer_leave = element_pointer_leave, }; +/** Default virtual method table. Initializes non-abstract methods. */ +static const wlmtk_container_vmt_t container_vmt = { + .update_layout = _wlmtk_container_update_layout, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_container_init( - wlmtk_container_t *container_ptr, - const wlmtk_container_impl_t *container_impl_ptr) +bool wlmtk_container_init(wlmtk_container_t *container_ptr) { BS_ASSERT(NULL != container_ptr); memset(container_ptr, 0, sizeof(wlmtk_container_t)); - BS_ASSERT(NULL != container_impl_ptr); - BS_ASSERT(NULL != container_impl_ptr->destroy); + container_ptr->vmt = container_vmt; if (!wlmtk_element_init(&container_ptr->super_element)) { return false; @@ -93,22 +93,15 @@ bool wlmtk_container_init( container_ptr->orig_super_element_vmt = wlmtk_element_extend( &container_ptr->super_element, &container_element_vmt); - memcpy(&container_ptr->impl, - container_impl_ptr, - sizeof(wlmtk_container_impl_t)); - if (NULL == container_ptr->impl.update_layout) { - container_ptr->impl.update_layout = base_container_update_layout; - } return true; } /* ------------------------------------------------------------------------- */ bool wlmtk_container_init_attached( wlmtk_container_t *container_ptr, - const wlmtk_container_impl_t *container_impl_ptr, struct wlr_scene_tree *root_wlr_scene_tree_ptr) { - if (!wlmtk_container_init(container_ptr, container_impl_ptr)) return false; + if (!wlmtk_container_init(container_ptr)) return false; container_ptr->super_element.wlr_scene_node_ptr = element_create_scene_node( @@ -122,6 +115,19 @@ bool wlmtk_container_init_attached( return true; } +/* ------------------------------------------------------------------------- */ +wlmtk_container_vmt_t wlmtk_container_extend( + wlmtk_container_t *container_ptr, + const wlmtk_container_vmt_t *container_vmt_ptr) +{ + wlmtk_container_vmt_t orig_vmt = container_ptr->vmt; + + if (NULL != container_vmt_ptr->update_layout) { + container_ptr->vmt.update_layout = container_vmt_ptr->update_layout; + } + return orig_vmt; +} + /* ------------------------------------------------------------------------- */ void wlmtk_container_fini(wlmtk_container_t *container_ptr) { @@ -218,19 +224,6 @@ struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( /* == Local (static) methods =============================================== */ -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the superclass wlmtk_element_t::destroy method. - * - * @param element_ptr - */ -void element_destroy(wlmtk_element_t *element_ptr) -{ - wlmtk_container_t *container_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_container_t, super_element); - container_ptr->impl.destroy(container_ptr); -} - /* ------------------------------------------------------------------------- */ /** * Implementation of the superclass wlmtk_element_t::create_scene_node method. @@ -562,13 +555,13 @@ bool update_pointer_focus_at( /* ------------------------------------------------------------------------- */ /** - * Base implementation of wlmtk_container_impl_t::update_layout. If there's - * a paraent, will call @ref wlmtk_container_update_layout. Otherwise, will + * Base implementation of wlmtk_container_vmt_t::update_layout. If there's + * a parent, will call @ref wlmtk_container_update_layout. Otherwise, will * update the pointer focus. * * @param container_ptr */ -void base_container_update_layout(wlmtk_container_t *container_ptr) +void _wlmtk_container_update_layout(wlmtk_container_t *container_ptr) { if (NULL != container_ptr->super_element.parent_container_ptr) { wlmtk_container_update_layout( @@ -582,22 +575,6 @@ void base_container_update_layout(wlmtk_container_t *container_ptr) } } -/* == Helper for unit test: A fake container =============================== */ - -static void fake_destroy(wlmtk_container_t *container_ptr); - -/** Method table for the container we're using for test. */ -const wlmtk_container_impl_t wlmtk_container_fake_impl = { - .destroy = fake_destroy -}; - -/* ------------------------------------------------------------------------- */ -/** dtor for the container under test. */ -void fake_destroy(wlmtk_container_t *container_ptr) -{ - wlmtk_container_fini(container_ptr); -} - /* == Helper for unit tests: A fake container with a tree, as parent ======= */ /** State of the "fake" parent container. Refers to a scene graph. */ @@ -608,30 +585,25 @@ typedef struct { struct wlr_scene *wlr_scene_ptr; } fake_parent_container_t; -static void fake_parent_destroy(wlmtk_container_t *container_ptr); - /* ------------------------------------------------------------------------- */ wlmtk_container_t *wlmtk_container_create_fake_parent(void) { - static const wlmtk_container_impl_t fake_parent_impl = { - .destroy = fake_parent_destroy - }; - fake_parent_container_t *fake_parent_container_ptr = logged_calloc( 1, sizeof(fake_parent_container_t)); if (NULL == fake_parent_container_ptr) return NULL; fake_parent_container_ptr->wlr_scene_ptr = wlr_scene_create(); if (NULL == fake_parent_container_ptr->wlr_scene_ptr) { - fake_parent_destroy(&fake_parent_container_ptr->container); + wlmtk_container_destroy_fake_parent( + &fake_parent_container_ptr->container); return NULL; } if (!wlmtk_container_init_attached( &fake_parent_container_ptr->container, - &fake_parent_impl, &fake_parent_container_ptr->wlr_scene_ptr->tree)) { - fake_parent_destroy(&fake_parent_container_ptr->container); + wlmtk_container_destroy_fake_parent( + &fake_parent_container_ptr->container); return NULL; } @@ -639,8 +611,7 @@ wlmtk_container_t *wlmtk_container_create_fake_parent(void) } /* ------------------------------------------------------------------------- */ -/** Destructor for the "fake" parent, to be used for tests. */ -void fake_parent_destroy(wlmtk_container_t *container_ptr) +void wlmtk_container_destroy_fake_parent(wlmtk_container_t *container_ptr) { fake_parent_container_t *fake_parent_container_ptr = BS_CONTAINER_OF( container_ptr, fake_parent_container_t, container); @@ -683,17 +654,15 @@ const bs_test_case_t wlmtk_container_test_cases[] = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( - &container, &wlmtk_container_fake_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container));; // Also expect the super element to be initialized. - BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.super_element.vmt.destroy); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, container.impl.destroy); - - wlmtk_container_destroy(&container); + BS_TEST_VERIFY_NEQ( + test_ptr, NULL, container.super_element.vmt.pointer_motion); + wlmtk_container_fini(&container); // Also expect the super element to be un-initialized. - BS_TEST_VERIFY_EQ(test_ptr, NULL, container.super_element.vmt.destroy); - BS_TEST_VERIFY_EQ(test_ptr, NULL, container.impl.destroy); + BS_TEST_VERIFY_EQ( + test_ptr, NULL, container.super_element.vmt.pointer_motion); } /* ------------------------------------------------------------------------- */ @@ -701,8 +670,7 @@ void test_init_fini(bs_test_t *test_ptr) void test_add_remove(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( - &container, &wlmtk_container_fake_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container)); wlmtk_fake_element_t *elem1_ptr, *elem2_ptr, *elem3_ptr; elem1_ptr = wlmtk_fake_element_create(); @@ -754,8 +722,7 @@ void test_add_remove(bs_test_t *test_ptr) void test_add_remove_with_scene_graph(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init( - &container, &wlmtk_container_fake_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container)); wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_parent_ptr); @@ -782,7 +749,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_element_set_parent_container(&container.super_element, NULL); wlmtk_container_fini(&container); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -790,7 +757,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) void test_pointer_motion(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + BS_ASSERT(wlmtk_container_init(&container)); wlmtk_element_set_visible(&container.super_element, true); // Note: pointer area extends by (-1, -2, 3, 4) on each fake element. @@ -823,8 +790,7 @@ void test_pointer_motion(bs_test_t *test_ptr) // Same must hold for the parent container. wlmtk_container_t parent_container; - BS_ASSERT(wlmtk_container_init(&parent_container, - &wlmtk_container_fake_impl)); + BS_ASSERT(wlmtk_container_init(&parent_container)); wlmtk_container_add_element(&parent_container, &container.super_element); @@ -923,7 +889,7 @@ void test_pointer_motion(bs_test_t *test_ptr) void test_pointer_focus(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + BS_ASSERT(wlmtk_container_init(&container)); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&elem1_ptr->element, true); @@ -1014,9 +980,9 @@ void test_pointer_focus(bs_test_t *test_ptr) void test_pointer_focus_layered(bs_test_t *test_ptr) { wlmtk_container_t container1; - BS_ASSERT(wlmtk_container_init(&container1, &wlmtk_container_fake_impl)); + BS_ASSERT(wlmtk_container_init(&container1)); wlmtk_container_t container2; - BS_ASSERT(wlmtk_container_init(&container2, &wlmtk_container_fake_impl)); + BS_ASSERT(wlmtk_container_init(&container2)); wlmtk_element_set_visible(&container2.super_element, true); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); @@ -1091,7 +1057,7 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) void test_pointer_button(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container, &wlmtk_container_fake_impl)); + BS_ASSERT(wlmtk_container_init(&container)); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&elem1_ptr->element, true); diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 1bb99bb8..2711a3d3 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -25,8 +25,8 @@ /** Forward declaration: Container. */ typedef struct _wlmtk_container_t wlmtk_container_t; -/** Forward declaration: Container virtual method implementations. */ -typedef struct _wlmtk_container_impl_t wlmtk_container_impl_t; +/** Forward declaration: Container virtual method table. */ +typedef struct _wlmtk_container_vmt_t wlmtk_container_vmt_t; #include "element.h" @@ -35,9 +35,7 @@ extern "C" { #endif // __cplusplus /** Virtual method table of the container. */ -struct _wlmtk_container_impl_t { - /** dtor. */ - void (*destroy)(wlmtk_container_t *container_ptr); +struct _wlmtk_container_vmt_t { /** * Updates the layout of the container elements. * @@ -45,7 +43,8 @@ struct _wlmtk_container_impl_t { * Additionally, this should be invoked by contained elements when * the visibility or dimensions change. * - * Each container will propagate a wlmtk_container_impl::update_layout call + * Each container will propagate a + * @ref wlmtk_container_vmt_t::update_layout call * upwards to it's parent container. The root container will then trigger * an update to pointer focus (since by then, the layout is updated). */ @@ -59,12 +58,12 @@ struct _wlmtk_container_t { /** Virtual method table of the super element before extending it. */ wlmtk_element_vmt_t orig_super_element_vmt; + /** Virtual method table for the container. */ + wlmtk_container_vmt_t vmt; + /** Elements contained here. */ bs_dllist_t elements; - /** Implementation of the container's virtual methods. */ - wlmtk_container_impl_t impl; - /** Scene tree. */ struct wlr_scene_tree *wlr_scene_tree_ptr; @@ -81,26 +80,33 @@ struct _wlmtk_container_t { * Initializes the container with the provided virtual method table. * * @param container_ptr - * @param container_impl_ptr * * @return true on success. */ -bool wlmtk_container_init( +bool wlmtk_container_init(wlmtk_container_t *container_ptr); + +/** + * Extends the container's virtual methods. + * + * @param container_ptr + * @param container_vmt_ptr + * + * @return The previous virtual method table. + */ +wlmtk_container_vmt_t wlmtk_container_extend( wlmtk_container_t *container_ptr, - const wlmtk_container_impl_t *container_impl_ptr); + const wlmtk_container_vmt_t *container_vmt_ptr); /** * Initializes the container, and attach to WLR sene graph. * * @param container_ptr - * @param container_impl_ptr * @param root_wlr_scene_tree_ptr * * @return true on success. */ bool wlmtk_container_init_attached( wlmtk_container_t *container_ptr, - const wlmtk_container_impl_t *container_impl_ptr, struct wlr_scene_tree *root_wlr_scene_tree_ptr); /** @@ -158,10 +164,9 @@ void wlmtk_container_remove_element( * @param container_ptr Container to update. NULL implies a no-op. */ static inline void wlmtk_container_update_layout( - wlmtk_container_t *container_ptr) { - if (NULL != container_ptr) { - container_ptr->impl.update_layout(container_ptr); - } + wlmtk_container_t *container_ptr) +{ + container_ptr->vmt.update_layout(container_ptr); } /** @@ -176,20 +181,13 @@ static inline void wlmtk_container_update_layout( struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( wlmtk_container_t *container_ptr); -/** Virtual method: Calls the dtor of the container's implementation. */ -static inline void wlmtk_container_destroy( - wlmtk_container_t *container_ptr) { - container_ptr->impl.destroy(container_ptr); -} - /** Unit tests for the container. */ extern const bs_test_case_t wlmtk_container_test_cases[]; -/** Implementation table of a "fake" container for tests. */ -extern const wlmtk_container_impl_t wlmtk_container_fake_impl; - /** Constructor for a fake container with a scene tree. */ wlmtk_container_t *wlmtk_container_create_fake_parent(void); +/** Destructor for that fake container. */ +void wlmtk_container_destroy_fake_parent(wlmtk_container_t *container_ptr); #ifdef __cplusplus } // extern "C" diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 1d103500..236d7c54 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -304,6 +304,9 @@ bool element_pointer_motion( wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); + // FIXME + if (NULL == content_ptr->super_element.wlr_scene_node_ptr) return false; + // Get the layout local coordinates of the node, so we can adjust the // node-local (x, y) for the `wlr_scene_node_at` call. int lx, ly; diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 6a76e701..9b771cad 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -198,7 +198,9 @@ void wlmtk_element_set_visible(wlmtk_element_t *element_ptr, bool visible) wlr_scene_node_set_enabled(element_ptr->wlr_scene_node_ptr, visible); } - wlmtk_container_update_layout(element_ptr->parent_container_ptr); + if (NULL != element_ptr->parent_container_ptr) { + wlmtk_container_update_layout(element_ptr->parent_container_ptr); + } } /* ------------------------------------------------------------------------- */ @@ -492,9 +494,7 @@ void test_set_parent_container(bs_test_t *test_ptr) // Setting a parent without a scene graph tree will not set a node. wlmtk_container_t parent_no_tree; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_container_init(&parent_no_tree, &wlmtk_container_fake_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&parent_no_tree)); wlmtk_element_set_parent_container(&element, &parent_no_tree); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); @@ -527,8 +527,8 @@ void test_set_parent_container(bs_test_t *test_ptr) wlmtk_element_set_parent_container(&element, NULL); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); - wlmtk_container_destroy(other_parent_ptr); - wlmtk_container_destroy(parent_ptr); + wlmtk_container_destroy_fake_parent(other_parent_ptr); + wlmtk_container_destroy_fake_parent(parent_ptr); wlmtk_element_fini(&element); } @@ -566,7 +566,7 @@ void test_set_get_position(bs_test_t *test_ptr) wlmtk_element_set_parent_container(&element, NULL); wlmtk_element_fini(&element); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 95bee006..22169637 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -56,14 +56,14 @@ struct _wlmtk_resizebar_t { wlmtk_resizebar_area_t *right_area_ptr; }; -static void resizebar_box_destroy(wlmtk_box_t *box_ptr); +static void _wlmtk_resizebar_element_destroy(wlmtk_element_t *element_ptr); static bool redraw_buffers(wlmtk_resizebar_t *resizebar_ptr, unsigned width); /* == Data ================================================================= */ -/** Method table for the box's virtual methods. */ -static const wlmtk_box_impl_t resizebar_box_impl = { - .destroy = resizebar_box_destroy +/** Virtual method table extension for the resizebar's element superclass. */ +static const wlmtk_element_vmt_t resizebar_element_vmt = { + .destroy = _wlmtk_resizebar_element_destroy, }; /* == Exported methods ===================================================== */ @@ -79,11 +79,14 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( memcpy(&resizebar_ptr->style, style_ptr, sizeof(wlmtk_resizebar_style_t)); if (!wlmtk_box_init(&resizebar_ptr->super_box, - &resizebar_box_impl, + NULL, WLMTK_BOX_HORIZONTAL)) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } + wlmtk_element_extend( + &resizebar_ptr->super_box.super_container.super_element, + &resizebar_element_vmt); resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( window_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); @@ -238,11 +241,12 @@ wlmtk_element_t *wlmtk_resizebar_element(wlmtk_resizebar_t *resizebar_ptr) /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Virtual destructor, in case called from box. Wraps to our dtor. */ -void resizebar_box_destroy(wlmtk_box_t *box_ptr) +/** Virtual destructor: Wraps to our dtor. */ +void _wlmtk_resizebar_element_destroy(wlmtk_element_t *element_ptr) { wlmtk_resizebar_t *resizebar_ptr = BS_CONTAINER_OF( - box_ptr, wlmtk_resizebar_t, super_box); + element_ptr, wlmtk_resizebar_t, + super_box.super_container.super_element); wlmtk_resizebar_destroy(resizebar_ptr); } diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 160caaeb..1d24b665 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -68,7 +68,7 @@ struct _wlmtk_titlebar_t { wlmtk_titlebar_style_t style; }; -static void titlebar_box_destroy(wlmtk_box_t *box_ptr); +static void _wlmtk_titlebar_element_destroy(wlmtk_element_t *element_ptr); static bool redraw_buffers( wlmtk_titlebar_t *titlebar_ptr, unsigned width); @@ -76,9 +76,9 @@ static bool redraw(wlmtk_titlebar_t *titlebar_ptr); /* == Data ================================================================= */ -/** Method table for the box's virtual methods. */ -static const wlmtk_box_impl_t titlebar_box_impl = { - .destroy = titlebar_box_destroy +/** Virtual method table extension for the titlebar's element superclass. */ +static const wlmtk_element_vmt_t titlebar_element_vmt = { + .destroy = _wlmtk_titlebar_element_destroy }; /* == Exported methods ===================================================== */ @@ -95,11 +95,14 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); if (!wlmtk_box_init(&titlebar_ptr->super_box, - &titlebar_box_impl, + NULL, WLMTK_BOX_HORIZONTAL)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } + wlmtk_element_extend( + &titlebar_ptr->super_box.super_container.super_element, + &titlebar_element_vmt); titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create(window_ptr); if (NULL == titlebar_ptr->titlebar_title_ptr) { @@ -240,11 +243,12 @@ wlmtk_element_t *wlmtk_titlebar_element(wlmtk_titlebar_t *titlebar_ptr) /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Virtual destructor, in case called from box. Wraps to our dtor. */ -void titlebar_box_destroy(wlmtk_box_t *box_ptr) +/** Virtual destructor, wraps to our dtor. */ +void _wlmtk_titlebar_element_destroy(wlmtk_element_t *element_ptr) { wlmtk_titlebar_t *titlebar_ptr = BS_CONTAINER_OF( - box_ptr, wlmtk_titlebar_t, super_box); + element_ptr, wlmtk_titlebar_t, + super_box.super_container.super_element); wlmtk_titlebar_destroy(titlebar_ptr); } diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 0b7facaf..7674e040 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -82,6 +82,7 @@ static void release_update( wlmtk_window_t *window_ptr, wlmtk_pending_update_t *update_ptr); +static void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr); static void box_update_layout(wlmtk_box_t *box_ptr); static void window_box_destroy(wlmtk_box_t *box_ptr); @@ -93,6 +94,11 @@ static const wlmtk_box_impl_t window_box_impl = { .update_layout = box_update_layout, }; +/** Virtual method table for the window's container superclass. */ +static const wlmtk_container_vmt_t window_container_vmt = { + .update_layout = _wlmtk_box_update_layout, +}; + /** Default methods of @ref wlmtk_window_t. To override for a mock. */ static const wlmtk_window_impl_t window_default_impl = { .destroy = wlmtk_window_destroy, @@ -188,6 +194,9 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_fini(window_ptr); return false; } + window_ptr->orig_super_container_vmt = wlmtk_container_extend( + &window_ptr->super_box.super_container, &window_container_vmt); + wlmtk_window_set_title(window_ptr, NULL); window_ptr->resizebar_ptr = wlmtk_resizebar_create( @@ -633,6 +642,35 @@ void release_update( bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); } +/* ------------------------------------------------------------------------- */ +/** + * Implementation of @ref wlmtk_container_vmt_t::update_layout. + * + * Invoked when the window's contained elements triggered a layout update, + * and will use this to trigger (potential) size updates to the window + * decorations. + * + * @param container_ptr + */ +void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_window_t, super_box.super_container); + + window_ptr->orig_super_container_vmt.update_layout(container_ptr); + + if (NULL != window_ptr->content_ptr) { + int width; + wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); + } + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); + } + } +} + /* ------------------------------------------------------------------------- */ /** * Implementation of @ref wlmtk_box_impl_t::update_layout. diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 56a7ed2c..dac3a8c6 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -92,6 +92,9 @@ typedef struct { struct _wlmtk_window_t { /** Superclass: Box. */ wlmtk_box_t super_box; + /** Original virtual method table of the box' container superclass. */ + wlmtk_container_vmt_t orig_super_container_vmt; + /** Virtual method table. */ wlmtk_window_impl_t impl; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 0e16cfc7..d20ef99b 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -61,8 +61,7 @@ struct _wlmtk_workspace_t { uint32_t resize_edges; }; -static void workspace_container_destroy(wlmtk_container_t *container_ptr); - +static void _wlmtk_workspace_element_destroy(wlmtk_element_t *element_ptr); static bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -100,13 +99,9 @@ typedef enum { PFSME_RESET, } pointer_state_event_t; -/** Method table for the container's virtual methods. */ -const wlmtk_container_impl_t workspace_container_impl = { - .destroy = workspace_container_destroy -}; - /** Extensions to the workspace's super element's virtual methods. */ const wlmtk_element_vmt_t workspace_element_vmt = { + .destroy = _wlmtk_workspace_element_destroy, .pointer_motion = element_pointer_motion, .pointer_button = element_pointer_button, .pointer_leave = element_pointer_leave, @@ -136,7 +131,6 @@ wlmtk_workspace_t *wlmtk_workspace_create( if (NULL == workspace_ptr) return NULL; if (!wlmtk_container_init_attached(&workspace_ptr->super_container, - &workspace_container_impl, wlr_scene_tree_ptr)) { wlmtk_workspace_destroy(workspace_ptr); return NULL; @@ -208,7 +202,8 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_workspace_t *wlmtk_workspace_from_container( wlmtk_container_t *container_ptr) { - BS_ASSERT(container_ptr->impl.destroy == workspace_container_impl.destroy); + BS_ASSERT(container_ptr->super_element.vmt.destroy == + _wlmtk_workspace_element_destroy); return BS_CONTAINER_OF(container_ptr, wlmtk_workspace_t, super_container); } @@ -276,11 +271,11 @@ void wlmtk_workspace_begin_window_resize( /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Virtual destructor, in case called from container. Wraps to our dtor. */ -void workspace_container_destroy(wlmtk_container_t *container_ptr) +/** Virtual destructor, wraps to our dtor. */ +void _wlmtk_workspace_element_destroy(wlmtk_element_t *element_ptr) { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_workspace_t, super_container); + element_ptr, wlmtk_workspace_t, super_container.super_element); wlmtk_workspace_destroy(workspace_ptr); } @@ -534,7 +529,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_workspace_from_container(&workspace_ptr->super_container)); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -577,7 +572,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -636,7 +631,7 @@ void test_button(bs_test_t *test_ptr) wlmtk_element_destroy(&fake_element_ptr->element); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -682,7 +677,7 @@ void test_move(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -726,7 +721,7 @@ void test_unmap_during_move(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -782,7 +777,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -840,7 +835,7 @@ void test_activate(bs_test_t *test_ptr) wlmtk_fake_window_destroy(fw2_ptr); wlmtk_fake_window_destroy(fw1_ptr); wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy(fake_parent_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* == End of workspace.c =================================================== */ From ccc83507fdec72138b4a2071610187a0439ff20d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 16:10:57 +0100 Subject: [PATCH 244/390] Moves wlmtk_box_t to using the virtual method table(s). --- src/toolkit/box.c | 35 ++++++--------------------- src/toolkit/box.h | 23 ------------------ src/toolkit/resizebar.c | 4 +--- src/toolkit/titlebar.c | 4 +--- src/toolkit/window.c | 52 ++++------------------------------------- 5 files changed, 13 insertions(+), 105 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index c8c87c08..87887881 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -37,23 +37,17 @@ static const wlmtk_container_vmt_t box_container_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - const wlmtk_box_impl_t *box_impl_ptr, wlmtk_box_orientation_t orientation) { BS_ASSERT(NULL != box_ptr); + memset(box_ptr, 0, sizeof(wlmtk_box_t)); if (!wlmtk_container_init(&box_ptr->super_container)) { return false; } box_ptr->orig_super_container_vmt = wlmtk_container_extend( &box_ptr->super_container, &box_container_vmt); - if (NULL != box_impl_ptr) { - BS_ASSERT(NULL != box_impl_ptr); - BS_ASSERT(NULL != box_impl_ptr->destroy); - memcpy(&box_ptr->impl, box_impl_ptr, sizeof(wlmtk_box_impl_t)); - } box_ptr->orientation = orientation; - return true; } @@ -114,11 +108,6 @@ void _wlmtk_box_container_update_layout( // We do this only after having updated the position of the elements. box_ptr->orig_super_container_vmt.update_layout(container_ptr); - // Forward to virtual methods, if any. - if (NULL != box_ptr->impl.update_layout) { - box_ptr->impl.update_layout(box_ptr); - } - // configure parent container. if (NULL != container_ptr->super_element.parent_container_ptr) { wlmtk_container_update_layout( @@ -139,23 +128,13 @@ const bs_test_case_t wlmtk_box_test_cases[] = { { 0, NULL, NULL } }; -/** dtor for the testcase. */ -static void test_box_destroy(wlmtk_box_t *box_ptr) { - wlmtk_box_fini(box_ptr); -} -/** A testcase box implementation. */ -static const wlmtk_box_impl_t test_box_impl = { - .destroy = test_box_destroy, -}; - /* ------------------------------------------------------------------------- */ /** Exercises setup and teardown. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, &test_box_impl, WLMTK_BOX_HORIZONTAL); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, box.impl.destroy); - box.impl.destroy(&box); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_box_init(&box, WLMTK_BOX_HORIZONTAL)); + wlmtk_box_fini(&box); } /* ------------------------------------------------------------------------- */ @@ -163,7 +142,7 @@ void test_init_fini(bs_test_t *test_ptr) void test_layout_horizontal(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, &test_box_impl, WLMTK_BOX_HORIZONTAL); + wlmtk_box_init(&box, WLMTK_BOX_HORIZONTAL); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); @@ -208,7 +187,7 @@ void test_layout_horizontal(bs_test_t *test_ptr) wlmtk_element_destroy(&e3_ptr->element); wlmtk_element_destroy(&e2_ptr->element); wlmtk_element_destroy(&e1_ptr->element); - box.impl.destroy(&box); + wlmtk_box_fini(&box); } /* ------------------------------------------------------------------------- */ @@ -216,7 +195,7 @@ void test_layout_horizontal(bs_test_t *test_ptr) void test_layout_vertical(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, &test_box_impl, WLMTK_BOX_VERTICAL); + wlmtk_box_init(&box, WLMTK_BOX_VERTICAL); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); @@ -244,7 +223,7 @@ void test_layout_vertical(bs_test_t *test_ptr) wlmtk_element_destroy(&e2_ptr->element); wlmtk_element_destroy(&e1_ptr->element); - box.impl.destroy(&box); + wlmtk_box_fini(&box); } /* == End of box.c ========================================================= */ diff --git a/src/toolkit/box.h b/src/toolkit/box.h index d1553af5..545c4294 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -22,8 +22,6 @@ /** Forward declaration: Box. */ typedef struct _wlmtk_box_t wlmtk_box_t; -/** Forward declaration: Box virtual method implementations. */ -typedef struct _wlmtk_box_impl_t wlmtk_box_impl_t; #include "container.h" @@ -31,23 +29,6 @@ typedef struct _wlmtk_box_impl_t wlmtk_box_impl_t; extern "C" { #endif // __cplusplus -/** Virtual method table of the box. */ -struct _wlmtk_box_impl_t { - /** dtor. */ - void (*destroy)(wlmtk_box_t *box_ptr); - /** - * Updates the layout of the elements. - * - * The box's @ref _wlmtk_box_container_update_layout method will invoke - * this optional method when a contained element changes visibility, - * dimensions or was added or removed. - * A derived class (eg. a window) can use this eg. to recompute dimensions - * of window decorations, when eg. a call to @ref wlmtk_content_commit_size - * had committed an update to the window content's dimensions. - */ - void (*update_layout)(wlmtk_box_t *box_ptr); -}; - /** Orientation of the box. */ typedef enum { WLMTK_BOX_HORIZONTAL, @@ -60,8 +41,6 @@ struct _wlmtk_box_t { wlmtk_container_t super_container; /** Virtual method table of the superclass' container. */ wlmtk_container_vmt_t orig_super_container_vmt; - /** Virtual method table of the box. */ - wlmtk_box_impl_t impl; /** Orientation of the box. */ wlmtk_box_orientation_t orientation; }; @@ -70,14 +49,12 @@ struct _wlmtk_box_t { * Initializes the box with the provided virtual method table. * * @param box_ptr - * @param box_impl_ptr * @param orientation * * @return true on success. */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - const wlmtk_box_impl_t *box_impl_ptr, wlmtk_box_orientation_t orientation); /** diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 22169637..95800ec1 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -78,9 +78,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( if (NULL == resizebar_ptr) return NULL; memcpy(&resizebar_ptr->style, style_ptr, sizeof(wlmtk_resizebar_style_t)); - if (!wlmtk_box_init(&resizebar_ptr->super_box, - NULL, - WLMTK_BOX_HORIZONTAL)) { + if (!wlmtk_box_init(&resizebar_ptr->super_box, WLMTK_BOX_HORIZONTAL)) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 1d24b665..920d46e0 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -94,9 +94,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); - if (!wlmtk_box_init(&titlebar_ptr->super_box, - NULL, - WLMTK_BOX_HORIZONTAL)) { + if (!wlmtk_box_init(&titlebar_ptr->super_box, WLMTK_BOX_HORIZONTAL)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7674e040..60bff739 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -83,17 +83,9 @@ static void release_update( wlmtk_pending_update_t *update_ptr); static void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr); -static void box_update_layout(wlmtk_box_t *box_ptr); -static void window_box_destroy(wlmtk_box_t *box_ptr); /* == Data ================================================================= */ -/** Method table for the box's virtual methods. */ -static const wlmtk_box_impl_t window_box_impl = { - .destroy = window_box_destroy, - .update_layout = box_update_layout, -}; - /** Virtual method table for the window's container superclass. */ static const wlmtk_container_vmt_t window_container_vmt = { .update_layout = _wlmtk_box_update_layout, @@ -188,9 +180,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, &window_ptr->pre_allocated_updates[i].dlnode); } - if (!wlmtk_box_init(&window_ptr->super_box, - &window_box_impl, - WLMTK_BOX_VERTICAL)) { + if (!wlmtk_box_init(&window_ptr->super_box, WLMTK_BOX_VERTICAL)) { wlmtk_window_fini(window_ptr); return false; } @@ -319,7 +309,9 @@ wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) // DEBT: FIXME - The assertion here is too lose. wlmtk_window_t *window_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_window_t, super_box.super_container.super_element); - BS_ASSERT(window_box_destroy == window_ptr->super_box.impl.destroy); + + BS_ASSERT(_wlmtk_box_update_layout == + window_ptr->super_box.super_container.vmt.update_layout); return window_ptr; } @@ -671,42 +663,6 @@ void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr) } } -/* ------------------------------------------------------------------------- */ -/** - * Implementation of @ref wlmtk_box_impl_t::update_layout. - * - * Invoked when the window's contained elements triggered a layout update, - * and will use this to trigger (potential) size updates to the window - * decorations. - * - * @param box_ptr - */ -void box_update_layout(wlmtk_box_t *box_ptr) -{ - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - box_ptr, wlmtk_window_t, super_box); - - if (NULL != window_ptr->content_ptr) { - int width; - wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); - } - if (NULL != window_ptr->resizebar_ptr) { - wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); - } - } -} - -/* ------------------------------------------------------------------------- */ -/** Virtual destructor, in case called from box. Wraps to our dtor. */ -void window_box_destroy(wlmtk_box_t *box_ptr) -{ - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - box_ptr, wlmtk_window_t, super_box); - window_ptr->impl.destroy(window_ptr); -} - /* == Virtual method implementation for the fake window ==================== */ /* ------------------------------------------------------------------------- */ From 60e3455f5e1c71e64030a979555fb5f3e0a8d5cc Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 16:41:43 +0100 Subject: [PATCH 245/390] Applies the virtual method table to wlmtk_buffer_t and throughout. --- src/toolkit/buffer.c | 81 +---------------------------------- src/toolkit/buffer.h | 25 +---------- src/toolkit/button.c | 75 +++++++++++++++----------------- src/toolkit/button.h | 3 +- src/toolkit/resizebar_area.c | 59 ++++++++++++++----------- src/toolkit/titlebar_button.c | 16 +++++-- src/toolkit/titlebar_title.c | 38 ++++++++-------- 7 files changed, 104 insertions(+), 193 deletions(-) diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index ed394be0..6aac7b92 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -28,7 +28,6 @@ /* == Declarations ========================================================= */ -static void element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); @@ -42,40 +41,21 @@ static void handle_wlr_scene_buffer_node_destroy( struct wl_listener *listener_ptr, void *data_ptr); -static bool element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, double y, - uint32_t time_msec); -static bool element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); -static void element_pointer_leave( - wlmtk_element_t *element_ptr); - /* == Data ================================================================= */ /** Method table for the buffer's virtual methods. */ static const wlmtk_element_vmt_t buffer_element_vmt = { - .destroy = element_destroy, .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, - .pointer_motion = element_pointer_motion, - .pointer_button = element_pointer_button, - .pointer_leave = element_pointer_leave, }; /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_buffer_init( - wlmtk_buffer_t *buffer_ptr, - const wlmtk_buffer_impl_t *buffer_impl_ptr) +bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr) { BS_ASSERT(NULL != buffer_ptr); memset(buffer_ptr, 0, sizeof(wlmtk_buffer_t)); - BS_ASSERT(NULL != buffer_impl_ptr); - BS_ASSERT(NULL != buffer_impl_ptr->destroy); - memcpy(&buffer_ptr->impl, buffer_impl_ptr, sizeof(wlmtk_buffer_impl_t)); if (!wlmtk_element_init(&buffer_ptr->super_element)) { return false; @@ -125,21 +105,6 @@ void wlmtk_buffer_set( /* == Local (static) methods =============================================== */ -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the superclass wlmtk_element_t::destroy method. - * - * Forwards the call to the wlmtk_buffer_t::destroy method. - * - * @param element_ptr - */ -void element_destroy(wlmtk_element_t *element_ptr) -{ - wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_buffer_t, super_element); - buffer_ptr->impl.destroy(buffer_ptr); -} - /* ------------------------------------------------------------------------- */ /** * Implementation of the superclass wlmtk_element_t::create_scene_node method. @@ -223,48 +188,4 @@ void handle_wlr_scene_buffer_node_destroy( wl_list_remove(&buffer_ptr->wlr_scene_buffer_node_destroy_listener.link); } -/* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_vmt_t::pointer_motion. */ -bool element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, double y, - uint32_t time_msec) -{ - wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_buffer_t, super_element); - buffer_ptr->orig_super_element_vmt.pointer_motion( - element_ptr, x, y, time_msec); - - if (NULL == buffer_ptr->impl.pointer_motion) return true; - return buffer_ptr->impl.pointer_motion(buffer_ptr, x, y, time_msec); -} - -/* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_vmt_t::pointer_button. */ -bool element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr) -{ - wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_buffer_t, super_element); - buffer_ptr->orig_super_element_vmt.pointer_button( - element_ptr, button_event_ptr); - - if (NULL == buffer_ptr->impl.pointer_button) return false; - return buffer_ptr->impl.pointer_button(buffer_ptr, button_event_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_vmt_t::pointer_leave. */ -void element_pointer_leave( - wlmtk_element_t *element_ptr) -{ - wlmtk_buffer_t *buffer_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_buffer_t, super_element); - buffer_ptr->orig_super_element_vmt.pointer_leave(element_ptr); - - if (NULL == buffer_ptr->impl.pointer_leave) return; - buffer_ptr->impl.pointer_leave(buffer_ptr); -} - /* == End of buffer.c ====================================================== */ diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index 31f65950..ef9eab90 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -38,23 +38,6 @@ struct wlr_scene_buffer; extern "C" { #endif // __cplusplus -/** Method table of the buffer. */ -// FIXME: Make this obsolete through extending element. -struct _wlmtk_buffer_impl_t { - /** Destroys the implementation of the buffer. */ - void (*destroy)(wlmtk_buffer_t *buffer_ptr); - - /** Optional. See @ref wlmtk_element_vmt_t::pointer_motion. */ - bool (*pointer_motion)(wlmtk_buffer_t *buffer_ptr, - double x, double y, - uint32_t time_msec); - /** Optional. See @ref wlmtk_element_vmt_t::pointer_button. */ - bool (*pointer_button)(wlmtk_buffer_t *buffer_ptr, - const wlmtk_button_event_t *button_event_ptr); - /** Optional. See @ref wlmtk_element_vmt_t::pointer_leave. */ - void (*pointer_leave)(wlmtk_buffer_t *buffer_ptr); -}; - /** State of a texture-backed buffer. */ struct _wlmtk_buffer_t { /** Super class of the buffer: An element. */ @@ -62,9 +45,6 @@ struct _wlmtk_buffer_t { /** Virtual method table of the super element before extending it. */ wlmtk_element_vmt_t orig_super_element_vmt; - /** Implementation of abstract virtual methods. */ - wlmtk_buffer_impl_t impl; - /** WLR buffer holding the contents. */ struct wlr_buffer *wlr_buffer_ptr; /** Scene graph API node. Only set after calling `create_scene_node`. */ @@ -78,13 +58,10 @@ struct _wlmtk_buffer_t { * Initializes the buffer. * * @param buffer_ptr - * @param buffer_impl_ptr * * @return true on success. */ -bool wlmtk_buffer_init( - wlmtk_buffer_t *buffer_ptr, - const wlmtk_buffer_impl_t *buffer_impl_ptr); +bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr); /** * Cleans up the buffer. diff --git a/src/toolkit/button.c b/src/toolkit/button.c index c7d16b0d..db1d80ab 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -30,26 +30,25 @@ /* == Declarations ========================================================= */ -static void button_buffer_destroy(wlmtk_buffer_t *buffer_ptr); -static bool buffer_pointer_motion( - wlmtk_buffer_t *buffer_ptr, +static bool _wlmtk_button_element_pointer_motion( + wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static bool buffer_pointer_button( - wlmtk_buffer_t *buffer_ptr, +static bool _wlmtk_button_element_pointer_button( + wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); -static void buffer_pointer_leave( - wlmtk_buffer_t *buffer_ptr); +static void _wlmtk_button_element_pointer_leave( + wlmtk_element_t *element_ptr); + static void apply_state(wlmtk_button_t *button_ptr); /* == Data ================================================================= */ -/** Virtual method table for @ref wlmtk_button_t::super_buffer. */ -static const wlmtk_buffer_impl_t button_buffer_impl = { - .destroy = button_buffer_destroy, - .pointer_motion = buffer_pointer_motion, - .pointer_button = buffer_pointer_button, - .pointer_leave = buffer_pointer_leave, +/** Virtual method table for the button's element super class. */ +static const wlmtk_element_vmt_t button_element_vmt = { + .pointer_motion = _wlmtk_button_element_pointer_motion, + .pointer_button = _wlmtk_button_element_pointer_button, + .pointer_leave = _wlmtk_button_element_pointer_leave, }; /* == Exported methods ===================================================== */ @@ -62,15 +61,15 @@ bool wlmtk_button_init( BS_ASSERT(NULL != button_ptr); memset(button_ptr, 0, sizeof(wlmtk_button_t)); BS_ASSERT(NULL != button_impl_ptr); - BS_ASSERT(NULL != button_impl_ptr->destroy); memcpy(&button_ptr->impl, button_impl_ptr, sizeof(wlmtk_button_impl_t)); - if (!wlmtk_buffer_init( - &button_ptr->super_buffer, - &button_buffer_impl)) { + if (!wlmtk_buffer_init(&button_ptr->super_buffer)) { wlmtk_button_fini(button_ptr); return false; } + button_ptr->orig_super_element_vmt = wlmtk_element_extend( + &button_ptr->super_buffer.super_element, + &button_element_vmt); return true; } @@ -123,37 +122,30 @@ void wlmtk_button_set( /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Destructor: Wraps to @ref wlmtk_button_impl_t::destroy. */ -void button_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +/** See @ref wlmtk_element_vmt_t::pointer_motion. */ +bool _wlmtk_button_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + uint32_t time_msec) { wlmtk_button_t *button_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_button_t, super_buffer); - button_ptr->impl.destroy(button_ptr); -} + element_ptr, wlmtk_button_t, super_buffer.super_element); -/* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_buffer_impl_t::pointer_motion. */ -bool buffer_pointer_motion( - wlmtk_buffer_t *buffer_ptr, - __UNUSED__ double x, - __UNUSED__ double y, - __UNUSED__ uint32_t time_msec) -{ - wlmtk_button_t *button_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_button_t, super_buffer); + button_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); button_ptr->pointer_inside = true; apply_state(button_ptr); return true; } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_buffer_impl_t::pointer_button. */ -bool buffer_pointer_button( - wlmtk_buffer_t *buffer_ptr, +/** See @ref wlmtk_element_vmt_t::pointer_button. */ +bool _wlmtk_button_element_pointer_button( + wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { wlmtk_button_t *button_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_button_t, super_buffer); + element_ptr, wlmtk_button_t, super_buffer.super_element); if (button_event_ptr->button != BTN_LEFT) return false; @@ -182,13 +174,14 @@ bool buffer_pointer_button( } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_buffer_impl_t::pointer_leave. */ -void buffer_pointer_leave( - wlmtk_buffer_t *buffer_ptr) +/** See @ref wlmtk_element_vmt_t::pointer_leave. */ +void _wlmtk_button_element_pointer_leave( + wlmtk_element_t *element_ptr) { wlmtk_button_t *button_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_button_t, super_buffer); + element_ptr, wlmtk_button_t, super_buffer.super_element); + button_ptr->orig_super_element_vmt.pointer_leave(element_ptr); button_ptr->pointer_inside = false; apply_state(button_ptr); } @@ -249,7 +242,7 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_button_init(&button, &fake_button_impl)); - wlmtk_element_destroy(&button.super_buffer.super_element); + wlmtk_button_fini(&button); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/button.h b/src/toolkit/button.h index a2f42699..6cead16c 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -43,7 +43,8 @@ typedef struct { struct _wlmtk_button_t { /** Super class of the button: A buffer. */ wlmtk_buffer_t super_buffer; - + /** Original virtual method table of the superclass element. */ + wlmtk_element_vmt_t orig_super_element_vmt; /** Implementation of abstract virtual methods. */ wlmtk_button_impl_t impl; diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 9222b663..1576d4db 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -40,6 +40,8 @@ struct _wlmtk_resizebar_area_t { /** Superclass: Buffer. */ wlmtk_buffer_t super_buffer; + /** Original virtual method table of the superclass element. */ + wlmtk_element_vmt_t orig_super_element_vmt; /** WLR buffer holding the buffer in released state. */ struct wlr_buffer *released_wlr_buffer_ptr; @@ -62,13 +64,14 @@ struct _wlmtk_resizebar_area_t { const char *xcursor_name_ptr; }; -static void buffer_destroy(wlmtk_buffer_t *buffer_ptr); -static bool buffer_pointer_motion( - wlmtk_buffer_t *buffer_ptr, +static void _wlmtk_resizebar_area_element_destroy( + wlmtk_element_t *element_ptr); +static bool _wlmtk_resizebar_area_element_pointer_motion( + wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static bool buffer_pointer_button( - wlmtk_buffer_t *buffer_ptr, +static bool _wlmtk_resizebar_area_element_pointer_button( + wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); static void draw_state(wlmtk_resizebar_area_t *resizebar_area_ptr); @@ -79,13 +82,13 @@ static struct wlr_buffer *create_buffer( const wlmtk_resizebar_style_t *style_ptr, bool pressed); -/* == Data ================================================================= */ +/* ========================================================================= */ /** Buffer implementation for title of the title bar. */ -static const wlmtk_buffer_impl_t area_buffer_impl = { - .destroy = buffer_destroy, - .pointer_motion = buffer_pointer_motion, - .pointer_button = buffer_pointer_button, +static const wlmtk_element_vmt_t resizebar_area_element_vmt = { + .destroy = _wlmtk_resizebar_area_element_destroy, + .pointer_motion = _wlmtk_resizebar_area_element_pointer_motion, + .pointer_button = _wlmtk_resizebar_area_element_pointer_button, }; /* == Exported methods ===================================================== */ @@ -117,12 +120,13 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( bs_log(BS_ERROR, "Unsupported edge %"PRIx32, edges); } - if (!wlmtk_buffer_init( - &resizebar_area_ptr->super_buffer, - &area_buffer_impl)) { + if (!wlmtk_buffer_init(&resizebar_area_ptr->super_buffer)) { wlmtk_resizebar_area_destroy(resizebar_area_ptr); return NULL; } + resizebar_area_ptr->orig_super_element_vmt = wlmtk_element_extend( + &resizebar_area_ptr->super_buffer.super_element, + &resizebar_area_element_vmt); draw_state(resizebar_area_ptr); return resizebar_area_ptr; @@ -192,23 +196,26 @@ wlmtk_element_t *wlmtk_resizebar_area_element( /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Dtor. Forwards to @ref wlmtk_resizebar_area_destroy. */ -void buffer_destroy(wlmtk_buffer_t *buffer_ptr) +/** Dtor. */ +void _wlmtk_resizebar_area_element_destroy(wlmtk_element_t *element_ptr) { wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_resizebar_area_t, super_buffer); + element_ptr, wlmtk_resizebar_area_t, super_buffer.super_element); wlmtk_resizebar_area_destroy(resizebar_area_ptr); } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_buffer_impl_t::pointer_motion. */ -bool buffer_pointer_motion( - wlmtk_buffer_t *buffer_ptr, - __UNUSED__ double x, __UNUSED__ double y, - __UNUSED__ uint32_t time_msec) +/** See @ref wlmtk_element_vmt_t::pointer_motion. */ +bool _wlmtk_resizebar_area_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec) { wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_resizebar_area_t, super_buffer); + element_ptr, wlmtk_resizebar_area_t, super_buffer.super_element); + resizebar_area_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); // TODO(kaeser@gubbe.ch): Inject something testable here. if (NULL != resizebar_area_ptr->wlr_cursor_ptr && @@ -222,13 +229,13 @@ bool buffer_pointer_motion( } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_buffer_impl_t::pointer_button. */ -bool buffer_pointer_button( - wlmtk_buffer_t *buffer_ptr, +/** See @ref wlmtk_element_vmt_t::pointer_button. */ +bool _wlmtk_resizebar_area_element_pointer_button( + wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { wlmtk_resizebar_area_t *resizebar_area_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_resizebar_area_t, super_buffer); + element_ptr, wlmtk_resizebar_area_t, super_buffer.super_element); if (button_event_ptr->button != BTN_LEFT) return false; diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index dca7bc02..677b63c5 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -52,7 +52,7 @@ struct _wlmtk_titlebar_button_t { struct wlr_buffer *blurred_wlr_buffer_ptr; }; -static void titlebar_button_destroy(wlmtk_button_t *button_ptr); +static void titlebar_button_element_destroy(wlmtk_element_t *element_ptr); static void titlebar_button_clicked(wlmtk_button_t *button_ptr); static void update_buffers(wlmtk_titlebar_button_t *titlebar_button_ptr); static struct wlr_buffer *create_buf( @@ -66,10 +66,14 @@ static struct wlr_buffer *create_buf( /** Buffer implementation for title of the title bar. */ static const wlmtk_button_impl_t titlebar_button_impl = { - .destroy = titlebar_button_destroy, .clicked = titlebar_button_clicked, }; +/** Extension to the superclass element's virtual method table. */ +static const wlmtk_element_vmt_t titlebar_button_element_vmt = { + .destroy = titlebar_button_element_destroy, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -94,6 +98,9 @@ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( wlmtk_titlebar_button_destroy(titlebar_button_ptr); return NULL; } + wlmtk_element_extend( + &titlebar_button_ptr->super_button.super_buffer.super_element, + &titlebar_button_element_vmt); return titlebar_button_ptr; } @@ -183,10 +190,11 @@ wlmtk_element_t *wlmtk_titlebar_button_element( /* ------------------------------------------------------------------------- */ /** Virtual destructor, wraps to @ref wlmtk_titlebar_button_destroy. */ -void titlebar_button_destroy(wlmtk_button_t *button_ptr) +void titlebar_button_element_destroy(wlmtk_element_t *element_ptr) { wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( - button_ptr, wlmtk_titlebar_button_t, super_button); + element_ptr, wlmtk_titlebar_button_t, + super_button.super_buffer.super_element); wlmtk_titlebar_button_destroy(titlebar_button_ptr); } diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index b384b94d..e7ecfdf2 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -44,10 +44,12 @@ struct _wlmtk_titlebar_title_t { struct wlr_buffer *blurred_wlr_buffer_ptr; }; -static void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr); -static bool title_buffer_pointer_button( - wlmtk_buffer_t *buffer_ptr, +static void _wlmtk_titlebar_title_element_destroy( + wlmtk_element_t *element_ptr); +static bool _wlmtk_titlebar_title_element_pointer_button( + wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); + static void title_set_activated( wlmtk_titlebar_title_t *titlebar_title_ptr, bool activated); @@ -61,10 +63,10 @@ struct wlr_buffer *title_create_buffer( /* == Data ================================================================= */ -/** Buffer implementation for title of the title bar. */ -static const wlmtk_buffer_impl_t title_buffer_impl = { - .destroy = title_buffer_destroy, - .pointer_button = title_buffer_pointer_button, +/** Extension to the superclass elment's virtual method table. */ +static const wlmtk_element_vmt_t titlebar_title_element_vmt = { + .destroy = _wlmtk_titlebar_title_element_destroy, + .pointer_button = _wlmtk_titlebar_title_element_pointer_button, }; /* == Exported methods ===================================================== */ @@ -78,12 +80,13 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( if (NULL == titlebar_title_ptr) return NULL; titlebar_title_ptr->window_ptr = window_ptr; - if (!wlmtk_buffer_init( - &titlebar_title_ptr->super_buffer, - &title_buffer_impl)) { + if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer)) { wlmtk_titlebar_title_destroy(titlebar_title_ptr); return NULL; } + wlmtk_element_extend( + &titlebar_title_ptr->super_buffer.super_element, + &titlebar_title_element_vmt); return titlebar_title_ptr; } @@ -157,22 +160,23 @@ wlmtk_element_t *wlmtk_titlebar_title_element( /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Dtor. Forwards to @ref wlmtk_titlebar_title_destroy. */ -void title_buffer_destroy(wlmtk_buffer_t *buffer_ptr) +/** Dtor. */ +void _wlmtk_titlebar_title_element_destroy( + wlmtk_element_t *element_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_titlebar_title_t, super_buffer); + element_ptr, wlmtk_titlebar_title_t, super_buffer.super_element); wlmtk_titlebar_title_destroy(titlebar_title_ptr); } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_buffer_impl_t::pointer_button. */ -bool title_buffer_pointer_button( - wlmtk_buffer_t *buffer_ptr, +/** See @ref wlmtk_element_vmt_t::pointer_button. */ +bool _wlmtk_titlebar_title_element_pointer_button( + wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = BS_CONTAINER_OF( - buffer_ptr, wlmtk_titlebar_title_t, super_buffer); + element_ptr, wlmtk_titlebar_title_t, super_buffer.super_element); if (button_event_ptr->button != BTN_LEFT) return false; From 520217fc0da9b782cf29ab9f3c12dfc2bde2dcff Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 16:59:58 +0100 Subject: [PATCH 246/390] Applies virtual method table to button and derivates. --- src/toolkit/button.c | 55 +++++++++++++++++++++++------------ src/toolkit/button.h | 26 ++++++++++------- src/toolkit/titlebar_button.c | 17 ++++++----- 3 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index db1d80ab..001f466e 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -30,6 +30,8 @@ /* == Declarations ========================================================= */ +static void _wlmtk_button_clicked(wlmtk_button_t *button_ptr); + static bool _wlmtk_button_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -51,17 +53,19 @@ static const wlmtk_element_vmt_t button_element_vmt = { .pointer_leave = _wlmtk_button_element_pointer_leave, }; +/** Virtual method table for the button. */ +static const wlmtk_button_vmt_t button_vmt = { + .clicked = _wlmtk_button_clicked, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_button_init( - wlmtk_button_t *button_ptr, - const wlmtk_button_impl_t *button_impl_ptr) +bool wlmtk_button_init(wlmtk_button_t *button_ptr) { BS_ASSERT(NULL != button_ptr); memset(button_ptr, 0, sizeof(wlmtk_button_t)); - BS_ASSERT(NULL != button_impl_ptr); - memcpy(&button_ptr->impl, button_impl_ptr, sizeof(wlmtk_button_impl_t)); + button_ptr->vmt = button_vmt; if (!wlmtk_buffer_init(&button_ptr->super_buffer)) { wlmtk_button_fini(button_ptr); @@ -74,6 +78,20 @@ bool wlmtk_button_init( return true; } +/* ------------------------------------------------------------------------- */ +wlmtk_button_vmt_t wlmtk_button_extend( + wlmtk_button_t *button_ptr, + const wlmtk_button_vmt_t *button_vmt_ptr) +{ + wlmtk_button_vmt_t orig_vmt = button_ptr->vmt; + + if (NULL != button_vmt_ptr->clicked) { + button_ptr->vmt.clicked = button_vmt_ptr->clicked; + } + + return orig_vmt; +} + /* ------------------------------------------------------------------------- */ void wlmtk_button_fini(wlmtk_button_t *button_ptr) { @@ -121,6 +139,13 @@ void wlmtk_button_set( /* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_button_vmt_t::clicked. Nothing. */ +void _wlmtk_button_clicked(__UNUSED__ wlmtk_button_t *button_ptr) +{ + // Nothing. +} + /* ------------------------------------------------------------------------- */ /** See @ref wlmtk_element_vmt_t::pointer_motion. */ bool _wlmtk_button_element_pointer_motion( @@ -161,9 +186,7 @@ bool _wlmtk_button_element_pointer_button( break; case WLMTK_BUTTON_CLICK: - if (NULL != button_ptr->impl.clicked) { - button_ptr->impl.clicked(button_ptr); - } + button_ptr->vmt.clicked(button_ptr); break; default: @@ -220,16 +243,13 @@ const bs_test_case_t wlmtk_button_test_cases[] = { /** Test outcome: Whether 'clicked' was called. */ static bool fake_button_got_clicked = false; -/** Fake destructor. */ -static void fake_button_destroy(__UNUSED__ wlmtk_button_t *button_ptr) {} /** Fake 'clicked' handler. */ static void fake_button_clicked(__UNUSED__ wlmtk_button_t *button_ptr) { fake_button_got_clicked = true; } /** Virtual method table of fake button. */ -const wlmtk_button_impl_t fake_button_impl = { - .destroy = fake_button_destroy, +static const wlmtk_button_vmt_t fake_button_vmt = { .clicked = fake_button_clicked, }; @@ -239,9 +259,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_TEST_VERIFY_TRUE( - test_ptr, - wlmtk_button_init(&button, &fake_button_impl)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_button_init(&button)); wlmtk_button_fini(&button); } @@ -250,7 +268,8 @@ void test_create_destroy(bs_test_t *test_ptr) void test_press_release(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_ASSERT(wlmtk_button_init(&button, &fake_button_impl)); + BS_ASSERT(wlmtk_button_init(&button)); + wlmtk_button_extend(&button, &fake_button_vmt); struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); @@ -308,7 +327,7 @@ void test_press_release(bs_test_t *test_ptr) void test_press_release_outside(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_ASSERT(wlmtk_button_init(&button, &fake_button_impl)); + BS_ASSERT(wlmtk_button_init(&button)); struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); @@ -355,7 +374,7 @@ void test_press_release_outside(bs_test_t *test_ptr) void test_press_right(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_ASSERT(wlmtk_button_init(&button, &fake_button_impl)); + BS_ASSERT(wlmtk_button_init(&button)); struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 6cead16c..33fa1e37 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -30,14 +30,11 @@ extern "C" { /** Forward declaration: State of a button. */ typedef struct _wlmtk_button_t wlmtk_button_t; -/** Method table of the button. */ +/** Virtual method table of the button. */ typedef struct { - /** Destroys the implementation of the button. */ - void (*destroy)(wlmtk_button_t *button_ptr); - /** Optional: Called when the button has been clicked. */ void (*clicked)(wlmtk_button_t *button_ptr); -} wlmtk_button_impl_t; +} wlmtk_button_vmt_t; /** State of a button. */ struct _wlmtk_button_t { @@ -45,8 +42,8 @@ struct _wlmtk_button_t { wlmtk_buffer_t super_buffer; /** Original virtual method table of the superclass element. */ wlmtk_element_vmt_t orig_super_element_vmt; - /** Implementation of abstract virtual methods. */ - wlmtk_button_impl_t impl; + /** The virtual method table. */ + wlmtk_button_vmt_t vmt; /** WLR buffer holding the button in released state. */ struct wlr_buffer *released_wlr_buffer_ptr; @@ -64,13 +61,22 @@ struct _wlmtk_button_t { * Initializes the button. * * @param button_ptr - * @param button_impl_ptr * * @return true on success. */ -bool wlmtk_button_init( +bool wlmtk_button_init(wlmtk_button_t *button_ptr); + +/** + * Extends the button's virtual methods. + * + * @param button_ptr + * @param button_vmt_ptr + * + * @return The original virtual method table. + */ +wlmtk_button_vmt_t wlmtk_button_extend( wlmtk_button_t *button_ptr, - const wlmtk_button_impl_t *button_impl_ptr); + const wlmtk_button_vmt_t *button_vmt_ptr); /** * Cleans up the button. diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 677b63c5..313cba9e 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -64,16 +64,16 @@ static struct wlr_buffer *create_buf( /* == Data ================================================================= */ -/** Buffer implementation for title of the title bar. */ -static const wlmtk_button_impl_t titlebar_button_impl = { - .clicked = titlebar_button_clicked, -}; - /** Extension to the superclass element's virtual method table. */ static const wlmtk_element_vmt_t titlebar_button_element_vmt = { .destroy = titlebar_button_element_destroy, }; +/** Extension to the parent button class' virtual methods. */ +static const wlmtk_button_vmt_t titlebar_button_vmt = { + .clicked = titlebar_button_clicked, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -92,15 +92,16 @@ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( titlebar_button_ptr->window_ptr = window_ptr; titlebar_button_ptr->draw = draw; - if (!wlmtk_button_init( - &titlebar_button_ptr->super_button, - &titlebar_button_impl)) { + if (!wlmtk_button_init(&titlebar_button_ptr->super_button)) { wlmtk_titlebar_button_destroy(titlebar_button_ptr); return NULL; } wlmtk_element_extend( &titlebar_button_ptr->super_button.super_buffer.super_element, &titlebar_button_element_vmt); + wlmtk_button_extend( + &titlebar_button_ptr->super_button, + &titlebar_button_vmt); return titlebar_button_ptr; } From 3342030ae6d25d5bedcdfad7efb1d4da2574a56c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 17:00:57 +0100 Subject: [PATCH 247/390] Removes forward definition of buffer impl. --- src/toolkit/buffer.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index ef9eab90..36d78ba9 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -24,8 +24,6 @@ /** Forward declaration: Buffer state. */ typedef struct _wlmtk_buffer_t wlmtk_buffer_t; -/** Forward declaration: Buffer implementation. */ -typedef struct _wlmtk_buffer_impl_t wlmtk_buffer_impl_t; #include "element.h" From cf0f8abae7baf902652e184acb61f5bf728ac3d3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 17:23:19 +0100 Subject: [PATCH 248/390] Applies virtual method table for content and derived classes. --- src/toolkit/content.c | 110 +++++++++++++-------------------------- src/toolkit/content.h | 63 +++++++++++----------- src/toolkit/window.c | 2 +- src/wlmtk_xdg_toplevel.c | 40 ++++++++------ 4 files changed, 94 insertions(+), 121 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 236d7c54..8b211cd6 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -30,10 +30,6 @@ /* == Declarations ========================================================= */ -static void element_destroy(wlmtk_element_t *element_ptr); -static struct wlr_scene_node *element_create_scene_node( - wlmtk_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); static void element_get_dimensions( wlmtk_element_t *element_ptr, int *left_ptr, @@ -60,8 +56,6 @@ static bool element_pointer_button( /** Method table for the container's virtual methods. */ static const wlmtk_element_vmt_t content_element_vmt = { - .destroy = element_destroy, - .create_scene_node = element_create_scene_node, .get_dimensions = element_get_dimensions, .get_pointer_area = element_get_pointer_area, .pointer_leave = element_pointer_leave, @@ -76,17 +70,10 @@ void *wlmtk_content_identifier_ptr = wlmtk_content_init; /* ------------------------------------------------------------------------- */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - const wlmtk_content_impl_t *content_impl_ptr, struct wlr_seat *wlr_seat_ptr) { BS_ASSERT(NULL != content_ptr); memset(content_ptr, 0, sizeof(wlmtk_content_t)); - BS_ASSERT(NULL != content_impl_ptr); - BS_ASSERT(NULL != content_impl_ptr->destroy); - BS_ASSERT(NULL != content_impl_ptr->create_scene_node); - BS_ASSERT(NULL != content_impl_ptr->request_close); - BS_ASSERT(NULL != content_impl_ptr->request_size); - BS_ASSERT(NULL != content_impl_ptr->set_activated); if (!wlmtk_element_init(&content_ptr->super_element)) { return false; @@ -96,11 +83,29 @@ bool wlmtk_content_init( content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; - - memcpy(&content_ptr->impl, content_impl_ptr, sizeof(wlmtk_content_impl_t)); return true; } +/* ------------------------------------------------------------------------- */ +wlmtk_content_vmt_t wlmtk_content_extend( + wlmtk_content_t *content_ptr, + const wlmtk_content_vmt_t *content_vmt_ptr) +{ + wlmtk_content_vmt_t orig_vmt = content_ptr->vmt; + + if (NULL != content_vmt_ptr->request_close) { + content_ptr->vmt.request_close = content_vmt_ptr->request_close; + } + if (NULL != content_vmt_ptr->request_size) { + content_ptr->vmt.request_size = content_vmt_ptr->request_size; + } + if (NULL != content_vmt_ptr->set_activated) { + content_ptr->vmt.set_activated = content_vmt_ptr->set_activated; + } + + return orig_vmt; +} + /* ------------------------------------------------------------------------- */ void wlmtk_content_fini(wlmtk_content_t *content_ptr) { @@ -157,40 +162,6 @@ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr) /* == Local (static) methods =============================================== */ -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the superclass wlmtk_element_t::destroy method. - * - * Forwards the call to the wlmtk_content_t::destroy method. - * - * @param element_ptr - */ -void element_destroy(wlmtk_element_t *element_ptr) -{ - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - content_ptr->impl.destroy(content_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the superclass wlmtk_element_t::create_scene_node method. - * - * Forwards the call to the wlmtk_content_t::create_scene_node method. - * - * @param element_ptr - * @param wlr_scene_tree_ptr - */ -struct wlr_scene_node *element_create_scene_node( - wlmtk_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr) -{ - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - return content_ptr->impl.create_scene_node( - content_ptr, wlr_scene_tree_ptr); -} - /* ------------------------------------------------------------------------- */ /** * Implementation of the element's get_dimensions method: Return dimensions. @@ -389,9 +360,9 @@ bool element_pointer_button( /* == Fake content, useful for unit tests. ================================= */ static void fake_content_destroy( - wlmtk_content_t *content_ptr); + wlmtk_element_t *element_ptr); static struct wlr_scene_node *fake_content_create_scene_node( - wlmtk_content_t *content_ptr, + wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); static void fake_content_request_close( wlmtk_content_t *content_ptr); @@ -414,21 +385,20 @@ static bool fake_content_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); -/** Method table of the fake content. */ -static const wlmtk_content_impl_t wlmtk_fake_content_impl = { - .destroy = fake_content_destroy, - .create_scene_node = fake_content_create_scene_node, - .request_close = fake_content_request_close, - .request_size = fake_content_request_size, - .set_activated = fake_content_set_activated, -}; - /** Extensions to the content's super elements virtual methods. */ static const wlmtk_element_vmt_t fake_content_element_vmt = { + .destroy = fake_content_destroy, + .create_scene_node = fake_content_create_scene_node, .pointer_motion = fake_content_element_pointer_motion, .pointer_button = fake_content_element_pointer_button, .pointer_leave = fake_content_element_pointer_leave, }; +/** Extensions to the content's virtual methods. */ +static const wlmtk_content_vmt_t fake_content_vmt = { + .request_close = fake_content_request_close, + .request_size = fake_content_request_size, + .set_activated = fake_content_set_activated, +}; /* ------------------------------------------------------------------------- */ wlmtk_fake_content_t *wlmtk_fake_content_create(void) @@ -437,15 +407,11 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) 1, sizeof(wlmtk_fake_content_t)); if (NULL == fake_content_ptr) return NULL; - if (!wlmtk_content_init(&fake_content_ptr->content, - &wlmtk_fake_content_impl, - NULL)) { + if (!wlmtk_content_init(&fake_content_ptr->content, NULL)) { free(fake_content_ptr); return NULL; } - - BS_ASSERT(NULL != fake_content_ptr->content.super_element.vmt.destroy); - BS_ASSERT(NULL != fake_content_ptr->content.impl.destroy); + wlmtk_content_extend(&fake_content_ptr->content, &fake_content_vmt); fake_content_ptr->orig_super_element_vmt = wlmtk_element_extend( &fake_content_ptr->content.super_element, &fake_content_element_vmt); @@ -454,22 +420,19 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) /* ------------------------------------------------------------------------- */ /** Dtor for the fake content. */ -void fake_content_destroy(wlmtk_content_t *content_ptr) +void fake_content_destroy(wlmtk_element_t *element_ptr) { wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_fake_content_t, content); + element_ptr, wlmtk_fake_content_t, content.super_element); wlmtk_content_fini(&fake_content_ptr->content); - - // Also expect the super element to be un-initialized. - BS_ASSERT(NULL == fake_content_ptr->content.impl.destroy); free(fake_content_ptr); } /* ------------------------------------------------------------------------- */ /** Creates a scene node for the fake content. */ struct wlr_scene_node *fake_content_create_scene_node( - __UNUSED__ wlmtk_content_t *content_ptr, + __UNUSED__ wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( @@ -567,9 +530,6 @@ void test_init_fini(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, fake_content_ptr->content.super_element.vmt.destroy); - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, - fake_content_ptr->content.impl.destroy); wlmtk_content_request_close(&fake_content_ptr->content); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 5c28e8e5..1c37a875 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -23,8 +23,8 @@ /** Forward declaration: Window content. */ typedef struct _wlmtk_content_t wlmtk_content_t; -/** Forward declaration: Content virtual method implementations. */ -typedef struct _wlmtk_content_impl_t wlmtk_content_impl_t; +/** Forward declaration: Content virtual method table. */ +typedef struct _wlmtk_content_vmt_t wlmtk_content_vmt_t; /** Forward declaration: Fake content, for tests. */ typedef struct _wlmtk_fake_content_t wlmtk_fake_content_t; @@ -35,20 +35,14 @@ typedef struct _wlmtk_fake_content_t wlmtk_fake_content_t; extern "C" { #endif // __cplusplus -/** Method table of the content. */ -struct _wlmtk_content_impl_t { - /** Destroys the implementation of the content. */ - void (*destroy)(wlmtk_content_t *content_ptr); - /** Creates content's scene graph API node, child to wlr_scene_tree_ptr. */ - struct wlr_scene_node *(*create_scene_node)( - wlmtk_content_t *content_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); - /** Requests the content to close. */ +/** The content's virtual method table. */ +struct _wlmtk_content_vmt_t { + /** Abstract: Requests the content to close. */ void (*request_close)(wlmtk_content_t *content_ptr); - /** Sets width and height of the content. Returns serial. */ + /** Abstract: Sets width and height of the content. Returns serial. */ uint32_t (*request_size)(wlmtk_content_t *content_ptr, int width, int height); - /** Sets whether the content is activated (has keyboard focus). */ + /** Abstract: Sets whether the content is activated (keyboard focus). */ void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); }; @@ -62,8 +56,8 @@ struct _wlmtk_content_t { /** Virtual method table of the super element before extending it. */ wlmtk_element_vmt_t orig_super_element_vmt; - /** Implementation of abstract virtual methods. */ - wlmtk_content_impl_t impl; + /** Virtual method table of the content. */ + wlmtk_content_vmt_t vmt; /** * The window this content belongs to. Will be set when creating @@ -91,16 +85,26 @@ struct _wlmtk_content_t { * Initializes the content. * * @param content_ptr - * @param content_impl_ptr * @param wlr_seat_ptr * * @return true on success. */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - const wlmtk_content_impl_t *content_impl_ptr, struct wlr_seat *wlr_seat_ptr); +/** + * Extends the content's virtual methods. + * + * @param content_ptr + * @param content_vmt_ptr + * + * @return The original virtual method table. + */ +wlmtk_content_vmt_t wlmtk_content_extend( + wlmtk_content_t *content_ptr, + const wlmtk_content_vmt_t *content_vmt_ptr); + /** * Cleans up the content. * @@ -162,26 +166,25 @@ void wlmtk_content_get_size( */ wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); -/** Wraps to @ref wlmtk_content_impl_t::destroy. */ -static inline void wlmtk_content_destroy(wlmtk_content_t *content_ptr) { - content_ptr->impl.destroy(content_ptr); -} -/** Wraps to @ref wlmtk_content_impl_t::request_close. */ -static inline void wlmtk_content_request_close(wlmtk_content_t *content_ptr) { - content_ptr->impl.request_close(content_ptr); +/** Wraps to @ref wlmtk_content_vmt_t::request_close. */ +static inline void wlmtk_content_request_close(wlmtk_content_t *content_ptr) +{ + content_ptr->vmt.request_close(content_ptr); } -/** Wraps to @ref wlmtk_content_impl_t::request_size. */ +/** Wraps to @ref wlmtk_content_vmt_t::request_size. */ static inline uint32_t wlmtk_content_request_size( wlmtk_content_t *content_ptr, int width, - int height) { - return content_ptr->impl.request_size(content_ptr, width, height); + int height) +{ + return content_ptr->vmt.request_size(content_ptr, width, height); } -/** Wraps to @ref wlmtk_content_impl_t::set_activated. */ +/** Wraps to @ref wlmtk_content_vmt_t::set_activated. */ static inline void wlmtk_content_set_activated( wlmtk_content_t *content_ptr, - bool activated) { - content_ptr->impl.set_activated(content_ptr, activated); + bool activated) +{ + content_ptr->vmt.set_activated(content_ptr, activated); } /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 60bff739..f2e05c86 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -256,7 +256,7 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) wlmtk_content_element(window_ptr->content_ptr), false); wlmtk_content_set_window(window_ptr->content_ptr, NULL); - wlmtk_content_destroy(window_ptr->content_ptr); + wlmtk_element_destroy(wlmtk_content_element(window_ptr->content_ptr)); window_ptr->content_ptr = NULL; } diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index b4c3c465..234f50f0 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -76,9 +76,9 @@ static void handle_toplevel_set_title( struct wl_listener *listener_ptr, void *data_ptr); -static void content_destroy(wlmtk_content_t *content_ptr); -static struct wlr_scene_node *content_create_scene_node( - wlmtk_content_t *content_ptr, +static void content_element_destroy(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *content_element_create_scene_node( + wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); static void content_request_close( wlmtk_content_t *content_ptr); @@ -92,16 +92,19 @@ static void content_set_activated( /* == Data ================================================================= */ -/** Method table for the `wlmtk_content_t` virtual methods. */ -const wlmtk_content_impl_t content_impl = { - .destroy = content_destroy, - .create_scene_node = content_create_scene_node, +/** Virtual methods for XDG toplevel content, for the Element superclass. */ +const wlmtk_element_vmt_t _wlmtk_xdg_toplevel_element_vmt = { + .destroy = content_element_destroy, + .create_scene_node = content_element_create_scene_node, +}; + +/** Virtual methods for XDG toplevel content, for the Content superclass. */ +const wlmtk_content_vmt_t _wlmtk_xdg_toplevel_content_vmt = { .request_close = content_request_close, .request_size = content_request_size, .set_activated = content_set_activated, }; - /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -118,7 +121,7 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( server_ptr->cursor_ptr->wlr_xcursor_manager_ptr, &content_ptr->super_content); if (NULL == wlmtk_window_ptr) { - wlmtk_content_destroy(&content_ptr->super_content); + content_element_destroy(&content_ptr->super_content.super_element); return NULL; } @@ -137,11 +140,16 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( if (NULL == xdg_tl_content_ptr) return NULL; if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, - &content_impl, server_ptr->wlr_seat_ptr)) { xdg_toplevel_content_destroy(xdg_tl_content_ptr); return NULL; } + wlmtk_element_extend( + &xdg_tl_content_ptr->super_content.super_element, + &_wlmtk_xdg_toplevel_element_vmt); + wlmtk_content_extend( + &xdg_tl_content_ptr->super_content, + &_wlmtk_xdg_toplevel_content_vmt); xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; xdg_tl_content_ptr->server_ptr = server_ptr; @@ -204,10 +212,11 @@ void xdg_toplevel_content_destroy( * * @param content_ptr */ -void content_destroy(wlmtk_content_t *content_ptr) +void content_element_destroy(wlmtk_element_t *element_ptr) { wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + element_ptr, wlmtk_xdg_toplevel_content_t, + super_content.super_element); xdg_toplevel_content_destroy(xdg_tl_content_ptr); } @@ -220,12 +229,13 @@ void content_destroy(wlmtk_content_t *content_ptr) * * @return Scene graph API node that represents the content. */ -struct wlr_scene_node *content_create_scene_node( - wlmtk_content_t *content_ptr, +struct wlr_scene_node *content_element_create_scene_node( + wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + element_ptr, wlmtk_xdg_toplevel_content_t, + super_content.super_element); struct wlr_scene_tree *surface_wlr_scene_tree_ptr = wlr_scene_xdg_surface_create( From e18678980fcaa0227c4f8747a36b2c560e25c312 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 17:52:20 +0100 Subject: [PATCH 249/390] Activates window on click, but test is broken. --- src/toolkit/window.c | 34 ++++++++++++++++++++++- src/toolkit/window.h | 4 ++- src/toolkit/workspace.c | 60 ++++++++++++++++++++--------------------- src/toolkit/workspace.h | 5 ++++ 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f2e05c86..7c11b3ea 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -29,7 +29,11 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_content_t *content_ptr); void wlmtk_window_fini(wlmtk_window_t *window_ptr); -static void wlmtk_window_set_activated_impl( +static bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); + + static void wlmtk_window_set_activated_impl( wlmtk_window_t *window_ptr, bool activated); static void wlmtk_window_set_server_side_decorated_impl( @@ -86,6 +90,10 @@ static void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr); /* == Data ================================================================= */ +/** Virtual method table for the window's element superclass. */ +static const wlmtk_element_vmt_t window_element_vmt = { + .pointer_button = _wlmtk_window_element_pointer_button, +}; /** Virtual method table for the window's container superclass. */ static const wlmtk_container_vmt_t window_container_vmt = { .update_layout = _wlmtk_box_update_layout, @@ -184,6 +192,9 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_fini(window_ptr); return false; } + window_ptr->orig_super_element_vmt = wlmtk_element_extend( + &window_ptr->super_box.super_container.super_element, + &window_element_vmt); window_ptr->orig_super_container_vmt = wlmtk_container_extend( &window_ptr->super_box.super_container, &window_container_vmt); @@ -488,6 +499,27 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) /* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** Activates window on button press, and calls the parent's implementation. */ +bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_window_t, super_box.super_container.super_element); + + // We shouldn't receive buttons when not mapped. + BS_ASSERT( + NULL != + window_ptr->super_box.super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_box.super_container.super_element.parent_container_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + + return window_ptr->orig_super_element_vmt.pointer_button( + element_ptr, button_event_ptr); +} + /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_set_activated. */ void wlmtk_window_set_activated_impl( diff --git a/src/toolkit/window.h b/src/toolkit/window.h index dac3a8c6..d8e5a877 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -92,7 +92,9 @@ typedef struct { struct _wlmtk_window_t { /** Superclass: Box. */ wlmtk_box_t super_box; - /** Original virtual method table of the box' container superclass. */ + /** Original virtual method table of the window's element superclass. */ + wlmtk_element_vmt_t orig_super_element_vmt; + /** Original virtual method table of the window' container superclass. */ wlmtk_container_vmt_t orig_super_container_vmt; /** Virtual method table. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index d20ef99b..21ebc4d0 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -78,9 +78,6 @@ static bool pfsm_resize_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); static bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); -static void activate_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); - /* == Data ================================================================= */ /** States of the pointer FSM. */ @@ -159,7 +156,7 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, &workspace_ptr->super_container, wlmtk_window_element(window_ptr)); - activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); } /* ------------------------------------------------------------------------- */ @@ -177,7 +174,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, } if (workspace_ptr->activated_window_ptr == window_ptr) { - activate_window(workspace_ptr, NULL); + wlmtk_workspace_activate_window(workspace_ptr, NULL); need_activation = true; } @@ -193,7 +190,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, if (NULL != dlnode_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); wlmtk_window_t *window_ptr = wlmtk_window_from_element(element_ptr); - activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); } } } @@ -268,6 +265,30 @@ void wlmtk_workspace_begin_window_resize( wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_RESIZE, window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Acticates `window_ptr`. Will de-activate an earlier window. */ +void wlmtk_workspace_activate_window( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) +{ + // Nothing to do. + if (workspace_ptr->activated_window_ptr == window_ptr) return; + + if (NULL != workspace_ptr->activated_window_ptr) { + wlmtk_window_set_activated(workspace_ptr->activated_window_ptr, false); + workspace_ptr->activated_window_ptr = NULL; + } + + if (NULL != window_ptr) { + wlmtk_window_set_activated(window_ptr, true); + workspace_ptr->activated_window_ptr = window_ptr; + } + // set activated. + // keep track of activated. => so it can be deactivated. + + +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -468,29 +489,6 @@ bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) return true; } -/* ------------------------------------------------------------------------- */ -/** Acticates `window_ptr`. Will de-activate an earlier window. */ -void activate_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr) -{ - // Nothing to do. - if (workspace_ptr->activated_window_ptr == window_ptr) return; - - if (NULL != workspace_ptr->activated_window_ptr) { - wlmtk_window_set_activated(workspace_ptr->activated_window_ptr, false); - workspace_ptr->activated_window_ptr = NULL; - } - - if (NULL != window_ptr) { - wlmtk_window_set_activated(window_ptr, true); - workspace_ptr->activated_window_ptr = window_ptr; - } - // set activated. - // keep track of activated. => so it can be deactivated. - - -} - /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); @@ -792,6 +790,7 @@ void test_activate(bs_test_t *test_ptr) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); + wlmtk_element_set_position(wlmtk_window_element(&fw1_ptr->window), 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); // Window 1 is mapped => it's activated. @@ -801,6 +800,7 @@ void test_activate(bs_test_t *test_ptr) // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); + wlmtk_element_set_position(wlmtk_window_element(&fw1_ptr->window), 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_workspace_map_window(workspace_ptr, &fw2_ptr->window); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); @@ -820,7 +820,7 @@ void test_activate(bs_test_t *test_ptr) wlmtk_workspace_button(workspace_ptr, &wlr_button_event); // FIXME: These are broken. - // BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); // BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); // Unmap window. The other one gets activated. diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index f7cf09c0..a49eee7b 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -143,6 +143,11 @@ void wlmtk_workspace_begin_window_resize( wlmtk_window_t *window_ptr, uint32_t edges); +/** Acticates `window_ptr`. Will de-activate an earlier window. */ +void wlmtk_workspace_activate_window( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; From ffe87ceda079eb9f4d745c2d8d079ee0f5da8ded Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 20:10:23 +0100 Subject: [PATCH 250/390] Fixes error in test for window activtation. --- src/toolkit/element.c | 2 ++ src/toolkit/workspace.c | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 9b771cad..ac4a6a8e 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -227,6 +227,8 @@ void wlmtk_element_set_position( element_ptr->x, element_ptr->y); } + + // FIXME: We should probably update the layout? } /* == Local (static) methods =============================================== */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 21ebc4d0..a3ebec48 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -788,6 +788,7 @@ void test_activate(bs_test_t *test_ptr) fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); + // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); wlmtk_element_set_position(wlmtk_window_element(&fw1_ptr->window), 0, 0); @@ -797,40 +798,39 @@ void test_activate(bs_test_t *test_ptr) wlmtk_workspace_map_window(workspace_ptr, &fw1_ptr->window); BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); + // Window 2: from (200, 0) to (300, 100). // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_element_set_position(wlmtk_window_element(&fw1_ptr->window), 200, 0); + wlmtk_element_set_position(wlmtk_window_element(&fw2_ptr->window), 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_workspace_map_window(workspace_ptr, &fw2_ptr->window); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Pointer move. Nothing happens: We have click-to-focus. + // Pointer move, over window 1. Nothing happens: We have click-to-focus. BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_workspace_motion(workspace_ptr, 50, 50, 0)); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Click on 1st window: Gets activated. + // Click on window 1: Gets activated. struct wlr_pointer_button_event wlr_button_event = { .button = BTN_RIGHT, .state = WLR_BUTTON_PRESSED }; wlmtk_workspace_button(workspace_ptr, &wlr_button_event); - - // FIXME: These are broken. BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); - // BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - - // Unmap window. The other one gets activated. - wlmtk_workspace_unmap_window(workspace_ptr, &fw2_ptr->window); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); - // Unmap the remaining window. Nothing is activated. + // Unmap window 1. Now window 2 gets activated. wlmtk_workspace_unmap_window(workspace_ptr, &fw1_ptr->window); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); + + // Unmap the remaining window 2. Nothing is activated. + wlmtk_workspace_unmap_window(workspace_ptr, &fw2_ptr->window); + BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_fake_window_destroy(fw2_ptr); wlmtk_fake_window_destroy(fw1_ptr); From 8c1c3990e26de9214189fde8e6a8dbddf89b2422 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 20:58:56 +0100 Subject: [PATCH 251/390] Adds a bit more verbosity on the FIXME. --- src/toolkit/workspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index a3ebec48..34396080 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -184,7 +184,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_element(window_ptr)); if (need_activation) { - // FIXME + // FIXME: What about raising? bs_dllist_node_t *dlnode_ptr = workspace_ptr->super_container.elements.head_ptr; if (NULL != dlnode_ptr) { From 228f210c4fe1cab79b50b7663c92f768701c2ad6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 21:04:05 +0100 Subject: [PATCH 252/390] Minor cleanup: Container test uses fake element in test. --- src/toolkit/container.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index b3ccf5a6..44ceb044 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -721,12 +721,10 @@ void test_add_remove(bs_test_t *test_ptr) /** Tests that elements are attached, resp. detached from scene graph. */ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) { - wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container)); - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_parent_ptr); - + wlmtk_container_t container; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container)); wlmtk_element_set_parent_container( &container.super_element, fake_parent_ptr); @@ -734,21 +732,21 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, container.super_element.wlr_scene_node_ptr); - // FIXME: Should use fake_element! - wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); - wlmtk_element_extend(&element, &fake_element_vmt); + // Fresh element: No scene graph node yet. + wlmtk_fake_element_t *fe_ptr = wlmtk_fake_element_create(); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe_ptr->element.wlr_scene_node_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); - wlmtk_container_add_element(&container, &element); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.wlr_scene_node_ptr); + // Add to container with attached graph: Element now has a graph node. + wlmtk_container_add_element(&container, &fe_ptr->element); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe_ptr->element.wlr_scene_node_ptr); - wlmtk_container_remove_element(&container, &element); - BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); + // Remove: The element's graph node must be destroyed & cleared.. + wlmtk_container_remove_element(&container, &fe_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe_ptr->element.wlr_scene_node_ptr); + wlmtk_element_destroy(&fe_ptr->element); wlmtk_element_set_parent_container(&container.super_element, NULL); wlmtk_container_fini(&container); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); } From e0240726fc039c5c32ed28db53b9d366e94ca2e8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 21:04:42 +0100 Subject: [PATCH 253/390] Internalizes fake_element_vmt. --- src/toolkit/element.c | 2 +- src/toolkit/element.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index ac4a6a8e..8d759d52 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -325,7 +325,7 @@ static void fake_pointer_leave( wlmtk_element_t *element_ptr); /** Virtual method table for the fake element. */ -const wlmtk_element_vmt_t fake_element_vmt = { +static const wlmtk_element_vmt_t fake_element_vmt = { .destroy = fake_destroy, .create_scene_node = fake_create_scene_node, .get_dimensions = fake_get_dimensions, diff --git a/src/toolkit/element.h b/src/toolkit/element.h index ac5572ad..6a043a38 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -365,9 +365,6 @@ typedef struct { /** Ctor for the fake element. */ wlmtk_fake_element_t *wlmtk_fake_element_create(void); -/** Implementation table of a "fake" element for tests. */ -extern const wlmtk_element_vmt_t fake_element_vmt; - #ifdef __cplusplus } // extern "C" #endif // __cplusplus From bad92bdb056f3ea9c3d9e23f7ae390f03a071a05 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 24 Nov 2023 21:07:08 +0100 Subject: [PATCH 254/390] Improves doxygen comment on wlmtk_fake_element_create. --- src/toolkit/element.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 6a043a38..2f7144b5 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -362,7 +362,13 @@ typedef struct { wlmtk_button_event_t pointer_button_event; } wlmtk_fake_element_t; -/** Ctor for the fake element. */ +/** + * Ctor for the fake element, useful for tests. + * + * @return A pointer to @ref wlmtk_fake_element_t. Should be destroyed via + * @ref wlmtk_element_destroy, by passing the pointer to + * @ref wlmtk_fake_element_t::element as argument. + */ wlmtk_fake_element_t *wlmtk_fake_element_create(void); #ifdef __cplusplus From 280d52783a74233737100a9cc754c5fe59d61743 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 25 Nov 2023 17:40:05 +0100 Subject: [PATCH 255/390] Removes some whitespace. --- src/toolkit/box.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 87887881..af6f1a1f 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -81,7 +81,6 @@ void _wlmtk_box_container_update_layout( wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); if (!element_ptr->visible) continue; - int left, top, right, bottom; wlmtk_element_get_dimensions(element_ptr, &left, &top, &right, &bottom); int x, y; From 8f909f2fa7cbeb6801d25a0335930466b47da667 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 25 Nov 2023 17:40:42 +0100 Subject: [PATCH 256/390] Implements and tests situation where element moves under the pointer focus. --- src/toolkit/container.c | 65 +++++++++++++++++++++++++++++++++++++---- src/toolkit/container.h | 7 +++++ src/toolkit/element.c | 7 ++++- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 44ceb044..97d18175 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -215,6 +215,21 @@ void wlmtk_container_remove_element( BS_ASSERT(element_ptr != container_ptr->pointer_focus_element_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_container_update_pointer_focus(wlmtk_container_t *container_ptr) +{ + if (NULL != container_ptr->super_element.parent_container_ptr) { + wlmtk_container_update_pointer_focus( + container_ptr->super_element.parent_container_ptr); + } else { + update_pointer_focus_at( + container_ptr, + container_ptr->super_element.last_pointer_x, + container_ptr->super_element.last_pointer_y, + container_ptr->super_element.last_pointer_time_msec); + } +} + /* ------------------------------------------------------------------------- */ struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( wlmtk_container_t *container_ptr) @@ -567,11 +582,7 @@ void _wlmtk_container_update_layout(wlmtk_container_t *container_ptr) wlmtk_container_update_layout( container_ptr->super_element.parent_container_ptr); } else { - update_pointer_focus_at( - container_ptr, - container_ptr->super_element.last_pointer_x, - container_ptr->super_element.last_pointer_y, - container_ptr->super_element.last_pointer_time_msec); + wlmtk_container_update_pointer_focus(container_ptr); } } @@ -635,6 +646,7 @@ static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); static void test_pointer_motion(bs_test_t *test_ptr); static void test_pointer_focus(bs_test_t *test_ptr); +static void test_pointer_focus_move(bs_test_t *test_ptr); static void test_pointer_focus_layered(bs_test_t *test_ptr); static void test_pointer_button(bs_test_t *test_ptr); @@ -644,6 +656,7 @@ const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, { 1, "pointer_motion", test_pointer_motion }, { 1, "pointer_focus", test_pointer_focus }, + { 1, "pointer_focus_move", test_pointer_focus_move }, { 1, "pointer_focus_layered", test_pointer_focus_layered }, { 1, "pointer_button", test_pointer_button }, { 0, NULL, NULL } @@ -973,6 +986,48 @@ void test_pointer_focus(bs_test_t *test_ptr) wlmtk_container_fini(&container); } +/* ------------------------------------------------------------------------- */ +/** Tests that pointer focus is updated when elements are moved. */ +void test_pointer_focus_move(bs_test_t *test_ptr) +{ + wlmtk_container_t container; + BS_ASSERT(wlmtk_container_init(&container)); + + // Setup to span an area where the container catches pointer coordinates. + wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&elem1_ptr->element, true); + wlmtk_element_set_position(&elem1_ptr->element, -20, 0); + wlmtk_container_add_element(&container, &elem1_ptr->element); + wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&elem2_ptr->element, true); + wlmtk_element_set_position(&elem2_ptr->element, 20, 0); + wlmtk_container_add_element(&container, &elem2_ptr->element); + + // Need the container to pick up the cursor position. + wlmtk_element_pointer_motion(&container.super_element, 0, 0, 7); + + // Is off the cursor, will get focus. + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + container.pointer_focus_element_ptr); + + // Now moves below the cursor, will get focus. + wlmtk_element_set_position(&elem1_ptr->element, 0, 0); + BS_TEST_VERIFY_EQ( + test_ptr, + &elem1_ptr->element, + container.pointer_focus_element_ptr); + + wlmtk_container_remove_element(&container, &elem2_ptr->element); + wlmtk_container_remove_element(&container, &elem1_ptr->element); + + wlmtk_element_destroy(&elem2_ptr->element); + wlmtk_element_destroy(&elem1_ptr->element); + wlmtk_container_fini(&container); +} + + /* ------------------------------------------------------------------------- */ /** Tests that pointer focus is updated across layers of containers. */ void test_pointer_focus_layered(bs_test_t *test_ptr) diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 2711a3d3..d1f14b3b 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -158,6 +158,13 @@ void wlmtk_container_remove_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr); +/** + * Updates pointer focus of the container. + * + * @param container_ptr + */ +void wlmtk_container_update_pointer_focus(wlmtk_container_t *container_ptr); + /** * Updates the layout of the container. * diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 8d759d52..2350e8e6 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -219,6 +219,9 @@ void wlmtk_element_set_position( int x, int y) { + // Optimization clause: No need for update, if coordinates didn't change. + if (element_ptr->x == x && element_ptr->y == y) return; + element_ptr->x = x; element_ptr->y = y; @@ -228,7 +231,9 @@ void wlmtk_element_set_position( element_ptr->y); } - // FIXME: We should probably update the layout? + if (NULL != element_ptr->parent_container_ptr) { + wlmtk_container_update_pointer_focus(element_ptr->parent_container_ptr); + } } /* == Local (static) methods =============================================== */ From 13aadf6fac7fea1f3cde16928af4be067a302f0c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 25 Nov 2023 17:53:00 +0100 Subject: [PATCH 257/390] Permits setting the extents of the workspace. --- src/toolkit/workspace.c | 75 +++++++++++++++++++++++++++++++++++++++++ src/toolkit/workspace.h | 11 ++++++ src/workspace.c | 4 +++ 3 files changed, 90 insertions(+) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 34396080..70dc9e0a 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -59,9 +59,30 @@ struct _wlmtk_workspace_t { int initial_height; /** Edges currently active for resizing: `enum wlr_edges`. */ uint32_t resize_edges; + + /** Top left X coordinate of workspace. */ + int x1; + /** Top left Y coordinate of workspace. */ + int y1; + /** Bottom right X coordinate of workspace. */ + int x2; + /** Bottom right Y coordinate of workspace. */ + int y2; }; static void _wlmtk_workspace_element_destroy(wlmtk_element_t *element_ptr); +static void _wlmtk_workspace_element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); +static void _wlmtk_workspace_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr); static bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -99,6 +120,8 @@ typedef enum { /** Extensions to the workspace's super element's virtual methods. */ const wlmtk_element_vmt_t workspace_element_vmt = { .destroy = _wlmtk_workspace_element_destroy, + .get_dimensions = _wlmtk_workspace_element_get_dimensions, + .get_pointer_area = _wlmtk_workspace_element_get_pointer_area, .pointer_motion = element_pointer_motion, .pointer_button = element_pointer_button, .pointer_leave = element_pointer_leave, @@ -147,6 +170,16 @@ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) free(workspace_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, + const struct wlr_box *extents_ptr) +{ + workspace_ptr->x1 = extents_ptr->x; + workspace_ptr->y1 = extents_ptr->y; + workspace_ptr->x2 = extents_ptr->x + extents_ptr->width; + workspace_ptr->y2 = extents_ptr->y + extents_ptr->height; +} + /* ------------------------------------------------------------------------- */ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) @@ -300,6 +333,37 @@ void _wlmtk_workspace_element_destroy(wlmtk_element_t *element_ptr) wlmtk_workspace_destroy(workspace_ptr); } +/* ------------------------------------------------------------------------- */ +/** Returns the workspace area. */ +void _wlmtk_workspace_element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_workspace_t, super_container.super_element); + + if (NULL != left_ptr) *left_ptr = workspace_ptr->x1; + if (NULL != top_ptr) *top_ptr = workspace_ptr->y1; + if (NULL != right_ptr) *right_ptr = workspace_ptr->x2; + if (NULL != bottom_ptr) *bottom_ptr = workspace_ptr->y2; +} + +/* ------------------------------------------------------------------------- */ +/** Returns workspace area: @ref _wlmtk_workspace_element_get_dimensions. */ +void _wlmtk_workspace_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr) +{ + return _wlmtk_workspace_element_get_dimensions( + element_ptr, x1_ptr, y1_ptr, x2_ptr, y2_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Extends wlmtk_container_t::pointer_button: Feeds the motion into the @@ -526,6 +590,17 @@ void test_create_destroy(bs_test_t *test_ptr) workspace_ptr, wlmtk_workspace_from_container(&workspace_ptr->super_container)); + struct wlr_box box = { .x = -10, .y = -20, .width = 100, .height = 200 }; + wlmtk_workspace_set_extents(workspace_ptr, &box); + int x1, y1, x2, y2; + wlmtk_element_get_pointer_area( + &workspace_ptr->super_container.super_element, &x1, &y1, &x2, &y2); + BS_TEST_VERIFY_EQ(test_ptr, -10, x1); + BS_TEST_VERIFY_EQ(test_ptr, -20, y1); + BS_TEST_VERIFY_EQ(test_ptr, 90, x2); + BS_TEST_VERIFY_EQ(test_ptr, 180, y2); + + wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index a49eee7b..d4ddc198 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -32,6 +32,8 @@ typedef struct _wlmtk_workspace_t wlmtk_workspace_t; /** Forward declaration. */ struct wlr_pointer_button_event; +/** Forward declaration. */ +struct wlr_box; /** * Creates a workspace. @@ -54,6 +56,15 @@ wlmtk_workspace_t *wlmtk_workspace_create( */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); +/** + * Sets (or updates) the extents of the workspace. + * + * @param workspace_ptr + * @param extents_ptr + */ +void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, + const struct wlr_box *extents_ptr); + /** * Maps the window: Adds it to the workspace container and makes it visible. * diff --git a/src/workspace.c b/src/workspace.c index c6d78d47..be181efe 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -178,6 +178,10 @@ wlmaker_workspace_t *wlmaker_workspace_create(wlmaker_server_t *server_ptr, wlmaker_workspace_destroy(workspace_ptr); return NULL; } + struct wlr_box extents; + wlr_output_layout_get_box( + workspace_ptr->server_ptr->wlr_output_layout_ptr, NULL, &extents); + wlmtk_workspace_set_extents(workspace_ptr->wlmtk_workspace_ptr, &extents); #endif // defined(ENABLE_TOOLKIT_PROTOTYPE) return workspace_ptr; From ccddffce793f4ee99d29ac0f984850fe277b2b32 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 26 Nov 2023 16:44:04 +0100 Subject: [PATCH 258/390] Moves the enter/leave handlint into _wlmtk_element_pointer_motion. --- src/toolkit/button.c | 47 +++++++++++++----------------- src/toolkit/button.h | 3 -- src/toolkit/container.c | 47 +++++++++++++----------------- src/toolkit/element.c | 64 ++++++++++++++++++++++++++++++++++------- src/toolkit/element.h | 33 +++++++++++---------- 5 files changed, 112 insertions(+), 82 deletions(-) diff --git a/src/toolkit/button.c b/src/toolkit/button.c index 001f466e..712b65c9 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -32,13 +32,11 @@ static void _wlmtk_button_clicked(wlmtk_button_t *button_ptr); -static bool _wlmtk_button_element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, double y, - uint32_t time_msec); static bool _wlmtk_button_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_button_element_pointer_enter( + wlmtk_element_t *element_ptr); static void _wlmtk_button_element_pointer_leave( wlmtk_element_t *element_ptr); @@ -48,8 +46,8 @@ static void apply_state(wlmtk_button_t *button_ptr); /** Virtual method table for the button's element super class. */ static const wlmtk_element_vmt_t button_element_vmt = { - .pointer_motion = _wlmtk_button_element_pointer_motion, .pointer_button = _wlmtk_button_element_pointer_button, + .pointer_enter = _wlmtk_button_element_pointer_enter, .pointer_leave = _wlmtk_button_element_pointer_leave, }; @@ -146,23 +144,6 @@ void _wlmtk_button_clicked(__UNUSED__ wlmtk_button_t *button_ptr) // Nothing. } -/* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_vmt_t::pointer_motion. */ -bool _wlmtk_button_element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, double y, - uint32_t time_msec) -{ - wlmtk_button_t *button_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_button_t, super_buffer.super_element); - - button_ptr->orig_super_element_vmt.pointer_motion( - element_ptr, x, y, time_msec); - button_ptr->pointer_inside = true; - apply_state(button_ptr); - return true; -} - /* ------------------------------------------------------------------------- */ /** See @ref wlmtk_element_vmt_t::pointer_button. */ bool _wlmtk_button_element_pointer_button( @@ -197,7 +178,19 @@ bool _wlmtk_button_element_pointer_button( } /* ------------------------------------------------------------------------- */ -/** See @ref wlmtk_element_vmt_t::pointer_leave. */ +/** Pointer enters the area: We may need to update visualization. */ +void _wlmtk_button_element_pointer_enter( + wlmtk_element_t *element_ptr) +{ + wlmtk_button_t *button_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_button_t, super_buffer.super_element); + button_ptr->orig_super_element_vmt.pointer_enter(element_ptr); + + apply_state(button_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Pointer leaves the area: We may need to update visualization. */ void _wlmtk_button_element_pointer_leave( wlmtk_element_t *element_ptr) { @@ -205,7 +198,6 @@ void _wlmtk_button_element_pointer_leave( element_ptr, wlmtk_button_t, super_buffer.super_element); button_ptr->orig_super_element_vmt.pointer_leave(element_ptr); - button_ptr->pointer_inside = false; apply_state(button_ptr); } @@ -213,7 +205,8 @@ void _wlmtk_button_element_pointer_leave( /** Sets the appropriate texture for the button. */ void apply_state(wlmtk_button_t *button_ptr) { - if (button_ptr->pointer_inside && button_ptr->pressed) { + if (button_ptr->super_buffer.super_element.pointer_inside && + button_ptr->pressed) { wlmtk_buffer_set( &button_ptr->super_buffer, button_ptr->pressed_wlr_buffer_ptr); @@ -294,7 +287,7 @@ void test_press_release(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, p_ptr); // Pointer leaves the area: released. - wlmtk_element_pointer_leave(element_ptr); + wlmtk_element_pointer_motion(element_ptr, NAN, NAN, 41); BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); // Pointer re-enters the area: pressed. @@ -350,7 +343,7 @@ void test_press_release_outside(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, p_ptr); // Pointer leaves the area: released. - wlmtk_element_pointer_leave(element_ptr); + wlmtk_element_pointer_motion(element_ptr, NAN, NAN, 41); BS_TEST_VERIFY_EQ(test_ptr, button.super_buffer.wlr_buffer_ptr, r_ptr); // Button up, outside the area. Then, re-enter: Still released. diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 33fa1e37..692862a8 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -52,9 +52,6 @@ struct _wlmtk_button_t { /** Whether the button is currently pressed. */ bool pressed; - - /** Whether the pointer is currently inside. */ - bool pointer_inside; }; /** diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 97d18175..85ede0f9 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -50,8 +50,6 @@ static bool element_pointer_motion( static bool element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); -static void element_pointer_leave( - wlmtk_element_t *element_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -70,7 +68,6 @@ static const wlmtk_element_vmt_t container_element_vmt = { .get_pointer_area = element_get_pointer_area, .pointer_motion = element_pointer_motion, .pointer_button = element_pointer_button, - .pointer_leave = element_pointer_leave, }; /** Default virtual method table. Initializes non-abstract methods. */ @@ -464,23 +461,6 @@ bool element_pointer_button( button_event_ptr); } -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the element's leave method: Forwards it to the element - * currently having pointer focus, and clears that. - * - * @param element_ptr - */ -void element_pointer_leave(wlmtk_element_t *element_ptr) -{ - wlmtk_container_t *container_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_container_t, super_element); - if (NULL == container_ptr->pointer_focus_element_ptr) return; - - wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); - container_ptr->pointer_focus_element_ptr = NULL; -} - /* ------------------------------------------------------------------------- */ /** * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. @@ -548,10 +528,13 @@ bool update_pointer_focus_at( continue; } - if (NULL != container_ptr->pointer_focus_element_ptr && - container_ptr->pointer_focus_element_ptr != element_ptr) { - wlmtk_element_pointer_leave( - container_ptr->pointer_focus_element_ptr); + // There is a focus change. Invalidate coordinates in old element. + if (container_ptr->pointer_focus_element_ptr != element_ptr && + NULL != container_ptr->pointer_focus_element_ptr) { + wlmtk_element_pointer_motion( + container_ptr->pointer_focus_element_ptr, + NAN, NAN, time_msec); + } container_ptr->pointer_focus_element_ptr = element_ptr; return true; @@ -562,7 +545,9 @@ bool update_pointer_focus_at( // so it must have happened outside our araea. We also should reset // pointer focus element now. if (NULL != container_ptr->pointer_focus_element_ptr) { - wlmtk_element_pointer_leave(container_ptr->pointer_focus_element_ptr); + wlmtk_element_pointer_motion( + container_ptr->pointer_focus_element_ptr, + NAN, NAN, time_msec); container_ptr->pointer_focus_element_ptr = NULL; } return false; @@ -832,6 +817,8 @@ void test_pointer_motion(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_pointer_motion(&container.super_element, -20, -40, 7)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_enter_called); + elem1_ptr->pointer_enter_called = false; BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); elem1_ptr->pointer_motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); @@ -842,6 +829,7 @@ void test_pointer_motion(bs_test_t *test_ptr) test_ptr, wlmtk_element_pointer_motion( &parent_container.super_element, -20, -40, 7)); + BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_enter_called); BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); elem1_ptr->pointer_motion_called = false; BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); @@ -853,9 +841,13 @@ void test_pointer_motion(bs_test_t *test_ptr) test_ptr, wlmtk_element_pointer_motion( &parent_container.super_element, 107, 203, 7)); + BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, isnan(elem1_ptr->element.last_pointer_x)); + elem1_ptr->pointer_motion_called = false; BS_TEST_VERIFY_TRUE(test_ptr, elem1_ptr->pointer_leave_called); elem1_ptr->pointer_leave_called = false; - BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_enter_called); + elem2_ptr->pointer_enter_called = false; BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_motion_called); elem2_ptr->pointer_motion_called = false; BS_TEST_VERIFY_EQ(test_ptr, 7, elem2_ptr->element.last_pointer_x); @@ -879,7 +871,8 @@ void test_pointer_motion(bs_test_t *test_ptr) wlmtk_element_pointer_motion( &parent_container.super_element, 113, 209, 7)); BS_TEST_VERIFY_FALSE(test_ptr, elem1_ptr->pointer_motion_called); - BS_TEST_VERIFY_FALSE(test_ptr, elem2_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_motion_called); + BS_TEST_VERIFY_TRUE(test_ptr, isnan(elem2_ptr->element.last_pointer_x)); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_leave_called); elem2_ptr->pointer_leave_called = false; diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 2350e8e6..8c9f9c37 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -43,10 +43,12 @@ static bool _wlmtk_element_pointer_motion( static bool _wlmtk_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_element_pointer_enter( + wlmtk_element_t *element_ptr); static void _wlmtk_element_pointer_leave( wlmtk_element_t *element_ptr); - static void handle_wlr_scene_node_destroy( +static void handle_wlr_scene_node_destroy( struct wl_listener *listener_ptr, void *data_ptr); @@ -57,6 +59,7 @@ static const wlmtk_element_vmt_t element_vmt = { .get_pointer_area = _wlmtk_element_get_pointer_area, .pointer_motion = _wlmtk_element_pointer_motion, .pointer_button = _wlmtk_element_pointer_button, + .pointer_enter = _wlmtk_element_pointer_enter, .pointer_leave = _wlmtk_element_pointer_leave, }; @@ -101,6 +104,9 @@ wlmtk_element_vmt_t wlmtk_element_extend( if (NULL != element_vmt_ptr->pointer_button) { element_ptr->vmt.pointer_button = element_vmt_ptr->pointer_button; } + if (NULL != element_vmt_ptr->pointer_enter) { + element_ptr->vmt.pointer_enter = element_vmt_ptr->pointer_enter; + } if (NULL != element_vmt_ptr->pointer_leave) { element_ptr->vmt.pointer_leave = element_vmt_ptr->pointer_leave; } @@ -232,7 +238,8 @@ void wlmtk_element_set_position( } if (NULL != element_ptr->parent_container_ptr) { - wlmtk_container_update_pointer_focus(element_ptr->parent_container_ptr); + wlmtk_container_update_pointer_focus( + element_ptr->parent_container_ptr); } } @@ -258,9 +265,26 @@ bool _wlmtk_element_pointer_motion( double y, uint32_t time_msec) { + if (isnan(x) || isnan(y)) { + if (element_ptr->pointer_inside) { + element_ptr->pointer_inside = false; + element_ptr->vmt.pointer_leave(element_ptr); + } + element_ptr->last_pointer_x = NAN; + element_ptr->last_pointer_y = NAN; + element_ptr->last_pointer_time_msec = time_msec; + return true; + } + + if (!element_ptr->pointer_inside) { + element_ptr->pointer_inside = true; + element_ptr->vmt.pointer_enter(element_ptr); + } + element_ptr->last_pointer_x = x; element_ptr->last_pointer_y = y; element_ptr->last_pointer_time_msec = time_msec; + return true; } @@ -274,13 +298,18 @@ bool _wlmtk_element_pointer_button( } /* ------------------------------------------------------------------------- */ -/** Resets the pointer coordinates. */ -void _wlmtk_element_pointer_leave( - wlmtk_element_t *element_ptr) +/** Handler for when the pointer enters the area. Nothing for default impl. */ +void _wlmtk_element_pointer_enter(__UNUSED__ wlmtk_element_t *element_ptr) { - element_ptr->last_pointer_x = NAN; - element_ptr->last_pointer_y = NAN; - element_ptr->last_pointer_time_msec = 0; + // Nothing. + bs_log(BS_WARNING, "FIXME: Pointer entered on %p", element_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Handler for when the pointer leaves the area. Nothing for default impl. */ +void _wlmtk_element_pointer_leave(__UNUSED__ wlmtk_element_t *element_ptr) +{ + // Nothing. } /* ------------------------------------------------------------------------- */ @@ -326,6 +355,8 @@ static bool fake_pointer_motion( static bool fake_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); +static void fake_pointer_enter( + wlmtk_element_t *element_ptr); static void fake_pointer_leave( wlmtk_element_t *element_ptr); @@ -337,6 +368,7 @@ static const wlmtk_element_vmt_t fake_element_vmt = { .get_pointer_area = fake_get_pointer_area, .pointer_motion = fake_pointer_motion, .pointer_button = fake_pointer_button, + .pointer_enter = fake_pointer_enter, .pointer_leave = fake_pointer_leave, }; @@ -446,6 +478,17 @@ bool fake_pointer_button( return true; } +/* ------------------------------------------------------------------------- */ +/** Handles 'enter' events for the fake element. */ +void fake_pointer_enter( + wlmtk_element_t *element_ptr) +{ + wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_element_t, element); + fake_element_ptr->orig_vmt.pointer_enter(element_ptr); + fake_element_ptr->pointer_enter_called = true; +} + /* ------------------------------------------------------------------------- */ /** Handles 'leave' events for the fake element. */ void fake_pointer_leave( @@ -637,6 +680,7 @@ void test_pointer_motion_leave(bs_test_t *test_ptr) isnan(fake_element_ptr->element.last_pointer_y)); wlmtk_element_pointer_motion(&fake_element_ptr->element, 1.0, 2.0, 1234); + BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_enter_called); BS_TEST_VERIFY_EQ(test_ptr, 1.0, fake_element_ptr->element.last_pointer_x); BS_TEST_VERIFY_EQ(test_ptr, 2.0, fake_element_ptr->element.last_pointer_y); BS_TEST_VERIFY_EQ( @@ -644,7 +688,7 @@ void test_pointer_motion_leave(bs_test_t *test_ptr) 1234, fake_element_ptr->element.last_pointer_time_msec); - wlmtk_element_pointer_leave(&fake_element_ptr->element); + wlmtk_element_pointer_motion(&fake_element_ptr->element, NAN, NAN, 1235); BS_TEST_VERIFY_TRUE(test_ptr, fake_element_ptr->pointer_leave_called); BS_TEST_VERIFY_TRUE( test_ptr, @@ -654,7 +698,7 @@ void test_pointer_motion_leave(bs_test_t *test_ptr) isnan(fake_element_ptr->element.last_pointer_y)); BS_TEST_VERIFY_EQ( test_ptr, - 0, + 1235, fake_element_ptr->element.last_pointer_time_msec); wlmtk_element_destroy(&fake_element_ptr->element); diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 2f7144b5..234ff595 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -99,6 +99,13 @@ struct _wlmtk_element_vmt_t { bool (*pointer_button)(wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); + /** + * Indicates the pointer has entered the element's area. + * + * @param element_ptr + */ + void (*pointer_enter)(wlmtk_element_t *element_ptr); + /** * Indicates the pointer has left the element's area. * @@ -133,22 +140,24 @@ struct _wlmtk_element_t { /** * Horizontal pointer position from last @ref wlmtk_element_pointer_motion - * call. NAN if there was no motion call yet, or if @ref - * wlmtk_element_pointer_leave was called since. + * call. NAN if there was no motion call yet, or if the last motion call + * had NAN arguments. * * Does not imply that the element has pointer focus. */ double last_pointer_x; /** * Vertical pointer position from last @ref wlmtk_element_pointer_motion - * call. NAN if there was no motion call yet, or if @ref - * wlmtk_element_pointer_leave was called since. + * call. NAN if there was no motion call yet, or if the last motion call + * had NAN arguments. * * Does not imply that the element has pointer focus. */ double last_pointer_y; /** Time of last @ref wlmtk_element_pointer_motion call, 0 otherwise. */ uint32_t last_pointer_time_msec; + /** Whether the pointer is currently within the element's bounds. */ + bool pointer_inside; }; /** @@ -317,13 +326,6 @@ static inline bool wlmtk_element_pointer_button( return element_ptr->vmt.pointer_button(element_ptr, button_event_ptr); } -/** Calls @ref wlmtk_element_vmt_t::pointer_leave. */ -static inline void wlmtk_element_pointer_leave( - wlmtk_element_t *element_ptr) -{ - element_ptr->vmt.pointer_leave(element_ptr); -} - /** * Virtual method: Calls the dtor of the element's implementation. * @@ -350,13 +352,14 @@ typedef struct { /** Height of the element, in pixels. */ int height; - /** Indicates that Element::pointer_motion() was called. */ + /** Indicates @ref wlmtk_element_vmt_t::pointer_motion() was called. */ bool pointer_motion_called; - /** Indicates that Element::pointer_leave() was called. */ + /** Indicates @ref wlmtk_element_vmt_t::pointer_enter() was called. */ + bool pointer_enter_called; + /** Indicates @ref wlmtk_element_vmt_t::pointer_leave() was called. */ bool pointer_leave_called; - - /** Indicates that Element::pointer_button() was called. */ + /** Indicates @ref wlmtk_element_vmt_t::pointer_button() was called. */ bool pointer_button_called; /** Last button event reveiced. */ wlmtk_button_event_t pointer_button_event; From cd538598a35fab99f48676fafc41d0fd99fd41a5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 26 Nov 2023 16:48:22 +0100 Subject: [PATCH 259/390] Adds an idea comment about using event listeners for enter and leave. --- src/toolkit/element.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 234ff595..8527999a 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -102,6 +102,10 @@ struct _wlmtk_element_vmt_t { /** * Indicates the pointer has entered the element's area. * + * TODO(kaeser@gubbe.ch): pointer_enter and pointer_leave would better be + * handled as events, where clients subscribe via listeners. Consider + * changing that. + * * @param element_ptr */ void (*pointer_enter)(wlmtk_element_t *element_ptr); From c774c49eb473ca6fbb09a87a05cfb192740b329a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 26 Nov 2023 17:05:20 +0100 Subject: [PATCH 260/390] Adds some debugging info. Content does not handle leave properly. --- src/toolkit/content.c | 7 +++++++ src/toolkit/element.c | 1 + src/toolkit/workspace.c | 3 +++ 3 files changed, 11 insertions(+) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 8b211cd6..98b45fc3 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -81,6 +81,8 @@ bool wlmtk_content_init( content_ptr->orig_super_element_vmt = wlmtk_element_extend( &content_ptr->super_element, &content_element_vmt); + bs_log(BS_WARNING, "FIXME: Content element at %p", &content_ptr->super_element); + content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; return true; @@ -275,6 +277,11 @@ bool element_pointer_motion( wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); + bs_log(BS_INFO, "Content motion %f, %f", x, y); + + content_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); + // FIXME if (NULL == content_ptr->super_element.wlr_scene_node_ptr) return false; diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 8c9f9c37..af11ab16 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -309,6 +309,7 @@ void _wlmtk_element_pointer_enter(__UNUSED__ wlmtk_element_t *element_ptr) /** Handler for when the pointer leaves the area. Nothing for default impl. */ void _wlmtk_element_pointer_leave(__UNUSED__ wlmtk_element_t *element_ptr) { + bs_log(BS_WARNING, "FIXME: Pointer left on %p", element_ptr); // Nothing. } diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 70dc9e0a..315f98f4 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -159,6 +159,9 @@ wlmtk_workspace_t *wlmtk_workspace_create( &workspace_ptr->super_container.super_element, &workspace_element_vmt); + bs_log(BS_WARNING, "FIXME: Workspace element %p", + &workspace_ptr->super_container.super_element); + wlmtk_fsm_init(&workspace_ptr->fsm, pfsm_transitions, PFSMS_PASSTHROUGH); return workspace_ptr; } From 0005a138443ca0020327e300e72ec52d4afbc37c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 26 Nov 2023 21:10:59 +0100 Subject: [PATCH 261/390] Moves the motion handling into the element's C file. --- src/toolkit/content.c | 5 ----- src/toolkit/element.c | 42 ++++++++++++++++++++++++----------------- src/toolkit/element.h | 9 +++------ src/toolkit/workspace.c | 11 +++++------ 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 98b45fc3..70d2131a 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -81,8 +81,6 @@ bool wlmtk_content_init( content_ptr->orig_super_element_vmt = wlmtk_element_extend( &content_ptr->super_element, &content_element_vmt); - bs_log(BS_WARNING, "FIXME: Content element at %p", &content_ptr->super_element); - content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; return true; @@ -277,12 +275,9 @@ bool element_pointer_motion( wlmtk_content_t *content_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_content_t, super_element); - bs_log(BS_INFO, "Content motion %f, %f", x, y); - content_ptr->orig_super_element_vmt.pointer_motion( element_ptr, x, y, time_msec); - // FIXME if (NULL == content_ptr->super_element.wlr_scene_node_ptr) return false; // Get the layout local coordinates of the node, so we can adjust the diff --git a/src/toolkit/element.c b/src/toolkit/element.c index af11ab16..c0def273 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -243,6 +243,27 @@ void wlmtk_element_set_position( } } +/* ------------------------------------------------------------------------- */ +bool wlmtk_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec) +{ + bool within = element_ptr->vmt.pointer_motion(element_ptr, x, y, time_msec); + if (within == element_ptr->pointer_inside) return within; + + if (within) { + element_ptr->pointer_inside = true; + element_ptr->vmt.pointer_enter(element_ptr); + } else { + element_ptr->pointer_inside = false; + element_ptr->vmt.pointer_leave(element_ptr); + } + + return within; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -258,7 +279,7 @@ void _wlmtk_element_get_pointer_area( } /* ------------------------------------------------------------------------- */ -/** Stores the pointer coordinates and timestamp. Returns true. */ +/** Stores pointer coordinates and timestamp. Returns true is x,y not NAN. */ bool _wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, @@ -266,26 +287,15 @@ bool _wlmtk_element_pointer_motion( uint32_t time_msec) { if (isnan(x) || isnan(y)) { - if (element_ptr->pointer_inside) { - element_ptr->pointer_inside = false; - element_ptr->vmt.pointer_leave(element_ptr); - } - element_ptr->last_pointer_x = NAN; - element_ptr->last_pointer_y = NAN; - element_ptr->last_pointer_time_msec = time_msec; - return true; - } - - if (!element_ptr->pointer_inside) { - element_ptr->pointer_inside = true; - element_ptr->vmt.pointer_enter(element_ptr); + x = NAN; + y = NAN; } element_ptr->last_pointer_x = x; element_ptr->last_pointer_y = y; element_ptr->last_pointer_time_msec = time_msec; - return true; + return !isnan(x) && !isnan(y); } /* ------------------------------------------------------------------------- */ @@ -302,14 +312,12 @@ bool _wlmtk_element_pointer_button( void _wlmtk_element_pointer_enter(__UNUSED__ wlmtk_element_t *element_ptr) { // Nothing. - bs_log(BS_WARNING, "FIXME: Pointer entered on %p", element_ptr); } /* ------------------------------------------------------------------------- */ /** Handler for when the pointer leaves the area. Nothing for default impl. */ void _wlmtk_element_pointer_leave(__UNUSED__ wlmtk_element_t *element_ptr) { - bs_log(BS_WARNING, "FIXME: Pointer left on %p", element_ptr); // Nothing. } diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 8527999a..949a56a6 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -312,15 +312,12 @@ static inline void wlmtk_element_get_dimensions( element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } -/** Calls @ref wlmtk_element_vmt_t::pointer_button. */ -static inline bool wlmtk_element_pointer_motion( +/* FIXME */ +bool wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - uint32_t time_msec) -{ - return element_ptr->vmt.pointer_motion(element_ptr, x, y, time_msec); -} + uint32_t time_msec); /** Calls @ref wlmtk_element_vmt_t::pointer_button. */ static inline bool wlmtk_element_pointer_button( diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 315f98f4..f0d3336b 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -159,9 +159,6 @@ wlmtk_workspace_t *wlmtk_workspace_create( &workspace_ptr->super_container.super_element, &workspace_element_vmt); - bs_log(BS_WARNING, "FIXME: Workspace element %p", - &workspace_ptr->super_container.super_element); - wlmtk_fsm_init(&workspace_ptr->fsm, pfsm_transitions, PFSMS_PASSTHROUGH); return workspace_ptr; } @@ -378,7 +375,7 @@ void _wlmtk_workspace_element_get_pointer_area( * @param y * @param time_msec * - * @return Whether the motion encountered an active element. + * @return Always true. */ bool element_pointer_motion( wlmtk_element_t *element_ptr, @@ -387,10 +384,12 @@ bool element_pointer_motion( { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_workspace_t, super_container.super_element); - bool rv = workspace_ptr->orig_super_element_vmt.pointer_motion( + + // Note: Workspace ignores the return value. All motion events are whitin. + workspace_ptr->orig_super_element_vmt.pointer_motion( element_ptr, x, y, time_msec); wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_MOTION, NULL); - return rv; + return true; } /* ------------------------------------------------------------------------- */ From a8366c9660cd9bc0fa1fa2db8546b354a1f813ff Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 26 Nov 2023 21:13:02 +0100 Subject: [PATCH 262/390] Fixes documentation for wlmtk_element_pointer_motion. --- src/toolkit/element.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 949a56a6..71935b16 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -312,7 +312,18 @@ static inline void wlmtk_element_get_dimensions( element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } -/* FIXME */ +/** + * Passes a pointer motion event on to the element. + * + * Will forward to @ref wlmtk_element_vmt_t::pointer_motion, and (depending on + * that return value) trigger @ref wlmtk_element_vmt_t::pointer_enter of + * @ref wlmtk_element_vmt_t::pointer_leave calls. + * + * @param element_ptr + * @param x + * @param y + * @param time_msec + */ bool wlmtk_element_pointer_motion( wlmtk_element_t *element_ptr, double x, From a4735b5ee7ca0aa6c6c5644775ad1af19ff9d84d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 26 Nov 2023 21:50:49 +0100 Subject: [PATCH 263/390] Adds a wlmtk_cursor_t arg to all the initialization routines. --- src/toolkit/box.c | 10 ++++++---- src/toolkit/box.h | 2 ++ src/toolkit/buffer.c | 5 +++-- src/toolkit/buffer.h | 4 +++- src/toolkit/button.c | 14 ++++++++------ src/toolkit/button.h | 4 +++- src/toolkit/container.c | 30 +++++++++++++++++------------- src/toolkit/container.h | 6 +++++- src/toolkit/content.c | 5 +++-- src/toolkit/content.h | 2 ++ src/toolkit/element.c | 14 ++++++++------ src/toolkit/element.h | 4 +++- src/toolkit/input.h | 7 +++++++ src/toolkit/resizebar.c | 14 ++++++++------ src/toolkit/resizebar.h | 2 ++ src/toolkit/resizebar_area.c | 5 +++-- src/toolkit/resizebar_area.h | 2 ++ src/toolkit/titlebar.c | 13 +++++++++---- src/toolkit/titlebar.h | 2 ++ src/toolkit/titlebar_button.c | 4 +++- src/toolkit/titlebar_button.h | 2 ++ src/toolkit/titlebar_title.c | 5 +++-- src/toolkit/titlebar_title.h | 2 ++ src/toolkit/window.c | 14 ++++++++++---- src/toolkit/workspace.c | 16 +++++++++------- src/toolkit/workspace.h | 2 ++ src/wlmtk_xdg_toplevel.c | 1 + src/workspace.c | 2 +- 28 files changed, 129 insertions(+), 64 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index af6f1a1f..63fd18ec 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -37,11 +37,12 @@ static const wlmtk_container_vmt_t box_container_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, + wlmtk_cursor_t *cursor_ptr, wlmtk_box_orientation_t orientation) { BS_ASSERT(NULL != box_ptr); memset(box_ptr, 0, sizeof(wlmtk_box_t)); - if (!wlmtk_container_init(&box_ptr->super_container)) { + if (!wlmtk_container_init(&box_ptr->super_container, cursor_ptr)) { return false; } box_ptr->orig_super_container_vmt = wlmtk_container_extend( @@ -132,7 +133,8 @@ const bs_test_case_t wlmtk_box_test_cases[] = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_box_t box; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_box_init(&box, WLMTK_BOX_HORIZONTAL)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_box_init( + &box, NULL, WLMTK_BOX_HORIZONTAL)); wlmtk_box_fini(&box); } @@ -141,7 +143,7 @@ void test_init_fini(bs_test_t *test_ptr) void test_layout_horizontal(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, WLMTK_BOX_HORIZONTAL); + wlmtk_box_init(&box, NULL, WLMTK_BOX_HORIZONTAL); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); @@ -194,7 +196,7 @@ void test_layout_horizontal(bs_test_t *test_ptr) void test_layout_vertical(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, WLMTK_BOX_VERTICAL); + wlmtk_box_init(&box, NULL, WLMTK_BOX_VERTICAL); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 545c4294..94d3d43d 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -50,11 +50,13 @@ struct _wlmtk_box_t { * * @param box_ptr * @param orientation + * @param cursor_ptr * * @return true on success. */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, + wlmtk_cursor_t *cursor_ptr, wlmtk_box_orientation_t orientation); /** diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index 6aac7b92..416e679c 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -52,12 +52,13 @@ static const wlmtk_element_vmt_t buffer_element_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr) +bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr, + wlmtk_cursor_t *cursor_ptr) { BS_ASSERT(NULL != buffer_ptr); memset(buffer_ptr, 0, sizeof(wlmtk_buffer_t)); - if (!wlmtk_element_init(&buffer_ptr->super_element)) { + if (!wlmtk_element_init(&buffer_ptr->super_element, cursor_ptr)) { return false; } buffer_ptr->orig_super_element_vmt = wlmtk_element_extend( diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index 36d78ba9..f5826eb8 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -56,10 +56,12 @@ struct _wlmtk_buffer_t { * Initializes the buffer. * * @param buffer_ptr + * @param cursor_ptr * * @return true on success. */ -bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr); +bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr, + wlmtk_cursor_t *cursor_ptr); /** * Cleans up the buffer. diff --git a/src/toolkit/button.c b/src/toolkit/button.c index 712b65c9..a714001b 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -59,13 +59,15 @@ static const wlmtk_button_vmt_t button_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_button_init(wlmtk_button_t *button_ptr) +bool wlmtk_button_init( + wlmtk_button_t *button_ptr, + wlmtk_cursor_t *cursor_ptr) { BS_ASSERT(NULL != button_ptr); memset(button_ptr, 0, sizeof(wlmtk_button_t)); button_ptr->vmt = button_vmt; - if (!wlmtk_buffer_init(&button_ptr->super_buffer)) { + if (!wlmtk_buffer_init(&button_ptr->super_buffer, cursor_ptr)) { wlmtk_button_fini(button_ptr); return false; } @@ -252,7 +254,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_button_init(&button)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_button_init(&button, NULL)); wlmtk_button_fini(&button); } @@ -261,7 +263,7 @@ void test_create_destroy(bs_test_t *test_ptr) void test_press_release(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_ASSERT(wlmtk_button_init(&button)); + BS_ASSERT(wlmtk_button_init(&button, NULL)); wlmtk_button_extend(&button, &fake_button_vmt); struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); @@ -320,7 +322,7 @@ void test_press_release(bs_test_t *test_ptr) void test_press_release_outside(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_ASSERT(wlmtk_button_init(&button)); + BS_ASSERT(wlmtk_button_init(&button, NULL)); struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); @@ -367,7 +369,7 @@ void test_press_release_outside(bs_test_t *test_ptr) void test_press_right(bs_test_t *test_ptr) { wlmtk_button_t button; - BS_ASSERT(wlmtk_button_init(&button)); + BS_ASSERT(wlmtk_button_init(&button, NULL)); struct wlr_buffer *p_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); struct wlr_buffer *r_ptr = bs_gfxbuf_create_wlr_buffer(1, 1); diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 692862a8..17f39a08 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -58,10 +58,12 @@ struct _wlmtk_button_t { * Initializes the button. * * @param button_ptr + * @param cursor_ptr * * @return true on success. */ -bool wlmtk_button_init(wlmtk_button_t *button_ptr); +bool wlmtk_button_init(wlmtk_button_t *button_ptr, + wlmtk_cursor_t *cursor_ptr); /** * Extends the button's virtual methods. diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 85ede0f9..db750ff1 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -78,13 +78,15 @@ static const wlmtk_container_vmt_t container_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_container_init(wlmtk_container_t *container_ptr) +bool wlmtk_container_init( + wlmtk_container_t *container_ptr, + wlmtk_cursor_t *cursor_ptr) { BS_ASSERT(NULL != container_ptr); memset(container_ptr, 0, sizeof(wlmtk_container_t)); container_ptr->vmt = container_vmt; - if (!wlmtk_element_init(&container_ptr->super_element)) { + if (!wlmtk_element_init(&container_ptr->super_element, cursor_ptr)) { return false; } container_ptr->orig_super_element_vmt = wlmtk_element_extend( @@ -96,9 +98,10 @@ bool wlmtk_container_init(wlmtk_container_t *container_ptr) /* ------------------------------------------------------------------------- */ bool wlmtk_container_init_attached( wlmtk_container_t *container_ptr, + wlmtk_cursor_t *cursor_ptr, struct wlr_scene_tree *root_wlr_scene_tree_ptr) { - if (!wlmtk_container_init(container_ptr)) return false; + if (!wlmtk_container_init(container_ptr, cursor_ptr)) return false; container_ptr->super_element.wlr_scene_node_ptr = element_create_scene_node( @@ -597,6 +600,7 @@ wlmtk_container_t *wlmtk_container_create_fake_parent(void) if (!wlmtk_container_init_attached( &fake_parent_container_ptr->container, + NULL, &fake_parent_container_ptr->wlr_scene_ptr->tree)) { wlmtk_container_destroy_fake_parent( &fake_parent_container_ptr->container); @@ -652,7 +656,7 @@ const bs_test_case_t wlmtk_container_test_cases[] = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container));; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container, NULL)); // Also expect the super element to be initialized. BS_TEST_VERIFY_NEQ( test_ptr, NULL, container.super_element.vmt.pointer_motion); @@ -668,7 +672,7 @@ void test_init_fini(bs_test_t *test_ptr) void test_add_remove(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container, NULL)); wlmtk_fake_element_t *elem1_ptr, *elem2_ptr, *elem3_ptr; elem1_ptr = wlmtk_fake_element_create(); @@ -722,7 +726,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_parent_ptr); wlmtk_container_t container; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container, NULL)); wlmtk_element_set_parent_container( &container.super_element, fake_parent_ptr); @@ -753,7 +757,7 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) void test_pointer_motion(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container)); + BS_ASSERT(wlmtk_container_init(&container, NULL)); wlmtk_element_set_visible(&container.super_element, true); // Note: pointer area extends by (-1, -2, 3, 4) on each fake element. @@ -786,7 +790,7 @@ void test_pointer_motion(bs_test_t *test_ptr) // Same must hold for the parent container. wlmtk_container_t parent_container; - BS_ASSERT(wlmtk_container_init(&parent_container)); + BS_ASSERT(wlmtk_container_init(&parent_container, NULL)); wlmtk_container_add_element(&parent_container, &container.super_element); @@ -893,7 +897,7 @@ void test_pointer_motion(bs_test_t *test_ptr) void test_pointer_focus(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container)); + BS_ASSERT(wlmtk_container_init(&container, NULL)); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&elem1_ptr->element, true); @@ -984,7 +988,7 @@ void test_pointer_focus(bs_test_t *test_ptr) void test_pointer_focus_move(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container)); + BS_ASSERT(wlmtk_container_init(&container, NULL)); // Setup to span an area where the container catches pointer coordinates. wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); @@ -1026,9 +1030,9 @@ void test_pointer_focus_move(bs_test_t *test_ptr) void test_pointer_focus_layered(bs_test_t *test_ptr) { wlmtk_container_t container1; - BS_ASSERT(wlmtk_container_init(&container1)); + BS_ASSERT(wlmtk_container_init(&container1, NULL)); wlmtk_container_t container2; - BS_ASSERT(wlmtk_container_init(&container2)); + BS_ASSERT(wlmtk_container_init(&container2, NULL)); wlmtk_element_set_visible(&container2.super_element, true); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); @@ -1103,7 +1107,7 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) void test_pointer_button(bs_test_t *test_ptr) { wlmtk_container_t container; - BS_ASSERT(wlmtk_container_init(&container)); + BS_ASSERT(wlmtk_container_init(&container, NULL)); wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&elem1_ptr->element, true); diff --git a/src/toolkit/container.h b/src/toolkit/container.h index d1f14b3b..ab512706 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -80,10 +80,12 @@ struct _wlmtk_container_t { * Initializes the container with the provided virtual method table. * * @param container_ptr + * @param cursor_ptr * * @return true on success. */ -bool wlmtk_container_init(wlmtk_container_t *container_ptr); +bool wlmtk_container_init(wlmtk_container_t *container_ptr, + wlmtk_cursor_t *cursor_ptr); /** * Extends the container's virtual methods. @@ -101,12 +103,14 @@ wlmtk_container_vmt_t wlmtk_container_extend( * Initializes the container, and attach to WLR sene graph. * * @param container_ptr + * @param cursor_ptr * @param root_wlr_scene_tree_ptr * * @return true on success. */ bool wlmtk_container_init_attached( wlmtk_container_t *container_ptr, + wlmtk_cursor_t *cursor_ptr, struct wlr_scene_tree *root_wlr_scene_tree_ptr); /** diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 70d2131a..a3388fbd 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -70,12 +70,13 @@ void *wlmtk_content_identifier_ptr = wlmtk_content_init; /* ------------------------------------------------------------------------- */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, + wlmtk_cursor_t *cursor_ptr, struct wlr_seat *wlr_seat_ptr) { BS_ASSERT(NULL != content_ptr); memset(content_ptr, 0, sizeof(wlmtk_content_t)); - if (!wlmtk_element_init(&content_ptr->super_element)) { + if (!wlmtk_element_init(&content_ptr->super_element, cursor_ptr)) { return false; } content_ptr->orig_super_element_vmt = wlmtk_element_extend( @@ -409,7 +410,7 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) 1, sizeof(wlmtk_fake_content_t)); if (NULL == fake_content_ptr) return NULL; - if (!wlmtk_content_init(&fake_content_ptr->content, NULL)) { + if (!wlmtk_content_init(&fake_content_ptr->content, NULL, NULL)) { free(fake_content_ptr); return NULL; } diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 1c37a875..52996a6c 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -85,12 +85,14 @@ struct _wlmtk_content_t { * Initializes the content. * * @param content_ptr + * @param cursor_ptr * @param wlr_seat_ptr * * @return true on success. */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, + wlmtk_cursor_t *cursor_ptr, struct wlr_seat *wlr_seat_ptr); /** diff --git a/src/toolkit/element.c b/src/toolkit/element.c index c0def273..b5c837b1 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -66,7 +66,9 @@ static const wlmtk_element_vmt_t element_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_element_init(wlmtk_element_t *element_ptr) +bool wlmtk_element_init( + wlmtk_element_t *element_ptr, + __UNUSED__ wlmtk_cursor_t *cursor_ptr) { BS_ASSERT(NULL != element_ptr); memset(element_ptr, 0, sizeof(wlmtk_element_t)); @@ -388,7 +390,7 @@ wlmtk_fake_element_t *wlmtk_fake_element_create(void) 1, sizeof(wlmtk_fake_element_t)); if (NULL == fake_element_ptr) return NULL; - if (!wlmtk_element_init(&fake_element_ptr->element)) { + if (!wlmtk_element_init(&fake_element_ptr->element, NULL)) { fake_destroy(&fake_element_ptr->element); return NULL; } @@ -535,7 +537,7 @@ const bs_test_case_t wlmtk_element_test_cases[] = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, NULL)); wlmtk_element_extend(&element, &fake_element_vmt); BS_TEST_VERIFY_NEQ(test_ptr, NULL, element.vmt.destroy); @@ -548,12 +550,12 @@ void test_init_fini(bs_test_t *test_ptr) void test_set_parent_container(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, NULL)); wlmtk_element_extend(&element, &fake_element_vmt); // Setting a parent without a scene graph tree will not set a node. wlmtk_container_t parent_no_tree; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&parent_no_tree)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&parent_no_tree, NULL)); wlmtk_element_set_parent_container(&element, &parent_no_tree); BS_TEST_VERIFY_EQ(test_ptr, NULL, element.wlr_scene_node_ptr); @@ -596,7 +598,7 @@ void test_set_parent_container(bs_test_t *test_ptr) void test_set_get_position(bs_test_t *test_ptr) { wlmtk_element_t element; - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_element_init(&element, NULL)); wlmtk_element_extend(&element, &fake_element_vmt); // Exercise, must not crash. diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 71935b16..b63722ae 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -168,10 +168,12 @@ struct _wlmtk_element_t { * Initializes the element. * * @param element_ptr + * @param cursor_ptr * * @return true on success. */ -bool wlmtk_element_init(wlmtk_element_t *element_ptr); +bool wlmtk_element_init(wlmtk_element_t *element_ptr, + wlmtk_cursor_t *cursor_ptr); /** * Extends the element's virtual methods. diff --git a/src/toolkit/input.h b/src/toolkit/input.h index fbf18ef2..c6610d6a 100644 --- a/src/toolkit/input.h +++ b/src/toolkit/input.h @@ -29,6 +29,8 @@ extern "C" { /** Forward declaration: Button event. */ typedef struct _wlmtk_button_event_t wlmtk_button_event_t; +/** Forward declaration: Cursor. */ +typedef struct _wlmtk_cursor_t wlmtk_cursor_t; /** Button state. */ typedef enum { @@ -48,6 +50,11 @@ struct _wlmtk_button_event_t { uint32_t time_msec; }; +/** Ctor: Creates a fake cursor. */ +wlmtk_cursor_t *wlmtk_fake_cursor_create(void); +/** Dtor: Destroys the fake cursor. */ +void wlmtk_fake_cursor_destroy(wlmtk_cursor_t *cursor_ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 95800ec1..d02b4b65 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -70,6 +70,7 @@ static const wlmtk_element_vmt_t resizebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( + wlmtk_cursor_t *cursor_ptr, wlmtk_window_t *window_ptr, const wlmtk_resizebar_style_t *style_ptr) { @@ -78,7 +79,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( if (NULL == resizebar_ptr) return NULL; memcpy(&resizebar_ptr->style, style_ptr, sizeof(wlmtk_resizebar_style_t)); - if (!wlmtk_box_init(&resizebar_ptr->super_box, WLMTK_BOX_HORIZONTAL)) { + if (!wlmtk_box_init(&resizebar_ptr->super_box, cursor_ptr, + WLMTK_BOX_HORIZONTAL)) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } @@ -87,7 +89,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( &resizebar_element_vmt); resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( - window_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); + window_ptr, cursor_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -97,7 +99,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( - window_ptr, WLR_EDGE_BOTTOM); + window_ptr, cursor_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -108,7 +110,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( - window_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); + window_ptr, cursor_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -291,7 +293,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = {}; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - &fake_window_ptr->window, &style); + NULL, &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); @@ -306,7 +308,7 @@ void test_variable_width(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - &fake_window_ptr->window, &style); + NULL, &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index f52766f3..d2f7ccb0 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -51,12 +51,14 @@ typedef struct { /** * Creates the resize bar. * + * @param cursor_ptr * @param window_ptr * @param style_ptr * * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( + wlmtk_cursor_t *cursor_ptr, wlmtk_window_t *window_ptr, const wlmtk_resizebar_style_t *style_ptr); diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 1576d4db..af19a85f 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -96,6 +96,7 @@ static const wlmtk_element_vmt_t resizebar_area_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( wlmtk_window_t *window_ptr, + wlmtk_cursor_t *cursor_ptr, uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( @@ -120,7 +121,7 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( bs_log(BS_ERROR, "Unsupported edge %"PRIx32, edges); } - if (!wlmtk_buffer_init(&resizebar_area_ptr->super_buffer)) { + if (!wlmtk_buffer_init(&resizebar_area_ptr->super_buffer, cursor_ptr)) { wlmtk_resizebar_area_destroy(resizebar_area_ptr); return NULL; } @@ -336,7 +337,7 @@ void test_area(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( - &fake_window_ptr->window, WLR_EDGE_BOTTOM); + &fake_window_ptr->window, NULL, WLR_EDGE_BOTTOM); BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index 472756de..61d096d0 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -42,12 +42,14 @@ struct wlr_xcursor_manager; * Creates a resizebar button. * * @param window_ptr + * @param cursor_ptr * @param edges * * @return Pointer to the resizebar button. */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( wlmtk_window_t *window_ptr, + wlmtk_cursor_t *cursor_ptr, uint32_t edges); /** diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 920d46e0..2e4a4de5 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -85,6 +85,7 @@ static const wlmtk_element_vmt_t titlebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( + wlmtk_cursor_t *cursor_ptr, wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr) { @@ -94,7 +95,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); - if (!wlmtk_box_init(&titlebar_ptr->super_box, WLMTK_BOX_HORIZONTAL)) { + if (!wlmtk_box_init(&titlebar_ptr->super_box, cursor_ptr, + WLMTK_BOX_HORIZONTAL)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } @@ -102,7 +104,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( &titlebar_ptr->super_box.super_container.super_element, &titlebar_element_vmt); - titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create(window_ptr); + titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create( + cursor_ptr, window_ptr); if (NULL == titlebar_ptr->titlebar_title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -112,6 +115,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( + cursor_ptr, wlmtk_window_request_minimize, window_ptr, wlmaker_primitives_draw_minimize_icon); @@ -124,6 +128,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( + cursor_ptr, wlmtk_window_request_close, window_ptr, wlmaker_primitives_draw_close_icon); @@ -371,7 +376,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = {}; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - &fake_window_ptr->window, &style); + NULL, &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); @@ -385,7 +390,7 @@ void test_variable_width(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = { .height = 22 }; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - &fake_window_ptr->window, &style); + NULL, &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); // Short names, for improved readability. diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 42b733ac..1ba81181 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -51,6 +51,7 @@ typedef struct { /** * Creates a title bar, suitable as a window title. * + * @param cursor_ptr * @param window_ptr * @param style_ptr * @@ -58,6 +59,7 @@ typedef struct { * by calling @ref wlmtk_titlebar_destroy. */ wlmtk_titlebar_t *wlmtk_titlebar_create( + wlmtk_cursor_t *cursor_ptr, wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr); diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 313cba9e..393b1e0d 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -78,6 +78,7 @@ static const wlmtk_button_vmt_t titlebar_button_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_cursor_t *cursor_ptr, void (*click_handler)(wlmtk_window_t *window_ptr), wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw) @@ -92,7 +93,7 @@ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( titlebar_button_ptr->window_ptr = window_ptr; titlebar_button_ptr->draw = draw; - if (!wlmtk_button_init(&titlebar_button_ptr->super_button)) { + if (!wlmtk_button_init(&titlebar_button_ptr->super_button, cursor_ptr)) { wlmtk_titlebar_button_destroy(titlebar_button_ptr); return NULL; } @@ -275,6 +276,7 @@ void test_button(bs_test_t *test_ptr) { wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( + NULL, wlmtk_window_request_close, &fake_window_ptr->window, wlmaker_primitives_draw_close_icon); diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index e4596dd7..bfa3ce61 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -39,6 +39,7 @@ typedef void (*wlmtk_titlebar_button_draw_t)( /** * Creates a button for the titlebar. * + * @param cursor_ptr * @param click_handler * @param window_ptr * @param draw @@ -46,6 +47,7 @@ typedef void (*wlmtk_titlebar_button_draw_t)( * @return Pointer to the titlebar button, or NULL on error. */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( + wlmtk_cursor_t *cursor_ptr, void (*click_handler)(wlmtk_window_t *window_ptr), wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw); diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index e7ecfdf2..692e3833 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -73,6 +73,7 @@ static const wlmtk_element_vmt_t titlebar_title_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + wlmtk_cursor_t *cursor_ptr, wlmtk_window_t *window_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( @@ -80,7 +81,7 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( if (NULL == titlebar_title_ptr) return NULL; titlebar_title_ptr->window_ptr = window_ptr; - if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer)) { + if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer, cursor_ptr)) { wlmtk_titlebar_title_destroy(titlebar_title_ptr); return NULL; } @@ -283,7 +284,7 @@ void test_title(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( - &fake_window_ptr->window); + NULL, &fake_window_ptr->window); wlmtk_element_t *element_ptr = wlmtk_titlebar_title_element( titlebar_title_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h index 2901746c..b84d91e0 100644 --- a/src/toolkit/titlebar_title.h +++ b/src/toolkit/titlebar_title.h @@ -35,11 +35,13 @@ extern "C" { /** * Creates a title bar title. * + * @param cursor_ptr * @param window_ptr * * @return Title handle. */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( + wlmtk_cursor_t *cursor_ptr, wlmtk_window_t *window_ptr); /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7c11b3ea..1ee1b580 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -26,6 +26,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, const wlmtk_window_impl_t *impl_ptr, + wlmtk_cursor_t *cursor_ptr, wlmtk_content_t *content_ptr); void wlmtk_window_fini(wlmtk_window_t *window_ptr); @@ -162,12 +163,14 @@ static const wlmtk_resizebar_style_t resizebar_style = { * * @param window_ptr * @param impl_ptr + * @param cursor_ptr * @param content_ptr Will take ownership of it. * * @return true on success. */ bool wlmtk_window_init(wlmtk_window_t *window_ptr, const wlmtk_window_impl_t *impl_ptr, + wlmtk_cursor_t *cursor_ptr, wlmtk_content_t *content_ptr) { BS_ASSERT(NULL != window_ptr); @@ -188,7 +191,8 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, &window_ptr->pre_allocated_updates[i].dlnode); } - if (!wlmtk_box_init(&window_ptr->super_box, WLMTK_BOX_VERTICAL)) { + if (!wlmtk_box_init(&window_ptr->super_box, cursor_ptr, + WLMTK_BOX_VERTICAL)) { wlmtk_window_fini(window_ptr); return false; } @@ -201,7 +205,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_set_title(window_ptr, NULL); window_ptr->resizebar_ptr = wlmtk_resizebar_create( - window_ptr, &resizebar_style); + cursor_ptr, window_ptr, &resizebar_style); if (NULL == window_ptr->resizebar_ptr) { wlmtk_window_fini(window_ptr); return false; @@ -221,7 +225,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); window_ptr->titlebar_ptr = wlmtk_titlebar_create( - window_ptr, &titlebar_style); + cursor_ptr, window_ptr, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_fini(window_ptr); return false; @@ -288,7 +292,8 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!wlmtk_window_init(window_ptr, &window_default_impl, content_ptr)) { + if (!wlmtk_window_init(window_ptr, &window_default_impl, NULL, + content_ptr)) { wlmtk_window_destroy(window_ptr); return NULL; } @@ -482,6 +487,7 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) if (!wlmtk_window_init(&fake_window_ptr->window, &fake_window_impl, + NULL, &fake_window_ptr->fake_content_ptr->content)) { wlmtk_fake_window_destroy(fake_window_ptr); return NULL; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index f0d3336b..0521a103 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -144,6 +144,7 @@ static const wlmtk_fsm_transition_t pfsm_transitions[] = { /* ------------------------------------------------------------------------- */ wlmtk_workspace_t *wlmtk_workspace_create( + wlmtk_cursor_t *cursor_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { wlmtk_workspace_t *workspace_ptr = @@ -151,6 +152,7 @@ wlmtk_workspace_t *wlmtk_workspace_create( if (NULL == workspace_ptr) return NULL; if (!wlmtk_container_init_attached(&workspace_ptr->super_container, + cursor_ptr, wlr_scene_tree_ptr)) { wlmtk_workspace_destroy(workspace_ptr); return NULL; @@ -584,7 +586,7 @@ void test_create_destroy(bs_test_t *test_ptr) BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); BS_TEST_VERIFY_EQ( @@ -614,7 +616,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); @@ -657,7 +659,7 @@ void test_button(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&fake_element_ptr->element, true); @@ -716,7 +718,7 @@ void test_move(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( @@ -762,7 +764,7 @@ void test_unmap_during_move(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( @@ -806,7 +808,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_content_commit_size(&fake_content_ptr->content, 1, 40, 20); @@ -862,7 +864,7 @@ void test_activate(bs_test_t *test_ptr) wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); BS_ASSERT(NULL != fake_parent_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - fake_parent_ptr->wlr_scene_tree_ptr); + NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); // Window 1: from (0, 0) to (100, 100) diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index d4ddc198..87c0227e 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -41,12 +41,14 @@ struct wlr_box; * TODO(kaeser@gubbe.ch): Consider replacing the interface with a container, * and permit a "toplevel" container that will be at the server level. * + * @param cursor_ptr * @param wlr_scene_tree_ptr * * @return Pointer to the workspace state, or NULL on error. Must be free'd * via @ref wlmtk_workspace_destroy. */ wlmtk_workspace_t *wlmtk_workspace_create( + wlmtk_cursor_t *cursor_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); /** diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 234f50f0..384790e8 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -140,6 +140,7 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( if (NULL == xdg_tl_content_ptr) return NULL; if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, + NULL, server_ptr->wlr_seat_ptr)) { xdg_toplevel_content_destroy(xdg_tl_content_ptr); return NULL; diff --git a/src/workspace.c b/src/workspace.c index be181efe..c01a87a9 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -173,7 +173,7 @@ wlmaker_workspace_t *wlmaker_workspace_create(wlmaker_server_t *server_ptr, #if defined(ENABLE_TOOLKIT_PROTOTYPE) // Transitional -- enable for prototyping: Toolkit-based workspace. workspace_ptr->wlmtk_workspace_ptr = wlmtk_workspace_create( - workspace_ptr->wlr_scene_tree_ptr); + NULL, workspace_ptr->wlr_scene_tree_ptr); if (NULL == workspace_ptr->wlmtk_workspace_ptr) { wlmaker_workspace_destroy(workspace_ptr); return NULL; From 51bff0d5603313a02314601816a4cf2f1e43d687 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 27 Nov 2023 19:58:22 +0100 Subject: [PATCH 264/390] Changes wlmtk_cursor_t to wlmtk_env_t, since we also want to store wlr_seat there. --- src/toolkit/box.c | 4 ++-- src/toolkit/box.h | 4 ++-- src/toolkit/buffer.c | 4 ++-- src/toolkit/buffer.h | 4 ++-- src/toolkit/button.c | 4 ++-- src/toolkit/button.h | 4 ++-- src/toolkit/container.c | 8 ++++---- src/toolkit/container.h | 8 ++++---- src/toolkit/content.c | 4 ++-- src/toolkit/content.h | 4 ++-- src/toolkit/element.c | 2 +- src/toolkit/element.h | 4 ++-- src/toolkit/input.h | 9 ++------- src/toolkit/resizebar.c | 10 +++++----- src/toolkit/resizebar.h | 4 ++-- src/toolkit/resizebar_area.c | 4 ++-- src/toolkit/resizebar_area.h | 4 ++-- src/toolkit/titlebar.c | 10 +++++----- src/toolkit/titlebar.h | 4 ++-- src/toolkit/titlebar_button.c | 4 ++-- src/toolkit/titlebar_button.h | 4 ++-- src/toolkit/titlebar_title.c | 4 ++-- src/toolkit/titlebar_title.h | 4 ++-- src/toolkit/window.c | 12 ++++++------ src/toolkit/workspace.c | 7 +++---- src/toolkit/workspace.h | 4 ++-- 26 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 63fd18ec..d13661d7 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -37,12 +37,12 @@ static const wlmtk_container_vmt_t box_container_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_box_orientation_t orientation) { BS_ASSERT(NULL != box_ptr); memset(box_ptr, 0, sizeof(wlmtk_box_t)); - if (!wlmtk_container_init(&box_ptr->super_container, cursor_ptr)) { + if (!wlmtk_container_init(&box_ptr->super_container, env_ptr)) { return false; } box_ptr->orig_super_container_vmt = wlmtk_container_extend( diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 94d3d43d..81b39b14 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -50,13 +50,13 @@ struct _wlmtk_box_t { * * @param box_ptr * @param orientation - * @param cursor_ptr + * @param env_ptr * * @return true on success. */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_box_orientation_t orientation); /** diff --git a/src/toolkit/buffer.c b/src/toolkit/buffer.c index 416e679c..351e0fe7 100644 --- a/src/toolkit/buffer.c +++ b/src/toolkit/buffer.c @@ -53,12 +53,12 @@ static const wlmtk_element_vmt_t buffer_element_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr, - wlmtk_cursor_t *cursor_ptr) + wlmtk_env_t *env_ptr) { BS_ASSERT(NULL != buffer_ptr); memset(buffer_ptr, 0, sizeof(wlmtk_buffer_t)); - if (!wlmtk_element_init(&buffer_ptr->super_element, cursor_ptr)) { + if (!wlmtk_element_init(&buffer_ptr->super_element, env_ptr)) { return false; } buffer_ptr->orig_super_element_vmt = wlmtk_element_extend( diff --git a/src/toolkit/buffer.h b/src/toolkit/buffer.h index f5826eb8..87655b9c 100644 --- a/src/toolkit/buffer.h +++ b/src/toolkit/buffer.h @@ -56,12 +56,12 @@ struct _wlmtk_buffer_t { * Initializes the buffer. * * @param buffer_ptr - * @param cursor_ptr + * @param env_ptr * * @return true on success. */ bool wlmtk_buffer_init(wlmtk_buffer_t *buffer_ptr, - wlmtk_cursor_t *cursor_ptr); + wlmtk_env_t *env_ptr); /** * Cleans up the buffer. diff --git a/src/toolkit/button.c b/src/toolkit/button.c index a714001b..c8a59e28 100644 --- a/src/toolkit/button.c +++ b/src/toolkit/button.c @@ -61,13 +61,13 @@ static const wlmtk_button_vmt_t button_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_button_init( wlmtk_button_t *button_ptr, - wlmtk_cursor_t *cursor_ptr) + wlmtk_env_t *env_ptr) { BS_ASSERT(NULL != button_ptr); memset(button_ptr, 0, sizeof(wlmtk_button_t)); button_ptr->vmt = button_vmt; - if (!wlmtk_buffer_init(&button_ptr->super_buffer, cursor_ptr)) { + if (!wlmtk_buffer_init(&button_ptr->super_buffer, env_ptr)) { wlmtk_button_fini(button_ptr); return false; } diff --git a/src/toolkit/button.h b/src/toolkit/button.h index 17f39a08..443ef9c6 100644 --- a/src/toolkit/button.h +++ b/src/toolkit/button.h @@ -58,12 +58,12 @@ struct _wlmtk_button_t { * Initializes the button. * * @param button_ptr - * @param cursor_ptr + * @param env_ptr * * @return true on success. */ bool wlmtk_button_init(wlmtk_button_t *button_ptr, - wlmtk_cursor_t *cursor_ptr); + wlmtk_env_t *env_ptr); /** * Extends the button's virtual methods. diff --git a/src/toolkit/container.c b/src/toolkit/container.c index db750ff1..ceb6dcbe 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -80,13 +80,13 @@ static const wlmtk_container_vmt_t container_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_container_init( wlmtk_container_t *container_ptr, - wlmtk_cursor_t *cursor_ptr) + wlmtk_env_t *env_ptr) { BS_ASSERT(NULL != container_ptr); memset(container_ptr, 0, sizeof(wlmtk_container_t)); container_ptr->vmt = container_vmt; - if (!wlmtk_element_init(&container_ptr->super_element, cursor_ptr)) { + if (!wlmtk_element_init(&container_ptr->super_element, env_ptr)) { return false; } container_ptr->orig_super_element_vmt = wlmtk_element_extend( @@ -98,10 +98,10 @@ bool wlmtk_container_init( /* ------------------------------------------------------------------------- */ bool wlmtk_container_init_attached( wlmtk_container_t *container_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, struct wlr_scene_tree *root_wlr_scene_tree_ptr) { - if (!wlmtk_container_init(container_ptr, cursor_ptr)) return false; + if (!wlmtk_container_init(container_ptr, env_ptr)) return false; container_ptr->super_element.wlr_scene_node_ptr = element_create_scene_node( diff --git a/src/toolkit/container.h b/src/toolkit/container.h index ab512706..6ddd737a 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -80,12 +80,12 @@ struct _wlmtk_container_t { * Initializes the container with the provided virtual method table. * * @param container_ptr - * @param cursor_ptr + * @param env_ptr * * @return true on success. */ bool wlmtk_container_init(wlmtk_container_t *container_ptr, - wlmtk_cursor_t *cursor_ptr); + wlmtk_env_t *env_ptr); /** * Extends the container's virtual methods. @@ -103,14 +103,14 @@ wlmtk_container_vmt_t wlmtk_container_extend( * Initializes the container, and attach to WLR sene graph. * * @param container_ptr - * @param cursor_ptr + * @param env_ptr * @param root_wlr_scene_tree_ptr * * @return true on success. */ bool wlmtk_container_init_attached( wlmtk_container_t *container_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, struct wlr_scene_tree *root_wlr_scene_tree_ptr); /** diff --git a/src/toolkit/content.c b/src/toolkit/content.c index a3388fbd..2c82dd23 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -70,13 +70,13 @@ void *wlmtk_content_identifier_ptr = wlmtk_content_init; /* ------------------------------------------------------------------------- */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, struct wlr_seat *wlr_seat_ptr) { BS_ASSERT(NULL != content_ptr); memset(content_ptr, 0, sizeof(wlmtk_content_t)); - if (!wlmtk_element_init(&content_ptr->super_element, cursor_ptr)) { + if (!wlmtk_element_init(&content_ptr->super_element, env_ptr)) { return false; } content_ptr->orig_super_element_vmt = wlmtk_element_extend( diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 52996a6c..5ccfb118 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -85,14 +85,14 @@ struct _wlmtk_content_t { * Initializes the content. * * @param content_ptr - * @param cursor_ptr + * @param env_ptr * @param wlr_seat_ptr * * @return true on success. */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, struct wlr_seat *wlr_seat_ptr); /** diff --git a/src/toolkit/element.c b/src/toolkit/element.c index b5c837b1..96039465 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -68,7 +68,7 @@ static const wlmtk_element_vmt_t element_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_element_init( wlmtk_element_t *element_ptr, - __UNUSED__ wlmtk_cursor_t *cursor_ptr) + __UNUSED__ wlmtk_env_t *env_ptr) { BS_ASSERT(NULL != element_ptr); memset(element_ptr, 0, sizeof(wlmtk_element_t)); diff --git a/src/toolkit/element.h b/src/toolkit/element.h index b63722ae..b511d7fc 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -168,12 +168,12 @@ struct _wlmtk_element_t { * Initializes the element. * * @param element_ptr - * @param cursor_ptr + * @param env_ptr * * @return true on success. */ bool wlmtk_element_init(wlmtk_element_t *element_ptr, - wlmtk_cursor_t *cursor_ptr); + wlmtk_env_t *env_ptr); /** * Extends the element's virtual methods. diff --git a/src/toolkit/input.h b/src/toolkit/input.h index c6610d6a..5b939245 100644 --- a/src/toolkit/input.h +++ b/src/toolkit/input.h @@ -29,8 +29,8 @@ extern "C" { /** Forward declaration: Button event. */ typedef struct _wlmtk_button_event_t wlmtk_button_event_t; -/** Forward declaration: Cursor. */ -typedef struct _wlmtk_cursor_t wlmtk_cursor_t; +/** Forward declaration: Environment. */ +typedef struct _wlmtk_env_t wlmtk_env_t; /** Button state. */ typedef enum { @@ -50,11 +50,6 @@ struct _wlmtk_button_event_t { uint32_t time_msec; }; -/** Ctor: Creates a fake cursor. */ -wlmtk_cursor_t *wlmtk_fake_cursor_create(void); -/** Dtor: Destroys the fake cursor. */ -void wlmtk_fake_cursor_destroy(wlmtk_cursor_t *cursor_ptr); - #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index d02b4b65..e46b51c7 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -70,7 +70,7 @@ static const wlmtk_element_vmt_t resizebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_window_t *window_ptr, const wlmtk_resizebar_style_t *style_ptr) { @@ -79,7 +79,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( if (NULL == resizebar_ptr) return NULL; memcpy(&resizebar_ptr->style, style_ptr, sizeof(wlmtk_resizebar_style_t)); - if (!wlmtk_box_init(&resizebar_ptr->super_box, cursor_ptr, + if (!wlmtk_box_init(&resizebar_ptr->super_box, env_ptr, WLMTK_BOX_HORIZONTAL)) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -89,7 +89,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( &resizebar_element_vmt); resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( - window_ptr, cursor_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); + window_ptr, env_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -99,7 +99,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( - window_ptr, cursor_ptr, WLR_EDGE_BOTTOM); + window_ptr, env_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -110,7 +110,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( - window_ptr, cursor_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); + window_ptr, env_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index d2f7ccb0..84ba8509 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -51,14 +51,14 @@ typedef struct { /** * Creates the resize bar. * - * @param cursor_ptr + * @param env_ptr * @param window_ptr * @param style_ptr * * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_window_t *window_ptr, const wlmtk_resizebar_style_t *style_ptr); diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index af19a85f..a5b08850 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -96,7 +96,7 @@ static const wlmtk_element_vmt_t resizebar_area_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( wlmtk_window_t *window_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( @@ -121,7 +121,7 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( bs_log(BS_ERROR, "Unsupported edge %"PRIx32, edges); } - if (!wlmtk_buffer_init(&resizebar_area_ptr->super_buffer, cursor_ptr)) { + if (!wlmtk_buffer_init(&resizebar_area_ptr->super_buffer, env_ptr)) { wlmtk_resizebar_area_destroy(resizebar_area_ptr); return NULL; } diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index 61d096d0..4cc972e3 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -42,14 +42,14 @@ struct wlr_xcursor_manager; * Creates a resizebar button. * * @param window_ptr - * @param cursor_ptr + * @param env_ptr * @param edges * * @return Pointer to the resizebar button. */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( wlmtk_window_t *window_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, uint32_t edges); /** diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 2e4a4de5..3804bd03 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -85,7 +85,7 @@ static const wlmtk_element_vmt_t titlebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr) { @@ -95,7 +95,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); - if (!wlmtk_box_init(&titlebar_ptr->super_box, cursor_ptr, + if (!wlmtk_box_init(&titlebar_ptr->super_box, env_ptr, WLMTK_BOX_HORIZONTAL)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -105,7 +105,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( &titlebar_element_vmt); titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create( - cursor_ptr, window_ptr); + env_ptr, window_ptr); if (NULL == titlebar_ptr->titlebar_title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -115,7 +115,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( - cursor_ptr, + env_ptr, wlmtk_window_request_minimize, window_ptr, wlmaker_primitives_draw_minimize_icon); @@ -128,7 +128,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( - cursor_ptr, + env_ptr, wlmtk_window_request_close, window_ptr, wlmaker_primitives_draw_close_icon); diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 1ba81181..e32612c4 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -51,7 +51,7 @@ typedef struct { /** * Creates a title bar, suitable as a window title. * - * @param cursor_ptr + * @param env_ptr * @param window_ptr * @param style_ptr * @@ -59,7 +59,7 @@ typedef struct { * by calling @ref wlmtk_titlebar_destroy. */ wlmtk_titlebar_t *wlmtk_titlebar_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr); diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 393b1e0d..4c66ef05 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -78,7 +78,7 @@ static const wlmtk_button_vmt_t titlebar_button_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, void (*click_handler)(wlmtk_window_t *window_ptr), wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw) @@ -93,7 +93,7 @@ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( titlebar_button_ptr->window_ptr = window_ptr; titlebar_button_ptr->draw = draw; - if (!wlmtk_button_init(&titlebar_button_ptr->super_button, cursor_ptr)) { + if (!wlmtk_button_init(&titlebar_button_ptr->super_button, env_ptr)) { wlmtk_titlebar_button_destroy(titlebar_button_ptr); return NULL; } diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index bfa3ce61..83501f00 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -39,7 +39,7 @@ typedef void (*wlmtk_titlebar_button_draw_t)( /** * Creates a button for the titlebar. * - * @param cursor_ptr + * @param env_ptr * @param click_handler * @param window_ptr * @param draw @@ -47,7 +47,7 @@ typedef void (*wlmtk_titlebar_button_draw_t)( * @return Pointer to the titlebar button, or NULL on error. */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, void (*click_handler)(wlmtk_window_t *window_ptr), wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw); diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index 692e3833..54c6057d 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -73,7 +73,7 @@ static const wlmtk_element_vmt_t titlebar_title_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_window_t *window_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( @@ -81,7 +81,7 @@ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( if (NULL == titlebar_title_ptr) return NULL; titlebar_title_ptr->window_ptr = window_ptr; - if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer, cursor_ptr)) { + if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer, env_ptr)) { wlmtk_titlebar_title_destroy(titlebar_title_ptr); return NULL; } diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h index b84d91e0..58b82820 100644 --- a/src/toolkit/titlebar_title.h +++ b/src/toolkit/titlebar_title.h @@ -35,13 +35,13 @@ extern "C" { /** * Creates a title bar title. * - * @param cursor_ptr + * @param env_ptr * @param window_ptr * * @return Title handle. */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_window_t *window_ptr); /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 1ee1b580..ee36c8f1 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -26,7 +26,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, const wlmtk_window_impl_t *impl_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr); void wlmtk_window_fini(wlmtk_window_t *window_ptr); @@ -163,14 +163,14 @@ static const wlmtk_resizebar_style_t resizebar_style = { * * @param window_ptr * @param impl_ptr - * @param cursor_ptr + * @param env_ptr * @param content_ptr Will take ownership of it. * * @return true on success. */ bool wlmtk_window_init(wlmtk_window_t *window_ptr, const wlmtk_window_impl_t *impl_ptr, - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr) { BS_ASSERT(NULL != window_ptr); @@ -191,7 +191,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, &window_ptr->pre_allocated_updates[i].dlnode); } - if (!wlmtk_box_init(&window_ptr->super_box, cursor_ptr, + if (!wlmtk_box_init(&window_ptr->super_box, env_ptr, WLMTK_BOX_VERTICAL)) { wlmtk_window_fini(window_ptr); return false; @@ -205,7 +205,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_set_title(window_ptr, NULL); window_ptr->resizebar_ptr = wlmtk_resizebar_create( - cursor_ptr, window_ptr, &resizebar_style); + env_ptr, window_ptr, &resizebar_style); if (NULL == window_ptr->resizebar_ptr) { wlmtk_window_fini(window_ptr); return false; @@ -225,7 +225,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); window_ptr->titlebar_ptr = wlmtk_titlebar_create( - cursor_ptr, window_ptr, &titlebar_style); + env_ptr, window_ptr, &titlebar_style); if (NULL == window_ptr->titlebar_ptr) { wlmtk_window_fini(window_ptr); return false; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 0521a103..f7bf19ac 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -144,16 +144,15 @@ static const wlmtk_fsm_transition_t pfsm_transitions[] = { /* ------------------------------------------------------------------------- */ wlmtk_workspace_t *wlmtk_workspace_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { wlmtk_workspace_t *workspace_ptr = logged_calloc(1, sizeof(wlmtk_workspace_t)); if (NULL == workspace_ptr) return NULL; - if (!wlmtk_container_init_attached(&workspace_ptr->super_container, - cursor_ptr, - wlr_scene_tree_ptr)) { + if (!wlmtk_container_init_attached( + &workspace_ptr->super_container, env_ptr, wlr_scene_tree_ptr)) { wlmtk_workspace_destroy(workspace_ptr); return NULL; } diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 87c0227e..461e93ca 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -41,14 +41,14 @@ struct wlr_box; * TODO(kaeser@gubbe.ch): Consider replacing the interface with a container, * and permit a "toplevel" container that will be at the server level. * - * @param cursor_ptr + * @param env_ptr * @param wlr_scene_tree_ptr * * @return Pointer to the workspace state, or NULL on error. Must be free'd * via @ref wlmtk_workspace_destroy. */ wlmtk_workspace_t *wlmtk_workspace_create( - wlmtk_cursor_t *cursor_ptr, + wlmtk_env_t *env_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); /** From 1446e49f61b3bc3bc0644a234bfd41c01d7fab96 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 27 Nov 2023 21:16:54 +0100 Subject: [PATCH 265/390] Adds wlmtk_env_t and wlmtk_env_set_cursor. --- src/server.c | 14 +++++ src/server.h | 5 ++ src/toolkit/CMakeLists.txt | 2 + src/toolkit/element.c | 3 +- src/toolkit/element.h | 4 ++ src/toolkit/env.c | 100 +++++++++++++++++++++++++++++++++++ src/toolkit/env.h | 79 +++++++++++++++++++++++++++ src/toolkit/input.h | 2 - src/toolkit/resizebar_area.c | 15 +++--- src/toolkit/resizebar_area.h | 5 -- src/toolkit/toolkit.h | 1 + src/toolkit/window.c | 13 ++--- src/toolkit/window.h | 2 + src/toolkit/workspace.c | 8 +-- src/wlmtk_xdg_toplevel.c | 1 + 15 files changed, 228 insertions(+), 26 deletions(-) create mode 100644 src/toolkit/env.c create mode 100644 src/toolkit/env.h diff --git a/src/server.c b/src/server.c index c390ab38..6f7864ed 100644 --- a/src/server.c +++ b/src/server.c @@ -311,6 +311,15 @@ wlmaker_server_t *wlmaker_server_create(void) return NULL; } + server_ptr->env_ptr = wlmtk_env_create( + server_ptr->cursor_ptr->wlr_cursor_ptr, + server_ptr->cursor_ptr->wlr_xcursor_manager_ptr); + if (NULL == server_ptr->env_ptr) { + wlmaker_server_destroy(server_ptr); + return NULL; + } + + return server_ptr; } @@ -325,6 +334,11 @@ void wlmaker_server_destroy(wlmaker_server_t *server_ptr) // * server_ptr->wlr_scene_ptr (there is no "destroy" function) // * server_ptr->void_wlr_scene_ptr + if (NULL != server_ptr->env_ptr) { + wlmtk_env_destroy(server_ptr->env_ptr); + server_ptr->env_ptr = NULL; + } + if (NULL != server_ptr->monitor_ptr) { wlmaker_subprocess_monitor_destroy(server_ptr->monitor_ptr); server_ptr->monitor_ptr =NULL; diff --git a/src/server.h b/src/server.h index 0b7f7b92..91de2968 100644 --- a/src/server.h +++ b/src/server.h @@ -49,6 +49,8 @@ typedef struct _wlmaker_server_t wlmaker_server_t; #include "xdg_shell.h" #include "workspace.h" +#include "toolkit/toolkit.h" + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -119,6 +121,9 @@ struct _wlmaker_server_t { /** The list of input devices. */ bs_dllist_t input_devices; + /** Toolkit environment. */ + wlmtk_env_t *env_ptr; + /** The current workspace. */ wlmaker_workspace_t *current_workspace_ptr; /** List of all workspaces. */ diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index afaedc25..928cf4f7 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(PUBLIC_HEADER_FILES container.h content.h element.h + env.h fsm.h input.h resizebar.h @@ -45,6 +46,7 @@ TARGET_SOURCES(toolkit PRIVATE container.c content.c element.c + env.c fsm.c gfxbuf.c primitives.c diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 96039465..8a94929c 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -68,11 +68,12 @@ static const wlmtk_element_vmt_t element_vmt = { /* ------------------------------------------------------------------------- */ bool wlmtk_element_init( wlmtk_element_t *element_ptr, - __UNUSED__ wlmtk_env_t *env_ptr) + wlmtk_env_t *env_ptr) { BS_ASSERT(NULL != element_ptr); memset(element_ptr, 0, sizeof(wlmtk_element_t)); element_ptr->vmt = element_vmt; + element_ptr->env_ptr = env_ptr; element_ptr->last_pointer_x = NAN; element_ptr->last_pointer_y = NAN; diff --git a/src/toolkit/element.h b/src/toolkit/element.h index b511d7fc..de567125 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -32,6 +32,7 @@ typedef struct _wlmtk_element_vmt_t wlmtk_element_vmt_t; typedef struct _wlmtk_container_t wlmtk_container_t; struct wlr_scene_tree; +#include "env.h" #include "input.h" #ifdef __cplusplus @@ -133,6 +134,9 @@ struct _wlmtk_element_t { /** Virtual method table for the element. */ wlmtk_element_vmt_t vmt; + /** Toolkit environment. */ + wlmtk_env_t *env_ptr; + /** Points to the wlroots scene graph API node, if attached. */ struct wlr_scene_node *wlr_scene_node_ptr; diff --git a/src/toolkit/env.c b/src/toolkit/env.c new file mode 100644 index 00000000..e22bebbe --- /dev/null +++ b/src/toolkit/env.c @@ -0,0 +1,100 @@ +/* ========================================================================= */ +/** + * @file env.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "env.h" + +#include + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +/** State of the environment. */ +struct _wlmtk_env_t { + /** Points to a `wlr_cursor`. */ + struct wlr_cursor *wlr_cursor_ptr; + /** Points to a `wlr_xcursor_manager`. */ + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr; +}; + +/** Struct to identify a @ref wlmtk_env_cursor_t with the xcursor name. */ +typedef struct { + /** The cursor. */ + wlmtk_env_cursor_t cursor; + /** And the xcursor name. */ + const char *xcursor_name_ptr; +} wlmtk_env_cursor_lookup_t; + +/** Lookup table for xcursor names. */ +static const wlmtk_env_cursor_lookup_t _wlmtk_env_cursor_lookup[] = { + { WLMTK_CURSOR_DEFAULT, "default" }, + { WLMTK_CURSOR_RESIZE_S, "s-resize" }, + { WLMTK_CURSOR_RESIZE_SE, "se-resize" }, + { WLMTK_CURSOR_RESIZE_SW, "sw-resize" }, + { 0, NULL }, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_env_t *wlmtk_env_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr) +{ + wlmtk_env_t *env_ptr = logged_calloc(1, sizeof(wlmtk_env_t)); + if (NULL == env_ptr) return NULL; + + env_ptr->wlr_cursor_ptr = wlr_cursor_ptr; + env_ptr->wlr_xcursor_manager_ptr = wlr_xcursor_manager_ptr; + + return env_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_env_destroy(wlmtk_env_t *env_ptr) +{ + free(env_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_env_set_cursor(wlmtk_env_t *env_ptr, wlmtk_env_cursor_t cursor) +{ + const wlmtk_env_cursor_lookup_t *lookup_ptr = &_wlmtk_env_cursor_lookup[0]; + for (; + NULL != lookup_ptr->xcursor_name_ptr && cursor != lookup_ptr->cursor; + ++lookup_ptr) ; + if (NULL == lookup_ptr->xcursor_name_ptr) { + bs_log(BS_FATAL, "No name for cursor %d", cursor); + return; + } + + if (NULL != env_ptr && + NULL != env_ptr->wlr_cursor_ptr && + NULL != env_ptr->wlr_xcursor_manager_ptr) { + wlr_cursor_set_xcursor( + env_ptr->wlr_cursor_ptr, + env_ptr->wlr_xcursor_manager_ptr, + lookup_ptr->xcursor_name_ptr); + } +} + +/* == End of env.c ========================================================= */ diff --git a/src/toolkit/env.h b/src/toolkit/env.h new file mode 100644 index 00000000..d1cba218 --- /dev/null +++ b/src/toolkit/env.h @@ -0,0 +1,79 @@ +/* ========================================================================= */ +/** + * @file env.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ENV_H__ +#define __ENV_H__ + +/** Forward declaration: Environment. */ +typedef struct _wlmtk_env_t wlmtk_env_t; + +/** Forward declaration. */ +struct wlr_cursor; +/** Forward declaration. */ +struct wlr_xcursor_manager; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Cursor types. */ +typedef enum { + /** Default. */ + WLMTK_CURSOR_DEFAULT, + /** Resizing, southern border. */ + WLMTK_CURSOR_RESIZE_S, + /** Resizing, south-eastern corner. */ + WLMTK_CURSOR_RESIZE_SE, + /** Resizing, south-western corner. */ + WLMTK_CURSOR_RESIZE_SW, +} wlmtk_env_cursor_t; + +/** + * Creates an environment state from the cursor. + * + * @param wlr_cursor_ptr + * @param wlr_xcursor_manager_ptr + * + * @return An environment state or NULL on error. + */ +wlmtk_env_t *wlmtk_env_create( + struct wlr_cursor *wlr_cursor_ptr, + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr); + +/** + * Destroys the environment state. + * + * @param env_ptr + */ +void wlmtk_env_destroy(wlmtk_env_t *env_ptr); + +/** + * Sets a cursor. + * + * @param env_ptr + * @param cursor + */ +void wlmtk_env_set_cursor(wlmtk_env_t *env_ptr, wlmtk_env_cursor_t cursor); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __ENV_H__ */ +/* == End of env.h ========================================================= */ diff --git a/src/toolkit/input.h b/src/toolkit/input.h index 5b939245..fbf18ef2 100644 --- a/src/toolkit/input.h +++ b/src/toolkit/input.h @@ -29,8 +29,6 @@ extern "C" { /** Forward declaration: Button event. */ typedef struct _wlmtk_button_event_t wlmtk_button_event_t; -/** Forward declaration: Environment. */ -typedef struct _wlmtk_env_t wlmtk_env_t; /** Button state. */ typedef enum { diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index a5b08850..da7e467b 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -62,6 +62,8 @@ struct _wlmtk_resizebar_area_t { struct wlr_xcursor_manager *wlr_xcursor_manager_ptr; /** Name of the cursor to show when having pointer focus. */ const char *xcursor_name_ptr; + /** The cursor to use when having pointer focus. */ + wlmtk_env_cursor_t cursor; }; static void _wlmtk_resizebar_area_element_destroy( @@ -106,15 +108,19 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( resizebar_area_ptr->window_ptr = window_ptr; resizebar_area_ptr->edges = edges; + resizebar_area_ptr->cursor = WLMTK_CURSOR_DEFAULT; resizebar_area_ptr->xcursor_name_ptr = "default"; // Fail-safe value. switch (resizebar_area_ptr->edges) { case WLR_EDGE_BOTTOM: + resizebar_area_ptr->cursor = WLMTK_CURSOR_RESIZE_S; resizebar_area_ptr->xcursor_name_ptr = "s-resize"; break; case WLR_EDGE_BOTTOM | WLR_EDGE_LEFT: + resizebar_area_ptr->cursor = WLMTK_CURSOR_RESIZE_SW; resizebar_area_ptr->xcursor_name_ptr = "sw-resize"; break; case WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT: + resizebar_area_ptr->cursor = WLMTK_CURSOR_RESIZE_SE; resizebar_area_ptr->xcursor_name_ptr = "se-resize"; break; default: @@ -218,14 +224,7 @@ bool _wlmtk_resizebar_area_element_pointer_motion( resizebar_area_ptr->orig_super_element_vmt.pointer_motion( element_ptr, x, y, time_msec); - // TODO(kaeser@gubbe.ch): Inject something testable here. - if (NULL != resizebar_area_ptr->wlr_cursor_ptr && - NULL != resizebar_area_ptr->wlr_xcursor_manager_ptr) { - wlr_cursor_set_xcursor( - resizebar_area_ptr->wlr_cursor_ptr, - resizebar_area_ptr->wlr_xcursor_manager_ptr, - resizebar_area_ptr->xcursor_name_ptr); - } + wlmtk_env_set_cursor(element_ptr->env_ptr, resizebar_area_ptr->cursor); return true; } diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index 4cc972e3..c420bf72 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -33,11 +33,6 @@ typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; extern "C" { #endif // __cplusplus -/** Forward declaration. */ -struct wlr_cursor; -/** Forward declaration. */ -struct wlr_xcursor_manager; - /** * Creates a resizebar button. * diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 287de098..2e548bf4 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -36,6 +36,7 @@ #include "container.h" #include "content.h" #include "element.h" +#include "env.h" #include "fsm.h" #include "input.h" #include "resizebar.h" diff --git a/src/toolkit/window.c b/src/toolkit/window.c index ee36c8f1..11ceb392 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -287,13 +287,14 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) wlmtk_window_t *wlmtk_window_create( struct wlr_cursor *wlr_cursor_ptr, struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr) { wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!wlmtk_window_init(window_ptr, &window_default_impl, NULL, - content_ptr)) { + if (!wlmtk_window_init( + window_ptr, &window_default_impl, env_ptr, content_ptr)) { wlmtk_window_destroy(window_ptr); return NULL; } @@ -829,7 +830,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, window_ptr, fake_content_ptr->content.window_ptr); @@ -843,7 +844,7 @@ void test_set_title(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); wlmtk_window_set_title(window_ptr, "Title"); BS_TEST_VERIFY_STREQ( @@ -866,7 +867,7 @@ void test_request_close(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); wlmtk_window_request_close(window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); @@ -880,7 +881,7 @@ void test_set_activated(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); wlmtk_window_set_activated(window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index d8e5a877..1022c826 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -123,6 +123,7 @@ struct _wlmtk_window_t { * * @param wlr_cursor_ptr * @param wlr_xcursor_manager_ptr + * @param env_ptr * @param content_ptr Will take ownership of content_ptr. * * @return Pointer to the window state, or NULL on error. Must be free'd @@ -131,6 +132,7 @@ struct _wlmtk_window_t { wlmtk_window_t *wlmtk_window_create( struct wlr_cursor *wlr_cursor_ptr, struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr); /** diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index f7bf19ac..729d5d8c 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -620,7 +620,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -721,7 +721,7 @@ void test_move(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -767,7 +767,7 @@ void test_unmap_during_move(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -812,7 +812,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_content_commit_size(&fake_content_ptr->content, 1, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, &fake_content_ptr->content); + NULL, NULL, NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 384790e8..32b9ab63 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -119,6 +119,7 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( server_ptr->cursor_ptr->wlr_cursor_ptr, server_ptr->cursor_ptr->wlr_xcursor_manager_ptr, + server_ptr->env_ptr, &content_ptr->super_content); if (NULL == wlmtk_window_ptr) { content_element_destroy(&content_ptr->super_content.super_element); From 30b014bf67f60cee250de3148b2c4709623f4312 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 27 Nov 2023 21:19:40 +0100 Subject: [PATCH 266/390] Removes the former wlr_cursor passdown. --- src/toolkit/resizebar.c | 20 -------------------- src/toolkit/resizebar.h | 14 -------------- src/toolkit/resizebar_area.c | 20 -------------------- src/toolkit/resizebar_area.h | 14 -------------- src/toolkit/window.c | 15 ++++----------- src/toolkit/window.h | 9 --------- src/toolkit/workspace.c | 8 ++++---- src/wlmtk_xdg_toplevel.c | 5 +---- 8 files changed, 9 insertions(+), 96 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index e46b51c7..0b181b98 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -158,26 +158,6 @@ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) free(resizebar_ptr); } -/* ------------------------------------------------------------------------- */ -void wlmtk_resizebar_set_cursor( - wlmtk_resizebar_t *resizebar_ptr, - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr) -{ - wlmtk_resizebar_area_set_cursor( - resizebar_ptr->left_area_ptr, - wlr_cursor_ptr, - wlr_xcursor_manager_ptr); - wlmtk_resizebar_area_set_cursor( - resizebar_ptr->center_area_ptr, - wlr_cursor_ptr, - wlr_xcursor_manager_ptr); - wlmtk_resizebar_area_set_cursor( - resizebar_ptr->right_area_ptr, - wlr_cursor_ptr, - wlr_xcursor_manager_ptr); -} - /* ------------------------------------------------------------------------- */ bool wlmtk_resizebar_set_width( wlmtk_resizebar_t *resizebar_ptr, diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 84ba8509..2f427825 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -69,20 +69,6 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( */ void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr); -/** - * Sets cursor pointers. - * - * TODO(kaeser@gubbe.ch): Abstract this away. - * - * @param resizebar_ptr - * @param wlr_cursor_ptr - * @param wlr_xcursor_manager_ptr - */ -void wlmtk_resizebar_set_cursor( - wlmtk_resizebar_t *resizebar_ptr, - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr); - /** * Sets the width of the resize bar. * diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index da7e467b..f90bfb33 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -56,12 +56,6 @@ struct _wlmtk_resizebar_area_t { /** Edges that the resizebar area controls. */ uint32_t edges; - /** Points to a `wlr_cursor`. */ - struct wlr_cursor *wlr_cursor_ptr; - /** Points to a `wlr_xcursor_manager`. */ - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr; - /** Name of the cursor to show when having pointer focus. */ - const char *xcursor_name_ptr; /** The cursor to use when having pointer focus. */ wlmtk_env_cursor_t cursor; }; @@ -109,19 +103,15 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( resizebar_area_ptr->edges = edges; resizebar_area_ptr->cursor = WLMTK_CURSOR_DEFAULT; - resizebar_area_ptr->xcursor_name_ptr = "default"; // Fail-safe value. switch (resizebar_area_ptr->edges) { case WLR_EDGE_BOTTOM: resizebar_area_ptr->cursor = WLMTK_CURSOR_RESIZE_S; - resizebar_area_ptr->xcursor_name_ptr = "s-resize"; break; case WLR_EDGE_BOTTOM | WLR_EDGE_LEFT: resizebar_area_ptr->cursor = WLMTK_CURSOR_RESIZE_SW; - resizebar_area_ptr->xcursor_name_ptr = "sw-resize"; break; case WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT: resizebar_area_ptr->cursor = WLMTK_CURSOR_RESIZE_SE; - resizebar_area_ptr->xcursor_name_ptr = "se-resize"; break; default: bs_log(BS_ERROR, "Unsupported edge %"PRIx32, edges); @@ -152,16 +142,6 @@ void wlmtk_resizebar_area_destroy( free(resizebar_area_ptr); } -/* ------------------------------------------------------------------------- */ -void wlmtk_resizebar_area_set_cursor( - wlmtk_resizebar_area_t *resizebar_area_ptr, - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr) -{ - resizebar_area_ptr->wlr_cursor_ptr = wlr_cursor_ptr; - resizebar_area_ptr->wlr_xcursor_manager_ptr = wlr_xcursor_manager_ptr; -} - /* ------------------------------------------------------------------------- */ bool wlmtk_resizebar_area_redraw( wlmtk_resizebar_area_t *resizebar_area_ptr, diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index c420bf72..c52e178f 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -55,20 +55,6 @@ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( void wlmtk_resizebar_area_destroy( wlmtk_resizebar_area_t *resizebar_area_ptr); -/** - * Sets cursor pointers. - * - * TODO(kaeser@gubbe.ch): Abstract this away. - * - * @param resizebar_area_ptr - * @param wlr_cursor_ptr - * @param wlr_xcursor_manager_ptr - */ -void wlmtk_resizebar_area_set_cursor( - wlmtk_resizebar_area_t *resizebar_area_ptr, - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr); - /** * Redraws the element, with updated position and width. * diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 11ceb392..22adbc8b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -285,8 +285,6 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) /* ------------------------------------------------------------------------- */ wlmtk_window_t *wlmtk_window_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr) { @@ -299,11 +297,6 @@ wlmtk_window_t *wlmtk_window_create( return NULL; } - wlmtk_resizebar_set_cursor( - window_ptr->resizebar_ptr, - wlr_cursor_ptr, - wlr_xcursor_manager_ptr); - return window_ptr; } @@ -830,7 +823,7 @@ void test_create_destroy(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, window_ptr, fake_content_ptr->content.window_ptr); @@ -844,7 +837,7 @@ void test_set_title(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); wlmtk_window_set_title(window_ptr, "Title"); BS_TEST_VERIFY_STREQ( @@ -867,7 +860,7 @@ void test_request_close(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); wlmtk_window_request_close(window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); @@ -881,7 +874,7 @@ void test_set_activated(bs_test_t *test_ptr) { wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); wlmtk_window_set_activated(window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 1022c826..48619015 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -33,11 +33,6 @@ typedef struct _wlmtk_window_t wlmtk_window_t; extern "C" { #endif // __cplusplus -/** Forward declaration. */ -struct wlr_cursor; -/** Forward declaration. */ -struct wlr_xcursor_manager; - /** Maximum number of pending state updates. */ #define WLMTK_WINDOW_MAX_PENDING 64 @@ -121,8 +116,6 @@ struct _wlmtk_window_t { /** * Creates a window for the given content. * - * @param wlr_cursor_ptr - * @param wlr_xcursor_manager_ptr * @param env_ptr * @param content_ptr Will take ownership of content_ptr. * @@ -130,8 +123,6 @@ struct _wlmtk_window_t { * by calling @ref wlmtk_window_destroy. */ wlmtk_window_t *wlmtk_window_create( - struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 729d5d8c..33ebf9f6 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -620,7 +620,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -721,7 +721,7 @@ void test_move(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -767,7 +767,7 @@ void test_unmap_during_move(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -812,7 +812,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); wlmtk_content_commit_size(&fake_content_ptr->content, 1, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, NULL, NULL, &fake_content_ptr->content); + NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 32b9ab63..64486690 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -117,10 +117,7 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( if (NULL == content_ptr) return NULL; wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( - server_ptr->cursor_ptr->wlr_cursor_ptr, - server_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - server_ptr->env_ptr, - &content_ptr->super_content); + server_ptr->env_ptr, &content_ptr->super_content); if (NULL == wlmtk_window_ptr) { content_element_destroy(&content_ptr->super_content.super_element); return NULL; From b8e5b2f2c68951fdd2cb8aed6ec27fc0f3b0b165 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 27 Nov 2023 21:33:42 +0100 Subject: [PATCH 267/390] Sets cursor on workspace. --- src/server.c | 27 +++++++++++++-------------- src/toolkit/workspace.c | 10 +++++++++- src/workspace.c | 2 +- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/server.c b/src/server.c index 6f7864ed..eb59b556 100644 --- a/src/server.c +++ b/src/server.c @@ -216,6 +216,14 @@ wlmaker_server_t *wlmaker_server_create(void) return NULL; } + server_ptr->env_ptr = wlmtk_env_create( + server_ptr->cursor_ptr->wlr_cursor_ptr, + server_ptr->cursor_ptr->wlr_xcursor_manager_ptr); + if (NULL == server_ptr->env_ptr) { + wlmaker_server_destroy(server_ptr); + return NULL; + } + // TODO(kaeser@gubbe.ch): Create the workspaces depending on configuration. int workspace_idx = 0; const wlmaker_config_workspace_t *workspace_config_ptr; @@ -311,15 +319,6 @@ wlmaker_server_t *wlmaker_server_create(void) return NULL; } - server_ptr->env_ptr = wlmtk_env_create( - server_ptr->cursor_ptr->wlr_cursor_ptr, - server_ptr->cursor_ptr->wlr_xcursor_manager_ptr); - if (NULL == server_ptr->env_ptr) { - wlmaker_server_destroy(server_ptr); - return NULL; - } - - return server_ptr; } @@ -334,11 +333,6 @@ void wlmaker_server_destroy(wlmaker_server_t *server_ptr) // * server_ptr->wlr_scene_ptr (there is no "destroy" function) // * server_ptr->void_wlr_scene_ptr - if (NULL != server_ptr->env_ptr) { - wlmtk_env_destroy(server_ptr->env_ptr); - server_ptr->env_ptr = NULL; - } - if (NULL != server_ptr->monitor_ptr) { wlmaker_subprocess_monitor_destroy(server_ptr->monitor_ptr); server_ptr->monitor_ptr =NULL; @@ -376,6 +370,11 @@ void wlmaker_server_destroy(wlmaker_server_t *server_ptr) wlmaker_workspace_destroy(wlmaker_workspace_from_dlnode(dlnode_ptr)); } + if (NULL != server_ptr->env_ptr) { + wlmtk_env_destroy(server_ptr->env_ptr); + server_ptr->env_ptr = NULL; + } + if (NULL != server_ptr->cursor_ptr) { wlmaker_cursor_destroy(server_ptr->cursor_ptr); server_ptr->cursor_ptr = NULL; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 33ebf9f6..64981dd2 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -387,9 +387,17 @@ bool element_pointer_motion( element_ptr, wlmtk_workspace_t, super_container.super_element); // Note: Workspace ignores the return value. All motion events are whitin. - workspace_ptr->orig_super_element_vmt.pointer_motion( + bool rv = workspace_ptr->orig_super_element_vmt.pointer_motion( element_ptr, x, y, time_msec); wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_MOTION, NULL); + + // Focus wasn't claimed, so we'll set the cursor here. + if (!rv) { + wlmtk_env_set_cursor( + workspace_ptr->super_container.super_element.env_ptr, + WLMTK_CURSOR_DEFAULT); + } + return true; } diff --git a/src/workspace.c b/src/workspace.c index c01a87a9..021602d1 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -173,7 +173,7 @@ wlmaker_workspace_t *wlmaker_workspace_create(wlmaker_server_t *server_ptr, #if defined(ENABLE_TOOLKIT_PROTOTYPE) // Transitional -- enable for prototyping: Toolkit-based workspace. workspace_ptr->wlmtk_workspace_ptr = wlmtk_workspace_create( - NULL, workspace_ptr->wlr_scene_tree_ptr); + workspace_ptr->server_ptr->env_ptr, workspace_ptr->wlr_scene_tree_ptr); if (NULL == workspace_ptr->wlmtk_workspace_ptr) { wlmaker_workspace_destroy(workspace_ptr); return NULL; From 137b92dffec352f441349f17351a20cbd5d5fc1b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 27 Nov 2023 21:39:22 +0100 Subject: [PATCH 268/390] Fixes cursor setting. --- src/toolkit/container.c | 10 ++++++++++ src/toolkit/element.c | 9 ++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index ceb6dcbe..36464c77 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -50,6 +50,8 @@ static bool element_pointer_motion( static bool element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); +static void element_pointer_enter( + wlmtk_element_t *element_ptr); static void handle_wlr_scene_tree_node_destroy( struct wl_listener *listener_ptr, @@ -68,6 +70,7 @@ static const wlmtk_element_vmt_t container_element_vmt = { .get_pointer_area = element_get_pointer_area, .pointer_motion = element_pointer_motion, .pointer_button = element_pointer_button, + .pointer_enter = element_pointer_enter, }; /** Default virtual method table. Initializes non-abstract methods. */ @@ -464,6 +467,13 @@ bool element_pointer_button( button_event_ptr); } +/* ------------------------------------------------------------------------- */ +/** Handler for when the pointer enters the area. Nothing for container. */ +void element_pointer_enter(__UNUSED__ wlmtk_element_t *element_ptr) +{ + // Nothing. Do not call parent. +} + /* ------------------------------------------------------------------------- */ /** * Handles the 'destroy' callback of wlr_scene_tree_ptr->node. diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 8a94929c..433d99bb 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -311,10 +311,13 @@ bool _wlmtk_element_pointer_button( } /* ------------------------------------------------------------------------- */ -/** Handler for when the pointer enters the area. Nothing for default impl. */ -void _wlmtk_element_pointer_enter(__UNUSED__ wlmtk_element_t *element_ptr) +/** Handler for when the pointer enters the area. Sets default cursor. */ +void _wlmtk_element_pointer_enter(wlmtk_element_t *element_ptr) { - // Nothing. + // TODO(kaeser@gubbe.ch): Consider forking this out into a 'leaf element' + // class. 'enter' and 'leave' don't make that much sense for eg. a + // container. + wlmtk_env_set_cursor(element_ptr->env_ptr, WLMTK_CURSOR_DEFAULT); } /* ------------------------------------------------------------------------- */ From a3ef1852567b462384ef0a6caeb4cf35203789ee Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 28 Nov 2023 21:25:09 +0100 Subject: [PATCH 269/390] Adds wlmtk_workspace_raise_window and raise when activating. --- src/toolkit/content.c | 3 +++ src/toolkit/window.c | 1 + src/toolkit/workspace.c | 23 +++++++++++++++++++++-- src/toolkit/workspace.h | 5 +++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 2c82dd23..44e79c83 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -343,6 +343,9 @@ bool element_pointer_button( struct wlr_surface *focused_wlr_surface_ptr = content_ptr->wlr_seat_ptr->pointer_state.focused_surface; if (NULL == focused_wlr_surface_ptr) return false; + // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated window + // over to a non-activated window will trigger the condition here on the + // WLMTK_BUTTON_UP event. Needs a test and fixing. BS_ASSERT(content_ptr->wlr_surface_ptr == wlr_surface_get_root_surface(focused_wlr_surface_ptr)); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 22adbc8b..120cca0f 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -515,6 +515,7 @@ bool _wlmtk_window_element_pointer_button( wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( window_ptr->super_box.super_container.super_element.parent_container_ptr); wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_raise_window(workspace_ptr, window_ptr); return window_ptr->orig_super_element_vmt.pointer_button( element_ptr, button_event_ptr); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 64981dd2..717321d7 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -317,10 +317,29 @@ void wlmtk_workspace_activate_window( wlmtk_window_set_activated(window_ptr, true); workspace_ptr->activated_window_ptr = window_ptr; } - // set activated. - // keep track of activated. => so it can be deactivated. +} +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_raise_window( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) +{ + wlmtk_element_t *element_ptr = wlmtk_window_element(window_ptr); + bs_dllist_node_t *dlnode_ptr = wlmtk_dlnode_from_element(element_ptr); + BS_ASSERT(bs_dllist_contains( + &workspace_ptr->super_container.elements, dlnode_ptr)); + + // Guard clause: Nothing to do if already at the front. + if (dlnode_ptr == workspace_ptr->super_container.elements.head_ptr) return; + + // This is terrible. Should be at container. + bs_dllist_remove(&workspace_ptr->super_container.elements, dlnode_ptr); + bs_dllist_push_front(&workspace_ptr->super_container.elements, dlnode_ptr); + if (NULL != element_ptr->wlr_scene_node_ptr) { + wlr_scene_node_raise_to_top(element_ptr->wlr_scene_node_ptr); + } + wlmtk_container_update_pointer_focus(&workspace_ptr->super_container); } /* == Local (static) methods =============================================== */ diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 461e93ca..8ad28557 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -161,6 +161,11 @@ void wlmtk_workspace_activate_window( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); +/** Raises `window_ptr`: Will show it atop all other windows. */ +void wlmtk_workspace_raise_window( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; From 976725a8c988f376d12d44bdfd78267b7481e60d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 28 Nov 2023 21:31:39 +0100 Subject: [PATCH 270/390] Adds some things to fix. --- src/toolkit/container.c | 4 ++++ src/toolkit/workspace.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 36464c77..cdc88461 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -194,6 +194,8 @@ void wlmtk_container_add_element_before( wlmtk_dlnode_from_element(element_ptr)); } + // FIXME: This may add it to the scene graph, but may add it at the wrong + // position. Needs to be rectified. wlmtk_element_set_parent_container(element_ptr, container_ptr); wlmtk_container_update_layout(container_ptr); } @@ -271,6 +273,8 @@ struct wlr_scene_node *element_create_scene_node( dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); + // FIXME: Each new node will be inserted at the top, but we're + // iterating head-to-tail. Should be tested and reversed. wlmtk_element_attach_to_scene_graph(element_ptr); } diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 717321d7..8046e17a 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -332,7 +332,7 @@ void wlmtk_workspace_raise_window( // Guard clause: Nothing to do if already at the front. if (dlnode_ptr == workspace_ptr->super_container.elements.head_ptr) return; - // This is terrible. Should be at container. + // FIXME: This is terrible. Should be at container. bs_dllist_remove(&workspace_ptr->super_container.elements, dlnode_ptr); bs_dllist_push_front(&workspace_ptr->super_container.elements, dlnode_ptr); if (NULL != element_ptr->wlr_scene_node_ptr) { From 198015f9916f14fa8359b0e3e653e47c08854f26 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 30 Nov 2023 21:38:38 +0100 Subject: [PATCH 271/390] Adds test for scene node order in container, on regular add/remove. --- src/toolkit/container.c | 67 ++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index cdc88461..ad9f4439 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -268,13 +268,13 @@ struct wlr_scene_node *element_create_scene_node( wlr_scene_tree_ptr); BS_ASSERT(NULL != container_ptr->wlr_scene_tree_ptr); - for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + // Build the nodes from tail to head: Adding an element to the scene graph + // will always put it on top, so this adds the elements in desired order. + for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.tail_ptr; dlnode_ptr != NULL; - dlnode_ptr = dlnode_ptr->next_ptr) { + dlnode_ptr = dlnode_ptr->prev_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); BS_ASSERT(NULL == element_ptr->wlr_scene_node_ptr); - // FIXME: Each new node will be inserted at the top, but we're - // iterating head-to-tail. Should be tested and reversed. wlmtk_element_attach_to_scene_graph(element_ptr); } @@ -741,27 +741,72 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_parent_ptr); wlmtk_container_t container; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_container_init(&container, NULL)); + + wlmtk_fake_element_t *fe3_ptr = wlmtk_fake_element_create(); + wlmtk_container_add_element(&container, &fe3_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe3_ptr->element.wlr_scene_node_ptr); + wlmtk_fake_element_t *fe2_ptr = wlmtk_fake_element_create(); + wlmtk_container_add_element(&container, &fe2_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe2_ptr->element.wlr_scene_node_ptr); + wlmtk_element_set_parent_container( &container.super_element, fake_parent_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe3_ptr->element.wlr_scene_node_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe2_ptr->element.wlr_scene_node_ptr); + + BS_TEST_VERIFY_EQ( + test_ptr, + container.elements.head_ptr, &fe2_ptr->element.dlnode); + BS_TEST_VERIFY_EQ( + test_ptr, + container.elements.tail_ptr, &fe3_ptr->element.dlnode); + + // The top is at parent->children.prev (see wlr_scene_node_raise_to_top). + // Seems counter-intuitive, since wayhland-util.h denotes `prev` to refer + // to the last element in the list. + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev, + &fe2_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev->prev, + &fe3_ptr->element.wlr_scene_node_ptr->link); + // Want to have the node. BS_TEST_VERIFY_NEQ( test_ptr, NULL, container.super_element.wlr_scene_node_ptr); // Fresh element: No scene graph node yet. - wlmtk_fake_element_t *fe_ptr = wlmtk_fake_element_create(); - BS_TEST_VERIFY_EQ(test_ptr, NULL, fe_ptr->element.wlr_scene_node_ptr); + wlmtk_fake_element_t *fe1_ptr = wlmtk_fake_element_create(); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); // Add to container with attached graph: Element now has a graph node. - wlmtk_container_add_element(&container, &fe_ptr->element); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe_ptr->element.wlr_scene_node_ptr); + wlmtk_container_add_element(&container, &fe1_ptr->element); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); + + // Now fe1 has to be on top. + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev, + &fe1_ptr->element.wlr_scene_node_ptr->link); // Remove: The element's graph node must be destroyed & cleared.. - wlmtk_container_remove_element(&container, &fe_ptr->element); - BS_TEST_VERIFY_EQ(test_ptr, NULL, fe_ptr->element.wlr_scene_node_ptr); - wlmtk_element_destroy(&fe_ptr->element); + wlmtk_container_remove_element(&container, &fe1_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); + wlmtk_element_destroy(&fe1_ptr->element); wlmtk_element_set_parent_container(&container.super_element, NULL); + + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe3_ptr->element.wlr_scene_node_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe2_ptr->element.wlr_scene_node_ptr); + + wlmtk_container_remove_element(&container, &fe3_ptr->element); + wlmtk_element_destroy(&fe3_ptr->element); + wlmtk_container_remove_element(&container, &fe2_ptr->element); + wlmtk_element_destroy(&fe2_ptr->element); + wlmtk_container_fini(&container); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } From c533dd7cd5c93c9873adb760afa8b51fb012fcd9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 30 Nov 2023 21:47:20 +0100 Subject: [PATCH 272/390] Fixes the position in the scene graph in wlmtk_container_add_element_before. --- src/toolkit/container.c | 54 +++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index ad9f4439..2afd5b6b 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -194,9 +194,12 @@ void wlmtk_container_add_element_before( wlmtk_dlnode_from_element(element_ptr)); } - // FIXME: This may add it to the scene graph, but may add it at the wrong - // position. Needs to be rectified. wlmtk_element_set_parent_container(element_ptr, container_ptr); + if (NULL != element_ptr->wlr_scene_node_ptr) { + BS_ASSERT(NULL != reference_element_ptr->wlr_scene_node_ptr); + wlr_scene_node_place_above(element_ptr->wlr_scene_node_ptr, + reference_element_ptr->wlr_scene_node_ptr); + } wlmtk_container_update_layout(container_ptr); } @@ -779,23 +782,54 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) test_ptr, NULL, container.super_element.wlr_scene_node_ptr); // Fresh element: No scene graph node yet. - wlmtk_fake_element_t *fe1_ptr = wlmtk_fake_element_create(); - BS_TEST_VERIFY_EQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); + wlmtk_fake_element_t *fe0_ptr = wlmtk_fake_element_create(); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe0_ptr->element.wlr_scene_node_ptr); // Add to container with attached graph: Element now has a graph node. - wlmtk_container_add_element(&container, &fe1_ptr->element); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); + wlmtk_container_add_element(&container, &fe0_ptr->element); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fe0_ptr->element.wlr_scene_node_ptr); + + // Now fe0 has to be on top, followed by fe2 and fe3. + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev, + &fe0_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev->prev, + &fe2_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev->prev->prev, + &fe3_ptr->element.wlr_scene_node_ptr->link); + + // One more element, but we add this in front of fe2. + wlmtk_fake_element_t *fe1_ptr = wlmtk_fake_element_create(); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); + wlmtk_container_add_element_before( + &container, &fe2_ptr->element, &fe1_ptr->element); - // Now fe1 has to be on top. BS_TEST_VERIFY_EQ( test_ptr, container.wlr_scene_tree_ptr->children.prev, + &fe0_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev->prev, &fe1_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev->prev->prev, + &fe2_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + container.wlr_scene_tree_ptr->children.prev->prev->prev->prev, + &fe3_ptr->element.wlr_scene_node_ptr->link); // Remove: The element's graph node must be destroyed & cleared.. - wlmtk_container_remove_element(&container, &fe1_ptr->element); - BS_TEST_VERIFY_EQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); - wlmtk_element_destroy(&fe1_ptr->element); + wlmtk_container_remove_element(&container, &fe0_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fe0_ptr->element.wlr_scene_node_ptr); + wlmtk_element_destroy(&fe0_ptr->element); wlmtk_element_set_parent_container(&container.super_element, NULL); From 2effeb71aba8379dc8fe98a07e9e4240ffb5360c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 30 Nov 2023 21:54:07 +0100 Subject: [PATCH 273/390] Fixes some comments referencing front/back but should be top/bottom. --- src/toolkit/box.h | 2 ++ src/toolkit/container.c | 22 +++++++++++----------- src/toolkit/container.h | 12 ++++++++---- src/toolkit/resizebar.c | 4 ++-- src/toolkit/titlebar.c | 2 +- src/toolkit/window.c | 2 +- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 81b39b14..30eb74c0 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -31,7 +31,9 @@ extern "C" { /** Orientation of the box. */ typedef enum { + /** Horizontal box layout. The container's "top" is on the left. */ WLMTK_BOX_HORIZONTAL, + /** Vertical box layout. The container's "top" is the top. */ WLMTK_BOX_VERTICAL, } wlmtk_box_orientation_t; diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 2afd5b6b..df1ebd85 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -172,7 +172,7 @@ void wlmtk_container_add_element( } /* ------------------------------------------------------------------------- */ -void wlmtk_container_add_element_before( +void wlmtk_container_add_element_atop( wlmtk_container_t *container_ptr, wlmtk_element_t *reference_element_ptr, wlmtk_element_t *element_ptr) @@ -710,19 +710,19 @@ void test_add_remove(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, &container, elem3_ptr->element.parent_container_ptr); - // Remove 2, then add at the end: 3 -> 1 -> 2. + // Remove 2, then add at the bottom: 3 -> 1 -> 2. wlmtk_container_remove_element(&container, &elem2_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, NULL, elem2_ptr->element.parent_container_ptr); - wlmtk_container_add_element_before(&container, NULL, &elem2_ptr->element); + wlmtk_container_add_element_atop(&container, NULL, &elem2_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, &container, elem2_ptr->element.parent_container_ptr); BS_TEST_VERIFY_EQ( test_ptr, wlmtk_dlnode_from_element(&elem1_ptr->element)->next_ptr, wlmtk_dlnode_from_element(&elem2_ptr->element)); - // Remove elem3 and add before elem2: 1 -> 3 -> 2. + // Remove elem3 and add atop elem2: 1 -> 3 -> 2. wlmtk_container_remove_element(&container, &elem3_ptr->element); - wlmtk_container_add_element_before( + wlmtk_container_add_element_atop( &container, &elem2_ptr->element, &elem3_ptr->element); BS_TEST_VERIFY_EQ( test_ptr, @@ -803,10 +803,10 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) container.wlr_scene_tree_ptr->children.prev->prev->prev, &fe3_ptr->element.wlr_scene_node_ptr->link); - // One more element, but we add this in front of fe2. + // One more element, but we add this atop of fe2. wlmtk_fake_element_t *fe1_ptr = wlmtk_fake_element_create(); BS_TEST_VERIFY_EQ(test_ptr, NULL, fe1_ptr->element.wlr_scene_node_ptr); - wlmtk_container_add_element_before( + wlmtk_container_add_element_atop( &container, &fe2_ptr->element, &fe1_ptr->element); BS_TEST_VERIFY_EQ( @@ -1017,14 +1017,14 @@ void test_pointer_focus(bs_test_t *test_ptr) &elem1_ptr->element, container.pointer_focus_element_ptr); - // Case 4: Add another visible element. Focus changes, since in front. + // Case 4: Add another visible element. Focus changes, since on top. wlmtk_container_add_element(&container, &elem2_ptr->element); BS_TEST_VERIFY_EQ( test_ptr, &elem2_ptr->element, container.pointer_focus_element_ptr); - // Case 5: Elem2 (added last = in front) becomes invisible. Focus changes. + // Case 5: Elem2 (added last = on top) becomes invisible. Focus changes. wlmtk_element_set_visible(&elem2_ptr->element, false); BS_TEST_VERIFY_EQ( test_ptr, @@ -1163,7 +1163,7 @@ void test_pointer_focus_layered(bs_test_t *test_ptr) container1.pointer_focus_element_ptr); BS_TEST_VERIFY_TRUE(test_ptr, elem2_ptr->pointer_leave_called); - // Case 3: Bring container2 in front. Now elem2 has focus. + // Case 3: Bring container2 to top. Now elem2 has focus. elem1_ptr->pointer_leave_called = false; wlmtk_container_remove_element(&container1, &container2.super_element); wlmtk_container_add_element(&container1, &container2.super_element); @@ -1211,7 +1211,7 @@ void test_pointer_button(bs_test_t *test_ptr) wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem2_ptr->element, 10, 10); wlmtk_element_set_visible(&elem2_ptr->element, true); - wlmtk_container_add_element_before(&container, NULL, &elem2_ptr->element); + wlmtk_container_add_element_atop(&container, NULL, &elem2_ptr->element); wlmtk_button_event_t button = { .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 6ddd737a..3e4959e4 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -61,7 +61,11 @@ struct _wlmtk_container_t { /** Virtual method table for the container. */ wlmtk_container_vmt_t vmt; - /** Elements contained here. */ + /** + * Elements contained here. + * + * `head_ptr` is the topmost element, and `tail_ptr` the bottom-most one. + */ bs_dllist_t elements; /** Scene tree. */ @@ -127,7 +131,7 @@ void wlmtk_container_fini( * Adds `element_ptr` to the container. * * Requires that `element_ptr` is not added to a container yet. The element - * will be added at the front of the container. * + * will be added at the top of the container. * * @param container_ptr * @param element_ptr @@ -137,7 +141,7 @@ void wlmtk_container_add_element( wlmtk_element_t *element_ptr); /** - * Adds `element_ptr` to the container at (before) the reference's position. + * Adds `element_ptr` to the container atop the reference's position. * * If reference_element_ptr is NULL, the element will be added at the back. * @@ -145,7 +149,7 @@ void wlmtk_container_add_element( * @param reference_element_ptr Must be an element of this container. * @param element_ptr */ -void wlmtk_container_add_element_before( +void wlmtk_container_add_element_atop( wlmtk_container_t *container_ptr, wlmtk_element_t *reference_element_ptr, wlmtk_element_t *element_ptr); diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 0b181b98..93f0c9ea 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -104,7 +104,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_container_add_element_before( + wlmtk_container_add_element_atop( &resizebar_ptr->super_box.super_container, NULL, wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); @@ -115,7 +115,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_container_add_element_before( + wlmtk_container_add_element_atop( &resizebar_ptr->super_box.super_container, NULL, wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr)); diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 3804bd03..a87448ea 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -136,7 +136,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_container_add_element_before( + wlmtk_container_add_element_atop( &titlebar_ptr->super_box.super_container, NULL, wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr)); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 120cca0f..bd63d52b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -216,7 +216,7 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - wlmtk_container_add_element_before( + wlmtk_container_add_element_atop( &window_ptr->super_box.super_container, wlmtk_resizebar_element(window_ptr->resizebar_ptr), wlmtk_content_element(content_ptr)); From 3af904a37cfa48bb51bdd908f8589ab106184a5f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 1 Dec 2023 20:31:34 +0100 Subject: [PATCH 274/390] Adds wlmtk_container_raise_element_top and tests. --- src/toolkit/container.c | 107 ++++++++++++++++++++++++++++++++++++++-- src/toolkit/container.h | 12 +++++ 2 files changed, 116 insertions(+), 3 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index df1ebd85..c7eba182 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -196,9 +196,15 @@ void wlmtk_container_add_element_atop( wlmtk_element_set_parent_container(element_ptr, container_ptr); if (NULL != element_ptr->wlr_scene_node_ptr) { - BS_ASSERT(NULL != reference_element_ptr->wlr_scene_node_ptr); - wlr_scene_node_place_above(element_ptr->wlr_scene_node_ptr, - reference_element_ptr->wlr_scene_node_ptr); + + if (NULL == reference_element_ptr) { + wlr_scene_node_lower_to_bottom(element_ptr->wlr_scene_node_ptr); + } else { + BS_ASSERT(NULL != reference_element_ptr->wlr_scene_node_ptr); + wlr_scene_node_place_above( + element_ptr->wlr_scene_node_ptr, + reference_element_ptr->wlr_scene_node_ptr); + } } wlmtk_container_update_layout(container_ptr); } @@ -223,6 +229,27 @@ void wlmtk_container_remove_element( BS_ASSERT(element_ptr != container_ptr->pointer_focus_element_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_container_raise_element_to_top( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr) +{ + BS_ASSERT(element_ptr->parent_container_ptr == container_ptr); + + bs_dllist_remove( + &container_ptr->elements, + wlmtk_dlnode_from_element(element_ptr)); + bs_dllist_push_front( + &container_ptr->elements, + wlmtk_dlnode_from_element(element_ptr)); + + if (NULL != element_ptr->wlr_scene_node_ptr) { + wlr_scene_node_raise_to_top(element_ptr->wlr_scene_node_ptr); + } + + wlmtk_container_update_layout(container_ptr); +} + /* ------------------------------------------------------------------------- */ void wlmtk_container_update_pointer_focus(wlmtk_container_t *container_ptr) { @@ -650,6 +677,7 @@ void wlmtk_container_destroy_fake_parent(wlmtk_container_t *container_ptr) static void test_init_fini(bs_test_t *test_ptr); static void test_add_remove(bs_test_t *test_ptr); static void test_add_remove_with_scene_graph(bs_test_t *test_ptr); +static void test_add_with_raise(bs_test_t *test_ptr); static void test_pointer_motion(bs_test_t *test_ptr); static void test_pointer_focus(bs_test_t *test_ptr); static void test_pointer_focus_move(bs_test_t *test_ptr); @@ -660,6 +688,7 @@ const bs_test_case_t wlmtk_container_test_cases[] = { { 1, "init_fini", test_init_fini }, { 1, "add_remove", test_add_remove }, { 1, "add_remove_with_scene_graph", test_add_remove_with_scene_graph }, + { 1, "add_with_raise", test_add_with_raise }, { 1, "pointer_motion", test_pointer_motion }, { 1, "pointer_focus", test_pointer_focus }, { 1, "pointer_focus_move", test_pointer_focus_move }, @@ -845,6 +874,78 @@ void test_add_remove_with_scene_graph(bs_test_t *test_ptr) wlmtk_container_destroy_fake_parent(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests that elements inserted at position are also placed in scene graph. */ +void test_add_with_raise(bs_test_t *test_ptr) +{ + wlmtk_container_t *c_ptr = wlmtk_container_create_fake_parent(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, c_ptr); + + // fe1 added. Sole element, is the top. + wlmtk_fake_element_t *fe1_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&fe1_ptr->element, true); + wlmtk_container_add_element(c_ptr, &fe1_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + c_ptr->wlr_scene_tree_ptr->children.prev, + &fe1_ptr->element.wlr_scene_node_ptr->link); + + wlmtk_element_pointer_motion(&c_ptr->super_element, 0, 0, 7); + BS_TEST_VERIFY_TRUE(test_ptr, fe1_ptr->pointer_motion_called); + fe1_ptr->pointer_motion_called = false; + BS_TEST_VERIFY_EQ( + test_ptr, &fe1_ptr->element, c_ptr->pointer_focus_element_ptr); + + // fe2 placed atop 'NULL', goes to back. + wlmtk_fake_element_t *fe2_ptr = wlmtk_fake_element_create(); + wlmtk_element_set_visible(&fe2_ptr->element, true); + wlmtk_container_add_element_atop(c_ptr, NULL, &fe2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + c_ptr->wlr_scene_tree_ptr->children.prev->prev, + &fe2_ptr->element.wlr_scene_node_ptr->link); + + // Raise fe2. + wlmtk_container_raise_element_to_top(c_ptr, &fe2_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + c_ptr->wlr_scene_tree_ptr->children.prev, + &fe2_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + c_ptr->wlr_scene_tree_ptr->children.prev->prev, + &fe1_ptr->element.wlr_scene_node_ptr->link); + + // Must also update pointer focus. + BS_TEST_VERIFY_EQ( + test_ptr, &fe2_ptr->element, c_ptr->pointer_focus_element_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fe2_ptr->pointer_motion_called); + fe2_ptr->pointer_motion_called = false; + + // Now remove fe1 and add on top of fe2. Ensure scene graph has fe1 on top + // and pointer focus is on it, too. + wlmtk_container_remove_element(c_ptr, &fe1_ptr->element); + wlmtk_container_add_element_atop(c_ptr, &fe2_ptr->element, &fe1_ptr->element); + BS_TEST_VERIFY_EQ( + test_ptr, + c_ptr->wlr_scene_tree_ptr->children.prev, + &fe1_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, + c_ptr->wlr_scene_tree_ptr->children.prev->prev, + &fe2_ptr->element.wlr_scene_node_ptr->link); + BS_TEST_VERIFY_EQ( + test_ptr, &fe1_ptr->element, c_ptr->pointer_focus_element_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fe1_ptr->pointer_motion_called); + + wlmtk_container_remove_element(c_ptr, &fe2_ptr->element); + wlmtk_element_destroy(&fe2_ptr->element); + wlmtk_container_remove_element(c_ptr, &fe1_ptr->element); + wlmtk_element_destroy(&fe1_ptr->element); + + wlmtk_container_destroy_fake_parent(c_ptr); +} + /* ------------------------------------------------------------------------- */ /** Tests the 'motion' method for container. */ void test_pointer_motion(bs_test_t *test_ptr) diff --git a/src/toolkit/container.h b/src/toolkit/container.h index 3e4959e4..b5b4cb5e 100644 --- a/src/toolkit/container.h +++ b/src/toolkit/container.h @@ -166,6 +166,18 @@ void wlmtk_container_remove_element( wlmtk_container_t *container_ptr, wlmtk_element_t *element_ptr); +/** + * Places `element_ptr` at the top (head) of the container. + * + * Expects that `container_ptr` is `element_ptr`'s parent container. + * + * @param container_ptr + * @param element_ptr + */ +void wlmtk_container_raise_element_to_top( + wlmtk_container_t *container_ptr, + wlmtk_element_t *element_ptr); + /** * Updates pointer focus of the container. * From 943a1b9c812f84d2d1888360483590c843504f9c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 1 Dec 2023 20:34:46 +0100 Subject: [PATCH 275/390] Makes use of wlmtk_container_raise_to_top in wlmtk_workspace_raise_window. --- src/toolkit/container.c | 4 ++++ src/toolkit/workspace.c | 18 ++---------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index c7eba182..2ff40b14 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -236,6 +236,10 @@ void wlmtk_container_raise_element_to_top( { BS_ASSERT(element_ptr->parent_container_ptr == container_ptr); + // Already at the top? Nothing to do. + if (wlmtk_dlnode_from_element(element_ptr) == + container_ptr->elements.head_ptr) return; + bs_dllist_remove( &container_ptr->elements, wlmtk_dlnode_from_element(element_ptr)); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 8046e17a..bd9cc901 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -324,22 +324,8 @@ void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { - wlmtk_element_t *element_ptr = wlmtk_window_element(window_ptr); - bs_dllist_node_t *dlnode_ptr = wlmtk_dlnode_from_element(element_ptr); - BS_ASSERT(bs_dllist_contains( - &workspace_ptr->super_container.elements, dlnode_ptr)); - - // Guard clause: Nothing to do if already at the front. - if (dlnode_ptr == workspace_ptr->super_container.elements.head_ptr) return; - - // FIXME: This is terrible. Should be at container. - bs_dllist_remove(&workspace_ptr->super_container.elements, dlnode_ptr); - bs_dllist_push_front(&workspace_ptr->super_container.elements, dlnode_ptr); - if (NULL != element_ptr->wlr_scene_node_ptr) { - wlr_scene_node_raise_to_top(element_ptr->wlr_scene_node_ptr); - } - - wlmtk_container_update_pointer_focus(&workspace_ptr->super_container); + wlmtk_container_raise_element_to_top(&workspace_ptr->super_container, + wlmtk_window_element(window_ptr)); } /* == Local (static) methods =============================================== */ From 0d1d3c169fcb3fced5b35d2a7b723453f337237b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 1 Dec 2023 20:37:23 +0100 Subject: [PATCH 276/390] Fixes wlmtk_box_fini: Should call the parent (container) fini. --- src/toolkit/box.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index d13661d7..ba26cfc2 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -53,9 +53,10 @@ bool wlmtk_box_init( } /* ------------------------------------------------------------------------- */ -void wlmtk_box_fini(__UNUSED__ wlmtk_box_t *box_ptr) +void wlmtk_box_fini(wlmtk_box_t *box_ptr) { - // nothing to do. + wlmtk_container_fini(&box_ptr->super_container); + memset(box_ptr, 0, sizeof(wlmtk_box_t)); } /* == Local (static) methods =============================================== */ From 5e58d5408525f8a05e1813716a843eb59af63a80 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 1 Dec 2023 21:28:55 +0100 Subject: [PATCH 277/390] Adds wlmtk_rectangle_t, as basis element for margins and borders. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/rectangle.c | 285 +++++++++++++++++++++++++++++++++++++ src/toolkit/rectangle.h | 79 ++++++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 5 files changed, 368 insertions(+) create mode 100644 src/toolkit/rectangle.c create mode 100644 src/toolkit/rectangle.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 928cf4f7..759c55f3 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -30,6 +30,7 @@ SET(PUBLIC_HEADER_FILES env.h fsm.h input.h + rectangle.h resizebar.h resizebar_area.h titlebar.h @@ -50,6 +51,7 @@ TARGET_SOURCES(toolkit PRIVATE fsm.c gfxbuf.c primitives.c + rectangle.c resizebar.c resizebar_area.c titlebar.c diff --git a/src/toolkit/rectangle.c b/src/toolkit/rectangle.c new file mode 100644 index 00000000..5f9038a3 --- /dev/null +++ b/src/toolkit/rectangle.c @@ -0,0 +1,285 @@ +/* ========================================================================= */ +/** + * @file rectangle.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rectangle.h" + +#include "container.h" +#include "util.h" + +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +/** State of a unicolor rectangle. */ +struct _wlmtk_rectangle_t { + /** Superclass element. */ + wlmtk_element_t super_element; + /** Original virtual method table of the superclass element. */ + wlmtk_element_vmt_t orig_super_element_vmt; + + /** Width of the rectangle. */ + int width; + /** Height of the rectangle. */ + int height; + /** Color of the rectangle, as an ARGB8888 value. */ + uint32_t color; + + /** WLR rectangle. */ + struct wlr_scene_rect *wlr_scene_rect_ptr; + /** Listener for the `destroy` signal of `wlr_rect_buffer_ptr->node`. */ + struct wl_listener wlr_scene_rect_node_destroy_listener; +}; + +static void _wlmtk_rectangle_element_destroy(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *_wlmtk_rectangle_element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +static void _wlmtk_rectangle_get_dimensions( + wlmtk_element_t *element_ptr, + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr); +static void handle_wlr_scene_rect_node_destroy( + struct wl_listener *listener_ptr, + void *data_ptr); + +/* == Data ================================================================= */ + +/** Virtual method table of the rectangle, extending the element. */ +static const wlmtk_element_vmt_t _wlmtk_rectangle_element_vmt = { + .destroy = _wlmtk_rectangle_element_destroy, + .create_scene_node = _wlmtk_rectangle_element_create_scene_node, + .get_dimensions = _wlmtk_rectangle_get_dimensions, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_rectangle_t *wlmtk_rectangle_create( + wlmtk_env_t *env_ptr, + int width, + int height, + uint32_t color) +{ + wlmtk_rectangle_t *rectangle_ptr = logged_calloc( + 1, sizeof(wlmtk_rectangle_t)); + if (NULL == rectangle_ptr) return NULL; + rectangle_ptr->width = width; + rectangle_ptr->height = height; + rectangle_ptr->color = color; + + if (!wlmtk_element_init(&rectangle_ptr->super_element, env_ptr)) { + wlmtk_rectangle_destroy(rectangle_ptr); + return NULL; + } + rectangle_ptr->orig_super_element_vmt = wlmtk_element_extend( + &rectangle_ptr->super_element, + &_wlmtk_rectangle_element_vmt); + + return rectangle_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_rectangle_destroy(wlmtk_rectangle_t *rectangle_ptr) +{ + if (NULL != rectangle_ptr->wlr_scene_rect_ptr) { + wlr_scene_node_destroy(&rectangle_ptr->wlr_scene_rect_ptr->node); + rectangle_ptr->wlr_scene_rect_ptr = NULL; + } + + wlmtk_element_fini(&rectangle_ptr->super_element); + free(rectangle_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_rectangle_set_size( + wlmtk_rectangle_t *rectangle_ptr, + int width, + int height) +{ + rectangle_ptr->width = width; + rectangle_ptr->height = height; + + if (NULL != rectangle_ptr->wlr_scene_rect_ptr) { + wlr_scene_rect_set_size( + rectangle_ptr->wlr_scene_rect_ptr, + rectangle_ptr->width, + rectangle_ptr->height); + } +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_rectangle_element(wlmtk_rectangle_t *rectangle_ptr) +{ + return &rectangle_ptr->super_element; +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** Virtual dtor: Invoke the rectangle's dtor. */ +void _wlmtk_rectangle_element_destroy(wlmtk_element_t *element_ptr) +{ + wlmtk_rectangle_t *rectangle_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_rectangle_t, super_element); + wlmtk_rectangle_destroy(rectangle_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the superclass wlmtk_element_t::create_scene_node method. + * + * Creates a `struct wlr_scene_rect` attached to `wlr_scene_tree_ptr`. + * + * @param element_ptr + * @param wlr_scene_tree_ptr + */ +struct wlr_scene_node *_wlmtk_rectangle_element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_rectangle_t *rectangle_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_rectangle_t, super_element); + + BS_ASSERT(NULL == rectangle_ptr->wlr_scene_rect_ptr); + float color[4]; + bs_gfxbuf_argb8888_to_floats( + rectangle_ptr->color, &color[0], &color[1], &color[2], &color[3]); + rectangle_ptr->wlr_scene_rect_ptr = wlr_scene_rect_create( + wlr_scene_tree_ptr, + rectangle_ptr->width, + rectangle_ptr->height, + color); + if (NULL == rectangle_ptr->wlr_scene_rect_ptr) return NULL; + + wlmtk_util_connect_listener_signal( + &rectangle_ptr->wlr_scene_rect_ptr->node.events.destroy, + &rectangle_ptr->wlr_scene_rect_node_destroy_listener, + handle_wlr_scene_rect_node_destroy); + return &rectangle_ptr->wlr_scene_rect_ptr->node; +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's get_dimensions method: Return dimensions. + * + * @param element_ptr + * @param x1_ptr 0. + * @param y1_ptr 0. + * @param x2_ptr Width. May be NULL. + * @param y2_ptr Height. May be NULL. + */ +void _wlmtk_rectangle_get_dimensions( + wlmtk_element_t *element_ptr, + int *x1_ptr, + int *y1_ptr, + int *x2_ptr, + int *y2_ptr) +{ + wlmtk_rectangle_t *rectangle_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_rectangle_t, super_element); + if (NULL != x1_ptr) *x1_ptr = 0; + if (NULL != y1_ptr) *y1_ptr = 0; + if (NULL != x2_ptr) *x2_ptr = rectangle_ptr->width; + if (NULL != y2_ptr) *y2_ptr = rectangle_ptr->height; +} + +/* ------------------------------------------------------------------------- */ +/** + * Handles the 'destroy' callback of wlr_scene_rect_ptr->node. + * + * Will reset the wlr_scene_rect_ptr value. Destruction of the node had + * been triggered (hence the callback). + * + * @param listener_ptr + * @param data_ptr + */ +void handle_wlr_scene_rect_node_destroy( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_rectangle_t *rectangle_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_rectangle_t, wlr_scene_rect_node_destroy_listener); + + rectangle_ptr->wlr_scene_rect_ptr = NULL; + wl_list_remove(&rectangle_ptr->wlr_scene_rect_node_destroy_listener.link); +} + +/* == Unit Tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); +static void test_create_destroy_scene(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_rectangle_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 1, "create_destroy_scene", test_create_destroy_scene }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown of rectangle. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + wlmtk_rectangle_t *rectangle_ptr = wlmtk_rectangle_create( + NULL, 10, 20, 0x01020304); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, rectangle_ptr); + + int x1, y1, x2, y2; + wlmtk_element_get_dimensions( + &rectangle_ptr->super_element, &x1, &y1, &x2, &y2); + BS_TEST_VERIFY_EQ(test_ptr, 0, x1); + BS_TEST_VERIFY_EQ(test_ptr, 0, y1); + BS_TEST_VERIFY_EQ(test_ptr, 10, x2); + BS_TEST_VERIFY_EQ(test_ptr, 20, y2); + + wlmtk_rectangle_destroy(rectangle_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown of rectangle, when attached to scene graph. */ +void test_create_destroy_scene(bs_test_t *test_ptr) +{ + wlmtk_container_t *c_ptr = wlmtk_container_create_fake_parent(); + wlmtk_rectangle_t *rectangle_ptr = wlmtk_rectangle_create( + NULL, 10, 20, 0x01020304); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, rectangle_ptr); + wlmtk_element_t *element_ptr = wlmtk_rectangle_element(rectangle_ptr); + + wlmtk_container_add_element(c_ptr, element_ptr); + + int x1, y1, x2, y2; + wlmtk_element_get_dimensions(element_ptr, &x1, &y1, &x2, &y2); + BS_TEST_VERIFY_EQ(test_ptr, 0, x1); + BS_TEST_VERIFY_EQ(test_ptr, 0, y1); + BS_TEST_VERIFY_EQ(test_ptr, 10, x2); + BS_TEST_VERIFY_EQ(test_ptr, 20, y2); + + BS_TEST_VERIFY_NEQ(test_ptr, NULL, rectangle_ptr->wlr_scene_rect_ptr); + + wlmtk_container_remove_element(c_ptr, element_ptr); + + wlmtk_element_destroy(element_ptr); + wlmtk_container_destroy_fake_parent(c_ptr); +} + +/* == End of rectangle.c =================================================== */ diff --git a/src/toolkit/rectangle.h b/src/toolkit/rectangle.h new file mode 100644 index 00000000..672669fd --- /dev/null +++ b/src/toolkit/rectangle.h @@ -0,0 +1,79 @@ +/* ========================================================================= */ +/** + * @file rectangle.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_RECTANGLE_H__ +#define __WLMTK_RECTANGLE_H__ + +#include "element.h" +#include "env.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Forward declaration: Rectangle state. */ +typedef struct _wlmtk_rectangle_t wlmtk_rectangle_t; + +/** + * Creates a rectangle. Useful for margins and borders. + * + * @param env_ptr + * @param width + * @param height + * @param color + * + * @return Pointer to the rectangle state or NULL on error. + */ +wlmtk_rectangle_t *wlmtk_rectangle_create( + wlmtk_env_t *env_ptr, + int width, + int height, + uint32_t color); + +/** + * Destroys the rectangle. + * + * @param rectangle_ptr + */ +void wlmtk_rectangle_destroy(wlmtk_rectangle_t *rectangle_ptr); + +/** + * Sets (or updates) the size of the rectangle. + * + * @param rectangle_ptr + * @param width + * @param height + */ +void wlmtk_rectangle_set_size( + wlmtk_rectangle_t *rectangle_ptr, + int width, + int height); + +/** Returns the superclass @ref wlmtk_element_t of the rectangle. */ +wlmtk_element_t *wlmtk_rectangle_element(wlmtk_rectangle_t *rectangle_ptr); + +/** Unit tests. */ +extern const bs_test_case_t wlmtk_rectangle_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_RECTANGLE_H__ */ +/* == End of rectangle.h =================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 2e548bf4..b0b78fb7 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -39,6 +39,7 @@ #include "env.h" #include "fsm.h" #include "input.h" +#include "rectangle.h" #include "resizebar.h" #include "resizebar_area.h" #include "titlebar.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index c8c38d28..7aa26ac0 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -28,6 +28,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, + { 1, "rectangle", wlmtk_rectangle_test_cases }, { 1, "resizebar", wlmtk_resizebar_test_cases }, { 1, "resizebar_area", wlmtk_resizebar_area_test_cases }, { 1, "titlebar", wlmtk_titlebar_test_cases }, From b75dd28cc37a38a878118f9abc2ab3e9a67a7784 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Dec 2023 13:19:12 +0100 Subject: [PATCH 278/390] Adds separate containers for element and margins to wlmtk_box_t. --- src/toolkit/box.c | 72 ++++++++++++++++++++++++++++++++++------- src/toolkit/box.h | 35 ++++++++++++++++++-- src/toolkit/resizebar.c | 26 +++++++-------- src/toolkit/titlebar.c | 24 +++++++------- src/toolkit/window.c | 25 +++++++------- 5 files changed, 130 insertions(+), 52 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index ba26cfc2..e7afb388 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -48,6 +48,21 @@ bool wlmtk_box_init( box_ptr->orig_super_container_vmt = wlmtk_container_extend( &box_ptr->super_container, &box_container_vmt); + if (!wlmtk_container_init(&box_ptr->element_container, env_ptr)) { + wlmtk_box_fini(box_ptr); + return false; + } + wlmtk_element_set_visible(&box_ptr->element_container.super_element, true); + wlmtk_container_add_element(&box_ptr->super_container, + &box_ptr->element_container.super_element); + if (!wlmtk_container_init(&box_ptr->margin_container, env_ptr)) { + wlmtk_box_fini(box_ptr); + return false; + } + wlmtk_element_set_visible(&box_ptr->margin_container.super_element, true); + wlmtk_container_add_element(&box_ptr->super_container, + &box_ptr->margin_container.super_element); + box_ptr->orientation = orientation; return true; } @@ -55,10 +70,45 @@ bool wlmtk_box_init( /* ------------------------------------------------------------------------- */ void wlmtk_box_fini(wlmtk_box_t *box_ptr) { + if (NULL != box_ptr->margin_container.super_element.parent_container_ptr) { + wlmtk_container_remove_element( + &box_ptr->super_container, + &box_ptr->margin_container.super_element); + } + if (NULL != box_ptr->element_container.super_element.parent_container_ptr) { + wlmtk_container_remove_element( + &box_ptr->super_container, + &box_ptr->element_container.super_element); + } + + wlmtk_container_fini(&box_ptr->super_container); memset(box_ptr, 0, sizeof(wlmtk_box_t)); } +/* ------------------------------------------------------------------------- */ +void wlmtk_box_add_element_front( + wlmtk_box_t *box_ptr, + wlmtk_element_t *element_ptr) +{ + wlmtk_container_add_element(&box_ptr->element_container, element_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_box_add_element_back( + wlmtk_box_t *box_ptr, + wlmtk_element_t *element_ptr) +{ + wlmtk_container_add_element_atop( + &box_ptr->element_container, NULL, element_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_box_remove_element(wlmtk_box_t *box_ptr, wlmtk_element_t *element_ptr) +{ + wlmtk_container_remove_element(&box_ptr->element_container, element_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -77,7 +127,7 @@ void _wlmtk_box_container_update_layout( container_ptr, wlmtk_box_t, super_container); int position = 0; - for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; + for (bs_dllist_node_t *dlnode_ptr = box_ptr->element_container.elements.head_ptr; dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); @@ -160,9 +210,9 @@ void test_layout_horizontal(bs_test_t *test_ptr) e3_ptr->height = 4; // Note: Elements are added "in front" == left. - wlmtk_container_add_element(&box.super_container, &e1_ptr->element); - wlmtk_container_add_element(&box.super_container, &e2_ptr->element); - wlmtk_container_add_element(&box.super_container, &e3_ptr->element); + wlmtk_box_add_element_front(&box, &e1_ptr->element); + wlmtk_box_add_element_front(&box, &e2_ptr->element); + wlmtk_box_add_element_front(&box, &e3_ptr->element); // Layout: e3 | e1 (e2 is invisible). BS_TEST_VERIFY_EQ(test_ptr, 40, e1_ptr->element.x); @@ -179,12 +229,12 @@ void test_layout_horizontal(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, e3_ptr->element.x); // Remove elements. Must update each. - wlmtk_container_remove_element(&box.super_container, &e3_ptr->element); + wlmtk_box_remove_element(&box, &e3_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, 20, e1_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); - wlmtk_container_remove_element(&box.super_container, &e2_ptr->element); + wlmtk_box_remove_element(&box, &e2_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.x); - wlmtk_container_remove_element(&box.super_container, &e1_ptr->element); + wlmtk_box_remove_element(&box, &e1_ptr->element); wlmtk_element_destroy(&e3_ptr->element); wlmtk_element_destroy(&e2_ptr->element); @@ -209,8 +259,8 @@ void test_layout_vertical(bs_test_t *test_ptr) e2_ptr->height = 2; // Note: Elements are added "in front" == left. - wlmtk_container_add_element(&box.super_container, &e1_ptr->element); - wlmtk_container_add_element(&box.super_container, &e2_ptr->element); + wlmtk_box_add_element_front(&box, &e1_ptr->element); + wlmtk_box_add_element_front(&box, &e2_ptr->element); // Layout: e2 | e1. BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.x); @@ -219,9 +269,9 @@ void test_layout_vertical(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.y); // Remove elements. Must update each. - wlmtk_container_remove_element(&box.super_container, &e2_ptr->element); + wlmtk_box_remove_element(&box, &e2_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.y); - wlmtk_container_remove_element(&box.super_container, &e1_ptr->element); + wlmtk_box_remove_element(&box, &e1_ptr->element); wlmtk_element_destroy(&e2_ptr->element); wlmtk_element_destroy(&e1_ptr->element); diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 30eb74c0..3cbc9f62 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -31,9 +31,9 @@ extern "C" { /** Orientation of the box. */ typedef enum { - /** Horizontal box layout. The container's "top" is on the left. */ + /** Horizontal box layout. The container's "front" is on the left. */ WLMTK_BOX_HORIZONTAL, - /** Vertical box layout. The container's "top" is the top. */ + /** Vertical box layout. The container's "front" is the top. */ WLMTK_BOX_VERTICAL, } wlmtk_box_orientation_t; @@ -45,6 +45,11 @@ struct _wlmtk_box_t { wlmtk_container_vmt_t orig_super_container_vmt; /** Orientation of the box. */ wlmtk_box_orientation_t orientation; + + /** Container for the box's elements. */ + wlmtk_container_t element_container; + /** Container for margin elements. */ + wlmtk_container_t margin_container; }; /** @@ -68,6 +73,32 @@ bool wlmtk_box_init( */ void wlmtk_box_fini(wlmtk_box_t *box_ptr); +/** + * Adds `element_ptr` to the front of the box. + * + * @param box_ptr + * @param element_ptr + */ +void wlmtk_box_add_element_front(wlmtk_box_t *box_ptr, wlmtk_element_t *element_ptr); + +/** + * Adds `element_ptr` to the back of the box. + * + * @param box_ptr + * @param element_ptr + */ +void wlmtk_box_add_element_back(wlmtk_box_t *box_ptr, wlmtk_element_t *element_ptr); + +/** + * Removes `element_ptr` from the box. + * + * Requires that element_ptr is an element of the box. + * + * @param box_ptr + * @param element_ptr + */ +void wlmtk_box_remove_element(wlmtk_box_t *box_ptr, wlmtk_element_t *element_ptr); + /** Unit tests. */ extern const bs_test_case_t wlmtk_box_test_cases[]; diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 93f0c9ea..204dc2b1 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -94,8 +94,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_container_add_element( - &resizebar_ptr->super_box.super_container, + wlmtk_box_add_element_front( + &resizebar_ptr->super_box, wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( @@ -104,9 +104,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_container_add_element_atop( - &resizebar_ptr->super_box.super_container, - NULL, + wlmtk_box_add_element_back( + &resizebar_ptr->super_box, wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( @@ -115,9 +114,8 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } - wlmtk_container_add_element_atop( - &resizebar_ptr->super_box.super_container, - NULL, + wlmtk_box_add_element_back( + &resizebar_ptr->super_box, wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr)); return resizebar_ptr; @@ -127,22 +125,22 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( void wlmtk_resizebar_destroy(wlmtk_resizebar_t *resizebar_ptr) { if (NULL != resizebar_ptr->right_area_ptr) { - wlmtk_container_remove_element( - &resizebar_ptr->super_box.super_container, + wlmtk_box_remove_element( + &resizebar_ptr->super_box, wlmtk_resizebar_area_element(resizebar_ptr->right_area_ptr)); wlmtk_resizebar_area_destroy(resizebar_ptr->right_area_ptr); resizebar_ptr->right_area_ptr = NULL; } if (NULL != resizebar_ptr->center_area_ptr) { - wlmtk_container_remove_element( - &resizebar_ptr->super_box.super_container, + wlmtk_box_remove_element( + &resizebar_ptr->super_box, wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); wlmtk_resizebar_area_destroy(resizebar_ptr->center_area_ptr); resizebar_ptr->center_area_ptr = NULL; } if (NULL != resizebar_ptr->left_area_ptr) { - wlmtk_container_remove_element( - &resizebar_ptr->super_box.super_container, + wlmtk_box_remove_element( + &resizebar_ptr->super_box, wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); wlmtk_resizebar_area_destroy(resizebar_ptr->left_area_ptr); diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index a87448ea..5221eaff 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -110,8 +110,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_container_add_element( - &titlebar_ptr->super_box.super_container, + wlmtk_box_add_element_front( + &titlebar_ptr->super_box, wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr)); titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( @@ -123,8 +123,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_container_add_element( - &titlebar_ptr->super_box.super_container, + wlmtk_box_add_element_front( + &titlebar_ptr->super_box, wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( @@ -136,8 +136,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } - wlmtk_container_add_element_atop( - &titlebar_ptr->super_box.super_container, NULL, + wlmtk_box_add_element_back( + &titlebar_ptr->super_box, wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr)); return titlebar_ptr; @@ -147,24 +147,24 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( void wlmtk_titlebar_destroy(wlmtk_titlebar_t *titlebar_ptr) { if (NULL != titlebar_ptr->close_button_ptr) { - wlmtk_container_remove_element( - &titlebar_ptr->super_box.super_container, + wlmtk_box_remove_element( + &titlebar_ptr->super_box, wlmtk_titlebar_button_element(titlebar_ptr->close_button_ptr)); wlmtk_titlebar_button_destroy(titlebar_ptr->close_button_ptr); titlebar_ptr->close_button_ptr = NULL; } if (NULL != titlebar_ptr->minimize_button_ptr) { - wlmtk_container_remove_element( - &titlebar_ptr->super_box.super_container, + wlmtk_box_remove_element( + &titlebar_ptr->super_box, wlmtk_titlebar_button_element(titlebar_ptr->minimize_button_ptr)); wlmtk_titlebar_button_destroy(titlebar_ptr->minimize_button_ptr); titlebar_ptr->minimize_button_ptr = NULL; } if (NULL != titlebar_ptr->titlebar_title_ptr) { - wlmtk_container_remove_element( - &titlebar_ptr->super_box.super_container, + wlmtk_box_remove_element( + &titlebar_ptr->super_box, wlmtk_titlebar_title_element(titlebar_ptr->titlebar_title_ptr)); wlmtk_titlebar_title_destroy(titlebar_ptr->titlebar_title_ptr); titlebar_ptr->titlebar_title_ptr = NULL; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index bd63d52b..337db85f 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -210,15 +210,14 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_fini(window_ptr); return false; } - wlmtk_container_add_element( - &window_ptr->super_box.super_container, + wlmtk_box_add_element_front( + &window_ptr->super_box, wlmtk_resizebar_element(window_ptr->resizebar_ptr)); wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - wlmtk_container_add_element_atop( - &window_ptr->super_box.super_container, - wlmtk_resizebar_element(window_ptr->resizebar_ptr), + wlmtk_box_add_element_front( + &window_ptr->super_box, wlmtk_content_element(content_ptr)); window_ptr->content_ptr = content_ptr; wlmtk_content_set_window(content_ptr, window_ptr); @@ -230,8 +229,8 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_window_fini(window_ptr); return false; } - wlmtk_container_add_element( - &window_ptr->super_box.super_container, + wlmtk_box_add_element_front( + &window_ptr->super_box, wlmtk_titlebar_element(window_ptr->titlebar_ptr)); wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); @@ -248,24 +247,24 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, void wlmtk_window_fini(wlmtk_window_t *window_ptr) { if (NULL != window_ptr->titlebar_ptr) { - wlmtk_container_remove_element( - &window_ptr->super_box.super_container, + wlmtk_box_remove_element( + &window_ptr->super_box, wlmtk_titlebar_element(window_ptr->titlebar_ptr)); wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); window_ptr->titlebar_ptr = NULL; } if (NULL != window_ptr->resizebar_ptr) { - wlmtk_container_remove_element( - &window_ptr->super_box.super_container, + wlmtk_box_remove_element( + &window_ptr->super_box, wlmtk_resizebar_element(window_ptr->resizebar_ptr)); wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); window_ptr->resizebar_ptr = NULL; } if (NULL != window_ptr->content_ptr) { - wlmtk_container_remove_element( - &window_ptr->super_box.super_container, + wlmtk_box_remove_element( + &window_ptr->super_box, wlmtk_content_element(window_ptr->content_ptr)); wlmtk_element_set_visible( wlmtk_content_element(window_ptr->content_ptr), false); From 2127c98f81b4972a4a3b064f95cfb5d453cbe134 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 2 Dec 2023 14:55:46 +0100 Subject: [PATCH 279/390] Adds wlmtk_rectangle_from_element. --- src/toolkit/rectangle.c | 18 ++++++++++++++++++ src/toolkit/rectangle.h | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/toolkit/rectangle.c b/src/toolkit/rectangle.c index 5f9038a3..bf5fbed1 100644 --- a/src/toolkit/rectangle.c +++ b/src/toolkit/rectangle.c @@ -134,6 +134,15 @@ wlmtk_element_t *wlmtk_rectangle_element(wlmtk_rectangle_t *rectangle_ptr) return &rectangle_ptr->super_element; } +/* ------------------------------------------------------------------------- */ +wlmtk_rectangle_t *wlmtk_rectangle_from_element(wlmtk_element_t *element_ptr) +{ + BS_ASSERT(element_ptr->vmt.destroy = _wlmtk_rectangle_element_destroy); + wlmtk_rectangle_t *rectangle_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_rectangle_t, super_element); + return rectangle_ptr; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -252,6 +261,15 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 10, x2); BS_TEST_VERIFY_EQ(test_ptr, 20, y2); + BS_TEST_VERIFY_EQ( + test_ptr, + &rectangle_ptr->super_element, + wlmtk_rectangle_element(rectangle_ptr)); + BS_TEST_VERIFY_EQ( + test_ptr, + rectangle_ptr, + wlmtk_rectangle_from_element(&rectangle_ptr->super_element)); + wlmtk_rectangle_destroy(rectangle_ptr); } diff --git a/src/toolkit/rectangle.h b/src/toolkit/rectangle.h index 672669fd..b41cdae8 100644 --- a/src/toolkit/rectangle.h +++ b/src/toolkit/rectangle.h @@ -68,6 +68,17 @@ void wlmtk_rectangle_set_size( /** Returns the superclass @ref wlmtk_element_t of the rectangle. */ wlmtk_element_t *wlmtk_rectangle_element(wlmtk_rectangle_t *rectangle_ptr); +/** + * Gets the @ref wlmtk_rectangle_t instance from it's element superclass. + * + * Requires `element_ptr` as pointer to @ref wlmtk_rectangle_t::super_element. + * + * @param element_ptr + * + * @return The pointer to the @ref wlmtk_rectangle_t instance. + */ +wlmtk_rectangle_t *wlmtk_rectangle_from_element(wlmtk_element_t *element_ptr); + /** Unit tests. */ extern const bs_test_case_t wlmtk_rectangle_test_cases[]; From 676135d6fea33781fc1608de0f82906d54359b1a Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Dec 2023 21:30:56 +0100 Subject: [PATCH 280/390] Considers visibility for container dimensions. --- src/toolkit/container.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index 2ff40b14..bc3b085f 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -339,11 +339,13 @@ void element_get_dimensions( wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); - int left = 0, top = 0, right = 0, bottom = 0; + int left = INT32_MAX, top = INT32_MAX; + int right = INT32_MIN, bottom = INT32_MIN; for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + if (!element_ptr->visible) continue; int x_pos, y_pos; wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); @@ -355,6 +357,9 @@ void element_get_dimensions( bottom = BS_MAX(bottom, y_pos + y2); } + if (left >= right) { left = 0; right = 0; } + if (top >= bottom) { top = 0; bottom = 0; } + if (NULL != left_ptr) *left_ptr = left; if (NULL != top_ptr) *top_ptr = top; if (NULL != right_ptr) *right_ptr = right; @@ -381,11 +386,13 @@ void element_get_pointer_area( wlmtk_container_t *container_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_container_t, super_element); - int left = 0, top = 0, right = 0, bottom = 0; + int left = INT32_MAX, top = INT32_MAX; + int right = INT32_MIN, bottom = INT32_MIN; for (bs_dllist_node_t *dlnode_ptr = container_ptr->elements.head_ptr; dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + if (!element_ptr->visible) continue; int x_pos, y_pos; wlmtk_element_get_position(element_ptr, &x_pos, &y_pos); @@ -397,6 +404,9 @@ void element_get_pointer_area( bottom = BS_MAX(bottom, y_pos + y2); } + if (left >= right) { left = 0; right = 0; } + if (top >= bottom) { top = 0; bottom = 0; } + if (NULL != left_ptr) *left_ptr = left; if (NULL != top_ptr) *top_ptr = top; if (NULL != right_ptr) *right_ptr = right; @@ -963,7 +973,7 @@ void test_pointer_motion(bs_test_t *test_ptr) wlmtk_element_set_position(&elem1_ptr->element, -20, -40); elem1_ptr->width = 10; elem1_ptr->height = 5; - wlmtk_element_set_visible(&elem1_ptr->element, true); + wlmtk_element_set_visible(&elem1_ptr->element, false); wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem2_ptr->element, 100, 200); @@ -975,11 +985,26 @@ void test_pointer_motion(bs_test_t *test_ptr) // Verify 'dimensions' and 'pointer_area', derived from children. int l, t, r, b; wlmtk_element_get_dimensions(&container.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, 100, l); + BS_TEST_VERIFY_EQ(test_ptr, 200, t); + BS_TEST_VERIFY_EQ(test_ptr, 110, r); + BS_TEST_VERIFY_EQ(test_ptr, 205, b); + + wlmtk_element_set_visible(&elem1_ptr->element, true); + wlmtk_element_get_dimensions(&container.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, -20, l); BS_TEST_VERIFY_EQ(test_ptr, -40, t); BS_TEST_VERIFY_EQ(test_ptr, 110, r); BS_TEST_VERIFY_EQ(test_ptr, 205, b); + wlmtk_element_set_visible(&elem1_ptr->element, false); + wlmtk_element_get_pointer_area(&container.super_element, &l, &t, &r, &b); + BS_TEST_VERIFY_EQ(test_ptr, 99, l); + BS_TEST_VERIFY_EQ(test_ptr, 198, t); + BS_TEST_VERIFY_EQ(test_ptr, 113, r); + BS_TEST_VERIFY_EQ(test_ptr, 209, b); + + wlmtk_element_set_visible(&elem1_ptr->element, true); wlmtk_element_get_pointer_area(&container.super_element, &l, &t, &r, &b); BS_TEST_VERIFY_EQ(test_ptr, -21, l); BS_TEST_VERIFY_EQ(test_ptr, -42, t); From db88399e5a5c8ef232c000afbac38b4692dda984 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 3 Dec 2023 21:43:51 +0100 Subject: [PATCH 281/390] Adds suport for margins in wlmtk_box_t. --- src/toolkit/box.c | 117 ++++++++++++++++++++++++++++++++++------ src/toolkit/box.h | 11 +++- src/toolkit/resizebar.c | 9 ++-- src/toolkit/resizebar.h | 2 + src/toolkit/style.h | 8 +++ src/toolkit/titlebar.c | 25 ++++++--- src/toolkit/titlebar.h | 2 + src/toolkit/window.c | 11 +++- 8 files changed, 156 insertions(+), 29 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index e7afb388..8f6b5f13 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -20,10 +20,13 @@ #include "box.h" +#include "rectangle.h" + /* == Declarations ========================================================= */ static void _wlmtk_box_container_update_layout( wlmtk_container_t *container_ptr); +static bs_dllist_node_t *create_margin(wlmtk_box_t *box_ptr); /* == Data ================================================================= */ @@ -38,7 +41,8 @@ static const wlmtk_container_vmt_t box_container_vmt = { bool wlmtk_box_init( wlmtk_box_t *box_ptr, wlmtk_env_t *env_ptr, - wlmtk_box_orientation_t orientation) + wlmtk_box_orientation_t orientation, + const wlmtk_margin_style_t *style_ptr) { BS_ASSERT(NULL != box_ptr); memset(box_ptr, 0, sizeof(wlmtk_box_t)); @@ -47,6 +51,8 @@ bool wlmtk_box_init( } box_ptr->orig_super_container_vmt = wlmtk_container_extend( &box_ptr->super_container, &box_container_vmt); + box_ptr->env_ptr = env_ptr; + memcpy(&box_ptr->style, style_ptr, sizeof(wlmtk_margin_style_t)); if (!wlmtk_container_init(&box_ptr->element_container, env_ptr)) { wlmtk_box_fini(box_ptr); @@ -81,7 +87,6 @@ void wlmtk_box_fini(wlmtk_box_t *box_ptr) &box_ptr->element_container.super_element); } - wlmtk_container_fini(&box_ptr->super_container); memset(box_ptr, 0, sizeof(wlmtk_box_t)); } @@ -116,7 +121,7 @@ void wlmtk_box_remove_element(wlmtk_box_t *box_ptr, wlmtk_element_t *element_ptr * Updates the layout of the box. * * Steps through all visible elements, and sets their position to be - * left-to-right. + * left-to-right. Also updates and repositions all margin elements. * * @param container_ptr */ @@ -125,8 +130,23 @@ void _wlmtk_box_container_update_layout( { wlmtk_box_t *box_ptr = BS_CONTAINER_OF( container_ptr, wlmtk_box_t, super_container); + wlmtk_element_t *margin_element_ptr = NULL; + + int margin_x = 0; + int margin_y = 0; + int margin_width = box_ptr->style.width; + int margin_height = box_ptr->style.width; + + size_t visible_elements = 0; + for (bs_dllist_node_t *dlnode_ptr = box_ptr->element_container.elements.head_ptr; + dlnode_ptr != NULL; + dlnode_ptr = dlnode_ptr->next_ptr) { + wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); + if (element_ptr->visible) visible_elements++; + } int position = 0; + bs_dllist_node_t *margin_dlnode_ptr = box_ptr->margin_container.elements.head_ptr; for (bs_dllist_node_t *dlnode_ptr = box_ptr->element_container.elements.head_ptr; dlnode_ptr != NULL; dlnode_ptr = dlnode_ptr->next_ptr) { @@ -141,18 +161,47 @@ void _wlmtk_box_container_update_layout( switch (box_ptr->orientation) { case WLMTK_BOX_HORIZONTAL: x = position - left; - position += right - left; + margin_x = position + right - left; + margin_height = bottom - top; + position = margin_x + box_ptr->style.width; break; case WLMTK_BOX_VERTICAL: y = position - top; - position += bottom - top; + margin_y = position + bottom - top; + margin_width = right - left; + position = margin_y + box_ptr->style.width; break; default: bs_log(BS_FATAL, "Weird orientation %d.", box_ptr->orientation); } wlmtk_element_set_position(element_ptr, x, y); + visible_elements--; + + // Early exit: No margin needed, if there's no next element. + if (NULL == dlnode_ptr->next_ptr || 0 >= visible_elements) break; + + // If required: Create new margin, then position the margin element. + if (NULL == margin_dlnode_ptr) { + margin_dlnode_ptr = create_margin(box_ptr); + } + margin_element_ptr = wlmtk_element_from_dlnode(margin_dlnode_ptr); + wlmtk_element_set_position(margin_element_ptr, margin_x, margin_y); + wlmtk_rectangle_set_size( + wlmtk_rectangle_from_element(margin_element_ptr), + margin_width, margin_height); + + margin_dlnode_ptr = margin_dlnode_ptr->next_ptr; + } + + // Remove excess margin nodes. + while (NULL != margin_dlnode_ptr) { + margin_element_ptr = wlmtk_element_from_dlnode(margin_dlnode_ptr); + margin_dlnode_ptr = margin_dlnode_ptr->next_ptr; + wlmtk_container_remove_element( + &box_ptr->margin_container, margin_element_ptr); + wlmtk_element_destroy(margin_element_ptr); } // Run the base class' update layout; may update pointer focus. @@ -166,6 +215,24 @@ void _wlmtk_box_container_update_layout( } } +/* ------------------------------------------------------------------------- */ +/** Creates a new margin element, and returns the dlnode. */ +bs_dllist_node_t *create_margin(wlmtk_box_t *box_ptr) +{ + wlmtk_rectangle_t *rect_ptr = wlmtk_rectangle_create( + box_ptr->env_ptr, 0, 0, box_ptr->style.color); + BS_ASSERT(NULL != rect_ptr); + + wlmtk_container_add_element_atop( + &box_ptr->margin_container, + NULL, + wlmtk_rectangle_element(rect_ptr)); + wlmtk_element_set_visible( + wlmtk_rectangle_element(rect_ptr), true); + + return wlmtk_dlnode_from_element(wlmtk_rectangle_element(rect_ptr)); +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); @@ -179,13 +246,19 @@ const bs_test_case_t wlmtk_box_test_cases[] = { { 0, NULL, NULL } }; +/** Style used for tests. */ +static const wlmtk_margin_style_t test_style = { + .width = 2, + .color = 0xff000000 +}; + /* ------------------------------------------------------------------------- */ /** Exercises setup and teardown. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_box_t box; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_box_init( - &box, NULL, WLMTK_BOX_HORIZONTAL)); + &box, NULL, WLMTK_BOX_HORIZONTAL, &test_style)); wlmtk_box_fini(&box); } @@ -194,7 +267,7 @@ void test_init_fini(bs_test_t *test_ptr) void test_layout_horizontal(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, NULL, WLMTK_BOX_HORIZONTAL); + wlmtk_box_init(&box, NULL, WLMTK_BOX_HORIZONTAL, &test_style); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); @@ -211,11 +284,14 @@ void test_layout_horizontal(bs_test_t *test_ptr) // Note: Elements are added "in front" == left. wlmtk_box_add_element_front(&box, &e1_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, 0, bs_dllist_size(&box.margin_container.elements)); wlmtk_box_add_element_front(&box, &e2_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, 0, bs_dllist_size(&box.margin_container.elements)); wlmtk_box_add_element_front(&box, &e3_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, 1, bs_dllist_size(&box.margin_container.elements)); // Layout: e3 | e1 (e2 is invisible). - BS_TEST_VERIFY_EQ(test_ptr, 40, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 42, e1_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.y); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.y); @@ -224,16 +300,23 @@ void test_layout_horizontal(bs_test_t *test_ptr) // Make e2 visible, now we should have: e3 | e2 | e1. wlmtk_element_set_visible(&e2_ptr->element, true); - BS_TEST_VERIFY_EQ(test_ptr, 60, e1_ptr->element.x); - BS_TEST_VERIFY_EQ(test_ptr, 40, e2_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 64, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 42, e2_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e3_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 2, bs_dllist_size(&box.margin_container.elements)); + + wlmtk_element_set_visible(&e1_ptr->element, false); + BS_TEST_VERIFY_EQ(test_ptr, 1, bs_dllist_size(&box.margin_container.elements)); + wlmtk_element_set_visible(&e1_ptr->element, true); // Remove elements. Must update each. wlmtk_box_remove_element(&box, &e3_ptr->element); - BS_TEST_VERIFY_EQ(test_ptr, 20, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 22, e1_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 1, bs_dllist_size(&box.margin_container.elements)); wlmtk_box_remove_element(&box, &e2_ptr->element); BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, bs_dllist_size(&box.margin_container.elements)); wlmtk_box_remove_element(&box, &e1_ptr->element); wlmtk_element_destroy(&e3_ptr->element); @@ -247,16 +330,16 @@ void test_layout_horizontal(bs_test_t *test_ptr) void test_layout_vertical(bs_test_t *test_ptr) { wlmtk_box_t box; - wlmtk_box_init(&box, NULL, WLMTK_BOX_VERTICAL); + wlmtk_box_init(&box, NULL, WLMTK_BOX_VERTICAL, &test_style); wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); - e1_ptr->width = 10; - e1_ptr->height = 1; + e1_ptr->width = 100; + e1_ptr->height = 10; wlmtk_fake_element_t *e2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e2_ptr->element, true); - e2_ptr->width = 20; - e2_ptr->height = 2; + e2_ptr->width = 200; + e2_ptr->height = 20; // Note: Elements are added "in front" == left. wlmtk_box_add_element_front(&box, &e1_ptr->element); @@ -264,7 +347,7 @@ void test_layout_vertical(bs_test_t *test_ptr) // Layout: e2 | e1. BS_TEST_VERIFY_EQ(test_ptr, 0, e1_ptr->element.x); - BS_TEST_VERIFY_EQ(test_ptr, 2, e1_ptr->element.y); + BS_TEST_VERIFY_EQ(test_ptr, 22, e1_ptr->element.y); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.x); BS_TEST_VERIFY_EQ(test_ptr, 0, e2_ptr->element.y); diff --git a/src/toolkit/box.h b/src/toolkit/box.h index 3cbc9f62..79b421ed 100644 --- a/src/toolkit/box.h +++ b/src/toolkit/box.h @@ -24,6 +24,7 @@ typedef struct _wlmtk_box_t wlmtk_box_t; #include "container.h" +#include "style.h" #ifdef __cplusplus extern "C" { @@ -46,10 +47,16 @@ struct _wlmtk_box_t { /** Orientation of the box. */ wlmtk_box_orientation_t orientation; + /** Environment. */ + wlmtk_env_t *env_ptr; + /** Container for the box's elements. */ wlmtk_container_t element_container; /** Container for margin elements. */ wlmtk_container_t margin_container; + + /** Margin style. */ + wlmtk_margin_style_t style; }; /** @@ -58,13 +65,15 @@ struct _wlmtk_box_t { * @param box_ptr * @param orientation * @param env_ptr + * @param style_ptr * * @return true on success. */ bool wlmtk_box_init( wlmtk_box_t *box_ptr, wlmtk_env_t *env_ptr, - wlmtk_box_orientation_t orientation); + wlmtk_box_orientation_t orientation, + const wlmtk_margin_style_t *style_ptr); /** * Un-initializes the box. diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 204dc2b1..d033d896 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -78,9 +78,12 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( 1, sizeof(wlmtk_resizebar_t)); if (NULL == resizebar_ptr) return NULL; memcpy(&resizebar_ptr->style, style_ptr, sizeof(wlmtk_resizebar_style_t)); + BS_ASSERT(0 == resizebar_ptr->style.margin_style.width); - if (!wlmtk_box_init(&resizebar_ptr->super_box, env_ptr, - WLMTK_BOX_HORIZONTAL)) { + if (!wlmtk_box_init(&resizebar_ptr->super_box, + env_ptr, + WLMTK_BOX_HORIZONTAL, + &resizebar_ptr->style.margin_style)) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; } @@ -310,7 +313,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 16, center_elem_ptr->x); BS_TEST_VERIFY_EQ(test_ptr, 17, right_elem_ptr->x); - // Not enough space for the center element. + // Not enough space for the center element with all margins. BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_resizebar_set_width(resizebar_ptr, 32)); BS_TEST_VERIFY_TRUE(test_ptr, left_elem_ptr->visible); diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 2f427825..f0382ae9 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -46,6 +46,8 @@ typedef struct { unsigned corner_width; /** Width of the bezel. */ uint32_t bezel_width; + /** Style of the margin within the resizebar. */ + wlmtk_margin_style_t margin_style; } wlmtk_resizebar_style_t; /** diff --git a/src/toolkit/style.h b/src/toolkit/style.h index 659ae9d3..7b8c05af 100644 --- a/src/toolkit/style.h +++ b/src/toolkit/style.h @@ -66,6 +66,14 @@ typedef struct { } param; } wlmtk_style_fill_t; +/** Specifies color and width of a margin. */ +typedef struct { + /** Width of the margin. */ + int width; + /** Color of the margin. */ + uint32_t color; +} wlmtk_margin_style_t; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 5221eaff..ffaefbfc 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -61,6 +61,8 @@ struct _wlmtk_titlebar_t { int close_position; /** Position of the title element. */ int title_position; + /** Width of the title element. */ + int title_width; /** Whether the title bar is currently displayed as activated. */ bool activated; @@ -96,7 +98,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); if (!wlmtk_box_init(&titlebar_ptr->super_box, env_ptr, - WLMTK_BOX_HORIZONTAL)) { + WLMTK_BOX_HORIZONTAL, + &titlebar_ptr->style.margin_style)) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; } @@ -192,14 +195,22 @@ bool wlmtk_titlebar_set_width( if (titlebar_ptr->width == width) return true; if (!redraw_buffers(titlebar_ptr, width)) return false; BS_ASSERT(width == titlebar_ptr->width); + titlebar_ptr->title_width = width; + // Room for a close button? titlebar_ptr->close_position = width; if (3 * titlebar_ptr->style.height < width) { titlebar_ptr->close_position = width - titlebar_ptr->style.height; + titlebar_ptr->title_width -= titlebar_ptr->style.height + + titlebar_ptr->style.margin_style.width; } titlebar_ptr->title_position = 0; + // Also having room for a minimize button? if (4 * titlebar_ptr->style.height < width) { - titlebar_ptr->title_position = titlebar_ptr->style.height; + titlebar_ptr->title_position = titlebar_ptr->style.height + + titlebar_ptr->style.margin_style.width; + titlebar_ptr->title_width -= titlebar_ptr->style.height + + titlebar_ptr->style.margin_style.width; } if (!redraw(titlebar_ptr)) { @@ -310,7 +321,7 @@ bool redraw(wlmtk_titlebar_t *titlebar_ptr) titlebar_ptr->focussed_gfxbuf_ptr, titlebar_ptr->blurred_gfxbuf_ptr, titlebar_ptr->title_position, - titlebar_ptr->close_position - titlebar_ptr->title_position, + titlebar_ptr->title_width, titlebar_ptr->activated, titlebar_ptr->title_ptr, &titlebar_ptr->style)) { @@ -388,7 +399,7 @@ void test_create_destroy(bs_test_t *test_ptr) void test_variable_width(bs_test_t *test_ptr) { wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); - wlmtk_titlebar_style_t style = { .height = 22 }; + wlmtk_titlebar_style_t style = { .height = 22, .margin_style = { .width = 2 } }; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( NULL, &fake_window_ptr->window, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); @@ -412,9 +423,9 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, title_elem_ptr->visible); BS_TEST_VERIFY_TRUE(test_ptr, minimize_elem_ptr->visible); BS_TEST_VERIFY_TRUE(test_ptr, close_elem_ptr->visible); - BS_TEST_VERIFY_EQ(test_ptr, 22, title_elem_ptr->x); + BS_TEST_VERIFY_EQ(test_ptr, 24, title_elem_ptr->x); wlmtk_element_get_dimensions(title_elem_ptr, NULL, NULL, &width, NULL); - BS_TEST_VERIFY_EQ(test_ptr, 45, width); + BS_TEST_VERIFY_EQ(test_ptr, 41, width); BS_TEST_VERIFY_EQ(test_ptr, 67, close_elem_ptr->x); // Width sufficient only for 1 button. @@ -424,7 +435,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, close_elem_ptr->visible); BS_TEST_VERIFY_EQ(test_ptr, 0, title_elem_ptr->x); wlmtk_element_get_dimensions(title_elem_ptr, NULL, NULL, &width, NULL); - BS_TEST_VERIFY_EQ(test_ptr, 45, width); + BS_TEST_VERIFY_EQ(test_ptr, 43, width); // Width doesn't permit any button. BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_titlebar_set_width(titlebar_ptr, 66)); diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index e32612c4..49970c24 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -46,6 +46,8 @@ typedef struct { uint32_t height; /** Width of the bezel. */ uint32_t bezel_width; + /** Style of the margin within the resizebar. */ + wlmtk_margin_style_t margin_style; } wlmtk_titlebar_style_t; /** diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 337db85f..25f3ae87 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -141,6 +141,7 @@ static const wlmtk_titlebar_style_t titlebar_style = { .blurred_text_color = 0xff000000, .height = 22, .bezel_width = 1, + .margin_style = { .width = 1, .color = 0xff000000 }, }; /** Style of the resize bar. */ @@ -153,6 +154,13 @@ static const wlmtk_resizebar_style_t resizebar_style = { .height = 7, .corner_width = 29, .bezel_width = 1, + .margin_style = { .width = 0, .color = 0xff000000 }, +}; + +/** Style of the margin between title, content and resizebar. */ +static const wlmtk_margin_style_t margin_style = { + .width = 1, + .color = 0xff000000, }; /* == Exported methods ===================================================== */ @@ -192,7 +200,8 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, } if (!wlmtk_box_init(&window_ptr->super_box, env_ptr, - WLMTK_BOX_VERTICAL)) { + WLMTK_BOX_VERTICAL, + &margin_style)) { wlmtk_window_fini(window_ptr); return false; } From a31122109e6cf4b7bea79a660b8ce9b3dea63ff7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Mon, 4 Dec 2023 21:34:48 +0100 Subject: [PATCH 282/390] Adds boilerplate code for a bordered element. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/bordered.c | 121 +++++++++++++++++++++++++++++++++++++ src/toolkit/bordered.h | 76 +++++++++++++++++++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 5 files changed, 201 insertions(+) create mode 100644 src/toolkit/bordered.c create mode 100644 src/toolkit/bordered.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 759c55f3..e26a9ba7 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -21,6 +21,7 @@ SET(PUBLIC_HEADER_FILES toolkit.h util.h + bordered.h box.h buffer.h button.h @@ -41,6 +42,7 @@ SET(PUBLIC_HEADER_FILES ADD_LIBRARY(toolkit STATIC) TARGET_SOURCES(toolkit PRIVATE + bordered.c box.c buffer.c button.c diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c new file mode 100644 index 00000000..99d1bfb4 --- /dev/null +++ b/src/toolkit/bordered.c @@ -0,0 +1,121 @@ +/* ========================================================================= */ +/** + * @file bordered.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bordered.h" + +/* == Declarations ========================================================= */ + +static void _wlmtk_bordered_container_update_layout( + wlmtk_container_t *container_ptr); + +/* == Data ================================================================= */ + +/** Virtual method table: @ref wlmtk_container_t at @ref wlmtk_bordered_t. */ +static const wlmtk_container_vmt_t bordered_container_vmt = { + .update_layout = _wlmtk_bordered_container_update_layout, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_bordered_init(wlmtk_bordered_t *bordered_ptr, + wlmtk_env_t *env_ptr, + wlmtk_element_t *element_ptr, + const wlmtk_margin_style_t *style_ptr) +{ + BS_ASSERT(NULL != bordered_ptr); + memset(bordered_ptr, 0, sizeof(wlmtk_bordered_t)); + if (!wlmtk_container_init(&bordered_ptr->super_container, env_ptr)) { + return false; + } + bordered_ptr->orig_super_container_vmt = wlmtk_container_extend( + &bordered_ptr->super_container, &bordered_container_vmt); + memcpy(&bordered_ptr->style, style_ptr, sizeof(wlmtk_margin_style_t)); + + bordered_ptr->element_ptr = element_ptr; + wlmtk_container_add_element(&bordered_ptr->super_container, + bordered_ptr->element_ptr); + + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_bordered_fini(wlmtk_bordered_t *bordered_ptr) +{ + wlmtk_container_remove_element(&bordered_ptr->super_container, + bordered_ptr->element_ptr); + wlmtk_container_fini(&bordered_ptr->super_container); + memset(bordered_ptr, 0, sizeof(wlmtk_bordered_t)); +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Updates the layout of the bordered element. + * + * @param container_ptr + */ +void _wlmtk_bordered_container_update_layout( + wlmtk_container_t *container_ptr) +{ + wlmtk_bordered_t *bordered_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_bordered_t, super_container); + + bordered_ptr->orig_super_container_vmt.update_layout(container_ptr); + + // configure parent container. + if (NULL != container_ptr->super_element.parent_container_ptr) { + wlmtk_container_update_layout( + container_ptr->super_element.parent_container_ptr); + } +} + +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_bordered_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 0, NULL, NULL } +}; + +/** Style used for tests. */ +static const wlmtk_margin_style_t test_style = { + .width = 2, + .color = 0xff000000 +}; + +/* ------------------------------------------------------------------------- */ +/** Exercises setup and teardown. */ +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_fake_element_t *fe_ptr = wlmtk_fake_element_create(); + + wlmtk_bordered_t bordered; + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_bordered_init( + &bordered, NULL, &fe_ptr->element, &test_style)); + wlmtk_bordered_fini(&bordered); + + wlmtk_element_destroy(&fe_ptr->element); +} + + +/* == End of bordered.c ==================================================== */ diff --git a/src/toolkit/bordered.h b/src/toolkit/bordered.h new file mode 100644 index 00000000..5bb740de --- /dev/null +++ b/src/toolkit/bordered.h @@ -0,0 +1,76 @@ +/* ========================================================================= */ +/** + * @file bordered.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_BORDERED_H__ +#define __WLMTK_BORDERED_H__ + +#include "container.h" +#include "style.h" + +/** Forward declaration: Bordered container state. */ +typedef struct _wlmtk_bordered_t wlmtk_bordered_t; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** State of the bordered container. */ +struct _wlmtk_bordered_t { + /** Super class of the bordered. */ + wlmtk_container_t super_container; + /** Virtual method table of the super container before extending it. */ + wlmtk_container_vmt_t orig_super_container_vmt; + + /** Points to the element that will be enclosed by the border. */ + wlmtk_element_t *element_ptr; + /** Style of the border. */ + wlmtk_margin_style_t style; +}; + +/** + * Initializes the bordered element. + * + * @param bordered_ptr + * @param env_ptr + * @param element_ptr + * @param style_ptr + * + * @return true on success. + */ +bool wlmtk_bordered_init(wlmtk_bordered_t *bordered_ptr, + wlmtk_env_t *env_ptr, + wlmtk_element_t *element_ptr, + const wlmtk_margin_style_t *style_ptr); + +/** + * Un-initializes the bordered element. + * + * @param bordered_ptr + */ +void wlmtk_bordered_fini(wlmtk_bordered_t *bordered_ptr); + +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_bordered_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_BORDERED_H__ */ +/* == End of bordered.h ==================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index b0b78fb7..f4d301a6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -30,6 +30,7 @@ #include #include +#include "bordered.h" #include "box.h" #include "buffer.h" #include "button.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 7aa26ac0..9ce37d5b 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -22,6 +22,7 @@ /** Toolkit unit tests. */ const bs_test_set_t toolkit_tests[] = { + { 1, "bordered", wlmtk_bordered_test_cases }, { 1, "box", wlmtk_box_test_cases }, { 1, "button", wlmtk_button_test_cases }, { 1, "container", wlmtk_container_test_cases }, From 4a62dc8633282be76ff023828753e1e4bcfc5a9b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 6 Dec 2023 21:05:48 +0100 Subject: [PATCH 283/390] Positions the border elements of wlmtk_bordered_t appropriately. --- src/toolkit/bordered.c | 175 +++++++++++++++++++++++++++++++++++++++++ src/toolkit/bordered.h | 10 +++ 2 files changed, 185 insertions(+) diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c index 99d1bfb4..d16f9c85 100644 --- a/src/toolkit/bordered.c +++ b/src/toolkit/bordered.c @@ -25,6 +25,14 @@ static void _wlmtk_bordered_container_update_layout( wlmtk_container_t *container_ptr); +static wlmtk_rectangle_t * _wlmtk_bordered_create_border_rectangle( + wlmtk_bordered_t *bordered_ptr, + wlmtk_env_t *env_ptr); +static void _wlmtk_bordered_destroy_border_rectangle( + wlmtk_bordered_t *bordered_ptr, + wlmtk_rectangle_t **rectangle_ptr_ptr); +static void _wlmtk_bordered_set_positions(wlmtk_bordered_t *bordered_ptr); + /* == Data ================================================================= */ /** Virtual method table: @ref wlmtk_container_t at @ref wlmtk_bordered_t. */ @@ -53,12 +61,38 @@ bool wlmtk_bordered_init(wlmtk_bordered_t *bordered_ptr, wlmtk_container_add_element(&bordered_ptr->super_container, bordered_ptr->element_ptr); + bordered_ptr->northern_border_rectangle_ptr = + _wlmtk_bordered_create_border_rectangle(bordered_ptr, env_ptr); + bordered_ptr->eastern_border_rectangle_ptr = + _wlmtk_bordered_create_border_rectangle(bordered_ptr, env_ptr); + bordered_ptr->southern_border_rectangle_ptr = + _wlmtk_bordered_create_border_rectangle(bordered_ptr, env_ptr); + bordered_ptr->western_border_rectangle_ptr = + _wlmtk_bordered_create_border_rectangle(bordered_ptr, env_ptr); + if (NULL == bordered_ptr->northern_border_rectangle_ptr || + NULL == bordered_ptr->eastern_border_rectangle_ptr || + NULL == bordered_ptr->southern_border_rectangle_ptr || + NULL == bordered_ptr->western_border_rectangle_ptr) { + wlmtk_bordered_fini(bordered_ptr); + return false; + } + + _wlmtk_bordered_set_positions(bordered_ptr); return true; } /* ------------------------------------------------------------------------- */ void wlmtk_bordered_fini(wlmtk_bordered_t *bordered_ptr) { + _wlmtk_bordered_destroy_border_rectangle( + bordered_ptr, &bordered_ptr->western_border_rectangle_ptr); + _wlmtk_bordered_destroy_border_rectangle( + bordered_ptr, &bordered_ptr->southern_border_rectangle_ptr); + _wlmtk_bordered_destroy_border_rectangle( + bordered_ptr, &bordered_ptr->eastern_border_rectangle_ptr); + _wlmtk_bordered_destroy_border_rectangle( + bordered_ptr, &bordered_ptr->northern_border_rectangle_ptr); + wlmtk_container_remove_element(&bordered_ptr->super_container, bordered_ptr->element_ptr); wlmtk_container_fini(&bordered_ptr->super_container); @@ -79,6 +113,8 @@ void _wlmtk_bordered_container_update_layout( wlmtk_bordered_t *bordered_ptr = BS_CONTAINER_OF( container_ptr, wlmtk_bordered_t, super_container); + _wlmtk_bordered_set_positions(bordered_ptr); + bordered_ptr->orig_super_container_vmt.update_layout(container_ptr); // configure parent container. @@ -88,6 +124,93 @@ void _wlmtk_bordered_container_update_layout( } } +/* ------------------------------------------------------------------------- */ +/** Creates a border rectangle and adds it to `bordered_ptr`. */ +wlmtk_rectangle_t * _wlmtk_bordered_create_border_rectangle( + wlmtk_bordered_t *bordered_ptr, + wlmtk_env_t *env_ptr) +{ + wlmtk_rectangle_t *rectangle_ptr = wlmtk_rectangle_create( + env_ptr, 0, 0, bordered_ptr->style.color); + if (NULL == rectangle_ptr) return NULL; + + wlmtk_element_set_visible(wlmtk_rectangle_element(rectangle_ptr), true); + wlmtk_container_add_element( + &bordered_ptr->super_container, + wlmtk_rectangle_element(rectangle_ptr)); + + return rectangle_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** Removes the rectangle from `bordered_ptr`, destroys it and NULLs it. */ +void _wlmtk_bordered_destroy_border_rectangle( + wlmtk_bordered_t *bordered_ptr, + wlmtk_rectangle_t **rectangle_ptr_ptr) +{ + if (NULL == *rectangle_ptr_ptr) return; + + wlmtk_container_remove_element( + &bordered_ptr->super_container, + wlmtk_rectangle_element(*rectangle_ptr_ptr)); + wlmtk_rectangle_destroy(*rectangle_ptr_ptr); + *rectangle_ptr_ptr = NULL; +} + +/* ------------------------------------------------------------------------- */ +/** + * Updates the position of all 4 border elements. + * + * Retrieves the position and dimensions of @ref wlmtk_bordered_t::element_ptr + * and arranges the 4 border elements around it. + * + * @param bordered_ptr + */ +void _wlmtk_bordered_set_positions(wlmtk_bordered_t *bordered_ptr) +{ + int x1, y1, x2, y2; + int x_pos, y_pos; + + if (NULL == bordered_ptr->western_border_rectangle_ptr) return; + + wlmtk_element_get_position(bordered_ptr->element_ptr, &x_pos, &y_pos); + wlmtk_element_get_dimensions( + bordered_ptr->element_ptr, &x1, &y1, &x2, &y2); + x_pos -= x1; + y_pos -= y1; + int width = x2 - x1; + int height = y2 - y1; + int margin = bordered_ptr->style.width; + + wlmtk_element_set_position( + wlmtk_rectangle_element(bordered_ptr->northern_border_rectangle_ptr), + x_pos - margin, y_pos - margin); + wlmtk_rectangle_set_size( + bordered_ptr->northern_border_rectangle_ptr, + width + 2 * margin, margin); + + wlmtk_element_set_position( + wlmtk_rectangle_element(bordered_ptr->eastern_border_rectangle_ptr), + x_pos + width, y_pos); + wlmtk_rectangle_set_size( + bordered_ptr->eastern_border_rectangle_ptr, + margin, height); + + wlmtk_element_set_position( + wlmtk_rectangle_element(bordered_ptr->southern_border_rectangle_ptr), + x_pos - margin, y_pos + height); + wlmtk_rectangle_set_size( + bordered_ptr->southern_border_rectangle_ptr, + width + 2 * margin, margin); + + wlmtk_element_set_position( + wlmtk_rectangle_element(bordered_ptr->western_border_rectangle_ptr), + x_pos - margin, y_pos); + wlmtk_rectangle_set_size( + bordered_ptr->western_border_rectangle_ptr, + margin, height); +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); @@ -103,15 +226,67 @@ static const wlmtk_margin_style_t test_style = { .color = 0xff000000 }; +/** Helper: Tests that the rectangle is positioned as specified. */ +void test_rectangle_pos(bs_test_t *test_ptr, wlmtk_rectangle_t *rect_ptr, + int x, int y, int width, int height) +{ + wlmtk_element_t *elem_ptr = wlmtk_rectangle_element(rect_ptr); + BS_TEST_VERIFY_EQ(test_ptr, x, elem_ptr->x); + BS_TEST_VERIFY_EQ(test_ptr, y, elem_ptr->y); + + int x1, y1, x2, y2; + wlmtk_element_get_dimensions(elem_ptr, &x1, &y1, &x2, &y2); + BS_TEST_VERIFY_EQ(test_ptr, 0, x1); + BS_TEST_VERIFY_EQ(test_ptr, 0, y1); + BS_TEST_VERIFY_EQ(test_ptr, width, x2 - x1); + BS_TEST_VERIFY_EQ(test_ptr, height, y2 - y1); +} + + /* ------------------------------------------------------------------------- */ /** Exercises setup and teardown. */ void test_init_fini(bs_test_t *test_ptr) { wlmtk_fake_element_t *fe_ptr = wlmtk_fake_element_create(); + fe_ptr->width = 100; + fe_ptr->height = 20; + wlmtk_element_set_position(&fe_ptr->element, -10, -4); wlmtk_bordered_t bordered; BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_bordered_init( &bordered, NULL, &fe_ptr->element, &test_style)); + + // Positions of border elements. + test_rectangle_pos( + test_ptr, bordered.northern_border_rectangle_ptr, + -12, -6, 104, 2); + test_rectangle_pos( + test_ptr, bordered.eastern_border_rectangle_ptr, + 90, -4, 2, 20); + test_rectangle_pos( + test_ptr, bordered.southern_border_rectangle_ptr, + -12, 16, 104, 2); + test_rectangle_pos( + test_ptr, bordered.western_border_rectangle_ptr, + -12, -4, 2, 20); + + // Update layout, test updated positions. + fe_ptr->width = 200; + fe_ptr->height = 120; + wlmtk_container_update_layout(&bordered.super_container); + test_rectangle_pos( + test_ptr, bordered.northern_border_rectangle_ptr, + -12, -6, 204, 2); + test_rectangle_pos( + test_ptr, bordered.eastern_border_rectangle_ptr, + 190, -4, 2, 120); + test_rectangle_pos( + test_ptr, bordered.southern_border_rectangle_ptr, + -12, 116, 204, 2); + test_rectangle_pos( + test_ptr, bordered.western_border_rectangle_ptr, + -12, -4, 2, 120); + wlmtk_bordered_fini(&bordered); wlmtk_element_destroy(&fe_ptr->element); diff --git a/src/toolkit/bordered.h b/src/toolkit/bordered.h index 5bb740de..84272b3e 100644 --- a/src/toolkit/bordered.h +++ b/src/toolkit/bordered.h @@ -21,6 +21,7 @@ #define __WLMTK_BORDERED_H__ #include "container.h" +#include "rectangle.h" #include "style.h" /** Forward declaration: Bordered container state. */ @@ -41,6 +42,15 @@ struct _wlmtk_bordered_t { wlmtk_element_t *element_ptr; /** Style of the border. */ wlmtk_margin_style_t style; + + /** Border element at the northern side. Includes east + west corners. */ + wlmtk_rectangle_t *northern_border_rectangle_ptr; + /** Border element at the eastern side. */ + wlmtk_rectangle_t *eastern_border_rectangle_ptr; + /** Border element at the southern side. Includes east + west corners. */ + wlmtk_rectangle_t *southern_border_rectangle_ptr; + /** Border element at the western side. */ + wlmtk_rectangle_t *western_border_rectangle_ptr; }; /** From 80f9481c0d448869af0b4e750c3ace06d85dadea Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 6 Dec 2023 21:15:18 +0100 Subject: [PATCH 284/390] Changes window to use wlmtk_bordered_t, and configure it to have a border. --- src/toolkit/window.c | 65 ++++++++++++++++++++++++++++++-------------- src/toolkit/window.h | 8 ++++-- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 25f3ae87..4a845b24 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -20,6 +20,7 @@ #include "window.h" +#include "rectangle.h" #include "workspace.h" /* == Declarations ========================================================= */ @@ -163,6 +164,12 @@ static const wlmtk_margin_style_t margin_style = { .color = 0xff000000, }; +/** Style of the border around the window. */ +static const wlmtk_margin_style_t border_style = { + .width = 1, + .color = 0xff000000, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -199,17 +206,28 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, &window_ptr->pre_allocated_updates[i].dlnode); } - if (!wlmtk_box_init(&window_ptr->super_box, env_ptr, + if (!wlmtk_box_init(&window_ptr->box, env_ptr, WLMTK_BOX_VERTICAL, &margin_style)) { wlmtk_window_fini(window_ptr); return false; } + wlmtk_element_set_visible( + &window_ptr->box.super_container.super_element, true); + + if (!wlmtk_bordered_init(&window_ptr->super_bordered, + env_ptr, + &window_ptr->box.super_container.super_element, + &border_style)) { + wlmtk_window_fini(window_ptr); + return false; + } + window_ptr->orig_super_element_vmt = wlmtk_element_extend( - &window_ptr->super_box.super_container.super_element, + &window_ptr->super_bordered.super_container.super_element, &window_element_vmt); window_ptr->orig_super_container_vmt = wlmtk_container_extend( - &window_ptr->super_box.super_container, &window_container_vmt); + &window_ptr->super_bordered.super_container, &window_container_vmt); wlmtk_window_set_title(window_ptr, NULL); @@ -220,13 +238,13 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, return false; } wlmtk_box_add_element_front( - &window_ptr->super_box, + &window_ptr->box, wlmtk_resizebar_element(window_ptr->resizebar_ptr)); wlmtk_element_set_visible( wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); wlmtk_box_add_element_front( - &window_ptr->super_box, + &window_ptr->box, wlmtk_content_element(content_ptr)); window_ptr->content_ptr = content_ptr; wlmtk_content_set_window(content_ptr, window_ptr); @@ -239,11 +257,15 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, return false; } wlmtk_box_add_element_front( - &window_ptr->super_box, + &window_ptr->box, wlmtk_titlebar_element(window_ptr->titlebar_ptr)); wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + wlmtk_rectangle_t *rect_ptr = wlmtk_rectangle_create( + env_ptr, 100, 50, 0xff406080); + wlmtk_element_set_visible(wlmtk_rectangle_element(rect_ptr), true); + return true; } @@ -257,7 +279,7 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) { if (NULL != window_ptr->titlebar_ptr) { wlmtk_box_remove_element( - &window_ptr->super_box, + &window_ptr->box, wlmtk_titlebar_element(window_ptr->titlebar_ptr)); wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); window_ptr->titlebar_ptr = NULL; @@ -265,7 +287,7 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) if (NULL != window_ptr->resizebar_ptr) { wlmtk_box_remove_element( - &window_ptr->super_box, + &window_ptr->box, wlmtk_resizebar_element(window_ptr->resizebar_ptr)); wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); window_ptr->resizebar_ptr = NULL; @@ -273,7 +295,7 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) if (NULL != window_ptr->content_ptr) { wlmtk_box_remove_element( - &window_ptr->super_box, + &window_ptr->box, wlmtk_content_element(window_ptr->content_ptr)); wlmtk_element_set_visible( wlmtk_content_element(window_ptr->content_ptr), false); @@ -288,7 +310,8 @@ void wlmtk_window_fini(wlmtk_window_t *window_ptr) window_ptr->title_ptr = NULL; } - wlmtk_box_fini(&window_ptr->super_box); + wlmtk_bordered_fini(&window_ptr->super_bordered); + wlmtk_box_fini(&window_ptr->box); } /* ------------------------------------------------------------------------- */ @@ -318,7 +341,7 @@ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) { - return &window_ptr->super_box.super_container.super_element; + return &window_ptr->super_bordered.super_container.super_element; } /* ------------------------------------------------------------------------- */ @@ -326,10 +349,10 @@ wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) { // DEBT: FIXME - The assertion here is too lose. wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_window_t, super_box.super_container.super_element); + element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); BS_ASSERT(_wlmtk_box_update_layout == - window_ptr->super_box.super_container.vmt.update_layout); + window_ptr->super_bordered.super_container.vmt.update_layout); return window_ptr; } @@ -514,14 +537,14 @@ bool _wlmtk_window_element_pointer_button( const wlmtk_button_event_t *button_event_ptr) { wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_window_t, super_box.super_container.super_element); + element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); // We shouldn't receive buttons when not mapped. BS_ASSERT( NULL != - window_ptr->super_box.super_container.super_element.parent_container_ptr); + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_box.super_container.super_element.parent_container_ptr); + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); wlmtk_workspace_activate_window(workspace_ptr, window_ptr); wlmtk_workspace_raise_window(workspace_ptr, window_ptr); @@ -572,9 +595,9 @@ void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) { BS_ASSERT( NULL != - window_ptr->super_box.super_container.super_element.parent_container_ptr); + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_box.super_container.super_element.parent_container_ptr); + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); } @@ -584,9 +607,9 @@ void wlmtk_window_request_resize_impl(wlmtk_window_t *window_ptr, uint32_t edges { BS_ASSERT( NULL != - window_ptr->super_box.super_container.super_element.parent_container_ptr); + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_box.super_container.super_element.parent_container_ptr); + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); } @@ -688,7 +711,7 @@ void release_update( void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr) { wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_window_t, super_box.super_container); + container_ptr, wlmtk_window_t, super_bordered.super_container); window_ptr->orig_super_container_vmt.update_layout(container_ptr); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 48619015..5bcfc4bf 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -23,6 +23,7 @@ /** Forward declaration: Window. */ typedef struct _wlmtk_window_t wlmtk_window_t; +#include "bordered.h" #include "box.h" #include "content.h" #include "element.h" @@ -85,8 +86,8 @@ typedef struct { /** State of the window. */ struct _wlmtk_window_t { - /** Superclass: Box. */ - wlmtk_box_t super_box; + /** Superclass: Bordered. */ + wlmtk_bordered_t super_bordered; /** Original virtual method table of the window's element superclass. */ wlmtk_element_vmt_t orig_super_element_vmt; /** Original virtual method table of the window' container superclass. */ @@ -95,6 +96,9 @@ struct _wlmtk_window_t { /** Virtual method table. */ wlmtk_window_impl_t impl; + /** Box: In `super_bordered`, holds tontent, title bar and resizebar. */ + wlmtk_box_t box; + /** Content of this window. */ wlmtk_content_t *content_ptr; /** Titlebar. */ From c835acf57101ae88cc9ad5df6b24e52c8d12a9d2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 6 Dec 2023 21:16:16 +0100 Subject: [PATCH 285/390] Removes an obsolete testing rectangle, fixing a test leak. --- src/toolkit/window.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 4a845b24..af7ad071 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -262,10 +262,6 @@ bool wlmtk_window_init(wlmtk_window_t *window_ptr, wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - wlmtk_rectangle_t *rect_ptr = wlmtk_rectangle_create( - env_ptr, 100, 50, 0xff406080); - wlmtk_element_set_visible(wlmtk_rectangle_element(rect_ptr), true); - return true; } From a3721a516a73db7d70613aa62f9af3f234db8b72 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 8 Dec 2023 16:51:39 +0100 Subject: [PATCH 286/390] Applies virtual method table pattern to wlmtk_window_t. --- src/toolkit/window.c | 393 +++++++++++++++++++++++-------------------- src/toolkit/window.h | 33 ++-- 2 files changed, 220 insertions(+), 206 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index af7ad071..54fb73ab 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -26,56 +26,46 @@ /* == Declarations ========================================================= */ bool wlmtk_window_init(wlmtk_window_t *window_ptr, - const wlmtk_window_impl_t *impl_ptr, wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr); void wlmtk_window_fini(wlmtk_window_t *window_ptr); -static bool _wlmtk_window_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); +static wlmtk_window_vmt_t _wlmtk_window_extend( + wlmtk_window_t *window_ptr, + const wlmtk_window_vmt_t *window_vmt_ptr); - static void wlmtk_window_set_activated_impl( +static void _wlmtk_window_destroy(wlmtk_window_t *window_ptr); +static void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated); -static void wlmtk_window_set_server_side_decorated_impl( - wlmtk_window_t *window_ptr, - bool decorated); -static void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr); -static void wlmtk_window_request_minimize_impl(wlmtk_window_t *window_ptr); -static void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr); -static void wlmtk_window_request_resize_impl( +static void _wlmtk_window_request_close(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_move(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_resize( wlmtk_window_t *window_ptr, uint32_t edges); -static void wlmtk_window_request_size_impl( - wlmtk_window_t *window_ptr, - int width, - int height); -static void wlmtk_window_request_position_and_size_impl( +static void _wlmtk_window_request_position_and_size( wlmtk_window_t *window_ptr, int x, int y, int width, int height); -static void fake_window_destroy(wlmtk_window_t *window_ptr); -static void fake_window_set_activated( + +static bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); + +static void _wlmtk_fake_window_set_activated( wlmtk_window_t *window_ptr, bool activated); -static void fake_window_set_server_side_decorated( - wlmtk_window_t *window_ptr, - bool decorated); -static void fake_window_request_close(wlmtk_window_t *window_ptr); -static void fake_window_request_minimize(wlmtk_window_t *window_ptr); -static void fake_window_request_move(wlmtk_window_t *window_ptr); -static void fake_window_request_resize( +static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_resize( wlmtk_window_t *window_ptr, uint32_t edges); -static void fake_window_request_size( - wlmtk_window_t *window_ptr, - int width, - int height); -static void fake_window_request_position_and_size( +static void _wlmtk_fake_window_request_position_and_size( wlmtk_window_t *window_ptr, int x, int y, @@ -100,31 +90,16 @@ static const wlmtk_element_vmt_t window_element_vmt = { static const wlmtk_container_vmt_t window_container_vmt = { .update_layout = _wlmtk_box_update_layout, }; - -/** Default methods of @ref wlmtk_window_t. To override for a mock. */ -static const wlmtk_window_impl_t window_default_impl = { - .destroy = wlmtk_window_destroy, - .set_activated = wlmtk_window_set_activated_impl, - .set_server_side_decorated = wlmtk_window_set_server_side_decorated_impl, - .request_close = wlmtk_window_request_close_impl, - .request_minimize = wlmtk_window_request_minimize_impl, - .request_move = wlmtk_window_request_move_impl, - .request_resize = wlmtk_window_request_resize_impl, - .request_size = wlmtk_window_request_size_impl, - .request_position_and_size = wlmtk_window_request_position_and_size_impl, -}; - -/** Default methods of @ref wlmtk_window_t. To override for a mock. */ -static const wlmtk_window_impl_t fake_window_impl = { - .destroy = fake_window_destroy, - .set_activated = fake_window_set_activated, - .set_server_side_decorated = fake_window_set_server_side_decorated, - .request_close = fake_window_request_close, - .request_minimize = fake_window_request_minimize, - .request_move = fake_window_request_move, - .request_resize = fake_window_request_resize, - .request_size = fake_window_request_size, - .request_position_and_size = fake_window_request_position_and_size, +/** Virtual method table for the window itself. */ +static const wlmtk_window_vmt_t _wlmtk_window_vmt = { + .destroy = _wlmtk_window_destroy, + + .set_activated = _wlmtk_window_set_activated, + .request_close = _wlmtk_window_request_close, + .request_minimize = _wlmtk_window_request_minimize, + .request_move = _wlmtk_window_request_move, + .request_resize = _wlmtk_window_request_resize, + .request_position_and_size = _wlmtk_window_request_position_and_size, }; /** Style of the title bar. */ @@ -177,29 +152,17 @@ static const wlmtk_margin_style_t border_style = { * Initializes the window. * * @param window_ptr - * @param impl_ptr * @param env_ptr * @param content_ptr Will take ownership of it. * * @return true on success. */ bool wlmtk_window_init(wlmtk_window_t *window_ptr, - const wlmtk_window_impl_t *impl_ptr, wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr) { BS_ASSERT(NULL != window_ptr); - BS_ASSERT(NULL != impl_ptr); - BS_ASSERT(NULL != impl_ptr->destroy); - BS_ASSERT(NULL != impl_ptr->set_activated); - BS_ASSERT(NULL != impl_ptr->set_server_side_decorated); - BS_ASSERT(NULL != impl_ptr->request_close); - BS_ASSERT(NULL != impl_ptr->request_minimize); - BS_ASSERT(NULL != impl_ptr->request_move); - BS_ASSERT(NULL != impl_ptr->request_resize); - BS_ASSERT(NULL != impl_ptr->request_size); - BS_ASSERT(NULL != impl_ptr->request_position_and_size); - memcpy(&window_ptr->impl, impl_ptr, sizeof(wlmtk_window_impl_t)); + memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { bs_dllist_push_back(&window_ptr->available_updates, @@ -318,8 +281,7 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!wlmtk_window_init( - window_ptr, &window_default_impl, env_ptr, content_ptr)) { + if (!wlmtk_window_init(window_ptr, env_ptr, content_ptr)) { wlmtk_window_destroy(window_ptr); return NULL; } @@ -330,8 +292,7 @@ wlmtk_window_t *wlmtk_window_create( /* ------------------------------------------------------------------------- */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { - wlmtk_window_fini(window_ptr); - free(window_ptr); + window_ptr->vmt.destroy(window_ptr); } /* ------------------------------------------------------------------------- */ @@ -393,14 +354,6 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) } } -/* ------------------------------------------------------------------------- */ -void wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated) -{ - window_ptr->impl.set_activated(window_ptr, activated); -} - /* ------------------------------------------------------------------------- */ void wlmtk_window_set_title( wlmtk_window_t *window_ptr, @@ -444,32 +397,42 @@ void wlmtk_window_set_server_side_decorated( wlmtk_window_t *window_ptr, bool decorated) { - window_ptr->impl.set_server_side_decorated(window_ptr, decorated); + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_INFO, "Set server side decoration for window %p: %d", + window_ptr, decorated); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated) +{ + window_ptr->vmt.set_activated(window_ptr, activated); } /* ------------------------------------------------------------------------- */ void wlmtk_window_request_close(wlmtk_window_t *window_ptr) { - window_ptr->impl.request_close(window_ptr); + window_ptr->vmt.request_close(window_ptr); } /* ------------------------------------------------------------------------- */ void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) { - window_ptr->impl.request_minimize(window_ptr); + window_ptr->vmt.request_minimize(window_ptr); } /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { - window_ptr->impl.request_move(window_ptr); + window_ptr->vmt.request_move(window_ptr); } /* ------------------------------------------------------------------------- */ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) { - window_ptr->impl.request_resize(window_ptr, edges); + window_ptr->vmt.request_resize(window_ptr, edges); } /* ------------------------------------------------------------------------- */ @@ -478,7 +441,15 @@ void wlmtk_window_request_size( int width, int height) { - window_ptr->impl.request_size(window_ptr, width, height); + // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. + wlmtk_content_request_size(window_ptr->content_ptr, width, height); + + // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting + // the size is an asynchronous operation and should be handled as such. + // Meaning: In example of resizing at the top-left corner, we'll want to + // request the content to adjust size, but wait with adjusting the + // content position until the size adjustment is applied. This implies we + // may need to combine the request_size and set_position methods for window. } /* ------------------------------------------------------------------------- */ @@ -489,10 +460,25 @@ void wlmtk_window_request_position_and_size( int width, int height) { - window_ptr->impl.request_position_and_size( + window_ptr->vmt.request_position_and_size( window_ptr, x, y, width, height); } +static void _wlmtk_fake_window_destroy(wlmtk_window_t *window_ptr); + +/** Virtual method table for the fake window itself. */ +static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { + .destroy = _wlmtk_fake_window_destroy, + + .set_activated = _wlmtk_fake_window_set_activated, + .request_close = _wlmtk_fake_window_request_close, + .request_minimize = _wlmtk_fake_window_request_minimize, + .request_move = _wlmtk_fake_window_request_move, + .request_resize = _wlmtk_fake_window_request_resize, + .request_position_and_size = _wlmtk_fake_window_request_position_and_size, + +}; + /* ------------------------------------------------------------------------- */ wlmtk_fake_window_t *wlmtk_fake_window_create(void) { @@ -507,12 +493,13 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) } if (!wlmtk_window_init(&fake_window_ptr->window, - &fake_window_impl, NULL, &fake_window_ptr->fake_content_ptr->content)) { wlmtk_fake_window_destroy(fake_window_ptr); return NULL; } + // Extend. We don't save the VMT, since it's for fake only. + _wlmtk_window_extend(&fake_window_ptr->window, &_wlmtk_fake_window_vmt); return fake_window_ptr; } @@ -524,33 +511,68 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) free(fake_window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Virtual dtor, extended wlmtk_window_vmt_t::destroy. */ +void _wlmtk_fake_window_destroy(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_t, window); + wlmtk_fake_window_destroy(fake_window_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -/** Activates window on button press, and calls the parent's implementation. */ -bool _wlmtk_window_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr) +/** + * Extends the window's virtual methods. + * + * @param window_ptr + * @param window_vmt_ptr + * + * @return The previous virtual method table. + */ +wlmtk_window_vmt_t _wlmtk_window_extend( + wlmtk_window_t *window_ptr, + const wlmtk_window_vmt_t *window_vmt_ptr) { - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); + wlmtk_window_vmt_t orig_vmt = window_ptr->vmt; - // We shouldn't receive buttons when not mapped. - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_activate_window(workspace_ptr, window_ptr); - wlmtk_workspace_raise_window(workspace_ptr, window_ptr); + if (NULL != window_vmt_ptr->destroy) { + window_ptr->vmt.destroy = window_vmt_ptr->destroy; + } + if (NULL != window_vmt_ptr->set_activated) { + window_ptr->vmt.set_activated = window_vmt_ptr->set_activated; + } + if (NULL != window_vmt_ptr->request_close) { + window_ptr->vmt.request_close = window_vmt_ptr->request_close; + } + if (NULL != window_vmt_ptr->request_minimize) { + window_ptr->vmt.request_minimize = window_vmt_ptr->request_minimize; + } + if (NULL != window_vmt_ptr->request_move) { + window_ptr->vmt.request_move = window_vmt_ptr->request_move; + } + if (NULL != window_vmt_ptr->request_resize) { + window_ptr->vmt.request_resize = window_vmt_ptr->request_resize; + } + if (NULL != window_vmt_ptr->request_position_and_size) { + window_ptr->vmt.request_position_and_size = window_vmt_ptr->request_position_and_size; + } - return window_ptr->orig_super_element_vmt.pointer_button( - element_ptr, button_event_ptr); + return orig_vmt; +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of dtor. */ +void _wlmtk_window_destroy(wlmtk_window_t *window_ptr) +{ + wlmtk_window_fini(window_ptr); + free(window_ptr); } /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_set_activated. */ -void wlmtk_window_set_activated_impl( +void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { @@ -561,33 +583,22 @@ void wlmtk_window_set_activated_impl( } /* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_set_server_side_decorated. */ -void wlmtk_window_set_server_side_decorated_impl( - wlmtk_window_t *window_ptr, - bool decorated) -{ - // TODO(kaeser@gubbe.ch): Implement. - bs_log(BS_INFO, "Set server side decoration for window %p: %d", - window_ptr, decorated); -} - -/* ------------------------------------------------------------------------- */ -/** Implements @ref wlmtk_window_request_close. Requests content closure. */ -void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr) +/** Default implementation of @ref wlmtk_window_request_close. */ +void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) { wlmtk_content_request_close(window_ptr->content_ptr); } /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_minimize. */ -void wlmtk_window_request_minimize_impl(wlmtk_window_t *window_ptr) +void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) { bs_log(BS_INFO, "Requesting window %p to minimize.", window_ptr); } /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_move. */ -void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) +void _wlmtk_window_request_move(wlmtk_window_t *window_ptr) { BS_ASSERT( NULL != @@ -599,7 +610,7 @@ void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_resize. */ -void wlmtk_window_request_resize_impl(wlmtk_window_t *window_ptr, uint32_t edges) +void _wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) { BS_ASSERT( NULL != @@ -609,27 +620,9 @@ void wlmtk_window_request_resize_impl(wlmtk_window_t *window_ptr, uint32_t edges wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); } -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_size. */ -void wlmtk_window_request_size_impl( - wlmtk_window_t *window_ptr, - int width, - int height) -{ - // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_content_request_size(window_ptr->content_ptr, width, height); - - // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting - // the size is an asynchronous operation and should be handled as such. - // Meaning: In example of resizing at the top-left corner, we'll want to - // request the content to adjust size, but wait with adjusting the - // content position until the size adjustment is applied. This implies we - // may need to combine the request_size and set_position methods for window. -} - /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_position_and_size. */ -void wlmtk_window_request_position_and_size_impl( +void _wlmtk_window_request_position_and_size( wlmtk_window_t *window_ptr, int x, int y, @@ -652,6 +645,68 @@ void wlmtk_window_request_position_and_size_impl( // the pending state should be applied right away. } + + +/* ------------------------------------------------------------------------- */ +/** Activates window on button press, and calls the parent's implementation. */ +bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); + + // We shouldn't receive buttons when not mapped. + BS_ASSERT( + NULL != + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_raise_window(workspace_ptr, window_ptr); + + return window_ptr->orig_super_element_vmt.pointer_button( + element_ptr, button_event_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Implements @ref wlmtk_window_request_close. Requests content closure. */ +void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr) +{ + wlmtk_content_request_close(window_ptr->content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_minimize. */ +void wlmtk_window_request_minimize_impl(wlmtk_window_t *window_ptr) +{ + bs_log(BS_INFO, "Requesting window %p to minimize.", window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_move. */ +void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) +{ + BS_ASSERT( + NULL != + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_resize. */ +void wlmtk_window_request_resize_impl(wlmtk_window_t *window_ptr, uint32_t edges) +{ + BS_ASSERT( + NULL != + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); +} + /* ------------------------------------------------------------------------- */ /** * Prepares a positional update: Allocates an item and attach it to the end @@ -726,17 +781,8 @@ void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr) /* == Virtual method implementation for the fake window ==================== */ /* ------------------------------------------------------------------------- */ -/** Virtual dtor, wraps to @ref wlmtk_fake_window_destroy. */ -void fake_window_destroy(wlmtk_window_t *window_ptr) -{ - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - wlmtk_fake_window_destroy(fake_window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_set_activated. */ -void fake_window_set_activated( +/** Fake implementation of @ref wlmtk_window_set_activated. Records call. */ +void _wlmtk_fake_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { @@ -746,19 +792,8 @@ void fake_window_set_activated( } /* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_set_server_side_decorated. */ -void fake_window_set_server_side_decorated( - wlmtk_window_t *window_ptr, - bool decorated) -{ - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->decorated = decorated; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_close. */ -void fake_window_request_close(wlmtk_window_t *window_ptr) +/** Fake implementation of @ref wlmtk_window_request_close. Records call. */ +void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr) { wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( window_ptr, wlmtk_fake_window_t, window); @@ -766,8 +801,8 @@ void fake_window_request_close(wlmtk_window_t *window_ptr) } /* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_minimize. */ -void fake_window_request_minimize(wlmtk_window_t *window_ptr) +/** Fake implementation of @ref wlmtk_window_request_minimize. Records call. */ +void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr) { wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( window_ptr, wlmtk_fake_window_t, window); @@ -775,8 +810,8 @@ void fake_window_request_minimize(wlmtk_window_t *window_ptr) } /* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_move. */ -void fake_window_request_move(wlmtk_window_t *window_ptr) +/** Fake implementation of @ref wlmtk_window_request_move. Records call */ +void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr) { wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( window_ptr, wlmtk_fake_window_t, window); @@ -784,8 +819,8 @@ void fake_window_request_move(wlmtk_window_t *window_ptr) } /* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_resize. */ -void fake_window_request_resize( +/** Fake implementation of @ref wlmtk_window_request_resize. Records call. */ +void _wlmtk_fake_window_request_resize( wlmtk_window_t *window_ptr, uint32_t edges) { @@ -795,23 +830,9 @@ void fake_window_request_resize( fake_window_ptr->request_resize_edges = edges; } -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_size. */ -void fake_window_request_size( - wlmtk_window_t *window_ptr, - int width, - int height) -{ - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->request_size_called = true; - fake_window_ptr->width = width; - fake_window_ptr->height = height; -} - /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_position_and_size. */ -void fake_window_request_position_and_size( +void _wlmtk_fake_window_request_position_and_size( wlmtk_window_t *window_ptr, int x, int y, diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 5bcfc4bf..7a3c3032 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -22,6 +22,8 @@ /** Forward declaration: Window. */ typedef struct _wlmtk_window_t wlmtk_window_t; +/** Forward declaration: Virtual method table. */ +typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; #include "bordered.h" #include "box.h" @@ -53,36 +55,26 @@ typedef struct { unsigned height; } wlmtk_pending_update_t; -/** Virtual method table for @ref wlmtk_window_t. */ -typedef struct { +/** Virtual method table for the window. */ +struct _wlmtk_window_vmt_t { /** Destructor. */ void (*destroy)(wlmtk_window_t *window_ptr); - /** See @ref wlmtk_window_set_activated. */ + /** Virtual method for @ref wlmtk_window_set_activated. */ void (*set_activated)(wlmtk_window_t *window_ptr, bool activated); - /** See @ref wlmtk_window_set_server_side_decorated. */ - void (*set_server_side_decorated)(wlmtk_window_t *window_ptr, - bool decorated); - /** See @ref wlmtk_window_set_title. */ - void (*set_title)(wlmtk_window_t *window_ptr, const char *title_ptr); - - /** See @ref wlmtk_window_request_close. */ + /** Virtual method for @ref wlmtk_window_request_close. */ void (*request_close)(wlmtk_window_t *window_ptr); - /** See @ref wlmtk_window_request_minimize. */ + /** Virtual method for @ref wlmtk_window_request_minimize. */ void (*request_minimize)(wlmtk_window_t *window_ptr); - /** See @ref wlmtk_window_request_move. */ + /** Virtual method for @ref wlmtk_window_request_move. */ void (*request_move)(wlmtk_window_t *window_ptr); - /** See @ref wlmtk_window_request_resize. */ + /** Virtual method for @ref wlmtk_window_request_resize. */ void (*request_resize)(wlmtk_window_t *window_ptr, uint32_t edges); - - /** See @ref wlmtk_window_request_size. */ - void (*request_size)(wlmtk_window_t *window_ptr, - int x, int y); - /** See @ref wlmtk_window_request_position_and_size. */ + /** Virtual method for @ref wlmtk_window_request_position_and_size. */ void (*request_position_and_size)(wlmtk_window_t *window_ptr, int x, int y, int width, int height); -} wlmtk_window_impl_t; +}; /** State of the window. */ struct _wlmtk_window_t { @@ -94,7 +86,7 @@ struct _wlmtk_window_t { wlmtk_container_vmt_t orig_super_container_vmt; /** Virtual method table. */ - wlmtk_window_impl_t impl; + wlmtk_window_vmt_t vmt; /** Box: In `super_bordered`, holds tontent, title bar and resizebar. */ wlmtk_box_t box; @@ -307,6 +299,7 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); typedef struct { /** Window state. */ wlmtk_window_t window; + /** Argument to last @ref wlmtk_window_set_activated call. */ bool activated; /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ From 58b6c169c1d561d380a6ee3c3823dd2220a9a7e1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 10:40:55 +0100 Subject: [PATCH 287/390] Makes fake window clients rely on pointer. --- src/toolkit/resizebar.c | 4 +- src/toolkit/resizebar_area.c | 2 +- src/toolkit/titlebar.c | 4 +- src/toolkit/titlebar_button.c | 2 +- src/toolkit/titlebar_title.c | 2 +- src/toolkit/window.c | 302 ++++++++++++++++------------------ src/toolkit/window.h | 19 ++- 7 files changed, 158 insertions(+), 177 deletions(-) diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index d033d896..9fd33388 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -274,7 +274,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = {}; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, &fake_window_ptr->window, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); @@ -289,7 +289,7 @@ void test_variable_width(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, &fake_window_ptr->window, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index f90bfb33..87cb1295 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -316,7 +316,7 @@ void test_area(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( - &fake_window_ptr->window, NULL, WLR_EDGE_BOTTOM); + fake_window_ptr->window_ptr, NULL, WLR_EDGE_BOTTOM); BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index ffaefbfc..f34b20d9 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -387,7 +387,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = {}; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - NULL, &fake_window_ptr->window, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); @@ -401,7 +401,7 @@ void test_variable_width(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = { .height = 22, .margin_style = { .width = 2 } }; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - NULL, &fake_window_ptr->window, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); // Short names, for improved readability. diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 4c66ef05..c70ba9dd 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -278,7 +278,7 @@ void test_button(bs_test_t *test_ptr) wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( NULL, wlmtk_window_request_close, - &fake_window_ptr->window, + fake_window_ptr->window_ptr, wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); wlmtk_titlebar_button_set_activated(button_ptr, true); diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index 54c6057d..4ebe4418 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -284,7 +284,7 @@ void test_title(bs_test_t *test_ptr) wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( - NULL, &fake_window_ptr->window); + NULL, fake_window_ptr->window_ptr); wlmtk_element_t *element_ptr = wlmtk_titlebar_title_element( titlebar_title_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 54fb73ab..d9a8e0bd 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -25,16 +25,16 @@ /* == Declarations ========================================================= */ -bool wlmtk_window_init(wlmtk_window_t *window_ptr, - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); -void wlmtk_window_fini(wlmtk_window_t *window_ptr); +static bool _wlmtk_window_init( + wlmtk_window_t *window_ptr, + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr); +static void _wlmtk_window_fini(wlmtk_window_t *window_ptr); static wlmtk_window_vmt_t _wlmtk_window_extend( wlmtk_window_t *window_ptr, const wlmtk_window_vmt_t *window_vmt_ptr); -static void _wlmtk_window_destroy(wlmtk_window_t *window_ptr); static void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated); @@ -92,8 +92,6 @@ static const wlmtk_container_vmt_t window_container_vmt = { }; /** Virtual method table for the window itself. */ static const wlmtk_window_vmt_t _wlmtk_window_vmt = { - .destroy = _wlmtk_window_destroy, - .set_activated = _wlmtk_window_set_activated, .request_close = _wlmtk_window_request_close, .request_minimize = _wlmtk_window_request_minimize, @@ -147,132 +145,6 @@ static const wlmtk_margin_style_t border_style = { /* == Exported methods ===================================================== */ -/* ------------------------------------------------------------------------- */ -/** - * Initializes the window. - * - * @param window_ptr - * @param env_ptr - * @param content_ptr Will take ownership of it. - * - * @return true on success. - */ -bool wlmtk_window_init(wlmtk_window_t *window_ptr, - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) -{ - BS_ASSERT(NULL != window_ptr); - memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); - - for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { - bs_dllist_push_back(&window_ptr->available_updates, - &window_ptr->pre_allocated_updates[i].dlnode); - } - - if (!wlmtk_box_init(&window_ptr->box, env_ptr, - WLMTK_BOX_VERTICAL, - &margin_style)) { - wlmtk_window_fini(window_ptr); - return false; - } - wlmtk_element_set_visible( - &window_ptr->box.super_container.super_element, true); - - if (!wlmtk_bordered_init(&window_ptr->super_bordered, - env_ptr, - &window_ptr->box.super_container.super_element, - &border_style)) { - wlmtk_window_fini(window_ptr); - return false; - } - - window_ptr->orig_super_element_vmt = wlmtk_element_extend( - &window_ptr->super_bordered.super_container.super_element, - &window_element_vmt); - window_ptr->orig_super_container_vmt = wlmtk_container_extend( - &window_ptr->super_bordered.super_container, &window_container_vmt); - - wlmtk_window_set_title(window_ptr, NULL); - - window_ptr->resizebar_ptr = wlmtk_resizebar_create( - env_ptr, window_ptr, &resizebar_style); - if (NULL == window_ptr->resizebar_ptr) { - wlmtk_window_fini(window_ptr); - return false; - } - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_element_set_visible( - wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_content_element(content_ptr)); - window_ptr->content_ptr = content_ptr; - wlmtk_content_set_window(content_ptr, window_ptr); - wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - - window_ptr->titlebar_ptr = wlmtk_titlebar_create( - env_ptr, window_ptr, &titlebar_style); - if (NULL == window_ptr->titlebar_ptr) { - wlmtk_window_fini(window_ptr); - return false; - } - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_element_set_visible( - wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - - return true; -} - -/* ------------------------------------------------------------------------- */ -/** - * Uninitializes the winodw. - * - * @param window_ptr - */ -void wlmtk_window_fini(wlmtk_window_t *window_ptr) -{ - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); - window_ptr->titlebar_ptr = NULL; - } - - if (NULL != window_ptr->resizebar_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); - window_ptr->resizebar_ptr = NULL; - } - - if (NULL != window_ptr->content_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_content_element(window_ptr->content_ptr)); - wlmtk_element_set_visible( - wlmtk_content_element(window_ptr->content_ptr), false); - wlmtk_content_set_window(window_ptr->content_ptr, NULL); - - wlmtk_element_destroy(wlmtk_content_element(window_ptr->content_ptr)); - window_ptr->content_ptr = NULL; - } - - if (NULL != window_ptr->title_ptr) { - free(window_ptr->title_ptr); - window_ptr->title_ptr = NULL; - } - - wlmtk_bordered_fini(&window_ptr->super_bordered); - wlmtk_box_fini(&window_ptr->box); -} - /* ------------------------------------------------------------------------- */ wlmtk_window_t *wlmtk_window_create( wlmtk_env_t *env_ptr, @@ -281,7 +153,7 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!wlmtk_window_init(window_ptr, env_ptr, content_ptr)) { + if (!_wlmtk_window_init(window_ptr, env_ptr, content_ptr)) { wlmtk_window_destroy(window_ptr); return NULL; } @@ -292,7 +164,8 @@ wlmtk_window_t *wlmtk_window_create( /* ------------------------------------------------------------------------- */ void wlmtk_window_destroy(wlmtk_window_t *window_ptr) { - window_ptr->vmt.destroy(window_ptr); + _wlmtk_window_fini(window_ptr); + free(window_ptr); } /* ------------------------------------------------------------------------- */ @@ -313,7 +186,6 @@ wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) return window_ptr; } - /* ------------------------------------------------------------------------- */ void wlmtk_window_get_size( wlmtk_window_t *window_ptr, @@ -464,12 +336,8 @@ void wlmtk_window_request_position_and_size( window_ptr, x, y, width, height); } -static void _wlmtk_fake_window_destroy(wlmtk_window_t *window_ptr); - /** Virtual method table for the fake window itself. */ static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { - .destroy = _wlmtk_fake_window_destroy, - .set_activated = _wlmtk_fake_window_set_activated, .request_close = _wlmtk_fake_window_request_close, .request_minimize = _wlmtk_fake_window_request_minimize, @@ -492,35 +360,155 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) return NULL; } - if (!wlmtk_window_init(&fake_window_ptr->window, + if (!_wlmtk_window_init(&fake_window_ptr->window, NULL, &fake_window_ptr->fake_content_ptr->content)) { wlmtk_fake_window_destroy(fake_window_ptr); return NULL; } - // Extend. We don't save the VMT, since it's for fake only. - _wlmtk_window_extend(&fake_window_ptr->window, &_wlmtk_fake_window_vmt); + fake_window_ptr->window_ptr = &fake_window_ptr->window; + // Extend. We don't save the VMT, since it's for fake only. + _wlmtk_window_extend(fake_window_ptr->window_ptr, + &_wlmtk_fake_window_vmt); return fake_window_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) { - wlmtk_window_fini(&fake_window_ptr->window); + _wlmtk_window_fini(&fake_window_ptr->window); free(fake_window_ptr); } +/* == Local (static) methods =============================================== */ + /* ------------------------------------------------------------------------- */ -/** Virtual dtor, extended wlmtk_window_vmt_t::destroy. */ -void _wlmtk_fake_window_destroy(wlmtk_window_t *window_ptr) +/** + * Initializes an (allocated) window. + * + * @param window_ptr + * @param env_ptr + * @param content_ptr + * + * @return true on success. + */ +bool _wlmtk_window_init( + wlmtk_window_t *window_ptr, + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - wlmtk_fake_window_destroy(fake_window_ptr); + BS_ASSERT(NULL != window_ptr); + memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); + + for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { + bs_dllist_push_back(&window_ptr->available_updates, + &window_ptr->pre_allocated_updates[i].dlnode); + } + + if (!wlmtk_box_init(&window_ptr->box, env_ptr, + WLMTK_BOX_VERTICAL, + &margin_style)) { + _wlmtk_window_fini(window_ptr); + return false; + } + wlmtk_element_set_visible( + &window_ptr->box.super_container.super_element, true); + + if (!wlmtk_bordered_init(&window_ptr->super_bordered, + env_ptr, + &window_ptr->box.super_container.super_element, + &border_style)) { + _wlmtk_window_fini(window_ptr); + return false; + } + + window_ptr->orig_super_element_vmt = wlmtk_element_extend( + &window_ptr->super_bordered.super_container.super_element, + &window_element_vmt); + window_ptr->orig_super_container_vmt = wlmtk_container_extend( + &window_ptr->super_bordered.super_container, &window_container_vmt); + + wlmtk_window_set_title(window_ptr, NULL); + + window_ptr->resizebar_ptr = wlmtk_resizebar_create( + env_ptr, window_ptr, &resizebar_style); + if (NULL == window_ptr->resizebar_ptr) { + _wlmtk_window_fini(window_ptr); + return false; + } + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_element_set_visible( + wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); + + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_content_element(content_ptr)); + window_ptr->content_ptr = content_ptr; + wlmtk_content_set_window(content_ptr, window_ptr); + wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + + window_ptr->titlebar_ptr = wlmtk_titlebar_create( + env_ptr, window_ptr, &titlebar_style); + if (NULL == window_ptr->titlebar_ptr) { + _wlmtk_window_fini(window_ptr); + return false; + } + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_element_set_visible( + wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + + return true; } -/* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** + * Uninitializes the winodw. + * + * @param window_ptr + */ +void _wlmtk_window_fini(wlmtk_window_t *window_ptr) +{ + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); + window_ptr->titlebar_ptr = NULL; + } + + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); + window_ptr->resizebar_ptr = NULL; + } + + if (NULL != window_ptr->content_ptr) { + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_content_element(window_ptr->content_ptr)); + wlmtk_element_set_visible( + wlmtk_content_element(window_ptr->content_ptr), false); + wlmtk_content_set_window(window_ptr->content_ptr, NULL); + + wlmtk_element_destroy(wlmtk_content_element(window_ptr->content_ptr)); + window_ptr->content_ptr = NULL; + } + + if (NULL != window_ptr->title_ptr) { + free(window_ptr->title_ptr); + window_ptr->title_ptr = NULL; + } + + wlmtk_bordered_fini(&window_ptr->super_bordered); + wlmtk_box_fini(&window_ptr->box); +} /* ------------------------------------------------------------------------- */ /** @@ -537,9 +525,6 @@ wlmtk_window_vmt_t _wlmtk_window_extend( { wlmtk_window_vmt_t orig_vmt = window_ptr->vmt; - if (NULL != window_vmt_ptr->destroy) { - window_ptr->vmt.destroy = window_vmt_ptr->destroy; - } if (NULL != window_vmt_ptr->set_activated) { window_ptr->vmt.set_activated = window_vmt_ptr->set_activated; } @@ -562,14 +547,6 @@ wlmtk_window_vmt_t _wlmtk_window_extend( return orig_vmt; } -/* ------------------------------------------------------------------------- */ -/** Default implementation of dtor. */ -void _wlmtk_window_destroy(wlmtk_window_t *window_ptr) -{ - wlmtk_window_fini(window_ptr); - free(window_ptr); -} - /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_set_activated. */ void _wlmtk_window_set_activated( @@ -645,8 +622,6 @@ void _wlmtk_window_request_position_and_size( // the pending state should be applied right away. } - - /* ------------------------------------------------------------------------- */ /** Activates window on button press, and calls the parent's implementation. */ bool _wlmtk_window_element_pointer_button( @@ -848,7 +823,6 @@ void _wlmtk_fake_window_request_position_and_size( fake_window_ptr->height = height; } - /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 7a3c3032..05d8085f 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -295,13 +295,22 @@ void wlmtk_window_request_position_and_size( */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); +/** Forward declaration: Fake window state. */ +typedef struct _wlmtk_fake_window_t wlmtk_fake_window_t; /** State of the fake window, for tests. */ -typedef struct { - /** Window state. */ +struct _wlmtk_fake_window_t { + /** Window state - to be hidden. */ wlmtk_window_t window; + /** Window state. */ + wlmtk_window_t *window_ptr; + /** Fake content, to manipulate the fake window's content. */ + wlmtk_fake_content_t *fake_content_ptr; + /** Argument to last @ref wlmtk_window_set_activated call. */ bool activated; + + // FIXME /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ bool decorated; /** Whether @ref wlmtk_window_request_close was called. */ @@ -314,6 +323,7 @@ typedef struct { bool request_resize_called; /** Argument to last @ref wlmtk_window_request_resize call. */ uint32_t request_resize_edges; + // FIXME /** Whether @ref wlmtk_window_request_size was called. */ bool request_size_called; /** Whether @ref wlmtk_window_request_position_and_size was called. */ @@ -326,10 +336,7 @@ typedef struct { int width; /** Argument to last @ref wlmtk_window_request_size call. */ int height; - - /** Fake content, to manipulate the fake window's content. */ - wlmtk_fake_content_t *fake_content_ptr; -} wlmtk_fake_window_t; +}; /** Ctor. */ wlmtk_fake_window_t *wlmtk_fake_window_create(void); From 2654f48d110380097c63f560281e91739de3dcca Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 10:41:31 +0100 Subject: [PATCH 288/390] Fixes typo. --- src/toolkit/window.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 05d8085f..77b4c7de 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -88,7 +88,7 @@ struct _wlmtk_window_t { /** Virtual method table. */ wlmtk_window_vmt_t vmt; - /** Box: In `super_bordered`, holds tontent, title bar and resizebar. */ + /** Box: In `super_bordered`, holds content, title bar and resizebar. */ wlmtk_box_t box; /** Content of this window. */ From 47e960b53f8f3a1369a82a89c59dffe44e7384d9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 10:58:39 +0100 Subject: [PATCH 289/390] Separates the public from private window state. --- src/toolkit/window.c | 90 ++++++++++++++++++++++++----------------- src/toolkit/window.h | 15 +------ src/toolkit/workspace.c | 12 +++--- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d9a8e0bd..a5ccd353 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -25,6 +25,14 @@ /* == Declarations ========================================================= */ +/** State of a fake window: Includes the public record and the window. */ +typedef struct { + /** Window state. */ + wlmtk_window_t window; + /** Fake window - public state. */ + wlmtk_fake_window_t fake_window; +} wlmtk_fake_window_state_t; + static bool _wlmtk_window_init( wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, @@ -350,35 +358,41 @@ static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_fake_window_t *wlmtk_fake_window_create(void) { - wlmtk_fake_window_t *fake_window_ptr = logged_calloc( - 1, sizeof(wlmtk_fake_window_t)); - if (NULL == fake_window_ptr) return NULL; + wlmtk_fake_window_state_t *fake_window_state_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_window_state_t)); + if (NULL == fake_window_state_ptr) return NULL; - fake_window_ptr->fake_content_ptr = wlmtk_fake_content_create(); - if (NULL == fake_window_ptr->fake_content_ptr) { - wlmtk_fake_window_destroy(fake_window_ptr); + fake_window_state_ptr->fake_window.fake_content_ptr = + wlmtk_fake_content_create(); + if (NULL == fake_window_state_ptr->fake_window.fake_content_ptr) { + wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); return NULL; } - if (!_wlmtk_window_init(&fake_window_ptr->window, - NULL, - &fake_window_ptr->fake_content_ptr->content)) { - wlmtk_fake_window_destroy(fake_window_ptr); + if (!_wlmtk_window_init( + &fake_window_state_ptr->window, + NULL, + &fake_window_state_ptr->fake_window.fake_content_ptr->content)) { + wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); return NULL; } - fake_window_ptr->window_ptr = &fake_window_ptr->window; + fake_window_state_ptr->fake_window.window_ptr = + &fake_window_state_ptr->window; // Extend. We don't save the VMT, since it's for fake only. - _wlmtk_window_extend(fake_window_ptr->window_ptr, + _wlmtk_window_extend(&fake_window_state_ptr->window, &_wlmtk_fake_window_vmt); - return fake_window_ptr; + return &fake_window_state_ptr->fake_window; } /* ------------------------------------------------------------------------- */ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) { - _wlmtk_window_fini(&fake_window_ptr->window); - free(fake_window_ptr); + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + fake_window_ptr, wlmtk_fake_window_state_t, fake_window); + + _wlmtk_window_fini(&fake_window_state_ptr->window); + free(fake_window_state_ptr); } /* == Local (static) methods =============================================== */ @@ -761,36 +775,36 @@ void _wlmtk_fake_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->activated = activated; + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.activated = activated; } /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_close. Records call. */ void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->request_close_called = true; + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_close_called = true; } /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_minimize. Records call. */ void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->request_minimize_called = true; + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_minimize_called = true; } /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_move. Records call */ void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->request_move_called = true; + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_move_called = true; } /* ------------------------------------------------------------------------- */ @@ -799,10 +813,10 @@ void _wlmtk_fake_window_request_resize( wlmtk_window_t *window_ptr, uint32_t edges) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->request_resize_called = true; - fake_window_ptr->request_resize_edges = edges; + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_resize_called = true; + fake_window_state_ptr->fake_window.request_resize_edges = edges; } /* ------------------------------------------------------------------------- */ @@ -814,13 +828,13 @@ void _wlmtk_fake_window_request_position_and_size( int width, int height) { - wlmtk_fake_window_t *fake_window_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_t, window); - fake_window_ptr->request_position_and_size_called = true; - fake_window_ptr->x = x; - fake_window_ptr->y = y; - fake_window_ptr->width = width; - fake_window_ptr->height = height; + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_position_and_size_called = true; + fake_window_state_ptr->fake_window.x = x; + fake_window_state_ptr->fake_window.y = y; + fake_window_state_ptr->fake_window.width = width; + fake_window_state_ptr->fake_window.height = height; } /* == Unit tests =========================================================== */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 77b4c7de..93422a3d 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -295,13 +295,8 @@ void wlmtk_window_request_position_and_size( */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); -/** Forward declaration: Fake window state. */ -typedef struct _wlmtk_fake_window_t wlmtk_fake_window_t; /** State of the fake window, for tests. */ -struct _wlmtk_fake_window_t { - /** Window state - to be hidden. */ - wlmtk_window_t window; - +typedef struct { /** Window state. */ wlmtk_window_t *window_ptr; /** Fake content, to manipulate the fake window's content. */ @@ -310,9 +305,6 @@ struct _wlmtk_fake_window_t { /** Argument to last @ref wlmtk_window_set_activated call. */ bool activated; - // FIXME - /** Argument to last @ref wlmtk_window_set_server_side_decorated call. */ - bool decorated; /** Whether @ref wlmtk_window_request_close was called. */ bool request_close_called; /** Whether @ref wlmtk_window_request_minimize was called. */ @@ -323,9 +315,6 @@ struct _wlmtk_fake_window_t { bool request_resize_called; /** Argument to last @ref wlmtk_window_request_resize call. */ uint32_t request_resize_edges; - // FIXME - /** Whether @ref wlmtk_window_request_size was called. */ - bool request_size_called; /** Whether @ref wlmtk_window_request_position_and_size was called. */ bool request_position_and_size_called; /** Argument to last @ref wlmtk_window_request_size call. */ @@ -336,7 +325,7 @@ struct _wlmtk_fake_window_t { int width; /** Argument to last @ref wlmtk_window_request_size call. */ int height; -}; +} wlmtk_fake_window_t; /** Ctor. */ wlmtk_fake_window_t *wlmtk_fake_window_create(void); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index bd9cc901..02cad39b 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -882,20 +882,20 @@ void test_activate(bs_test_t *test_ptr) // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_element_set_position(wlmtk_window_element(&fw1_ptr->window), 0, 0); + wlmtk_element_set_position(wlmtk_window_element(fw1_ptr->window_ptr), 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); // Window 1 is mapped => it's activated. - wlmtk_workspace_map_window(workspace_ptr, &fw1_ptr->window); + wlmtk_workspace_map_window(workspace_ptr, fw1_ptr->window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); // Window 2: from (200, 0) to (300, 100). // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_element_set_position(wlmtk_window_element(&fw2_ptr->window), 200, 0); + wlmtk_element_set_position(wlmtk_window_element(fw2_ptr->window_ptr), 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - wlmtk_workspace_map_window(workspace_ptr, &fw2_ptr->window); + wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); @@ -915,12 +915,12 @@ void test_activate(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); // Unmap window 1. Now window 2 gets activated. - wlmtk_workspace_unmap_window(workspace_ptr, &fw1_ptr->window); + wlmtk_workspace_unmap_window(workspace_ptr, fw1_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); // Unmap the remaining window 2. Nothing is activated. - wlmtk_workspace_unmap_window(workspace_ptr, &fw2_ptr->window); + wlmtk_workspace_unmap_window(workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_fake_window_destroy(fw2_ptr); From 0858c557db137575db4efb78fa6c6a3c39e7bef2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 11:01:06 +0100 Subject: [PATCH 290/390] Moves the window internal state into the header file. --- src/toolkit/window.c | 73 ++++++++++++++++++++++++++++++++++++++++++ src/toolkit/window.h | 76 ++------------------------------------------ 2 files changed, 75 insertions(+), 74 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a5ccd353..11a429d2 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -25,6 +25,79 @@ /* == Declarations ========================================================= */ +/** Maximum number of pending state updates. */ +#define WLMTK_WINDOW_MAX_PENDING 64 + +/** Virtual method table for the window. */ +struct _wlmtk_window_vmt_t { + /** Destructor. */ + void (*destroy)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_set_activated. */ + void (*set_activated)(wlmtk_window_t *window_ptr, + bool activated); + /** Virtual method for @ref wlmtk_window_request_close. */ + void (*request_close)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_request_minimize. */ + void (*request_minimize)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_request_move. */ + void (*request_move)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_request_resize. */ + void (*request_resize)(wlmtk_window_t *window_ptr, + uint32_t edges); + /** Virtual method for @ref wlmtk_window_request_position_and_size. */ + void (*request_position_and_size)(wlmtk_window_t *window_ptr, + int x, int y, int width, int height); +}; + +/** Pending positional updates. */ +typedef struct { + /** Node within @ref wlmtk_window_t::pending_updates. */ + bs_dllist_node_t dlnode; + /** Serial of the update. */ + uint32_t serial; + /** Pending X position. */ + int x; + /** Pending Y position. */ + int y; + /** Width that is to be committed at serial. */ + unsigned width; + /** Height that is to be committed at serial. */ + unsigned height; +} wlmtk_pending_update_t; + +/** State of the window. */ +struct _wlmtk_window_t { + /** Superclass: Bordered. */ + wlmtk_bordered_t super_bordered; + /** Original virtual method table of the window's element superclass. */ + wlmtk_element_vmt_t orig_super_element_vmt; + /** Original virtual method table of the window' container superclass. */ + wlmtk_container_vmt_t orig_super_container_vmt; + + /** Virtual method table. */ + wlmtk_window_vmt_t vmt; + + /** Box: In `super_bordered`, holds content, title bar and resizebar. */ + wlmtk_box_t box; + + /** Content of this window. */ + wlmtk_content_t *content_ptr; + /** Titlebar. */ + wlmtk_titlebar_t *titlebar_ptr; + /** Resizebar. */ + wlmtk_resizebar_t *resizebar_ptr; + + /** Window title. Set through @ref wlmtk_window_set_title. */ + char *title_ptr; + + /** Pending updates. */ + bs_dllist_t pending_updates; + /** List of udpates currently available. */ + bs_dllist_t available_updates; + /** Pre-alloocated updates. */ + wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; +}; + /** State of a fake window: Includes the public record and the window. */ typedef struct { /** Window state. */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 93422a3d..274d1ef1 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -36,79 +36,6 @@ typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; extern "C" { #endif // __cplusplus -/** Maximum number of pending state updates. */ -#define WLMTK_WINDOW_MAX_PENDING 64 - -/** Pending positional updates. */ -typedef struct { - /** Node within @ref wlmtk_window_t::pending_updates. */ - bs_dllist_node_t dlnode; - /** Serial of the update. */ - uint32_t serial; - /** Pending X position. */ - int x; - /** Pending Y position. */ - int y; - /** Width that is to be committed at serial. */ - unsigned width; - /** Height that is to be committed at serial. */ - unsigned height; -} wlmtk_pending_update_t; - -/** Virtual method table for the window. */ -struct _wlmtk_window_vmt_t { - /** Destructor. */ - void (*destroy)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_set_activated. */ - void (*set_activated)(wlmtk_window_t *window_ptr, - bool activated); - /** Virtual method for @ref wlmtk_window_request_close. */ - void (*request_close)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_minimize. */ - void (*request_minimize)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_move. */ - void (*request_move)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_resize. */ - void (*request_resize)(wlmtk_window_t *window_ptr, - uint32_t edges); - /** Virtual method for @ref wlmtk_window_request_position_and_size. */ - void (*request_position_and_size)(wlmtk_window_t *window_ptr, - int x, int y, int width, int height); -}; - -/** State of the window. */ -struct _wlmtk_window_t { - /** Superclass: Bordered. */ - wlmtk_bordered_t super_bordered; - /** Original virtual method table of the window's element superclass. */ - wlmtk_element_vmt_t orig_super_element_vmt; - /** Original virtual method table of the window' container superclass. */ - wlmtk_container_vmt_t orig_super_container_vmt; - - /** Virtual method table. */ - wlmtk_window_vmt_t vmt; - - /** Box: In `super_bordered`, holds content, title bar and resizebar. */ - wlmtk_box_t box; - - /** Content of this window. */ - wlmtk_content_t *content_ptr; - /** Titlebar. */ - wlmtk_titlebar_t *titlebar_ptr; - /** Resizebar. */ - wlmtk_resizebar_t *resizebar_ptr; - - /** Window title. Set through @ref wlmtk_window_set_title. */ - char *title_ptr; - - /** Pending updates. */ - bs_dllist_t pending_updates; - /** List of udpates currently available. */ - bs_dllist_t available_updates; - /** Pre-alloocated updates. */ - wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; -}; - /** * Creates a window for the given content. * @@ -295,6 +222,8 @@ void wlmtk_window_request_position_and_size( */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); +/* ------------------------------------------------------------------------- */ + /** State of the fake window, for tests. */ typedef struct { /** Window state. */ @@ -304,7 +233,6 @@ typedef struct { /** Argument to last @ref wlmtk_window_set_activated call. */ bool activated; - /** Whether @ref wlmtk_window_request_close was called. */ bool request_close_called; /** Whether @ref wlmtk_window_request_minimize was called. */ From 68a52c9af1386b71b2ac385c1e3ceb507cba404b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 11:02:32 +0100 Subject: [PATCH 291/390] Removes a few obsolete methods. --- src/toolkit/window.c | 45 +++++--------------------------------------- 1 file changed, 5 insertions(+), 40 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 11a429d2..fe944ab5 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -111,7 +111,6 @@ static bool _wlmtk_window_init( wlmtk_env_t *env_ptr, wlmtk_content_t *content_ptr); static void _wlmtk_window_fini(wlmtk_window_t *window_ptr); - static wlmtk_window_vmt_t _wlmtk_window_extend( wlmtk_window_t *window_ptr, const wlmtk_window_vmt_t *window_vmt_ptr); @@ -132,11 +131,15 @@ static void _wlmtk_window_request_position_and_size( int width, int height); - static bool _wlmtk_window_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); + + + + + static void _wlmtk_fake_window_set_activated( wlmtk_window_t *window_ptr, bool activated); @@ -731,44 +734,6 @@ bool _wlmtk_window_element_pointer_button( element_ptr, button_event_ptr); } -/* ------------------------------------------------------------------------- */ -/** Implements @ref wlmtk_window_request_close. Requests content closure. */ -void wlmtk_window_request_close_impl(wlmtk_window_t *window_ptr) -{ - wlmtk_content_request_close(window_ptr->content_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_minimize. */ -void wlmtk_window_request_minimize_impl(wlmtk_window_t *window_ptr) -{ - bs_log(BS_INFO, "Requesting window %p to minimize.", window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_move. */ -void wlmtk_window_request_move_impl(wlmtk_window_t *window_ptr) -{ - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_resize. */ -void wlmtk_window_request_resize_impl(wlmtk_window_t *window_ptr, uint32_t edges) -{ - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); -} - /* ------------------------------------------------------------------------- */ /** * Prepares a positional update: Allocates an item and attach it to the end From 7ac11fd3f898a4ab701883ffe66e6652f977b619 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 11:07:57 +0100 Subject: [PATCH 292/390] Re-arrange window functions in the file, for improved readability. --- src/toolkit/window.c | 260 +++++++++++++++++++++---------------------- 1 file changed, 127 insertions(+), 133 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index fe944ab5..5aa10653 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -115,6 +115,12 @@ static wlmtk_window_vmt_t _wlmtk_window_extend( wlmtk_window_t *window_ptr, const wlmtk_window_vmt_t *window_vmt_ptr); +static bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_window_container_update_layout( + wlmtk_container_t *container_ptr); + static void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated); @@ -131,39 +137,12 @@ static void _wlmtk_window_request_position_and_size( int width, int height); -static bool _wlmtk_window_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); - - - - - - -static void _wlmtk_fake_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated); -static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); -static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); -static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); -static void _wlmtk_fake_window_request_resize( - wlmtk_window_t *window_ptr, - uint32_t edges); -static void _wlmtk_fake_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height); - -static wlmtk_pending_update_t *prepare_update( +static wlmtk_pending_update_t *_wlmtk_window_prepare_update( wlmtk_window_t *window_ptr); -static void release_update( +static void _wlmtk_window_release_update( wlmtk_window_t *window_ptr, wlmtk_pending_update_t *update_ptr); -static void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr); - /* == Data ================================================================= */ /** Virtual method table for the window's element superclass. */ @@ -172,7 +151,7 @@ static const wlmtk_element_vmt_t window_element_vmt = { }; /** Virtual method table for the window's container superclass. */ static const wlmtk_container_vmt_t window_container_vmt = { - .update_layout = _wlmtk_box_update_layout, + .update_layout = _wlmtk_window_container_update_layout, }; /** Virtual method table for the window itself. */ static const wlmtk_window_vmt_t _wlmtk_window_vmt = { @@ -261,11 +240,9 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) /* ------------------------------------------------------------------------- */ wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) { - // DEBT: FIXME - The assertion here is too lose. wlmtk_window_t *window_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); - - BS_ASSERT(_wlmtk_box_update_layout == + BS_ASSERT(_wlmtk_window_container_update_layout == window_ptr->super_bordered.super_container.vmt.update_layout); return window_ptr; } @@ -306,7 +283,7 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) wlmtk_window_element(window_ptr), pending_update_ptr->x, pending_update_ptr->y); - release_update(window_ptr, pending_update_ptr); + _wlmtk_window_release_update(window_ptr, pending_update_ptr); } } @@ -420,57 +397,6 @@ void wlmtk_window_request_position_and_size( window_ptr, x, y, width, height); } -/** Virtual method table for the fake window itself. */ -static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { - .set_activated = _wlmtk_fake_window_set_activated, - .request_close = _wlmtk_fake_window_request_close, - .request_minimize = _wlmtk_fake_window_request_minimize, - .request_move = _wlmtk_fake_window_request_move, - .request_resize = _wlmtk_fake_window_request_resize, - .request_position_and_size = _wlmtk_fake_window_request_position_and_size, - -}; - -/* ------------------------------------------------------------------------- */ -wlmtk_fake_window_t *wlmtk_fake_window_create(void) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = logged_calloc( - 1, sizeof(wlmtk_fake_window_state_t)); - if (NULL == fake_window_state_ptr) return NULL; - - fake_window_state_ptr->fake_window.fake_content_ptr = - wlmtk_fake_content_create(); - if (NULL == fake_window_state_ptr->fake_window.fake_content_ptr) { - wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); - return NULL; - } - - if (!_wlmtk_window_init( - &fake_window_state_ptr->window, - NULL, - &fake_window_state_ptr->fake_window.fake_content_ptr->content)) { - wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); - return NULL; - } - fake_window_state_ptr->fake_window.window_ptr = - &fake_window_state_ptr->window; - - // Extend. We don't save the VMT, since it's for fake only. - _wlmtk_window_extend(&fake_window_state_ptr->window, - &_wlmtk_fake_window_vmt); - return &fake_window_state_ptr->fake_window; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - fake_window_ptr, wlmtk_fake_window_state_t, fake_window); - - _wlmtk_window_fini(&fake_window_state_ptr->window); - free(fake_window_state_ptr); -} - /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -637,6 +563,57 @@ wlmtk_window_vmt_t _wlmtk_window_extend( return orig_vmt; } +/* ------------------------------------------------------------------------- */ +/** Activates window on button press, and calls the parent's implementation. */ +bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); + + // We shouldn't receive buttons when not mapped. + BS_ASSERT( + NULL != + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( + window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_raise_window(workspace_ptr, window_ptr); + + return window_ptr->orig_super_element_vmt.pointer_button( + element_ptr, button_event_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of @ref wlmtk_container_vmt_t::update_layout. + * + * Invoked when the window's contained elements triggered a layout update, + * and will use this to trigger (potential) size updates to the window + * decorations. + * + * @param container_ptr + */ +void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_window_t, super_bordered.super_container); + + window_ptr->orig_super_container_vmt.update_layout(container_ptr); + + if (NULL != window_ptr->content_ptr) { + int width; + wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); + } + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); + } + } +} + /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_set_activated. */ void _wlmtk_window_set_activated( @@ -699,7 +676,8 @@ void _wlmtk_window_request_position_and_size( uint32_t serial = wlmtk_content_request_size( window_ptr->content_ptr, width, height); - wlmtk_pending_update_t *pending_update_ptr = prepare_update(window_ptr); + wlmtk_pending_update_t *pending_update_ptr = + _wlmtk_window_prepare_update(window_ptr); pending_update_ptr->serial = serial; pending_update_ptr->x = x; pending_update_ptr->y = y; @@ -712,28 +690,6 @@ void _wlmtk_window_request_position_and_size( // the pending state should be applied right away. } -/* ------------------------------------------------------------------------- */ -/** Activates window on button press, and calls the parent's implementation. */ -bool _wlmtk_window_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr) -{ - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); - - // We shouldn't receive buttons when not mapped. - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_activate_window(workspace_ptr, window_ptr); - wlmtk_workspace_raise_window(workspace_ptr, window_ptr); - - return window_ptr->orig_super_element_vmt.pointer_button( - element_ptr, button_event_ptr); -} - /* ------------------------------------------------------------------------- */ /** * Prepares a positional update: Allocates an item and attach it to the end @@ -744,7 +700,7 @@ bool _wlmtk_window_element_pointer_button( * @return A pointer to a @ref wlmtk_pending_update_t, already positioned at the * back of @ref wlmtk_window_t::pending_updates. */ -wlmtk_pending_update_t *prepare_update( +wlmtk_pending_update_t *_wlmtk_window_prepare_update( wlmtk_window_t *window_ptr) { bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( @@ -768,7 +724,7 @@ wlmtk_pending_update_t *prepare_update( * @param window_ptr * @param update_ptr */ -void release_update( +void _wlmtk_window_release_update( wlmtk_window_t *window_ptr, wlmtk_pending_update_t *update_ptr) { @@ -776,36 +732,74 @@ void release_update( bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); } +/* == Implementation of the fake window ==================================== */ + +static void _wlmtk_fake_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated); +static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_resize( + wlmtk_window_t *window_ptr, + uint32_t edges); +static void _wlmtk_fake_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); + +/** Virtual method table for the fake window itself. */ +static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { + .set_activated = _wlmtk_fake_window_set_activated, + .request_close = _wlmtk_fake_window_request_close, + .request_minimize = _wlmtk_fake_window_request_minimize, + .request_move = _wlmtk_fake_window_request_move, + .request_resize = _wlmtk_fake_window_request_resize, + .request_position_and_size = _wlmtk_fake_window_request_position_and_size, + +}; + /* ------------------------------------------------------------------------- */ -/** - * Implementation of @ref wlmtk_container_vmt_t::update_layout. - * - * Invoked when the window's contained elements triggered a layout update, - * and will use this to trigger (potential) size updates to the window - * decorations. - * - * @param container_ptr - */ -void _wlmtk_box_update_layout(wlmtk_container_t *container_ptr) +wlmtk_fake_window_t *wlmtk_fake_window_create(void) { - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_window_t, super_bordered.super_container); + wlmtk_fake_window_state_t *fake_window_state_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_window_state_t)); + if (NULL == fake_window_state_ptr) return NULL; - window_ptr->orig_super_container_vmt.update_layout(container_ptr); + fake_window_state_ptr->fake_window.fake_content_ptr = + wlmtk_fake_content_create(); + if (NULL == fake_window_state_ptr->fake_window.fake_content_ptr) { + wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); + return NULL; + } - if (NULL != window_ptr->content_ptr) { - int width; - wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); - } - if (NULL != window_ptr->resizebar_ptr) { - wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); - } + if (!_wlmtk_window_init( + &fake_window_state_ptr->window, + NULL, + &fake_window_state_ptr->fake_window.fake_content_ptr->content)) { + wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); + return NULL; } + fake_window_state_ptr->fake_window.window_ptr = + &fake_window_state_ptr->window; + + // Extend. We don't save the VMT, since it's for fake only. + _wlmtk_window_extend(&fake_window_state_ptr->window, + &_wlmtk_fake_window_vmt); + return &fake_window_state_ptr->fake_window; } -/* == Virtual method implementation for the fake window ==================== */ +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + fake_window_ptr, wlmtk_fake_window_state_t, fake_window); + + _wlmtk_window_fini(&fake_window_state_ptr->window); + free(fake_window_state_ptr); +} /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_set_activated. Records call. */ From 187df80b6feb8a917f55f9da3bad52e15261a02e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 11:26:42 +0100 Subject: [PATCH 293/390] Forwards env to wlmtk_content_t from XDG toplevel init. --- src/wlmtk_xdg_toplevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 64486690..6575b359 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -138,7 +138,7 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( if (NULL == xdg_tl_content_ptr) return NULL; if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, - NULL, + server_ptr->env_ptr, server_ptr->wlr_seat_ptr)) { xdg_toplevel_content_destroy(xdg_tl_content_ptr); return NULL; From a2c065c32e50228d7d29969518541da78e273dad Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 11:38:19 +0100 Subject: [PATCH 294/390] Moves the wlr_seat_ptr arg from content into wlmtk_env_t. --- src/server.c | 3 ++- src/toolkit/content.c | 21 +++++++++++---------- src/toolkit/content.h | 6 +----- src/toolkit/env.c | 12 +++++++++++- src/toolkit/env.h | 13 ++++++++++++- src/wlmtk_xdg_toplevel.c | 3 +-- 6 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/server.c b/src/server.c index eb59b556..7883bed1 100644 --- a/src/server.c +++ b/src/server.c @@ -218,7 +218,8 @@ wlmaker_server_t *wlmaker_server_create(void) server_ptr->env_ptr = wlmtk_env_create( server_ptr->cursor_ptr->wlr_cursor_ptr, - server_ptr->cursor_ptr->wlr_xcursor_manager_ptr); + server_ptr->cursor_ptr->wlr_xcursor_manager_ptr, + server_ptr->wlr_seat_ptr); if (NULL == server_ptr->env_ptr) { wlmaker_server_destroy(server_ptr); return NULL; diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 44e79c83..acde87b3 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -70,8 +70,7 @@ void *wlmtk_content_identifier_ptr = wlmtk_content_init; /* ------------------------------------------------------------------------- */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - wlmtk_env_t *env_ptr, - struct wlr_seat *wlr_seat_ptr) + wlmtk_env_t *env_ptr) { BS_ASSERT(NULL != content_ptr); memset(content_ptr, 0, sizeof(wlmtk_content_t)); @@ -82,7 +81,6 @@ bool wlmtk_content_init( content_ptr->orig_super_element_vmt = wlmtk_element_extend( &content_ptr->super_element, &content_element_vmt); - content_ptr->wlr_seat_ptr = wlr_seat_ptr; content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; return true; } @@ -242,11 +240,13 @@ void element_pointer_leave(wlmtk_element_t *element_ptr) // If the current surface's parent is our surface: clear it. struct wlr_surface *focused_wlr_surface_ptr = - content_ptr->wlr_seat_ptr->pointer_state.focused_surface; + wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr + )->pointer_state.focused_surface; if (NULL != focused_wlr_surface_ptr && wlr_surface_get_root_surface(focused_wlr_surface_ptr) == content_ptr->wlr_surface_ptr) { - wlr_seat_pointer_clear_focus(content_ptr->wlr_seat_ptr); + wlr_seat_pointer_clear_focus( + wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr)); } } @@ -310,11 +310,11 @@ bool element_pointer_motion( BS_ASSERT(content_ptr->wlr_surface_ptr == wlr_surface_get_root_surface(wlr_scene_surface_ptr->surface)); wlr_seat_pointer_notify_enter( - content_ptr->wlr_seat_ptr, + wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr), wlr_scene_surface_ptr->surface, node_x, node_y); wlr_seat_pointer_notify_motion( - content_ptr->wlr_seat_ptr, + wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr), time_msec, node_x, node_y); return true; @@ -341,7 +341,8 @@ bool element_pointer_button( // Complain if the surface isn't part of our responsibility. struct wlr_surface *focused_wlr_surface_ptr = - content_ptr->wlr_seat_ptr->pointer_state.focused_surface; + wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr + )->pointer_state.focused_surface; if (NULL == focused_wlr_surface_ptr) return false; // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated window // over to a non-activated window will trigger the condition here on the @@ -353,7 +354,7 @@ bool element_pointer_button( if (WLMTK_BUTTON_DOWN == button_event_ptr->type || WLMTK_BUTTON_UP == button_event_ptr->type) { wlr_seat_pointer_notify_button( - content_ptr->wlr_seat_ptr, + wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr), button_event_ptr->time_msec, button_event_ptr->button, (button_event_ptr->type == WLMTK_BUTTON_DOWN) ? @@ -413,7 +414,7 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) 1, sizeof(wlmtk_fake_content_t)); if (NULL == fake_content_ptr) return NULL; - if (!wlmtk_content_init(&fake_content_ptr->content, NULL, NULL)) { + if (!wlmtk_content_init(&fake_content_ptr->content, NULL)) { free(fake_content_ptr); return NULL; } diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 5ccfb118..f0be63aa 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -65,8 +65,6 @@ struct _wlmtk_content_t { */ wlmtk_window_t *window_ptr; - /** Back-link to the the associated seat. */ - struct wlr_seat *wlr_seat_ptr; /** * Surface associated with this content. * @@ -86,14 +84,12 @@ struct _wlmtk_content_t { * * @param content_ptr * @param env_ptr - * @param wlr_seat_ptr * * @return true on success. */ bool wlmtk_content_init( wlmtk_content_t *content_ptr, - wlmtk_env_t *env_ptr, - struct wlr_seat *wlr_seat_ptr); + wlmtk_env_t *env_ptr); /** * Extends the content's virtual methods. diff --git a/src/toolkit/env.c b/src/toolkit/env.c index e22bebbe..bbaaa68a 100644 --- a/src/toolkit/env.c +++ b/src/toolkit/env.c @@ -34,6 +34,8 @@ struct _wlmtk_env_t { struct wlr_cursor *wlr_cursor_ptr; /** Points to a `wlr_xcursor_manager`. */ struct wlr_xcursor_manager *wlr_xcursor_manager_ptr; + /** Points to a `wlr_seat`. */ + struct wlr_seat *wlr_seat_ptr; }; /** Struct to identify a @ref wlmtk_env_cursor_t with the xcursor name. */ @@ -58,13 +60,15 @@ static const wlmtk_env_cursor_lookup_t _wlmtk_env_cursor_lookup[] = { /* ------------------------------------------------------------------------- */ wlmtk_env_t *wlmtk_env_create( struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr) + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + struct wlr_seat *wlr_seat_ptr) { wlmtk_env_t *env_ptr = logged_calloc(1, sizeof(wlmtk_env_t)); if (NULL == env_ptr) return NULL; env_ptr->wlr_cursor_ptr = wlr_cursor_ptr; env_ptr->wlr_xcursor_manager_ptr = wlr_xcursor_manager_ptr; + env_ptr->wlr_seat_ptr = wlr_seat_ptr; return env_ptr; } @@ -97,4 +101,10 @@ void wlmtk_env_set_cursor(wlmtk_env_t *env_ptr, wlmtk_env_cursor_t cursor) } } +/* ------------------------------------------------------------------------- */ +struct wlr_seat *wlmtk_env_wlr_seat(wlmtk_env_t *env_ptr) +{ + return env_ptr->wlr_seat_ptr; +} + /* == End of env.c ========================================================= */ diff --git a/src/toolkit/env.h b/src/toolkit/env.h index d1cba218..6b0ca35e 100644 --- a/src/toolkit/env.h +++ b/src/toolkit/env.h @@ -26,6 +26,8 @@ typedef struct _wlmtk_env_t wlmtk_env_t; /** Forward declaration. */ struct wlr_cursor; /** Forward declaration. */ +struct wlr_seat; +/** Forward declaration. */ struct wlr_xcursor_manager; #ifdef __cplusplus @@ -49,12 +51,14 @@ typedef enum { * * @param wlr_cursor_ptr * @param wlr_xcursor_manager_ptr + * @param wlr_seat_ptr * * @return An environment state or NULL on error. */ wlmtk_env_t *wlmtk_env_create( struct wlr_cursor *wlr_cursor_ptr, - struct wlr_xcursor_manager *wlr_xcursor_manager_ptr); + struct wlr_xcursor_manager *wlr_xcursor_manager_ptr, + struct wlr_seat *wlr_seat_ptr); /** * Destroys the environment state. @@ -71,6 +75,13 @@ void wlmtk_env_destroy(wlmtk_env_t *env_ptr); */ void wlmtk_env_set_cursor(wlmtk_env_t *env_ptr, wlmtk_env_cursor_t cursor); +/** + * Returns the pointer to the wlr_seat. + * + * @param env_ptr + */ +struct wlr_seat *wlmtk_env_wlr_seat(wlmtk_env_t *env_ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 6575b359..e41fe7e2 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -138,8 +138,7 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( if (NULL == xdg_tl_content_ptr) return NULL; if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, - server_ptr->env_ptr, - server_ptr->wlr_seat_ptr)) { + server_ptr->env_ptr)) { xdg_toplevel_content_destroy(xdg_tl_content_ptr); return NULL; } From 5b926f14f1e1f704ca55b8e30ee74744c117d4f0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 11:59:09 +0100 Subject: [PATCH 295/390] Connects the xdg surface destroy listener, fixes a leak on toolkit window turndown. --- src/wlmtk_xdg_toplevel.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index e41fe7e2..db550db7 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -35,6 +35,8 @@ typedef struct { /** Whether this surface is currently activated. */ bool activated; + /** Listener for the `destroy` signal of the `wlr_xdg_surface::events`. */ + struct wl_listener destroy_listener; /** Listener for the `map` signal of the `wlr_surface`. */ struct wl_listener surface_map_listener; /** Listener for the `unmap` signal of the `wlr_surface`. */ @@ -56,7 +58,9 @@ static wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( static void xdg_toplevel_content_destroy( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr); - +static void handle_destroy( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_surface_map( struct wl_listener *listener_ptr, void *data_ptr); @@ -151,6 +155,10 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; xdg_tl_content_ptr->server_ptr = server_ptr; + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->events.destroy, + &xdg_tl_content_ptr->destroy_listener, + handle_destroy); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.map, &xdg_tl_content_ptr->surface_map_listener, @@ -199,6 +207,7 @@ void xdg_toplevel_content_destroy( wl_list_remove(&xdg_tl_content_ptr->surface_commit_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); + wl_list_remove(&xdg_tl_content_ptr->destroy_listener.link); wlmtk_content_fini(&xdg_tl_content_ptr->super_content); free(xdg_tl_content_ptr); @@ -257,7 +266,6 @@ void content_request_close(wlmtk_content_t *content_ptr) xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel); } - /* ------------------------------------------------------------------------- */ /** * Sets the dimensions of the element in pixels. @@ -324,6 +332,22 @@ void content_set_activated( xdg_tl_content_ptr->activated = activated; } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `destroy` signal of the `wlr_xdg_surface::events`. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_destroy(struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, destroy_listener); + // Destroy the window -> also destroys the content. + wlmtk_window_destroy(xdg_tl_content_ptr->super_content.window_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `map` signal. From c2991aef68348c8736f02cde1e4a67ac7a502c6f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 10 Dec 2023 20:55:20 +0100 Subject: [PATCH 296/390] Wires up XDG decoration protocol with the window. --- src/toolkit/window.c | 113 ++++++++++++++++++++++++++++--------------- src/xdg_decoration.c | 64 +++++++++++++----------- 2 files changed, 108 insertions(+), 69 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 5aa10653..fbb2d4cc 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -96,6 +96,13 @@ struct _wlmtk_window_t { bs_dllist_t available_updates; /** Pre-alloocated updates. */ wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; + + /** + * Stores whether the window is server-side decorated. + * + * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). + */ + bool server_side_decorated; }; /** State of a fake window: Includes the public record and the window. */ @@ -333,6 +340,46 @@ void wlmtk_window_set_server_side_decorated( // TODO(kaeser@gubbe.ch): Implement. bs_log(BS_INFO, "Set server side decoration for window %p: %d", window_ptr, decorated); + + if (window_ptr->server_side_decorated == decorated) return; + + if (decorated) { + // Create decoration. + window_ptr->titlebar_ptr = wlmtk_titlebar_create( + window_ptr->super_bordered.super_container.super_element.env_ptr, + window_ptr, &titlebar_style); + BS_ASSERT(NULL != window_ptr->titlebar_ptr); + wlmtk_element_set_visible( + wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + + window_ptr->resizebar_ptr = wlmtk_resizebar_create( + window_ptr->super_bordered.super_container.super_element.env_ptr, + window_ptr, &resizebar_style); + BS_ASSERT(NULL != window_ptr->resizebar_ptr); + wlmtk_element_set_visible( + wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); + wlmtk_box_add_element_back( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + } else { + // Remove & destroy the decoration. + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); + window_ptr->titlebar_ptr = NULL; + + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); + window_ptr->resizebar_ptr = NULL; + } + + window_ptr->server_side_decorated = decorated; } /* ------------------------------------------------------------------------- */ @@ -447,18 +494,6 @@ bool _wlmtk_window_init( wlmtk_window_set_title(window_ptr, NULL); - window_ptr->resizebar_ptr = wlmtk_resizebar_create( - env_ptr, window_ptr, &resizebar_style); - if (NULL == window_ptr->resizebar_ptr) { - _wlmtk_window_fini(window_ptr); - return false; - } - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_element_set_visible( - wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - wlmtk_box_add_element_front( &window_ptr->box, wlmtk_content_element(content_ptr)); @@ -466,18 +501,6 @@ bool _wlmtk_window_init( wlmtk_content_set_window(content_ptr, window_ptr); wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - window_ptr->titlebar_ptr = wlmtk_titlebar_create( - env_ptr, window_ptr, &titlebar_style); - if (NULL == window_ptr->titlebar_ptr) { - _wlmtk_window_fini(window_ptr); - return false; - } - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_element_set_visible( - wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - return true; } @@ -489,21 +512,7 @@ bool _wlmtk_window_init( */ void _wlmtk_window_fini(wlmtk_window_t *window_ptr) { - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); - window_ptr->titlebar_ptr = NULL; - } - - if (NULL != window_ptr->resizebar_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); - window_ptr->resizebar_ptr = NULL; - } + wlmtk_window_set_server_side_decorated(window_ptr, false); if (NULL != window_ptr->content_ptr) { wlmtk_box_remove_element( @@ -557,7 +566,8 @@ wlmtk_window_vmt_t _wlmtk_window_extend( window_ptr->vmt.request_resize = window_vmt_ptr->request_resize; } if (NULL != window_vmt_ptr->request_position_and_size) { - window_ptr->vmt.request_position_and_size = window_vmt_ptr->request_position_and_size; + window_ptr->vmt.request_position_and_size = + window_vmt_ptr->request_position_and_size; } return orig_vmt; @@ -875,6 +885,7 @@ static void test_create_destroy(bs_test_t *test_ptr); static void test_set_title(bs_test_t *test_ptr); static void test_request_close(bs_test_t *test_ptr); static void test_set_activated(bs_test_t *test_ptr); +static void test_server_side_decorated(bs_test_t *test_ptr); static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { @@ -882,6 +893,7 @@ const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "set_title", test_set_title }, { 1, "request_close", test_request_close }, { 1, "set_activated", test_set_activated }, + { 1, "set_server_side_decorated", test_server_side_decorated }, { 1, "fake", test_fake }, { 0, NULL, NULL } }; @@ -954,6 +966,27 @@ void test_set_activated(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests enabling and disabling server-side decoration. */ +void test_server_side_decorated(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + wlmtk_window_set_server_side_decorated(window_ptr, true); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + wlmtk_window_set_server_side_decorated(window_ptr, false); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + wlmtk_window_destroy(window_ptr); +} + /* ------------------------------------------------------------------------- */ /** Tests fake window ctor and dtor. */ void test_fake(bs_test_t *test_ptr) diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index d12e6eeb..56d65cc7 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -220,25 +220,10 @@ void handle_decoration_request_mode( struct wlr_scene_tree *wlr_scene_tree_ptr = (struct wlr_scene_tree*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; + wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; wlmtk_content_t *content_ptr = (wlmtk_content_t*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; - if (NULL != content_ptr && - content_ptr->identifier_ptr == wlmtk_content_identifier_ptr) { - bs_log(BS_WARNING, - "Toolkit window: Enforcing client-side decoration."); - - enum wlr_xdg_toplevel_decoration_v1_mode mode = - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - wlr_xdg_toplevel_decoration_v1_set_mode( - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr, - mode); - wlmtk_window_set_server_side_decorated( - content_ptr->window_ptr, - mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - return; - } - wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; enum wlr_xdg_toplevel_decoration_v1_mode mode = decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode; @@ -272,19 +257,40 @@ void handle_decoration_request_mode( wlr_xdg_toplevel_decoration_v1_set_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr, mode); - bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, view %p: " - "Current %d, pending %d, scheduled %d, requested %d. Set: %d", - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, - view_ptr, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->scheduled_mode, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode, - mode); - - wlmaker_view_set_server_side_decoration( - view_ptr, - mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + if (NULL != content_ptr && + content_ptr->identifier_ptr == wlmtk_content_identifier_ptr) { + + bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, " + "content %p: Current %d, pending %d, scheduled %d, " + "requested %d. Set: %d", + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, + content_ptr, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->scheduled_mode, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode, + mode); + + wlmtk_window_set_server_side_decorated( + content_ptr->window_ptr, + mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + + } else { + + bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, view %p: " + "Current %d, pending %d, scheduled %d, requested %d. Set: %d", + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, + view_ptr, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->scheduled_mode, + decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode, + mode); + + wlmaker_view_set_server_side_decoration( + view_ptr, + mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + } } /* ------------------------------------------------------------------------- */ From 2379780b4ee10a25b71f5ce826af11b52c8c01a7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 20:45:19 +0100 Subject: [PATCH 297/390] Adds wlmtk_get_dimensinos_box as an easier accessor to the dimensions. --- src/toolkit/bordered.c | 8 ++++---- src/toolkit/box.c | 20 +++++++++--------- src/toolkit/container.c | 12 +++++------ src/toolkit/element.c | 45 ++++++++++++++++++++++++++--------------- src/toolkit/element.h | 27 +++++++++++++++++++++---- 5 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c index d16f9c85..f66df1ee 100644 --- a/src/toolkit/bordered.c +++ b/src/toolkit/bordered.c @@ -248,8 +248,8 @@ void test_rectangle_pos(bs_test_t *test_ptr, wlmtk_rectangle_t *rect_ptr, void test_init_fini(bs_test_t *test_ptr) { wlmtk_fake_element_t *fe_ptr = wlmtk_fake_element_create(); - fe_ptr->width = 100; - fe_ptr->height = 20; + fe_ptr->dimensions.width = 100; + fe_ptr->dimensions.height = 20; wlmtk_element_set_position(&fe_ptr->element, -10, -4); wlmtk_bordered_t bordered; @@ -271,8 +271,8 @@ void test_init_fini(bs_test_t *test_ptr) -12, -4, 2, 20); // Update layout, test updated positions. - fe_ptr->width = 200; - fe_ptr->height = 120; + fe_ptr->dimensions.width = 200; + fe_ptr->dimensions.height = 120; wlmtk_container_update_layout(&bordered.super_container); test_rectangle_pos( test_ptr, bordered.northern_border_rectangle_ptr, diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 8f6b5f13..1106fe8e 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -271,16 +271,16 @@ void test_layout_horizontal(bs_test_t *test_ptr) wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); - e1_ptr->width = 10; - e1_ptr->height = 1; + e1_ptr->dimensions.width = 10; + e1_ptr->dimensions.height = 1; wlmtk_fake_element_t *e2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e2_ptr->element, false); - e2_ptr->width = 20; - e1_ptr->height = 2; + e2_ptr->dimensions.width = 20; + e1_ptr->dimensions.height = 2; wlmtk_fake_element_t *e3_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e3_ptr->element, true); - e3_ptr->width = 40; - e3_ptr->height = 4; + e3_ptr->dimensions.width = 40; + e3_ptr->dimensions.height = 4; // Note: Elements are added "in front" == left. wlmtk_box_add_element_front(&box, &e1_ptr->element); @@ -334,12 +334,12 @@ void test_layout_vertical(bs_test_t *test_ptr) wlmtk_fake_element_t *e1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e1_ptr->element, true); - e1_ptr->width = 100; - e1_ptr->height = 10; + e1_ptr->dimensions.width = 100; + e1_ptr->dimensions.height = 10; wlmtk_fake_element_t *e2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&e2_ptr->element, true); - e2_ptr->width = 200; - e2_ptr->height = 20; + e2_ptr->dimensions.width = 200; + e2_ptr->dimensions.height = 20; // Note: Elements are added "in front" == left. wlmtk_box_add_element_front(&box, &e1_ptr->element); diff --git a/src/toolkit/container.c b/src/toolkit/container.c index bc3b085f..eb4424a1 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -971,14 +971,14 @@ void test_pointer_motion(bs_test_t *test_ptr) // Note: pointer area extends by (-1, -2, 3, 4) on each fake element. wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem1_ptr->element, -20, -40); - elem1_ptr->width = 10; - elem1_ptr->height = 5; + elem1_ptr->dimensions.width = 10; + elem1_ptr->dimensions.height = 5; wlmtk_element_set_visible(&elem1_ptr->element, false); wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); wlmtk_element_set_position(&elem2_ptr->element, 100, 200); - elem2_ptr->width = 10; - elem2_ptr->height = 5; + elem2_ptr->dimensions.width = 10; + elem2_ptr->dimensions.height = 5; wlmtk_element_set_visible(&elem2_ptr->element, true); wlmtk_container_add_element(&container, &elem2_ptr->element); @@ -1334,8 +1334,8 @@ void test_pointer_button(bs_test_t *test_ptr) wlmtk_fake_element_t *elem1_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&elem1_ptr->element, true); - elem1_ptr->width = 1; - elem1_ptr->height = 1; + elem1_ptr->dimensions.width = 1; + elem1_ptr->dimensions.height = 1; wlmtk_container_add_element(&container, &elem1_ptr->element); wlmtk_fake_element_t *elem2_ptr = wlmtk_fake_element_create(); diff --git a/src/toolkit/element.c b/src/toolkit/element.c index 433d99bb..b042021a 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -437,10 +437,12 @@ void fake_get_dimensions( { wlmtk_fake_element_t *fake_element_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_fake_element_t, element); - if (NULL != left_ptr) *left_ptr = 0; - if (NULL != top_ptr) *top_ptr = 0; - if (NULL != right_ptr) *right_ptr = fake_element_ptr->width; - if (NULL != bottom_ptr) *bottom_ptr = fake_element_ptr->height; + if (NULL != left_ptr) *left_ptr = fake_element_ptr->dimensions.x; + if (NULL != top_ptr) *top_ptr = fake_element_ptr->dimensions.y; + if (NULL != right_ptr) *right_ptr = ( + fake_element_ptr->dimensions.width - fake_element_ptr->dimensions.x); + if (NULL != bottom_ptr) *bottom_ptr = ( + fake_element_ptr->dimensions.height - fake_element_ptr->dimensions.y); } /* ------------------------------------------------------------------------- */ @@ -456,8 +458,10 @@ void fake_get_pointer_area( element_ptr, wlmtk_fake_element_t, element); if (NULL != left_ptr) *left_ptr = -1; if (NULL != top_ptr) *top_ptr = -2; - if (NULL != right_ptr) *right_ptr = fake_element_ptr->width + 3; - if (NULL != bottom_ptr) *bottom_ptr = fake_element_ptr->height + 4; + if (NULL != right_ptr) *right_ptr = ( + fake_element_ptr->dimensions.width + 3); + if (NULL != bottom_ptr) *bottom_ptr = ( + fake_element_ptr->dimensions.height + 4); } /* ------------------------------------------------------------------------- */ @@ -472,8 +476,8 @@ bool fake_pointer_motion( element_ptr, wlmtk_fake_element_t, element); fake_element_ptr->orig_vmt.pointer_motion(element_ptr, x, y, time_msec); fake_element_ptr->pointer_motion_called = true; - return (-1 <= x && x < fake_element_ptr->width + 3 && - -2 < y && y < fake_element_ptr->height + 4); + return (-1 <= x && x < fake_element_ptr->dimensions.width + 3 && + -2 < y && y < fake_element_ptr->dimensions.height + 4); } /* ------------------------------------------------------------------------- */ @@ -639,8 +643,10 @@ void test_set_get_position(bs_test_t *test_ptr) void test_get_dimensions(bs_test_t *test_ptr) { wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); - fake_element_ptr->width = 42; - fake_element_ptr->height = 21; + fake_element_ptr->dimensions.x = -10; + fake_element_ptr->dimensions.y = -20; + fake_element_ptr->dimensions.width = 42; + fake_element_ptr->dimensions.height = 21; // Must not crash. wlmtk_element_get_dimensions( @@ -649,10 +655,17 @@ void test_get_dimensions(bs_test_t *test_ptr) int top, left, right, bottom; wlmtk_element_get_dimensions( &fake_element_ptr->element, &top, &left, &right, &bottom); - BS_TEST_VERIFY_EQ(test_ptr, 0, top); - BS_TEST_VERIFY_EQ(test_ptr, 0, left); - BS_TEST_VERIFY_EQ(test_ptr, 42, right); - BS_TEST_VERIFY_EQ(test_ptr, 21, bottom); + BS_TEST_VERIFY_EQ(test_ptr, -10, top); + BS_TEST_VERIFY_EQ(test_ptr, -20, left); + BS_TEST_VERIFY_EQ(test_ptr, 52, right); + BS_TEST_VERIFY_EQ(test_ptr, 41, bottom); + + struct wlr_box box = wlmtk_element_get_dimensions_box( + &fake_element_ptr->element); + BS_TEST_VERIFY_EQ(test_ptr, -10, box.x); + BS_TEST_VERIFY_EQ(test_ptr, -20, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 42, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 21, box.height); wlmtk_element_destroy(&fake_element_ptr->element); } @@ -662,8 +675,8 @@ void test_get_dimensions(bs_test_t *test_ptr) void test_get_pointer_area(bs_test_t *test_ptr) { wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); - fake_element_ptr->width = 42; - fake_element_ptr->height = 21; + fake_element_ptr->dimensions.width = 42; + fake_element_ptr->dimensions.height = 21; // Must not crash. wlmtk_element_get_pointer_area( diff --git a/src/toolkit/element.h b/src/toolkit/element.h index de567125..9fbe5fd4 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -23,6 +23,8 @@ #include #include +#include "wlr/util/box.h" + /** Forward declaration: Element. */ typedef struct _wlmtk_element_t wlmtk_element_t; /** Forward declaration: Element virtual method table. */ @@ -318,6 +320,25 @@ static inline void wlmtk_element_get_dimensions( element_ptr, left_ptr, top_ptr, right_ptr, bottom_ptr); } +/** + * Gets the element's dimensions in pixel as wlr_box, relative to the position. + * + * @param element_ptr + * + * @return A struct wlr_box that specifies the top-left corner of the element + * relative to it's position, and the element's total width and height. + */ +static inline struct wlr_box wlmtk_element_get_dimensions_box( + wlmtk_element_t *element_ptr) +{ + struct wlr_box box; + element_ptr->vmt.get_dimensions( + element_ptr, &box.x, &box.y, &box.width, &box.height); + box.width += box.x; + box.height += box.y; + return box; +} + /** * Passes a pointer motion event on to the element. * @@ -365,10 +386,8 @@ typedef struct { wlmtk_element_t element; /** Original VMT. */ wlmtk_element_vmt_t orig_vmt; - /** Width of the element, in pixels. */ - int width; - /** Height of the element, in pixels. */ - int height; + /** Dimensions of the fake element, in pixels. */ + struct wlr_box dimensions; /** Indicates @ref wlmtk_element_vmt_t::pointer_motion() was called. */ bool pointer_motion_called; From 2fdc1e37696b8eb671935bc272d48c97a117a184 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:32:56 +0100 Subject: [PATCH 298/390] Adds wlmtk_fake_content_commit for eaiser testing. --- src/toolkit/content.c | 12 +++++++++++- src/toolkit/content.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index acde87b3..462de88d 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -139,7 +139,7 @@ void wlmtk_content_commit_size( if (NULL != content_ptr->super_element.parent_container_ptr) { wlmtk_container_update_layout( - content_ptr->super_element.parent_container_ptr); + content_ptr->super_element.parent_container_ptr); } } @@ -425,6 +425,16 @@ wlmtk_fake_content_t *wlmtk_fake_content_create(void) return fake_content_ptr; } +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_content_commit(wlmtk_fake_content_t *fake_content_ptr) +{ + wlmtk_content_commit_size( + &fake_content_ptr->content, + fake_content_ptr->return_request_size, + fake_content_ptr->requested_width, + fake_content_ptr->requested_height); +} + /* ------------------------------------------------------------------------- */ /** Dtor for the fake content. */ void fake_content_destroy(wlmtk_element_t *element_ptr) diff --git a/src/toolkit/content.h b/src/toolkit/content.h index f0be63aa..569867dc 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -216,6 +216,9 @@ struct _wlmtk_fake_content_t { /** Ctor for a fake content. */ wlmtk_fake_content_t *wlmtk_fake_content_create(void); +/** Commits dimensions from earlier @ref wlmtk_content_request_size call. */ +void wlmtk_fake_content_commit(wlmtk_fake_content_t *fake_content_ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus From 7ea1f9a9c0a10827bc109d5cba35ffce8d66a0a2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:33:31 +0100 Subject: [PATCH 299/390] Adds wlmtk_workspace_get_maximize_extents. --- src/toolkit/workspace.c | 18 ++++++++++++++++++ src/toolkit/workspace.h | 10 ++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 02cad39b..c7b4fb36 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -181,6 +181,19 @@ void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, workspace_ptr->y2 = extents_ptr->y + extents_ptr->height; } +/* ------------------------------------------------------------------------- */ +struct wlr_box wlmtk_workspace_get_maximize_extents( + wlmtk_workspace_t *workspace_ptr) +{ + // TODO(kaeser@gubbe.ch): Well, actually compute something sensible. + struct wlr_box box = { + .x = workspace_ptr->x1, + .y = workspace_ptr->y1, + .width = workspace_ptr->x2 - workspace_ptr->x1 - 64, + .height = workspace_ptr->y2 - workspace_ptr->y1 - 64 }; + return box; +} + /* ------------------------------------------------------------------------- */ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) @@ -616,6 +629,11 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 90, x2); BS_TEST_VERIFY_EQ(test_ptr, 180, y2); + box = wlmtk_workspace_get_maximize_extents(workspace_ptr); + BS_TEST_VERIFY_EQ(test_ptr, -10, box.x); + BS_TEST_VERIFY_EQ(test_ptr, -20, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 36, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 136, box.height); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 8ad28557..0859f892 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -67,6 +67,16 @@ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr); void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, const struct wlr_box *extents_ptr); +/** + * Returns the extents of the workspace available for maximized windows. + * + * @param workspace_ptr + * + * @return A `struct wlr_box` that lines out the available space and position. + */ +struct wlr_box wlmtk_workspace_get_maximize_extents( + wlmtk_workspace_t *workspace_ptr); + /** * Maps the window: Adds it to the workspace container and makes it visible. * From f191e6bdd5d26a9e8e7a87d5f808b4d00f16119c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:33:49 +0100 Subject: [PATCH 300/390] Adds wlmtk_window_request_maximize function and tests. --- src/toolkit/window.c | 155 +++++++++++++++++++++++++++++++++++++------ src/toolkit/window.h | 35 ++++++++++ 2 files changed, 168 insertions(+), 22 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index fbb2d4cc..70419514 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -23,6 +23,8 @@ #include "rectangle.h" #include "workspace.h" +#include "wlr/util/box.h" + /* == Declarations ========================================================= */ /** Maximum number of pending state updates. */ @@ -49,19 +51,19 @@ struct _wlmtk_window_vmt_t { int x, int y, int width, int height); }; -/** Pending positional updates. */ +/** Pending positional updates for @ref wlmtk_window_t::content_ptr. */ typedef struct { /** Node within @ref wlmtk_window_t::pending_updates. */ bs_dllist_node_t dlnode; /** Serial of the update. */ uint32_t serial; - /** Pending X position. */ + /** Pending X position of the content. */ int x; - /** Pending Y position. */ + /** Pending Y position of the content. */ int y; - /** Width that is to be committed at serial. */ + /** Content's width that is to be committed at serial. */ unsigned width; - /** Height that is to be committed at serial. */ + /** Content's hehight that is to be committed at serial. */ unsigned height; } wlmtk_pending_update_t; @@ -97,6 +99,11 @@ struct _wlmtk_window_t { /** Pre-alloocated updates. */ wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; + /** Organic size of the window, ie. when not maximized. */ + struct wlr_box organic_size; + /** Whether the window has been requested as maximized. */ + bool maximized; + /** * Stores whether the window is server-side decorated. * @@ -149,6 +156,7 @@ static wlmtk_pending_update_t *_wlmtk_window_prepare_update( static void _wlmtk_window_release_update( wlmtk_window_t *window_ptr, wlmtk_pending_update_t *update_ptr); +static wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr); /* == Data ================================================================= */ @@ -268,6 +276,13 @@ void wlmtk_window_get_size( void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) { bs_dllist_node_t *dlnode_ptr; + + if (NULL == window_ptr->pending_updates.head_ptr) { + window_ptr->organic_size = wlmtk_element_get_dimensions_box( + wlmtk_window_element(window_ptr)); + return; + } + while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( dlnode_ptr, wlmtk_pending_update_t, dlnode); @@ -442,6 +457,51 @@ void wlmtk_window_request_position_and_size( { window_ptr->vmt.request_position_and_size( window_ptr, x, y, width, height); + + window_ptr->organic_size.x = x; + window_ptr->organic_size.y = y; + window_ptr->organic_size.width = width; + window_ptr->organic_size.height = height; +} + +/* ------------------------------------------------------------------------- */ +struct wlr_box wlmtk_window_get_position_and_size( + wlmtk_window_t *window_ptr) +{ + struct wlr_box box; + + wlmtk_element_get_position( + wlmtk_window_element(window_ptr), &box.x, &box.y); + wlmtk_window_get_size(window_ptr, &box.width, &box.height); + return box; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized) +{ + if (window_ptr->maximized == maximized) return; + + window_ptr->maximized = maximized; + + struct wlr_box box; + if (window_ptr->maximized) { + box = wlmtk_workspace_get_maximize_extents( + _wlmtk_window_workspace(window_ptr)); + } else { + box = window_ptr->organic_size; + } + + uint32_t serial = wlmtk_content_request_size( + window_ptr->content_ptr, box.width, box.height); + wlmtk_pending_update_t *pending_update_ptr = + _wlmtk_window_prepare_update(window_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = box.x; + pending_update_ptr->y = box.y; + pending_update_ptr->width = box.width; + pending_update_ptr->height = box.height; } /* == Local (static) methods =============================================== */ @@ -583,11 +643,7 @@ bool _wlmtk_window_element_pointer_button( element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); // We shouldn't receive buttons when not mapped. - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); + wlmtk_workspace_t *workspace_ptr = _wlmtk_window_workspace(window_ptr); wlmtk_workspace_activate_window(workspace_ptr, window_ptr); wlmtk_workspace_raise_window(workspace_ptr, window_ptr); @@ -654,24 +710,16 @@ void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) /** Default implementation of @ref wlmtk_window_request_move. */ void _wlmtk_window_request_move(wlmtk_window_t *window_ptr) { - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); + wlmtk_workspace_begin_window_move( + _wlmtk_window_workspace(window_ptr), window_ptr); } /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_resize. */ void _wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) { - BS_ASSERT( - NULL != - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_from_container( - window_ptr->super_bordered.super_container.super_element.parent_container_ptr); - wlmtk_workspace_begin_window_resize(workspace_ptr, window_ptr, edges); + wlmtk_workspace_begin_window_resize( + _wlmtk_window_workspace(window_ptr), window_ptr, edges); } /* ------------------------------------------------------------------------- */ @@ -742,6 +790,15 @@ void _wlmtk_window_release_update( bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); } +/* ------------------------------------------------------------------------- */ +/** Returns the workspace of the (mapped) window. */ +wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(NULL != wlmtk_window_element(window_ptr)->parent_container_ptr); + return wlmtk_workspace_from_container( + wlmtk_window_element(window_ptr)->parent_container_ptr); +} + /* == Implementation of the fake window ==================================== */ static void _wlmtk_fake_window_set_activated( @@ -886,6 +943,7 @@ static void test_set_title(bs_test_t *test_ptr); static void test_request_close(bs_test_t *test_ptr); static void test_set_activated(bs_test_t *test_ptr); static void test_server_side_decorated(bs_test_t *test_ptr); +static void test_maximize(bs_test_t *test_ptr); static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { @@ -894,6 +952,7 @@ const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "request_close", test_request_close }, { 1, "set_activated", test_set_activated }, { 1, "set_server_side_decorated", test_server_side_decorated }, + { 1, "maximize", test_maximize }, { 1, "fake", test_fake }, { 0, NULL, NULL } }; @@ -987,6 +1046,58 @@ void test_server_side_decorated(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests maximizing and un-maximizing a window. */ +void test_maximize(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + NULL, fake_parent_ptr->wlr_scene_tree_ptr); + struct wlr_box extents = { .width = 1024, .height = 768 }, box; + wlmtk_workspace_set_extents(workspace_ptr, &extents); + BS_ASSERT(NULL != workspace_ptr); + + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + BS_ASSERT(NULL != window_ptr); + // Window must be mapped to get maximized: Need workspace dimensions. + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + + // Set up initial organic size, and verify. + wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Maximize. + wlmtk_window_request_maximize(window_ptr, true); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); + + // Unmaximize. Restore earlier organic size and position. + wlmtk_window_request_maximize(window_ptr, false); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_window_destroy(window_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); +} + /* ------------------------------------------------------------------------- */ /** Tests fake window ctor and dtor. */ void test_fake(bs_test_t *test_ptr) diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 274d1ef1..dff592d4 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -173,6 +173,23 @@ void wlmtk_window_request_move(wlmtk_window_t *window_ptr); void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges); +/** + * Reuests the window to be maximized. + * + * Requires the window to be mapped (to a workspace). Will lookup the maximize + * extents from the workspace, and request a corresponding updated position and + * size for the window. @ref wlmtk_window_t::organic_size will not be updated. + * + * This may be implemented as an asynchronous operation. Maximization will be + * applied once the size change has been committed by the content. + * + * @param window_ptr + * @param maximized + */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized); + /** * Requests a new size for the window, including potential decorations. * @@ -194,6 +211,8 @@ void wlmtk_window_request_size( * This may be implemented as an asynchronous operation. The re-positioning * will be applied only once the size change has been committed by the client. * + * The position and size will be stored in @ref wlmtk_window_t::organic_size. + * * @param window_ptr * @param x * @param y @@ -207,6 +226,17 @@ void wlmtk_window_request_position_and_size( int width, int height); +/** + * Returns the current position and size of the window. + * + * @param window_ptr + * + * @return The position of the window (the window's element), and the currently + * committed width and height of the window. + */ +struct wlr_box wlmtk_window_get_position_and_size( + wlmtk_window_t *window_ptr); + /** * Updates the window state to what was requested at the `serial`. * @@ -217,6 +247,11 @@ void wlmtk_window_request_position_and_size( * Only then, the corresponding positional update on the top/left edges are * supposed to be applied. * + * @ref wlmtk_window_t::organic_size will be updated, if there was no pending + * update: Meaning that the commit originated not from an earlier + * @ref wlmtk_window_request_position_and_size or @ref + * wlmtk_window_request_maximize call. + * * @param window_ptr * @param serial */ From 28597e573c88a3eae2ca8822d8615d7a59055816 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:53:59 +0100 Subject: [PATCH 301/390] Adds wlmtk_workspace_set_extents to wrap to wlmtk. --- src/workspace.c | 14 ++++++++++++++ src/workspace.h | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/workspace.c b/src/workspace.c index 021602d1..ffcf8cff 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -433,6 +433,20 @@ const bs_dllist_t *wlmaker_workspace_get_views_dllist( return &workspace_ptr->views; } +/* ------------------------------------------------------------------------- */ +void wlmaker_workspace_set_extents( + wlmaker_workspace_t *workspace_ptr, + const struct wlr_box *extents_ptr) +{ +#if defined(ENABLE_TOOLKIT_PROTOTYPE) + wlmtk_workspace_set_extents(workspace_ptr->wlmtk_workspace_ptr, + extents_ptr); +#else + workspace_ptr = workspace_ptr; + extents_ptr = extents_ptr; +#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) +} + /* ------------------------------------------------------------------------- */ void wlmaker_workspace_arrange_views(wlmaker_workspace_t *workspace_ptr) { diff --git a/src/workspace.h b/src/workspace.h index eb0fdfbf..783d1243 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -189,6 +189,18 @@ void wlmaker_workspace_activate_previous_view( const bs_dllist_t *wlmaker_workspace_get_views_dllist( wlmaker_workspace_t *workspace_ptr); +/** + * Sets extents of the workspace. + * + * TODO(kaeser@gubbe.ch): Should re-trigger re-arranging. + * + * @param workspace_ptr + * @param extents_ptr + */ +void wlmaker_workspace_set_extents( + wlmaker_workspace_t *workspace_ptr, + const struct wlr_box *extents_ptr); + /** * (Re)arranges the views in the workspace. * From c765397a2f90a4f241c053b6800acc843a1b470b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:54:19 +0100 Subject: [PATCH 302/390] Updates workspace extents on layout callback. --- src/server.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/server.c b/src/server.c index 7883bed1..2196abd9 100644 --- a/src/server.c +++ b/src/server.c @@ -83,6 +83,9 @@ static void handle_destroy_input_device( static void handle_output_layout_change( struct wl_listener *listener_ptr, void *data_ptr); +static void set_extents( + bs_dllist_node_t *dlnode_ptr, + void *ud_ptr); static void arrange_views( bs_dllist_node_t *dlnode_ptr, void *ud_ptr); @@ -727,9 +730,24 @@ void handle_output_layout_change( bs_log(BS_INFO, "Output layout change: Pos %d, %d (%d x %d).", extents.x, extents.y, extents.width, extents.height); + bs_dllist_for_each(&server_ptr->workspaces, set_extents, &extents); bs_dllist_for_each(&server_ptr->workspaces, arrange_views, NULL); } +/* ------------------------------------------------------------------------- */ +/** + * Callback for `bs_dllist_for_each` to set extents of the workspace. + * + * @param dlnode_ptr + * @param ud_ptr + */ +void set_extents(bs_dllist_node_t *dlnode_ptr, void *ud_ptr) +{ + struct wlr_box *extents_ptr = ud_ptr; + wlmaker_workspace_set_extents( + wlmaker_workspace_from_dlnode(dlnode_ptr), extents_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Callback for `bs_dllist_for_each` to arrange views in a workspace. From 485a314e1a2f7717b7a180b037a202f31d1358c6 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:54:41 +0100 Subject: [PATCH 303/390] Adds wlmtk_window_maximized. --- src/toolkit/window.c | 9 +++++++++ src/toolkit/window.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 70419514..e5c1ab96 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -504,6 +504,12 @@ void wlmtk_window_request_maximize( pending_update_ptr->height = box.height; } +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) +{ + return window_ptr->maximized; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -1073,6 +1079,7 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); // Maximize. wlmtk_window_request_maximize(window_ptr, true); @@ -1082,6 +1089,7 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); // Unmaximize. Restore earlier organic size and position. wlmtk_window_request_maximize(window_ptr, false); @@ -1091,6 +1099,7 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index dff592d4..71ac5f72 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -190,6 +190,9 @@ void wlmtk_window_request_maximize( wlmtk_window_t *window_ptr, bool maximized); +/** Returns whether the window is currently (requested to be) maximized. */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); + /** * Requests a new size for the window, including potential decorations. * From 139b9d10a02e2f7a8e2cee3d2c03c27fc8f794cb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 19 Dec 2023 21:55:38 +0100 Subject: [PATCH 304/390] Wires up the 'maximize' signal for the window. Not all good yet, but data is passed on. --- src/wlmtk_xdg_toplevel.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index db550db7..db95981b 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -44,6 +44,8 @@ typedef struct { /** Listener for the `commit` signal of the `wlr_surface`. */ struct wl_listener surface_commit_listener; + /** Listener for `maximize` signal of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_request_maximize_listener; /** Listener for `request_move` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_move_listener; /** Listener for `request_resize` signal of `wlr_xdg_toplevel::events`. */ @@ -70,6 +72,9 @@ static void handle_surface_unmap( static void handle_surface_commit( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_request_maximize( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_toplevel_request_move( struct wl_listener *listener_ptr, void *data_ptr); @@ -172,6 +177,10 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &xdg_tl_content_ptr->surface_commit_listener, handle_surface_commit); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.request_maximize, + &xdg_tl_content_ptr->toplevel_request_maximize_listener, + handle_toplevel_request_maximize); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_move, &xdg_tl_content_ptr->toplevel_request_move_listener, @@ -203,6 +212,7 @@ void xdg_toplevel_content_destroy( &xdg_tl_content_ptr->toplevel_set_title_listener.link); wl_list_remove(&xdg_tl_content_ptr->toplevel_request_resize_listener.link); wl_list_remove(&xdg_tl_content_ptr->toplevel_request_move_listener.link); + wl_list_remove(&xdg_tl_content_ptr->toplevel_request_maximize_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_commit_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); @@ -417,6 +427,26 @@ void handle_surface_commit( xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.height); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `request_maximize` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_request_maximize( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_content_t, + toplevel_request_maximize_listener); + wlmtk_window_request_maximize( + xdg_tl_content_ptr->super_content.window_ptr, + !wlmtk_window_maximized(xdg_tl_content_ptr->super_content.window_ptr)); +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `request_move` signal. From 8996e9fea0c168e1cc3a1314aec260a8b20e3f06 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 20:57:05 +0100 Subject: [PATCH 305/390] Fixes overwrites of organic size when multiple commits came on maximized state. --- src/toolkit/window.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index e5c1ab96..40d87f91 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -277,7 +277,8 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) { bs_dllist_node_t *dlnode_ptr; - if (NULL == window_ptr->pending_updates.head_ptr) { + if (!window_ptr->maximized && + NULL == window_ptr->pending_updates.head_ptr) { window_ptr->organic_size = wlmtk_element_get_dimensions_box( wlmtk_window_element(window_ptr)); return; @@ -1091,6 +1092,9 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); + // A second commit: should not overwrite the organic dimension. + wlmtk_fake_content_commit(fake_content_ptr); + // Unmaximize. Restore earlier organic size and position. wlmtk_window_request_maximize(window_ptr, false); wlmtk_fake_content_commit(fake_content_ptr); From b8c855a53f1fadd64b63f44050dee472596df884 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 21:13:49 +0100 Subject: [PATCH 306/390] Window corrects content size by the decoration, margin and borders. --- src/toolkit/window.c | 33 ++++++++++++++++++++++++--------- src/toolkit/workspace.c | 9 +++++---- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 40d87f91..a992653d 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -270,6 +270,16 @@ void wlmtk_window_get_size( { // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); + + if (NULL != window_ptr->titlebar_ptr) { + *height_ptr += titlebar_style.height + margin_style.width; + } + if (NULL != window_ptr->resizebar_ptr) { + *height_ptr += resizebar_style.height + margin_style.width; + } + *height_ptr += 2 * border_style.width; + + *width_ptr += 2 * border_style.width; } /* ------------------------------------------------------------------------- */ @@ -494,15 +504,8 @@ void wlmtk_window_request_maximize( box = window_ptr->organic_size; } - uint32_t serial = wlmtk_content_request_size( - window_ptr->content_ptr, box.width, box.height); - wlmtk_pending_update_t *pending_update_ptr = - _wlmtk_window_prepare_update(window_ptr); - pending_update_ptr->serial = serial; - pending_update_ptr->x = box.x; - pending_update_ptr->y = box.y; - pending_update_ptr->width = box.width; - pending_update_ptr->height = box.height; + _wlmtk_window_request_position_and_size( + window_ptr, box.x, box.y, box.width, box.height); } /* ------------------------------------------------------------------------- */ @@ -738,6 +741,18 @@ void _wlmtk_window_request_position_and_size( int width, int height) { + // Correct for borders, margin and decoration. + if (NULL != window_ptr->titlebar_ptr) { + height -= titlebar_style.height + margin_style.width; + } + if (NULL != window_ptr->resizebar_ptr) { + height -= resizebar_style.height + margin_style.width; + } + height -= 2 * border_style.width; + width -= 2 * border_style.width; + height = BS_MAX(0, height); + width = BS_MAX(0, width); + uint32_t serial = wlmtk_content_request_size( window_ptr->content_ptr, width, height); diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index c7b4fb36..242f736a 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -841,10 +841,11 @@ void test_resize(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_content_commit_size(&fake_content_ptr->content, 1, 40, 20); wlmtk_window_t *window_ptr = wlmtk_window_create( NULL, &fake_content_ptr->content); BS_ASSERT(NULL != window_ptr); + wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); + wlmtk_fake_content_commit(fake_content_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); wlmtk_workspace_map_window(workspace_ptr, window_ptr); @@ -862,10 +863,10 @@ void test_resize(bs_test_t *test_ptr) wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); - BS_TEST_VERIFY_EQ(test_ptr, 39, fake_content_ptr->requested_width); - BS_TEST_VERIFY_EQ(test_ptr, 18, fake_content_ptr->requested_height); + BS_TEST_VERIFY_EQ(test_ptr, 37, fake_content_ptr->requested_width); + BS_TEST_VERIFY_EQ(test_ptr, 16, fake_content_ptr->requested_height); // This updates for the given serial. - wlmtk_content_commit_size(&fake_content_ptr->content, 1, 39, 18); + wlmtk_fake_content_commit(fake_content_ptr); wlmtk_window_get_size(window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); From 2f05a59fe0999eb75b3f3eba927daf3f999a9e8b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 21:33:19 +0100 Subject: [PATCH 307/390] Adds wlmtk_window_set_position for organically setting the window position. --- src/toolkit/window.c | 28 +++++++++++++++++++++++++--- src/toolkit/window.h | 10 ++++++++++ src/toolkit/workspace.c | 8 ++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a992653d..f87ca83d 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -289,8 +289,12 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) if (!window_ptr->maximized && NULL == window_ptr->pending_updates.head_ptr) { - window_ptr->organic_size = wlmtk_element_get_dimensions_box( + // The element's dimensions does not matter for window positioning, + // thus only store width & height. + struct wlr_box box = wlmtk_element_get_dimensions_box( wlmtk_window_element(window_ptr)); + window_ptr->organic_size.width = box.width; + window_ptr->organic_size.height = box.height; return; } @@ -441,6 +445,14 @@ void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, window_ptr->vmt.request_resize(window_ptr, edges); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y) +{ + window_ptr->organic_size.x = x; + window_ptr->organic_size.y = y; + wlmtk_element_set_position(wlmtk_window_element(window_ptr), x, y); +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_size( wlmtk_window_t *window_ptr, @@ -473,6 +485,10 @@ void wlmtk_window_request_position_and_size( window_ptr->organic_size.y = y; window_ptr->organic_size.width = width; window_ptr->organic_size.height = height; + + bs_log(BS_ERROR, "FIXME: %d, %d at %d x %d", + window_ptr->organic_size.x, window_ptr->organic_size.y, + window_ptr->organic_size.width, window_ptr->organic_size.height); } /* ------------------------------------------------------------------------- */ @@ -1097,6 +1113,12 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); + // Re-position the window. + wlmtk_window_set_position(window_ptr, 50, 30); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + // Maximize. wlmtk_window_request_maximize(window_ptr, true); wlmtk_fake_content_commit(fake_content_ptr); @@ -1114,8 +1136,8 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_window_request_maximize(window_ptr, false); wlmtk_fake_content_commit(fake_content_ptr); box = wlmtk_window_get_position_and_size(window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 71ac5f72..a4eed71e 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -193,6 +193,16 @@ void wlmtk_window_request_maximize( /** Returns whether the window is currently (requested to be) maximized. */ bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); +/** + * Sets the window's position. This is a synchronous operation. + * + * Updates the position in @ref wlmtk_window_t::organic_size. + * @param window_ptr + * @param x + * @param y + */ +void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y); + /** * Requests a new size for the window, including potential decorations. * diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 242f736a..00c29529 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -498,8 +498,8 @@ bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) double rel_y = workspace_ptr->super_container.super_element.last_pointer_y - workspace_ptr->motion_y; - wlmtk_element_set_position( - wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + wlmtk_window_set_position( + workspace_ptr->grabbed_window_ptr, workspace_ptr->initial_x + rel_x, workspace_ptr->initial_y + rel_y); @@ -901,7 +901,7 @@ void test_activate(bs_test_t *test_ptr) // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_element_set_position(wlmtk_window_element(fw1_ptr->window_ptr), 0, 0); + wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); // Window 1 is mapped => it's activated. @@ -912,7 +912,7 @@ void test_activate(bs_test_t *test_ptr) // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_element_set_position(wlmtk_window_element(fw2_ptr->window_ptr), 200, 0); + wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); From 5bafe072e2b55d5fdabec5a8cca017bf5711344d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 21:41:35 +0100 Subject: [PATCH 308/390] Fixes organic size storage on late serial() calls. --- src/toolkit/window.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f87ca83d..5f2a942d 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -289,12 +289,9 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) if (!window_ptr->maximized && NULL == window_ptr->pending_updates.head_ptr) { - // The element's dimensions does not matter for window positioning, - // thus only store width & height. - struct wlr_box box = wlmtk_element_get_dimensions_box( - wlmtk_window_element(window_ptr)); - window_ptr->organic_size.width = box.width; - window_ptr->organic_size.height = box.height; + wlmtk_window_get_size(window_ptr, + &window_ptr->organic_size.width, + &window_ptr->organic_size.height); return; } @@ -485,10 +482,6 @@ void wlmtk_window_request_position_and_size( window_ptr->organic_size.y = y; window_ptr->organic_size.width = width; window_ptr->organic_size.height = height; - - bs_log(BS_ERROR, "FIXME: %d, %d at %d x %d", - window_ptr->organic_size.x, window_ptr->organic_size.y, - window_ptr->organic_size.width, window_ptr->organic_size.height); } /* ------------------------------------------------------------------------- */ @@ -1118,6 +1111,16 @@ void test_maximize(bs_test_t *test_ptr) box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Trigger another serial update. Should not change position nor size. + wlmtk_window_serial(window_ptr, 1234); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); // Maximize. wlmtk_window_request_maximize(window_ptr, true); From ba39f45f138cb27bef3ad7c4cc29bc508c50ae7b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 21:45:35 +0100 Subject: [PATCH 309/390] Adds a TODO regarding the handling of maximized windows when moving. --- src/toolkit/window.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 5f2a942d..d686b8f5 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -1145,6 +1145,11 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); + // TODO(kaeser@gubbe.ch): Define what should happen when a maximized + // window is moved. Should it lose maximization? Should it not move? + // Or just move on? + // Window Maker keeps maximization, but it's ... odd. + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); From c19c683ead934207c728547cba029864a06ba141 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 21:51:09 +0100 Subject: [PATCH 310/390] Reorders the window functions in .h and .c for alignment. --- src/toolkit/window.c | 250 +++++++++++++++++++++---------------------- src/toolkit/window.h | 86 +++++++-------- 2 files changed, 168 insertions(+), 168 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d686b8f5..ef8c62f9 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -263,100 +263,11 @@ wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) } /* ------------------------------------------------------------------------- */ -void wlmtk_window_get_size( - wlmtk_window_t *window_ptr, - int *width_ptr, - int *height_ptr) -{ - // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); - - if (NULL != window_ptr->titlebar_ptr) { - *height_ptr += titlebar_style.height + margin_style.width; - } - if (NULL != window_ptr->resizebar_ptr) { - *height_ptr += resizebar_style.height + margin_style.width; - } - *height_ptr += 2 * border_style.width; - - *width_ptr += 2 * border_style.width; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) -{ - bs_dllist_node_t *dlnode_ptr; - - if (!window_ptr->maximized && - NULL == window_ptr->pending_updates.head_ptr) { - wlmtk_window_get_size(window_ptr, - &window_ptr->organic_size.width, - &window_ptr->organic_size.height); - return; - } - - while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { - wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); - - int32_t delta = pending_update_ptr->serial - serial; - if (0 < delta) break; - - if (pending_update_ptr->serial == serial) { - if (window_ptr->content_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (window_ptr->content_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); - } - } - - wlmtk_element_set_position( - wlmtk_window_element(window_ptr), - pending_update_ptr->x, - pending_update_ptr->y); - _wlmtk_window_release_update(window_ptr, pending_update_ptr); - } -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_set_title( +void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, - const char *title_ptr) -{ - char *new_title_ptr = NULL; - if (NULL != title_ptr) { - new_title_ptr = logged_strdup(title_ptr); - BS_ASSERT(NULL != new_title_ptr); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), "Unnamed window %p", window_ptr); - new_title_ptr = logged_strdup(buf); - BS_ASSERT(NULL != new_title_ptr); - } - - if (NULL != window_ptr->title_ptr) { - if (0 == strcmp(window_ptr->title_ptr, new_title_ptr)) { - free(new_title_ptr); - return; - } - free(window_ptr->title_ptr); - } - window_ptr->title_ptr = new_title_ptr; - - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, - window_ptr->title_ptr); - } -} - -/* ------------------------------------------------------------------------- */ -const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr) + bool activated) { - BS_ASSERT(NULL != window_ptr->title_ptr); - return window_ptr->title_ptr; + window_ptr->vmt.set_activated(window_ptr, activated); } /* ------------------------------------------------------------------------- */ @@ -410,11 +321,41 @@ void wlmtk_window_set_server_side_decorated( } /* ------------------------------------------------------------------------- */ -void wlmtk_window_set_activated( +void wlmtk_window_set_title( wlmtk_window_t *window_ptr, - bool activated) + const char *title_ptr) { - window_ptr->vmt.set_activated(window_ptr, activated); + char *new_title_ptr = NULL; + if (NULL != title_ptr) { + new_title_ptr = logged_strdup(title_ptr); + BS_ASSERT(NULL != new_title_ptr); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), "Unnamed window %p", window_ptr); + new_title_ptr = logged_strdup(buf); + BS_ASSERT(NULL != new_title_ptr); + } + + if (NULL != window_ptr->title_ptr) { + if (0 == strcmp(window_ptr->title_ptr, new_title_ptr)) { + free(new_title_ptr); + return; + } + free(window_ptr->title_ptr); + } + window_ptr->title_ptr = new_title_ptr; + + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, + window_ptr->title_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(NULL != window_ptr->title_ptr); + return window_ptr->title_ptr; } /* ------------------------------------------------------------------------- */ @@ -429,6 +370,33 @@ void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) window_ptr->vmt.request_minimize(window_ptr); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized) +{ + if (window_ptr->maximized == maximized) return; + + window_ptr->maximized = maximized; + + struct wlr_box box; + if (window_ptr->maximized) { + box = wlmtk_workspace_get_maximize_extents( + _wlmtk_window_workspace(window_ptr)); + } else { + box = window_ptr->organic_size; + } + + _wlmtk_window_request_position_and_size( + window_ptr, box.x, box.y, box.width, box.height); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) +{ + return window_ptr->maximized; +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { @@ -450,6 +418,26 @@ void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y) wlmtk_element_set_position(wlmtk_window_element(window_ptr), x, y); } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr) +{ + // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. + wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); + + if (NULL != window_ptr->titlebar_ptr) { + *height_ptr += titlebar_style.height + margin_style.width; + } + if (NULL != window_ptr->resizebar_ptr) { + *height_ptr += resizebar_style.height + margin_style.width; + } + *height_ptr += 2 * border_style.width; + + *width_ptr += 2 * border_style.width; +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_size( wlmtk_window_t *window_ptr, @@ -467,6 +455,18 @@ void wlmtk_window_request_size( // may need to combine the request_size and set_position methods for window. } +/* ------------------------------------------------------------------------- */ +struct wlr_box wlmtk_window_get_position_and_size( + wlmtk_window_t *window_ptr) +{ + struct wlr_box box; + + wlmtk_element_get_position( + wlmtk_window_element(window_ptr), &box.x, &box.y); + wlmtk_window_get_size(window_ptr, &box.width, &box.height); + return box; +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_position_and_size( wlmtk_window_t *window_ptr, @@ -485,42 +485,42 @@ void wlmtk_window_request_position_and_size( } /* ------------------------------------------------------------------------- */ -struct wlr_box wlmtk_window_get_position_and_size( - wlmtk_window_t *window_ptr) +void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) { - struct wlr_box box; - - wlmtk_element_get_position( - wlmtk_window_element(window_ptr), &box.x, &box.y); - wlmtk_window_get_size(window_ptr, &box.width, &box.height); - return box; -} + bs_dllist_node_t *dlnode_ptr; -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_maximize( - wlmtk_window_t *window_ptr, - bool maximized) -{ - if (window_ptr->maximized == maximized) return; + if (!window_ptr->maximized && + NULL == window_ptr->pending_updates.head_ptr) { + wlmtk_window_get_size(window_ptr, + &window_ptr->organic_size.width, + &window_ptr->organic_size.height); + return; + } - window_ptr->maximized = maximized; + while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { + wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); - struct wlr_box box; - if (window_ptr->maximized) { - box = wlmtk_workspace_get_maximize_extents( - _wlmtk_window_workspace(window_ptr)); - } else { - box = window_ptr->organic_size; - } + int32_t delta = pending_update_ptr->serial - serial; + if (0 < delta) break; - _wlmtk_window_request_position_and_size( - window_ptr, box.x, box.y, box.width, box.height); -} + if (pending_update_ptr->serial == serial) { + if (window_ptr->content_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (window_ptr->content_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } + } -/* ------------------------------------------------------------------------- */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) -{ - return window_ptr->maximized; + wlmtk_element_set_position( + wlmtk_window_element(window_ptr), + pending_update_ptr->x, + pending_update_ptr->y); + _wlmtk_window_release_update(window_ptr, pending_update_ptr); + } } /* == Local (static) methods =============================================== */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index a4eed71e..fb99b4cd 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -79,18 +79,6 @@ wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); */ wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr); -/** - * Obtains the size of the window, including potential decorations. - * - * @param window_ptr - * @param width_ptr May be NULL. - * @param height_ptr May be NULL. - */ -void wlmtk_window_get_size( - wlmtk_window_t *window_ptr, - int *width_ptr, - int *height_ptr); - /** * Sets the window as activated, depending on the argument's value. * @@ -151,6 +139,26 @@ void wlmtk_window_request_close(wlmtk_window_t *window_ptr); */ void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); +/** + * Reuests the window to be maximized. + * + * Requires the window to be mapped (to a workspace). Will lookup the maximize + * extents from the workspace, and request a corresponding updated position and + * size for the window. @ref wlmtk_window_t::organic_size will not be updated. + * + * This may be implemented as an asynchronous operation. Maximization will be + * applied once the size change has been committed by the content. + * + * @param window_ptr + * @param maximized + */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized); + +/** Returns whether the window is currently (requested to be) maximized. */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); + /** * Requests a move for the window. * @@ -173,26 +181,6 @@ void wlmtk_window_request_move(wlmtk_window_t *window_ptr); void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges); -/** - * Reuests the window to be maximized. - * - * Requires the window to be mapped (to a workspace). Will lookup the maximize - * extents from the workspace, and request a corresponding updated position and - * size for the window. @ref wlmtk_window_t::organic_size will not be updated. - * - * This may be implemented as an asynchronous operation. Maximization will be - * applied once the size change has been committed by the content. - * - * @param window_ptr - * @param maximized - */ -void wlmtk_window_request_maximize( - wlmtk_window_t *window_ptr, - bool maximized); - -/** Returns whether the window is currently (requested to be) maximized. */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); - /** * Sets the window's position. This is a synchronous operation. * @@ -203,6 +191,18 @@ bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); */ void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y); +/** + * Obtains the size of the window, including potential decorations. + * + * @param window_ptr + * @param width_ptr May be NULL. + * @param height_ptr May be NULL. + */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr); + /** * Requests a new size for the window, including potential decorations. * @@ -217,6 +217,17 @@ void wlmtk_window_request_size( int width, int height); +/** + * Returns the current position and size of the window. + * + * @param window_ptr + * + * @return The position of the window (the window's element), and the currently + * committed width and height of the window. + */ +struct wlr_box wlmtk_window_get_position_and_size( + wlmtk_window_t *window_ptr); + /** * Requests an updated position and size for the window, including potential * decorations. @@ -239,17 +250,6 @@ void wlmtk_window_request_position_and_size( int width, int height); -/** - * Returns the current position and size of the window. - * - * @param window_ptr - * - * @return The position of the window (the window's element), and the currently - * committed width and height of the window. - */ -struct wlr_box wlmtk_window_get_position_and_size( - wlmtk_window_t *window_ptr); - /** * Updates the window state to what was requested at the `serial`. * From 93a5b9eb05fc670a5f438b2094f3e4b6bd5f351e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 21 Dec 2023 22:05:18 +0100 Subject: [PATCH 311/390] Fixes the positioning of the bodered element. --- src/toolkit/bordered.c | 25 +++++++++++++------------ src/toolkit/bordered.h | 3 +++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c index f66df1ee..b465f062 100644 --- a/src/toolkit/bordered.c +++ b/src/toolkit/bordered.c @@ -173,14 +173,15 @@ void _wlmtk_bordered_set_positions(wlmtk_bordered_t *bordered_ptr) if (NULL == bordered_ptr->western_border_rectangle_ptr) return; - wlmtk_element_get_position(bordered_ptr->element_ptr, &x_pos, &y_pos); + int margin = bordered_ptr->style.width; + wlmtk_element_get_dimensions( bordered_ptr->element_ptr, &x1, &y1, &x2, &y2); - x_pos -= x1; - y_pos -= y1; + x_pos = -x1 + margin; + y_pos = -y1 + margin; int width = x2 - x1; int height = y2 - y1; - int margin = bordered_ptr->style.width; + wlmtk_element_set_position(bordered_ptr->element_ptr, x_pos, y_pos); wlmtk_element_set_position( wlmtk_rectangle_element(bordered_ptr->northern_border_rectangle_ptr), @@ -259,16 +260,16 @@ void test_init_fini(bs_test_t *test_ptr) // Positions of border elements. test_rectangle_pos( test_ptr, bordered.northern_border_rectangle_ptr, - -12, -6, 104, 2); + 0, 0, 104, 2); test_rectangle_pos( test_ptr, bordered.eastern_border_rectangle_ptr, - 90, -4, 2, 20); + 102, 2, 2, 20); test_rectangle_pos( test_ptr, bordered.southern_border_rectangle_ptr, - -12, 16, 104, 2); + 0, 22, 104, 2); test_rectangle_pos( test_ptr, bordered.western_border_rectangle_ptr, - -12, -4, 2, 20); + 0, 2, 2, 20); // Update layout, test updated positions. fe_ptr->dimensions.width = 200; @@ -276,16 +277,16 @@ void test_init_fini(bs_test_t *test_ptr) wlmtk_container_update_layout(&bordered.super_container); test_rectangle_pos( test_ptr, bordered.northern_border_rectangle_ptr, - -12, -6, 204, 2); + 0, 0, 204, 2); test_rectangle_pos( test_ptr, bordered.eastern_border_rectangle_ptr, - 190, -4, 2, 120); + 202, 2, 2, 120); test_rectangle_pos( test_ptr, bordered.southern_border_rectangle_ptr, - -12, 116, 204, 2); + 0, 122, 204, 2); test_rectangle_pos( test_ptr, bordered.western_border_rectangle_ptr, - -12, -4, 2, 120); + 0, 2, 2, 120); wlmtk_bordered_fini(&bordered); diff --git a/src/toolkit/bordered.h b/src/toolkit/bordered.h index 84272b3e..0bfeb517 100644 --- a/src/toolkit/bordered.h +++ b/src/toolkit/bordered.h @@ -56,6 +56,9 @@ struct _wlmtk_bordered_t { /** * Initializes the bordered element. * + * The bordered element positions the element within such that north-western + * corner is at (0, 0). + * * @param bordered_ptr * @param env_ptr * @param element_ptr From a1f27aa4dd3deea014717e53857be59d3778c335 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Dec 2023 16:07:45 +0100 Subject: [PATCH 312/390] Fixes a few comments. --- src/toolkit/content.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 462de88d..001b4648 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -47,14 +47,14 @@ static bool element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, - __UNUSED__ uint32_t time_msec); + uint32_t time_msec); static bool element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); /* == Data ================================================================= */ -/** Method table for the container's virtual methods. */ +/** Method table for the element's virtual methods. */ static const wlmtk_element_vmt_t content_element_vmt = { .get_dimensions = element_get_dimensions, .get_pointer_area = element_get_pointer_area, From b4dd852754b6fb53679b7dc0bded808ad588a241 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Dec 2023 16:08:37 +0100 Subject: [PATCH 313/390] Adds boilerplate for wlmtk_surface_t, forking from wlmtk_content_t. No real functionality nor tests yet. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/surface.c | 323 +++++++++++++++++++++++++++++++++++++ src/toolkit/surface.h | 62 +++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 5 files changed, 389 insertions(+) create mode 100644 src/toolkit/surface.c create mode 100644 src/toolkit/surface.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index e26a9ba7..aacd623b 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -31,6 +31,7 @@ SET(PUBLIC_HEADER_FILES env.h fsm.h input.h + surface.h rectangle.h resizebar.h resizebar_area.h @@ -53,6 +54,7 @@ TARGET_SOURCES(toolkit PRIVATE fsm.c gfxbuf.c primitives.c + surface.c rectangle.c resizebar.c resizebar_area.c diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c new file mode 100644 index 00000000..5375373f --- /dev/null +++ b/src/toolkit/surface.c @@ -0,0 +1,323 @@ +/* ========================================================================= */ +/** + * @file surface.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "surface.h" + +#include "element.h" + +#define WLR_USE_UNSTABLE +#include +#include +#include +#undef WLR_USE_UNSTABLE + +/* == Declarations ========================================================= */ + +/** State of a `struct wlr_surface`, encapsuled for toolkit. */ +struct _wlmtk_surface_t { + /** Super class of the surface: An element. */ + wlmtk_element_t super_element; + /** Virtual method table of the super element before extending it. */ + wlmtk_element_vmt_t orig_super_element_vmt; + + /** The `struct wlr_surface` wrapped. */ + struct wlr_surface *wlr_surface_ptr; +}; + +static void _wlmtk_surface_element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); +static void _wlmtk_surface_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr); +static void _wlmtk_surface_element_pointer_leave(wlmtk_element_t *element_ptr); +static bool _wlmtk_surface_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec); +static bool _wlmtk_surface_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); + +/* == Data ================================================================= */ + +/** Method table for the element's virtual methods. */ +static const wlmtk_element_vmt_t surface_element_vmt = { + .get_dimensions = _wlmtk_surface_element_get_dimensions, + .get_pointer_area = _wlmtk_surface_element_get_pointer_area, + .pointer_leave = _wlmtk_surface_element_pointer_leave, + .pointer_motion = _wlmtk_surface_element_pointer_motion, + .pointer_button = _wlmtk_surface_element_pointer_button, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_surface_t *wlmtk_surface_create( + struct wlr_surface *wlr_surface_ptr, + wlmtk_env_t *env_ptr) +{ + wlmtk_surface_t *surface_ptr = logged_calloc(1, sizeof(wlmtk_surface_t)); + if (NULL == surface_ptr) return NULL; + + if (!wlmtk_element_init(&surface_ptr->super_element, env_ptr)) { + wlmtk_surface_destroy(surface_ptr); + return NULL; + } + surface_ptr->orig_super_element_vmt = wlmtk_element_extend( + &surface_ptr->super_element, &surface_element_vmt); + + surface_ptr->wlr_surface_ptr = wlr_surface_ptr; + return surface_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr) +{ + wlmtk_element_fini(&surface_ptr->super_element); + free(surface_ptr); +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of the element's get_dimensions method: Return dimensions. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void _wlmtk_surface_element_get_dimensions( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_surface_t, super_element); + + struct wlr_box box; + wlr_surface_get_extends(surface_ptr->wlr_surface_ptr, &box); + if (NULL != left_ptr) *left_ptr = box.x; + if (NULL != top_ptr) *top_ptr = box.y; + if (NULL != right_ptr) *right_ptr = box.width; + if (NULL != bottom_ptr) *bottom_ptr = box.height; +} + +/* ------------------------------------------------------------------------- */ +/** + * Overwrites the element's get_pointer_area method: Returns the extents of + * the surface and all subsurfaces. + * + * @param element_ptr + * @param left_ptr Leftmost position. May be NULL. + * @param top_ptr Topmost position. May be NULL. + * @param right_ptr Rightmost position. Ma be NULL. + * @param bottom_ptr Bottommost position. May be NULL. + */ +void _wlmtk_surface_element_get_pointer_area( + wlmtk_element_t *element_ptr, + int *left_ptr, + int *top_ptr, + int *right_ptr, + int *bottom_ptr) +{ + wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_surface_t, super_element); + + struct wlr_box box; + wlr_surface_get_extends(surface_ptr->wlr_surface_ptr, &box); + + if (NULL != left_ptr) *left_ptr = box.x; + if (NULL != top_ptr) *top_ptr = box.y; + if (NULL != right_ptr) *right_ptr = box.width - box.x; + if (NULL != bottom_ptr) *bottom_ptr = box.height - box.y; +} + +/* ------------------------------------------------------------------------- */ +/** + * Implements the element's leave method: If there's a WLR (sub)surface + * currently holding focus, that will be cleared. + * + * @param element_ptr + */ +void _wlmtk_surface_element_pointer_leave(wlmtk_element_t *element_ptr) +{ + wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_surface_t, super_element); + + // If the current surface's parent is our surface: clear it. + struct wlr_surface *focused_wlr_surface_ptr = + wlmtk_env_wlr_seat(surface_ptr->super_element.env_ptr + )->pointer_state.focused_surface; + if (NULL != focused_wlr_surface_ptr && + wlr_surface_get_root_surface(focused_wlr_surface_ptr) == + surface_ptr->wlr_surface_ptr) { + wlr_seat_pointer_clear_focus( + wlmtk_env_wlr_seat(surface_ptr->super_element.env_ptr)); + } +} + +/* ------------------------------------------------------------------------- */ +/** + * Pass pointer motion events to client's surface. + * + * Identifies the surface (or sub-surface) at the given coordinates, and pass + * on the motion event to that surface. If needed, will update the seat's + * pointer focus. + * + * @param element_ptr + * @param x Pointer horizontal position, relative to this + * element's node. + * @param y Pointer vertical position, relative to this + * element's node. + * @param time_msec + * + * @return Whether if the motion is within the area. + */ +bool _wlmtk_surface_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, + double y, + uint32_t time_msec) +{ + wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_surface_t, super_element); + + surface_ptr->orig_super_element_vmt.pointer_motion( + element_ptr, x, y, time_msec); + + if (NULL == surface_ptr->super_element.wlr_scene_node_ptr) return false; + + // Get the layout local coordinates of the node, so we can adjust the + // node-local (x, y) for the `wlr_scene_node_at` call. + int lx, ly; + if (!wlr_scene_node_coords( + surface_ptr->super_element.wlr_scene_node_ptr, &lx, &ly)) { + return false; + } + // Get the node below the cursor. Return if there's no buffer node. + double node_x, node_y; + struct wlr_scene_node *wlr_scene_node_ptr = wlr_scene_node_at( + surface_ptr->super_element.wlr_scene_node_ptr, + x + lx, y + ly, &node_x, &node_y); + + if (NULL == wlr_scene_node_ptr || + WLR_SCENE_NODE_BUFFER != wlr_scene_node_ptr->type) { + return false; + } + + struct wlr_scene_buffer *wlr_scene_buffer_ptr = + wlr_scene_buffer_from_node(wlr_scene_node_ptr); + struct wlr_scene_surface *wlr_scene_surface_ptr = + wlr_scene_surface_try_from_buffer(wlr_scene_buffer_ptr); + if (NULL == wlr_scene_surface_ptr) { + return false; + } + + BS_ASSERT(surface_ptr->wlr_surface_ptr == + wlr_surface_get_root_surface(wlr_scene_surface_ptr->surface)); + wlr_seat_pointer_notify_enter( + wlmtk_env_wlr_seat(surface_ptr->super_element.env_ptr), + wlr_scene_surface_ptr->surface, + node_x, node_y); + wlr_seat_pointer_notify_motion( + wlmtk_env_wlr_seat(surface_ptr->super_element.env_ptr), + time_msec, + node_x, node_y); + return true; +} + +/* ------------------------------------------------------------------------- */ +/** + * Passes pointer button event further to the focused surface, if any. + * + * The actual passing is handled by `wlr_seat`. Here we just verify that the + * currently-focused surface (or sub-surface) is part of this surface. + * + * @param element_ptr + * @param button_event_ptr + * + * @return Whether the button event was consumed. + */ +bool _wlmtk_surface_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_surface_t, super_element); + + // Complain if the surface isn't part of our responsibility. + struct wlr_surface *focused_wlr_surface_ptr = + wlmtk_env_wlr_seat(surface_ptr->super_element.env_ptr + )->pointer_state.focused_surface; + if (NULL == focused_wlr_surface_ptr) return false; + // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated window + // over to a non-activated window will trigger the condition here on the + // WLMTK_BUTTON_UP event. Needs a test and fixing. + BS_ASSERT(surface_ptr->wlr_surface_ptr == + wlr_surface_get_root_surface(focused_wlr_surface_ptr)); + + // We're only forwarding PRESSED & RELEASED events. + if (WLMTK_BUTTON_DOWN == button_event_ptr->type || + WLMTK_BUTTON_UP == button_event_ptr->type) { + wlr_seat_pointer_notify_button( + wlmtk_env_wlr_seat(surface_ptr->super_element.env_ptr), + button_event_ptr->time_msec, + button_event_ptr->button, + (button_event_ptr->type == WLMTK_BUTTON_DOWN) ? + WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); + return true; + } + return false; +} + +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_surface_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + wlmtk_surface_t *surface_ptr = wlmtk_surface_create(NULL, NULL); + + BS_TEST_VERIFY_NEQ(test_ptr, NULL, surface_ptr); + + wlmtk_surface_destroy(surface_ptr); +} + +/* == End of surface.c ===================================================== */ diff --git a/src/toolkit/surface.h b/src/toolkit/surface.h new file mode 100644 index 00000000..dfd761ee --- /dev/null +++ b/src/toolkit/surface.h @@ -0,0 +1,62 @@ +/* ========================================================================= */ +/** + * @file surface.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_SURFACE_H__ +#define __WLMTK_SURFACE_H__ + +#include + +#include "env.h" + +/** Forward declaration. */ +struct wlr_surface; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Forward declaration: State of a toolkit's WLR surface. */ +typedef struct _wlmtk_surface_t wlmtk_surface_t; + +/** + * Creates a surface. + * + * @param wlr_surface_ptr + * @param env_ptr + */ +wlmtk_surface_t *wlmtk_surface_create( + struct wlr_surface *wlr_surface_ptr, + wlmtk_env_t *env_ptr); + +/** + * Destroys the surface. + * + * @param surface_ptr + */ +void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr); + +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_surface_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_SURFACE_H__ */ +/* == End of surface.h ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index f4d301a6..1c1edf29 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -40,6 +40,7 @@ #include "env.h" #include "fsm.h" #include "input.h" +#include "surface.h" #include "rectangle.h" #include "resizebar.h" #include "resizebar_area.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 9ce37d5b..886bc141 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -29,6 +29,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, + { 1, "surface", wlmtk_surface_test_cases }, { 1, "rectangle", wlmtk_rectangle_test_cases }, { 1, "resizebar", wlmtk_resizebar_test_cases }, { 1, "resizebar_area", wlmtk_resizebar_area_test_cases }, From 5ef153b99f4bd818c9db8fc68e69fef1fca7de04 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Dec 2023 16:09:30 +0100 Subject: [PATCH 314/390] Adds a dummy handler for of wlmtk_xdg_toplevel. --- src/wlmtk_xdg_toplevel.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index db95981b..640a25f5 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -37,6 +37,8 @@ typedef struct { /** Listener for the `destroy` signal of the `wlr_xdg_surface::events`. */ struct wl_listener destroy_listener; + /** Listener for the `new_popup` signal of the `wlr_xdg_surface`. */ + struct wl_listener new_popup_listener; /** Listener for the `map` signal of the `wlr_surface`. */ struct wl_listener surface_map_listener; /** Listener for the `unmap` signal of the `wlr_surface`. */ @@ -63,6 +65,9 @@ static void xdg_toplevel_content_destroy( static void handle_destroy( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_new_popup( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_surface_map( struct wl_listener *listener_ptr, void *data_ptr); @@ -164,6 +169,10 @@ wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( &wlr_xdg_surface_ptr->events.destroy, &xdg_tl_content_ptr->destroy_listener, handle_destroy); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->events.new_popup, + &xdg_tl_content_ptr->new_popup_listener, + handle_new_popup); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.map, &xdg_tl_content_ptr->surface_map_listener, @@ -217,6 +226,7 @@ void xdg_toplevel_content_destroy( wl_list_remove(&xdg_tl_content_ptr->surface_commit_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); + wl_list_remove(&xdg_tl_content_ptr->new_popup_listener.link); wl_list_remove(&xdg_tl_content_ptr->destroy_listener.link); wlmtk_content_fini(&xdg_tl_content_ptr->super_content); @@ -358,6 +368,24 @@ void handle_destroy(struct wl_listener *listener_ptr, wlmtk_window_destroy(xdg_tl_content_ptr->super_content.window_ptr); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `new_popup` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_new_popup( + struct wl_listener *listener_ptr, + void *data_ptr) +{ + wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_content_t, new_popup_listener); + + bs_log(BS_WARNING, "FIXME: wlmtk_xdg_toplevel %p, New popup %p", + xdg_tl_content_ptr, data_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `map` signal. From 3f4549a43b72dd396cb4c5e99ec99555ccffa5b9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Dec 2023 16:10:14 +0100 Subject: [PATCH 315/390] Adds boilerplate for wlmtk_xdg_popup. Nothing there so far. --- src/CMakeLists.txt | 2 ++ src/wlmtk_xdg_popup.c | 36 +++++++++++++++++++++++++++++++++ src/wlmtk_xdg_popup.h | 47 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/wlmtk_xdg_popup.c create mode 100644 src/wlmtk_xdg_popup.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5aa0a083..c7a1a4ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,7 @@ SET(SOURCES tile_container.c titlebar.c view.c + wlmtk_xdg_popup.c wlmtk_xdg_toplevel.c workspace.c xdg_decoration.c @@ -74,6 +75,7 @@ SET(HEADERS tile.h titlebar.h view.h + wlmtk_xdg_popup.h wlmtk_xdg_toplevel.h workspace.h xdg_decoration.h diff --git a/src/wlmtk_xdg_popup.c b/src/wlmtk_xdg_popup.c new file mode 100644 index 00000000..a8d51f9e --- /dev/null +++ b/src/wlmtk_xdg_popup.c @@ -0,0 +1,36 @@ +/* ========================================================================= */ +/** + * @file wlmtk_xdg_popup.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wlmtk_xdg_popup.h" + +/* == Declarations ========================================================= */ + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +void wlmtk_create_popup( + __UNUSED__ struct wlr_xdg_popup *wlr_xdg_popup_ptr, + __UNUSED__ wlmtk_window_t *window_ptr) +{ +} + +/* == Local (static) methods =============================================== */ + +/* == End of wlmtk_xdg_popup.c ============================================= */ diff --git a/src/wlmtk_xdg_popup.h b/src/wlmtk_xdg_popup.h new file mode 100644 index 00000000..ad040758 --- /dev/null +++ b/src/wlmtk_xdg_popup.h @@ -0,0 +1,47 @@ +/* ========================================================================= */ +/** + * @file wlmtk_xdg_popup.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_XDG_POPUP_H__ +#define __WLMTK_XDG_POPUP_H__ + +#include "toolkit/toolkit.h" + +/** Forward declaration. */ +struct wlr_xdg_popup; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a popup. + * + * @param wlr_xdg_popup_ptr + * @param window_ptr + */ +void wlmtk_create_popup( + struct wlr_xdg_popup *wlr_xdg_popup_ptr, + wlmtk_window_t *window_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_XDG_POPUP_H__ */ +/* == End of wlmtk_xdg_popup.h ============================================= */ From 52f41b1dafd082ee1e52a84ea5e0fe1c7406e5dd Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 23 Dec 2023 16:11:45 +0100 Subject: [PATCH 316/390] Extend toolkit prototype to allow Google Chrome. Doesn't work yet. --- src/xdg_shell.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xdg_shell.c b/src/xdg_shell.c index fc05dead..41631214 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -133,7 +133,8 @@ void handle_new_surface(struct wl_listener *listener_ptr, break; } path_exe[rv] = '\0'; - if (0 == strcmp(path_exe, "/usr/bin/foot")) { + if (0 == strcmp(path_exe, "/usr/bin/foot") || + 0 == strcmp(path_exe, "/opt/google/chrome/chrome")) { wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", From 09393fe431e6c59aad7ad60312bd7f2ffe5ccaec Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 26 Dec 2023 14:33:38 +0100 Subject: [PATCH 317/390] Renames wlmtk_window to wlmtk_toplevel throughout. --- src/toolkit/CMakeLists.txt | 4 +- src/toolkit/content.c | 14 +- src/toolkit/content.h | 23 +- src/toolkit/resizebar.c | 20 +- src/toolkit/resizebar.h | 7 +- src/toolkit/resizebar_area.c | 26 +- src/toolkit/resizebar_area.h | 7 +- src/toolkit/titlebar.c | 28 +- src/toolkit/titlebar.h | 8 +- src/toolkit/titlebar_button.c | 30 +- src/toolkit/titlebar_button.h | 6 +- src/toolkit/titlebar_title.c | 22 +- src/toolkit/titlebar_title.h | 4 +- src/toolkit/toolkit.h | 2 +- src/toolkit/toolkit.md | 67 +- src/toolkit/toolkit_test.c | 2 +- src/toolkit/toplevel.c | 1168 +++++++++++++++++++++++++++++++++ src/toolkit/toplevel.h | 319 +++++++++ src/toolkit/window.c | 1168 --------------------------------- src/toolkit/window.h | 319 --------- src/toolkit/workspace.c | 266 ++++---- src/toolkit/workspace.h | 48 +- src/wlmtk_xdg_popup.c | 2 +- src/wlmtk_xdg_popup.h | 4 +- src/wlmtk_xdg_toplevel.c | 40 +- src/wlmtk_xdg_toplevel.h | 2 +- src/xdg_decoration.c | 4 +- src/xdg_shell.c | 6 +- 28 files changed, 1813 insertions(+), 1803 deletions(-) create mode 100644 src/toolkit/toplevel.c create mode 100644 src/toolkit/toplevel.h delete mode 100644 src/toolkit/window.c delete mode 100644 src/toolkit/window.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index aacd623b..3d9b8eaa 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -38,7 +38,7 @@ SET(PUBLIC_HEADER_FILES titlebar.h titlebar_button.h titlebar_title.h - window.h + toplevel.h workspace.h) ADD_LIBRARY(toolkit STATIC) @@ -62,7 +62,7 @@ TARGET_SOURCES(toolkit PRIVATE titlebar_button.c titlebar_title.c util.c - window.c + toplevel.c workspace.c) TARGET_INCLUDE_DIRECTORIES( toolkit PUBLIC diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 001b4648..b68cac63 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -113,11 +113,11 @@ void wlmtk_content_fini(wlmtk_content_t *content_ptr) } /* ------------------------------------------------------------------------- */ -void wlmtk_content_set_window( +void wlmtk_content_set_toplevel( wlmtk_content_t *content_ptr, - wlmtk_window_t *window_ptr) + wlmtk_toplevel_t *toplevel_ptr) { - content_ptr->window_ptr = window_ptr; + content_ptr->toplevel_ptr = toplevel_ptr; } /* ------------------------------------------------------------------------- */ @@ -133,8 +133,8 @@ void wlmtk_content_commit_size( content_ptr->committed_height = height; } - if (NULL != content_ptr->window_ptr) { - wlmtk_window_serial(content_ptr->window_ptr, serial); + if (NULL != content_ptr->toplevel_ptr) { + wlmtk_toplevel_serial(content_ptr->toplevel_ptr, serial); } if (NULL != content_ptr->super_element.parent_container_ptr) { @@ -344,8 +344,8 @@ bool element_pointer_button( wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr )->pointer_state.focused_surface; if (NULL == focused_wlr_surface_ptr) return false; - // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated window - // over to a non-activated window will trigger the condition here on the + // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated toplevel + // over to a non-activated toplevel will trigger the condition here on the // WLMTK_BUTTON_UP event. Needs a test and fixing. BS_ASSERT(content_ptr->wlr_surface_ptr == wlr_surface_get_root_surface(focused_wlr_surface_ptr)); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 569867dc..d37c52d1 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -20,7 +20,7 @@ #ifndef __WLMTK_CONTENT_H__ #define __WLMTK_CONTENT_H__ -/** Forward declaration: Window content. */ +/** Forward declaration: Toplevel content. */ typedef struct _wlmtk_content_t wlmtk_content_t; /** Forward declaration: Content virtual method table. */ @@ -28,8 +28,7 @@ typedef struct _wlmtk_content_vmt_t wlmtk_content_vmt_t; /** Forward declaration: Fake content, for tests. */ typedef struct _wlmtk_fake_content_t wlmtk_fake_content_t; - -#include "window.h" +#include "toplevel.h" #ifdef __cplusplus extern "C" { @@ -60,10 +59,10 @@ struct _wlmtk_content_t { wlmtk_content_vmt_t vmt; /** - * The window this content belongs to. Will be set when creating - * the window. + * The toplevel this content belongs to. Will be set when creating + * the toplevel. */ - wlmtk_window_t *window_ptr; + wlmtk_toplevel_t *toplevel_ptr; /** * Surface associated with this content. @@ -111,16 +110,16 @@ wlmtk_content_vmt_t wlmtk_content_extend( void wlmtk_content_fini(wlmtk_content_t *content_ptr); /** - * Sets the window for the content. + * Sets the toplevel for the content. * - * Private: Should only be called by Window ctor (a friend). + * Private: Should only be called by Toplevel ctor (a friend). * * @param content_ptr - * @param window_ptr + * @param toplevel_ptr */ -void wlmtk_content_set_window( +void wlmtk_content_set_toplevel( wlmtk_content_t *content_ptr, - wlmtk_window_t *window_ptr); + wlmtk_toplevel_t *toplevel_ptr); /** * Sets the committed size of the content. @@ -130,7 +129,7 @@ void wlmtk_content_set_window( * forwards the request to the content (eg. the Wayland client surface). The * client then configures it's surface and commits it. The content needs to * catch that commit and call @ref wlmtk_content_commit_size accordingly. - * This will then update the parent container's (and window's) layout. + * This will then update the parent container's (and toplevel's) layout. * * @param content_ptr * @param serial diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 9fd33388..2bf2b6d8 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -71,7 +71,7 @@ static const wlmtk_element_vmt_t resizebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_env_t *env_ptr, - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, const wlmtk_resizebar_style_t *style_ptr) { wlmtk_resizebar_t *resizebar_ptr = logged_calloc( @@ -92,7 +92,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( &resizebar_element_vmt); resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( - window_ptr, env_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); + toplevel_ptr, env_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -102,7 +102,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( - window_ptr, env_ptr, WLR_EDGE_BOTTOM); + toplevel_ptr, env_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -112,7 +112,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( - window_ptr, env_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); + toplevel_ptr, env_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -271,25 +271,25 @@ const bs_test_case_t wlmtk_resizebar_test_cases[] = { /** Exercises @ref wlmtk_resizebar_create and @ref wlmtk_resizebar_destroy. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_resizebar_style_t style = {}; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, fake_window_ptr->window_ptr, &style); + NULL, fake_toplevel_ptr->toplevel_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); } /* ------------------------------------------------------------------------- */ /** Performs resizing and verifies the elements are shown as expected. */ void test_variable_width(bs_test_t *test_ptr) { - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, fake_window_ptr->window_ptr, &style); + NULL, fake_toplevel_ptr->toplevel_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( @@ -330,7 +330,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, right_elem_ptr->x); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); } /* == End of resizebar.c =================================================== */ diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index f0382ae9..44acb9d0 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -27,10 +27,9 @@ struct wlr_cursor; /** Forward declaration. */ struct wlr_xcursor_manager; - #include "element.h" #include "primitives.h" -#include "window.h" +#include "toplevel.h" #ifdef __cplusplus extern "C" { @@ -54,14 +53,14 @@ typedef struct { * Creates the resize bar. * * @param env_ptr - * @param window_ptr + * @param toplevel_ptr * @param style_ptr * * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_env_t *env_ptr, - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, const wlmtk_resizebar_style_t *style_ptr); /** diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 87cb1295..63202704 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -24,7 +24,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" -#include "window.h" +#include "toplevel.h" #include @@ -52,7 +52,7 @@ struct _wlmtk_resizebar_area_t { bool pressed; /** Window to which the resize bar area belongs. To initiate resizing. */ - wlmtk_window_t *window_ptr; + wlmtk_toplevel_t *toplevel_ptr; /** Edges that the resizebar area controls. */ uint32_t edges; @@ -91,15 +91,15 @@ static const wlmtk_element_vmt_t resizebar_area_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, wlmtk_env_t *env_ptr, uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); if (NULL == resizebar_area_ptr) return NULL; - BS_ASSERT(NULL != window_ptr); - resizebar_area_ptr->window_ptr = window_ptr; + BS_ASSERT(NULL != toplevel_ptr); + resizebar_area_ptr->toplevel_ptr = toplevel_ptr; resizebar_area_ptr->edges = edges; resizebar_area_ptr->cursor = WLMTK_CURSOR_DEFAULT; @@ -223,8 +223,8 @@ bool _wlmtk_resizebar_area_element_pointer_button( case WLMTK_BUTTON_DOWN: resizebar_area_ptr->pressed = true; - wlmtk_window_request_resize( - resizebar_area_ptr->window_ptr, + wlmtk_toplevel_request_resize( + resizebar_area_ptr->toplevel_ptr, resizebar_area_ptr->edges); draw_state(resizebar_area_ptr); break; @@ -313,10 +313,10 @@ const bs_test_case_t wlmtk_resizebar_area_test_cases[] = { /** Tests the area behaviour. */ void test_area(bs_test_t *test_ptr) { - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( - fake_window_ptr->window_ptr, NULL, WLR_EDGE_BOTTOM); + fake_toplevel_ptr->toplevel_ptr, NULL, WLR_EDGE_BOTTOM); BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); @@ -332,7 +332,7 @@ void test_area(bs_test_t *test_ptr) test_ptr, bs_gfxbuf_from_wlr_buffer(area_ptr->super_buffer.wlr_buffer_ptr), "toolkit/resizebar_area_released.png"); - BS_TEST_VERIFY_FALSE(test_ptr, fake_window_ptr->request_resize_called); + BS_TEST_VERIFY_FALSE(test_ptr, fake_toplevel_ptr->request_resize_called); // Pointer must be inside the button for accepting DOWN. BS_TEST_VERIFY_TRUE( @@ -351,14 +351,14 @@ void test_area(bs_test_t *test_ptr) "toolkit/resizebar_area_pressed.png"); // TODO(kaeser@gubbe.ch): Should verify setting the cursor. - BS_TEST_VERIFY_TRUE(test_ptr, fake_window_ptr->request_resize_called); + BS_TEST_VERIFY_TRUE(test_ptr, fake_toplevel_ptr->request_resize_called); BS_TEST_VERIFY_EQ( test_ptr, WLR_EDGE_BOTTOM, - fake_window_ptr->request_resize_edges); + fake_toplevel_ptr->request_resize_edges); wlmtk_element_destroy(element_ptr); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); } /* == End of resizebar_area.c ============================================== */ diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index c52e178f..551d5d7d 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -25,9 +25,8 @@ /** Forward declaration: Element of the resizebar. */ typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; - #include "resizebar.h" -#include "window.h" +#include "toplevel.h" #ifdef __cplusplus extern "C" { @@ -36,14 +35,14 @@ extern "C" { /** * Creates a resizebar button. * - * @param window_ptr + * @param toplevel_ptr * @param env_ptr * @param edges * * @return Pointer to the resizebar button. */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, wlmtk_env_t *env_ptr, uint32_t edges); diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index f34b20d9..1193550f 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -27,7 +27,7 @@ #include "primitives.h" #include "titlebar_button.h" #include "titlebar_title.h" -#include "window.h" +#include "toplevel.h" #define WLR_USE_UNSTABLE #include @@ -88,14 +88,14 @@ static const wlmtk_element_vmt_t titlebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_env_t *env_ptr, - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_t *titlebar_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_t)); if (NULL == titlebar_ptr) return NULL; memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); - titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); + titlebar_ptr->title_ptr = wlmtk_toplevel_get_title(toplevel_ptr); if (!wlmtk_box_init(&titlebar_ptr->super_box, env_ptr, WLMTK_BOX_HORIZONTAL, @@ -108,7 +108,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( &titlebar_element_vmt); titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create( - env_ptr, window_ptr); + env_ptr, toplevel_ptr); if (NULL == titlebar_ptr->titlebar_title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -119,8 +119,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( env_ptr, - wlmtk_window_request_minimize, - window_ptr, + wlmtk_toplevel_request_minimize, + toplevel_ptr, wlmaker_primitives_draw_minimize_icon); if (NULL == titlebar_ptr->minimize_button_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -132,8 +132,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( env_ptr, - wlmtk_window_request_close, - window_ptr, + wlmtk_toplevel_request_close, + toplevel_ptr, wlmaker_primitives_draw_close_icon); if (NULL == titlebar_ptr->close_button_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -384,24 +384,24 @@ const bs_test_case_t wlmtk_titlebar_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_titlebar_style_t style = {}; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - NULL, fake_window_ptr->window_ptr, &style); + NULL, fake_toplevel_ptr->toplevel_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); } /* ------------------------------------------------------------------------- */ /** Tests titlebar with variable width. */ void test_variable_width(bs_test_t *test_ptr) { - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_titlebar_style_t style = { .height = 22, .margin_style = { .width = 2 } }; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - NULL, fake_window_ptr->window_ptr, &style); + NULL, fake_toplevel_ptr->toplevel_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); // Short names, for improved readability. @@ -447,7 +447,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 66, width); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); } /* == End of titlebar.c ==================================================== */ diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 49970c24..163225c5 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -26,7 +26,7 @@ typedef struct _wlmtk_titlebar_t wlmtk_titlebar_t; #include "element.h" #include "primitives.h" -#include "window.h" +#include "toplevel.h" #ifdef __cplusplus extern "C" { @@ -51,10 +51,10 @@ typedef struct { } wlmtk_titlebar_style_t; /** - * Creates a title bar, suitable as a window title. + * Creates a title bar, suitable as a toplevel title. * * @param env_ptr - * @param window_ptr + * @param toplevel_ptr * @param style_ptr * * @return Pointer to the title bar state, or NULL on error. Must be free'd @@ -62,7 +62,7 @@ typedef struct { */ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_env_t *env_ptr, - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, const wlmtk_titlebar_style_t *style_ptr); /** diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index c70ba9dd..7b4cf011 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -38,9 +38,9 @@ struct _wlmtk_titlebar_button_t { bool activated; /** Callback for when the button is clicked. */ - void (*click_handler)(wlmtk_window_t *window_ptr); - /** Points to the @ref wlmtk_window_t that carries this titlebar. */ - wlmtk_window_t *window_ptr; + void (*click_handler)(wlmtk_toplevel_t *toplevel_ptr); + /** Points to the @ref wlmtk_toplevel_t that carries this titlebar. */ + wlmtk_toplevel_t *toplevel_ptr; /** For drawing the button contents. */ wlmtk_titlebar_button_draw_t draw; @@ -79,18 +79,18 @@ static const wlmtk_button_vmt_t titlebar_button_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( wlmtk_env_t *env_ptr, - void (*click_handler)(wlmtk_window_t *window_ptr), - wlmtk_window_t *window_ptr, + void (*click_handler)(wlmtk_toplevel_t *toplevel_ptr), + wlmtk_toplevel_t *toplevel_ptr, wlmtk_titlebar_button_draw_t draw) { - BS_ASSERT(NULL != window_ptr); + BS_ASSERT(NULL != toplevel_ptr); BS_ASSERT(NULL != click_handler); BS_ASSERT(NULL != draw); wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_button_t)); if (NULL == titlebar_button_ptr) return NULL; titlebar_button_ptr->click_handler = click_handler; - titlebar_button_ptr->window_ptr = window_ptr; + titlebar_button_ptr->toplevel_ptr = toplevel_ptr; titlebar_button_ptr->draw = draw; if (!wlmtk_button_init(&titlebar_button_ptr->super_button, env_ptr)) { @@ -201,12 +201,12 @@ void titlebar_button_element_destroy(wlmtk_element_t *element_ptr) } /* ------------------------------------------------------------------------- */ -/** Handles button clicks: Passes the request to the window. */ +/** Handles button clicks: Passes the request to the toplevel. */ void titlebar_button_clicked(wlmtk_button_t *button_ptr) { wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( button_ptr, wlmtk_titlebar_button_t, super_button); - titlebar_button_ptr->click_handler(titlebar_button_ptr->window_ptr); + titlebar_button_ptr->click_handler(titlebar_button_ptr->toplevel_ptr); } /* ------------------------------------------------------------------------- */ @@ -274,11 +274,11 @@ const bs_test_case_t wlmtk_titlebar_button_test_cases[] = { /** Tests button visualization. */ void test_button(bs_test_t *test_ptr) { - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( NULL, - wlmtk_window_request_close, - fake_window_ptr->window_ptr, + wlmtk_toplevel_request_close, + fake_toplevel_ptr->toplevel_ptr, wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); wlmtk_titlebar_button_set_activated(button_ptr, true); @@ -336,7 +336,7 @@ void test_button(bs_test_t *test_ptr) // Click: To be passed along, no change to visual. BS_TEST_VERIFY_FALSE( test_ptr, - fake_window_ptr->request_close_called); + fake_toplevel_ptr->request_close_called); button.type = WLMTK_BUTTON_CLICK; BS_TEST_VERIFY_TRUE( test_ptr, @@ -347,7 +347,7 @@ void test_button(bs_test_t *test_ptr) "toolkit/title_button_focussed_released.png"); BS_TEST_VERIFY_TRUE( test_ptr, - fake_window_ptr->request_close_called); + fake_toplevel_ptr->request_close_called); // De-activate: Show as blurred. wlmtk_titlebar_button_set_activated(button_ptr, false); @@ -357,7 +357,7 @@ void test_button(bs_test_t *test_ptr) "toolkit/title_button_blurred.png"); wlmtk_element_destroy(element_ptr); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); } /* == End of titlebar_button.c ============================================= */ diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index 83501f00..60e980d0 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -41,15 +41,15 @@ typedef void (*wlmtk_titlebar_button_draw_t)( * * @param env_ptr * @param click_handler - * @param window_ptr + * @param toplevel_ptr * @param draw * * @return Pointer to the titlebar button, or NULL on error. */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( wlmtk_env_t *env_ptr, - void (*click_handler)(wlmtk_window_t *window_ptr), - wlmtk_window_t *window_ptr, + void (*click_handler)(wlmtk_toplevel_t *toplevel_ptr), + wlmtk_toplevel_t *toplevel_ptr, wlmtk_titlebar_button_draw_t draw); /** diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index 4ebe4418..56edcb59 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -23,7 +23,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" -#include "window.h" +#include "toplevel.h" #define WLR_USE_UNSTABLE #include @@ -35,8 +35,8 @@ struct _wlmtk_titlebar_title_t { /** Superclass: Buffer. */ wlmtk_buffer_t super_buffer; - /** Pointer to the window the title element belongs to. */ - wlmtk_window_t *window_ptr; + /** Pointer to the toplevel the title element belongs to. */ + wlmtk_toplevel_t *toplevel_ptr; /** The drawn title, when focussed. */ struct wlr_buffer *focussed_wlr_buffer_ptr; @@ -74,12 +74,12 @@ static const wlmtk_element_vmt_t titlebar_title_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( wlmtk_env_t *env_ptr, - wlmtk_window_t *window_ptr) + wlmtk_toplevel_t *toplevel_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_title_t)); if (NULL == titlebar_title_ptr) return NULL; - titlebar_title_ptr->window_ptr = window_ptr; + titlebar_title_ptr->toplevel_ptr = toplevel_ptr; if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer, env_ptr)) { wlmtk_titlebar_title_destroy(titlebar_title_ptr); @@ -183,7 +183,7 @@ bool _wlmtk_titlebar_title_element_pointer_button( switch (button_event_ptr->type) { case WLMTK_BUTTON_DOWN: - wlmtk_window_request_move(titlebar_title_ptr->window_ptr); + wlmtk_toplevel_request_move(titlebar_title_ptr->toplevel_ptr); break; default: // Can be ignored. @@ -282,9 +282,9 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( - NULL, fake_window_ptr->window_ptr); + NULL, fake_toplevel_ptr->toplevel_ptr); wlmtk_element_t *element_ptr = wlmtk_titlebar_title_element( titlebar_title_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); @@ -328,17 +328,17 @@ void test_title(bs_test_t *test_ptr) "toolkit/title_blurred_short.png"); // Pressing a button should trigger a move. - BS_TEST_VERIFY_FALSE(test_ptr, fake_window_ptr->request_move_called); + BS_TEST_VERIFY_FALSE(test_ptr, fake_toplevel_ptr->request_move_called); wlmtk_button_event_t button = { .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN }; BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_pointer_button(element_ptr, &button)); - BS_TEST_VERIFY_TRUE(test_ptr, fake_window_ptr->request_move_called); + BS_TEST_VERIFY_TRUE(test_ptr, fake_toplevel_ptr->request_move_called); wlmtk_element_destroy(element_ptr); - wlmtk_fake_window_destroy(fake_window_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); } diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h index 58b82820..4642e62c 100644 --- a/src/toolkit/titlebar_title.h +++ b/src/toolkit/titlebar_title.h @@ -36,13 +36,13 @@ extern "C" { * Creates a title bar title. * * @param env_ptr - * @param window_ptr + * @param toplevel_ptr * * @return Title handle. */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( wlmtk_env_t *env_ptr, - wlmtk_window_t *window_ptr); + wlmtk_toplevel_t *toplevel_ptr); /** * Destroys the titlebar title. diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 1c1edf29..f67b42e6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -47,7 +47,7 @@ #include "titlebar.h" #include "titlebar_button.h" #include "titlebar_title.h" -#include "window.h" +#include "toplevel.h" #include "workspace.h" #ifdef __cplusplus diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 46906daf..40822c86 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -81,11 +81,11 @@ class Workspace { Container *create() void destroy() - map_window(Window*) - unmap_window(Window*) + map_toplevel(Toplevel*) + unmap_toplevel(Toplevel*) - activate_window(Window*) - begin_window_move(Window*) + activate_toplevel(Toplevel*) + begin_toplevel_move(Toplevel*) map_layer_element(LayerElement *, layer) unmap_layer_element(LayerElement *, layer) @@ -99,6 +99,19 @@ class Box { } Container <|-- Box + + +abstract class Surface { +} + +abstract class Window { + private Container super_container; + + Surface surface; + Surface popups[]; +} + + abstract class Content { Element super_element @@ -106,7 +119,7 @@ abstract class Content { fini() struct wlr_scene_node *create_scene_node() Element *element() - -set_window(Window*) + -set_toplevel(Toplevel*) {abstract}#void get_size(int *, int *) {abstract}#void set_size(int, int) @@ -116,7 +129,7 @@ abstract class Content { } Element <|-- Content note right of Content - Interface for Window contents. + Interface for Toplevel contents. A surface (or... buffer? ...). Ultimately wraps a node, thus may be an element. end note @@ -152,12 +165,12 @@ class Button { } Buffer <|-- Button -class Window { +class Toplevel { Box super_box - Content *content + Window *content TitleBar *title_bar - Window *create(Content*) + Toplevel *create(Content*) destroy() Element *element() @@ -166,7 +179,7 @@ class Window { get_size(int *, int *) set_size(int, int) } -Box *-- Window +Box *-- Toplevel class TitleBar { Box super_box @@ -220,56 +233,56 @@ class Cursor { => so yes, what will this do when mapped? - * Window::create(surface) - * registers the window for workspace + * Toplevel::create(surface) + * registers the toplevel for workspace - * creates the container, with parent of window element + * creates the container, with parent of toplevel element * if decoration: * will setup listeners for the various events, ... * request maximize * request move - * request show window menu + * request show toplevel menu * set title * ... set title handler: - * window::set_title + * toplevel::set_title request maximize handler: - * window::request_maximize - * window::set_maximized + * toplevel::request_maximize + * toplevel::set_maximized * internally: get view from workspace, ... set_size * callback to surface (if set): set_maximized upon surface::map - * workspace::add_window(window) (unsure: do we need this?) - => should set "container" of window parent... element to workspace::container + * workspace::add_toplevel(toplevel) (unsure: do we need this?) + => should set "container" of toplevel parent... element to workspace::container (ie. set_parent(...); and add "element" to "container") - * workspace::map_window(window) - => this should add window to the set of workspace::mapped_windows - => window element->container -> map_element(element) + * workspace::map_toplevel(toplevel) + => this should add toplevel to the set of workspace::mapped_toplevels + => toplevel element->container -> map_element(element) (expects the container to be mapped) - => will call map(node?) on window element + => will call map(node?) on toplevel element - is implemented in Container: - create a scene tree (from parents node) oc reparent (from parent) - calls map for every item in container upon surface::unmap - * workspace::unmap_window + * workspace::unmap_toplevel - => window element->container -> unmap_element(element) - => will call unmap() on window element + => toplevel element->container -> unmap_element(element) + => will call unmap() on toplevel element => destroy the node - * workspace::remove_window(window) (do we need this?) + * workspace::remove_toplevel(toplevel) (do we need this?) There is a click ("pointer button event") -> goes to workspace. diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 886bc141..bbcf2cda 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -36,7 +36,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "titlebar", wlmtk_titlebar_test_cases }, { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, - { 1, "window", wlmtk_window_test_cases }, + { 1, "toplevel", wlmtk_toplevel_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } diff --git a/src/toolkit/toplevel.c b/src/toolkit/toplevel.c new file mode 100644 index 00000000..ee4eb6c0 --- /dev/null +++ b/src/toolkit/toplevel.c @@ -0,0 +1,1168 @@ +/* ========================================================================= */ +/** + * @file toplevel.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toplevel.h" + +#include "rectangle.h" +#include "workspace.h" + +#include "wlr/util/box.h" + +/* == Declarations ========================================================= */ + +/** Maximum number of pending state updates. */ +#define WLMTK_TOPLEVEL_MAX_PENDING 64 + +/** Virtual method table for the toplevel. */ +struct _wlmtk_toplevel_vmt_t { + /** Destructor. */ + void (*destroy)(wlmtk_toplevel_t *toplevel_ptr); + /** Virtual method for @ref wlmtk_toplevel_set_activated. */ + void (*set_activated)(wlmtk_toplevel_t *toplevel_ptr, + bool activated); + /** Virtual method for @ref wlmtk_toplevel_request_close. */ + void (*request_close)(wlmtk_toplevel_t *toplevel_ptr); + /** Virtual method for @ref wlmtk_toplevel_request_minimize. */ + void (*request_minimize)(wlmtk_toplevel_t *toplevel_ptr); + /** Virtual method for @ref wlmtk_toplevel_request_move. */ + void (*request_move)(wlmtk_toplevel_t *toplevel_ptr); + /** Virtual method for @ref wlmtk_toplevel_request_resize. */ + void (*request_resize)(wlmtk_toplevel_t *toplevel_ptr, + uint32_t edges); + /** Virtual method for @ref wlmtk_toplevel_request_position_and_size. */ + void (*request_position_and_size)(wlmtk_toplevel_t *toplevel_ptr, + int x, int y, int width, int height); +}; + +/** Pending positional updates for @ref wlmtk_toplevel_t::content_ptr. */ +typedef struct { + /** Node within @ref wlmtk_toplevel_t::pending_updates. */ + bs_dllist_node_t dlnode; + /** Serial of the update. */ + uint32_t serial; + /** Pending X position of the content. */ + int x; + /** Pending Y position of the content. */ + int y; + /** Content's width that is to be committed at serial. */ + unsigned width; + /** Content's hehight that is to be committed at serial. */ + unsigned height; +} wlmtk_pending_update_t; + +/** State of the toplevel. */ +struct _wlmtk_toplevel_t { + /** Superclass: Bordered. */ + wlmtk_bordered_t super_bordered; + /** Original virtual method table of the toplevel's element superclass. */ + wlmtk_element_vmt_t orig_super_element_vmt; + /** Original virtual method table of the toplevel' container superclass. */ + wlmtk_container_vmt_t orig_super_container_vmt; + + /** Virtual method table. */ + wlmtk_toplevel_vmt_t vmt; + + /** Box: In `super_bordered`, holds content, title bar and resizebar. */ + wlmtk_box_t box; + + /** Content of this toplevel. */ + wlmtk_content_t *content_ptr; + /** Titlebar. */ + wlmtk_titlebar_t *titlebar_ptr; + /** Resizebar. */ + wlmtk_resizebar_t *resizebar_ptr; + + /** Toplevel title. Set through @ref wlmtk_toplevel_set_title. */ + char *title_ptr; + + /** Pending updates. */ + bs_dllist_t pending_updates; + /** List of udpates currently available. */ + bs_dllist_t available_updates; + /** Pre-alloocated updates. */ + wlmtk_pending_update_t pre_allocated_updates[WLMTK_TOPLEVEL_MAX_PENDING]; + + /** Organic size of the toplevel, ie. when not maximized. */ + struct wlr_box organic_size; + /** Whether the toplevel has been requested as maximized. */ + bool maximized; + + /** + * Stores whether the toplevel is server-side decorated. + * + * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). + */ + bool server_side_decorated; +}; + +/** State of a fake toplevel: Includes the public record and the toplevel. */ +typedef struct { + /** Toplevel state. */ + wlmtk_toplevel_t toplevel; + /** Fake toplevel - public state. */ + wlmtk_fake_toplevel_t fake_toplevel; +} wlmtk_fake_toplevel_state_t; + +static bool _wlmtk_toplevel_init( + wlmtk_toplevel_t *toplevel_ptr, + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr); +static void _wlmtk_toplevel_fini(wlmtk_toplevel_t *toplevel_ptr); +static wlmtk_toplevel_vmt_t _wlmtk_toplevel_extend( + wlmtk_toplevel_t *toplevel_ptr, + const wlmtk_toplevel_vmt_t *toplevel_vmt_ptr); + +static bool _wlmtk_toplevel_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_toplevel_container_update_layout( + wlmtk_container_t *container_ptr); + +static void _wlmtk_toplevel_set_activated( + wlmtk_toplevel_t *toplevel_ptr, + bool activated); +static void _wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_toplevel_request_resize( + wlmtk_toplevel_t *toplevel_ptr, + uint32_t edges); +static void _wlmtk_toplevel_request_position_and_size( + wlmtk_toplevel_t *toplevel_ptr, + int x, + int y, + int width, + int height); + +static wlmtk_pending_update_t *_wlmtk_toplevel_prepare_update( + wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_toplevel_release_update( + wlmtk_toplevel_t *toplevel_ptr, + wlmtk_pending_update_t *update_ptr); +static wlmtk_workspace_t *_wlmtk_toplevel_workspace(wlmtk_toplevel_t *toplevel_ptr); + +/* == Data ================================================================= */ + +/** Virtual method table for the toplevel's element superclass. */ +static const wlmtk_element_vmt_t toplevel_element_vmt = { + .pointer_button = _wlmtk_toplevel_element_pointer_button, +}; +/** Virtual method table for the toplevel's container superclass. */ +static const wlmtk_container_vmt_t toplevel_container_vmt = { + .update_layout = _wlmtk_toplevel_container_update_layout, +}; +/** Virtual method table for the toplevel itself. */ +static const wlmtk_toplevel_vmt_t _wlmtk_toplevel_vmt = { + .set_activated = _wlmtk_toplevel_set_activated, + .request_close = _wlmtk_toplevel_request_close, + .request_minimize = _wlmtk_toplevel_request_minimize, + .request_move = _wlmtk_toplevel_request_move, + .request_resize = _wlmtk_toplevel_request_resize, + .request_position_and_size = _wlmtk_toplevel_request_position_and_size, +}; + +/** Style of the title bar. */ +// TODO(kaeser@gubbe.ch): Move to central config. */ +static const wlmtk_titlebar_style_t titlebar_style = { + .focussed_fill = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, + .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} + }, + .blurred_fill = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, + .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} + }, + .focussed_text_color = 0xffffffff, + .blurred_text_color = 0xff000000, + .height = 22, + .bezel_width = 1, + .margin_style = { .width = 1, .color = 0xff000000 }, +}; + +/** Style of the resize bar. */ +// TODO(kaeser@gubbe.ch): Move to central config. */ +static const wlmtk_resizebar_style_t resizebar_style = { + .fill = { + .type = WLMTK_STYLE_COLOR_SOLID, + .param = { .solid = { .color = 0xffc2c0c5 }} + }, + .height = 7, + .corner_width = 29, + .bezel_width = 1, + .margin_style = { .width = 0, .color = 0xff000000 }, +}; + +/** Style of the margin between title, content and resizebar. */ +static const wlmtk_margin_style_t margin_style = { + .width = 1, + .color = 0xff000000, +}; + +/** Style of the border around the toplevel. */ +static const wlmtk_margin_style_t border_style = { + .width = 1, + .color = 0xff000000, +}; + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +wlmtk_toplevel_t *wlmtk_toplevel_create( + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr) +{ + wlmtk_toplevel_t *toplevel_ptr = logged_calloc(1, sizeof(wlmtk_toplevel_t)); + if (NULL == toplevel_ptr) return NULL; + + if (!_wlmtk_toplevel_init(toplevel_ptr, env_ptr, content_ptr)) { + wlmtk_toplevel_destroy(toplevel_ptr); + return NULL; + } + + return toplevel_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_destroy(wlmtk_toplevel_t *toplevel_ptr) +{ + _wlmtk_toplevel_fini(toplevel_ptr); + free(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_toplevel_element(wlmtk_toplevel_t *toplevel_ptr) +{ + return &toplevel_ptr->super_bordered.super_container.super_element; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_toplevel_t *wlmtk_toplevel_from_element(wlmtk_element_t *element_ptr) +{ + wlmtk_toplevel_t *toplevel_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_toplevel_t, super_bordered.super_container.super_element); + BS_ASSERT(_wlmtk_toplevel_container_update_layout == + toplevel_ptr->super_bordered.super_container.vmt.update_layout); + return toplevel_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_set_activated( + wlmtk_toplevel_t *toplevel_ptr, + bool activated) +{ + toplevel_ptr->vmt.set_activated(toplevel_ptr, activated); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_set_server_side_decorated( + wlmtk_toplevel_t *toplevel_ptr, + bool decorated) +{ + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_INFO, "Set server side decoration for toplevel %p: %d", + toplevel_ptr, decorated); + + if (toplevel_ptr->server_side_decorated == decorated) return; + + if (decorated) { + // Create decoration. + toplevel_ptr->titlebar_ptr = wlmtk_titlebar_create( + toplevel_ptr->super_bordered.super_container.super_element.env_ptr, + toplevel_ptr, &titlebar_style); + BS_ASSERT(NULL != toplevel_ptr->titlebar_ptr); + wlmtk_element_set_visible( + wlmtk_titlebar_element(toplevel_ptr->titlebar_ptr), true); + wlmtk_box_add_element_front( + &toplevel_ptr->box, + wlmtk_titlebar_element(toplevel_ptr->titlebar_ptr)); + + toplevel_ptr->resizebar_ptr = wlmtk_resizebar_create( + toplevel_ptr->super_bordered.super_container.super_element.env_ptr, + toplevel_ptr, &resizebar_style); + BS_ASSERT(NULL != toplevel_ptr->resizebar_ptr); + wlmtk_element_set_visible( + wlmtk_resizebar_element(toplevel_ptr->resizebar_ptr), true); + wlmtk_box_add_element_back( + &toplevel_ptr->box, + wlmtk_resizebar_element(toplevel_ptr->resizebar_ptr)); + } else { + // Remove & destroy the decoration. + wlmtk_box_remove_element( + &toplevel_ptr->box, + wlmtk_titlebar_element(toplevel_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(toplevel_ptr->titlebar_ptr); + toplevel_ptr->titlebar_ptr = NULL; + + wlmtk_box_remove_element( + &toplevel_ptr->box, + wlmtk_resizebar_element(toplevel_ptr->resizebar_ptr)); + wlmtk_resizebar_destroy(toplevel_ptr->resizebar_ptr); + toplevel_ptr->resizebar_ptr = NULL; + } + + toplevel_ptr->server_side_decorated = decorated; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_set_title( + wlmtk_toplevel_t *toplevel_ptr, + const char *title_ptr) +{ + char *new_title_ptr = NULL; + if (NULL != title_ptr) { + new_title_ptr = logged_strdup(title_ptr); + BS_ASSERT(NULL != new_title_ptr); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), "Unnamed toplevel %p", toplevel_ptr); + new_title_ptr = logged_strdup(buf); + BS_ASSERT(NULL != new_title_ptr); + } + + if (NULL != toplevel_ptr->title_ptr) { + if (0 == strcmp(toplevel_ptr->title_ptr, new_title_ptr)) { + free(new_title_ptr); + return; + } + free(toplevel_ptr->title_ptr); + } + toplevel_ptr->title_ptr = new_title_ptr; + + if (NULL != toplevel_ptr->titlebar_ptr) { + wlmtk_titlebar_set_title(toplevel_ptr->titlebar_ptr, + toplevel_ptr->title_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +const char *wlmtk_toplevel_get_title(wlmtk_toplevel_t *toplevel_ptr) +{ + BS_ASSERT(NULL != toplevel_ptr->title_ptr); + return toplevel_ptr->title_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr) +{ + toplevel_ptr->vmt.request_close(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr) +{ + toplevel_ptr->vmt.request_minimize(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_maximize( + wlmtk_toplevel_t *toplevel_ptr, + bool maximized) +{ + if (toplevel_ptr->maximized == maximized) return; + + toplevel_ptr->maximized = maximized; + + struct wlr_box box; + if (toplevel_ptr->maximized) { + box = wlmtk_workspace_get_maximize_extents( + _wlmtk_toplevel_workspace(toplevel_ptr)); + } else { + box = toplevel_ptr->organic_size; + } + + _wlmtk_toplevel_request_position_and_size( + toplevel_ptr, box.x, box.y, box.width, box.height); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_toplevel_maximized(wlmtk_toplevel_t *toplevel_ptr) +{ + return toplevel_ptr->maximized; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr) +{ + toplevel_ptr->vmt.request_move(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_resize(wlmtk_toplevel_t *toplevel_ptr, + uint32_t edges) +{ + toplevel_ptr->vmt.request_resize(toplevel_ptr, edges); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_set_position(wlmtk_toplevel_t *toplevel_ptr, int x, int y) +{ + toplevel_ptr->organic_size.x = x; + toplevel_ptr->organic_size.y = y; + wlmtk_element_set_position(wlmtk_toplevel_element(toplevel_ptr), x, y); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_get_size( + wlmtk_toplevel_t *toplevel_ptr, + int *width_ptr, + int *height_ptr) +{ + // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. + wlmtk_content_get_size(toplevel_ptr->content_ptr, width_ptr, height_ptr); + + if (NULL != toplevel_ptr->titlebar_ptr) { + *height_ptr += titlebar_style.height + margin_style.width; + } + if (NULL != toplevel_ptr->resizebar_ptr) { + *height_ptr += resizebar_style.height + margin_style.width; + } + *height_ptr += 2 * border_style.width; + + *width_ptr += 2 * border_style.width; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_size( + wlmtk_toplevel_t *toplevel_ptr, + int width, + int height) +{ + // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. + wlmtk_content_request_size(toplevel_ptr->content_ptr, width, height); + + // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting + // the size is an asynchronous operation and should be handled as such. + // Meaning: In example of resizing at the top-left corner, we'll want to + // request the content to adjust size, but wait with adjusting the + // content position until the size adjustment is applied. This implies we + // may need to combine the request_size and set_position methods for toplevel. +} + +/* ------------------------------------------------------------------------- */ +struct wlr_box wlmtk_toplevel_get_position_and_size( + wlmtk_toplevel_t *toplevel_ptr) +{ + struct wlr_box box; + + wlmtk_element_get_position( + wlmtk_toplevel_element(toplevel_ptr), &box.x, &box.y); + wlmtk_toplevel_get_size(toplevel_ptr, &box.width, &box.height); + return box; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_request_position_and_size( + wlmtk_toplevel_t *toplevel_ptr, + int x, + int y, + int width, + int height) +{ + toplevel_ptr->vmt.request_position_and_size( + toplevel_ptr, x, y, width, height); + + toplevel_ptr->organic_size.x = x; + toplevel_ptr->organic_size.y = y; + toplevel_ptr->organic_size.width = width; + toplevel_ptr->organic_size.height = height; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_toplevel_serial(wlmtk_toplevel_t *toplevel_ptr, uint32_t serial) +{ + bs_dllist_node_t *dlnode_ptr; + + if (!toplevel_ptr->maximized && + NULL == toplevel_ptr->pending_updates.head_ptr) { + wlmtk_toplevel_get_size(toplevel_ptr, + &toplevel_ptr->organic_size.width, + &toplevel_ptr->organic_size.height); + return; + } + + while (NULL != (dlnode_ptr = toplevel_ptr->pending_updates.head_ptr)) { + wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); + + int32_t delta = pending_update_ptr->serial - serial; + if (0 < delta) break; + + if (pending_update_ptr->serial == serial) { + if (toplevel_ptr->content_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (toplevel_ptr->content_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } + } + + wlmtk_element_set_position( + wlmtk_toplevel_element(toplevel_ptr), + pending_update_ptr->x, + pending_update_ptr->y); + _wlmtk_toplevel_release_update(toplevel_ptr, pending_update_ptr); + } +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Initializes an (allocated) toplevel. + * + * @param toplevel_ptr + * @param env_ptr + * @param content_ptr + * + * @return true on success. + */ +bool _wlmtk_toplevel_init( + wlmtk_toplevel_t *toplevel_ptr, + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr) +{ + BS_ASSERT(NULL != toplevel_ptr); + memcpy(&toplevel_ptr->vmt, &_wlmtk_toplevel_vmt, sizeof(wlmtk_toplevel_vmt_t)); + + for (size_t i = 0; i < WLMTK_TOPLEVEL_MAX_PENDING; ++i) { + bs_dllist_push_back(&toplevel_ptr->available_updates, + &toplevel_ptr->pre_allocated_updates[i].dlnode); + } + + if (!wlmtk_box_init(&toplevel_ptr->box, env_ptr, + WLMTK_BOX_VERTICAL, + &margin_style)) { + _wlmtk_toplevel_fini(toplevel_ptr); + return false; + } + wlmtk_element_set_visible( + &toplevel_ptr->box.super_container.super_element, true); + + if (!wlmtk_bordered_init(&toplevel_ptr->super_bordered, + env_ptr, + &toplevel_ptr->box.super_container.super_element, + &border_style)) { + _wlmtk_toplevel_fini(toplevel_ptr); + return false; + } + + toplevel_ptr->orig_super_element_vmt = wlmtk_element_extend( + &toplevel_ptr->super_bordered.super_container.super_element, + &toplevel_element_vmt); + toplevel_ptr->orig_super_container_vmt = wlmtk_container_extend( + &toplevel_ptr->super_bordered.super_container, &toplevel_container_vmt); + + wlmtk_toplevel_set_title(toplevel_ptr, NULL); + + wlmtk_box_add_element_front( + &toplevel_ptr->box, + wlmtk_content_element(content_ptr)); + toplevel_ptr->content_ptr = content_ptr; + wlmtk_content_set_toplevel(content_ptr, toplevel_ptr); + wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + + return true; +} + +/* ------------------------------------------------------------------------- */ +/** + * Uninitializes the winodw. + * + * @param toplevel_ptr + */ +void _wlmtk_toplevel_fini(wlmtk_toplevel_t *toplevel_ptr) +{ + wlmtk_toplevel_set_server_side_decorated(toplevel_ptr, false); + + if (NULL != toplevel_ptr->content_ptr) { + wlmtk_box_remove_element( + &toplevel_ptr->box, + wlmtk_content_element(toplevel_ptr->content_ptr)); + wlmtk_element_set_visible( + wlmtk_content_element(toplevel_ptr->content_ptr), false); + wlmtk_content_set_toplevel(toplevel_ptr->content_ptr, NULL); + + wlmtk_element_destroy(wlmtk_content_element(toplevel_ptr->content_ptr)); + toplevel_ptr->content_ptr = NULL; + } + + if (NULL != toplevel_ptr->title_ptr) { + free(toplevel_ptr->title_ptr); + toplevel_ptr->title_ptr = NULL; + } + + wlmtk_bordered_fini(&toplevel_ptr->super_bordered); + wlmtk_box_fini(&toplevel_ptr->box); +} + +/* ------------------------------------------------------------------------- */ +/** + * Extends the toplevel's virtual methods. + * + * @param toplevel_ptr + * @param toplevel_vmt_ptr + * + * @return The previous virtual method table. + */ +wlmtk_toplevel_vmt_t _wlmtk_toplevel_extend( + wlmtk_toplevel_t *toplevel_ptr, + const wlmtk_toplevel_vmt_t *toplevel_vmt_ptr) +{ + wlmtk_toplevel_vmt_t orig_vmt = toplevel_ptr->vmt; + + if (NULL != toplevel_vmt_ptr->set_activated) { + toplevel_ptr->vmt.set_activated = toplevel_vmt_ptr->set_activated; + } + if (NULL != toplevel_vmt_ptr->request_close) { + toplevel_ptr->vmt.request_close = toplevel_vmt_ptr->request_close; + } + if (NULL != toplevel_vmt_ptr->request_minimize) { + toplevel_ptr->vmt.request_minimize = toplevel_vmt_ptr->request_minimize; + } + if (NULL != toplevel_vmt_ptr->request_move) { + toplevel_ptr->vmt.request_move = toplevel_vmt_ptr->request_move; + } + if (NULL != toplevel_vmt_ptr->request_resize) { + toplevel_ptr->vmt.request_resize = toplevel_vmt_ptr->request_resize; + } + if (NULL != toplevel_vmt_ptr->request_position_and_size) { + toplevel_ptr->vmt.request_position_and_size = + toplevel_vmt_ptr->request_position_and_size; + } + + return orig_vmt; +} + +/* ------------------------------------------------------------------------- */ +/** Activates toplevel on button press, and calls the parent's implementation. */ +bool _wlmtk_toplevel_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_toplevel_t *toplevel_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_toplevel_t, super_bordered.super_container.super_element); + + // We shouldn't receive buttons when not mapped. + wlmtk_workspace_t *workspace_ptr = _wlmtk_toplevel_workspace(toplevel_ptr); + wlmtk_workspace_activate_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_workspace_raise_toplevel(workspace_ptr, toplevel_ptr); + + return toplevel_ptr->orig_super_element_vmt.pointer_button( + element_ptr, button_event_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of @ref wlmtk_container_vmt_t::update_layout. + * + * Invoked when the toplevel's contained elements triggered a layout update, + * and will use this to trigger (potential) size updates to the toplevel + * decorations. + * + * @param container_ptr + */ +void _wlmtk_toplevel_container_update_layout(wlmtk_container_t *container_ptr) +{ + wlmtk_toplevel_t *toplevel_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_toplevel_t, super_bordered.super_container); + + toplevel_ptr->orig_super_container_vmt.update_layout(container_ptr); + + if (NULL != toplevel_ptr->content_ptr) { + int width; + wlmtk_content_get_size(toplevel_ptr->content_ptr, &width, NULL); + if (NULL != toplevel_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(toplevel_ptr->titlebar_ptr, width); + } + if (NULL != toplevel_ptr->resizebar_ptr) { + wlmtk_resizebar_set_width(toplevel_ptr->resizebar_ptr, width); + } + } +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_toplevel_set_activated. */ +void _wlmtk_toplevel_set_activated( + wlmtk_toplevel_t *toplevel_ptr, + bool activated) +{ + wlmtk_content_set_activated(toplevel_ptr->content_ptr, activated); + if (NULL != toplevel_ptr->titlebar_ptr) { + wlmtk_titlebar_set_activated(toplevel_ptr->titlebar_ptr, activated); + } +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_toplevel_request_close. */ +void _wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr) +{ + wlmtk_content_request_close(toplevel_ptr->content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_toplevel_request_minimize. */ +void _wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr) +{ + bs_log(BS_INFO, "Requesting toplevel %p to minimize.", toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_toplevel_request_move. */ +void _wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr) +{ + wlmtk_workspace_begin_toplevel_move( + _wlmtk_toplevel_workspace(toplevel_ptr), toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_toplevel_request_resize. */ +void _wlmtk_toplevel_request_resize(wlmtk_toplevel_t *toplevel_ptr, uint32_t edges) +{ + wlmtk_workspace_begin_toplevel_resize( + _wlmtk_toplevel_workspace(toplevel_ptr), toplevel_ptr, edges); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_toplevel_request_position_and_size. */ +void _wlmtk_toplevel_request_position_and_size( + wlmtk_toplevel_t *toplevel_ptr, + int x, + int y, + int width, + int height) +{ + // Correct for borders, margin and decoration. + if (NULL != toplevel_ptr->titlebar_ptr) { + height -= titlebar_style.height + margin_style.width; + } + if (NULL != toplevel_ptr->resizebar_ptr) { + height -= resizebar_style.height + margin_style.width; + } + height -= 2 * border_style.width; + width -= 2 * border_style.width; + height = BS_MAX(0, height); + width = BS_MAX(0, width); + + uint32_t serial = wlmtk_content_request_size( + toplevel_ptr->content_ptr, width, height); + + wlmtk_pending_update_t *pending_update_ptr = + _wlmtk_toplevel_prepare_update(toplevel_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = x; + pending_update_ptr->y = y; + pending_update_ptr->width = width; + pending_update_ptr->height = height; + + // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_toplevel_serial + // may have been called early, so we should check if serial had just been + // called before (or is below the last @wlmt_toplevel_serial). In that case, + // the pending state should be applied right away. +} + +/* ------------------------------------------------------------------------- */ +/** + * Prepares a positional update: Allocates an item and attach it to the end + * of the list of pending updates. + * + * @param toplevel_ptr + * + * @return A pointer to a @ref wlmtk_pending_update_t, already positioned at the + * back of @ref wlmtk_toplevel_t::pending_updates. + */ +wlmtk_pending_update_t *_wlmtk_toplevel_prepare_update( + wlmtk_toplevel_t *toplevel_ptr) +{ + bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( + &toplevel_ptr->available_updates); + if (NULL == dlnode_ptr) { + dlnode_ptr = bs_dllist_pop_front(&toplevel_ptr->pending_updates); + bs_log(BS_WARNING, "Toplevel %p: No updates available.", toplevel_ptr); + // TODO(kaeser@gubbe.ch): Hm, should we apply this (old) update? + } + wlmtk_pending_update_t *update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); + bs_dllist_push_back(&toplevel_ptr->pending_updates, &update_ptr->dlnode); + return update_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** + * Releases a pending positional update. Moves it to the list of + * @ref wlmtk_toplevel_t::available_updates. + * + * @param toplevel_ptr + * @param update_ptr + */ +void _wlmtk_toplevel_release_update( + wlmtk_toplevel_t *toplevel_ptr, + wlmtk_pending_update_t *update_ptr) +{ + bs_dllist_remove(&toplevel_ptr->pending_updates, &update_ptr->dlnode); + bs_dllist_push_front(&toplevel_ptr->available_updates, &update_ptr->dlnode); +} + +/* ------------------------------------------------------------------------- */ +/** Returns the workspace of the (mapped) toplevel. */ +wlmtk_workspace_t *_wlmtk_toplevel_workspace(wlmtk_toplevel_t *toplevel_ptr) +{ + BS_ASSERT(NULL != wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr); + return wlmtk_workspace_from_container( + wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr); +} + +/* == Implementation of the fake toplevel ==================================== */ + +static void _wlmtk_fake_toplevel_set_activated( + wlmtk_toplevel_t *toplevel_ptr, + bool activated); +static void _wlmtk_fake_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_fake_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_fake_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr); +static void _wlmtk_fake_toplevel_request_resize( + wlmtk_toplevel_t *toplevel_ptr, + uint32_t edges); +static void _wlmtk_fake_toplevel_request_position_and_size( + wlmtk_toplevel_t *toplevel_ptr, + int x, + int y, + int width, + int height); + +/** Virtual method table for the fake toplevel itself. */ +static const wlmtk_toplevel_vmt_t _wlmtk_fake_toplevel_vmt = { + .set_activated = _wlmtk_fake_toplevel_set_activated, + .request_close = _wlmtk_fake_toplevel_request_close, + .request_minimize = _wlmtk_fake_toplevel_request_minimize, + .request_move = _wlmtk_fake_toplevel_request_move, + .request_resize = _wlmtk_fake_toplevel_request_resize, + .request_position_and_size = _wlmtk_fake_toplevel_request_position_and_size, + +}; + +/* ------------------------------------------------------------------------- */ +wlmtk_fake_toplevel_t *wlmtk_fake_toplevel_create(void) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_toplevel_state_t)); + if (NULL == fake_toplevel_state_ptr) return NULL; + + fake_toplevel_state_ptr->fake_toplevel.fake_content_ptr = + wlmtk_fake_content_create(); + if (NULL == fake_toplevel_state_ptr->fake_toplevel.fake_content_ptr) { + wlmtk_fake_toplevel_destroy(&fake_toplevel_state_ptr->fake_toplevel); + return NULL; + } + + if (!_wlmtk_toplevel_init( + &fake_toplevel_state_ptr->toplevel, + NULL, + &fake_toplevel_state_ptr->fake_toplevel.fake_content_ptr->content)) { + wlmtk_fake_toplevel_destroy(&fake_toplevel_state_ptr->fake_toplevel); + return NULL; + } + fake_toplevel_state_ptr->fake_toplevel.toplevel_ptr = + &fake_toplevel_state_ptr->toplevel; + + // Extend. We don't save the VMT, since it's for fake only. + _wlmtk_toplevel_extend(&fake_toplevel_state_ptr->toplevel, + &_wlmtk_fake_toplevel_vmt); + return &fake_toplevel_state_ptr->fake_toplevel; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_toplevel_destroy(wlmtk_fake_toplevel_t *fake_toplevel_ptr) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + fake_toplevel_ptr, wlmtk_fake_toplevel_state_t, fake_toplevel); + + _wlmtk_toplevel_fini(&fake_toplevel_state_ptr->toplevel); + free(fake_toplevel_state_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_toplevel_set_activated. Records call. */ +void _wlmtk_fake_toplevel_set_activated( + wlmtk_toplevel_t *toplevel_ptr, + bool activated) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); + fake_toplevel_state_ptr->fake_toplevel.activated = activated; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_toplevel_request_close. Records call. */ +void _wlmtk_fake_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); + fake_toplevel_state_ptr->fake_toplevel.request_close_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_toplevel_request_minimize. Records call. */ +void _wlmtk_fake_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); + fake_toplevel_state_ptr->fake_toplevel.request_minimize_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_toplevel_request_move. Records call */ +void _wlmtk_fake_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); + fake_toplevel_state_ptr->fake_toplevel.request_move_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_toplevel_request_resize. Records call. */ +void _wlmtk_fake_toplevel_request_resize( + wlmtk_toplevel_t *toplevel_ptr, + uint32_t edges) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); + fake_toplevel_state_ptr->fake_toplevel.request_resize_called = true; + fake_toplevel_state_ptr->fake_toplevel.request_resize_edges = edges; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_toplevel_request_position_and_size. */ +void _wlmtk_fake_toplevel_request_position_and_size( + wlmtk_toplevel_t *toplevel_ptr, + int x, + int y, + int width, + int height) +{ + wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( + toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); + fake_toplevel_state_ptr->fake_toplevel.request_position_and_size_called = true; + fake_toplevel_state_ptr->fake_toplevel.x = x; + fake_toplevel_state_ptr->fake_toplevel.y = y; + fake_toplevel_state_ptr->fake_toplevel.width = width; + fake_toplevel_state_ptr->fake_toplevel.height = height; +} + +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); +static void test_set_title(bs_test_t *test_ptr); +static void test_request_close(bs_test_t *test_ptr); +static void test_set_activated(bs_test_t *test_ptr); +static void test_server_side_decorated(bs_test_t *test_ptr); +static void test_maximize(bs_test_t *test_ptr); +static void test_fake(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_toplevel_test_cases[] = { + { 1, "create_destroy", test_create_destroy }, + { 1, "set_title", test_set_title }, + { 1, "request_close", test_request_close }, + { 1, "set_activated", test_set_activated }, + { 1, "set_server_side_decorated", test_server_side_decorated }, + { 1, "maximize", test_maximize }, + { 1, "fake", test_fake }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown. */ +void test_create_destroy(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + NULL, &fake_content_ptr->content); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, toplevel_ptr, + fake_content_ptr->content.toplevel_ptr); + + wlmtk_toplevel_destroy(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests title. */ +void test_set_title(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + NULL, &fake_content_ptr->content); + + wlmtk_toplevel_set_title(toplevel_ptr, "Title"); + BS_TEST_VERIFY_STREQ( + test_ptr, + "Title", + wlmtk_toplevel_get_title(toplevel_ptr)); + + wlmtk_toplevel_set_title(toplevel_ptr, NULL); + BS_TEST_VERIFY_STRMATCH( + test_ptr, + wlmtk_toplevel_get_title(toplevel_ptr), + "Unnamed toplevel .*"); + + wlmtk_toplevel_destroy(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests activation. */ +void test_request_close(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + NULL, &fake_content_ptr->content); + + wlmtk_toplevel_request_close(toplevel_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); + + wlmtk_toplevel_destroy(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests activation. */ +void test_set_activated(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + NULL, &fake_content_ptr->content); + + wlmtk_toplevel_set_activated(toplevel_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); + + wlmtk_toplevel_set_activated(toplevel_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->activated); + + wlmtk_toplevel_destroy(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests enabling and disabling server-side decoration. */ +void test_server_side_decorated(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + NULL, &fake_content_ptr->content); + BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->resizebar_ptr); + + wlmtk_toplevel_set_server_side_decorated(toplevel_ptr, true); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr->resizebar_ptr); + + wlmtk_toplevel_set_server_side_decorated(toplevel_ptr, false); + BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->resizebar_ptr); + + wlmtk_toplevel_destroy(toplevel_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests maximizing and un-maximizing a toplevel. */ +void test_maximize(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + NULL, fake_parent_ptr->wlr_scene_tree_ptr); + struct wlr_box extents = { .width = 1024, .height = 768 }, box; + wlmtk_workspace_set_extents(workspace_ptr, &extents); + BS_ASSERT(NULL != workspace_ptr); + + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + NULL, &fake_content_ptr->content); + BS_ASSERT(NULL != toplevel_ptr); + // Toplevel must be mapped to get maximized: Need workspace dimensions. + wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); + + // Set up initial organic size, and verify. + wlmtk_toplevel_request_position_and_size(toplevel_ptr, 20, 10, 200, 100); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_maximized(toplevel_ptr)); + + // Re-position the toplevel. + wlmtk_toplevel_set_position(toplevel_ptr, 50, 30); + box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Trigger another serial update. Should not change position nor size. + wlmtk_toplevel_serial(toplevel_ptr, 1234); + box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Maximize. + wlmtk_toplevel_request_maximize(toplevel_ptr, true); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_toplevel_maximized(toplevel_ptr)); + + // A second commit: should not overwrite the organic dimension. + wlmtk_fake_content_commit(fake_content_ptr); + + // Unmaximize. Restore earlier organic size and position. + wlmtk_toplevel_request_maximize(toplevel_ptr, false); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_maximized(toplevel_ptr)); + + // TODO(kaeser@gubbe.ch): Define what should happen when a maximized + // toplevel is moved. Should it lose maximization? Should it not move? + // Or just move on? + // Toplevel Maker keeps maximization, but it's ... odd. + + wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_toplevel_destroy(toplevel_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests fake toplevel ctor and dtor. */ +void test_fake(bs_test_t *test_ptr) +{ + wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_toplevel_ptr); + wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); +} + +/* == End of toplevel.c ==================================================== */ diff --git a/src/toolkit/toplevel.h b/src/toolkit/toplevel.h new file mode 100644 index 00000000..6478971a --- /dev/null +++ b/src/toolkit/toplevel.h @@ -0,0 +1,319 @@ +/* ========================================================================= */ +/** + * @file toplevel.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_TOPLEVEL_H__ +#define __WLMTK_TOPLEVEL_H__ + +/** Forward declaration: Toplevel. */ +typedef struct _wlmtk_toplevel_t wlmtk_toplevel_t; +/** Forward declaration: Virtual method table. */ +typedef struct _wlmtk_toplevel_vmt_t wlmtk_toplevel_vmt_t; + +#include "bordered.h" +#include "box.h" +#include "content.h" +#include "element.h" +#include "resizebar.h" +#include "titlebar.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a toplevel for the given content. + * + * @param env_ptr + * @param content_ptr Will take ownership of content_ptr. + * + * @return Pointer to the toplevel state, or NULL on error. Must be free'd + * by calling @ref wlmtk_toplevel_destroy. + */ +wlmtk_toplevel_t *wlmtk_toplevel_create( + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr); + +/** + * Destroys the toplevel. + * + * @param toplevel_ptr + */ +void wlmtk_toplevel_destroy(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Returns the super Element of the toplevel. + * + * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or + * whether to keep the ancestry members public. + * + * @param toplevel_ptr + * + * @return Pointer to the @ref wlmtk_element_t base instantiation to + * toplevel_ptr. + */ +wlmtk_element_t *wlmtk_toplevel_element(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Returns the toplevel from the super Element. + * + * @param element_ptr + * + * @return Pointer to the @ref wlmtk_toplevel_t, for which `element_ptr` is + * the ancestor. + */ +wlmtk_toplevel_t *wlmtk_toplevel_from_element(wlmtk_element_t *element_ptr); + +/** + * Sets the toplevel as activated, depending on the argument's value. + * + * An activated toplevel will have keyboard focus and would have distinct + * decorations to indicate state. + * + * @param toplevel_ptr + * @param activated + */ +void wlmtk_toplevel_set_activated( + wlmtk_toplevel_t *toplevel_ptr, + bool activated); + +/** + * Sets whether to have server-side decorations for this toplevel. + * + * @param toplevel_ptr + * @param decorated + */ +void wlmtk_toplevel_set_server_side_decorated( + wlmtk_toplevel_t *toplevel_ptr, + bool decorated); + +/** + * Sets the title for the toplevel. + * + * If `title_ptr` is NULL, a generic name is set. + * + * @param toplevel_ptr + * @param title_ptr May be NULL. + */ +void wlmtk_toplevel_set_title( + wlmtk_toplevel_t *toplevel_ptr, + const char *title_ptr); + +/** + * Returns the title of the toplevel. + * + * @param toplevel_ptr + * + * @returns Pointer to the toplevel title. Will remain valid until the next call + * to @ref wlmtk_toplevel_set_title, or until the toplevel is destroyed. Will + * never be NULL. + */ +const char *wlmtk_toplevel_get_title(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Requests to close the toplevel. + * + * @param toplevel_ptr + */ +void wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Requests to minimize (iconify) the toplevel. + * + * @param toplevel_ptr + */ +void wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Reuests the toplevel to be maximized. + * + * Requires the toplevel to be mapped (to a workspace). Will lookup the maximize + * extents from the workspace, and request a corresponding updated position and + * size for the toplevel. @ref wlmtk_toplevel_t::organic_size will not be updated. + * + * This may be implemented as an asynchronous operation. Maximization will be + * applied once the size change has been committed by the content. + * + * @param toplevel_ptr + * @param maximized + */ +void wlmtk_toplevel_request_maximize( + wlmtk_toplevel_t *toplevel_ptr, + bool maximized); + +/** Returns whether the toplevel is currently (requested to be) maximized. */ +bool wlmtk_toplevel_maximized(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Requests a move for the toplevel. + * + * Requires the toplevel to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_toplevel_move. + * + * @param toplevel_ptr + */ +void wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr); + +/** + * Requests the toplevel to be resized. + * + * Requires the toplevel to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_toplevel_resize. + * + * @param toplevel_ptr + * @param edges + */ +void wlmtk_toplevel_request_resize(wlmtk_toplevel_t *toplevel_ptr, + uint32_t edges); + +/** + * Sets the toplevel's position. This is a synchronous operation. + * + * Updates the position in @ref wlmtk_toplevel_t::organic_size. + * @param toplevel_ptr + * @param x + * @param y + */ +void wlmtk_toplevel_set_position(wlmtk_toplevel_t *toplevel_ptr, int x, int y); + +/** + * Obtains the size of the toplevel, including potential decorations. + * + * @param toplevel_ptr + * @param width_ptr May be NULL. + * @param height_ptr May be NULL. + */ +void wlmtk_toplevel_get_size( + wlmtk_toplevel_t *toplevel_ptr, + int *width_ptr, + int *height_ptr); + +/** + * Requests a new size for the toplevel, including potential decorations. + * + * This may be implemented as an asynchronous operation. + * + * @param toplevel_ptr + * @param width + * @param height + */ +void wlmtk_toplevel_request_size( + wlmtk_toplevel_t *toplevel_ptr, + int width, + int height); + +/** + * Returns the current position and size of the toplevel. + * + * @param toplevel_ptr + * + * @return The position of the toplevel (the toplevel's element), and the currently + * committed width and height of the toplevel. + */ +struct wlr_box wlmtk_toplevel_get_position_and_size( + wlmtk_toplevel_t *toplevel_ptr); + +/** + * Requests an updated position and size for the toplevel, including potential + * decorations. + * + * This may be implemented as an asynchronous operation. The re-positioning + * will be applied only once the size change has been committed by the client. + * + * The position and size will be stored in @ref wlmtk_toplevel_t::organic_size. + * + * @param toplevel_ptr + * @param x + * @param y + * @param width + * @param height + */ +void wlmtk_toplevel_request_position_and_size( + wlmtk_toplevel_t *toplevel_ptr, + int x, + int y, + int width, + int height); + +/** + * Updates the toplevel state to what was requested at the `serial`. + * + * Used for example when resizing a toplevel from the top or left edges. In that + * case, @ref wlmtk_content_request_size may be asynchronous and returns a + * serial. The content is expected to call @ref wlmtk_toplevel_serial with the + * returned serial when the size is committed. + * Only then, the corresponding positional update on the top/left edges are + * supposed to be applied. + * + * @ref wlmtk_toplevel_t::organic_size will be updated, if there was no pending + * update: Meaning that the commit originated not from an earlier + * @ref wlmtk_toplevel_request_position_and_size or @ref + * wlmtk_toplevel_request_maximize call. + * + * @param toplevel_ptr + * @param serial + */ +void wlmtk_toplevel_serial(wlmtk_toplevel_t *toplevel_ptr, uint32_t serial); + +/* ------------------------------------------------------------------------- */ + +/** State of the fake toplevel, for tests. */ +typedef struct { + /** Toplevel state. */ + wlmtk_toplevel_t *toplevel_ptr; + /** Fake content, to manipulate the fake toplevel's content. */ + wlmtk_fake_content_t *fake_content_ptr; + + /** Argument to last @ref wlmtk_toplevel_set_activated call. */ + bool activated; + /** Whether @ref wlmtk_toplevel_request_close was called. */ + bool request_close_called; + /** Whether @ref wlmtk_toplevel_request_minimize was called. */ + bool request_minimize_called; + /** Whether @ref wlmtk_toplevel_request_move was called. */ + bool request_move_called; + /** Whether @ref wlmtk_toplevel_request_resize was called. */ + bool request_resize_called; + /** Argument to last @ref wlmtk_toplevel_request_resize call. */ + uint32_t request_resize_edges; + /** Whether @ref wlmtk_toplevel_request_position_and_size was called. */ + bool request_position_and_size_called; + /** Argument to last @ref wlmtk_toplevel_request_size call. */ + int x; + /** Argument to last @ref wlmtk_toplevel_request_size call. */ + int y; + /** Argument to last @ref wlmtk_toplevel_request_size call. */ + int width; + /** Argument to last @ref wlmtk_toplevel_request_size call. */ + int height; +} wlmtk_fake_toplevel_t; + +/** Ctor. */ +wlmtk_fake_toplevel_t *wlmtk_fake_toplevel_create(void); +/** Dtor. */ +void wlmtk_fake_toplevel_destroy(wlmtk_fake_toplevel_t *fake_toplevel_ptr); + +/** Unit tests for toplevel. */ +extern const bs_test_case_t wlmtk_toplevel_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_TOPLEVEL_H__ */ +/* == End of toplevel.h ==================================================== */ diff --git a/src/toolkit/window.c b/src/toolkit/window.c deleted file mode 100644 index ef8c62f9..00000000 --- a/src/toolkit/window.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* ========================================================================= */ -/** - * @file window.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "window.h" - -#include "rectangle.h" -#include "workspace.h" - -#include "wlr/util/box.h" - -/* == Declarations ========================================================= */ - -/** Maximum number of pending state updates. */ -#define WLMTK_WINDOW_MAX_PENDING 64 - -/** Virtual method table for the window. */ -struct _wlmtk_window_vmt_t { - /** Destructor. */ - void (*destroy)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_set_activated. */ - void (*set_activated)(wlmtk_window_t *window_ptr, - bool activated); - /** Virtual method for @ref wlmtk_window_request_close. */ - void (*request_close)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_minimize. */ - void (*request_minimize)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_move. */ - void (*request_move)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_resize. */ - void (*request_resize)(wlmtk_window_t *window_ptr, - uint32_t edges); - /** Virtual method for @ref wlmtk_window_request_position_and_size. */ - void (*request_position_and_size)(wlmtk_window_t *window_ptr, - int x, int y, int width, int height); -}; - -/** Pending positional updates for @ref wlmtk_window_t::content_ptr. */ -typedef struct { - /** Node within @ref wlmtk_window_t::pending_updates. */ - bs_dllist_node_t dlnode; - /** Serial of the update. */ - uint32_t serial; - /** Pending X position of the content. */ - int x; - /** Pending Y position of the content. */ - int y; - /** Content's width that is to be committed at serial. */ - unsigned width; - /** Content's hehight that is to be committed at serial. */ - unsigned height; -} wlmtk_pending_update_t; - -/** State of the window. */ -struct _wlmtk_window_t { - /** Superclass: Bordered. */ - wlmtk_bordered_t super_bordered; - /** Original virtual method table of the window's element superclass. */ - wlmtk_element_vmt_t orig_super_element_vmt; - /** Original virtual method table of the window' container superclass. */ - wlmtk_container_vmt_t orig_super_container_vmt; - - /** Virtual method table. */ - wlmtk_window_vmt_t vmt; - - /** Box: In `super_bordered`, holds content, title bar and resizebar. */ - wlmtk_box_t box; - - /** Content of this window. */ - wlmtk_content_t *content_ptr; - /** Titlebar. */ - wlmtk_titlebar_t *titlebar_ptr; - /** Resizebar. */ - wlmtk_resizebar_t *resizebar_ptr; - - /** Window title. Set through @ref wlmtk_window_set_title. */ - char *title_ptr; - - /** Pending updates. */ - bs_dllist_t pending_updates; - /** List of udpates currently available. */ - bs_dllist_t available_updates; - /** Pre-alloocated updates. */ - wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; - - /** Organic size of the window, ie. when not maximized. */ - struct wlr_box organic_size; - /** Whether the window has been requested as maximized. */ - bool maximized; - - /** - * Stores whether the window is server-side decorated. - * - * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). - */ - bool server_side_decorated; -}; - -/** State of a fake window: Includes the public record and the window. */ -typedef struct { - /** Window state. */ - wlmtk_window_t window; - /** Fake window - public state. */ - wlmtk_fake_window_t fake_window; -} wlmtk_fake_window_state_t; - -static bool _wlmtk_window_init( - wlmtk_window_t *window_ptr, - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); -static void _wlmtk_window_fini(wlmtk_window_t *window_ptr); -static wlmtk_window_vmt_t _wlmtk_window_extend( - wlmtk_window_t *window_ptr, - const wlmtk_window_vmt_t *window_vmt_ptr); - -static bool _wlmtk_window_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); -static void _wlmtk_window_container_update_layout( - wlmtk_container_t *container_ptr); - -static void _wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated); -static void _wlmtk_window_request_close(wlmtk_window_t *window_ptr); -static void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); -static void _wlmtk_window_request_move(wlmtk_window_t *window_ptr); -static void _wlmtk_window_request_resize( - wlmtk_window_t *window_ptr, - uint32_t edges); -static void _wlmtk_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height); - -static wlmtk_pending_update_t *_wlmtk_window_prepare_update( - wlmtk_window_t *window_ptr); -static void _wlmtk_window_release_update( - wlmtk_window_t *window_ptr, - wlmtk_pending_update_t *update_ptr); -static wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr); - -/* == Data ================================================================= */ - -/** Virtual method table for the window's element superclass. */ -static const wlmtk_element_vmt_t window_element_vmt = { - .pointer_button = _wlmtk_window_element_pointer_button, -}; -/** Virtual method table for the window's container superclass. */ -static const wlmtk_container_vmt_t window_container_vmt = { - .update_layout = _wlmtk_window_container_update_layout, -}; -/** Virtual method table for the window itself. */ -static const wlmtk_window_vmt_t _wlmtk_window_vmt = { - .set_activated = _wlmtk_window_set_activated, - .request_close = _wlmtk_window_request_close, - .request_minimize = _wlmtk_window_request_minimize, - .request_move = _wlmtk_window_request_move, - .request_resize = _wlmtk_window_request_resize, - .request_position_and_size = _wlmtk_window_request_position_and_size, -}; - -/** Style of the title bar. */ -// TODO(kaeser@gubbe.ch): Move to central config. */ -static const wlmtk_titlebar_style_t titlebar_style = { - .focussed_fill = { - .type = WLMTK_STYLE_COLOR_HGRADIENT, - .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} - }, - .blurred_fill = { - .type = WLMTK_STYLE_COLOR_HGRADIENT, - .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} - }, - .focussed_text_color = 0xffffffff, - .blurred_text_color = 0xff000000, - .height = 22, - .bezel_width = 1, - .margin_style = { .width = 1, .color = 0xff000000 }, -}; - -/** Style of the resize bar. */ -// TODO(kaeser@gubbe.ch): Move to central config. */ -static const wlmtk_resizebar_style_t resizebar_style = { - .fill = { - .type = WLMTK_STYLE_COLOR_SOLID, - .param = { .solid = { .color = 0xffc2c0c5 }} - }, - .height = 7, - .corner_width = 29, - .bezel_width = 1, - .margin_style = { .width = 0, .color = 0xff000000 }, -}; - -/** Style of the margin between title, content and resizebar. */ -static const wlmtk_margin_style_t margin_style = { - .width = 1, - .color = 0xff000000, -}; - -/** Style of the border around the window. */ -static const wlmtk_margin_style_t border_style = { - .width = 1, - .color = 0xff000000, -}; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create( - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) -{ - wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); - if (NULL == window_ptr) return NULL; - - if (!_wlmtk_window_init(window_ptr, env_ptr, content_ptr)) { - wlmtk_window_destroy(window_ptr); - return NULL; - } - - return window_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_destroy(wlmtk_window_t *window_ptr) -{ - _wlmtk_window_fini(window_ptr); - free(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) -{ - return &window_ptr->super_bordered.super_container.super_element; -} - -/* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) -{ - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); - BS_ASSERT(_wlmtk_window_container_update_layout == - window_ptr->super_bordered.super_container.vmt.update_layout); - return window_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated) -{ - window_ptr->vmt.set_activated(window_ptr, activated); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_set_server_side_decorated( - wlmtk_window_t *window_ptr, - bool decorated) -{ - // TODO(kaeser@gubbe.ch): Implement. - bs_log(BS_INFO, "Set server side decoration for window %p: %d", - window_ptr, decorated); - - if (window_ptr->server_side_decorated == decorated) return; - - if (decorated) { - // Create decoration. - window_ptr->titlebar_ptr = wlmtk_titlebar_create( - window_ptr->super_bordered.super_container.super_element.env_ptr, - window_ptr, &titlebar_style); - BS_ASSERT(NULL != window_ptr->titlebar_ptr); - wlmtk_element_set_visible( - wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - - window_ptr->resizebar_ptr = wlmtk_resizebar_create( - window_ptr->super_bordered.super_container.super_element.env_ptr, - window_ptr, &resizebar_style); - BS_ASSERT(NULL != window_ptr->resizebar_ptr); - wlmtk_element_set_visible( - wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - wlmtk_box_add_element_back( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - } else { - // Remove & destroy the decoration. - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); - window_ptr->titlebar_ptr = NULL; - - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); - window_ptr->resizebar_ptr = NULL; - } - - window_ptr->server_side_decorated = decorated; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_set_title( - wlmtk_window_t *window_ptr, - const char *title_ptr) -{ - char *new_title_ptr = NULL; - if (NULL != title_ptr) { - new_title_ptr = logged_strdup(title_ptr); - BS_ASSERT(NULL != new_title_ptr); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), "Unnamed window %p", window_ptr); - new_title_ptr = logged_strdup(buf); - BS_ASSERT(NULL != new_title_ptr); - } - - if (NULL != window_ptr->title_ptr) { - if (0 == strcmp(window_ptr->title_ptr, new_title_ptr)) { - free(new_title_ptr); - return; - } - free(window_ptr->title_ptr); - } - window_ptr->title_ptr = new_title_ptr; - - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, - window_ptr->title_ptr); - } -} - -/* ------------------------------------------------------------------------- */ -const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr) -{ - BS_ASSERT(NULL != window_ptr->title_ptr); - return window_ptr->title_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_close(wlmtk_window_t *window_ptr) -{ - window_ptr->vmt.request_close(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) -{ - window_ptr->vmt.request_minimize(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_maximize( - wlmtk_window_t *window_ptr, - bool maximized) -{ - if (window_ptr->maximized == maximized) return; - - window_ptr->maximized = maximized; - - struct wlr_box box; - if (window_ptr->maximized) { - box = wlmtk_workspace_get_maximize_extents( - _wlmtk_window_workspace(window_ptr)); - } else { - box = window_ptr->organic_size; - } - - _wlmtk_window_request_position_and_size( - window_ptr, box.x, box.y, box.width, box.height); -} - -/* ------------------------------------------------------------------------- */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) -{ - return window_ptr->maximized; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_move(wlmtk_window_t *window_ptr) -{ - window_ptr->vmt.request_move(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, - uint32_t edges) -{ - window_ptr->vmt.request_resize(window_ptr, edges); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y) -{ - window_ptr->organic_size.x = x; - window_ptr->organic_size.y = y; - wlmtk_element_set_position(wlmtk_window_element(window_ptr), x, y); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_get_size( - wlmtk_window_t *window_ptr, - int *width_ptr, - int *height_ptr) -{ - // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); - - if (NULL != window_ptr->titlebar_ptr) { - *height_ptr += titlebar_style.height + margin_style.width; - } - if (NULL != window_ptr->resizebar_ptr) { - *height_ptr += resizebar_style.height + margin_style.width; - } - *height_ptr += 2 * border_style.width; - - *width_ptr += 2 * border_style.width; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_size( - wlmtk_window_t *window_ptr, - int width, - int height) -{ - // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_content_request_size(window_ptr->content_ptr, width, height); - - // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting - // the size is an asynchronous operation and should be handled as such. - // Meaning: In example of resizing at the top-left corner, we'll want to - // request the content to adjust size, but wait with adjusting the - // content position until the size adjustment is applied. This implies we - // may need to combine the request_size and set_position methods for window. -} - -/* ------------------------------------------------------------------------- */ -struct wlr_box wlmtk_window_get_position_and_size( - wlmtk_window_t *window_ptr) -{ - struct wlr_box box; - - wlmtk_element_get_position( - wlmtk_window_element(window_ptr), &box.x, &box.y); - wlmtk_window_get_size(window_ptr, &box.width, &box.height); - return box; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height) -{ - window_ptr->vmt.request_position_and_size( - window_ptr, x, y, width, height); - - window_ptr->organic_size.x = x; - window_ptr->organic_size.y = y; - window_ptr->organic_size.width = width; - window_ptr->organic_size.height = height; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) -{ - bs_dllist_node_t *dlnode_ptr; - - if (!window_ptr->maximized && - NULL == window_ptr->pending_updates.head_ptr) { - wlmtk_window_get_size(window_ptr, - &window_ptr->organic_size.width, - &window_ptr->organic_size.height); - return; - } - - while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { - wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); - - int32_t delta = pending_update_ptr->serial - serial; - if (0 < delta) break; - - if (pending_update_ptr->serial == serial) { - if (window_ptr->content_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (window_ptr->content_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); - } - } - - wlmtk_element_set_position( - wlmtk_window_element(window_ptr), - pending_update_ptr->x, - pending_update_ptr->y); - _wlmtk_window_release_update(window_ptr, pending_update_ptr); - } -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** - * Initializes an (allocated) window. - * - * @param window_ptr - * @param env_ptr - * @param content_ptr - * - * @return true on success. - */ -bool _wlmtk_window_init( - wlmtk_window_t *window_ptr, - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) -{ - BS_ASSERT(NULL != window_ptr); - memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); - - for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { - bs_dllist_push_back(&window_ptr->available_updates, - &window_ptr->pre_allocated_updates[i].dlnode); - } - - if (!wlmtk_box_init(&window_ptr->box, env_ptr, - WLMTK_BOX_VERTICAL, - &margin_style)) { - _wlmtk_window_fini(window_ptr); - return false; - } - wlmtk_element_set_visible( - &window_ptr->box.super_container.super_element, true); - - if (!wlmtk_bordered_init(&window_ptr->super_bordered, - env_ptr, - &window_ptr->box.super_container.super_element, - &border_style)) { - _wlmtk_window_fini(window_ptr); - return false; - } - - window_ptr->orig_super_element_vmt = wlmtk_element_extend( - &window_ptr->super_bordered.super_container.super_element, - &window_element_vmt); - window_ptr->orig_super_container_vmt = wlmtk_container_extend( - &window_ptr->super_bordered.super_container, &window_container_vmt); - - wlmtk_window_set_title(window_ptr, NULL); - - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_content_element(content_ptr)); - window_ptr->content_ptr = content_ptr; - wlmtk_content_set_window(content_ptr, window_ptr); - wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - - return true; -} - -/* ------------------------------------------------------------------------- */ -/** - * Uninitializes the winodw. - * - * @param window_ptr - */ -void _wlmtk_window_fini(wlmtk_window_t *window_ptr) -{ - wlmtk_window_set_server_side_decorated(window_ptr, false); - - if (NULL != window_ptr->content_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_content_element(window_ptr->content_ptr)); - wlmtk_element_set_visible( - wlmtk_content_element(window_ptr->content_ptr), false); - wlmtk_content_set_window(window_ptr->content_ptr, NULL); - - wlmtk_element_destroy(wlmtk_content_element(window_ptr->content_ptr)); - window_ptr->content_ptr = NULL; - } - - if (NULL != window_ptr->title_ptr) { - free(window_ptr->title_ptr); - window_ptr->title_ptr = NULL; - } - - wlmtk_bordered_fini(&window_ptr->super_bordered); - wlmtk_box_fini(&window_ptr->box); -} - -/* ------------------------------------------------------------------------- */ -/** - * Extends the window's virtual methods. - * - * @param window_ptr - * @param window_vmt_ptr - * - * @return The previous virtual method table. - */ -wlmtk_window_vmt_t _wlmtk_window_extend( - wlmtk_window_t *window_ptr, - const wlmtk_window_vmt_t *window_vmt_ptr) -{ - wlmtk_window_vmt_t orig_vmt = window_ptr->vmt; - - if (NULL != window_vmt_ptr->set_activated) { - window_ptr->vmt.set_activated = window_vmt_ptr->set_activated; - } - if (NULL != window_vmt_ptr->request_close) { - window_ptr->vmt.request_close = window_vmt_ptr->request_close; - } - if (NULL != window_vmt_ptr->request_minimize) { - window_ptr->vmt.request_minimize = window_vmt_ptr->request_minimize; - } - if (NULL != window_vmt_ptr->request_move) { - window_ptr->vmt.request_move = window_vmt_ptr->request_move; - } - if (NULL != window_vmt_ptr->request_resize) { - window_ptr->vmt.request_resize = window_vmt_ptr->request_resize; - } - if (NULL != window_vmt_ptr->request_position_and_size) { - window_ptr->vmt.request_position_and_size = - window_vmt_ptr->request_position_and_size; - } - - return orig_vmt; -} - -/* ------------------------------------------------------------------------- */ -/** Activates window on button press, and calls the parent's implementation. */ -bool _wlmtk_window_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr) -{ - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); - - // We shouldn't receive buttons when not mapped. - wlmtk_workspace_t *workspace_ptr = _wlmtk_window_workspace(window_ptr); - wlmtk_workspace_activate_window(workspace_ptr, window_ptr); - wlmtk_workspace_raise_window(workspace_ptr, window_ptr); - - return window_ptr->orig_super_element_vmt.pointer_button( - element_ptr, button_event_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Implementation of @ref wlmtk_container_vmt_t::update_layout. - * - * Invoked when the window's contained elements triggered a layout update, - * and will use this to trigger (potential) size updates to the window - * decorations. - * - * @param container_ptr - */ -void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) -{ - wlmtk_window_t *window_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_window_t, super_bordered.super_container); - - window_ptr->orig_super_container_vmt.update_layout(container_ptr); - - if (NULL != window_ptr->content_ptr) { - int width; - wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); - } - if (NULL != window_ptr->resizebar_ptr) { - wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); - } - } -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_set_activated. */ -void _wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated) -{ - wlmtk_content_set_activated(window_ptr->content_ptr, activated); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); - } -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_close. */ -void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) -{ - wlmtk_content_request_close(window_ptr->content_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_minimize. */ -void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) -{ - bs_log(BS_INFO, "Requesting window %p to minimize.", window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_move. */ -void _wlmtk_window_request_move(wlmtk_window_t *window_ptr) -{ - wlmtk_workspace_begin_window_move( - _wlmtk_window_workspace(window_ptr), window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_resize. */ -void _wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) -{ - wlmtk_workspace_begin_window_resize( - _wlmtk_window_workspace(window_ptr), window_ptr, edges); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_position_and_size. */ -void _wlmtk_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height) -{ - // Correct for borders, margin and decoration. - if (NULL != window_ptr->titlebar_ptr) { - height -= titlebar_style.height + margin_style.width; - } - if (NULL != window_ptr->resizebar_ptr) { - height -= resizebar_style.height + margin_style.width; - } - height -= 2 * border_style.width; - width -= 2 * border_style.width; - height = BS_MAX(0, height); - width = BS_MAX(0, width); - - uint32_t serial = wlmtk_content_request_size( - window_ptr->content_ptr, width, height); - - wlmtk_pending_update_t *pending_update_ptr = - _wlmtk_window_prepare_update(window_ptr); - pending_update_ptr->serial = serial; - pending_update_ptr->x = x; - pending_update_ptr->y = y; - pending_update_ptr->width = width; - pending_update_ptr->height = height; - - // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial - // may have been called early, so we should check if serial had just been - // called before (or is below the last @wlmt_window_serial). In that case, - // the pending state should be applied right away. -} - -/* ------------------------------------------------------------------------- */ -/** - * Prepares a positional update: Allocates an item and attach it to the end - * of the list of pending updates. - * - * @param window_ptr - * - * @return A pointer to a @ref wlmtk_pending_update_t, already positioned at the - * back of @ref wlmtk_window_t::pending_updates. - */ -wlmtk_pending_update_t *_wlmtk_window_prepare_update( - wlmtk_window_t *window_ptr) -{ - bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( - &window_ptr->available_updates); - if (NULL == dlnode_ptr) { - dlnode_ptr = bs_dllist_pop_front(&window_ptr->pending_updates); - bs_log(BS_WARNING, "Window %p: No updates available.", window_ptr); - // TODO(kaeser@gubbe.ch): Hm, should we apply this (old) update? - } - wlmtk_pending_update_t *update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); - bs_dllist_push_back(&window_ptr->pending_updates, &update_ptr->dlnode); - return update_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Releases a pending positional update. Moves it to the list of - * @ref wlmtk_window_t::available_updates. - * - * @param window_ptr - * @param update_ptr - */ -void _wlmtk_window_release_update( - wlmtk_window_t *window_ptr, - wlmtk_pending_update_t *update_ptr) -{ - bs_dllist_remove(&window_ptr->pending_updates, &update_ptr->dlnode); - bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); -} - -/* ------------------------------------------------------------------------- */ -/** Returns the workspace of the (mapped) window. */ -wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr) -{ - BS_ASSERT(NULL != wlmtk_window_element(window_ptr)->parent_container_ptr); - return wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr); -} - -/* == Implementation of the fake window ==================================== */ - -static void _wlmtk_fake_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated); -static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); -static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); -static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); -static void _wlmtk_fake_window_request_resize( - wlmtk_window_t *window_ptr, - uint32_t edges); -static void _wlmtk_fake_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height); - -/** Virtual method table for the fake window itself. */ -static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { - .set_activated = _wlmtk_fake_window_set_activated, - .request_close = _wlmtk_fake_window_request_close, - .request_minimize = _wlmtk_fake_window_request_minimize, - .request_move = _wlmtk_fake_window_request_move, - .request_resize = _wlmtk_fake_window_request_resize, - .request_position_and_size = _wlmtk_fake_window_request_position_and_size, - -}; - -/* ------------------------------------------------------------------------- */ -wlmtk_fake_window_t *wlmtk_fake_window_create(void) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = logged_calloc( - 1, sizeof(wlmtk_fake_window_state_t)); - if (NULL == fake_window_state_ptr) return NULL; - - fake_window_state_ptr->fake_window.fake_content_ptr = - wlmtk_fake_content_create(); - if (NULL == fake_window_state_ptr->fake_window.fake_content_ptr) { - wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); - return NULL; - } - - if (!_wlmtk_window_init( - &fake_window_state_ptr->window, - NULL, - &fake_window_state_ptr->fake_window.fake_content_ptr->content)) { - wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); - return NULL; - } - fake_window_state_ptr->fake_window.window_ptr = - &fake_window_state_ptr->window; - - // Extend. We don't save the VMT, since it's for fake only. - _wlmtk_window_extend(&fake_window_state_ptr->window, - &_wlmtk_fake_window_vmt); - return &fake_window_state_ptr->fake_window; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - fake_window_ptr, wlmtk_fake_window_state_t, fake_window); - - _wlmtk_window_fini(&fake_window_state_ptr->window); - free(fake_window_state_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_set_activated. Records call. */ -void _wlmtk_fake_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.activated = activated; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_close. Records call. */ -void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_close_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_minimize. Records call. */ -void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_minimize_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_move. Records call */ -void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_move_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_resize. Records call. */ -void _wlmtk_fake_window_request_resize( - wlmtk_window_t *window_ptr, - uint32_t edges) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_resize_called = true; - fake_window_state_ptr->fake_window.request_resize_edges = edges; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_position_and_size. */ -void _wlmtk_fake_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_position_and_size_called = true; - fake_window_state_ptr->fake_window.x = x; - fake_window_state_ptr->fake_window.y = y; - fake_window_state_ptr->fake_window.width = width; - fake_window_state_ptr->fake_window.height = height; -} - -/* == Unit tests =========================================================== */ - -static void test_create_destroy(bs_test_t *test_ptr); -static void test_set_title(bs_test_t *test_ptr); -static void test_request_close(bs_test_t *test_ptr); -static void test_set_activated(bs_test_t *test_ptr); -static void test_server_side_decorated(bs_test_t *test_ptr); -static void test_maximize(bs_test_t *test_ptr); -static void test_fake(bs_test_t *test_ptr); - -const bs_test_case_t wlmtk_window_test_cases[] = { - { 1, "create_destroy", test_create_destroy }, - { 1, "set_title", test_set_title }, - { 1, "request_close", test_request_close }, - { 1, "set_activated", test_set_activated }, - { 1, "set_server_side_decorated", test_server_side_decorated }, - { 1, "maximize", test_maximize }, - { 1, "fake", test_fake }, - { 0, NULL, NULL } -}; - -/* ------------------------------------------------------------------------- */ -/** Tests setup and teardown. */ -void test_create_destroy(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, window_ptr, - fake_content_ptr->content.window_ptr); - - wlmtk_window_destroy(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests title. */ -void test_set_title(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); - - wlmtk_window_set_title(window_ptr, "Title"); - BS_TEST_VERIFY_STREQ( - test_ptr, - "Title", - wlmtk_window_get_title(window_ptr)); - - wlmtk_window_set_title(window_ptr, NULL); - BS_TEST_VERIFY_STRMATCH( - test_ptr, - wlmtk_window_get_title(window_ptr), - "Unnamed window .*"); - - wlmtk_window_destroy(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests activation. */ -void test_request_close(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); - - wlmtk_window_request_close(window_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); - - wlmtk_window_destroy(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests activation. */ -void test_set_activated(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); - - wlmtk_window_set_activated(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); - - wlmtk_window_set_activated(window_ptr, false); - BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->activated); - - wlmtk_window_destroy(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests enabling and disabling server-side decoration. */ -void test_server_side_decorated(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); - - wlmtk_window_set_server_side_decorated(window_ptr, true); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); - - wlmtk_window_set_server_side_decorated(window_ptr, false); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); - - wlmtk_window_destroy(window_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests maximizing and un-maximizing a window. */ -void test_maximize(bs_test_t *test_ptr) -{ - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - struct wlr_box extents = { .width = 1024, .height = 768 }, box; - wlmtk_workspace_set_extents(workspace_ptr, &extents); - BS_ASSERT(NULL != workspace_ptr); - - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != window_ptr); - // Window must be mapped to get maximized: Need workspace dimensions. - wlmtk_workspace_map_window(workspace_ptr, window_ptr); - - // Set up initial organic size, and verify. - wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); - wlmtk_fake_content_commit(fake_content_ptr); - box = wlmtk_window_get_position_and_size(window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); - - // Re-position the window. - wlmtk_window_set_position(window_ptr, 50, 30); - box = wlmtk_window_get_position_and_size(window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - - // Trigger another serial update. Should not change position nor size. - wlmtk_window_serial(window_ptr, 1234); - box = wlmtk_window_get_position_and_size(window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - - // Maximize. - wlmtk_window_request_maximize(window_ptr, true); - wlmtk_fake_content_commit(fake_content_ptr); - box = wlmtk_window_get_position_and_size(window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); - - // A second commit: should not overwrite the organic dimension. - wlmtk_fake_content_commit(fake_content_ptr); - - // Unmaximize. Restore earlier organic size and position. - wlmtk_window_request_maximize(window_ptr, false); - wlmtk_fake_content_commit(fake_content_ptr); - box = wlmtk_window_get_position_and_size(window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); - - // TODO(kaeser@gubbe.ch): Define what should happen when a maximized - // window is moved. Should it lose maximization? Should it not move? - // Or just move on? - // Window Maker keeps maximization, but it's ... odd. - - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); - wlmtk_window_destroy(window_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests fake window ctor and dtor. */ -void test_fake(bs_test_t *test_ptr) -{ - wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_window_ptr); - wlmtk_fake_window_destroy(fake_window_ptr); -} - -/* == End of window.c ====================================================== */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h deleted file mode 100644 index fb99b4cd..00000000 --- a/src/toolkit/window.h +++ /dev/null @@ -1,319 +0,0 @@ -/* ========================================================================= */ -/** - * @file window.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __WLMTK_WINDOW_H__ -#define __WLMTK_WINDOW_H__ - -/** Forward declaration: Window. */ -typedef struct _wlmtk_window_t wlmtk_window_t; -/** Forward declaration: Virtual method table. */ -typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; - -#include "bordered.h" -#include "box.h" -#include "content.h" -#include "element.h" -#include "resizebar.h" -#include "titlebar.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Creates a window for the given content. - * - * @param env_ptr - * @param content_ptr Will take ownership of content_ptr. - * - * @return Pointer to the window state, or NULL on error. Must be free'd - * by calling @ref wlmtk_window_destroy. - */ -wlmtk_window_t *wlmtk_window_create( - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); - -/** - * Destroys the window. - * - * @param window_ptr - */ -void wlmtk_window_destroy(wlmtk_window_t *window_ptr); - -/** - * Returns the super Element of the window. - * - * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or - * whether to keep the ancestry members public. - * - * @param window_ptr - * - * @return Pointer to the @ref wlmtk_element_t base instantiation to - * window_ptr. - */ -wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); - -/** - * Returns the window from the super Element. - * - * @param element_ptr - * - * @return Pointer to the @ref wlmtk_window_t, for which `element_ptr` is - * the ancestor. - */ -wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr); - -/** - * Sets the window as activated, depending on the argument's value. - * - * An activated window will have keyboard focus and would have distinct - * decorations to indicate state. - * - * @param window_ptr - * @param activated - */ -void wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated); - -/** - * Sets whether to have server-side decorations for this window. - * - * @param window_ptr - * @param decorated - */ -void wlmtk_window_set_server_side_decorated( - wlmtk_window_t *window_ptr, - bool decorated); - -/** - * Sets the title for the window. - * - * If `title_ptr` is NULL, a generic name is set. - * - * @param window_ptr - * @param title_ptr May be NULL. - */ -void wlmtk_window_set_title( - wlmtk_window_t *window_ptr, - const char *title_ptr); - -/** - * Returns the title of the window. - * - * @param window_ptr - * - * @returns Pointer to the window title. Will remain valid until the next call - * to @ref wlmtk_window_set_title, or until the window is destroyed. Will - * never be NULL. - */ -const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr); - -/** - * Requests to close the window. - * - * @param window_ptr - */ -void wlmtk_window_request_close(wlmtk_window_t *window_ptr); - -/** - * Requests to minimize (iconify) the window. - * - * @param window_ptr - */ -void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); - -/** - * Reuests the window to be maximized. - * - * Requires the window to be mapped (to a workspace). Will lookup the maximize - * extents from the workspace, and request a corresponding updated position and - * size for the window. @ref wlmtk_window_t::organic_size will not be updated. - * - * This may be implemented as an asynchronous operation. Maximization will be - * applied once the size change has been committed by the content. - * - * @param window_ptr - * @param maximized - */ -void wlmtk_window_request_maximize( - wlmtk_window_t *window_ptr, - bool maximized); - -/** Returns whether the window is currently (requested to be) maximized. */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); - -/** - * Requests a move for the window. - * - * Requires the window to be mapped (to a workspace), and forwards the call to - * @ref wlmtk_workspace_begin_window_move. - * - * @param window_ptr - */ -void wlmtk_window_request_move(wlmtk_window_t *window_ptr); - -/** - * Requests the window to be resized. - * - * Requires the window to be mapped (to a workspace), and forwards the call to - * @ref wlmtk_workspace_begin_window_resize. - * - * @param window_ptr - * @param edges - */ -void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, - uint32_t edges); - -/** - * Sets the window's position. This is a synchronous operation. - * - * Updates the position in @ref wlmtk_window_t::organic_size. - * @param window_ptr - * @param x - * @param y - */ -void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y); - -/** - * Obtains the size of the window, including potential decorations. - * - * @param window_ptr - * @param width_ptr May be NULL. - * @param height_ptr May be NULL. - */ -void wlmtk_window_get_size( - wlmtk_window_t *window_ptr, - int *width_ptr, - int *height_ptr); - -/** - * Requests a new size for the window, including potential decorations. - * - * This may be implemented as an asynchronous operation. - * - * @param window_ptr - * @param width - * @param height - */ -void wlmtk_window_request_size( - wlmtk_window_t *window_ptr, - int width, - int height); - -/** - * Returns the current position and size of the window. - * - * @param window_ptr - * - * @return The position of the window (the window's element), and the currently - * committed width and height of the window. - */ -struct wlr_box wlmtk_window_get_position_and_size( - wlmtk_window_t *window_ptr); - -/** - * Requests an updated position and size for the window, including potential - * decorations. - * - * This may be implemented as an asynchronous operation. The re-positioning - * will be applied only once the size change has been committed by the client. - * - * The position and size will be stored in @ref wlmtk_window_t::organic_size. - * - * @param window_ptr - * @param x - * @param y - * @param width - * @param height - */ -void wlmtk_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height); - -/** - * Updates the window state to what was requested at the `serial`. - * - * Used for example when resizing a window from the top or left edges. In that - * case, @ref wlmtk_content_request_size may be asynchronous and returns a - * serial. The content is expected to call @ref wlmtk_window_serial with the - * returned serial when the size is committed. - * Only then, the corresponding positional update on the top/left edges are - * supposed to be applied. - * - * @ref wlmtk_window_t::organic_size will be updated, if there was no pending - * update: Meaning that the commit originated not from an earlier - * @ref wlmtk_window_request_position_and_size or @ref - * wlmtk_window_request_maximize call. - * - * @param window_ptr - * @param serial - */ -void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); - -/* ------------------------------------------------------------------------- */ - -/** State of the fake window, for tests. */ -typedef struct { - /** Window state. */ - wlmtk_window_t *window_ptr; - /** Fake content, to manipulate the fake window's content. */ - wlmtk_fake_content_t *fake_content_ptr; - - /** Argument to last @ref wlmtk_window_set_activated call. */ - bool activated; - /** Whether @ref wlmtk_window_request_close was called. */ - bool request_close_called; - /** Whether @ref wlmtk_window_request_minimize was called. */ - bool request_minimize_called; - /** Whether @ref wlmtk_window_request_move was called. */ - bool request_move_called; - /** Whether @ref wlmtk_window_request_resize was called. */ - bool request_resize_called; - /** Argument to last @ref wlmtk_window_request_resize call. */ - uint32_t request_resize_edges; - /** Whether @ref wlmtk_window_request_position_and_size was called. */ - bool request_position_and_size_called; - /** Argument to last @ref wlmtk_window_request_size call. */ - int x; - /** Argument to last @ref wlmtk_window_request_size call. */ - int y; - /** Argument to last @ref wlmtk_window_request_size call. */ - int width; - /** Argument to last @ref wlmtk_window_request_size call. */ - int height; -} wlmtk_fake_window_t; - -/** Ctor. */ -wlmtk_fake_window_t *wlmtk_fake_window_create(void); -/** Dtor. */ -void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr); - -/** Unit tests for window. */ -extern const bs_test_case_t wlmtk_window_test_cases[]; - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __WLMTK_WINDOW_H__ */ -/* == End of window.h ====================================================== */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 00c29529..2b9681f3 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -40,11 +40,11 @@ struct _wlmtk_workspace_t { /** Current FSM state. */ wlmtk_fsm_t fsm; - /** The activated window. */ - wlmtk_window_t *activated_window_ptr; + /** The activated toplevel. */ + wlmtk_toplevel_t *activated_toplevel_ptr; - /** The grabbed window. */ - wlmtk_window_t *grabbed_window_ptr; + /** The grabbed toplevel. */ + wlmtk_toplevel_t *grabbed_toplevel_ptr; /** Motion X */ int motion_x; /** Motion Y */ @@ -53,9 +53,9 @@ struct _wlmtk_workspace_t { int initial_x; /** Element's Y position when initiating a move or resize. */ int initial_y; - /** Window's width when initiazing the resize. */ + /** Toplevel's width when initiazing the resize. */ int initial_width; - /** Window's height when initiazing the resize. */ + /** Toplevel's height when initiazing the resize. */ int initial_height; /** Edges currently active for resizing: `enum wlr_edges`. */ uint32_t resize_edges; @@ -195,40 +195,40 @@ struct wlr_box wlmtk_workspace_get_maximize_extents( } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr) +void wlmtk_workspace_map_toplevel(wlmtk_workspace_t *workspace_ptr, + wlmtk_toplevel_t *toplevel_ptr) { - wlmtk_element_set_visible(wlmtk_window_element(window_ptr), true); + wlmtk_element_set_visible(wlmtk_toplevel_element(toplevel_ptr), true); wlmtk_container_add_element( &workspace_ptr->super_container, - wlmtk_window_element(window_ptr)); + wlmtk_toplevel_element(toplevel_ptr)); - wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_activate_toplevel(workspace_ptr, toplevel_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr) +void wlmtk_workspace_unmap_toplevel(wlmtk_workspace_t *workspace_ptr, + wlmtk_toplevel_t *toplevel_ptr) { bool need_activation = false; BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr)); + wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr)); - if (workspace_ptr->grabbed_window_ptr == window_ptr) { + if (workspace_ptr->grabbed_toplevel_ptr == toplevel_ptr) { wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); - BS_ASSERT(NULL == workspace_ptr->grabbed_window_ptr); + BS_ASSERT(NULL == workspace_ptr->grabbed_toplevel_ptr); } - if (workspace_ptr->activated_window_ptr == window_ptr) { - wlmtk_workspace_activate_window(workspace_ptr, NULL); + if (workspace_ptr->activated_toplevel_ptr == toplevel_ptr) { + wlmtk_workspace_activate_toplevel(workspace_ptr, NULL); need_activation = true; } - wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); + wlmtk_element_set_visible(wlmtk_toplevel_element(toplevel_ptr), false); wlmtk_container_remove_element( &workspace_ptr->super_container, - wlmtk_window_element(window_ptr)); + wlmtk_toplevel_element(toplevel_ptr)); if (need_activation) { // FIXME: What about raising? @@ -236,8 +236,8 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, workspace_ptr->super_container.elements.head_ptr; if (NULL != dlnode_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - wlmtk_window_t *window_ptr = wlmtk_window_from_element(element_ptr); - wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_from_element(element_ptr); + wlmtk_workspace_activate_toplevel(workspace_ptr, toplevel_ptr); } } } @@ -295,50 +295,50 @@ void wlmtk_workspace_button( } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_begin_window_move( +void wlmtk_workspace_begin_toplevel_move( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr) + wlmtk_toplevel_t *toplevel_ptr) { - wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_MOVE, window_ptr); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_MOVE, toplevel_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_begin_window_resize( +void wlmtk_workspace_begin_toplevel_resize( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, uint32_t edges) { workspace_ptr->resize_edges = edges; - wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_RESIZE, window_ptr); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_RESIZE, toplevel_ptr); } /* ------------------------------------------------------------------------- */ -/** Acticates `window_ptr`. Will de-activate an earlier window. */ -void wlmtk_workspace_activate_window( +/** Acticates `toplevel_ptr`. Will de-activate an earlier toplevel. */ +void wlmtk_workspace_activate_toplevel( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr) + wlmtk_toplevel_t *toplevel_ptr) { // Nothing to do. - if (workspace_ptr->activated_window_ptr == window_ptr) return; + if (workspace_ptr->activated_toplevel_ptr == toplevel_ptr) return; - if (NULL != workspace_ptr->activated_window_ptr) { - wlmtk_window_set_activated(workspace_ptr->activated_window_ptr, false); - workspace_ptr->activated_window_ptr = NULL; + if (NULL != workspace_ptr->activated_toplevel_ptr) { + wlmtk_toplevel_set_activated(workspace_ptr->activated_toplevel_ptr, false); + workspace_ptr->activated_toplevel_ptr = NULL; } - if (NULL != window_ptr) { - wlmtk_window_set_activated(window_ptr, true); - workspace_ptr->activated_window_ptr = window_ptr; + if (NULL != toplevel_ptr) { + wlmtk_toplevel_set_activated(toplevel_ptr, true); + workspace_ptr->activated_toplevel_ptr = toplevel_ptr; } } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_raise_window( +void wlmtk_workspace_raise_toplevel( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr) + wlmtk_toplevel_t *toplevel_ptr) { wlmtk_container_raise_element_to_top(&workspace_ptr->super_container, - wlmtk_window_element(window_ptr)); + wlmtk_toplevel_element(toplevel_ptr)); } /* == Local (static) methods =============================================== */ @@ -470,14 +470,14 @@ bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( fsm_ptr, wlmtk_workspace_t, fsm); - workspace_ptr->grabbed_window_ptr = ud_ptr; + workspace_ptr->grabbed_toplevel_ptr = ud_ptr; workspace_ptr->motion_x = workspace_ptr->super_container.super_element.last_pointer_x; workspace_ptr->motion_y = workspace_ptr->super_container.super_element.last_pointer_y; wlmtk_element_get_position( - wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + wlmtk_toplevel_element(workspace_ptr->grabbed_toplevel_ptr), &workspace_ptr->initial_x, &workspace_ptr->initial_y); @@ -498,8 +498,8 @@ bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) double rel_y = workspace_ptr->super_container.super_element.last_pointer_y - workspace_ptr->motion_y; - wlmtk_window_set_position( - workspace_ptr->grabbed_window_ptr, + wlmtk_toplevel_set_position( + workspace_ptr->grabbed_toplevel_ptr, workspace_ptr->initial_x + rel_x, workspace_ptr->initial_y + rel_y); @@ -513,19 +513,19 @@ bool pfsm_resize_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( fsm_ptr, wlmtk_workspace_t, fsm); - workspace_ptr->grabbed_window_ptr = ud_ptr; + workspace_ptr->grabbed_toplevel_ptr = ud_ptr; workspace_ptr->motion_x = workspace_ptr->super_container.super_element.last_pointer_x; workspace_ptr->motion_y = workspace_ptr->super_container.super_element.last_pointer_y; wlmtk_element_get_position( - wlmtk_window_element(workspace_ptr->grabbed_window_ptr), + wlmtk_toplevel_element(workspace_ptr->grabbed_toplevel_ptr), &workspace_ptr->initial_x, &workspace_ptr->initial_y); - wlmtk_window_get_size( - workspace_ptr->grabbed_window_ptr, + wlmtk_toplevel_get_size( + workspace_ptr->grabbed_toplevel_ptr, &workspace_ptr->initial_width, &workspace_ptr->initial_height); @@ -565,8 +565,8 @@ bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) if (right <= left) right = left + 1; } - wlmtk_window_request_position_and_size( - workspace_ptr->grabbed_window_ptr, + wlmtk_toplevel_request_position_and_size( + workspace_ptr->grabbed_toplevel_ptr, left, top, right - left, bottom - top); return true; @@ -578,7 +578,7 @@ bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( fsm_ptr, wlmtk_workspace_t, fsm); - workspace_ptr->grabbed_window_ptr = NULL; + workspace_ptr->grabbed_toplevel_ptr = NULL; return true; } @@ -640,7 +640,7 @@ void test_create_destroy(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Verifies that mapping and unmapping windows works. */ +/** Verifies that mapping and unmapping toplevels works. */ void test_map_unmap(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -650,34 +650,34 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( NULL, &fake_content_ptr->content); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_element(toplevel_ptr)->visible); + wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); + wlmtk_toplevel_element(toplevel_ptr)->wlr_scene_node_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, fake_content_ptr->content.super_element.wlr_scene_node_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_toplevel_element(toplevel_ptr)->visible); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); + wlmtk_toplevel_element(toplevel_ptr)->wlr_scene_node_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, fake_content_ptr->content.super_element.wlr_scene_node_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_element(toplevel_ptr)->visible); - wlmtk_window_destroy(window_ptr); + wlmtk_toplevel_destroy(toplevel_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } @@ -742,7 +742,7 @@ void test_button(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests moving a window. */ +/** Tests moving a toplevel. */ void test_move(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -751,20 +751,20 @@ void test_move(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != window_ptr); + BS_ASSERT(NULL != toplevel_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); - // Starts a move for the window. Will move it... - wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); + // Starts a move for the toplevel. Will move it... + wlmtk_workspace_begin_toplevel_move(workspace_ptr, toplevel_ptr); wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); // Releases the button. Should end the move. struct wlr_pointer_button_event wlr_pointer_button_event = { @@ -773,22 +773,22 @@ void test_move(bs_test_t *test_ptr) .time_msec = 44, }; wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_toplevel_ptr); // More motion, no longer updates the position. wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); - wlmtk_window_destroy(window_ptr); + wlmtk_toplevel_destroy(toplevel_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ -/** Tests moving a window that unmaps during the move. */ +/** Tests moving a toplevel that unmaps during the move. */ void test_unmap_during_move(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -797,42 +797,42 @@ void test_unmap_during_move(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != window_ptr); + BS_ASSERT(NULL != toplevel_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); - // Starts a move for the window. Will move it... - wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); + // Starts a move for the toplevel. Will move it... + wlmtk_workspace_begin_toplevel_move(workspace_ptr, toplevel_ptr); wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_toplevel_ptr); // More motion, no longer updates the position. wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); // More motion, no longer updates the position. wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); - wlmtk_window_destroy(window_ptr); + wlmtk_toplevel_destroy(toplevel_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ -/** Tests resizing a window. */ +/** Tests resizing a toplevel. */ void test_resize(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -841,35 +841,35 @@ void test_resize(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != window_ptr); - wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); + BS_ASSERT(NULL != toplevel_ptr); + wlmtk_toplevel_request_position_and_size(toplevel_ptr, 0, 0, 40, 20); wlmtk_fake_content_commit(fake_content_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); int width, height; - wlmtk_window_get_size(window_ptr, &width, &height); + wlmtk_toplevel_get_size(toplevel_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 40, width); BS_TEST_VERIFY_EQ(test_ptr, 20, height); - // Starts a resize for the window. Will resize & move it... - wlmtk_workspace_begin_window_resize( - workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); + // Starts a resize for the toplevel. Will resize & move it... + wlmtk_workspace_begin_toplevel_resize( + workspace_ptr, toplevel_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); fake_content_ptr->return_request_size = 1; // The serial. wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 37, fake_content_ptr->requested_width); BS_TEST_VERIFY_EQ(test_ptr, 16, fake_content_ptr->requested_height); // This updates for the given serial. wlmtk_fake_content_commit(fake_content_ptr); - wlmtk_window_get_size(window_ptr, &width, &height); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + wlmtk_toplevel_get_size(toplevel_ptr, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 39, width); BS_TEST_VERIFY_EQ(test_ptr, 18, height); @@ -880,16 +880,16 @@ void test_resize(bs_test_t *test_ptr) .time_msec = 44, }; wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_toplevel_ptr); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); - wlmtk_window_destroy(window_ptr); + wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_toplevel_destroy(toplevel_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ -/** Tests window activation. */ +/** Tests toplevel activation. */ void test_activate(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -898,34 +898,34 @@ void test_activate(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); - // Window 1: from (0, 0) to (100, 100) - wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); + // Toplevel 1: from (0, 0) to (100, 100) + wlmtk_fake_toplevel_t *fw1_ptr = wlmtk_fake_toplevel_create(); wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); + wlmtk_toplevel_set_position(fw1_ptr->toplevel_ptr, 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); - // Window 1 is mapped => it's activated. - wlmtk_workspace_map_window(workspace_ptr, fw1_ptr->window_ptr); + // Toplevel 1 is mapped => it's activated. + wlmtk_workspace_map_toplevel(workspace_ptr, fw1_ptr->toplevel_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); - // Window 2: from (200, 0) to (300, 100). - // Window 2 is mapped: Will get activated, and 1st one de-activated. - wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); + // Toplevel 2: from (200, 0) to (300, 100). + // Toplevel 2 is mapped: Will get activated, and 1st one de-activated. + wlmtk_fake_toplevel_t *fw2_ptr = wlmtk_fake_toplevel_create(); wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); + wlmtk_toplevel_set_position(fw2_ptr->toplevel_ptr, 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); + wlmtk_workspace_map_toplevel(workspace_ptr, fw2_ptr->toplevel_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Pointer move, over window 1. Nothing happens: We have click-to-focus. + // Pointer move, over toplevel 1. Nothing happens: We have click-to-focus. BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_workspace_motion(workspace_ptr, 50, 50, 0)); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Click on window 1: Gets activated. + // Click on toplevel 1: Gets activated. struct wlr_pointer_button_event wlr_button_event = { .button = BTN_RIGHT, .state = WLR_BUTTON_PRESSED }; @@ -933,17 +933,17 @@ void test_activate(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - // Unmap window 1. Now window 2 gets activated. - wlmtk_workspace_unmap_window(workspace_ptr, fw1_ptr->window_ptr); + // Unmap toplevel 1. Now toplevel 2 gets activated. + wlmtk_workspace_unmap_toplevel(workspace_ptr, fw1_ptr->toplevel_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Unmap the remaining window 2. Nothing is activated. - wlmtk_workspace_unmap_window(workspace_ptr, fw2_ptr->window_ptr); + // Unmap the remaining toplevel 2. Nothing is activated. + wlmtk_workspace_unmap_toplevel(workspace_ptr, fw2_ptr->toplevel_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - wlmtk_fake_window_destroy(fw2_ptr); - wlmtk_fake_window_destroy(fw1_ptr); + wlmtk_fake_toplevel_destroy(fw2_ptr); + wlmtk_fake_toplevel_destroy(fw1_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 0859f892..b36dff08 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -21,7 +21,7 @@ #define __WLMTK_WORKSPACE_H__ #include "container.h" -#include "window.h" +#include "toplevel.h" #ifdef __cplusplus extern "C" { @@ -68,7 +68,7 @@ void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, const struct wlr_box *extents_ptr); /** - * Returns the extents of the workspace available for maximized windows. + * Returns the extents of the workspace available for maximized toplevels. * * @param workspace_ptr * @@ -78,22 +78,22 @@ struct wlr_box wlmtk_workspace_get_maximize_extents( wlmtk_workspace_t *workspace_ptr); /** - * Maps the window: Adds it to the workspace container and makes it visible. + * Maps the toplevel: Adds it to the workspace container and makes it visible. * * @param workspace_ptr - * @param window_ptr + * @param toplevel_ptr */ -void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); +void wlmtk_workspace_map_toplevel(wlmtk_workspace_t *workspace_ptr, + wlmtk_toplevel_t *toplevel_ptr); /** - * Unmaps the window: Sets it as invisible and removes it from the container. + * Unmaps the toplevel: Sets it as invisible and removes it from the container. * * @param workspace_ptr - * @param window_ptr + * @param toplevel_ptr */ -void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); +void wlmtk_workspace_unmap_toplevel(wlmtk_workspace_t *workspace_ptr, + wlmtk_toplevel_t *toplevel_ptr); /** * Type conversion: Returns the @ref wlmtk_workspace_t from the container_ptr @@ -145,36 +145,36 @@ void wlmtk_workspace_button( const struct wlr_pointer_button_event *event_ptr); /** - * Initiates a 'move' for the window. + * Initiates a 'move' for the toplevel. * * @param workspace_ptr - * @param window_ptr + * @param toplevel_ptr */ -void wlmtk_workspace_begin_window_move( +void wlmtk_workspace_begin_toplevel_move( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); + wlmtk_toplevel_t *toplevel_ptr); /** - * Initiates a 'resize' for the window. + * Initiates a 'resize' for the toplevel. * * @param workspace_ptr - * @param window_ptr + * @param toplevel_ptr * @param edges */ -void wlmtk_workspace_begin_window_resize( +void wlmtk_workspace_begin_toplevel_resize( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr, + wlmtk_toplevel_t *toplevel_ptr, uint32_t edges); -/** Acticates `window_ptr`. Will de-activate an earlier window. */ -void wlmtk_workspace_activate_window( +/** Acticates `toplevel_ptr`. Will de-activate an earlier toplevel. */ +void wlmtk_workspace_activate_toplevel( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); + wlmtk_toplevel_t *toplevel_ptr); -/** Raises `window_ptr`: Will show it atop all other windows. */ -void wlmtk_workspace_raise_window( +/** Raises `toplevel_ptr`: Will show it atop all other toplevels. */ +void wlmtk_workspace_raise_toplevel( wlmtk_workspace_t *workspace_ptr, - wlmtk_window_t *window_ptr); + wlmtk_toplevel_t *toplevel_ptr); /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; diff --git a/src/wlmtk_xdg_popup.c b/src/wlmtk_xdg_popup.c index a8d51f9e..f9c4ded6 100644 --- a/src/wlmtk_xdg_popup.c +++ b/src/wlmtk_xdg_popup.c @@ -27,7 +27,7 @@ /* ------------------------------------------------------------------------- */ void wlmtk_create_popup( __UNUSED__ struct wlr_xdg_popup *wlr_xdg_popup_ptr, - __UNUSED__ wlmtk_window_t *window_ptr) + __UNUSED__ wlmtk_toplevel_t *toplevel_ptr) { } diff --git a/src/wlmtk_xdg_popup.h b/src/wlmtk_xdg_popup.h index ad040758..4a7296e0 100644 --- a/src/wlmtk_xdg_popup.h +++ b/src/wlmtk_xdg_popup.h @@ -33,11 +33,11 @@ extern "C" { * Creates a popup. * * @param wlr_xdg_popup_ptr - * @param window_ptr + * @param toplevel_ptr */ void wlmtk_create_popup( struct wlr_xdg_popup *wlr_xdg_popup_ptr, - wlmtk_window_t *window_ptr); + wlmtk_toplevel_t *toplevel_ptr); #ifdef __cplusplus } // extern "C" diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 640a25f5..0485b260 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -122,7 +122,7 @@ const wlmtk_content_vmt_t _wlmtk_xdg_toplevel_content_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( +wlmtk_toplevel_t *wlmtk_toplevel_create_from_xdg_toplevel( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr) { @@ -130,14 +130,14 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, server_ptr); if (NULL == content_ptr) return NULL; - wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( + wlmtk_toplevel_t *wlmtk_toplevel_ptr = wlmtk_toplevel_create( server_ptr->env_ptr, &content_ptr->super_content); - if (NULL == wlmtk_window_ptr) { + if (NULL == wlmtk_toplevel_ptr) { content_element_destroy(&content_ptr->super_content.super_element); return NULL; } - return wlmtk_window_ptr; + return wlmtk_toplevel_ptr; } /* == Local (static) methods =============================================== */ @@ -364,8 +364,8 @@ void handle_destroy(struct wl_listener *listener_ptr, { wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_content_t, destroy_listener); - // Destroy the window -> also destroys the content. - wlmtk_window_destroy(xdg_tl_content_ptr->super_content.window_ptr); + // Destroy the toplevel -> also destroys the content. + wlmtk_toplevel_destroy(xdg_tl_content_ptr->super_content.toplevel_ptr); } /* ------------------------------------------------------------------------- */ @@ -406,9 +406,9 @@ void handle_surface_map( wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( wlmaker_server_get_current_workspace(xdg_tl_content_ptr->server_ptr)); - wlmtk_workspace_map_window( + wlmtk_workspace_map_toplevel( wlmtk_workspace_ptr, - xdg_tl_content_ptr->super_content.window_ptr); + xdg_tl_content_ptr->super_content.toplevel_ptr); } /* ------------------------------------------------------------------------- */ @@ -425,11 +425,11 @@ void handle_surface_unmap( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_content_t, surface_unmap_listener); - wlmtk_window_t *window_ptr = xdg_tl_content_ptr->super_content.window_ptr; - wlmtk_workspace_unmap_window( + wlmtk_toplevel_t *toplevel_ptr = xdg_tl_content_ptr->super_content.toplevel_ptr; + wlmtk_workspace_unmap_toplevel( wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr), - window_ptr); + wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr), + toplevel_ptr); } /* ------------------------------------------------------------------------- */ @@ -470,9 +470,9 @@ void handle_toplevel_request_maximize( listener_ptr, wlmtk_xdg_toplevel_content_t, toplevel_request_maximize_listener); - wlmtk_window_request_maximize( - xdg_tl_content_ptr->super_content.window_ptr, - !wlmtk_window_maximized(xdg_tl_content_ptr->super_content.window_ptr)); + wlmtk_toplevel_request_maximize( + xdg_tl_content_ptr->super_content.toplevel_ptr, + !wlmtk_toplevel_maximized(xdg_tl_content_ptr->super_content.toplevel_ptr)); } /* ------------------------------------------------------------------------- */ @@ -490,7 +490,7 @@ void handle_toplevel_request_move( listener_ptr, wlmtk_xdg_toplevel_content_t, toplevel_request_move_listener); - wlmtk_window_request_move(xdg_tl_content_ptr->super_content.window_ptr); + wlmtk_toplevel_request_move(xdg_tl_content_ptr->super_content.toplevel_ptr); } /* ------------------------------------------------------------------------- */ @@ -509,8 +509,8 @@ void handle_toplevel_request_resize( wlmtk_xdg_toplevel_content_t, toplevel_request_resize_listener); struct wlr_xdg_toplevel_resize_event *resize_event_ptr = data_ptr; - wlmtk_window_request_resize( - xdg_tl_content_ptr->super_content.window_ptr, + wlmtk_toplevel_request_resize( + xdg_tl_content_ptr->super_content.toplevel_ptr, resize_event_ptr->edges); } @@ -530,8 +530,8 @@ void handle_toplevel_set_title( wlmtk_xdg_toplevel_content_t, toplevel_set_title_listener); - wlmtk_window_set_title( - xdg_tl_content_ptr->super_content.window_ptr, + wlmtk_toplevel_set_title( + xdg_tl_content_ptr->super_content.toplevel_ptr, xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->title); } diff --git a/src/wlmtk_xdg_toplevel.h b/src/wlmtk_xdg_toplevel.h index c4cae753..25bf7ccf 100644 --- a/src/wlmtk_xdg_toplevel.h +++ b/src/wlmtk_xdg_toplevel.h @@ -34,7 +34,7 @@ extern "C" { * * @return The window, or NULL on error. */ -wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( +wlmtk_toplevel_t *wlmtk_toplevel_create_from_xdg_toplevel( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr); diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 56d65cc7..28ba389d 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -271,8 +271,8 @@ void handle_decoration_request_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode, mode); - wlmtk_window_set_server_side_decorated( - content_ptr->window_ptr, + wlmtk_toplevel_set_server_side_decorated( + content_ptr->toplevel_ptr, mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } else { diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 41631214..cec5f6af 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -135,10 +135,10 @@ void handle_new_surface(struct wl_listener *listener_ptr, path_exe[rv] = '\0'; if (0 == strcmp(path_exe, "/usr/bin/foot") || 0 == strcmp(path_exe, "/opt/google/chrome/chrome")) { - wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( + wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create_from_xdg_toplevel( wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); - bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", - window_ptr, wlr_xdg_surface_ptr); + bs_log(BS_INFO, "XDG shell: Toolkit toplevel %p for surface %p", + toplevel_ptr, wlr_xdg_surface_ptr); break; } #endif // defined(ENABLE_TOOLKIT_PROTOTYPE) From cdda97074583c745de38cba12d6da6891384e08e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 26 Dec 2023 14:45:23 +0100 Subject: [PATCH 318/390] Adjusts the ifndef protective. --- src/toolkit/env.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/toolkit/env.h b/src/toolkit/env.h index 6b0ca35e..9c55550a 100644 --- a/src/toolkit/env.h +++ b/src/toolkit/env.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __ENV_H__ -#define __ENV_H__ +#ifndef __WLMTK_ENV_H__ +#define __WLMTK_ENV_H__ /** Forward declaration: Environment. */ typedef struct _wlmtk_env_t wlmtk_env_t; @@ -86,5 +86,5 @@ struct wlr_seat *wlmtk_env_wlr_seat(wlmtk_env_t *env_ptr); } // extern "C" #endif // __cplusplus -#endif /* __ENV_H__ */ +#endif /* __WLMTK_ENV_H__ */ /* == End of env.h ========================================================= */ From 7943a84e545358e0f91c5593baa6fa4cc954eb2c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 26 Dec 2023 19:05:55 +0100 Subject: [PATCH 319/390] Adds boilerplate for the new wlmtk_window_t. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/surface.c | 11 +++++ src/toolkit/surface.h | 10 +++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + src/toolkit/window.c | 87 ++++++++++++++++++++++++++++++++++++++ src/toolkit/window.h | 73 ++++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+) create mode 100644 src/toolkit/window.c create mode 100644 src/toolkit/window.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 3d9b8eaa..0e8ae321 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -39,6 +39,7 @@ SET(PUBLIC_HEADER_FILES titlebar_button.h titlebar_title.h toplevel.h + window.h workspace.h) ADD_LIBRARY(toolkit STATIC) @@ -61,6 +62,7 @@ TARGET_SOURCES(toolkit PRIVATE titlebar.c titlebar_button.c titlebar_title.c + window.c util.c toplevel.c workspace.c) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 5375373f..145c7a6c 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -102,6 +102,12 @@ void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr) free(surface_ptr); } +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_surface_element(wlmtk_surface_t *surface_ptr) +{ + return &surface_ptr->super_element; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -317,6 +323,11 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, surface_ptr); + BS_TEST_VERIFY_EQ( + test_ptr, + &surface_ptr->super_element, + wlmtk_surface_element(surface_ptr)); + wlmtk_surface_destroy(surface_ptr); } diff --git a/src/toolkit/surface.h b/src/toolkit/surface.h index dfd761ee..f198f81c 100644 --- a/src/toolkit/surface.h +++ b/src/toolkit/surface.h @@ -22,6 +22,7 @@ #include +#include "element.h" #include "env.h" /** Forward declaration. */ @@ -51,6 +52,15 @@ wlmtk_surface_t *wlmtk_surface_create( */ void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr); +/** + * Returns a pointer to the surface's element superclass instance. + * + * @param surface_ptr + * + * @return Pointer to the corresponding @ref wlmtk_element_t. + */ +wlmtk_element_t *wlmtk_surface_element(wlmtk_surface_t *surface_ptr); + /** Unit test cases. */ extern const bs_test_case_t wlmtk_surface_test_cases[]; diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index f67b42e6..c4be88df 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -48,6 +48,7 @@ #include "titlebar_button.h" #include "titlebar_title.h" #include "toplevel.h" +#include "window.h" #include "workspace.h" #ifdef __cplusplus diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index bbcf2cda..cd237125 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -37,6 +37,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, { 1, "toplevel", wlmtk_toplevel_test_cases }, + { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } diff --git a/src/toolkit/window.c b/src/toolkit/window.c new file mode 100644 index 00000000..52f17ce7 --- /dev/null +++ b/src/toolkit/window.c @@ -0,0 +1,87 @@ +/* ========================================================================= */ +/** + * @file window.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "window.h" + +/* == Declarations ========================================================= */ + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_init( + wlmtk_window_t *window_ptr, + wlmtk_surface_t *surface_ptr, + wlmtk_env_t *env_ptr) +{ + BS_ASSERT(NULL != window_ptr); + memset(window_ptr, 0, sizeof(wlmtk_window_t)); + if (!wlmtk_container_init(&window_ptr->super_container, env_ptr)) { + return false; + } + + BS_ASSERT(NULL != surface_ptr); + window_ptr->surface_ptr = surface_ptr; + wlmtk_container_add_element( + &window_ptr->super_container, + wlmtk_surface_element(window_ptr->surface_ptr)); + + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_fini( + wlmtk_window_t *window_ptr) +{ + if (NULL != window_ptr->surface_ptr) { + wlmtk_container_remove_element( + &window_ptr->super_container, + wlmtk_surface_element(window_ptr->surface_ptr)); + window_ptr->surface_ptr = NULL; + } + + wlmtk_container_fini(&window_ptr->super_container); + memset(window_ptr, 0, sizeof(wlmtk_window_t)); +} + +/* == Local (static) methods =============================================== */ + +static void test_init_fini(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_window_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests initialization and un-initialization. */ +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_window_t window; + wlmtk_surface_t *surface_ptr = wlmtk_surface_create(NULL, NULL); + + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_window_init(&window, surface_ptr, NULL)); + wlmtk_window_fini(&window); + + wlmtk_surface_destroy(surface_ptr); +} + +/* == End of window.c ====================================================== */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h new file mode 100644 index 00000000..3b22f1e2 --- /dev/null +++ b/src/toolkit/window.h @@ -0,0 +1,73 @@ +/* ========================================================================= */ +/** + * @file window.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_WINDOW_H__ +#define __WLMTK_WINDOW_H__ + +/** Forward declaration. */ +typedef struct _wlmtk_window_t wlmtk_window_t; + +#include "container.h" +#include "surface.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** Window state. */ +struct _wlmtk_window_t { + /** Super class of the window. */ + wlmtk_container_t super_container; + /** Virtual method table of the superclass' container. */ + wlmtk_container_vmt_t orig_super_container_vmt; + + /** The principal surface of the window. */ + wlmtk_surface_t *surface_ptr; +}; + +/** + * Initializes the window with the provided surface. + * + * @param window_ptr + * @param surface_ptr + * @param env_ptr + * + * @return true on success. + */ +bool wlmtk_window_init( + wlmtk_window_t *window_ptr, + wlmtk_surface_t *surface_ptr, + wlmtk_env_t *env_ptr); + +/** + * Un-initializes the window. + * + * @param window_ptr + */ +void wlmtk_window_fini(wlmtk_window_t *window_ptr); + +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_window_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_WINDOW_H__ */ +/* == End of window.h ====================================================== */ From b50efa69b480d3efcb29bd9a2b0e5a3faa56421c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 26 Dec 2023 20:56:40 +0100 Subject: [PATCH 320/390] Keeps adding functionality to wlmtk_surface_t. --- src/toolkit/surface.c | 209 ++++++++++++++++++++++++++++++++++++------ src/toolkit/surface.h | 111 ++++++++++++++++++++-- src/toolkit/window.c | 7 +- 3 files changed, 291 insertions(+), 36 deletions(-) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 145c7a6c..fa5d7cea 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -21,6 +21,7 @@ #include "surface.h" #include "element.h" +#include "util.h" #define WLR_USE_UNSTABLE #include @@ -30,17 +31,6 @@ /* == Declarations ========================================================= */ -/** State of a `struct wlr_surface`, encapsuled for toolkit. */ -struct _wlmtk_surface_t { - /** Super class of the surface: An element. */ - wlmtk_element_t super_element; - /** Virtual method table of the super element before extending it. */ - wlmtk_element_vmt_t orig_super_element_vmt; - - /** The `struct wlr_surface` wrapped. */ - struct wlr_surface *wlr_surface_ptr; -}; - static void _wlmtk_surface_element_get_dimensions( wlmtk_element_t *element_ptr, int *left_ptr, @@ -63,6 +53,10 @@ static bool _wlmtk_surface_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); +static void handle_surface_commit( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr); + /* == Data ================================================================= */ /** Method table for the element's virtual methods. */ @@ -77,29 +71,55 @@ static const wlmtk_element_vmt_t surface_element_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_surface_t *wlmtk_surface_create( +bool wlmtk_surface_init( + wlmtk_surface_t *surface_ptr, struct wlr_surface *wlr_surface_ptr, wlmtk_env_t *env_ptr) { - wlmtk_surface_t *surface_ptr = logged_calloc(1, sizeof(wlmtk_surface_t)); - if (NULL == surface_ptr) return NULL; + BS_ASSERT(NULL != surface_ptr); + memset(surface_ptr, 0, sizeof(wlmtk_surface_t)); if (!wlmtk_element_init(&surface_ptr->super_element, env_ptr)) { - wlmtk_surface_destroy(surface_ptr); - return NULL; + wlmtk_surface_fini(surface_ptr); + return false; } surface_ptr->orig_super_element_vmt = wlmtk_element_extend( &surface_ptr->super_element, &surface_element_vmt); surface_ptr->wlr_surface_ptr = wlr_surface_ptr; - return surface_ptr; + if (NULL != surface_ptr->wlr_surface_ptr) { + wlmtk_util_connect_listener_signal( + &surface_ptr->wlr_surface_ptr->events.commit, + &surface_ptr->surface_commit_listener, + handle_surface_commit); + } + return true; } /* ------------------------------------------------------------------------- */ -void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr) +void wlmtk_surface_fini(wlmtk_surface_t *surface_ptr) { + if (NULL != surface_ptr->wlr_surface_ptr) { + wl_list_remove(&surface_ptr->surface_commit_listener.link); + surface_ptr->wlr_surface_ptr= NULL; + } + wlmtk_element_fini(&surface_ptr->super_element); - free(surface_ptr); + memset(surface_ptr, 0, sizeof(wlmtk_surface_t)); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_surface_vmt_t wlmtk_surface_extend( + wlmtk_surface_t *surface_ptr, + const wlmtk_surface_vmt_t *surface_vmt_ptr) +{ + wlmtk_surface_vmt_t orig_vmt = surface_ptr->vmt; + + if (NULL != surface_vmt_ptr->request_size) { + surface_ptr->vmt.request_size = surface_vmt_ptr->request_size; + } + + return orig_vmt; } /* ------------------------------------------------------------------------- */ @@ -108,6 +128,16 @@ wlmtk_element_t *wlmtk_surface_element(wlmtk_surface_t *surface_ptr) return &surface_ptr->super_element; } +/* ------------------------------------------------------------------------- */ +void wlmtk_surface_get_size( + wlmtk_surface_t *surface_ptr, + int *width_ptr, + int *height_ptr) +{ + if (NULL != width_ptr) *width_ptr = surface_ptr->committed_width; + if (NULL != height_ptr) *height_ptr = surface_ptr->committed_height; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -306,29 +336,154 @@ bool _wlmtk_surface_element_pointer_button( return false; } +/* ------------------------------------------------------------------------- */ +/** + * Commits the given dimensions for the surface. + * + * @param surface_ptr + * @param serial + * @param width + * @param height + */ +void _wlmtk_surface_commit_size( + wlmtk_surface_t *surface_ptr, + uint32_t serial, + int width, + int height) +{ + serial = serial; // FIXME + + surface_ptr->committed_width = width; + surface_ptr->committed_height = height; +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `commit` signal of the `struct wlr_surface`. + * + * @param listener_ptr + * @param data_ptr Points to the const struct wlr_surface. + */ +void handle_surface_commit( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_surface_t, surface_commit_listener); + + _wlmtk_surface_commit_size( + surface_ptr, + 0, // FIXME: Where do we get the serial from? + surface_ptr->wlr_surface_ptr->current.width, + surface_ptr->wlr_surface_ptr->current.height); +} + +/* == Fake surface methods ================================================= */ + +static uint32_t _wlmtk_fake_surface_request_size( + wlmtk_surface_t *surface_ptr, + int width, + int height); + +/** Virtual method table for the fake surface. */ +static const wlmtk_surface_vmt_t _wlmtk_fake_surface_vmt = { + .request_size = _wlmtk_fake_surface_request_size, +}; + +/* ------------------------------------------------------------------------- */ +wlmtk_fake_surface_t *wlmtk_fake_surface_create(void) +{ + wlmtk_fake_surface_t *fake_surface_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_surface_t)); + if (NULL == fake_surface_ptr) return NULL; + + wlmtk_surface_init(&fake_surface_ptr->surface, NULL, NULL); + wlmtk_surface_extend(&fake_surface_ptr->surface, &_wlmtk_fake_surface_vmt); + return fake_surface_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_surface_destroy(wlmtk_fake_surface_t *fake_surface_ptr) +{ + wlmtk_surface_fini(&fake_surface_ptr->surface); + free(fake_surface_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_surface_commit(wlmtk_fake_surface_t *fake_surface_ptr) +{ + _wlmtk_surface_commit_size( + &fake_surface_ptr->surface, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_surface_vmt_t::request_size. */ +uint32_t _wlmtk_fake_surface_request_size( + wlmtk_surface_t *surface_ptr, + int width, + int height) +{ + wlmtk_fake_surface_t *fake_surface_ptr = BS_CONTAINER_OF( + surface_ptr, wlmtk_fake_surface_t, surface); + fake_surface_ptr->requested_width = width; + fake_surface_ptr->requested_height = height; + return fake_surface_ptr->serial; +} + /* == Unit tests =========================================================== */ -static void test_create_destroy(bs_test_t *test_ptr); +static void test_init_fini(bs_test_t *test_ptr); +static void test_fake_commit(bs_test_t *test_ptr); const bs_test_case_t wlmtk_surface_test_cases[] = { - { 1, "create_destroy", test_create_destroy }, + { 1, "init_fini", test_init_fini }, + { 1, "fake_commit", test_fake_commit }, { 0, NULL, NULL } }; /* ------------------------------------------------------------------------- */ /** Tests setup and teardown. */ -void test_create_destroy(bs_test_t *test_ptr) +void test_init_fini(bs_test_t *test_ptr) { - wlmtk_surface_t *surface_ptr = wlmtk_surface_create(NULL, NULL); + wlmtk_surface_t surface; - BS_TEST_VERIFY_NEQ(test_ptr, NULL, surface_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_surface_init(&surface, NULL, NULL)); BS_TEST_VERIFY_EQ( test_ptr, - &surface_ptr->super_element, - wlmtk_surface_element(surface_ptr)); + &surface.super_element, + wlmtk_surface_element(&surface)); + + wlmtk_surface_fini(&surface); +} + +/* ------------------------------------------------------------------------- */ +/** Exercises the request_size / commit flow. */ +void test_fake_commit(bs_test_t *test_ptr) +{ + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); + int w, h; + + fake_surface_ptr->serial = 42; + + BS_TEST_VERIFY_EQ( + test_ptr, + 42, + wlmtk_surface_request_size(&fake_surface_ptr->surface, 200, 100)); + + wlmtk_surface_get_size(&fake_surface_ptr->surface, &w, &h); + BS_TEST_VERIFY_EQ(test_ptr, 0, w); + BS_TEST_VERIFY_EQ(test_ptr, 0, h); + + wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_surface_get_size(&fake_surface_ptr->surface, &w, &h); + BS_TEST_VERIFY_EQ(test_ptr, 200, w); + BS_TEST_VERIFY_EQ(test_ptr, 100, h); - wlmtk_surface_destroy(surface_ptr); + wlmtk_fake_surface_destroy(fake_surface_ptr); } /* == End of surface.c ===================================================== */ diff --git a/src/toolkit/surface.h b/src/toolkit/surface.h index f198f81c..31b0e7dc 100644 --- a/src/toolkit/surface.h +++ b/src/toolkit/surface.h @@ -22,6 +22,11 @@ #include +/** Forward declaration: State of a toolkit's WLR surface. */ +typedef struct _wlmtk_surface_t wlmtk_surface_t; +/** Forward declaration: Virtual method table of the toolkit's WLR surface. */ +typedef struct _wlmtk_surface_vmt_t wlmtk_surface_vmt_t; + #include "element.h" #include "env.h" @@ -32,25 +37,68 @@ struct wlr_surface; extern "C" { #endif // __cplusplus -/** Forward declaration: State of a toolkit's WLR surface. */ -typedef struct _wlmtk_surface_t wlmtk_surface_t; +/** Virtual method table of the surface. */ +struct _wlmtk_surface_vmt_t { + /** Abstract: Requests width and height of the surface. Returns serial. */ + uint32_t (*request_size)(wlmtk_surface_t *surface_ptr, + int width, + int height); +}; + +/** State of a `struct wlr_surface`, encapsuled for toolkit. */ +struct _wlmtk_surface_t { + /** Super class of the surface: An element. */ + wlmtk_element_t super_element; + /** Virtual method table of the super element before extending it. */ + wlmtk_element_vmt_t orig_super_element_vmt; + + /** The surface's virtual method table. */ + wlmtk_surface_vmt_t vmt; + + /** The `struct wlr_surface` wrapped. */ + struct wlr_surface *wlr_surface_ptr; + + /** Listener for the `commit` signal of the `wlr_surface_ptr`. */ + struct wl_listener surface_commit_listener; + + /** Committed width of the surface, in pixels. */ + int committed_width; + /** Committed height of the surface, in pixels. */ + int committed_height; +}; /** - * Creates a surface. + * Initializes the surface. * + * @param surface_ptr * @param wlr_surface_ptr * @param env_ptr + * + * @return true on success. */ -wlmtk_surface_t *wlmtk_surface_create( +bool wlmtk_surface_init( + wlmtk_surface_t *surface_ptr, struct wlr_surface *wlr_surface_ptr, wlmtk_env_t *env_ptr); /** - * Destroys the surface. + * Un-initializes the surface. + * + * @param surface_ptr + */ +void wlmtk_surface_fini(wlmtk_surface_t *surface_ptr); + +/** + * Extends the surface's virtual methods. * * @param surface_ptr + * @param surface_vmt_ptr + * + * @return The earlier virtual method table. */ -void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr); +wlmtk_surface_vmt_t wlmtk_surface_extend( + wlmtk_surface_t *surface_ptr, + const wlmtk_surface_vmt_t *surface_vmt_ptr); /** * Returns a pointer to the surface's element superclass instance. @@ -61,9 +109,60 @@ void wlmtk_surface_destroy(wlmtk_surface_t *surface_ptr); */ wlmtk_element_t *wlmtk_surface_element(wlmtk_surface_t *surface_ptr); +/** + * Virtual method: Request a new size and height for the surface. + * + * Wraps to @ref wlmtk_surface_vmt_t::request_size. + * + * @param surface_ptr + * @param width + * @param height + */ +static inline uint32_t wlmtk_surface_request_size( + wlmtk_surface_t *surface_ptr, + int width, + int height) +{ + return surface_ptr->vmt.request_size(surface_ptr, width, height); +} + +/** + * Returns committed size of the surface. + * + * @param surface_ptr + * @param width_ptr + * @param height_ptr + */ +void wlmtk_surface_get_size( + wlmtk_surface_t *surface_ptr, + int *width_ptr, + int *height_ptr); + /** Unit test cases. */ extern const bs_test_case_t wlmtk_surface_test_cases[]; +/** Fake surface, useful for unit test. */ +typedef struct { + /** Superclass: surface. */ + wlmtk_surface_t surface; + + /** Serial to return on next request_size call. */ + uint32_t serial; + /** `width` argument eof last @ref wlmtk_surface_request_size call. */ + int requested_width; + /** `height` argument of last @ref wlmtk_surface_request_size call. */ + int requested_height; +} wlmtk_fake_surface_t; + +/** Ctor for the fake surface.*/ +wlmtk_fake_surface_t *wlmtk_fake_surface_create(void); + +/** Dtor for the fake surface.*/ +void wlmtk_fake_surface_destroy(wlmtk_fake_surface_t *fake_surface_ptr); + +/** Commits the earlier @ref wlmtk_surface_request_size data. */ +void wlmtk_fake_surface_commit(wlmtk_fake_surface_t *fake_surface_ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 52f17ce7..d83f3428 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -74,14 +74,15 @@ const bs_test_case_t wlmtk_window_test_cases[] = { void test_init_fini(bs_test_t *test_ptr) { wlmtk_window_t window; - wlmtk_surface_t *surface_ptr = wlmtk_surface_create(NULL, NULL); + wlmtk_surface_t surface; + wlmtk_surface_init(&surface, NULL, NULL); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_window_init(&window, surface_ptr, NULL)); + wlmtk_window_init(&window, &surface, NULL)); wlmtk_window_fini(&window); - wlmtk_surface_destroy(surface_ptr); + wlmtk_surface_fini(&surface); } /* == End of window.c ====================================================== */ From c7106d3bde7c37cb16cb5fc8a329484cbba3aa89 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 27 Dec 2023 10:05:30 +0100 Subject: [PATCH 321/390] Revert "Adds boilerplate for the new wlmtk_window_t." This reverts commit 7943a84e545358e0f91c5593baa6fa4cc954eb2c. --- src/toolkit/CMakeLists.txt | 2 -- src/toolkit/toolkit.h | 1 - src/toolkit/toolkit_test.c | 1 - src/toolkit/window.h | 73 -------------------------------------- 4 files changed, 77 deletions(-) delete mode 100644 src/toolkit/window.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 0e8ae321..3d9b8eaa 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -39,7 +39,6 @@ SET(PUBLIC_HEADER_FILES titlebar_button.h titlebar_title.h toplevel.h - window.h workspace.h) ADD_LIBRARY(toolkit STATIC) @@ -62,7 +61,6 @@ TARGET_SOURCES(toolkit PRIVATE titlebar.c titlebar_button.c titlebar_title.c - window.c util.c toplevel.c workspace.c) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index c4be88df..f67b42e6 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -48,7 +48,6 @@ #include "titlebar_button.h" #include "titlebar_title.h" #include "toplevel.h" -#include "window.h" #include "workspace.h" #ifdef __cplusplus diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index cd237125..bbcf2cda 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -37,7 +37,6 @@ const bs_test_set_t toolkit_tests[] = { { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, { 1, "toplevel", wlmtk_toplevel_test_cases }, - { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } diff --git a/src/toolkit/window.h b/src/toolkit/window.h deleted file mode 100644 index 3b22f1e2..00000000 --- a/src/toolkit/window.h +++ /dev/null @@ -1,73 +0,0 @@ -/* ========================================================================= */ -/** - * @file window.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __WLMTK_WINDOW_H__ -#define __WLMTK_WINDOW_H__ - -/** Forward declaration. */ -typedef struct _wlmtk_window_t wlmtk_window_t; - -#include "container.h" -#include "surface.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** Window state. */ -struct _wlmtk_window_t { - /** Super class of the window. */ - wlmtk_container_t super_container; - /** Virtual method table of the superclass' container. */ - wlmtk_container_vmt_t orig_super_container_vmt; - - /** The principal surface of the window. */ - wlmtk_surface_t *surface_ptr; -}; - -/** - * Initializes the window with the provided surface. - * - * @param window_ptr - * @param surface_ptr - * @param env_ptr - * - * @return true on success. - */ -bool wlmtk_window_init( - wlmtk_window_t *window_ptr, - wlmtk_surface_t *surface_ptr, - wlmtk_env_t *env_ptr); - -/** - * Un-initializes the window. - * - * @param window_ptr - */ -void wlmtk_window_fini(wlmtk_window_t *window_ptr); - -/** Unit test cases. */ -extern const bs_test_case_t wlmtk_window_test_cases[]; - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __WLMTK_WINDOW_H__ */ -/* == End of window.h ====================================================== */ From 89862aaa902cca4c1bb370089f9f38e288cd40ab Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 27 Dec 2023 10:07:18 +0100 Subject: [PATCH 322/390] Revert "Renames wlmtk_window to wlmtk_toplevel throughout." This reverts commit 09393fe431e6c59aad7ad60312bd7f2ffe5ccaec. --- src/toolkit/CMakeLists.txt | 4 +- src/toolkit/content.c | 14 +- src/toolkit/content.h | 23 +- src/toolkit/resizebar.c | 20 +- src/toolkit/resizebar.h | 7 +- src/toolkit/resizebar_area.c | 26 +- src/toolkit/resizebar_area.h | 7 +- src/toolkit/titlebar.c | 28 +- src/toolkit/titlebar.h | 8 +- src/toolkit/titlebar_button.c | 30 +- src/toolkit/titlebar_button.h | 6 +- src/toolkit/titlebar_title.c | 22 +- src/toolkit/titlebar_title.h | 4 +- src/toolkit/toolkit.h | 2 +- src/toolkit/toolkit.md | 67 +- src/toolkit/toolkit_test.c | 2 +- src/toolkit/toplevel.c | 1168 --------------------------------- src/toolkit/toplevel.h | 319 --------- src/toolkit/window.c | 1139 +++++++++++++++++++++++++++++++- src/toolkit/window.h | 319 +++++++++ src/toolkit/workspace.c | 266 ++++---- src/toolkit/workspace.h | 48 +- src/wlmtk_xdg_popup.c | 2 +- src/wlmtk_xdg_popup.h | 4 +- src/wlmtk_xdg_toplevel.c | 40 +- src/wlmtk_xdg_toplevel.h | 2 +- src/xdg_decoration.c | 4 +- src/xdg_shell.c | 6 +- 28 files changed, 1744 insertions(+), 1843 deletions(-) delete mode 100644 src/toolkit/toplevel.c delete mode 100644 src/toolkit/toplevel.h create mode 100644 src/toolkit/window.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 3d9b8eaa..aacd623b 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -38,7 +38,7 @@ SET(PUBLIC_HEADER_FILES titlebar.h titlebar_button.h titlebar_title.h - toplevel.h + window.h workspace.h) ADD_LIBRARY(toolkit STATIC) @@ -62,7 +62,7 @@ TARGET_SOURCES(toolkit PRIVATE titlebar_button.c titlebar_title.c util.c - toplevel.c + window.c workspace.c) TARGET_INCLUDE_DIRECTORIES( toolkit PUBLIC diff --git a/src/toolkit/content.c b/src/toolkit/content.c index b68cac63..001b4648 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -113,11 +113,11 @@ void wlmtk_content_fini(wlmtk_content_t *content_ptr) } /* ------------------------------------------------------------------------- */ -void wlmtk_content_set_toplevel( +void wlmtk_content_set_window( wlmtk_content_t *content_ptr, - wlmtk_toplevel_t *toplevel_ptr) + wlmtk_window_t *window_ptr) { - content_ptr->toplevel_ptr = toplevel_ptr; + content_ptr->window_ptr = window_ptr; } /* ------------------------------------------------------------------------- */ @@ -133,8 +133,8 @@ void wlmtk_content_commit_size( content_ptr->committed_height = height; } - if (NULL != content_ptr->toplevel_ptr) { - wlmtk_toplevel_serial(content_ptr->toplevel_ptr, serial); + if (NULL != content_ptr->window_ptr) { + wlmtk_window_serial(content_ptr->window_ptr, serial); } if (NULL != content_ptr->super_element.parent_container_ptr) { @@ -344,8 +344,8 @@ bool element_pointer_button( wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr )->pointer_state.focused_surface; if (NULL == focused_wlr_surface_ptr) return false; - // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated toplevel - // over to a non-activated toplevel will trigger the condition here on the + // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated window + // over to a non-activated window will trigger the condition here on the // WLMTK_BUTTON_UP event. Needs a test and fixing. BS_ASSERT(content_ptr->wlr_surface_ptr == wlr_surface_get_root_surface(focused_wlr_surface_ptr)); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index d37c52d1..569867dc 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -20,7 +20,7 @@ #ifndef __WLMTK_CONTENT_H__ #define __WLMTK_CONTENT_H__ -/** Forward declaration: Toplevel content. */ +/** Forward declaration: Window content. */ typedef struct _wlmtk_content_t wlmtk_content_t; /** Forward declaration: Content virtual method table. */ @@ -28,7 +28,8 @@ typedef struct _wlmtk_content_vmt_t wlmtk_content_vmt_t; /** Forward declaration: Fake content, for tests. */ typedef struct _wlmtk_fake_content_t wlmtk_fake_content_t; -#include "toplevel.h" + +#include "window.h" #ifdef __cplusplus extern "C" { @@ -59,10 +60,10 @@ struct _wlmtk_content_t { wlmtk_content_vmt_t vmt; /** - * The toplevel this content belongs to. Will be set when creating - * the toplevel. + * The window this content belongs to. Will be set when creating + * the window. */ - wlmtk_toplevel_t *toplevel_ptr; + wlmtk_window_t *window_ptr; /** * Surface associated with this content. @@ -110,16 +111,16 @@ wlmtk_content_vmt_t wlmtk_content_extend( void wlmtk_content_fini(wlmtk_content_t *content_ptr); /** - * Sets the toplevel for the content. + * Sets the window for the content. * - * Private: Should only be called by Toplevel ctor (a friend). + * Private: Should only be called by Window ctor (a friend). * * @param content_ptr - * @param toplevel_ptr + * @param window_ptr */ -void wlmtk_content_set_toplevel( +void wlmtk_content_set_window( wlmtk_content_t *content_ptr, - wlmtk_toplevel_t *toplevel_ptr); + wlmtk_window_t *window_ptr); /** * Sets the committed size of the content. @@ -129,7 +130,7 @@ void wlmtk_content_set_toplevel( * forwards the request to the content (eg. the Wayland client surface). The * client then configures it's surface and commits it. The content needs to * catch that commit and call @ref wlmtk_content_commit_size accordingly. - * This will then update the parent container's (and toplevel's) layout. + * This will then update the parent container's (and window's) layout. * * @param content_ptr * @param serial diff --git a/src/toolkit/resizebar.c b/src/toolkit/resizebar.c index 2bf2b6d8..9fd33388 100644 --- a/src/toolkit/resizebar.c +++ b/src/toolkit/resizebar.c @@ -71,7 +71,7 @@ static const wlmtk_element_vmt_t resizebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_env_t *env_ptr, - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, const wlmtk_resizebar_style_t *style_ptr) { wlmtk_resizebar_t *resizebar_ptr = logged_calloc( @@ -92,7 +92,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( &resizebar_element_vmt); resizebar_ptr->left_area_ptr = wlmtk_resizebar_area_create( - toplevel_ptr, env_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); + window_ptr, env_ptr, WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->left_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -102,7 +102,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->left_area_ptr)); resizebar_ptr->center_area_ptr = wlmtk_resizebar_area_create( - toplevel_ptr, env_ptr, WLR_EDGE_BOTTOM); + window_ptr, env_ptr, WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->center_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -112,7 +112,7 @@ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_resizebar_area_element(resizebar_ptr->center_area_ptr)); resizebar_ptr->right_area_ptr = wlmtk_resizebar_area_create( - toplevel_ptr, env_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); + window_ptr, env_ptr, WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); if (NULL == resizebar_ptr->right_area_ptr) { wlmtk_resizebar_destroy(resizebar_ptr); return NULL; @@ -271,25 +271,25 @@ const bs_test_case_t wlmtk_resizebar_test_cases[] = { /** Exercises @ref wlmtk_resizebar_create and @ref wlmtk_resizebar_destroy. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = {}; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, fake_toplevel_ptr->toplevel_ptr, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* ------------------------------------------------------------------------- */ /** Performs resizing and verifies the elements are shown as expected. */ void test_variable_width(bs_test_t *test_ptr) { - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_style_t style = { .height = 7, .corner_width = 16 }; wlmtk_resizebar_t *resizebar_ptr = wlmtk_resizebar_create( - NULL, fake_toplevel_ptr->toplevel_ptr, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, resizebar_ptr); wlmtk_element_t *left_elem_ptr = wlmtk_resizebar_area_element( @@ -330,7 +330,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, right_elem_ptr->x); wlmtk_element_destroy(wlmtk_resizebar_element(resizebar_ptr)); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of resizebar.c =================================================== */ diff --git a/src/toolkit/resizebar.h b/src/toolkit/resizebar.h index 44acb9d0..f0382ae9 100644 --- a/src/toolkit/resizebar.h +++ b/src/toolkit/resizebar.h @@ -27,9 +27,10 @@ struct wlr_cursor; /** Forward declaration. */ struct wlr_xcursor_manager; + #include "element.h" #include "primitives.h" -#include "toplevel.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -53,14 +54,14 @@ typedef struct { * Creates the resize bar. * * @param env_ptr - * @param toplevel_ptr + * @param window_ptr * @param style_ptr * * @return Pointer to the resizebar state, or NULL on error. */ wlmtk_resizebar_t *wlmtk_resizebar_create( wlmtk_env_t *env_ptr, - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, const wlmtk_resizebar_style_t *style_ptr); /** diff --git a/src/toolkit/resizebar_area.c b/src/toolkit/resizebar_area.c index 63202704..87cb1295 100644 --- a/src/toolkit/resizebar_area.c +++ b/src/toolkit/resizebar_area.c @@ -24,7 +24,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" -#include "toplevel.h" +#include "window.h" #include @@ -52,7 +52,7 @@ struct _wlmtk_resizebar_area_t { bool pressed; /** Window to which the resize bar area belongs. To initiate resizing. */ - wlmtk_toplevel_t *toplevel_ptr; + wlmtk_window_t *window_ptr; /** Edges that the resizebar area controls. */ uint32_t edges; @@ -91,15 +91,15 @@ static const wlmtk_element_vmt_t resizebar_area_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, uint32_t edges) { wlmtk_resizebar_area_t *resizebar_area_ptr = logged_calloc( 1, sizeof(wlmtk_resizebar_area_t)); if (NULL == resizebar_area_ptr) return NULL; - BS_ASSERT(NULL != toplevel_ptr); - resizebar_area_ptr->toplevel_ptr = toplevel_ptr; + BS_ASSERT(NULL != window_ptr); + resizebar_area_ptr->window_ptr = window_ptr; resizebar_area_ptr->edges = edges; resizebar_area_ptr->cursor = WLMTK_CURSOR_DEFAULT; @@ -223,8 +223,8 @@ bool _wlmtk_resizebar_area_element_pointer_button( case WLMTK_BUTTON_DOWN: resizebar_area_ptr->pressed = true; - wlmtk_toplevel_request_resize( - resizebar_area_ptr->toplevel_ptr, + wlmtk_window_request_resize( + resizebar_area_ptr->window_ptr, resizebar_area_ptr->edges); draw_state(resizebar_area_ptr); break; @@ -313,10 +313,10 @@ const bs_test_case_t wlmtk_resizebar_area_test_cases[] = { /** Tests the area behaviour. */ void test_area(bs_test_t *test_ptr) { - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_resizebar_area_t *area_ptr = wlmtk_resizebar_area_create( - fake_toplevel_ptr->toplevel_ptr, NULL, WLR_EDGE_BOTTOM); + fake_window_ptr->window_ptr, NULL, WLR_EDGE_BOTTOM); BS_TEST_VERIFY_NEQ(test_ptr, NULL, area_ptr); wlmtk_element_t *element_ptr = wlmtk_resizebar_area_element(area_ptr); @@ -332,7 +332,7 @@ void test_area(bs_test_t *test_ptr) test_ptr, bs_gfxbuf_from_wlr_buffer(area_ptr->super_buffer.wlr_buffer_ptr), "toolkit/resizebar_area_released.png"); - BS_TEST_VERIFY_FALSE(test_ptr, fake_toplevel_ptr->request_resize_called); + BS_TEST_VERIFY_FALSE(test_ptr, fake_window_ptr->request_resize_called); // Pointer must be inside the button for accepting DOWN. BS_TEST_VERIFY_TRUE( @@ -351,14 +351,14 @@ void test_area(bs_test_t *test_ptr) "toolkit/resizebar_area_pressed.png"); // TODO(kaeser@gubbe.ch): Should verify setting the cursor. - BS_TEST_VERIFY_TRUE(test_ptr, fake_toplevel_ptr->request_resize_called); + BS_TEST_VERIFY_TRUE(test_ptr, fake_window_ptr->request_resize_called); BS_TEST_VERIFY_EQ( test_ptr, WLR_EDGE_BOTTOM, - fake_toplevel_ptr->request_resize_edges); + fake_window_ptr->request_resize_edges); wlmtk_element_destroy(element_ptr); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of resizebar_area.c ============================================== */ diff --git a/src/toolkit/resizebar_area.h b/src/toolkit/resizebar_area.h index 551d5d7d..c52e178f 100644 --- a/src/toolkit/resizebar_area.h +++ b/src/toolkit/resizebar_area.h @@ -25,8 +25,9 @@ /** Forward declaration: Element of the resizebar. */ typedef struct _wlmtk_resizebar_area_t wlmtk_resizebar_area_t ; + #include "resizebar.h" -#include "toplevel.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -35,14 +36,14 @@ extern "C" { /** * Creates a resizebar button. * - * @param toplevel_ptr + * @param window_ptr * @param env_ptr * @param edges * * @return Pointer to the resizebar button. */ wlmtk_resizebar_area_t *wlmtk_resizebar_area_create( - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, uint32_t edges); diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index 1193550f..f34b20d9 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -27,7 +27,7 @@ #include "primitives.h" #include "titlebar_button.h" #include "titlebar_title.h" -#include "toplevel.h" +#include "window.h" #define WLR_USE_UNSTABLE #include @@ -88,14 +88,14 @@ static const wlmtk_element_vmt_t titlebar_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_env_t *env_ptr, - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr) { wlmtk_titlebar_t *titlebar_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_t)); if (NULL == titlebar_ptr) return NULL; memcpy(&titlebar_ptr->style, style_ptr, sizeof(wlmtk_titlebar_style_t)); - titlebar_ptr->title_ptr = wlmtk_toplevel_get_title(toplevel_ptr); + titlebar_ptr->title_ptr = wlmtk_window_get_title(window_ptr); if (!wlmtk_box_init(&titlebar_ptr->super_box, env_ptr, WLMTK_BOX_HORIZONTAL, @@ -108,7 +108,7 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( &titlebar_element_vmt); titlebar_ptr->titlebar_title_ptr = wlmtk_titlebar_title_create( - env_ptr, toplevel_ptr); + env_ptr, window_ptr); if (NULL == titlebar_ptr->titlebar_title_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); return NULL; @@ -119,8 +119,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->minimize_button_ptr = wlmtk_titlebar_button_create( env_ptr, - wlmtk_toplevel_request_minimize, - toplevel_ptr, + wlmtk_window_request_minimize, + window_ptr, wlmaker_primitives_draw_minimize_icon); if (NULL == titlebar_ptr->minimize_button_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -132,8 +132,8 @@ wlmtk_titlebar_t *wlmtk_titlebar_create( titlebar_ptr->close_button_ptr = wlmtk_titlebar_button_create( env_ptr, - wlmtk_toplevel_request_close, - toplevel_ptr, + wlmtk_window_request_close, + window_ptr, wlmaker_primitives_draw_close_icon); if (NULL == titlebar_ptr->close_button_ptr) { wlmtk_titlebar_destroy(titlebar_ptr); @@ -384,24 +384,24 @@ const bs_test_case_t wlmtk_titlebar_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = {}; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - NULL, fake_toplevel_ptr->toplevel_ptr, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* ------------------------------------------------------------------------- */ /** Tests titlebar with variable width. */ void test_variable_width(bs_test_t *test_ptr) { - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_style_t style = { .height = 22, .margin_style = { .width = 2 } }; wlmtk_titlebar_t *titlebar_ptr = wlmtk_titlebar_create( - NULL, fake_toplevel_ptr->toplevel_ptr, &style); + NULL, fake_window_ptr->window_ptr, &style); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_ptr); // Short names, for improved readability. @@ -447,7 +447,7 @@ void test_variable_width(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 66, width); wlmtk_element_destroy(wlmtk_titlebar_element(titlebar_ptr)); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of titlebar.c ==================================================== */ diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 163225c5..49970c24 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -26,7 +26,7 @@ typedef struct _wlmtk_titlebar_t wlmtk_titlebar_t; #include "element.h" #include "primitives.h" -#include "toplevel.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -51,10 +51,10 @@ typedef struct { } wlmtk_titlebar_style_t; /** - * Creates a title bar, suitable as a toplevel title. + * Creates a title bar, suitable as a window title. * * @param env_ptr - * @param toplevel_ptr + * @param window_ptr * @param style_ptr * * @return Pointer to the title bar state, or NULL on error. Must be free'd @@ -62,7 +62,7 @@ typedef struct { */ wlmtk_titlebar_t *wlmtk_titlebar_create( wlmtk_env_t *env_ptr, - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, const wlmtk_titlebar_style_t *style_ptr); /** diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index 7b4cf011..c70ba9dd 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -38,9 +38,9 @@ struct _wlmtk_titlebar_button_t { bool activated; /** Callback for when the button is clicked. */ - void (*click_handler)(wlmtk_toplevel_t *toplevel_ptr); - /** Points to the @ref wlmtk_toplevel_t that carries this titlebar. */ - wlmtk_toplevel_t *toplevel_ptr; + void (*click_handler)(wlmtk_window_t *window_ptr); + /** Points to the @ref wlmtk_window_t that carries this titlebar. */ + wlmtk_window_t *window_ptr; /** For drawing the button contents. */ wlmtk_titlebar_button_draw_t draw; @@ -79,18 +79,18 @@ static const wlmtk_button_vmt_t titlebar_button_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( wlmtk_env_t *env_ptr, - void (*click_handler)(wlmtk_toplevel_t *toplevel_ptr), - wlmtk_toplevel_t *toplevel_ptr, + void (*click_handler)(wlmtk_window_t *window_ptr), + wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw) { - BS_ASSERT(NULL != toplevel_ptr); + BS_ASSERT(NULL != window_ptr); BS_ASSERT(NULL != click_handler); BS_ASSERT(NULL != draw); wlmtk_titlebar_button_t *titlebar_button_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_button_t)); if (NULL == titlebar_button_ptr) return NULL; titlebar_button_ptr->click_handler = click_handler; - titlebar_button_ptr->toplevel_ptr = toplevel_ptr; + titlebar_button_ptr->window_ptr = window_ptr; titlebar_button_ptr->draw = draw; if (!wlmtk_button_init(&titlebar_button_ptr->super_button, env_ptr)) { @@ -201,12 +201,12 @@ void titlebar_button_element_destroy(wlmtk_element_t *element_ptr) } /* ------------------------------------------------------------------------- */ -/** Handles button clicks: Passes the request to the toplevel. */ +/** Handles button clicks: Passes the request to the window. */ void titlebar_button_clicked(wlmtk_button_t *button_ptr) { wlmtk_titlebar_button_t *titlebar_button_ptr = BS_CONTAINER_OF( button_ptr, wlmtk_titlebar_button_t, super_button); - titlebar_button_ptr->click_handler(titlebar_button_ptr->toplevel_ptr); + titlebar_button_ptr->click_handler(titlebar_button_ptr->window_ptr); } /* ------------------------------------------------------------------------- */ @@ -274,11 +274,11 @@ const bs_test_case_t wlmtk_titlebar_button_test_cases[] = { /** Tests button visualization. */ void test_button(bs_test_t *test_ptr) { - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_button_t *button_ptr = wlmtk_titlebar_button_create( NULL, - wlmtk_toplevel_request_close, - fake_toplevel_ptr->toplevel_ptr, + wlmtk_window_request_close, + fake_window_ptr->window_ptr, wlmaker_primitives_draw_close_icon); BS_TEST_VERIFY_NEQ(test_ptr, NULL, button_ptr); wlmtk_titlebar_button_set_activated(button_ptr, true); @@ -336,7 +336,7 @@ void test_button(bs_test_t *test_ptr) // Click: To be passed along, no change to visual. BS_TEST_VERIFY_FALSE( test_ptr, - fake_toplevel_ptr->request_close_called); + fake_window_ptr->request_close_called); button.type = WLMTK_BUTTON_CLICK; BS_TEST_VERIFY_TRUE( test_ptr, @@ -347,7 +347,7 @@ void test_button(bs_test_t *test_ptr) "toolkit/title_button_focussed_released.png"); BS_TEST_VERIFY_TRUE( test_ptr, - fake_toplevel_ptr->request_close_called); + fake_window_ptr->request_close_called); // De-activate: Show as blurred. wlmtk_titlebar_button_set_activated(button_ptr, false); @@ -357,7 +357,7 @@ void test_button(bs_test_t *test_ptr) "toolkit/title_button_blurred.png"); wlmtk_element_destroy(element_ptr); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of titlebar_button.c ============================================= */ diff --git a/src/toolkit/titlebar_button.h b/src/toolkit/titlebar_button.h index 60e980d0..83501f00 100644 --- a/src/toolkit/titlebar_button.h +++ b/src/toolkit/titlebar_button.h @@ -41,15 +41,15 @@ typedef void (*wlmtk_titlebar_button_draw_t)( * * @param env_ptr * @param click_handler - * @param toplevel_ptr + * @param window_ptr * @param draw * * @return Pointer to the titlebar button, or NULL on error. */ wlmtk_titlebar_button_t *wlmtk_titlebar_button_create( wlmtk_env_t *env_ptr, - void (*click_handler)(wlmtk_toplevel_t *toplevel_ptr), - wlmtk_toplevel_t *toplevel_ptr, + void (*click_handler)(wlmtk_window_t *window_ptr), + wlmtk_window_t *window_ptr, wlmtk_titlebar_button_draw_t draw); /** diff --git a/src/toolkit/titlebar_title.c b/src/toolkit/titlebar_title.c index 56edcb59..4ebe4418 100644 --- a/src/toolkit/titlebar_title.c +++ b/src/toolkit/titlebar_title.c @@ -23,7 +23,7 @@ #include "buffer.h" #include "gfxbuf.h" #include "primitives.h" -#include "toplevel.h" +#include "window.h" #define WLR_USE_UNSTABLE #include @@ -35,8 +35,8 @@ struct _wlmtk_titlebar_title_t { /** Superclass: Buffer. */ wlmtk_buffer_t super_buffer; - /** Pointer to the toplevel the title element belongs to. */ - wlmtk_toplevel_t *toplevel_ptr; + /** Pointer to the window the title element belongs to. */ + wlmtk_window_t *window_ptr; /** The drawn title, when focussed. */ struct wlr_buffer *focussed_wlr_buffer_ptr; @@ -74,12 +74,12 @@ static const wlmtk_element_vmt_t titlebar_title_element_vmt = { /* ------------------------------------------------------------------------- */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( wlmtk_env_t *env_ptr, - wlmtk_toplevel_t *toplevel_ptr) + wlmtk_window_t *window_ptr) { wlmtk_titlebar_title_t *titlebar_title_ptr = logged_calloc( 1, sizeof(wlmtk_titlebar_title_t)); if (NULL == titlebar_title_ptr) return NULL; - titlebar_title_ptr->toplevel_ptr = toplevel_ptr; + titlebar_title_ptr->window_ptr = window_ptr; if (!wlmtk_buffer_init(&titlebar_title_ptr->super_buffer, env_ptr)) { wlmtk_titlebar_title_destroy(titlebar_title_ptr); @@ -183,7 +183,7 @@ bool _wlmtk_titlebar_title_element_pointer_button( switch (button_event_ptr->type) { case WLMTK_BUTTON_DOWN: - wlmtk_toplevel_request_move(titlebar_title_ptr->toplevel_ptr); + wlmtk_window_request_move(titlebar_title_ptr->window_ptr); break; default: // Can be ignored. @@ -282,9 +282,9 @@ void test_title(bs_test_t *test_ptr) bs_gfxbuf_clear(focussed_gfxbuf_ptr, 0xff2020c0); bs_gfxbuf_clear(blurred_gfxbuf_ptr, 0xff404040); - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); wlmtk_titlebar_title_t *titlebar_title_ptr = wlmtk_titlebar_title_create( - NULL, fake_toplevel_ptr->toplevel_ptr); + NULL, fake_window_ptr->window_ptr); wlmtk_element_t *element_ptr = wlmtk_titlebar_title_element( titlebar_title_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, titlebar_title_ptr); @@ -328,17 +328,17 @@ void test_title(bs_test_t *test_ptr) "toolkit/title_blurred_short.png"); // Pressing a button should trigger a move. - BS_TEST_VERIFY_FALSE(test_ptr, fake_toplevel_ptr->request_move_called); + BS_TEST_VERIFY_FALSE(test_ptr, fake_window_ptr->request_move_called); wlmtk_button_event_t button = { .button = BTN_LEFT, .type = WLMTK_BUTTON_DOWN }; BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_element_pointer_button(element_ptr, &button)); - BS_TEST_VERIFY_TRUE(test_ptr, fake_toplevel_ptr->request_move_called); + BS_TEST_VERIFY_TRUE(test_ptr, fake_window_ptr->request_move_called); wlmtk_element_destroy(element_ptr); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); bs_gfxbuf_destroy(focussed_gfxbuf_ptr); bs_gfxbuf_destroy(blurred_gfxbuf_ptr); } diff --git a/src/toolkit/titlebar_title.h b/src/toolkit/titlebar_title.h index 4642e62c..58b82820 100644 --- a/src/toolkit/titlebar_title.h +++ b/src/toolkit/titlebar_title.h @@ -36,13 +36,13 @@ extern "C" { * Creates a title bar title. * * @param env_ptr - * @param toplevel_ptr + * @param window_ptr * * @return Title handle. */ wlmtk_titlebar_title_t *wlmtk_titlebar_title_create( wlmtk_env_t *env_ptr, - wlmtk_toplevel_t *toplevel_ptr); + wlmtk_window_t *window_ptr); /** * Destroys the titlebar title. diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index f67b42e6..1c1edf29 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -47,7 +47,7 @@ #include "titlebar.h" #include "titlebar_button.h" #include "titlebar_title.h" -#include "toplevel.h" +#include "window.h" #include "workspace.h" #ifdef __cplusplus diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 40822c86..46906daf 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -81,11 +81,11 @@ class Workspace { Container *create() void destroy() - map_toplevel(Toplevel*) - unmap_toplevel(Toplevel*) + map_window(Window*) + unmap_window(Window*) - activate_toplevel(Toplevel*) - begin_toplevel_move(Toplevel*) + activate_window(Window*) + begin_window_move(Window*) map_layer_element(LayerElement *, layer) unmap_layer_element(LayerElement *, layer) @@ -99,19 +99,6 @@ class Box { } Container <|-- Box - - -abstract class Surface { -} - -abstract class Window { - private Container super_container; - - Surface surface; - Surface popups[]; -} - - abstract class Content { Element super_element @@ -119,7 +106,7 @@ abstract class Content { fini() struct wlr_scene_node *create_scene_node() Element *element() - -set_toplevel(Toplevel*) + -set_window(Window*) {abstract}#void get_size(int *, int *) {abstract}#void set_size(int, int) @@ -129,7 +116,7 @@ abstract class Content { } Element <|-- Content note right of Content - Interface for Toplevel contents. + Interface for Window contents. A surface (or... buffer? ...). Ultimately wraps a node, thus may be an element. end note @@ -165,12 +152,12 @@ class Button { } Buffer <|-- Button -class Toplevel { +class Window { Box super_box - Window *content + Content *content TitleBar *title_bar - Toplevel *create(Content*) + Window *create(Content*) destroy() Element *element() @@ -179,7 +166,7 @@ class Toplevel { get_size(int *, int *) set_size(int, int) } -Box *-- Toplevel +Box *-- Window class TitleBar { Box super_box @@ -233,56 +220,56 @@ class Cursor { => so yes, what will this do when mapped? - * Toplevel::create(surface) - * registers the toplevel for workspace + * Window::create(surface) + * registers the window for workspace - * creates the container, with parent of toplevel element + * creates the container, with parent of window element * if decoration: * will setup listeners for the various events, ... * request maximize * request move - * request show toplevel menu + * request show window menu * set title * ... set title handler: - * toplevel::set_title + * window::set_title request maximize handler: - * toplevel::request_maximize - * toplevel::set_maximized + * window::request_maximize + * window::set_maximized * internally: get view from workspace, ... set_size * callback to surface (if set): set_maximized upon surface::map - * workspace::add_toplevel(toplevel) (unsure: do we need this?) - => should set "container" of toplevel parent... element to workspace::container + * workspace::add_window(window) (unsure: do we need this?) + => should set "container" of window parent... element to workspace::container (ie. set_parent(...); and add "element" to "container") - * workspace::map_toplevel(toplevel) - => this should add toplevel to the set of workspace::mapped_toplevels - => toplevel element->container -> map_element(element) + * workspace::map_window(window) + => this should add window to the set of workspace::mapped_windows + => window element->container -> map_element(element) (expects the container to be mapped) - => will call map(node?) on toplevel element + => will call map(node?) on window element - is implemented in Container: - create a scene tree (from parents node) oc reparent (from parent) - calls map for every item in container upon surface::unmap - * workspace::unmap_toplevel + * workspace::unmap_window - => toplevel element->container -> unmap_element(element) - => will call unmap() on toplevel element + => window element->container -> unmap_element(element) + => will call unmap() on window element => destroy the node - * workspace::remove_toplevel(toplevel) (do we need this?) + * workspace::remove_window(window) (do we need this?) There is a click ("pointer button event") -> goes to workspace. diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index bbcf2cda..886bc141 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -36,7 +36,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "titlebar", wlmtk_titlebar_test_cases }, { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, - { 1, "toplevel", wlmtk_toplevel_test_cases }, + { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, { 0, NULL, NULL } diff --git a/src/toolkit/toplevel.c b/src/toolkit/toplevel.c deleted file mode 100644 index ee4eb6c0..00000000 --- a/src/toolkit/toplevel.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* ========================================================================= */ -/** - * @file toplevel.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "toplevel.h" - -#include "rectangle.h" -#include "workspace.h" - -#include "wlr/util/box.h" - -/* == Declarations ========================================================= */ - -/** Maximum number of pending state updates. */ -#define WLMTK_TOPLEVEL_MAX_PENDING 64 - -/** Virtual method table for the toplevel. */ -struct _wlmtk_toplevel_vmt_t { - /** Destructor. */ - void (*destroy)(wlmtk_toplevel_t *toplevel_ptr); - /** Virtual method for @ref wlmtk_toplevel_set_activated. */ - void (*set_activated)(wlmtk_toplevel_t *toplevel_ptr, - bool activated); - /** Virtual method for @ref wlmtk_toplevel_request_close. */ - void (*request_close)(wlmtk_toplevel_t *toplevel_ptr); - /** Virtual method for @ref wlmtk_toplevel_request_minimize. */ - void (*request_minimize)(wlmtk_toplevel_t *toplevel_ptr); - /** Virtual method for @ref wlmtk_toplevel_request_move. */ - void (*request_move)(wlmtk_toplevel_t *toplevel_ptr); - /** Virtual method for @ref wlmtk_toplevel_request_resize. */ - void (*request_resize)(wlmtk_toplevel_t *toplevel_ptr, - uint32_t edges); - /** Virtual method for @ref wlmtk_toplevel_request_position_and_size. */ - void (*request_position_and_size)(wlmtk_toplevel_t *toplevel_ptr, - int x, int y, int width, int height); -}; - -/** Pending positional updates for @ref wlmtk_toplevel_t::content_ptr. */ -typedef struct { - /** Node within @ref wlmtk_toplevel_t::pending_updates. */ - bs_dllist_node_t dlnode; - /** Serial of the update. */ - uint32_t serial; - /** Pending X position of the content. */ - int x; - /** Pending Y position of the content. */ - int y; - /** Content's width that is to be committed at serial. */ - unsigned width; - /** Content's hehight that is to be committed at serial. */ - unsigned height; -} wlmtk_pending_update_t; - -/** State of the toplevel. */ -struct _wlmtk_toplevel_t { - /** Superclass: Bordered. */ - wlmtk_bordered_t super_bordered; - /** Original virtual method table of the toplevel's element superclass. */ - wlmtk_element_vmt_t orig_super_element_vmt; - /** Original virtual method table of the toplevel' container superclass. */ - wlmtk_container_vmt_t orig_super_container_vmt; - - /** Virtual method table. */ - wlmtk_toplevel_vmt_t vmt; - - /** Box: In `super_bordered`, holds content, title bar and resizebar. */ - wlmtk_box_t box; - - /** Content of this toplevel. */ - wlmtk_content_t *content_ptr; - /** Titlebar. */ - wlmtk_titlebar_t *titlebar_ptr; - /** Resizebar. */ - wlmtk_resizebar_t *resizebar_ptr; - - /** Toplevel title. Set through @ref wlmtk_toplevel_set_title. */ - char *title_ptr; - - /** Pending updates. */ - bs_dllist_t pending_updates; - /** List of udpates currently available. */ - bs_dllist_t available_updates; - /** Pre-alloocated updates. */ - wlmtk_pending_update_t pre_allocated_updates[WLMTK_TOPLEVEL_MAX_PENDING]; - - /** Organic size of the toplevel, ie. when not maximized. */ - struct wlr_box organic_size; - /** Whether the toplevel has been requested as maximized. */ - bool maximized; - - /** - * Stores whether the toplevel is server-side decorated. - * - * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). - */ - bool server_side_decorated; -}; - -/** State of a fake toplevel: Includes the public record and the toplevel. */ -typedef struct { - /** Toplevel state. */ - wlmtk_toplevel_t toplevel; - /** Fake toplevel - public state. */ - wlmtk_fake_toplevel_t fake_toplevel; -} wlmtk_fake_toplevel_state_t; - -static bool _wlmtk_toplevel_init( - wlmtk_toplevel_t *toplevel_ptr, - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); -static void _wlmtk_toplevel_fini(wlmtk_toplevel_t *toplevel_ptr); -static wlmtk_toplevel_vmt_t _wlmtk_toplevel_extend( - wlmtk_toplevel_t *toplevel_ptr, - const wlmtk_toplevel_vmt_t *toplevel_vmt_ptr); - -static bool _wlmtk_toplevel_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); -static void _wlmtk_toplevel_container_update_layout( - wlmtk_container_t *container_ptr); - -static void _wlmtk_toplevel_set_activated( - wlmtk_toplevel_t *toplevel_ptr, - bool activated); -static void _wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_toplevel_request_resize( - wlmtk_toplevel_t *toplevel_ptr, - uint32_t edges); -static void _wlmtk_toplevel_request_position_and_size( - wlmtk_toplevel_t *toplevel_ptr, - int x, - int y, - int width, - int height); - -static wlmtk_pending_update_t *_wlmtk_toplevel_prepare_update( - wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_toplevel_release_update( - wlmtk_toplevel_t *toplevel_ptr, - wlmtk_pending_update_t *update_ptr); -static wlmtk_workspace_t *_wlmtk_toplevel_workspace(wlmtk_toplevel_t *toplevel_ptr); - -/* == Data ================================================================= */ - -/** Virtual method table for the toplevel's element superclass. */ -static const wlmtk_element_vmt_t toplevel_element_vmt = { - .pointer_button = _wlmtk_toplevel_element_pointer_button, -}; -/** Virtual method table for the toplevel's container superclass. */ -static const wlmtk_container_vmt_t toplevel_container_vmt = { - .update_layout = _wlmtk_toplevel_container_update_layout, -}; -/** Virtual method table for the toplevel itself. */ -static const wlmtk_toplevel_vmt_t _wlmtk_toplevel_vmt = { - .set_activated = _wlmtk_toplevel_set_activated, - .request_close = _wlmtk_toplevel_request_close, - .request_minimize = _wlmtk_toplevel_request_minimize, - .request_move = _wlmtk_toplevel_request_move, - .request_resize = _wlmtk_toplevel_request_resize, - .request_position_and_size = _wlmtk_toplevel_request_position_and_size, -}; - -/** Style of the title bar. */ -// TODO(kaeser@gubbe.ch): Move to central config. */ -static const wlmtk_titlebar_style_t titlebar_style = { - .focussed_fill = { - .type = WLMTK_STYLE_COLOR_HGRADIENT, - .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} - }, - .blurred_fill = { - .type = WLMTK_STYLE_COLOR_HGRADIENT, - .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} - }, - .focussed_text_color = 0xffffffff, - .blurred_text_color = 0xff000000, - .height = 22, - .bezel_width = 1, - .margin_style = { .width = 1, .color = 0xff000000 }, -}; - -/** Style of the resize bar. */ -// TODO(kaeser@gubbe.ch): Move to central config. */ -static const wlmtk_resizebar_style_t resizebar_style = { - .fill = { - .type = WLMTK_STYLE_COLOR_SOLID, - .param = { .solid = { .color = 0xffc2c0c5 }} - }, - .height = 7, - .corner_width = 29, - .bezel_width = 1, - .margin_style = { .width = 0, .color = 0xff000000 }, -}; - -/** Style of the margin between title, content and resizebar. */ -static const wlmtk_margin_style_t margin_style = { - .width = 1, - .color = 0xff000000, -}; - -/** Style of the border around the toplevel. */ -static const wlmtk_margin_style_t border_style = { - .width = 1, - .color = 0xff000000, -}; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmtk_toplevel_t *wlmtk_toplevel_create( - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) -{ - wlmtk_toplevel_t *toplevel_ptr = logged_calloc(1, sizeof(wlmtk_toplevel_t)); - if (NULL == toplevel_ptr) return NULL; - - if (!_wlmtk_toplevel_init(toplevel_ptr, env_ptr, content_ptr)) { - wlmtk_toplevel_destroy(toplevel_ptr); - return NULL; - } - - return toplevel_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_destroy(wlmtk_toplevel_t *toplevel_ptr) -{ - _wlmtk_toplevel_fini(toplevel_ptr); - free(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -wlmtk_element_t *wlmtk_toplevel_element(wlmtk_toplevel_t *toplevel_ptr) -{ - return &toplevel_ptr->super_bordered.super_container.super_element; -} - -/* ------------------------------------------------------------------------- */ -wlmtk_toplevel_t *wlmtk_toplevel_from_element(wlmtk_element_t *element_ptr) -{ - wlmtk_toplevel_t *toplevel_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_toplevel_t, super_bordered.super_container.super_element); - BS_ASSERT(_wlmtk_toplevel_container_update_layout == - toplevel_ptr->super_bordered.super_container.vmt.update_layout); - return toplevel_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_set_activated( - wlmtk_toplevel_t *toplevel_ptr, - bool activated) -{ - toplevel_ptr->vmt.set_activated(toplevel_ptr, activated); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_set_server_side_decorated( - wlmtk_toplevel_t *toplevel_ptr, - bool decorated) -{ - // TODO(kaeser@gubbe.ch): Implement. - bs_log(BS_INFO, "Set server side decoration for toplevel %p: %d", - toplevel_ptr, decorated); - - if (toplevel_ptr->server_side_decorated == decorated) return; - - if (decorated) { - // Create decoration. - toplevel_ptr->titlebar_ptr = wlmtk_titlebar_create( - toplevel_ptr->super_bordered.super_container.super_element.env_ptr, - toplevel_ptr, &titlebar_style); - BS_ASSERT(NULL != toplevel_ptr->titlebar_ptr); - wlmtk_element_set_visible( - wlmtk_titlebar_element(toplevel_ptr->titlebar_ptr), true); - wlmtk_box_add_element_front( - &toplevel_ptr->box, - wlmtk_titlebar_element(toplevel_ptr->titlebar_ptr)); - - toplevel_ptr->resizebar_ptr = wlmtk_resizebar_create( - toplevel_ptr->super_bordered.super_container.super_element.env_ptr, - toplevel_ptr, &resizebar_style); - BS_ASSERT(NULL != toplevel_ptr->resizebar_ptr); - wlmtk_element_set_visible( - wlmtk_resizebar_element(toplevel_ptr->resizebar_ptr), true); - wlmtk_box_add_element_back( - &toplevel_ptr->box, - wlmtk_resizebar_element(toplevel_ptr->resizebar_ptr)); - } else { - // Remove & destroy the decoration. - wlmtk_box_remove_element( - &toplevel_ptr->box, - wlmtk_titlebar_element(toplevel_ptr->titlebar_ptr)); - wlmtk_titlebar_destroy(toplevel_ptr->titlebar_ptr); - toplevel_ptr->titlebar_ptr = NULL; - - wlmtk_box_remove_element( - &toplevel_ptr->box, - wlmtk_resizebar_element(toplevel_ptr->resizebar_ptr)); - wlmtk_resizebar_destroy(toplevel_ptr->resizebar_ptr); - toplevel_ptr->resizebar_ptr = NULL; - } - - toplevel_ptr->server_side_decorated = decorated; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_set_title( - wlmtk_toplevel_t *toplevel_ptr, - const char *title_ptr) -{ - char *new_title_ptr = NULL; - if (NULL != title_ptr) { - new_title_ptr = logged_strdup(title_ptr); - BS_ASSERT(NULL != new_title_ptr); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), "Unnamed toplevel %p", toplevel_ptr); - new_title_ptr = logged_strdup(buf); - BS_ASSERT(NULL != new_title_ptr); - } - - if (NULL != toplevel_ptr->title_ptr) { - if (0 == strcmp(toplevel_ptr->title_ptr, new_title_ptr)) { - free(new_title_ptr); - return; - } - free(toplevel_ptr->title_ptr); - } - toplevel_ptr->title_ptr = new_title_ptr; - - if (NULL != toplevel_ptr->titlebar_ptr) { - wlmtk_titlebar_set_title(toplevel_ptr->titlebar_ptr, - toplevel_ptr->title_ptr); - } -} - -/* ------------------------------------------------------------------------- */ -const char *wlmtk_toplevel_get_title(wlmtk_toplevel_t *toplevel_ptr) -{ - BS_ASSERT(NULL != toplevel_ptr->title_ptr); - return toplevel_ptr->title_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr) -{ - toplevel_ptr->vmt.request_close(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr) -{ - toplevel_ptr->vmt.request_minimize(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_maximize( - wlmtk_toplevel_t *toplevel_ptr, - bool maximized) -{ - if (toplevel_ptr->maximized == maximized) return; - - toplevel_ptr->maximized = maximized; - - struct wlr_box box; - if (toplevel_ptr->maximized) { - box = wlmtk_workspace_get_maximize_extents( - _wlmtk_toplevel_workspace(toplevel_ptr)); - } else { - box = toplevel_ptr->organic_size; - } - - _wlmtk_toplevel_request_position_and_size( - toplevel_ptr, box.x, box.y, box.width, box.height); -} - -/* ------------------------------------------------------------------------- */ -bool wlmtk_toplevel_maximized(wlmtk_toplevel_t *toplevel_ptr) -{ - return toplevel_ptr->maximized; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr) -{ - toplevel_ptr->vmt.request_move(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_resize(wlmtk_toplevel_t *toplevel_ptr, - uint32_t edges) -{ - toplevel_ptr->vmt.request_resize(toplevel_ptr, edges); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_set_position(wlmtk_toplevel_t *toplevel_ptr, int x, int y) -{ - toplevel_ptr->organic_size.x = x; - toplevel_ptr->organic_size.y = y; - wlmtk_element_set_position(wlmtk_toplevel_element(toplevel_ptr), x, y); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_get_size( - wlmtk_toplevel_t *toplevel_ptr, - int *width_ptr, - int *height_ptr) -{ - // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - wlmtk_content_get_size(toplevel_ptr->content_ptr, width_ptr, height_ptr); - - if (NULL != toplevel_ptr->titlebar_ptr) { - *height_ptr += titlebar_style.height + margin_style.width; - } - if (NULL != toplevel_ptr->resizebar_ptr) { - *height_ptr += resizebar_style.height + margin_style.width; - } - *height_ptr += 2 * border_style.width; - - *width_ptr += 2 * border_style.width; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_size( - wlmtk_toplevel_t *toplevel_ptr, - int width, - int height) -{ - // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_content_request_size(toplevel_ptr->content_ptr, width, height); - - // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting - // the size is an asynchronous operation and should be handled as such. - // Meaning: In example of resizing at the top-left corner, we'll want to - // request the content to adjust size, but wait with adjusting the - // content position until the size adjustment is applied. This implies we - // may need to combine the request_size and set_position methods for toplevel. -} - -/* ------------------------------------------------------------------------- */ -struct wlr_box wlmtk_toplevel_get_position_and_size( - wlmtk_toplevel_t *toplevel_ptr) -{ - struct wlr_box box; - - wlmtk_element_get_position( - wlmtk_toplevel_element(toplevel_ptr), &box.x, &box.y); - wlmtk_toplevel_get_size(toplevel_ptr, &box.width, &box.height); - return box; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_request_position_and_size( - wlmtk_toplevel_t *toplevel_ptr, - int x, - int y, - int width, - int height) -{ - toplevel_ptr->vmt.request_position_and_size( - toplevel_ptr, x, y, width, height); - - toplevel_ptr->organic_size.x = x; - toplevel_ptr->organic_size.y = y; - toplevel_ptr->organic_size.width = width; - toplevel_ptr->organic_size.height = height; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_toplevel_serial(wlmtk_toplevel_t *toplevel_ptr, uint32_t serial) -{ - bs_dllist_node_t *dlnode_ptr; - - if (!toplevel_ptr->maximized && - NULL == toplevel_ptr->pending_updates.head_ptr) { - wlmtk_toplevel_get_size(toplevel_ptr, - &toplevel_ptr->organic_size.width, - &toplevel_ptr->organic_size.height); - return; - } - - while (NULL != (dlnode_ptr = toplevel_ptr->pending_updates.head_ptr)) { - wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); - - int32_t delta = pending_update_ptr->serial - serial; - if (0 < delta) break; - - if (pending_update_ptr->serial == serial) { - if (toplevel_ptr->content_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (toplevel_ptr->content_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); - } - } - - wlmtk_element_set_position( - wlmtk_toplevel_element(toplevel_ptr), - pending_update_ptr->x, - pending_update_ptr->y); - _wlmtk_toplevel_release_update(toplevel_ptr, pending_update_ptr); - } -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** - * Initializes an (allocated) toplevel. - * - * @param toplevel_ptr - * @param env_ptr - * @param content_ptr - * - * @return true on success. - */ -bool _wlmtk_toplevel_init( - wlmtk_toplevel_t *toplevel_ptr, - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) -{ - BS_ASSERT(NULL != toplevel_ptr); - memcpy(&toplevel_ptr->vmt, &_wlmtk_toplevel_vmt, sizeof(wlmtk_toplevel_vmt_t)); - - for (size_t i = 0; i < WLMTK_TOPLEVEL_MAX_PENDING; ++i) { - bs_dllist_push_back(&toplevel_ptr->available_updates, - &toplevel_ptr->pre_allocated_updates[i].dlnode); - } - - if (!wlmtk_box_init(&toplevel_ptr->box, env_ptr, - WLMTK_BOX_VERTICAL, - &margin_style)) { - _wlmtk_toplevel_fini(toplevel_ptr); - return false; - } - wlmtk_element_set_visible( - &toplevel_ptr->box.super_container.super_element, true); - - if (!wlmtk_bordered_init(&toplevel_ptr->super_bordered, - env_ptr, - &toplevel_ptr->box.super_container.super_element, - &border_style)) { - _wlmtk_toplevel_fini(toplevel_ptr); - return false; - } - - toplevel_ptr->orig_super_element_vmt = wlmtk_element_extend( - &toplevel_ptr->super_bordered.super_container.super_element, - &toplevel_element_vmt); - toplevel_ptr->orig_super_container_vmt = wlmtk_container_extend( - &toplevel_ptr->super_bordered.super_container, &toplevel_container_vmt); - - wlmtk_toplevel_set_title(toplevel_ptr, NULL); - - wlmtk_box_add_element_front( - &toplevel_ptr->box, - wlmtk_content_element(content_ptr)); - toplevel_ptr->content_ptr = content_ptr; - wlmtk_content_set_toplevel(content_ptr, toplevel_ptr); - wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); - - return true; -} - -/* ------------------------------------------------------------------------- */ -/** - * Uninitializes the winodw. - * - * @param toplevel_ptr - */ -void _wlmtk_toplevel_fini(wlmtk_toplevel_t *toplevel_ptr) -{ - wlmtk_toplevel_set_server_side_decorated(toplevel_ptr, false); - - if (NULL != toplevel_ptr->content_ptr) { - wlmtk_box_remove_element( - &toplevel_ptr->box, - wlmtk_content_element(toplevel_ptr->content_ptr)); - wlmtk_element_set_visible( - wlmtk_content_element(toplevel_ptr->content_ptr), false); - wlmtk_content_set_toplevel(toplevel_ptr->content_ptr, NULL); - - wlmtk_element_destroy(wlmtk_content_element(toplevel_ptr->content_ptr)); - toplevel_ptr->content_ptr = NULL; - } - - if (NULL != toplevel_ptr->title_ptr) { - free(toplevel_ptr->title_ptr); - toplevel_ptr->title_ptr = NULL; - } - - wlmtk_bordered_fini(&toplevel_ptr->super_bordered); - wlmtk_box_fini(&toplevel_ptr->box); -} - -/* ------------------------------------------------------------------------- */ -/** - * Extends the toplevel's virtual methods. - * - * @param toplevel_ptr - * @param toplevel_vmt_ptr - * - * @return The previous virtual method table. - */ -wlmtk_toplevel_vmt_t _wlmtk_toplevel_extend( - wlmtk_toplevel_t *toplevel_ptr, - const wlmtk_toplevel_vmt_t *toplevel_vmt_ptr) -{ - wlmtk_toplevel_vmt_t orig_vmt = toplevel_ptr->vmt; - - if (NULL != toplevel_vmt_ptr->set_activated) { - toplevel_ptr->vmt.set_activated = toplevel_vmt_ptr->set_activated; - } - if (NULL != toplevel_vmt_ptr->request_close) { - toplevel_ptr->vmt.request_close = toplevel_vmt_ptr->request_close; - } - if (NULL != toplevel_vmt_ptr->request_minimize) { - toplevel_ptr->vmt.request_minimize = toplevel_vmt_ptr->request_minimize; - } - if (NULL != toplevel_vmt_ptr->request_move) { - toplevel_ptr->vmt.request_move = toplevel_vmt_ptr->request_move; - } - if (NULL != toplevel_vmt_ptr->request_resize) { - toplevel_ptr->vmt.request_resize = toplevel_vmt_ptr->request_resize; - } - if (NULL != toplevel_vmt_ptr->request_position_and_size) { - toplevel_ptr->vmt.request_position_and_size = - toplevel_vmt_ptr->request_position_and_size; - } - - return orig_vmt; -} - -/* ------------------------------------------------------------------------- */ -/** Activates toplevel on button press, and calls the parent's implementation. */ -bool _wlmtk_toplevel_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr) -{ - wlmtk_toplevel_t *toplevel_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_toplevel_t, super_bordered.super_container.super_element); - - // We shouldn't receive buttons when not mapped. - wlmtk_workspace_t *workspace_ptr = _wlmtk_toplevel_workspace(toplevel_ptr); - wlmtk_workspace_activate_toplevel(workspace_ptr, toplevel_ptr); - wlmtk_workspace_raise_toplevel(workspace_ptr, toplevel_ptr); - - return toplevel_ptr->orig_super_element_vmt.pointer_button( - element_ptr, button_event_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Implementation of @ref wlmtk_container_vmt_t::update_layout. - * - * Invoked when the toplevel's contained elements triggered a layout update, - * and will use this to trigger (potential) size updates to the toplevel - * decorations. - * - * @param container_ptr - */ -void _wlmtk_toplevel_container_update_layout(wlmtk_container_t *container_ptr) -{ - wlmtk_toplevel_t *toplevel_ptr = BS_CONTAINER_OF( - container_ptr, wlmtk_toplevel_t, super_bordered.super_container); - - toplevel_ptr->orig_super_container_vmt.update_layout(container_ptr); - - if (NULL != toplevel_ptr->content_ptr) { - int width; - wlmtk_content_get_size(toplevel_ptr->content_ptr, &width, NULL); - if (NULL != toplevel_ptr->titlebar_ptr) { - wlmtk_titlebar_set_width(toplevel_ptr->titlebar_ptr, width); - } - if (NULL != toplevel_ptr->resizebar_ptr) { - wlmtk_resizebar_set_width(toplevel_ptr->resizebar_ptr, width); - } - } -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_toplevel_set_activated. */ -void _wlmtk_toplevel_set_activated( - wlmtk_toplevel_t *toplevel_ptr, - bool activated) -{ - wlmtk_content_set_activated(toplevel_ptr->content_ptr, activated); - if (NULL != toplevel_ptr->titlebar_ptr) { - wlmtk_titlebar_set_activated(toplevel_ptr->titlebar_ptr, activated); - } -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_toplevel_request_close. */ -void _wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr) -{ - wlmtk_content_request_close(toplevel_ptr->content_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_toplevel_request_minimize. */ -void _wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr) -{ - bs_log(BS_INFO, "Requesting toplevel %p to minimize.", toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_toplevel_request_move. */ -void _wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr) -{ - wlmtk_workspace_begin_toplevel_move( - _wlmtk_toplevel_workspace(toplevel_ptr), toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_toplevel_request_resize. */ -void _wlmtk_toplevel_request_resize(wlmtk_toplevel_t *toplevel_ptr, uint32_t edges) -{ - wlmtk_workspace_begin_toplevel_resize( - _wlmtk_toplevel_workspace(toplevel_ptr), toplevel_ptr, edges); -} - -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_toplevel_request_position_and_size. */ -void _wlmtk_toplevel_request_position_and_size( - wlmtk_toplevel_t *toplevel_ptr, - int x, - int y, - int width, - int height) -{ - // Correct for borders, margin and decoration. - if (NULL != toplevel_ptr->titlebar_ptr) { - height -= titlebar_style.height + margin_style.width; - } - if (NULL != toplevel_ptr->resizebar_ptr) { - height -= resizebar_style.height + margin_style.width; - } - height -= 2 * border_style.width; - width -= 2 * border_style.width; - height = BS_MAX(0, height); - width = BS_MAX(0, width); - - uint32_t serial = wlmtk_content_request_size( - toplevel_ptr->content_ptr, width, height); - - wlmtk_pending_update_t *pending_update_ptr = - _wlmtk_toplevel_prepare_update(toplevel_ptr); - pending_update_ptr->serial = serial; - pending_update_ptr->x = x; - pending_update_ptr->y = y; - pending_update_ptr->width = width; - pending_update_ptr->height = height; - - // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_toplevel_serial - // may have been called early, so we should check if serial had just been - // called before (or is below the last @wlmt_toplevel_serial). In that case, - // the pending state should be applied right away. -} - -/* ------------------------------------------------------------------------- */ -/** - * Prepares a positional update: Allocates an item and attach it to the end - * of the list of pending updates. - * - * @param toplevel_ptr - * - * @return A pointer to a @ref wlmtk_pending_update_t, already positioned at the - * back of @ref wlmtk_toplevel_t::pending_updates. - */ -wlmtk_pending_update_t *_wlmtk_toplevel_prepare_update( - wlmtk_toplevel_t *toplevel_ptr) -{ - bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( - &toplevel_ptr->available_updates); - if (NULL == dlnode_ptr) { - dlnode_ptr = bs_dllist_pop_front(&toplevel_ptr->pending_updates); - bs_log(BS_WARNING, "Toplevel %p: No updates available.", toplevel_ptr); - // TODO(kaeser@gubbe.ch): Hm, should we apply this (old) update? - } - wlmtk_pending_update_t *update_ptr = BS_CONTAINER_OF( - dlnode_ptr, wlmtk_pending_update_t, dlnode); - bs_dllist_push_back(&toplevel_ptr->pending_updates, &update_ptr->dlnode); - return update_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Releases a pending positional update. Moves it to the list of - * @ref wlmtk_toplevel_t::available_updates. - * - * @param toplevel_ptr - * @param update_ptr - */ -void _wlmtk_toplevel_release_update( - wlmtk_toplevel_t *toplevel_ptr, - wlmtk_pending_update_t *update_ptr) -{ - bs_dllist_remove(&toplevel_ptr->pending_updates, &update_ptr->dlnode); - bs_dllist_push_front(&toplevel_ptr->available_updates, &update_ptr->dlnode); -} - -/* ------------------------------------------------------------------------- */ -/** Returns the workspace of the (mapped) toplevel. */ -wlmtk_workspace_t *_wlmtk_toplevel_workspace(wlmtk_toplevel_t *toplevel_ptr) -{ - BS_ASSERT(NULL != wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr); - return wlmtk_workspace_from_container( - wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr); -} - -/* == Implementation of the fake toplevel ==================================== */ - -static void _wlmtk_fake_toplevel_set_activated( - wlmtk_toplevel_t *toplevel_ptr, - bool activated); -static void _wlmtk_fake_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_fake_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_fake_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr); -static void _wlmtk_fake_toplevel_request_resize( - wlmtk_toplevel_t *toplevel_ptr, - uint32_t edges); -static void _wlmtk_fake_toplevel_request_position_and_size( - wlmtk_toplevel_t *toplevel_ptr, - int x, - int y, - int width, - int height); - -/** Virtual method table for the fake toplevel itself. */ -static const wlmtk_toplevel_vmt_t _wlmtk_fake_toplevel_vmt = { - .set_activated = _wlmtk_fake_toplevel_set_activated, - .request_close = _wlmtk_fake_toplevel_request_close, - .request_minimize = _wlmtk_fake_toplevel_request_minimize, - .request_move = _wlmtk_fake_toplevel_request_move, - .request_resize = _wlmtk_fake_toplevel_request_resize, - .request_position_and_size = _wlmtk_fake_toplevel_request_position_and_size, - -}; - -/* ------------------------------------------------------------------------- */ -wlmtk_fake_toplevel_t *wlmtk_fake_toplevel_create(void) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = logged_calloc( - 1, sizeof(wlmtk_fake_toplevel_state_t)); - if (NULL == fake_toplevel_state_ptr) return NULL; - - fake_toplevel_state_ptr->fake_toplevel.fake_content_ptr = - wlmtk_fake_content_create(); - if (NULL == fake_toplevel_state_ptr->fake_toplevel.fake_content_ptr) { - wlmtk_fake_toplevel_destroy(&fake_toplevel_state_ptr->fake_toplevel); - return NULL; - } - - if (!_wlmtk_toplevel_init( - &fake_toplevel_state_ptr->toplevel, - NULL, - &fake_toplevel_state_ptr->fake_toplevel.fake_content_ptr->content)) { - wlmtk_fake_toplevel_destroy(&fake_toplevel_state_ptr->fake_toplevel); - return NULL; - } - fake_toplevel_state_ptr->fake_toplevel.toplevel_ptr = - &fake_toplevel_state_ptr->toplevel; - - // Extend. We don't save the VMT, since it's for fake only. - _wlmtk_toplevel_extend(&fake_toplevel_state_ptr->toplevel, - &_wlmtk_fake_toplevel_vmt); - return &fake_toplevel_state_ptr->fake_toplevel; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_fake_toplevel_destroy(wlmtk_fake_toplevel_t *fake_toplevel_ptr) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - fake_toplevel_ptr, wlmtk_fake_toplevel_state_t, fake_toplevel); - - _wlmtk_toplevel_fini(&fake_toplevel_state_ptr->toplevel); - free(fake_toplevel_state_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_toplevel_set_activated. Records call. */ -void _wlmtk_fake_toplevel_set_activated( - wlmtk_toplevel_t *toplevel_ptr, - bool activated) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); - fake_toplevel_state_ptr->fake_toplevel.activated = activated; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_toplevel_request_close. Records call. */ -void _wlmtk_fake_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); - fake_toplevel_state_ptr->fake_toplevel.request_close_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_toplevel_request_minimize. Records call. */ -void _wlmtk_fake_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); - fake_toplevel_state_ptr->fake_toplevel.request_minimize_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_toplevel_request_move. Records call */ -void _wlmtk_fake_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); - fake_toplevel_state_ptr->fake_toplevel.request_move_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_toplevel_request_resize. Records call. */ -void _wlmtk_fake_toplevel_request_resize( - wlmtk_toplevel_t *toplevel_ptr, - uint32_t edges) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); - fake_toplevel_state_ptr->fake_toplevel.request_resize_called = true; - fake_toplevel_state_ptr->fake_toplevel.request_resize_edges = edges; -} - -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_toplevel_request_position_and_size. */ -void _wlmtk_fake_toplevel_request_position_and_size( - wlmtk_toplevel_t *toplevel_ptr, - int x, - int y, - int width, - int height) -{ - wlmtk_fake_toplevel_state_t *fake_toplevel_state_ptr = BS_CONTAINER_OF( - toplevel_ptr, wlmtk_fake_toplevel_state_t, toplevel); - fake_toplevel_state_ptr->fake_toplevel.request_position_and_size_called = true; - fake_toplevel_state_ptr->fake_toplevel.x = x; - fake_toplevel_state_ptr->fake_toplevel.y = y; - fake_toplevel_state_ptr->fake_toplevel.width = width; - fake_toplevel_state_ptr->fake_toplevel.height = height; -} - -/* == Unit tests =========================================================== */ - -static void test_create_destroy(bs_test_t *test_ptr); -static void test_set_title(bs_test_t *test_ptr); -static void test_request_close(bs_test_t *test_ptr); -static void test_set_activated(bs_test_t *test_ptr); -static void test_server_side_decorated(bs_test_t *test_ptr); -static void test_maximize(bs_test_t *test_ptr); -static void test_fake(bs_test_t *test_ptr); - -const bs_test_case_t wlmtk_toplevel_test_cases[] = { - { 1, "create_destroy", test_create_destroy }, - { 1, "set_title", test_set_title }, - { 1, "request_close", test_request_close }, - { 1, "set_activated", test_set_activated }, - { 1, "set_server_side_decorated", test_server_side_decorated }, - { 1, "maximize", test_maximize }, - { 1, "fake", test_fake }, - { 0, NULL, NULL } -}; - -/* ------------------------------------------------------------------------- */ -/** Tests setup and teardown. */ -void test_create_destroy(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( - NULL, &fake_content_ptr->content); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, toplevel_ptr, - fake_content_ptr->content.toplevel_ptr); - - wlmtk_toplevel_destroy(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests title. */ -void test_set_title(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( - NULL, &fake_content_ptr->content); - - wlmtk_toplevel_set_title(toplevel_ptr, "Title"); - BS_TEST_VERIFY_STREQ( - test_ptr, - "Title", - wlmtk_toplevel_get_title(toplevel_ptr)); - - wlmtk_toplevel_set_title(toplevel_ptr, NULL); - BS_TEST_VERIFY_STRMATCH( - test_ptr, - wlmtk_toplevel_get_title(toplevel_ptr), - "Unnamed toplevel .*"); - - wlmtk_toplevel_destroy(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests activation. */ -void test_request_close(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( - NULL, &fake_content_ptr->content); - - wlmtk_toplevel_request_close(toplevel_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); - - wlmtk_toplevel_destroy(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests activation. */ -void test_set_activated(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( - NULL, &fake_content_ptr->content); - - wlmtk_toplevel_set_activated(toplevel_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); - - wlmtk_toplevel_set_activated(toplevel_ptr, false); - BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->activated); - - wlmtk_toplevel_destroy(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests enabling and disabling server-side decoration. */ -void test_server_side_decorated(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( - NULL, &fake_content_ptr->content); - BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->resizebar_ptr); - - wlmtk_toplevel_set_server_side_decorated(toplevel_ptr, true); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr->titlebar_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr->resizebar_ptr); - - wlmtk_toplevel_set_server_side_decorated(toplevel_ptr, false); - BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, toplevel_ptr->resizebar_ptr); - - wlmtk_toplevel_destroy(toplevel_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests maximizing and un-maximizing a toplevel. */ -void test_maximize(bs_test_t *test_ptr) -{ - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - struct wlr_box extents = { .width = 1024, .height = 768 }, box; - wlmtk_workspace_set_extents(workspace_ptr, &extents); - BS_ASSERT(NULL != workspace_ptr); - - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( - NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != toplevel_ptr); - // Toplevel must be mapped to get maximized: Need workspace dimensions. - wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); - - // Set up initial organic size, and verify. - wlmtk_toplevel_request_position_and_size(toplevel_ptr, 20, 10, 200, 100); - wlmtk_fake_content_commit(fake_content_ptr); - box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_maximized(toplevel_ptr)); - - // Re-position the toplevel. - wlmtk_toplevel_set_position(toplevel_ptr, 50, 30); - box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - - // Trigger another serial update. Should not change position nor size. - wlmtk_toplevel_serial(toplevel_ptr, 1234); - box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - - // Maximize. - wlmtk_toplevel_request_maximize(toplevel_ptr, true); - wlmtk_fake_content_commit(fake_content_ptr); - box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_toplevel_maximized(toplevel_ptr)); - - // A second commit: should not overwrite the organic dimension. - wlmtk_fake_content_commit(fake_content_ptr); - - // Unmaximize. Restore earlier organic size and position. - wlmtk_toplevel_request_maximize(toplevel_ptr, false); - wlmtk_fake_content_commit(fake_content_ptr); - box = wlmtk_toplevel_get_position_and_size(toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); - BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); - BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); - BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_maximized(toplevel_ptr)); - - // TODO(kaeser@gubbe.ch): Define what should happen when a maximized - // toplevel is moved. Should it lose maximization? Should it not move? - // Or just move on? - // Toplevel Maker keeps maximization, but it's ... odd. - - wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); - wlmtk_toplevel_destroy(toplevel_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Tests fake toplevel ctor and dtor. */ -void test_fake(bs_test_t *test_ptr) -{ - wlmtk_fake_toplevel_t *fake_toplevel_ptr = wlmtk_fake_toplevel_create(); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_toplevel_ptr); - wlmtk_fake_toplevel_destroy(fake_toplevel_ptr); -} - -/* == End of toplevel.c ==================================================== */ diff --git a/src/toolkit/toplevel.h b/src/toolkit/toplevel.h deleted file mode 100644 index 6478971a..00000000 --- a/src/toolkit/toplevel.h +++ /dev/null @@ -1,319 +0,0 @@ -/* ========================================================================= */ -/** - * @file toplevel.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __WLMTK_TOPLEVEL_H__ -#define __WLMTK_TOPLEVEL_H__ - -/** Forward declaration: Toplevel. */ -typedef struct _wlmtk_toplevel_t wlmtk_toplevel_t; -/** Forward declaration: Virtual method table. */ -typedef struct _wlmtk_toplevel_vmt_t wlmtk_toplevel_vmt_t; - -#include "bordered.h" -#include "box.h" -#include "content.h" -#include "element.h" -#include "resizebar.h" -#include "titlebar.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Creates a toplevel for the given content. - * - * @param env_ptr - * @param content_ptr Will take ownership of content_ptr. - * - * @return Pointer to the toplevel state, or NULL on error. Must be free'd - * by calling @ref wlmtk_toplevel_destroy. - */ -wlmtk_toplevel_t *wlmtk_toplevel_create( - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); - -/** - * Destroys the toplevel. - * - * @param toplevel_ptr - */ -void wlmtk_toplevel_destroy(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Returns the super Element of the toplevel. - * - * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or - * whether to keep the ancestry members public. - * - * @param toplevel_ptr - * - * @return Pointer to the @ref wlmtk_element_t base instantiation to - * toplevel_ptr. - */ -wlmtk_element_t *wlmtk_toplevel_element(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Returns the toplevel from the super Element. - * - * @param element_ptr - * - * @return Pointer to the @ref wlmtk_toplevel_t, for which `element_ptr` is - * the ancestor. - */ -wlmtk_toplevel_t *wlmtk_toplevel_from_element(wlmtk_element_t *element_ptr); - -/** - * Sets the toplevel as activated, depending on the argument's value. - * - * An activated toplevel will have keyboard focus and would have distinct - * decorations to indicate state. - * - * @param toplevel_ptr - * @param activated - */ -void wlmtk_toplevel_set_activated( - wlmtk_toplevel_t *toplevel_ptr, - bool activated); - -/** - * Sets whether to have server-side decorations for this toplevel. - * - * @param toplevel_ptr - * @param decorated - */ -void wlmtk_toplevel_set_server_side_decorated( - wlmtk_toplevel_t *toplevel_ptr, - bool decorated); - -/** - * Sets the title for the toplevel. - * - * If `title_ptr` is NULL, a generic name is set. - * - * @param toplevel_ptr - * @param title_ptr May be NULL. - */ -void wlmtk_toplevel_set_title( - wlmtk_toplevel_t *toplevel_ptr, - const char *title_ptr); - -/** - * Returns the title of the toplevel. - * - * @param toplevel_ptr - * - * @returns Pointer to the toplevel title. Will remain valid until the next call - * to @ref wlmtk_toplevel_set_title, or until the toplevel is destroyed. Will - * never be NULL. - */ -const char *wlmtk_toplevel_get_title(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Requests to close the toplevel. - * - * @param toplevel_ptr - */ -void wlmtk_toplevel_request_close(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Requests to minimize (iconify) the toplevel. - * - * @param toplevel_ptr - */ -void wlmtk_toplevel_request_minimize(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Reuests the toplevel to be maximized. - * - * Requires the toplevel to be mapped (to a workspace). Will lookup the maximize - * extents from the workspace, and request a corresponding updated position and - * size for the toplevel. @ref wlmtk_toplevel_t::organic_size will not be updated. - * - * This may be implemented as an asynchronous operation. Maximization will be - * applied once the size change has been committed by the content. - * - * @param toplevel_ptr - * @param maximized - */ -void wlmtk_toplevel_request_maximize( - wlmtk_toplevel_t *toplevel_ptr, - bool maximized); - -/** Returns whether the toplevel is currently (requested to be) maximized. */ -bool wlmtk_toplevel_maximized(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Requests a move for the toplevel. - * - * Requires the toplevel to be mapped (to a workspace), and forwards the call to - * @ref wlmtk_workspace_begin_toplevel_move. - * - * @param toplevel_ptr - */ -void wlmtk_toplevel_request_move(wlmtk_toplevel_t *toplevel_ptr); - -/** - * Requests the toplevel to be resized. - * - * Requires the toplevel to be mapped (to a workspace), and forwards the call to - * @ref wlmtk_workspace_begin_toplevel_resize. - * - * @param toplevel_ptr - * @param edges - */ -void wlmtk_toplevel_request_resize(wlmtk_toplevel_t *toplevel_ptr, - uint32_t edges); - -/** - * Sets the toplevel's position. This is a synchronous operation. - * - * Updates the position in @ref wlmtk_toplevel_t::organic_size. - * @param toplevel_ptr - * @param x - * @param y - */ -void wlmtk_toplevel_set_position(wlmtk_toplevel_t *toplevel_ptr, int x, int y); - -/** - * Obtains the size of the toplevel, including potential decorations. - * - * @param toplevel_ptr - * @param width_ptr May be NULL. - * @param height_ptr May be NULL. - */ -void wlmtk_toplevel_get_size( - wlmtk_toplevel_t *toplevel_ptr, - int *width_ptr, - int *height_ptr); - -/** - * Requests a new size for the toplevel, including potential decorations. - * - * This may be implemented as an asynchronous operation. - * - * @param toplevel_ptr - * @param width - * @param height - */ -void wlmtk_toplevel_request_size( - wlmtk_toplevel_t *toplevel_ptr, - int width, - int height); - -/** - * Returns the current position and size of the toplevel. - * - * @param toplevel_ptr - * - * @return The position of the toplevel (the toplevel's element), and the currently - * committed width and height of the toplevel. - */ -struct wlr_box wlmtk_toplevel_get_position_and_size( - wlmtk_toplevel_t *toplevel_ptr); - -/** - * Requests an updated position and size for the toplevel, including potential - * decorations. - * - * This may be implemented as an asynchronous operation. The re-positioning - * will be applied only once the size change has been committed by the client. - * - * The position and size will be stored in @ref wlmtk_toplevel_t::organic_size. - * - * @param toplevel_ptr - * @param x - * @param y - * @param width - * @param height - */ -void wlmtk_toplevel_request_position_and_size( - wlmtk_toplevel_t *toplevel_ptr, - int x, - int y, - int width, - int height); - -/** - * Updates the toplevel state to what was requested at the `serial`. - * - * Used for example when resizing a toplevel from the top or left edges. In that - * case, @ref wlmtk_content_request_size may be asynchronous and returns a - * serial. The content is expected to call @ref wlmtk_toplevel_serial with the - * returned serial when the size is committed. - * Only then, the corresponding positional update on the top/left edges are - * supposed to be applied. - * - * @ref wlmtk_toplevel_t::organic_size will be updated, if there was no pending - * update: Meaning that the commit originated not from an earlier - * @ref wlmtk_toplevel_request_position_and_size or @ref - * wlmtk_toplevel_request_maximize call. - * - * @param toplevel_ptr - * @param serial - */ -void wlmtk_toplevel_serial(wlmtk_toplevel_t *toplevel_ptr, uint32_t serial); - -/* ------------------------------------------------------------------------- */ - -/** State of the fake toplevel, for tests. */ -typedef struct { - /** Toplevel state. */ - wlmtk_toplevel_t *toplevel_ptr; - /** Fake content, to manipulate the fake toplevel's content. */ - wlmtk_fake_content_t *fake_content_ptr; - - /** Argument to last @ref wlmtk_toplevel_set_activated call. */ - bool activated; - /** Whether @ref wlmtk_toplevel_request_close was called. */ - bool request_close_called; - /** Whether @ref wlmtk_toplevel_request_minimize was called. */ - bool request_minimize_called; - /** Whether @ref wlmtk_toplevel_request_move was called. */ - bool request_move_called; - /** Whether @ref wlmtk_toplevel_request_resize was called. */ - bool request_resize_called; - /** Argument to last @ref wlmtk_toplevel_request_resize call. */ - uint32_t request_resize_edges; - /** Whether @ref wlmtk_toplevel_request_position_and_size was called. */ - bool request_position_and_size_called; - /** Argument to last @ref wlmtk_toplevel_request_size call. */ - int x; - /** Argument to last @ref wlmtk_toplevel_request_size call. */ - int y; - /** Argument to last @ref wlmtk_toplevel_request_size call. */ - int width; - /** Argument to last @ref wlmtk_toplevel_request_size call. */ - int height; -} wlmtk_fake_toplevel_t; - -/** Ctor. */ -wlmtk_fake_toplevel_t *wlmtk_fake_toplevel_create(void); -/** Dtor. */ -void wlmtk_fake_toplevel_destroy(wlmtk_fake_toplevel_t *fake_toplevel_ptr); - -/** Unit tests for toplevel. */ -extern const bs_test_case_t wlmtk_toplevel_test_cases[]; - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __WLMTK_TOPLEVEL_H__ */ -/* == End of toplevel.h ==================================================== */ diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d83f3428..41787c64 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -20,69 +20,1148 @@ #include "window.h" +#include "rectangle.h" +#include "workspace.h" + +#include "wlr/util/box.h" + /* == Declarations ========================================================= */ +/** Maximum number of pending state updates. */ +#define WLMTK_WINDOW_MAX_PENDING 64 + +/** Virtual method table for the window. */ +struct _wlmtk_window_vmt_t { + /** Destructor. */ + void (*destroy)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_set_activated. */ + void (*set_activated)(wlmtk_window_t *window_ptr, + bool activated); + /** Virtual method for @ref wlmtk_window_request_close. */ + void (*request_close)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_request_minimize. */ + void (*request_minimize)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_request_move. */ + void (*request_move)(wlmtk_window_t *window_ptr); + /** Virtual method for @ref wlmtk_window_request_resize. */ + void (*request_resize)(wlmtk_window_t *window_ptr, + uint32_t edges); + /** Virtual method for @ref wlmtk_window_request_position_and_size. */ + void (*request_position_and_size)(wlmtk_window_t *window_ptr, + int x, int y, int width, int height); +}; + +/** Pending positional updates for @ref wlmtk_window_t::content_ptr. */ +typedef struct { + /** Node within @ref wlmtk_window_t::pending_updates. */ + bs_dllist_node_t dlnode; + /** Serial of the update. */ + uint32_t serial; + /** Pending X position of the content. */ + int x; + /** Pending Y position of the content. */ + int y; + /** Content's width that is to be committed at serial. */ + unsigned width; + /** Content's hehight that is to be committed at serial. */ + unsigned height; +} wlmtk_pending_update_t; + +/** State of the window. */ +struct _wlmtk_window_t { + /** Superclass: Bordered. */ + wlmtk_bordered_t super_bordered; + /** Original virtual method table of the window's element superclass. */ + wlmtk_element_vmt_t orig_super_element_vmt; + /** Original virtual method table of the window' container superclass. */ + wlmtk_container_vmt_t orig_super_container_vmt; + + /** Virtual method table. */ + wlmtk_window_vmt_t vmt; + + /** Box: In `super_bordered`, holds content, title bar and resizebar. */ + wlmtk_box_t box; + + /** Content of this window. */ + wlmtk_content_t *content_ptr; + /** Titlebar. */ + wlmtk_titlebar_t *titlebar_ptr; + /** Resizebar. */ + wlmtk_resizebar_t *resizebar_ptr; + + /** Window title. Set through @ref wlmtk_window_set_title. */ + char *title_ptr; + + /** Pending updates. */ + bs_dllist_t pending_updates; + /** List of udpates currently available. */ + bs_dllist_t available_updates; + /** Pre-alloocated updates. */ + wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; + + /** Organic size of the window, ie. when not maximized. */ + struct wlr_box organic_size; + /** Whether the window has been requested as maximized. */ + bool maximized; + + /** + * Stores whether the window is server-side decorated. + * + * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). + */ + bool server_side_decorated; +}; + +/** State of a fake window: Includes the public record and the window. */ +typedef struct { + /** Window state. */ + wlmtk_window_t window; + /** Fake window - public state. */ + wlmtk_fake_window_t fake_window; +} wlmtk_fake_window_state_t; + +static bool _wlmtk_window_init( + wlmtk_window_t *window_ptr, + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr); +static void _wlmtk_window_fini(wlmtk_window_t *window_ptr); +static wlmtk_window_vmt_t _wlmtk_window_extend( + wlmtk_window_t *window_ptr, + const wlmtk_window_vmt_t *window_vmt_ptr); + +static bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_window_container_update_layout( + wlmtk_container_t *container_ptr); + +static void _wlmtk_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated); +static void _wlmtk_window_request_close(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_move(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_resize( + wlmtk_window_t *window_ptr, + uint32_t edges); +static void _wlmtk_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); + +static wlmtk_pending_update_t *_wlmtk_window_prepare_update( + wlmtk_window_t *window_ptr); +static void _wlmtk_window_release_update( + wlmtk_window_t *window_ptr, + wlmtk_pending_update_t *update_ptr); +static wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr); + +/* == Data ================================================================= */ + +/** Virtual method table for the window's element superclass. */ +static const wlmtk_element_vmt_t window_element_vmt = { + .pointer_button = _wlmtk_window_element_pointer_button, +}; +/** Virtual method table for the window's container superclass. */ +static const wlmtk_container_vmt_t window_container_vmt = { + .update_layout = _wlmtk_window_container_update_layout, +}; +/** Virtual method table for the window itself. */ +static const wlmtk_window_vmt_t _wlmtk_window_vmt = { + .set_activated = _wlmtk_window_set_activated, + .request_close = _wlmtk_window_request_close, + .request_minimize = _wlmtk_window_request_minimize, + .request_move = _wlmtk_window_request_move, + .request_resize = _wlmtk_window_request_resize, + .request_position_and_size = _wlmtk_window_request_position_and_size, +}; + +/** Style of the title bar. */ +// TODO(kaeser@gubbe.ch): Move to central config. */ +static const wlmtk_titlebar_style_t titlebar_style = { + .focussed_fill = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, + .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} + }, + .blurred_fill = { + .type = WLMTK_STYLE_COLOR_HGRADIENT, + .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} + }, + .focussed_text_color = 0xffffffff, + .blurred_text_color = 0xff000000, + .height = 22, + .bezel_width = 1, + .margin_style = { .width = 1, .color = 0xff000000 }, +}; + +/** Style of the resize bar. */ +// TODO(kaeser@gubbe.ch): Move to central config. */ +static const wlmtk_resizebar_style_t resizebar_style = { + .fill = { + .type = WLMTK_STYLE_COLOR_SOLID, + .param = { .solid = { .color = 0xffc2c0c5 }} + }, + .height = 7, + .corner_width = 29, + .bezel_width = 1, + .margin_style = { .width = 0, .color = 0xff000000 }, +}; + +/** Style of the margin between title, content and resizebar. */ +static const wlmtk_margin_style_t margin_style = { + .width = 1, + .color = 0xff000000, +}; + +/** Style of the border around the window. */ +static const wlmtk_margin_style_t border_style = { + .width = 1, + .color = 0xff000000, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -bool wlmtk_window_init( +wlmtk_window_t *wlmtk_window_create( + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr) +{ + wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); + if (NULL == window_ptr) return NULL; + + if (!_wlmtk_window_init(window_ptr, env_ptr, content_ptr)) { + wlmtk_window_destroy(window_ptr); + return NULL; + } + + return window_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_destroy(wlmtk_window_t *window_ptr) +{ + _wlmtk_window_fini(window_ptr); + free(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr) +{ + return &window_ptr->super_bordered.super_container.super_element; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); + BS_ASSERT(_wlmtk_window_container_update_layout == + window_ptr->super_bordered.super_container.vmt.update_layout); + return window_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, - wlmtk_surface_t *surface_ptr, - wlmtk_env_t *env_ptr) + bool activated) +{ + window_ptr->vmt.set_activated(window_ptr, activated); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_server_side_decorated( + wlmtk_window_t *window_ptr, + bool decorated) +{ + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_INFO, "Set server side decoration for window %p: %d", + window_ptr, decorated); + + if (window_ptr->server_side_decorated == decorated) return; + + if (decorated) { + // Create decoration. + window_ptr->titlebar_ptr = wlmtk_titlebar_create( + window_ptr->super_bordered.super_container.super_element.env_ptr, + window_ptr, &titlebar_style); + BS_ASSERT(NULL != window_ptr->titlebar_ptr); + wlmtk_element_set_visible( + wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + + window_ptr->resizebar_ptr = wlmtk_resizebar_create( + window_ptr->super_bordered.super_container.super_element.env_ptr, + window_ptr, &resizebar_style); + BS_ASSERT(NULL != window_ptr->resizebar_ptr); + wlmtk_element_set_visible( + wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); + wlmtk_box_add_element_back( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + } else { + // Remove & destroy the decoration. + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); + window_ptr->titlebar_ptr = NULL; + + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); + window_ptr->resizebar_ptr = NULL; + } + + window_ptr->server_side_decorated = decorated; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_title( + wlmtk_window_t *window_ptr, + const char *title_ptr) +{ + char *new_title_ptr = NULL; + if (NULL != title_ptr) { + new_title_ptr = logged_strdup(title_ptr); + BS_ASSERT(NULL != new_title_ptr); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), "Unnamed window %p", window_ptr); + new_title_ptr = logged_strdup(buf); + BS_ASSERT(NULL != new_title_ptr); + } + + if (NULL != window_ptr->title_ptr) { + if (0 == strcmp(window_ptr->title_ptr, new_title_ptr)) { + free(new_title_ptr); + return; + } + free(window_ptr->title_ptr); + } + window_ptr->title_ptr = new_title_ptr; + + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_title(window_ptr->titlebar_ptr, + window_ptr->title_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(NULL != window_ptr->title_ptr); + return window_ptr->title_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_close(wlmtk_window_t *window_ptr) +{ + window_ptr->vmt.request_close(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) +{ + window_ptr->vmt.request_minimize(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized) +{ + if (window_ptr->maximized == maximized) return; + + window_ptr->maximized = maximized; + + struct wlr_box box; + if (window_ptr->maximized) { + box = wlmtk_workspace_get_maximize_extents( + _wlmtk_window_workspace(window_ptr)); + } else { + box = window_ptr->organic_size; + } + + _wlmtk_window_request_position_and_size( + window_ptr, box.x, box.y, box.width, box.height); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) +{ + return window_ptr->maximized; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_move(wlmtk_window_t *window_ptr) +{ + window_ptr->vmt.request_move(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, + uint32_t edges) +{ + window_ptr->vmt.request_resize(window_ptr, edges); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y) +{ + window_ptr->organic_size.x = x; + window_ptr->organic_size.y = y; + wlmtk_element_set_position(wlmtk_window_element(window_ptr), x, y); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr) +{ + // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. + wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); + + if (NULL != window_ptr->titlebar_ptr) { + *height_ptr += titlebar_style.height + margin_style.width; + } + if (NULL != window_ptr->resizebar_ptr) { + *height_ptr += resizebar_style.height + margin_style.width; + } + *height_ptr += 2 * border_style.width; + + *width_ptr += 2 * border_style.width; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_size( + wlmtk_window_t *window_ptr, + int width, + int height) +{ + // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. + wlmtk_content_request_size(window_ptr->content_ptr, width, height); + + // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting + // the size is an asynchronous operation and should be handled as such. + // Meaning: In example of resizing at the top-left corner, we'll want to + // request the content to adjust size, but wait with adjusting the + // content position until the size adjustment is applied. This implies we + // may need to combine the request_size and set_position methods for window. +} + +/* ------------------------------------------------------------------------- */ +struct wlr_box wlmtk_window_get_position_and_size( + wlmtk_window_t *window_ptr) +{ + struct wlr_box box; + + wlmtk_element_get_position( + wlmtk_window_element(window_ptr), &box.x, &box.y); + wlmtk_window_get_size(window_ptr, &box.width, &box.height); + return box; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height) +{ + window_ptr->vmt.request_position_and_size( + window_ptr, x, y, width, height); + + window_ptr->organic_size.x = x; + window_ptr->organic_size.y = y; + window_ptr->organic_size.width = width; + window_ptr->organic_size.height = height; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) +{ + bs_dllist_node_t *dlnode_ptr; + + if (!window_ptr->maximized && + NULL == window_ptr->pending_updates.head_ptr) { + wlmtk_window_get_size(window_ptr, + &window_ptr->organic_size.width, + &window_ptr->organic_size.height); + return; + } + + while (NULL != (dlnode_ptr = window_ptr->pending_updates.head_ptr)) { + wlmtk_pending_update_t *pending_update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); + + int32_t delta = pending_update_ptr->serial - serial; + if (0 < delta) break; + + if (pending_update_ptr->serial == serial) { + if (window_ptr->content_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (window_ptr->content_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } + } + + wlmtk_element_set_position( + wlmtk_window_element(window_ptr), + pending_update_ptr->x, + pending_update_ptr->y); + _wlmtk_window_release_update(window_ptr, pending_update_ptr); + } +} + +/* == Local (static) methods =============================================== */ + +/* ------------------------------------------------------------------------- */ +/** + * Initializes an (allocated) window. + * + * @param window_ptr + * @param env_ptr + * @param content_ptr + * + * @return true on success. + */ +bool _wlmtk_window_init( + wlmtk_window_t *window_ptr, + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr) { BS_ASSERT(NULL != window_ptr); - memset(window_ptr, 0, sizeof(wlmtk_window_t)); - if (!wlmtk_container_init(&window_ptr->super_container, env_ptr)) { + memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); + + for (size_t i = 0; i < WLMTK_WINDOW_MAX_PENDING; ++i) { + bs_dllist_push_back(&window_ptr->available_updates, + &window_ptr->pre_allocated_updates[i].dlnode); + } + + if (!wlmtk_box_init(&window_ptr->box, env_ptr, + WLMTK_BOX_VERTICAL, + &margin_style)) { + _wlmtk_window_fini(window_ptr); + return false; + } + wlmtk_element_set_visible( + &window_ptr->box.super_container.super_element, true); + + if (!wlmtk_bordered_init(&window_ptr->super_bordered, + env_ptr, + &window_ptr->box.super_container.super_element, + &border_style)) { + _wlmtk_window_fini(window_ptr); return false; } - BS_ASSERT(NULL != surface_ptr); - window_ptr->surface_ptr = surface_ptr; - wlmtk_container_add_element( - &window_ptr->super_container, - wlmtk_surface_element(window_ptr->surface_ptr)); + window_ptr->orig_super_element_vmt = wlmtk_element_extend( + &window_ptr->super_bordered.super_container.super_element, + &window_element_vmt); + window_ptr->orig_super_container_vmt = wlmtk_container_extend( + &window_ptr->super_bordered.super_container, &window_container_vmt); + + wlmtk_window_set_title(window_ptr, NULL); + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_content_element(content_ptr)); + window_ptr->content_ptr = content_ptr; + wlmtk_content_set_window(content_ptr, window_ptr); + wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); return true; } /* ------------------------------------------------------------------------- */ -void wlmtk_window_fini( +/** + * Uninitializes the winodw. + * + * @param window_ptr + */ +void _wlmtk_window_fini(wlmtk_window_t *window_ptr) +{ + wlmtk_window_set_server_side_decorated(window_ptr, false); + + if (NULL != window_ptr->content_ptr) { + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_content_element(window_ptr->content_ptr)); + wlmtk_element_set_visible( + wlmtk_content_element(window_ptr->content_ptr), false); + wlmtk_content_set_window(window_ptr->content_ptr, NULL); + + wlmtk_element_destroy(wlmtk_content_element(window_ptr->content_ptr)); + window_ptr->content_ptr = NULL; + } + + if (NULL != window_ptr->title_ptr) { + free(window_ptr->title_ptr); + window_ptr->title_ptr = NULL; + } + + wlmtk_bordered_fini(&window_ptr->super_bordered); + wlmtk_box_fini(&window_ptr->box); +} + +/* ------------------------------------------------------------------------- */ +/** + * Extends the window's virtual methods. + * + * @param window_ptr + * @param window_vmt_ptr + * + * @return The previous virtual method table. + */ +wlmtk_window_vmt_t _wlmtk_window_extend( + wlmtk_window_t *window_ptr, + const wlmtk_window_vmt_t *window_vmt_ptr) +{ + wlmtk_window_vmt_t orig_vmt = window_ptr->vmt; + + if (NULL != window_vmt_ptr->set_activated) { + window_ptr->vmt.set_activated = window_vmt_ptr->set_activated; + } + if (NULL != window_vmt_ptr->request_close) { + window_ptr->vmt.request_close = window_vmt_ptr->request_close; + } + if (NULL != window_vmt_ptr->request_minimize) { + window_ptr->vmt.request_minimize = window_vmt_ptr->request_minimize; + } + if (NULL != window_vmt_ptr->request_move) { + window_ptr->vmt.request_move = window_vmt_ptr->request_move; + } + if (NULL != window_vmt_ptr->request_resize) { + window_ptr->vmt.request_resize = window_vmt_ptr->request_resize; + } + if (NULL != window_vmt_ptr->request_position_and_size) { + window_ptr->vmt.request_position_and_size = + window_vmt_ptr->request_position_and_size; + } + + return orig_vmt; +} + +/* ------------------------------------------------------------------------- */ +/** Activates window on button press, and calls the parent's implementation. */ +bool _wlmtk_window_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); + + // We shouldn't receive buttons when not mapped. + wlmtk_workspace_t *workspace_ptr = _wlmtk_window_workspace(window_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + wlmtk_workspace_raise_window(workspace_ptr, window_ptr); + + return window_ptr->orig_super_element_vmt.pointer_button( + element_ptr, button_event_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Implementation of @ref wlmtk_container_vmt_t::update_layout. + * + * Invoked when the window's contained elements triggered a layout update, + * and will use this to trigger (potential) size updates to the window + * decorations. + * + * @param container_ptr + */ +void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) +{ + wlmtk_window_t *window_ptr = BS_CONTAINER_OF( + container_ptr, wlmtk_window_t, super_bordered.super_container); + + window_ptr->orig_super_container_vmt.update_layout(container_ptr); + + if (NULL != window_ptr->content_ptr) { + int width; + wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); + } + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); + } + } +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_set_activated. */ +void _wlmtk_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated) +{ + wlmtk_content_set_activated(window_ptr->content_ptr, activated); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); + } +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_close. */ +void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) +{ + wlmtk_content_request_close(window_ptr->content_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_minimize. */ +void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) +{ + bs_log(BS_INFO, "Requesting window %p to minimize.", window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_move. */ +void _wlmtk_window_request_move(wlmtk_window_t *window_ptr) +{ + wlmtk_workspace_begin_window_move( + _wlmtk_window_workspace(window_ptr), window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_resize. */ +void _wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) +{ + wlmtk_workspace_begin_window_resize( + _wlmtk_window_workspace(window_ptr), window_ptr, edges); +} + +/* ------------------------------------------------------------------------- */ +/** Default implementation of @ref wlmtk_window_request_position_and_size. */ +void _wlmtk_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height) +{ + // Correct for borders, margin and decoration. + if (NULL != window_ptr->titlebar_ptr) { + height -= titlebar_style.height + margin_style.width; + } + if (NULL != window_ptr->resizebar_ptr) { + height -= resizebar_style.height + margin_style.width; + } + height -= 2 * border_style.width; + width -= 2 * border_style.width; + height = BS_MAX(0, height); + width = BS_MAX(0, width); + + uint32_t serial = wlmtk_content_request_size( + window_ptr->content_ptr, width, height); + + wlmtk_pending_update_t *pending_update_ptr = + _wlmtk_window_prepare_update(window_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = x; + pending_update_ptr->y = y; + pending_update_ptr->width = width; + pending_update_ptr->height = height; + + // TODO(kaeser@gubbe.ch): Handle synchronous case: @ref wlmtk_window_serial + // may have been called early, so we should check if serial had just been + // called before (or is below the last @wlmt_window_serial). In that case, + // the pending state should be applied right away. +} + +/* ------------------------------------------------------------------------- */ +/** + * Prepares a positional update: Allocates an item and attach it to the end + * of the list of pending updates. + * + * @param window_ptr + * + * @return A pointer to a @ref wlmtk_pending_update_t, already positioned at the + * back of @ref wlmtk_window_t::pending_updates. + */ +wlmtk_pending_update_t *_wlmtk_window_prepare_update( wlmtk_window_t *window_ptr) { - if (NULL != window_ptr->surface_ptr) { - wlmtk_container_remove_element( - &window_ptr->super_container, - wlmtk_surface_element(window_ptr->surface_ptr)); - window_ptr->surface_ptr = NULL; + bs_dllist_node_t *dlnode_ptr = bs_dllist_pop_front( + &window_ptr->available_updates); + if (NULL == dlnode_ptr) { + dlnode_ptr = bs_dllist_pop_front(&window_ptr->pending_updates); + bs_log(BS_WARNING, "Window %p: No updates available.", window_ptr); + // TODO(kaeser@gubbe.ch): Hm, should we apply this (old) update? } + wlmtk_pending_update_t *update_ptr = BS_CONTAINER_OF( + dlnode_ptr, wlmtk_pending_update_t, dlnode); + bs_dllist_push_back(&window_ptr->pending_updates, &update_ptr->dlnode); + return update_ptr; +} + +/* ------------------------------------------------------------------------- */ +/** + * Releases a pending positional update. Moves it to the list of + * @ref wlmtk_window_t::available_updates. + * + * @param window_ptr + * @param update_ptr + */ +void _wlmtk_window_release_update( + wlmtk_window_t *window_ptr, + wlmtk_pending_update_t *update_ptr) +{ + bs_dllist_remove(&window_ptr->pending_updates, &update_ptr->dlnode); + bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); +} - wlmtk_container_fini(&window_ptr->super_container); - memset(window_ptr, 0, sizeof(wlmtk_window_t)); +/* ------------------------------------------------------------------------- */ +/** Returns the workspace of the (mapped) window. */ +wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(NULL != wlmtk_window_element(window_ptr)->parent_container_ptr); + return wlmtk_workspace_from_container( + wlmtk_window_element(window_ptr)->parent_container_ptr); } -/* == Local (static) methods =============================================== */ +/* == Implementation of the fake window ==================================== */ + +static void _wlmtk_fake_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated); +static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); +static void _wlmtk_fake_window_request_resize( + wlmtk_window_t *window_ptr, + uint32_t edges); +static void _wlmtk_fake_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); -static void test_init_fini(bs_test_t *test_ptr); +/** Virtual method table for the fake window itself. */ +static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { + .set_activated = _wlmtk_fake_window_set_activated, + .request_close = _wlmtk_fake_window_request_close, + .request_minimize = _wlmtk_fake_window_request_minimize, + .request_move = _wlmtk_fake_window_request_move, + .request_resize = _wlmtk_fake_window_request_resize, + .request_position_and_size = _wlmtk_fake_window_request_position_and_size, + +}; + +/* ------------------------------------------------------------------------- */ +wlmtk_fake_window_t *wlmtk_fake_window_create(void) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_window_state_t)); + if (NULL == fake_window_state_ptr) return NULL; + + fake_window_state_ptr->fake_window.fake_content_ptr = + wlmtk_fake_content_create(); + if (NULL == fake_window_state_ptr->fake_window.fake_content_ptr) { + wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); + return NULL; + } + + if (!_wlmtk_window_init( + &fake_window_state_ptr->window, + NULL, + &fake_window_state_ptr->fake_window.fake_content_ptr->content)) { + wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); + return NULL; + } + fake_window_state_ptr->fake_window.window_ptr = + &fake_window_state_ptr->window; + + // Extend. We don't save the VMT, since it's for fake only. + _wlmtk_window_extend(&fake_window_state_ptr->window, + &_wlmtk_fake_window_vmt); + return &fake_window_state_ptr->fake_window; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + fake_window_ptr, wlmtk_fake_window_state_t, fake_window); + + _wlmtk_window_fini(&fake_window_state_ptr->window); + free(fake_window_state_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_set_activated. Records call. */ +void _wlmtk_fake_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.activated = activated; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_close. Records call. */ +void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_close_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_minimize. Records call. */ +void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_minimize_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_move. Records call */ +void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_move_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_resize. Records call. */ +void _wlmtk_fake_window_request_resize( + wlmtk_window_t *window_ptr, + uint32_t edges) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_resize_called = true; + fake_window_state_ptr->fake_window.request_resize_edges = edges; +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_window_request_position_and_size. */ +void _wlmtk_fake_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height) +{ + wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( + window_ptr, wlmtk_fake_window_state_t, window); + fake_window_state_ptr->fake_window.request_position_and_size_called = true; + fake_window_state_ptr->fake_window.x = x; + fake_window_state_ptr->fake_window.y = y; + fake_window_state_ptr->fake_window.width = width; + fake_window_state_ptr->fake_window.height = height; +} + +/* == Unit tests =========================================================== */ + +static void test_create_destroy(bs_test_t *test_ptr); +static void test_set_title(bs_test_t *test_ptr); +static void test_request_close(bs_test_t *test_ptr); +static void test_set_activated(bs_test_t *test_ptr); +static void test_server_side_decorated(bs_test_t *test_ptr); +static void test_maximize(bs_test_t *test_ptr); +static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { - { 1, "init_fini", test_init_fini }, + { 1, "create_destroy", test_create_destroy }, + { 1, "set_title", test_set_title }, + { 1, "request_close", test_request_close }, + { 1, "set_activated", test_set_activated }, + { 1, "set_server_side_decorated", test_server_side_decorated }, + { 1, "maximize", test_maximize }, + { 1, "fake", test_fake }, { 0, NULL, NULL } }; /* ------------------------------------------------------------------------- */ -/** Tests initialization and un-initialization. */ -void test_init_fini(bs_test_t *test_ptr) +/** Tests setup and teardown. */ +void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_window_t window; - wlmtk_surface_t surface; - wlmtk_surface_init(&surface, NULL, NULL); + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, window_ptr, + fake_content_ptr->content.window_ptr); - BS_TEST_VERIFY_TRUE( + wlmtk_window_destroy(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests title. */ +void test_set_title(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + + wlmtk_window_set_title(window_ptr, "Title"); + BS_TEST_VERIFY_STREQ( + test_ptr, + "Title", + wlmtk_window_get_title(window_ptr)); + + wlmtk_window_set_title(window_ptr, NULL); + BS_TEST_VERIFY_STRMATCH( test_ptr, - wlmtk_window_init(&window, &surface, NULL)); - wlmtk_window_fini(&window); + wlmtk_window_get_title(window_ptr), + "Unnamed window .*"); + + wlmtk_window_destroy(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests activation. */ +void test_request_close(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); - wlmtk_surface_fini(&surface); + wlmtk_window_request_close(window_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); + + wlmtk_window_destroy(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests activation. */ +void test_set_activated(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + + wlmtk_window_set_activated(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); + + wlmtk_window_set_activated(window_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->activated); + + wlmtk_window_destroy(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests enabling and disabling server-side decoration. */ +void test_server_side_decorated(bs_test_t *test_ptr) +{ + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + wlmtk_window_set_server_side_decorated(window_ptr, true); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + wlmtk_window_set_server_side_decorated(window_ptr, false); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + wlmtk_window_destroy(window_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests maximizing and un-maximizing a window. */ +void test_maximize(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + NULL, fake_parent_ptr->wlr_scene_tree_ptr); + struct wlr_box extents = { .width = 1024, .height = 768 }, box; + wlmtk_workspace_set_extents(workspace_ptr, &extents); + BS_ASSERT(NULL != workspace_ptr); + + wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_window_t *window_ptr = wlmtk_window_create( + NULL, &fake_content_ptr->content); + BS_ASSERT(NULL != window_ptr); + // Window must be mapped to get maximized: Need workspace dimensions. + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + + // Set up initial organic size, and verify. + wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); + + // Re-position the window. + wlmtk_window_set_position(window_ptr, 50, 30); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Trigger another serial update. Should not change position nor size. + wlmtk_window_serial(window_ptr, 1234); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Maximize. + wlmtk_window_request_maximize(window_ptr, true); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); + + // A second commit: should not overwrite the organic dimension. + wlmtk_fake_content_commit(fake_content_ptr); + + // Unmaximize. Restore earlier organic size and position. + wlmtk_window_request_maximize(window_ptr, false); + wlmtk_fake_content_commit(fake_content_ptr); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); + + // TODO(kaeser@gubbe.ch): Define what should happen when a maximized + // window is moved. Should it lose maximization? Should it not move? + // Or just move on? + // Window Maker keeps maximization, but it's ... odd. + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_window_destroy(window_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Tests fake window ctor and dtor. */ +void test_fake(bs_test_t *test_ptr) +{ + wlmtk_fake_window_t *fake_window_ptr = wlmtk_fake_window_create(); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_window_ptr); + wlmtk_fake_window_destroy(fake_window_ptr); } /* == End of window.c ====================================================== */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h new file mode 100644 index 00000000..fb99b4cd --- /dev/null +++ b/src/toolkit/window.h @@ -0,0 +1,319 @@ +/* ========================================================================= */ +/** + * @file window.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_WINDOW_H__ +#define __WLMTK_WINDOW_H__ + +/** Forward declaration: Window. */ +typedef struct _wlmtk_window_t wlmtk_window_t; +/** Forward declaration: Virtual method table. */ +typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; + +#include "bordered.h" +#include "box.h" +#include "content.h" +#include "element.h" +#include "resizebar.h" +#include "titlebar.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Creates a window for the given content. + * + * @param env_ptr + * @param content_ptr Will take ownership of content_ptr. + * + * @return Pointer to the window state, or NULL on error. Must be free'd + * by calling @ref wlmtk_window_destroy. + */ +wlmtk_window_t *wlmtk_window_create( + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr); + +/** + * Destroys the window. + * + * @param window_ptr + */ +void wlmtk_window_destroy(wlmtk_window_t *window_ptr); + +/** + * Returns the super Element of the window. + * + * TODO(kaeser@gubbe.ch): Re-evaluate whether to work with accessors, or + * whether to keep the ancestry members public. + * + * @param window_ptr + * + * @return Pointer to the @ref wlmtk_element_t base instantiation to + * window_ptr. + */ +wlmtk_element_t *wlmtk_window_element(wlmtk_window_t *window_ptr); + +/** + * Returns the window from the super Element. + * + * @param element_ptr + * + * @return Pointer to the @ref wlmtk_window_t, for which `element_ptr` is + * the ancestor. + */ +wlmtk_window_t *wlmtk_window_from_element(wlmtk_element_t *element_ptr); + +/** + * Sets the window as activated, depending on the argument's value. + * + * An activated window will have keyboard focus and would have distinct + * decorations to indicate state. + * + * @param window_ptr + * @param activated + */ +void wlmtk_window_set_activated( + wlmtk_window_t *window_ptr, + bool activated); + +/** + * Sets whether to have server-side decorations for this window. + * + * @param window_ptr + * @param decorated + */ +void wlmtk_window_set_server_side_decorated( + wlmtk_window_t *window_ptr, + bool decorated); + +/** + * Sets the title for the window. + * + * If `title_ptr` is NULL, a generic name is set. + * + * @param window_ptr + * @param title_ptr May be NULL. + */ +void wlmtk_window_set_title( + wlmtk_window_t *window_ptr, + const char *title_ptr); + +/** + * Returns the title of the window. + * + * @param window_ptr + * + * @returns Pointer to the window title. Will remain valid until the next call + * to @ref wlmtk_window_set_title, or until the window is destroyed. Will + * never be NULL. + */ +const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr); + +/** + * Requests to close the window. + * + * @param window_ptr + */ +void wlmtk_window_request_close(wlmtk_window_t *window_ptr); + +/** + * Requests to minimize (iconify) the window. + * + * @param window_ptr + */ +void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); + +/** + * Reuests the window to be maximized. + * + * Requires the window to be mapped (to a workspace). Will lookup the maximize + * extents from the workspace, and request a corresponding updated position and + * size for the window. @ref wlmtk_window_t::organic_size will not be updated. + * + * This may be implemented as an asynchronous operation. Maximization will be + * applied once the size change has been committed by the content. + * + * @param window_ptr + * @param maximized + */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized); + +/** Returns whether the window is currently (requested to be) maximized. */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); + +/** + * Requests a move for the window. + * + * Requires the window to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_window_move. + * + * @param window_ptr + */ +void wlmtk_window_request_move(wlmtk_window_t *window_ptr); + +/** + * Requests the window to be resized. + * + * Requires the window to be mapped (to a workspace), and forwards the call to + * @ref wlmtk_workspace_begin_window_resize. + * + * @param window_ptr + * @param edges + */ +void wlmtk_window_request_resize(wlmtk_window_t *window_ptr, + uint32_t edges); + +/** + * Sets the window's position. This is a synchronous operation. + * + * Updates the position in @ref wlmtk_window_t::organic_size. + * @param window_ptr + * @param x + * @param y + */ +void wlmtk_window_set_position(wlmtk_window_t *window_ptr, int x, int y); + +/** + * Obtains the size of the window, including potential decorations. + * + * @param window_ptr + * @param width_ptr May be NULL. + * @param height_ptr May be NULL. + */ +void wlmtk_window_get_size( + wlmtk_window_t *window_ptr, + int *width_ptr, + int *height_ptr); + +/** + * Requests a new size for the window, including potential decorations. + * + * This may be implemented as an asynchronous operation. + * + * @param window_ptr + * @param width + * @param height + */ +void wlmtk_window_request_size( + wlmtk_window_t *window_ptr, + int width, + int height); + +/** + * Returns the current position and size of the window. + * + * @param window_ptr + * + * @return The position of the window (the window's element), and the currently + * committed width and height of the window. + */ +struct wlr_box wlmtk_window_get_position_and_size( + wlmtk_window_t *window_ptr); + +/** + * Requests an updated position and size for the window, including potential + * decorations. + * + * This may be implemented as an asynchronous operation. The re-positioning + * will be applied only once the size change has been committed by the client. + * + * The position and size will be stored in @ref wlmtk_window_t::organic_size. + * + * @param window_ptr + * @param x + * @param y + * @param width + * @param height + */ +void wlmtk_window_request_position_and_size( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height); + +/** + * Updates the window state to what was requested at the `serial`. + * + * Used for example when resizing a window from the top or left edges. In that + * case, @ref wlmtk_content_request_size may be asynchronous and returns a + * serial. The content is expected to call @ref wlmtk_window_serial with the + * returned serial when the size is committed. + * Only then, the corresponding positional update on the top/left edges are + * supposed to be applied. + * + * @ref wlmtk_window_t::organic_size will be updated, if there was no pending + * update: Meaning that the commit originated not from an earlier + * @ref wlmtk_window_request_position_and_size or @ref + * wlmtk_window_request_maximize call. + * + * @param window_ptr + * @param serial + */ +void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); + +/* ------------------------------------------------------------------------- */ + +/** State of the fake window, for tests. */ +typedef struct { + /** Window state. */ + wlmtk_window_t *window_ptr; + /** Fake content, to manipulate the fake window's content. */ + wlmtk_fake_content_t *fake_content_ptr; + + /** Argument to last @ref wlmtk_window_set_activated call. */ + bool activated; + /** Whether @ref wlmtk_window_request_close was called. */ + bool request_close_called; + /** Whether @ref wlmtk_window_request_minimize was called. */ + bool request_minimize_called; + /** Whether @ref wlmtk_window_request_move was called. */ + bool request_move_called; + /** Whether @ref wlmtk_window_request_resize was called. */ + bool request_resize_called; + /** Argument to last @ref wlmtk_window_request_resize call. */ + uint32_t request_resize_edges; + /** Whether @ref wlmtk_window_request_position_and_size was called. */ + bool request_position_and_size_called; + /** Argument to last @ref wlmtk_window_request_size call. */ + int x; + /** Argument to last @ref wlmtk_window_request_size call. */ + int y; + /** Argument to last @ref wlmtk_window_request_size call. */ + int width; + /** Argument to last @ref wlmtk_window_request_size call. */ + int height; +} wlmtk_fake_window_t; + +/** Ctor. */ +wlmtk_fake_window_t *wlmtk_fake_window_create(void); +/** Dtor. */ +void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr); + +/** Unit tests for window. */ +extern const bs_test_case_t wlmtk_window_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_WINDOW_H__ */ +/* == End of window.h ====================================================== */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 2b9681f3..00c29529 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -40,11 +40,11 @@ struct _wlmtk_workspace_t { /** Current FSM state. */ wlmtk_fsm_t fsm; - /** The activated toplevel. */ - wlmtk_toplevel_t *activated_toplevel_ptr; + /** The activated window. */ + wlmtk_window_t *activated_window_ptr; - /** The grabbed toplevel. */ - wlmtk_toplevel_t *grabbed_toplevel_ptr; + /** The grabbed window. */ + wlmtk_window_t *grabbed_window_ptr; /** Motion X */ int motion_x; /** Motion Y */ @@ -53,9 +53,9 @@ struct _wlmtk_workspace_t { int initial_x; /** Element's Y position when initiating a move or resize. */ int initial_y; - /** Toplevel's width when initiazing the resize. */ + /** Window's width when initiazing the resize. */ int initial_width; - /** Toplevel's height when initiazing the resize. */ + /** Window's height when initiazing the resize. */ int initial_height; /** Edges currently active for resizing: `enum wlr_edges`. */ uint32_t resize_edges; @@ -195,40 +195,40 @@ struct wlr_box wlmtk_workspace_get_maximize_extents( } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_map_toplevel(wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr) +void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) { - wlmtk_element_set_visible(wlmtk_toplevel_element(toplevel_ptr), true); + wlmtk_element_set_visible(wlmtk_window_element(window_ptr), true); wlmtk_container_add_element( &workspace_ptr->super_container, - wlmtk_toplevel_element(toplevel_ptr)); + wlmtk_window_element(window_ptr)); - wlmtk_workspace_activate_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_unmap_toplevel(wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr) +void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr) { bool need_activation = false; BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( - wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr)); + wlmtk_window_element(window_ptr)->parent_container_ptr)); - if (workspace_ptr->grabbed_toplevel_ptr == toplevel_ptr) { + if (workspace_ptr->grabbed_window_ptr == window_ptr) { wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); - BS_ASSERT(NULL == workspace_ptr->grabbed_toplevel_ptr); + BS_ASSERT(NULL == workspace_ptr->grabbed_window_ptr); } - if (workspace_ptr->activated_toplevel_ptr == toplevel_ptr) { - wlmtk_workspace_activate_toplevel(workspace_ptr, NULL); + if (workspace_ptr->activated_window_ptr == window_ptr) { + wlmtk_workspace_activate_window(workspace_ptr, NULL); need_activation = true; } - wlmtk_element_set_visible(wlmtk_toplevel_element(toplevel_ptr), false); + wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); wlmtk_container_remove_element( &workspace_ptr->super_container, - wlmtk_toplevel_element(toplevel_ptr)); + wlmtk_window_element(window_ptr)); if (need_activation) { // FIXME: What about raising? @@ -236,8 +236,8 @@ void wlmtk_workspace_unmap_toplevel(wlmtk_workspace_t *workspace_ptr, workspace_ptr->super_container.elements.head_ptr; if (NULL != dlnode_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_from_element(element_ptr); - wlmtk_workspace_activate_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_window_t *window_ptr = wlmtk_window_from_element(element_ptr); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); } } } @@ -295,50 +295,50 @@ void wlmtk_workspace_button( } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_begin_toplevel_move( +void wlmtk_workspace_begin_window_move( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr) + wlmtk_window_t *window_ptr) { - wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_MOVE, toplevel_ptr); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_MOVE, window_ptr); } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_begin_toplevel_resize( +void wlmtk_workspace_begin_window_resize( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, uint32_t edges) { workspace_ptr->resize_edges = edges; - wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_RESIZE, toplevel_ptr); + wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_BEGIN_RESIZE, window_ptr); } /* ------------------------------------------------------------------------- */ -/** Acticates `toplevel_ptr`. Will de-activate an earlier toplevel. */ -void wlmtk_workspace_activate_toplevel( +/** Acticates `window_ptr`. Will de-activate an earlier window. */ +void wlmtk_workspace_activate_window( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr) + wlmtk_window_t *window_ptr) { // Nothing to do. - if (workspace_ptr->activated_toplevel_ptr == toplevel_ptr) return; + if (workspace_ptr->activated_window_ptr == window_ptr) return; - if (NULL != workspace_ptr->activated_toplevel_ptr) { - wlmtk_toplevel_set_activated(workspace_ptr->activated_toplevel_ptr, false); - workspace_ptr->activated_toplevel_ptr = NULL; + if (NULL != workspace_ptr->activated_window_ptr) { + wlmtk_window_set_activated(workspace_ptr->activated_window_ptr, false); + workspace_ptr->activated_window_ptr = NULL; } - if (NULL != toplevel_ptr) { - wlmtk_toplevel_set_activated(toplevel_ptr, true); - workspace_ptr->activated_toplevel_ptr = toplevel_ptr; + if (NULL != window_ptr) { + wlmtk_window_set_activated(window_ptr, true); + workspace_ptr->activated_window_ptr = window_ptr; } } /* ------------------------------------------------------------------------- */ -void wlmtk_workspace_raise_toplevel( +void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr) + wlmtk_window_t *window_ptr) { wlmtk_container_raise_element_to_top(&workspace_ptr->super_container, - wlmtk_toplevel_element(toplevel_ptr)); + wlmtk_window_element(window_ptr)); } /* == Local (static) methods =============================================== */ @@ -470,14 +470,14 @@ bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( fsm_ptr, wlmtk_workspace_t, fsm); - workspace_ptr->grabbed_toplevel_ptr = ud_ptr; + workspace_ptr->grabbed_window_ptr = ud_ptr; workspace_ptr->motion_x = workspace_ptr->super_container.super_element.last_pointer_x; workspace_ptr->motion_y = workspace_ptr->super_container.super_element.last_pointer_y; wlmtk_element_get_position( - wlmtk_toplevel_element(workspace_ptr->grabbed_toplevel_ptr), + wlmtk_window_element(workspace_ptr->grabbed_window_ptr), &workspace_ptr->initial_x, &workspace_ptr->initial_y); @@ -498,8 +498,8 @@ bool pfsm_move_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) double rel_y = workspace_ptr->super_container.super_element.last_pointer_y - workspace_ptr->motion_y; - wlmtk_toplevel_set_position( - workspace_ptr->grabbed_toplevel_ptr, + wlmtk_window_set_position( + workspace_ptr->grabbed_window_ptr, workspace_ptr->initial_x + rel_x, workspace_ptr->initial_y + rel_y); @@ -513,19 +513,19 @@ bool pfsm_resize_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr) wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( fsm_ptr, wlmtk_workspace_t, fsm); - workspace_ptr->grabbed_toplevel_ptr = ud_ptr; + workspace_ptr->grabbed_window_ptr = ud_ptr; workspace_ptr->motion_x = workspace_ptr->super_container.super_element.last_pointer_x; workspace_ptr->motion_y = workspace_ptr->super_container.super_element.last_pointer_y; wlmtk_element_get_position( - wlmtk_toplevel_element(workspace_ptr->grabbed_toplevel_ptr), + wlmtk_window_element(workspace_ptr->grabbed_window_ptr), &workspace_ptr->initial_x, &workspace_ptr->initial_y); - wlmtk_toplevel_get_size( - workspace_ptr->grabbed_toplevel_ptr, + wlmtk_window_get_size( + workspace_ptr->grabbed_window_ptr, &workspace_ptr->initial_width, &workspace_ptr->initial_height); @@ -565,8 +565,8 @@ bool pfsm_resize_motion(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) if (right <= left) right = left + 1; } - wlmtk_toplevel_request_position_and_size( - workspace_ptr->grabbed_toplevel_ptr, + wlmtk_window_request_position_and_size( + workspace_ptr->grabbed_window_ptr, left, top, right - left, bottom - top); return true; @@ -578,7 +578,7 @@ bool pfsm_reset(wlmtk_fsm_t *fsm_ptr, __UNUSED__ void *ud_ptr) { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( fsm_ptr, wlmtk_workspace_t, fsm); - workspace_ptr->grabbed_toplevel_ptr = NULL; + workspace_ptr->grabbed_window_ptr = NULL; return true; } @@ -640,7 +640,7 @@ void test_create_destroy(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Verifies that mapping and unmapping toplevels works. */ +/** Verifies that mapping and unmapping windows works. */ void test_map_unmap(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -650,34 +650,34 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + wlmtk_window_t *window_ptr = wlmtk_window_create( NULL, &fake_content_ptr->content); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, toplevel_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_element(toplevel_ptr)->visible); - wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_toplevel_element(toplevel_ptr)->wlr_scene_node_ptr); + wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, fake_content_ptr->content.super_element.wlr_scene_node_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_toplevel_element(toplevel_ptr)->visible); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); - wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_toplevel_element(toplevel_ptr)->wlr_scene_node_ptr); + wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, fake_content_ptr->content.super_element.wlr_scene_node_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_toplevel_element(toplevel_ptr)->visible); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); - wlmtk_toplevel_destroy(toplevel_ptr); + wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } @@ -742,7 +742,7 @@ void test_button(bs_test_t *test_ptr) } /* ------------------------------------------------------------------------- */ -/** Tests moving a toplevel. */ +/** Tests moving a window. */ void test_move(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -751,20 +751,20 @@ void test_move(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + wlmtk_window_t *window_ptr = wlmtk_window_create( NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != toplevel_ptr); + BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); - // Starts a move for the toplevel. Will move it... - wlmtk_workspace_begin_toplevel_move(workspace_ptr, toplevel_ptr); + // Starts a move for the window. Will move it... + wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); // Releases the button. Should end the move. struct wlr_pointer_button_event wlr_pointer_button_event = { @@ -773,22 +773,22 @@ void test_move(bs_test_t *test_ptr) .time_msec = 44, }; wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); // More motion, no longer updates the position. wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); - wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); - wlmtk_toplevel_destroy(toplevel_ptr); + wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ -/** Tests moving a toplevel that unmaps during the move. */ +/** Tests moving a window that unmaps during the move. */ void test_unmap_during_move(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -797,42 +797,42 @@ void test_unmap_during_move(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + wlmtk_window_t *window_ptr = wlmtk_window_create( NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != toplevel_ptr); + BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); - // Starts a move for the toplevel. Will move it... - wlmtk_workspace_begin_toplevel_move(workspace_ptr, toplevel_ptr); + // Starts a move for the window. Will move it... + wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); - wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_toplevel_ptr); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); // More motion, no longer updates the position. wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); // More motion, no longer updates the position. wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); - wlmtk_toplevel_destroy(toplevel_ptr); + wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ -/** Tests resizing a toplevel. */ +/** Tests resizing a window. */ void test_resize(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -841,35 +841,35 @@ void test_resize(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create( + wlmtk_window_t *window_ptr = wlmtk_window_create( NULL, &fake_content_ptr->content); - BS_ASSERT(NULL != toplevel_ptr); - wlmtk_toplevel_request_position_and_size(toplevel_ptr, 0, 0, 40, 20); + BS_ASSERT(NULL != window_ptr); + wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); wlmtk_fake_content_commit(fake_content_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_toplevel(workspace_ptr, toplevel_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); int width, height; - wlmtk_toplevel_get_size(toplevel_ptr, &width, &height); + wlmtk_window_get_size(window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 40, width); BS_TEST_VERIFY_EQ(test_ptr, 20, height); - // Starts a resize for the toplevel. Will resize & move it... - wlmtk_workspace_begin_toplevel_resize( - workspace_ptr, toplevel_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); + // Starts a resize for the window. Will resize & move it... + wlmtk_workspace_begin_window_resize( + workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); fake_content_ptr->return_request_size = 1; // The serial. wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_toplevel_element(toplevel_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 37, fake_content_ptr->requested_width); BS_TEST_VERIFY_EQ(test_ptr, 16, fake_content_ptr->requested_height); // This updates for the given serial. wlmtk_fake_content_commit(fake_content_ptr); - wlmtk_toplevel_get_size(toplevel_ptr, &width, &height); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_toplevel_element(toplevel_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_toplevel_element(toplevel_ptr)->y); + wlmtk_window_get_size(window_ptr, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 39, width); BS_TEST_VERIFY_EQ(test_ptr, 18, height); @@ -880,16 +880,16 @@ void test_resize(bs_test_t *test_ptr) .time_msec = 44, }; wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_toplevel_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); - wlmtk_workspace_unmap_toplevel(workspace_ptr, toplevel_ptr); - wlmtk_toplevel_destroy(toplevel_ptr); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_window_destroy(window_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ -/** Tests toplevel activation. */ +/** Tests window activation. */ void test_activate(bs_test_t *test_ptr) { wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); @@ -898,34 +898,34 @@ void test_activate(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); - // Toplevel 1: from (0, 0) to (100, 100) - wlmtk_fake_toplevel_t *fw1_ptr = wlmtk_fake_toplevel_create(); + // Window 1: from (0, 0) to (100, 100) + wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_toplevel_set_position(fw1_ptr->toplevel_ptr, 0, 0); + wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); - // Toplevel 1 is mapped => it's activated. - wlmtk_workspace_map_toplevel(workspace_ptr, fw1_ptr->toplevel_ptr); + // Window 1 is mapped => it's activated. + wlmtk_workspace_map_window(workspace_ptr, fw1_ptr->window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); - // Toplevel 2: from (200, 0) to (300, 100). - // Toplevel 2 is mapped: Will get activated, and 1st one de-activated. - wlmtk_fake_toplevel_t *fw2_ptr = wlmtk_fake_toplevel_create(); + // Window 2: from (200, 0) to (300, 100). + // Window 2 is mapped: Will get activated, and 1st one de-activated. + wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); - wlmtk_toplevel_set_position(fw2_ptr->toplevel_ptr, 200, 0); + wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - wlmtk_workspace_map_toplevel(workspace_ptr, fw2_ptr->toplevel_ptr); + wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Pointer move, over toplevel 1. Nothing happens: We have click-to-focus. + // Pointer move, over window 1. Nothing happens: We have click-to-focus. BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_workspace_motion(workspace_ptr, 50, 50, 0)); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Click on toplevel 1: Gets activated. + // Click on window 1: Gets activated. struct wlr_pointer_button_event wlr_button_event = { .button = BTN_RIGHT, .state = WLR_BUTTON_PRESSED }; @@ -933,17 +933,17 @@ void test_activate(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - // Unmap toplevel 1. Now toplevel 2 gets activated. - wlmtk_workspace_unmap_toplevel(workspace_ptr, fw1_ptr->toplevel_ptr); + // Unmap window 1. Now window 2 gets activated. + wlmtk_workspace_unmap_window(workspace_ptr, fw1_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); - // Unmap the remaining toplevel 2. Nothing is activated. - wlmtk_workspace_unmap_toplevel(workspace_ptr, fw2_ptr->toplevel_ptr); + // Unmap the remaining window 2. Nothing is activated. + wlmtk_workspace_unmap_window(workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - wlmtk_fake_toplevel_destroy(fw2_ptr); - wlmtk_fake_toplevel_destroy(fw1_ptr); + wlmtk_fake_window_destroy(fw2_ptr); + wlmtk_fake_window_destroy(fw1_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index b36dff08..0859f892 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -21,7 +21,7 @@ #define __WLMTK_WORKSPACE_H__ #include "container.h" -#include "toplevel.h" +#include "window.h" #ifdef __cplusplus extern "C" { @@ -68,7 +68,7 @@ void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, const struct wlr_box *extents_ptr); /** - * Returns the extents of the workspace available for maximized toplevels. + * Returns the extents of the workspace available for maximized windows. * * @param workspace_ptr * @@ -78,22 +78,22 @@ struct wlr_box wlmtk_workspace_get_maximize_extents( wlmtk_workspace_t *workspace_ptr); /** - * Maps the toplevel: Adds it to the workspace container and makes it visible. + * Maps the window: Adds it to the workspace container and makes it visible. * * @param workspace_ptr - * @param toplevel_ptr + * @param window_ptr */ -void wlmtk_workspace_map_toplevel(wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr); +void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); /** - * Unmaps the toplevel: Sets it as invisible and removes it from the container. + * Unmaps the window: Sets it as invisible and removes it from the container. * * @param workspace_ptr - * @param toplevel_ptr + * @param window_ptr */ -void wlmtk_workspace_unmap_toplevel(wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr); +void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr); /** * Type conversion: Returns the @ref wlmtk_workspace_t from the container_ptr @@ -145,36 +145,36 @@ void wlmtk_workspace_button( const struct wlr_pointer_button_event *event_ptr); /** - * Initiates a 'move' for the toplevel. + * Initiates a 'move' for the window. * * @param workspace_ptr - * @param toplevel_ptr + * @param window_ptr */ -void wlmtk_workspace_begin_toplevel_move( +void wlmtk_workspace_begin_window_move( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr); + wlmtk_window_t *window_ptr); /** - * Initiates a 'resize' for the toplevel. + * Initiates a 'resize' for the window. * * @param workspace_ptr - * @param toplevel_ptr + * @param window_ptr * @param edges */ -void wlmtk_workspace_begin_toplevel_resize( +void wlmtk_workspace_begin_window_resize( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr, + wlmtk_window_t *window_ptr, uint32_t edges); -/** Acticates `toplevel_ptr`. Will de-activate an earlier toplevel. */ -void wlmtk_workspace_activate_toplevel( +/** Acticates `window_ptr`. Will de-activate an earlier window. */ +void wlmtk_workspace_activate_window( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr); + wlmtk_window_t *window_ptr); -/** Raises `toplevel_ptr`: Will show it atop all other toplevels. */ -void wlmtk_workspace_raise_toplevel( +/** Raises `window_ptr`: Will show it atop all other windows. */ +void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, - wlmtk_toplevel_t *toplevel_ptr); + wlmtk_window_t *window_ptr); /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; diff --git a/src/wlmtk_xdg_popup.c b/src/wlmtk_xdg_popup.c index f9c4ded6..a8d51f9e 100644 --- a/src/wlmtk_xdg_popup.c +++ b/src/wlmtk_xdg_popup.c @@ -27,7 +27,7 @@ /* ------------------------------------------------------------------------- */ void wlmtk_create_popup( __UNUSED__ struct wlr_xdg_popup *wlr_xdg_popup_ptr, - __UNUSED__ wlmtk_toplevel_t *toplevel_ptr) + __UNUSED__ wlmtk_window_t *window_ptr) { } diff --git a/src/wlmtk_xdg_popup.h b/src/wlmtk_xdg_popup.h index 4a7296e0..ad040758 100644 --- a/src/wlmtk_xdg_popup.h +++ b/src/wlmtk_xdg_popup.h @@ -33,11 +33,11 @@ extern "C" { * Creates a popup. * * @param wlr_xdg_popup_ptr - * @param toplevel_ptr + * @param window_ptr */ void wlmtk_create_popup( struct wlr_xdg_popup *wlr_xdg_popup_ptr, - wlmtk_toplevel_t *toplevel_ptr); + wlmtk_window_t *window_ptr); #ifdef __cplusplus } // extern "C" diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 0485b260..640a25f5 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -122,7 +122,7 @@ const wlmtk_content_vmt_t _wlmtk_xdg_toplevel_content_vmt = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_toplevel_t *wlmtk_toplevel_create_from_xdg_toplevel( +wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr) { @@ -130,14 +130,14 @@ wlmtk_toplevel_t *wlmtk_toplevel_create_from_xdg_toplevel( wlr_xdg_surface_ptr, server_ptr); if (NULL == content_ptr) return NULL; - wlmtk_toplevel_t *wlmtk_toplevel_ptr = wlmtk_toplevel_create( + wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( server_ptr->env_ptr, &content_ptr->super_content); - if (NULL == wlmtk_toplevel_ptr) { + if (NULL == wlmtk_window_ptr) { content_element_destroy(&content_ptr->super_content.super_element); return NULL; } - return wlmtk_toplevel_ptr; + return wlmtk_window_ptr; } /* == Local (static) methods =============================================== */ @@ -364,8 +364,8 @@ void handle_destroy(struct wl_listener *listener_ptr, { wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_content_t, destroy_listener); - // Destroy the toplevel -> also destroys the content. - wlmtk_toplevel_destroy(xdg_tl_content_ptr->super_content.toplevel_ptr); + // Destroy the window -> also destroys the content. + wlmtk_window_destroy(xdg_tl_content_ptr->super_content.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -406,9 +406,9 @@ void handle_surface_map( wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( wlmaker_server_get_current_workspace(xdg_tl_content_ptr->server_ptr)); - wlmtk_workspace_map_toplevel( + wlmtk_workspace_map_window( wlmtk_workspace_ptr, - xdg_tl_content_ptr->super_content.toplevel_ptr); + xdg_tl_content_ptr->super_content.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -425,11 +425,11 @@ void handle_surface_unmap( wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_content_t, surface_unmap_listener); - wlmtk_toplevel_t *toplevel_ptr = xdg_tl_content_ptr->super_content.toplevel_ptr; - wlmtk_workspace_unmap_toplevel( + wlmtk_window_t *window_ptr = xdg_tl_content_ptr->super_content.window_ptr; + wlmtk_workspace_unmap_window( wlmtk_workspace_from_container( - wlmtk_toplevel_element(toplevel_ptr)->parent_container_ptr), - toplevel_ptr); + wlmtk_window_element(window_ptr)->parent_container_ptr), + window_ptr); } /* ------------------------------------------------------------------------- */ @@ -470,9 +470,9 @@ void handle_toplevel_request_maximize( listener_ptr, wlmtk_xdg_toplevel_content_t, toplevel_request_maximize_listener); - wlmtk_toplevel_request_maximize( - xdg_tl_content_ptr->super_content.toplevel_ptr, - !wlmtk_toplevel_maximized(xdg_tl_content_ptr->super_content.toplevel_ptr)); + wlmtk_window_request_maximize( + xdg_tl_content_ptr->super_content.window_ptr, + !wlmtk_window_maximized(xdg_tl_content_ptr->super_content.window_ptr)); } /* ------------------------------------------------------------------------- */ @@ -490,7 +490,7 @@ void handle_toplevel_request_move( listener_ptr, wlmtk_xdg_toplevel_content_t, toplevel_request_move_listener); - wlmtk_toplevel_request_move(xdg_tl_content_ptr->super_content.toplevel_ptr); + wlmtk_window_request_move(xdg_tl_content_ptr->super_content.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -509,8 +509,8 @@ void handle_toplevel_request_resize( wlmtk_xdg_toplevel_content_t, toplevel_request_resize_listener); struct wlr_xdg_toplevel_resize_event *resize_event_ptr = data_ptr; - wlmtk_toplevel_request_resize( - xdg_tl_content_ptr->super_content.toplevel_ptr, + wlmtk_window_request_resize( + xdg_tl_content_ptr->super_content.window_ptr, resize_event_ptr->edges); } @@ -530,8 +530,8 @@ void handle_toplevel_set_title( wlmtk_xdg_toplevel_content_t, toplevel_set_title_listener); - wlmtk_toplevel_set_title( - xdg_tl_content_ptr->super_content.toplevel_ptr, + wlmtk_window_set_title( + xdg_tl_content_ptr->super_content.window_ptr, xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->title); } diff --git a/src/wlmtk_xdg_toplevel.h b/src/wlmtk_xdg_toplevel.h index 25bf7ccf..c4cae753 100644 --- a/src/wlmtk_xdg_toplevel.h +++ b/src/wlmtk_xdg_toplevel.h @@ -34,7 +34,7 @@ extern "C" { * * @return The window, or NULL on error. */ -wlmtk_toplevel_t *wlmtk_toplevel_create_from_xdg_toplevel( +wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr); diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 28ba389d..56d65cc7 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -271,8 +271,8 @@ void handle_decoration_request_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode, mode); - wlmtk_toplevel_set_server_side_decorated( - content_ptr->toplevel_ptr, + wlmtk_window_set_server_side_decorated( + content_ptr->window_ptr, mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } else { diff --git a/src/xdg_shell.c b/src/xdg_shell.c index cec5f6af..41631214 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -135,10 +135,10 @@ void handle_new_surface(struct wl_listener *listener_ptr, path_exe[rv] = '\0'; if (0 == strcmp(path_exe, "/usr/bin/foot") || 0 == strcmp(path_exe, "/opt/google/chrome/chrome")) { - wlmtk_toplevel_t *toplevel_ptr = wlmtk_toplevel_create_from_xdg_toplevel( + wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); - bs_log(BS_INFO, "XDG shell: Toolkit toplevel %p for surface %p", - toplevel_ptr, wlr_xdg_surface_ptr); + bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", + window_ptr, wlr_xdg_surface_ptr); break; } #endif // defined(ENABLE_TOOLKIT_PROTOTYPE) From b034a1aed2acd1849c891c7878ad82982381da8e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 27 Dec 2023 21:57:51 +0200 Subject: [PATCH 323/390] Moves wlmtk_content_t to wlmtk_surface_t. --- src/toolkit/surface.c | 230 ++++++++++++++++++++++--------- src/toolkit/surface.h | 74 +++++++++- src/toolkit/toolkit.md | 16 +++ src/toolkit/window.c | 126 ++++++++--------- src/toolkit/window.h | 18 +-- src/toolkit/workspace.c | 36 ++--- src/wlmtk_xdg_toplevel.c | 290 +++++++++++++++++++-------------------- src/xdg_decoration.c | 12 +- 8 files changed, 490 insertions(+), 312 deletions(-) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index fa5d7cea..8aa66e64 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -21,6 +21,7 @@ #include "surface.h" #include "element.h" +#include "gfxbuf.h" #include "util.h" #define WLR_USE_UNSTABLE @@ -53,10 +54,6 @@ static bool _wlmtk_surface_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); -static void handle_surface_commit( - struct wl_listener *listener_ptr, - __UNUSED__ void *data_ptr); - /* == Data ================================================================= */ /** Method table for the element's virtual methods. */ @@ -68,6 +65,8 @@ static const wlmtk_element_vmt_t surface_element_vmt = { .pointer_button = _wlmtk_surface_element_pointer_button, }; +void *wlmtk_surface_identifier_ptr = wlmtk_surface_init; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -87,27 +86,25 @@ bool wlmtk_surface_init( &surface_ptr->super_element, &surface_element_vmt); surface_ptr->wlr_surface_ptr = wlr_surface_ptr; - if (NULL != surface_ptr->wlr_surface_ptr) { - wlmtk_util_connect_listener_signal( - &surface_ptr->wlr_surface_ptr->events.commit, - &surface_ptr->surface_commit_listener, - handle_surface_commit); - } + surface_ptr->identifier_ptr = wlmtk_surface_identifier_ptr; return true; } /* ------------------------------------------------------------------------- */ void wlmtk_surface_fini(wlmtk_surface_t *surface_ptr) { - if (NULL != surface_ptr->wlr_surface_ptr) { - wl_list_remove(&surface_ptr->surface_commit_listener.link); - surface_ptr->wlr_surface_ptr= NULL; - } - wlmtk_element_fini(&surface_ptr->super_element); memset(surface_ptr, 0, sizeof(wlmtk_surface_t)); } +/* ------------------------------------------------------------------------- */ +void wlmtk_surface_set_window( + wlmtk_surface_t *surface_ptr, + wlmtk_window_t *window_ptr) +{ + surface_ptr->window_ptr = window_ptr; +} + /* ------------------------------------------------------------------------- */ wlmtk_surface_vmt_t wlmtk_surface_extend( wlmtk_surface_t *surface_ptr, @@ -118,6 +115,12 @@ wlmtk_surface_vmt_t wlmtk_surface_extend( if (NULL != surface_vmt_ptr->request_size) { surface_ptr->vmt.request_size = surface_vmt_ptr->request_size; } + if (NULL != surface_vmt_ptr->request_close) { + surface_ptr->vmt.request_close = surface_vmt_ptr->request_close; + } + if (NULL != surface_vmt_ptr->set_activated) { + surface_ptr->vmt.set_activated = surface_vmt_ptr->set_activated; + } return orig_vmt; } @@ -138,6 +141,30 @@ void wlmtk_surface_get_size( if (NULL != height_ptr) *height_ptr = surface_ptr->committed_height; } +/* ------------------------------------------------------------------------- */ +void wlmtk_surface_commit_size( + wlmtk_surface_t *surface_ptr, + uint32_t serial, + int width, + int height) +{ + if (surface_ptr->committed_width != width || + surface_ptr->committed_height != height) { + surface_ptr->committed_width = width; + surface_ptr->committed_height = height; + } + + if (NULL != surface_ptr->window_ptr) { + wlmtk_window_serial(surface_ptr->window_ptr, serial); + } + + if (NULL != surface_ptr->super_element.parent_container_ptr) { + wlmtk_container_update_layout( + surface_ptr->super_element.parent_container_ptr); + } + +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -160,12 +187,10 @@ void _wlmtk_surface_element_get_dimensions( wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( element_ptr, wlmtk_surface_t, super_element); - struct wlr_box box; - wlr_surface_get_extends(surface_ptr->wlr_surface_ptr, &box); - if (NULL != left_ptr) *left_ptr = box.x; - if (NULL != top_ptr) *top_ptr = box.y; - if (NULL != right_ptr) *right_ptr = box.width; - if (NULL != bottom_ptr) *bottom_ptr = box.height; + if (NULL != left_ptr) *left_ptr = 0; + if (NULL != top_ptr) *top_ptr = 0; + if (NULL != right_ptr) *right_ptr = surface_ptr->committed_width; + if (NULL != bottom_ptr) *bottom_ptr = surface_ptr->committed_height; } /* ------------------------------------------------------------------------- */ @@ -190,7 +215,14 @@ void _wlmtk_surface_element_get_pointer_area( element_ptr, wlmtk_surface_t, super_element); struct wlr_box box; - wlr_surface_get_extends(surface_ptr->wlr_surface_ptr, &box); + if (NULL == surface_ptr->wlr_surface_ptr) { + box.x = 0; + box.y = 0; + box.width = surface_ptr->committed_width; + box.height = surface_ptr->committed_height; + } else { + wlr_surface_get_extends(surface_ptr->wlr_surface_ptr, &box); + } if (NULL != left_ptr) *left_ptr = box.x; if (NULL != top_ptr) *top_ptr = box.y; @@ -276,7 +308,7 @@ bool _wlmtk_surface_element_pointer_motion( struct wlr_scene_surface *wlr_scene_surface_ptr = wlr_scene_surface_try_from_buffer(wlr_scene_buffer_ptr); if (NULL == wlr_scene_surface_ptr) { - return false; + return true; } BS_ASSERT(surface_ptr->wlr_surface_ptr == @@ -336,58 +368,42 @@ bool _wlmtk_surface_element_pointer_button( return false; } -/* ------------------------------------------------------------------------- */ -/** - * Commits the given dimensions for the surface. - * - * @param surface_ptr - * @param serial - * @param width - * @param height - */ -void _wlmtk_surface_commit_size( - wlmtk_surface_t *surface_ptr, - uint32_t serial, - int width, - int height) -{ - serial = serial; // FIXME - - surface_ptr->committed_width = width; - surface_ptr->committed_height = height; -} - -/* ------------------------------------------------------------------------- */ -/** - * Handler for the `commit` signal of the `struct wlr_surface`. - * - * @param listener_ptr - * @param data_ptr Points to the const struct wlr_surface. - */ -void handle_surface_commit( - struct wl_listener *listener_ptr, - __UNUSED__ void *data_ptr) -{ - wlmtk_surface_t *surface_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_surface_t, surface_commit_listener); - - _wlmtk_surface_commit_size( - surface_ptr, - 0, // FIXME: Where do we get the serial from? - surface_ptr->wlr_surface_ptr->current.width, - surface_ptr->wlr_surface_ptr->current.height); -} - /* == Fake surface methods ================================================= */ +static void _wlmtk_fake_surface_element_destroy( + wlmtk_element_t *element_ptr); +static struct wlr_scene_node *_wlmtk_fake_surface_element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); +static bool _wlmtk_fake_surface_element_pointer_button( + wlmtk_element_t *element_ptr, + const wlmtk_button_event_t *button_event_ptr); +static void _wlmtk_fake_surface_element_pointer_leave( + wlmtk_element_t *element_ptr); + +/** Extensions to the surface's super elements virtual methods. */ +static const wlmtk_element_vmt_t _wlmtk_fake_surface_element_vmt = { + .destroy = _wlmtk_fake_surface_element_destroy, + .create_scene_node = _wlmtk_fake_surface_element_create_scene_node, + .pointer_button = _wlmtk_fake_surface_element_pointer_button, + .pointer_leave = _wlmtk_fake_surface_element_pointer_leave, +}; + static uint32_t _wlmtk_fake_surface_request_size( wlmtk_surface_t *surface_ptr, int width, int height); +static void _wlmtk_fake_surface_request_close( + wlmtk_surface_t *surface_ptr); +static void _wlmtk_fake_surface_set_activated( + wlmtk_surface_t *surface_ptr, + bool activated); /** Virtual method table for the fake surface. */ static const wlmtk_surface_vmt_t _wlmtk_fake_surface_vmt = { .request_size = _wlmtk_fake_surface_request_size, + .request_close = _wlmtk_fake_surface_request_close, + .set_activated = _wlmtk_fake_surface_set_activated, }; /* ------------------------------------------------------------------------- */ @@ -399,6 +415,9 @@ wlmtk_fake_surface_t *wlmtk_fake_surface_create(void) wlmtk_surface_init(&fake_surface_ptr->surface, NULL, NULL); wlmtk_surface_extend(&fake_surface_ptr->surface, &_wlmtk_fake_surface_vmt); + wlmtk_element_extend( + &fake_surface_ptr->surface.super_element, + &_wlmtk_fake_surface_element_vmt); return fake_surface_ptr; } @@ -412,11 +431,70 @@ void wlmtk_fake_surface_destroy(wlmtk_fake_surface_t *fake_surface_ptr) /* ------------------------------------------------------------------------- */ void wlmtk_fake_surface_commit(wlmtk_fake_surface_t *fake_surface_ptr) { - _wlmtk_surface_commit_size( + wlmtk_surface_commit_size( &fake_surface_ptr->surface, fake_surface_ptr->serial, fake_surface_ptr->requested_width, fake_surface_ptr->requested_height); + + if (NULL != fake_surface_ptr->surface.super_element.wlr_scene_node_ptr) { + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + fake_surface_ptr->surface.committed_width, + fake_surface_ptr->surface.committed_height); + BS_ASSERT(NULL != wlr_buffer_ptr); + + struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_from_node( + fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); + BS_ASSERT(NULL != wlr_scene_buffer_ptr); + + wlr_scene_buffer_set_buffer(wlr_scene_buffer_ptr, wlr_buffer_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of the dtor, @ref wlmtk_element_vmt_t::destroy. */ +void _wlmtk_fake_surface_element_destroy( + wlmtk_element_t *element_ptr) +{ + wlmtk_fake_surface_t *fake_surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_surface_t, surface.super_element); + wlmtk_fake_surface_destroy(fake_surface_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Fake implementation of @ref wlmtk_element_vmt_t::create_scene_node. */ +struct wlr_scene_node *_wlmtk_fake_surface_element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_fake_surface_t *fake_surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_surface_t, surface.super_element); + + struct wlr_buffer *wlr_buffer_ptr = bs_gfxbuf_create_wlr_buffer( + fake_surface_ptr->surface.committed_width, + fake_surface_ptr->surface.committed_height); + BS_ASSERT(NULL != wlr_buffer_ptr); + + struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( + wlr_scene_tree_ptr, wlr_buffer_ptr); + return &wlr_scene_buffer_ptr->node; +} + +/* ------------------------------------------------------------------------- */ +/** Fake for @ref wlmtk_element_vmt_t::pointer_button. Returns true. */ +bool _wlmtk_fake_surface_element_pointer_button( + __UNUSED__ wlmtk_element_t *element_ptr, + __UNUSED__ const wlmtk_button_event_t *button_event_ptr) +{ + return true; +} + +/* ------------------------------------------------------------------------- */ +/** Fake for @ref wlmtk_element_vmt_t::pointer_leave. Does nothing. */ +void _wlmtk_fake_surface_element_pointer_leave( + __UNUSED__ wlmtk_element_t *element_ptr) +{ + // Nothing to do. } /* ------------------------------------------------------------------------- */ @@ -433,6 +511,26 @@ uint32_t _wlmtk_fake_surface_request_size( return fake_surface_ptr->serial; } +/* ------------------------------------------------------------------------- */ +/** Records that @ref wlmtk_surface_request_close was called. */ +void _wlmtk_fake_surface_request_close(wlmtk_surface_t *surface_ptr) +{ + wlmtk_fake_surface_t *fake_surface_ptr = BS_CONTAINER_OF( + surface_ptr, wlmtk_fake_surface_t, surface); + fake_surface_ptr->request_close_called = true; +} + +/* ------------------------------------------------------------------------- */ +/** Sets the surface's activated status. */ +void _wlmtk_fake_surface_set_activated( + wlmtk_surface_t *surface_ptr, + bool activated) +{ + wlmtk_fake_surface_t *fake_surface_ptr = BS_CONTAINER_OF( + surface_ptr, wlmtk_fake_surface_t, surface); + fake_surface_ptr->activated = activated; +} + /* == Unit tests =========================================================== */ static void test_init_fini(bs_test_t *test_ptr); diff --git a/src/toolkit/surface.h b/src/toolkit/surface.h index 31b0e7dc..884f6210 100644 --- a/src/toolkit/surface.h +++ b/src/toolkit/surface.h @@ -26,9 +26,12 @@ typedef struct _wlmtk_surface_t wlmtk_surface_t; /** Forward declaration: Virtual method table of the toolkit's WLR surface. */ typedef struct _wlmtk_surface_vmt_t wlmtk_surface_vmt_t; +/** Forward declaration: State of fake surface, for tests. */ +typedef struct _wlmtk_fake_surface_t wlmtk_fake_surface_t; #include "element.h" #include "env.h" +#include "window.h" /** Forward declaration. */ struct wlr_surface; @@ -43,10 +46,17 @@ struct _wlmtk_surface_vmt_t { uint32_t (*request_size)(wlmtk_surface_t *surface_ptr, int width, int height); + /** Abstract: Requests the surface to close. */ + void (*request_close)(wlmtk_surface_t *surface_ptr); + /** Abstract: Sets whether the surface is activated (keyboard focus). */ + void (*set_activated)(wlmtk_surface_t *surface_ptr, bool activated); }; /** State of a `struct wlr_surface`, encapsuled for toolkit. */ struct _wlmtk_surface_t { + /** Temporary: Identifier, to disambiguate from XDG nodes. */ + void *identifier_ptr; + /** Super class of the surface: An element. */ wlmtk_element_t super_element; /** Virtual method table of the super element before extending it. */ @@ -55,18 +65,27 @@ struct _wlmtk_surface_t { /** The surface's virtual method table. */ wlmtk_surface_vmt_t vmt; + /** + * The window this surface belongs to. Will be set when creating + * the window. + */ + wlmtk_window_t *window_ptr; /** The `struct wlr_surface` wrapped. */ struct wlr_surface *wlr_surface_ptr; - /** Listener for the `commit` signal of the `wlr_surface_ptr`. */ - struct wl_listener surface_commit_listener; - /** Committed width of the surface, in pixels. */ int committed_width; /** Committed height of the surface, in pixels. */ int committed_height; }; +/** + * Identifying pointer: Value unique to wlmtk_surface. + * + * TODO(kaeser@gubbe.ch): Remove, once migrated to toolkit. + */ +extern void *wlmtk_surface_identifier_ptr; + /** * Initializes the surface. * @@ -88,6 +107,18 @@ bool wlmtk_surface_init( */ void wlmtk_surface_fini(wlmtk_surface_t *surface_ptr); +/** + * Sets the window for the surface. + * + * Private: Should only be called by Window ctor (a friend). + * + * @param surface_ptr + * @param window_ptr + */ +void wlmtk_surface_set_window( + wlmtk_surface_t *surface_ptr, + wlmtk_window_t *window_ptr); + /** * Extends the surface's virtual methods. * @@ -126,6 +157,20 @@ static inline uint32_t wlmtk_surface_request_size( return surface_ptr->vmt.request_size(surface_ptr, width, height); } +/** Wraps to @ref wlmtk_surface_vmt_t::request_close. */ +static inline void wlmtk_surface_request_close(wlmtk_surface_t *surface_ptr) +{ + surface_ptr->vmt.request_close(surface_ptr); +} + +/** Wraps to @ref wlmtk_surface_vmt_t::set_activated. */ +static inline void wlmtk_surface_set_activated( + wlmtk_surface_t *surface_ptr, + bool activated) +{ + surface_ptr->vmt.set_activated(surface_ptr, activated); +} + /** * Returns committed size of the surface. * @@ -138,11 +183,25 @@ void wlmtk_surface_get_size( int *width_ptr, int *height_ptr); +/** + * Commits the given dimensions for the surface. + * + * @param surface_ptr + * @param serial + * @param width + * @param height + */ +void wlmtk_surface_commit_size( + wlmtk_surface_t *surface_ptr, + uint32_t serial, + int width, + int height); + /** Unit test cases. */ extern const bs_test_case_t wlmtk_surface_test_cases[]; /** Fake surface, useful for unit test. */ -typedef struct { +struct _wlmtk_fake_surface_t { /** Superclass: surface. */ wlmtk_surface_t surface; @@ -152,7 +211,12 @@ typedef struct { int requested_width; /** `height` argument of last @ref wlmtk_surface_request_size call. */ int requested_height; -} wlmtk_fake_surface_t; + + /** Whether @ref wlmtk_surface_request_close was called. */ + bool request_close_called; + /** Argument of last @ref wlmtk_surface_set_activated call. */ + bool activated; +}; /** Ctor for the fake surface.*/ wlmtk_fake_surface_t *wlmtk_fake_surface_create(void); diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 46906daf..3fd32146 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -99,6 +99,22 @@ class Box { } Container <|-- Box +abstract class Surface { + Element super_element + + Surface popups[] +} + + +class Toplevel { + Surface super_surface; + + request_close() + set_activated() +} + + + abstract class Content { Element super_element diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 41787c64..0b58d7d8 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -51,20 +51,20 @@ struct _wlmtk_window_vmt_t { int x, int y, int width, int height); }; -/** Pending positional updates for @ref wlmtk_window_t::content_ptr. */ +/** Pending positional updates for @ref wlmtk_window_t::surface_ptr. */ typedef struct { /** Node within @ref wlmtk_window_t::pending_updates. */ bs_dllist_node_t dlnode; /** Serial of the update. */ uint32_t serial; - /** Pending X position of the content. */ + /** Pending X position of the surface. */ int x; - /** Pending Y position of the content. */ + /** Pending Y position of the surface. */ int y; - /** Content's width that is to be committed at serial. */ - unsigned width; - /** Content's hehight that is to be committed at serial. */ - unsigned height; + /** Surface's width that is to be committed at serial. */ + int width; + /** Surface's hehight that is to be committed at serial. */ + int height; } wlmtk_pending_update_t; /** State of the window. */ @@ -79,11 +79,11 @@ struct _wlmtk_window_t { /** Virtual method table. */ wlmtk_window_vmt_t vmt; - /** Box: In `super_bordered`, holds content, title bar and resizebar. */ + /** Box: In `super_bordered`, holds surface, title bar and resizebar. */ wlmtk_box_t box; - /** Content of this window. */ - wlmtk_content_t *content_ptr; + /** Surface of this window. */ + wlmtk_surface_t *surface_ptr; /** Titlebar. */ wlmtk_titlebar_t *titlebar_ptr; /** Resizebar. */ @@ -123,7 +123,7 @@ typedef struct { static bool _wlmtk_window_init( wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); + wlmtk_surface_t *surface_ptr); static void _wlmtk_window_fini(wlmtk_window_t *window_ptr); static wlmtk_window_vmt_t _wlmtk_window_extend( wlmtk_window_t *window_ptr, @@ -209,7 +209,7 @@ static const wlmtk_resizebar_style_t resizebar_style = { .margin_style = { .width = 0, .color = 0xff000000 }, }; -/** Style of the margin between title, content and resizebar. */ +/** Style of the margin between title, surface and resizebar. */ static const wlmtk_margin_style_t margin_style = { .width = 1, .color = 0xff000000, @@ -226,12 +226,12 @@ static const wlmtk_margin_style_t border_style = { /* ------------------------------------------------------------------------- */ wlmtk_window_t *wlmtk_window_create( wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) + wlmtk_surface_t *surface_ptr) { wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!_wlmtk_window_init(window_ptr, env_ptr, content_ptr)) { + if (!_wlmtk_window_init(window_ptr, env_ptr, surface_ptr)) { wlmtk_window_destroy(window_ptr); return NULL; } @@ -425,7 +425,7 @@ void wlmtk_window_get_size( int *height_ptr) { // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); + wlmtk_surface_get_size(window_ptr->surface_ptr, width_ptr, height_ptr); if (NULL != window_ptr->titlebar_ptr) { *height_ptr += titlebar_style.height + margin_style.width; @@ -445,13 +445,13 @@ void wlmtk_window_request_size( int height) { // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_content_request_size(window_ptr->content_ptr, width, height); + wlmtk_surface_request_size(window_ptr->surface_ptr, width, height); - // TODO(kaeser@gubbe.ch): For client content (eg. a wlr_surface), setting + // TODO(kaeser@gubbe.ch): For client surface (eg. a wlr_surface), setting // the size is an asynchronous operation and should be handled as such. // Meaning: In example of resizing at the top-left corner, we'll want to - // request the content to adjust size, but wait with adjusting the - // content position until the size adjustment is applied. This implies we + // request the surface to adjust size, but wait with adjusting the + // surface position until the size adjustment is applied. This implies we // may need to combine the request_size and set_position methods for window. } @@ -505,11 +505,11 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) if (0 < delta) break; if (pending_update_ptr->serial == serial) { - if (window_ptr->content_ptr->committed_width != + if (window_ptr->surface_ptr->committed_width != pending_update_ptr->width) { bs_log(BS_ERROR, "FIXME: width mismatch!"); } - if (window_ptr->content_ptr->committed_height != + if (window_ptr->surface_ptr->committed_height != pending_update_ptr->height) { bs_log(BS_ERROR, "FIXME: height mismatch!"); } @@ -531,14 +531,14 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) * * @param window_ptr * @param env_ptr - * @param content_ptr + * @param surface_ptr * * @return true on success. */ bool _wlmtk_window_init( wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) + wlmtk_surface_t *surface_ptr) { BS_ASSERT(NULL != window_ptr); memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); @@ -575,10 +575,10 @@ bool _wlmtk_window_init( wlmtk_box_add_element_front( &window_ptr->box, - wlmtk_content_element(content_ptr)); - window_ptr->content_ptr = content_ptr; - wlmtk_content_set_window(content_ptr, window_ptr); - wlmtk_element_set_visible(wlmtk_content_element(content_ptr), true); + wlmtk_surface_element(surface_ptr)); + window_ptr->surface_ptr = surface_ptr; + wlmtk_surface_set_window(surface_ptr, window_ptr); + wlmtk_element_set_visible(wlmtk_surface_element(surface_ptr), true); return true; } @@ -592,16 +592,16 @@ void _wlmtk_window_fini(wlmtk_window_t *window_ptr) { wlmtk_window_set_server_side_decorated(window_ptr, false); - if (NULL != window_ptr->content_ptr) { + if (NULL != window_ptr->surface_ptr) { wlmtk_box_remove_element( &window_ptr->box, - wlmtk_content_element(window_ptr->content_ptr)); + wlmtk_surface_element(window_ptr->surface_ptr)); wlmtk_element_set_visible( - wlmtk_content_element(window_ptr->content_ptr), false); - wlmtk_content_set_window(window_ptr->content_ptr, NULL); + wlmtk_surface_element(window_ptr->surface_ptr), false); + wlmtk_surface_set_window(window_ptr->surface_ptr, NULL); - wlmtk_element_destroy(wlmtk_content_element(window_ptr->content_ptr)); - window_ptr->content_ptr = NULL; + wlmtk_element_destroy(wlmtk_surface_element(window_ptr->surface_ptr)); + window_ptr->surface_ptr = NULL; } if (NULL != window_ptr->title_ptr) { @@ -686,9 +686,9 @@ void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) window_ptr->orig_super_container_vmt.update_layout(container_ptr); - if (NULL != window_ptr->content_ptr) { + if (NULL != window_ptr->surface_ptr) { int width; - wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); + wlmtk_surface_get_size(window_ptr->surface_ptr, &width, NULL); if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); } @@ -704,7 +704,7 @@ void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { - wlmtk_content_set_activated(window_ptr->content_ptr, activated); + wlmtk_surface_set_activated(window_ptr->surface_ptr, activated); if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); } @@ -714,7 +714,7 @@ void _wlmtk_window_set_activated( /** Default implementation of @ref wlmtk_window_request_close. */ void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) { - wlmtk_content_request_close(window_ptr->content_ptr); + wlmtk_surface_request_close(window_ptr->surface_ptr); } /* ------------------------------------------------------------------------- */ @@ -761,8 +761,8 @@ void _wlmtk_window_request_position_and_size( height = BS_MAX(0, height); width = BS_MAX(0, width); - uint32_t serial = wlmtk_content_request_size( - window_ptr->content_ptr, width, height); + uint32_t serial = wlmtk_surface_request_size( + window_ptr->surface_ptr, width, height); wlmtk_pending_update_t *pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); @@ -865,9 +865,9 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) 1, sizeof(wlmtk_fake_window_state_t)); if (NULL == fake_window_state_ptr) return NULL; - fake_window_state_ptr->fake_window.fake_content_ptr = - wlmtk_fake_content_create(); - if (NULL == fake_window_state_ptr->fake_window.fake_content_ptr) { + fake_window_state_ptr->fake_window.fake_surface_ptr = + wlmtk_fake_surface_create(); + if (NULL == fake_window_state_ptr->fake_window.fake_surface_ptr) { wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); return NULL; } @@ -875,7 +875,7 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) if (!_wlmtk_window_init( &fake_window_state_ptr->window, NULL, - &fake_window_state_ptr->fake_window.fake_content_ptr->content)) { + &fake_window_state_ptr->fake_window.fake_surface_ptr->surface)) { wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); return NULL; } @@ -991,12 +991,12 @@ const bs_test_case_t wlmtk_window_test_cases[] = { /** Tests setup and teardown. */ void test_create_destroy(bs_test_t *test_ptr) { - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, window_ptr, - fake_content_ptr->content.window_ptr); + fake_surface_ptr->surface.window_ptr); wlmtk_window_destroy(window_ptr); } @@ -1005,9 +1005,9 @@ void test_create_destroy(bs_test_t *test_ptr) /** Tests title. */ void test_set_title(bs_test_t *test_ptr) { - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); wlmtk_window_set_title(window_ptr, "Title"); BS_TEST_VERIFY_STREQ( @@ -1028,12 +1028,12 @@ void test_set_title(bs_test_t *test_ptr) /** Tests activation. */ void test_request_close(bs_test_t *test_ptr) { - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); wlmtk_window_request_close(window_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->request_close_called); wlmtk_window_destroy(window_ptr); } @@ -1042,15 +1042,15 @@ void test_request_close(bs_test_t *test_ptr) /** Tests activation. */ void test_set_activated(bs_test_t *test_ptr) { - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); wlmtk_window_set_activated(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); wlmtk_window_set_activated(window_ptr, false); - BS_TEST_VERIFY_FALSE(test_ptr, fake_content_ptr->activated); + BS_TEST_VERIFY_FALSE(test_ptr, fake_surface_ptr->activated); wlmtk_window_destroy(window_ptr); } @@ -1059,9 +1059,9 @@ void test_set_activated(bs_test_t *test_ptr) /** Tests enabling and disabling server-side decoration. */ void test_server_side_decorated(bs_test_t *test_ptr) { - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); @@ -1088,16 +1088,16 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_workspace_set_extents(workspace_ptr, &extents); BS_ASSERT(NULL != workspace_ptr); - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_ASSERT(NULL != window_ptr); // Window must be mapped to get maximized: Need workspace dimensions. wlmtk_workspace_map_window(workspace_ptr, window_ptr); // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); - wlmtk_fake_content_commit(fake_content_ptr); + wlmtk_fake_surface_commit(fake_surface_ptr); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); @@ -1123,7 +1123,7 @@ void test_maximize(bs_test_t *test_ptr) // Maximize. wlmtk_window_request_maximize(window_ptr, true); - wlmtk_fake_content_commit(fake_content_ptr); + wlmtk_fake_surface_commit(fake_surface_ptr); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); @@ -1132,11 +1132,11 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); // A second commit: should not overwrite the organic dimension. - wlmtk_fake_content_commit(fake_content_ptr); + wlmtk_fake_surface_commit(fake_surface_ptr); // Unmaximize. Restore earlier organic size and position. wlmtk_window_request_maximize(window_ptr, false); - wlmtk_fake_content_commit(fake_content_ptr); + wlmtk_fake_surface_commit(fake_surface_ptr); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index fb99b4cd..8a1ae74a 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -27,9 +27,9 @@ typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; #include "bordered.h" #include "box.h" -#include "content.h" #include "element.h" #include "resizebar.h" +#include "surface.h" #include "titlebar.h" #ifdef __cplusplus @@ -37,17 +37,17 @@ extern "C" { #endif // __cplusplus /** - * Creates a window for the given content. + * Creates a window for the given surface. * * @param env_ptr - * @param content_ptr Will take ownership of content_ptr. + * @param surface_ptr Will take ownership of surface_ptr. * * @return Pointer to the window state, or NULL on error. Must be free'd * by calling @ref wlmtk_window_destroy. */ wlmtk_window_t *wlmtk_window_create( wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); + wlmtk_surface_t *surface_ptr); /** * Destroys the window. @@ -147,7 +147,7 @@ void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); * size for the window. @ref wlmtk_window_t::organic_size will not be updated. * * This may be implemented as an asynchronous operation. Maximization will be - * applied once the size change has been committed by the content. + * applied once the size change has been committed by the surface. * * @param window_ptr * @param maximized @@ -254,8 +254,8 @@ void wlmtk_window_request_position_and_size( * Updates the window state to what was requested at the `serial`. * * Used for example when resizing a window from the top or left edges. In that - * case, @ref wlmtk_content_request_size may be asynchronous and returns a - * serial. The content is expected to call @ref wlmtk_window_serial with the + * case, @ref wlmtk_surface_request_size may be asynchronous and returns a + * serial. The surface is expected to call @ref wlmtk_window_serial with the * returned serial when the size is committed. * Only then, the corresponding positional update on the top/left edges are * supposed to be applied. @@ -276,8 +276,8 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); typedef struct { /** Window state. */ wlmtk_window_t *window_ptr; - /** Fake content, to manipulate the fake window's content. */ - wlmtk_fake_content_t *fake_content_ptr; + /** Fake surface, to manipulate the fake window's surface. */ + wlmtk_fake_surface_t *fake_surface_ptr; /** Argument to last @ref wlmtk_window_set_activated call. */ bool activated; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 00c29529..f85700dd 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -649,9 +649,9 @@ void test_map_unmap(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -663,7 +663,7 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ( test_ptr, NULL, - fake_content_ptr->content.super_element.wlr_scene_node_ptr); + fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); @@ -674,7 +674,7 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, NULL, - fake_content_ptr->content.super_element.wlr_scene_node_ptr); + fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_window_destroy(window_ptr); @@ -750,9 +750,9 @@ void test_move(bs_test_t *test_ptr) wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -796,9 +796,9 @@ void test_unmap_during_move(bs_test_t *test_ptr) wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -840,12 +840,12 @@ void test_resize(bs_test_t *test_ptr) wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); - wlmtk_fake_content_t *fake_content_ptr = wlmtk_fake_content_create(); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_content_ptr->content); + NULL, &fake_surface_ptr->surface); BS_ASSERT(NULL != window_ptr); wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); - wlmtk_fake_content_commit(fake_content_ptr); + wlmtk_fake_surface_commit(fake_surface_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); wlmtk_workspace_map_window(workspace_ptr, window_ptr); @@ -859,14 +859,14 @@ void test_resize(bs_test_t *test_ptr) // Starts a resize for the window. Will resize & move it... wlmtk_workspace_begin_window_resize( workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); - fake_content_ptr->return_request_size = 1; // The serial. + fake_surface_ptr->serial = 1; // The serial. wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); - BS_TEST_VERIFY_EQ(test_ptr, 37, fake_content_ptr->requested_width); - BS_TEST_VERIFY_EQ(test_ptr, 16, fake_content_ptr->requested_height); + BS_TEST_VERIFY_EQ(test_ptr, 37, fake_surface_ptr->requested_width); + BS_TEST_VERIFY_EQ(test_ptr, 16, fake_surface_ptr->requested_height); // This updates for the given serial. - wlmtk_fake_content_commit(fake_content_ptr); + wlmtk_fake_surface_commit(fake_surface_ptr); wlmtk_window_get_size(window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); @@ -900,7 +900,8 @@ void test_activate(bs_test_t *test_ptr) // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); - wlmtk_content_commit_size(&fw1_ptr->fake_content_ptr->content, 0, 100, 100); + wlmtk_surface_request_size(&fw1_ptr->fake_surface_ptr->surface, 100, 100); + wlmtk_fake_surface_commit(fw1_ptr->fake_surface_ptr); wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); @@ -911,7 +912,8 @@ void test_activate(bs_test_t *test_ptr) // Window 2: from (200, 0) to (300, 100). // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); - wlmtk_content_commit_size(&fw2_ptr->fake_content_ptr->content, 0, 100, 100); + wlmtk_surface_request_size(&fw2_ptr->fake_surface_ptr->surface, 100, 100); + wlmtk_fake_surface_commit(fw2_ptr->fake_surface_ptr); wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 640a25f5..993b809b 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -25,7 +25,7 @@ /** State of the content for an XDG toplevel surface. */ typedef struct { /** Super class. */ - wlmtk_content_t super_content; + wlmtk_surface_t super_surface; /** Back-link to server. */ wlmaker_server_t *server_ptr; @@ -54,13 +54,13 @@ typedef struct { struct wl_listener toplevel_request_resize_listener; /** Listener for the `set_title` signal of the `wlr_xdg_toplevel`. */ struct wl_listener toplevel_set_title_listener; -} wlmtk_xdg_toplevel_content_t; +} wlmtk_xdg_toplevel_surface_t; -static wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( +static wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr); -static void xdg_toplevel_content_destroy( - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr); +static void xdg_toplevel_surface_destroy( + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr); static void handle_destroy( struct wl_listener *listener_ptr, @@ -90,33 +90,33 @@ static void handle_toplevel_set_title( struct wl_listener *listener_ptr, void *data_ptr); -static void content_element_destroy(wlmtk_element_t *element_ptr); -static struct wlr_scene_node *content_element_create_scene_node( +static void surface_element_destroy(wlmtk_element_t *element_ptr); +static struct wlr_scene_node *surface_element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void content_request_close( - wlmtk_content_t *content_ptr); -static uint32_t content_request_size( - wlmtk_content_t *content_ptr, +static void surface_request_close( + wlmtk_surface_t *surface_ptr); +static uint32_t surface_request_size( + wlmtk_surface_t *surface_ptr, int width, int height); -static void content_set_activated( - wlmtk_content_t *content_ptr, +static void surface_set_activated( + wlmtk_surface_t *surface_ptr, bool activated); /* == Data ================================================================= */ -/** Virtual methods for XDG toplevel content, for the Element superclass. */ +/** Virtual methods for XDG toplevel surface, for the Element superclass. */ const wlmtk_element_vmt_t _wlmtk_xdg_toplevel_element_vmt = { - .destroy = content_element_destroy, - .create_scene_node = content_element_create_scene_node, + .destroy = surface_element_destroy, + .create_scene_node = surface_element_create_scene_node, }; -/** Virtual methods for XDG toplevel content, for the Content superclass. */ -const wlmtk_content_vmt_t _wlmtk_xdg_toplevel_content_vmt = { - .request_close = content_request_close, - .request_size = content_request_size, - .set_activated = content_set_activated, +/** Virtual methods for XDG toplevel surface, for the Surface superclass. */ +const wlmtk_surface_vmt_t _wlmtk_xdg_toplevel_surface_vmt = { + .request_close = surface_request_close, + .request_size = surface_request_size, + .set_activated = surface_set_activated, }; /* == Exported methods ===================================================== */ @@ -126,14 +126,14 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr) { - wlmtk_xdg_toplevel_content_t *content_ptr = xdg_toplevel_content_create( + wlmtk_xdg_toplevel_surface_t *surface_ptr = xdg_toplevel_surface_create( wlr_xdg_surface_ptr, server_ptr); - if (NULL == content_ptr) return NULL; + if (NULL == surface_ptr) return NULL; wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( - server_ptr->env_ptr, &content_ptr->super_content); + server_ptr->env_ptr, &surface_ptr->super_surface); if (NULL == wlmtk_window_ptr) { - content_element_destroy(&content_ptr->super_content.super_element); + surface_element_destroy(&surface_ptr->super_surface.super_element); return NULL; } @@ -143,191 +143,189 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_xdg_toplevel_content_t *xdg_toplevel_content_create( +wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( struct wlr_xdg_surface *wlr_xdg_surface_ptr, wlmaker_server_t *server_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = logged_calloc( - 1, sizeof(wlmtk_xdg_toplevel_content_t)); - if (NULL == xdg_tl_content_ptr) return NULL; - - if (!wlmtk_content_init(&xdg_tl_content_ptr->super_content, - server_ptr->env_ptr)) { - xdg_toplevel_content_destroy(xdg_tl_content_ptr); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = logged_calloc( + 1, sizeof(wlmtk_xdg_toplevel_surface_t)); + if (NULL == xdg_tl_surface_ptr) return NULL; + + if (!wlmtk_surface_init( + &xdg_tl_surface_ptr->super_surface, + wlr_xdg_surface_ptr->surface, + server_ptr->env_ptr)) { + xdg_toplevel_surface_destroy(xdg_tl_surface_ptr); return NULL; } wlmtk_element_extend( - &xdg_tl_content_ptr->super_content.super_element, + &xdg_tl_surface_ptr->super_surface.super_element, &_wlmtk_xdg_toplevel_element_vmt); - wlmtk_content_extend( - &xdg_tl_content_ptr->super_content, - &_wlmtk_xdg_toplevel_content_vmt); - xdg_tl_content_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; - xdg_tl_content_ptr->server_ptr = server_ptr; + wlmtk_surface_extend( + &xdg_tl_surface_ptr->super_surface, + &_wlmtk_xdg_toplevel_surface_vmt); + xdg_tl_surface_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; + xdg_tl_surface_ptr->server_ptr = server_ptr; wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->events.destroy, - &xdg_tl_content_ptr->destroy_listener, + &xdg_tl_surface_ptr->destroy_listener, handle_destroy); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->events.new_popup, - &xdg_tl_content_ptr->new_popup_listener, + &xdg_tl_surface_ptr->new_popup_listener, handle_new_popup); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.map, - &xdg_tl_content_ptr->surface_map_listener, + &xdg_tl_surface_ptr->surface_map_listener, handle_surface_map); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.unmap, - &xdg_tl_content_ptr->surface_unmap_listener, + &xdg_tl_surface_ptr->surface_unmap_listener, handle_surface_unmap); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->surface->events.commit, - &xdg_tl_content_ptr->surface_commit_listener, + &xdg_tl_surface_ptr->surface_commit_listener, handle_surface_commit); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_maximize, - &xdg_tl_content_ptr->toplevel_request_maximize_listener, + &xdg_tl_surface_ptr->toplevel_request_maximize_listener, handle_toplevel_request_maximize); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_move, - &xdg_tl_content_ptr->toplevel_request_move_listener, + &xdg_tl_surface_ptr->toplevel_request_move_listener, handle_toplevel_request_move); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_resize, - &xdg_tl_content_ptr->toplevel_request_resize_listener, + &xdg_tl_surface_ptr->toplevel_request_resize_listener, handle_toplevel_request_resize); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.set_title, - &xdg_tl_content_ptr->toplevel_set_title_listener, + &xdg_tl_surface_ptr->toplevel_set_title_listener, handle_toplevel_set_title); - xdg_tl_content_ptr->wlr_xdg_surface_ptr->data = - &xdg_tl_content_ptr->super_content; - - // FIXME - xdg_tl_content_ptr->super_content.wlr_surface_ptr = - xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface; + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->data = + &xdg_tl_surface_ptr->super_surface; - return xdg_tl_content_ptr; + return xdg_tl_surface_ptr; } /* ------------------------------------------------------------------------- */ -void xdg_toplevel_content_destroy( - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr) +void xdg_toplevel_surface_destroy( + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr) { wl_list_remove( - &xdg_tl_content_ptr->toplevel_set_title_listener.link); - wl_list_remove(&xdg_tl_content_ptr->toplevel_request_resize_listener.link); - wl_list_remove(&xdg_tl_content_ptr->toplevel_request_move_listener.link); - wl_list_remove(&xdg_tl_content_ptr->toplevel_request_maximize_listener.link); - - wl_list_remove(&xdg_tl_content_ptr->surface_commit_listener.link); - wl_list_remove(&xdg_tl_content_ptr->surface_map_listener.link); - wl_list_remove(&xdg_tl_content_ptr->surface_unmap_listener.link); - wl_list_remove(&xdg_tl_content_ptr->new_popup_listener.link); - wl_list_remove(&xdg_tl_content_ptr->destroy_listener.link); - - wlmtk_content_fini(&xdg_tl_content_ptr->super_content); - free(xdg_tl_content_ptr); + &xdg_tl_surface_ptr->toplevel_set_title_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_resize_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_move_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_maximize_listener.link); + + wl_list_remove(&xdg_tl_surface_ptr->surface_commit_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->surface_map_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->surface_unmap_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->new_popup_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->destroy_listener.link); + + wlmtk_surface_fini(&xdg_tl_surface_ptr->super_surface); + free(xdg_tl_surface_ptr); } /* ------------------------------------------------------------------------- */ /** - * Destructor. Wraps to @ref wlmtk_xdg_toplevel_content_destroy. + * Destructor. Wraps to @ref wlmtk_xdg_toplevel_surface_destroy. * - * @param content_ptr + * @param surface_ptr */ -void content_element_destroy(wlmtk_element_t *element_ptr) +void surface_element_destroy(wlmtk_element_t *element_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_xdg_toplevel_content_t, - super_content.super_element); - xdg_toplevel_content_destroy(xdg_tl_content_ptr); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_xdg_toplevel_surface_t, + super_surface.super_element); + xdg_toplevel_surface_destroy(xdg_tl_surface_ptr); } /* ------------------------------------------------------------------------- */ /** * Creates the wlroots scene graph API node, attached to `wlr_scene_tree_ptr`. * - * @param content_ptr + * @param surface_ptr * @param wlr_scene_tree_ptr * - * @return Scene graph API node that represents the content. + * @return Scene graph API node that represents the surface. */ -struct wlr_scene_node *content_element_create_scene_node( +struct wlr_scene_node *surface_element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_xdg_toplevel_content_t, - super_content.super_element); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_xdg_toplevel_surface_t, + super_surface.super_element); struct wlr_scene_tree *surface_wlr_scene_tree_ptr = wlr_scene_xdg_surface_create( wlr_scene_tree_ptr, - xdg_tl_content_ptr->wlr_xdg_surface_ptr); + xdg_tl_surface_ptr->wlr_xdg_surface_ptr); return &surface_wlr_scene_tree_ptr->node; } /* ------------------------------------------------------------------------- */ /** - * Requests the content to close: Sends a 'close' message to the toplevel. + * Requests the surface to close: Sends a 'close' message to the toplevel. * - * @param content_ptr + * @param surface_ptr */ -void content_request_close(wlmtk_content_t *content_ptr) +void surface_request_close(wlmtk_surface_t *surface_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + surface_ptr, wlmtk_xdg_toplevel_surface_t, super_surface); wlr_xdg_toplevel_send_close( - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel); + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel); } /* ------------------------------------------------------------------------- */ /** * Sets the dimensions of the element in pixels. * - * @param content_ptr - * @param width Width of content. - * @param height Height of content. + * @param surface_ptr + * @param width Width of surface. + * @param height Height of surface. * * @return The serial. */ -uint32_t content_request_size( - wlmtk_content_t *content_ptr, +uint32_t surface_request_size( + wlmtk_surface_t *surface_ptr, int width, int height) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + surface_ptr, wlmtk_xdg_toplevel_surface_t, super_surface); return wlr_xdg_toplevel_set_size( - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, width, height); + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel, width, height); } /* ------------------------------------------------------------------------- */ /** * Sets the keyboard activation status for the surface. * - * @param content_ptr + * @param surface_ptr * @param activated */ -void content_set_activated( - wlmtk_content_t *content_ptr, +void surface_set_activated( + wlmtk_surface_t *surface_ptr, bool activated) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_xdg_toplevel_content_t, super_content); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + surface_ptr, wlmtk_xdg_toplevel_surface_t, super_surface); // Early return, if nothing to be done. - if (xdg_tl_content_ptr->activated == activated) return; + if (xdg_tl_surface_ptr->activated == activated) return; struct wlr_seat *wlr_seat_ptr = - xdg_tl_content_ptr->server_ptr->wlr_seat_ptr; + xdg_tl_surface_ptr->server_ptr->wlr_seat_ptr; wlr_xdg_toplevel_set_activated( - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel, activated); + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel, activated); if (activated) { struct wlr_keyboard *wlr_keyboard_ptr = wlr_seat_get_keyboard( @@ -335,21 +333,21 @@ void content_set_activated( if (NULL != wlr_keyboard_ptr) { wlr_seat_keyboard_notify_enter( wlr_seat_ptr, - xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->surface, wlr_keyboard_ptr->keycodes, wlr_keyboard_ptr->num_keycodes, &wlr_keyboard_ptr->modifiers); } } else { - BS_ASSERT(xdg_tl_content_ptr->activated); + BS_ASSERT(xdg_tl_surface_ptr->activated); // FIXME: This clears pointer focus. But, this is keyboard focus? if (wlr_seat_ptr->keyboard_state.focused_surface == - xdg_tl_content_ptr->wlr_xdg_surface_ptr->surface) { + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->surface) { wlr_seat_pointer_clear_focus(wlr_seat_ptr); } } - xdg_tl_content_ptr->activated = activated; + xdg_tl_surface_ptr->activated = activated; } /* ------------------------------------------------------------------------- */ @@ -362,10 +360,10 @@ void content_set_activated( void handle_destroy(struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, destroy_listener); - // Destroy the window -> also destroys the content. - wlmtk_window_destroy(xdg_tl_content_ptr->super_content.window_ptr); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_surface_t, destroy_listener); + // Destroy the window -> also destroys the surface. + wlmtk_window_destroy(xdg_tl_surface_ptr->super_surface.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -379,11 +377,11 @@ void handle_new_popup( struct wl_listener *listener_ptr, void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, new_popup_listener); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_surface_t, new_popup_listener); bs_log(BS_WARNING, "FIXME: wlmtk_xdg_toplevel %p, New popup %p", - xdg_tl_content_ptr, data_ptr); + xdg_tl_surface_ptr, data_ptr); } /* ------------------------------------------------------------------------- */ @@ -400,15 +398,15 @@ void handle_surface_map( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, surface_map_listener); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_surface_t, surface_map_listener); wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( - wlmaker_server_get_current_workspace(xdg_tl_content_ptr->server_ptr)); + wlmaker_server_get_current_workspace(xdg_tl_surface_ptr->server_ptr)); wlmtk_workspace_map_window( wlmtk_workspace_ptr, - xdg_tl_content_ptr->super_content.window_ptr); + xdg_tl_surface_ptr->super_surface.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -422,10 +420,10 @@ void handle_surface_unmap( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, surface_unmap_listener); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_surface_t, surface_unmap_listener); - wlmtk_window_t *window_ptr = xdg_tl_content_ptr->super_content.window_ptr; + wlmtk_window_t *window_ptr = xdg_tl_surface_ptr->super_surface.window_ptr; wlmtk_workspace_unmap_window( wlmtk_workspace_from_container( wlmtk_window_element(window_ptr)->parent_container_ptr), @@ -443,16 +441,16 @@ void handle_surface_commit( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( - listener_ptr, wlmtk_xdg_toplevel_content_t, surface_commit_listener); + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_toplevel_surface_t, surface_commit_listener); - if (NULL == xdg_tl_content_ptr->wlr_xdg_surface_ptr) return; + if (NULL == xdg_tl_surface_ptr->wlr_xdg_surface_ptr) return; - wlmtk_content_commit_size( - &xdg_tl_content_ptr->super_content, - xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.configure_serial, - xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.width, - xdg_tl_content_ptr->wlr_xdg_surface_ptr->current.geometry.height); + wlmtk_surface_commit_size( + &xdg_tl_surface_ptr->super_surface, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.configure_serial, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.width, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.height); } /* ------------------------------------------------------------------------- */ @@ -466,13 +464,13 @@ void handle_toplevel_request_maximize( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, - wlmtk_xdg_toplevel_content_t, + wlmtk_xdg_toplevel_surface_t, toplevel_request_maximize_listener); wlmtk_window_request_maximize( - xdg_tl_content_ptr->super_content.window_ptr, - !wlmtk_window_maximized(xdg_tl_content_ptr->super_content.window_ptr)); + xdg_tl_surface_ptr->super_surface.window_ptr, + !wlmtk_window_maximized(xdg_tl_surface_ptr->super_surface.window_ptr)); } /* ------------------------------------------------------------------------- */ @@ -486,11 +484,11 @@ void handle_toplevel_request_move( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, - wlmtk_xdg_toplevel_content_t, + wlmtk_xdg_toplevel_surface_t, toplevel_request_move_listener); - wlmtk_window_request_move(xdg_tl_content_ptr->super_content.window_ptr); + wlmtk_window_request_move(xdg_tl_surface_ptr->super_surface.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -504,13 +502,13 @@ void handle_toplevel_request_resize( struct wl_listener *listener_ptr, void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, - wlmtk_xdg_toplevel_content_t, + wlmtk_xdg_toplevel_surface_t, toplevel_request_resize_listener); struct wlr_xdg_toplevel_resize_event *resize_event_ptr = data_ptr; wlmtk_window_request_resize( - xdg_tl_content_ptr->super_content.window_ptr, + xdg_tl_surface_ptr->super_surface.window_ptr, resize_event_ptr->edges); } @@ -525,14 +523,14 @@ void handle_toplevel_set_title( struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { - wlmtk_xdg_toplevel_content_t *xdg_tl_content_ptr = BS_CONTAINER_OF( + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, - wlmtk_xdg_toplevel_content_t, + wlmtk_xdg_toplevel_surface_t, toplevel_set_title_listener); wlmtk_window_set_title( - xdg_tl_content_ptr->super_content.window_ptr, - xdg_tl_content_ptr->wlr_xdg_surface_ptr->toplevel->title); + xdg_tl_surface_ptr->super_surface.window_ptr, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->title); } /* == End of xdg_toplevel.c ================================================ */ diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 56d65cc7..6e68a153 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -222,7 +222,7 @@ void handle_decoration_request_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; - wlmtk_content_t *content_ptr = (wlmtk_content_t*) + wlmtk_surface_t *surface_ptr = (wlmtk_surface_t*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; enum wlr_xdg_toplevel_decoration_v1_mode mode = @@ -257,14 +257,14 @@ void handle_decoration_request_mode( wlr_xdg_toplevel_decoration_v1_set_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr, mode); - if (NULL != content_ptr && - content_ptr->identifier_ptr == wlmtk_content_identifier_ptr) { + if (NULL != surface_ptr && + surface_ptr->identifier_ptr == wlmtk_surface_identifier_ptr) { bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, " - "content %p: Current %d, pending %d, scheduled %d, " + "surface %p: Current %d, pending %d, scheduled %d, " "requested %d. Set: %d", decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, - content_ptr, + surface_ptr, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->scheduled_mode, @@ -272,7 +272,7 @@ void handle_decoration_request_mode( mode); wlmtk_window_set_server_side_decorated( - content_ptr->window_ptr, + surface_ptr->window_ptr, mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } else { From 65ddf4b57085de12225c339af58b4ea0b8bcaada Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 27 Dec 2023 21:59:13 +0200 Subject: [PATCH 324/390] Elimiates content.[h|c]. --- src/toolkit/CMakeLists.txt | 2 - src/toolkit/content.c | 585 ------------------------------------- src/toolkit/content.h | 227 -------------- src/toolkit/toolkit.h | 1 - src/toolkit/toolkit_test.c | 1 - 5 files changed, 816 deletions(-) delete mode 100644 src/toolkit/content.c delete mode 100644 src/toolkit/content.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index aacd623b..3d1873b2 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -26,7 +26,6 @@ SET(PUBLIC_HEADER_FILES buffer.h button.h container.h - content.h element.h env.h fsm.h @@ -48,7 +47,6 @@ TARGET_SOURCES(toolkit PRIVATE buffer.c button.c container.c - content.c element.c env.c fsm.c diff --git a/src/toolkit/content.c b/src/toolkit/content.c deleted file mode 100644 index 001b4648..00000000 --- a/src/toolkit/content.c +++ /dev/null @@ -1,585 +0,0 @@ -/* ========================================================================= */ -/** - * @file content.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "content.h" - -#include "container.h" - -#define WLR_USE_UNSTABLE -#include -#include -#include -#undef WLR_USE_UNSTABLE - -/* == Declarations ========================================================= */ - -static void element_get_dimensions( - wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr); -static void element_get_pointer_area( - wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr); -static void element_pointer_leave(wlmtk_element_t *element_ptr); -static bool element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, - double y, - uint32_t time_msec); -static bool element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); - -/* == Data ================================================================= */ - -/** Method table for the element's virtual methods. */ -static const wlmtk_element_vmt_t content_element_vmt = { - .get_dimensions = element_get_dimensions, - .get_pointer_area = element_get_pointer_area, - .pointer_leave = element_pointer_leave, - .pointer_motion = element_pointer_motion, - .pointer_button = element_pointer_button, -}; - -void *wlmtk_content_identifier_ptr = wlmtk_content_init; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -bool wlmtk_content_init( - wlmtk_content_t *content_ptr, - wlmtk_env_t *env_ptr) -{ - BS_ASSERT(NULL != content_ptr); - memset(content_ptr, 0, sizeof(wlmtk_content_t)); - - if (!wlmtk_element_init(&content_ptr->super_element, env_ptr)) { - return false; - } - content_ptr->orig_super_element_vmt = wlmtk_element_extend( - &content_ptr->super_element, &content_element_vmt); - - content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; - return true; -} - -/* ------------------------------------------------------------------------- */ -wlmtk_content_vmt_t wlmtk_content_extend( - wlmtk_content_t *content_ptr, - const wlmtk_content_vmt_t *content_vmt_ptr) -{ - wlmtk_content_vmt_t orig_vmt = content_ptr->vmt; - - if (NULL != content_vmt_ptr->request_close) { - content_ptr->vmt.request_close = content_vmt_ptr->request_close; - } - if (NULL != content_vmt_ptr->request_size) { - content_ptr->vmt.request_size = content_vmt_ptr->request_size; - } - if (NULL != content_vmt_ptr->set_activated) { - content_ptr->vmt.set_activated = content_vmt_ptr->set_activated; - } - - return orig_vmt; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_content_fini(wlmtk_content_t *content_ptr) -{ - wlmtk_element_fini(&content_ptr->super_element); - memset(content_ptr, 0, sizeof(wlmtk_content_t)); -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_content_set_window( - wlmtk_content_t *content_ptr, - wlmtk_window_t *window_ptr) -{ - content_ptr->window_ptr = window_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_content_commit_size( - wlmtk_content_t *content_ptr, - uint32_t serial, - unsigned width, - unsigned height) -{ - if (content_ptr->committed_width != width || - content_ptr->committed_height != height) { - content_ptr->committed_width = width; - content_ptr->committed_height = height; - } - - if (NULL != content_ptr->window_ptr) { - wlmtk_window_serial(content_ptr->window_ptr, serial); - } - - if (NULL != content_ptr->super_element.parent_container_ptr) { - wlmtk_container_update_layout( - content_ptr->super_element.parent_container_ptr); - } -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, - int *height_ptr) -{ - if (NULL != width_ptr) *width_ptr = content_ptr->committed_width; - if (NULL != height_ptr) *height_ptr = content_ptr->committed_height; -} - -/* ------------------------------------------------------------------------- */ -wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr) -{ - return &content_ptr->super_element; -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** - * Implementation of the element's get_dimensions method: Return dimensions. - * - * @param element_ptr - * @param left_ptr Leftmost position. May be NULL. - * @param top_ptr Topmost position. May be NULL. - * @param right_ptr Rightmost position. Ma be NULL. - * @param bottom_ptr Bottommost position. May be NULL. - */ -void element_get_dimensions( - wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr) -{ - if (NULL != left_ptr) *left_ptr = 0; - if (NULL != top_ptr) *top_ptr = 0; - - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - - if (NULL != right_ptr) *right_ptr = content_ptr->committed_width; - if (NULL != bottom_ptr) *bottom_ptr = content_ptr->committed_height; -} - -/* ------------------------------------------------------------------------- */ -/** - * Overwrites the element's get_pointer_area method: Returns the extents of - * the surface and all subsurfaces. - * - * @param element_ptr - * @param left_ptr Leftmost position. May be NULL. - * @param top_ptr Topmost position. May be NULL. - * @param right_ptr Rightmost position. Ma be NULL. - * @param bottom_ptr Bottommost position. May be NULL. - */ -void element_get_pointer_area( - wlmtk_element_t *element_ptr, - int *left_ptr, - int *top_ptr, - int *right_ptr, - int *bottom_ptr) -{ - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - - struct wlr_box box; - if (NULL == content_ptr->wlr_surface_ptr) { - // DEBT: Should only get initialized with a valid surface. - box.x = 0; - box.y = 0; - box.width = content_ptr->committed_width; - box.height = content_ptr->committed_height; - } else { - wlr_surface_get_extends(content_ptr->wlr_surface_ptr, &box); - } - - if (NULL != left_ptr) *left_ptr = box.x; - if (NULL != top_ptr) *top_ptr = box.y; - if (NULL != right_ptr) *right_ptr = box.width - box.x; - if (NULL != bottom_ptr) *bottom_ptr = box.height - box.y; -} - -/* ------------------------------------------------------------------------- */ -/** - * Implements the element's leave method: If there's a WLR (sub)surface - * currently holding focus, that will be cleared. - * - * @param element_ptr - */ -void element_pointer_leave(wlmtk_element_t *element_ptr) -{ - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - - // If the current surface's parent is our surface: clear it. - struct wlr_surface *focused_wlr_surface_ptr = - wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr - )->pointer_state.focused_surface; - if (NULL != focused_wlr_surface_ptr && - wlr_surface_get_root_surface(focused_wlr_surface_ptr) == - content_ptr->wlr_surface_ptr) { - wlr_seat_pointer_clear_focus( - wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr)); - } -} - -/* ------------------------------------------------------------------------- */ -/** - * Pass pointer motion events to client's surface. - * - * Identifies the surface (or sub-surface) at the given coordinates, and pass - * on the motion event to that surface. If needed, will update the seat's - * pointer focus. - * - * @param element_ptr - * @param x Pointer horizontal position, relative to this - * element's node. - * @param y Pointer vertical position, relative to this - * element's node. - * @param time_msec - * - * @return Whether if the motion is within the area. - */ -bool element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, - double y, - uint32_t time_msec) -{ - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - - content_ptr->orig_super_element_vmt.pointer_motion( - element_ptr, x, y, time_msec); - - if (NULL == content_ptr->super_element.wlr_scene_node_ptr) return false; - - // Get the layout local coordinates of the node, so we can adjust the - // node-local (x, y) for the `wlr_scene_node_at` call. - int lx, ly; - if (!wlr_scene_node_coords( - content_ptr->super_element.wlr_scene_node_ptr, &lx, &ly)) { - return false; - } - // Get the node below the cursor. Return if there's no buffer node. - double node_x, node_y; - struct wlr_scene_node *wlr_scene_node_ptr = wlr_scene_node_at( - content_ptr->super_element.wlr_scene_node_ptr, - x + lx, y + ly, &node_x, &node_y); - - if (NULL == wlr_scene_node_ptr || - WLR_SCENE_NODE_BUFFER != wlr_scene_node_ptr->type) { - return false; - } - - struct wlr_scene_buffer *wlr_scene_buffer_ptr = - wlr_scene_buffer_from_node(wlr_scene_node_ptr); - struct wlr_scene_surface *wlr_scene_surface_ptr = - wlr_scene_surface_try_from_buffer(wlr_scene_buffer_ptr); - if (NULL == wlr_scene_surface_ptr) { - return false; - } - - BS_ASSERT(content_ptr->wlr_surface_ptr == - wlr_surface_get_root_surface(wlr_scene_surface_ptr->surface)); - wlr_seat_pointer_notify_enter( - wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr), - wlr_scene_surface_ptr->surface, - node_x, node_y); - wlr_seat_pointer_notify_motion( - wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr), - time_msec, - node_x, node_y); - return true; -} - -/* ------------------------------------------------------------------------- */ -/** - * Passes pointer button event further to the focused surface, if any. - * - * The actual passing is handled by `wlr_seat`. Here we just verify that the - * currently-focused surface (or sub-surface) is part of this content. - * - * @param element_ptr - * @param button_event_ptr - * - * @return Whether the button event was consumed. - */ -bool element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr) -{ - wlmtk_content_t *content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_content_t, super_element); - - // Complain if the surface isn't part of our responsibility. - struct wlr_surface *focused_wlr_surface_ptr = - wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr - )->pointer_state.focused_surface; - if (NULL == focused_wlr_surface_ptr) return false; - // TODO(kaeser@gubbe.ch): Dragging the pointer from an activated window - // over to a non-activated window will trigger the condition here on the - // WLMTK_BUTTON_UP event. Needs a test and fixing. - BS_ASSERT(content_ptr->wlr_surface_ptr == - wlr_surface_get_root_surface(focused_wlr_surface_ptr)); - - // We're only forwarding PRESSED & RELEASED events. - if (WLMTK_BUTTON_DOWN == button_event_ptr->type || - WLMTK_BUTTON_UP == button_event_ptr->type) { - wlr_seat_pointer_notify_button( - wlmtk_env_wlr_seat(content_ptr->super_element.env_ptr), - button_event_ptr->time_msec, - button_event_ptr->button, - (button_event_ptr->type == WLMTK_BUTTON_DOWN) ? - WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); - return true; - } - return false; -} - -/* == Fake content, useful for unit tests. ================================= */ - -static void fake_content_destroy( - wlmtk_element_t *element_ptr); -static struct wlr_scene_node *fake_content_create_scene_node( - wlmtk_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr); -static void fake_content_request_close( - wlmtk_content_t *content_ptr); -static uint32_t fake_content_request_size( - wlmtk_content_t *content_ptr, - int width, - int height); -static void fake_content_set_activated( - wlmtk_content_t *content_ptr, - bool activated); - -// Debt: Should separate content abstract implementation from surface. -static void fake_content_element_pointer_leave(wlmtk_element_t *element_ptr); -static bool fake_content_element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, - double y, - uint32_t time_msec); -static bool fake_content_element_pointer_button( - wlmtk_element_t *element_ptr, - const wlmtk_button_event_t *button_event_ptr); - -/** Extensions to the content's super elements virtual methods. */ -static const wlmtk_element_vmt_t fake_content_element_vmt = { - .destroy = fake_content_destroy, - .create_scene_node = fake_content_create_scene_node, - .pointer_motion = fake_content_element_pointer_motion, - .pointer_button = fake_content_element_pointer_button, - .pointer_leave = fake_content_element_pointer_leave, -}; -/** Extensions to the content's virtual methods. */ -static const wlmtk_content_vmt_t fake_content_vmt = { - .request_close = fake_content_request_close, - .request_size = fake_content_request_size, - .set_activated = fake_content_set_activated, -}; - -/* ------------------------------------------------------------------------- */ -wlmtk_fake_content_t *wlmtk_fake_content_create(void) -{ - wlmtk_fake_content_t *fake_content_ptr = logged_calloc( - 1, sizeof(wlmtk_fake_content_t)); - if (NULL == fake_content_ptr) return NULL; - - if (!wlmtk_content_init(&fake_content_ptr->content, NULL)) { - free(fake_content_ptr); - return NULL; - } - wlmtk_content_extend(&fake_content_ptr->content, &fake_content_vmt); - - fake_content_ptr->orig_super_element_vmt = wlmtk_element_extend( - &fake_content_ptr->content.super_element, &fake_content_element_vmt); - return fake_content_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmtk_fake_content_commit(wlmtk_fake_content_t *fake_content_ptr) -{ - wlmtk_content_commit_size( - &fake_content_ptr->content, - fake_content_ptr->return_request_size, - fake_content_ptr->requested_width, - fake_content_ptr->requested_height); -} - -/* ------------------------------------------------------------------------- */ -/** Dtor for the fake content. */ -void fake_content_destroy(wlmtk_element_t *element_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_fake_content_t, content.super_element); - - wlmtk_content_fini(&fake_content_ptr->content); - free(fake_content_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** Creates a scene node for the fake content. */ -struct wlr_scene_node *fake_content_create_scene_node( - __UNUSED__ wlmtk_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr) -{ - struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( - wlr_scene_tree_ptr, NULL); - return &wlr_scene_buffer_ptr->node; -} - -/* ------------------------------------------------------------------------- */ -/** Records that @ref wlmtk_content_request_close was called. */ -void fake_content_request_close(wlmtk_content_t *content_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_fake_content_t, content); - fake_content_ptr->request_close_called = true; -} - -/* ------------------------------------------------------------------------- */ -/** Sets the size of the fake content. */ -uint32_t fake_content_request_size( - wlmtk_content_t *content_ptr, - int width, - int height) -{ - wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_fake_content_t, content); - fake_content_ptr->requested_width = width; - fake_content_ptr->requested_height = height; - return fake_content_ptr->return_request_size; -} - -/* ------------------------------------------------------------------------- */ -/** Sets the content's activated status. */ -void fake_content_set_activated( - wlmtk_content_t *content_ptr, - bool activated) -{ - wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - content_ptr, wlmtk_fake_content_t, content); - fake_content_ptr->activated = activated; -} - -/* ------------------------------------------------------------------------- */ -/** Returns (x, y) in [(0, committed_with), (0, committed_height)). */ -bool fake_content_element_pointer_motion( - wlmtk_element_t *element_ptr, - double x, - double y, - uint32_t time_msec) -{ - wlmtk_fake_content_t *fake_content_ptr = BS_CONTAINER_OF( - element_ptr, wlmtk_fake_content_t, content.super_element); - fake_content_ptr->orig_super_element_vmt.pointer_motion( - element_ptr, x, y, time_msec); - - return (0 <= x && x < fake_content_ptr->content.committed_width && - 0 <= y && y < fake_content_ptr->content.committed_height); -} - -/* ------------------------------------------------------------------------- */ -/** Returns true. */ -bool fake_content_element_pointer_button( - __UNUSED__ wlmtk_element_t *element_ptr, - __UNUSED__ const wlmtk_button_event_t *button_event_ptr) -{ - return true; -} - -/* ------------------------------------------------------------------------- */ -/** Does nothing. */ -void fake_content_element_pointer_leave( - __UNUSED__ wlmtk_element_t *element_ptr) -{ - // Nothing to do. -} - -/* == Unit tests =========================================================== */ - -static void test_init_fini(bs_test_t *test_ptr); - -const bs_test_case_t wlmtk_content_test_cases[] = { - { 1, "init_fini", test_init_fini }, - { 0, NULL, NULL } -}; - -/* ------------------------------------------------------------------------- */ -/** Exercises init() and fini() methods, verifies dtor forwarding. */ -void test_init_fini(bs_test_t *test_ptr) -{ - wlmtk_fake_content_t *fake_content_ptr; - - fake_content_ptr = wlmtk_fake_content_create(); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, fake_content_ptr); - - // Also expect the super element to be initialized. - BS_TEST_VERIFY_NEQ( - test_ptr, NULL, - fake_content_ptr->content.super_element.vmt.destroy); - - wlmtk_content_request_close(&fake_content_ptr->content); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->request_close_called); - - int l, t, r, b; - fake_content_ptr->return_request_size = 42; - BS_TEST_VERIFY_EQ( - test_ptr, - 42, - wlmtk_content_request_size(&fake_content_ptr->content, 42, 21)); - wlmtk_element_get_dimensions( - &fake_content_ptr->content.super_element, &l, &t, &r, &b); - BS_TEST_VERIFY_EQ(test_ptr, 0, l); - BS_TEST_VERIFY_EQ(test_ptr, 0, t); - BS_TEST_VERIFY_EQ(test_ptr, 0, r); - BS_TEST_VERIFY_EQ(test_ptr, 0, b); - - wlmtk_content_commit_size(&fake_content_ptr->content, 1, 42, 21); - wlmtk_content_get_size(&fake_content_ptr->content, &r, &b); - BS_TEST_VERIFY_EQ(test_ptr, 42, r); - BS_TEST_VERIFY_EQ(test_ptr, 21, b); - - wlmtk_element_get_dimensions( - &fake_content_ptr->content.super_element, &l, &t, &r, &b); - BS_TEST_VERIFY_EQ(test_ptr, 0, l); - BS_TEST_VERIFY_EQ(test_ptr, 0, t); - BS_TEST_VERIFY_EQ(test_ptr, 42, r); - BS_TEST_VERIFY_EQ(test_ptr, 21, b); - - wlmtk_content_set_activated(&fake_content_ptr->content, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_content_ptr->activated); - - wlmtk_element_destroy(&fake_content_ptr->content.super_element); -} - -/* == End of content.c ================================================== */ diff --git a/src/toolkit/content.h b/src/toolkit/content.h deleted file mode 100644 index 569867dc..00000000 --- a/src/toolkit/content.h +++ /dev/null @@ -1,227 +0,0 @@ -/* ========================================================================= */ -/** - * @file content.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __WLMTK_CONTENT_H__ -#define __WLMTK_CONTENT_H__ - -/** Forward declaration: Window content. */ -typedef struct _wlmtk_content_t wlmtk_content_t; - -/** Forward declaration: Content virtual method table. */ -typedef struct _wlmtk_content_vmt_t wlmtk_content_vmt_t; -/** Forward declaration: Fake content, for tests. */ -typedef struct _wlmtk_fake_content_t wlmtk_fake_content_t; - - -#include "window.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** The content's virtual method table. */ -struct _wlmtk_content_vmt_t { - /** Abstract: Requests the content to close. */ - void (*request_close)(wlmtk_content_t *content_ptr); - /** Abstract: Sets width and height of the content. Returns serial. */ - uint32_t (*request_size)(wlmtk_content_t *content_ptr, - int width, int height); - /** Abstract: Sets whether the content is activated (keyboard focus). */ - void (*set_activated)(wlmtk_content_t *content_ptr, bool activated); -}; - -/** State of the element. */ -struct _wlmtk_content_t { - /** Temporary: Identifier, to disambiguate from XDG nodes. */ - void *identifier_ptr; - - /** Super class of the content: An element. */ - wlmtk_element_t super_element; - /** Virtual method table of the super element before extending it. */ - wlmtk_element_vmt_t orig_super_element_vmt; - - /** Virtual method table of the content. */ - wlmtk_content_vmt_t vmt; - - /** - * The window this content belongs to. Will be set when creating - * the window. - */ - wlmtk_window_t *window_ptr; - - /** - * Surface associated with this content. - * - * TODO(kaeser@gubbe.ch): If we extend 'content' to support different - * elements (eg. buffer), this should be abstracted away. - */ - struct wlr_surface *wlr_surface_ptr; - - /** Committed width of the content. See @ref wlmtk_content_commit_size. */ - unsigned committed_width; - /** Committed height of the content. See @ref wlmtk_content_commit_size. */ - unsigned committed_height; -}; - -/** - * Initializes the content. - * - * @param content_ptr - * @param env_ptr - * - * @return true on success. - */ -bool wlmtk_content_init( - wlmtk_content_t *content_ptr, - wlmtk_env_t *env_ptr); - -/** - * Extends the content's virtual methods. - * - * @param content_ptr - * @param content_vmt_ptr - * - * @return The original virtual method table. - */ -wlmtk_content_vmt_t wlmtk_content_extend( - wlmtk_content_t *content_ptr, - const wlmtk_content_vmt_t *content_vmt_ptr); - -/** - * Cleans up the content. - * - * @param content_ptr - */ -void wlmtk_content_fini(wlmtk_content_t *content_ptr); - -/** - * Sets the window for the content. - * - * Private: Should only be called by Window ctor (a friend). - * - * @param content_ptr - * @param window_ptr - */ -void wlmtk_content_set_window( - wlmtk_content_t *content_ptr, - wlmtk_window_t *window_ptr); - -/** - * Sets the committed size of the content. - * - * Size operations on Wayland content are (often) asynchronous. The server - * should call @ref wlmtk_content_request_size, which (as a virtual method) - * forwards the request to the content (eg. the Wayland client surface). The - * client then configures it's surface and commits it. The content needs to - * catch that commit and call @ref wlmtk_content_commit_size accordingly. - * This will then update the parent container's (and window's) layout. - * - * @param content_ptr - * @param serial - * @param width - * @param height - */ -void wlmtk_content_commit_size( - wlmtk_content_t *content_ptr, - uint32_t serial, - unsigned width, - unsigned height); - -/** - * Returns committed size of the content. - * - * @param content_ptr - * @param width_ptr - * @param height_ptr - */ -void wlmtk_content_get_size( - wlmtk_content_t *content_ptr, - int *width_ptr, int *height_ptr); - -/** - * Returns the super Element of the content. - * - * @param content_ptr - * - * @return Pointer to the @ref wlmtk_element_t base instantiation to - * content_ptr. - */ -wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); - -/** Wraps to @ref wlmtk_content_vmt_t::request_close. */ -static inline void wlmtk_content_request_close(wlmtk_content_t *content_ptr) -{ - content_ptr->vmt.request_close(content_ptr); -} -/** Wraps to @ref wlmtk_content_vmt_t::request_size. */ -static inline uint32_t wlmtk_content_request_size( - wlmtk_content_t *content_ptr, - int width, - int height) -{ - return content_ptr->vmt.request_size(content_ptr, width, height); -} -/** Wraps to @ref wlmtk_content_vmt_t::set_activated. */ -static inline void wlmtk_content_set_activated( - wlmtk_content_t *content_ptr, - bool activated) -{ - content_ptr->vmt.set_activated(content_ptr, activated); -} - -/** - * Identifying pointer: Value unique to wlmtk_content. - * - * TODO(kaeser@gubbe.ch): Remove, once migrated to toolkit. - */ -extern void *wlmtk_content_identifier_ptr; - -/** Unit tests for content. */ -extern const bs_test_case_t wlmtk_content_test_cases[]; - -/** Fake content, useful for unit test. */ -struct _wlmtk_fake_content_t { - /** State of the content. */ - wlmtk_content_t content; - /** Original virtual method table of the content's super element. */ - wlmtk_element_vmt_t orig_super_element_vmt; - /** Whether @ref wlmtk_content_request_close was called. */ - bool request_close_called; - /** `width` argument eof last @ref wlmtk_content_request_size call. */ - int requested_width; - /** `height` argument of last @ref wlmtk_content_request_size call. */ - int requested_height; - /** Return value of @ref wlmtk_content_request_size call. */ - uint32_t return_request_size; - /** Argument of last @ref wlmtk_content_set_activated call. */ - bool activated; -}; - -/** Ctor for a fake content. */ -wlmtk_fake_content_t *wlmtk_fake_content_create(void); - -/** Commits dimensions from earlier @ref wlmtk_content_request_size call. */ -void wlmtk_fake_content_commit(wlmtk_fake_content_t *fake_content_ptr); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __WLMTK_CONTENT_H__ */ -/* == End of content.h ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 1c1edf29..9f31b361 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -35,7 +35,6 @@ #include "buffer.h" #include "button.h" #include "container.h" -#include "content.h" #include "element.h" #include "env.h" #include "fsm.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 886bc141..701974c7 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -26,7 +26,6 @@ const bs_test_set_t toolkit_tests[] = { { 1, "box", wlmtk_box_test_cases }, { 1, "button", wlmtk_button_test_cases }, { 1, "container", wlmtk_container_test_cases }, - { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, { 1, "surface", wlmtk_surface_test_cases }, From 4e2f2352b1ed9f187da03e685a493ffcf248dcb8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 28 Dec 2023 10:32:37 +0200 Subject: [PATCH 325/390] Fixes a memory leak in tests. --- src/toolkit/surface.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 8aa66e64..096222a1 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -448,6 +448,7 @@ void wlmtk_fake_surface_commit(wlmtk_fake_surface_t *fake_surface_ptr) BS_ASSERT(NULL != wlr_scene_buffer_ptr); wlr_scene_buffer_set_buffer(wlr_scene_buffer_ptr, wlr_buffer_ptr); + wlr_buffer_drop(wlr_buffer_ptr); } } @@ -477,7 +478,8 @@ struct wlr_scene_node *_wlmtk_fake_surface_element_create_scene_node( struct wlr_scene_buffer *wlr_scene_buffer_ptr = wlr_scene_buffer_create( wlr_scene_tree_ptr, wlr_buffer_ptr); - return &wlr_scene_buffer_ptr->node; + wlr_buffer_drop(wlr_buffer_ptr); + return &wlr_scene_buffer_ptr->node; } /* ------------------------------------------------------------------------- */ From 2a66fcfeb613b1fbfac17dbc0c01aca7a5cdcc03 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 28 Dec 2023 22:00:34 +0200 Subject: [PATCH 326/390] Adds pointer_motion to wmkt_fake_surface_t, ensuring pointer motion can be tested correctly also without a scene graph API. --- src/toolkit/surface.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 096222a1..bf2726b2 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -375,6 +375,10 @@ static void _wlmtk_fake_surface_element_destroy( static struct wlr_scene_node *_wlmtk_fake_surface_element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); +static bool _wlmtk_fake_surface_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + __UNUSED__ uint32_t time_msec); static bool _wlmtk_fake_surface_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); @@ -385,6 +389,7 @@ static void _wlmtk_fake_surface_element_pointer_leave( static const wlmtk_element_vmt_t _wlmtk_fake_surface_element_vmt = { .destroy = _wlmtk_fake_surface_element_destroy, .create_scene_node = _wlmtk_fake_surface_element_create_scene_node, + .pointer_motion = _wlmtk_fake_surface_element_pointer_motion, .pointer_button = _wlmtk_fake_surface_element_pointer_button, .pointer_leave = _wlmtk_fake_surface_element_pointer_leave, }; @@ -482,6 +487,20 @@ struct wlr_scene_node *_wlmtk_fake_surface_element_create_scene_node( return &wlr_scene_buffer_ptr->node; } +/* ------------------------------------------------------------------------- */ +/** Fake for @ref wlmtk_element_vmt_t::pointer_motion. True if in committed. */ +bool _wlmtk_fake_surface_element_pointer_motion( + wlmtk_element_t *element_ptr, + double x, double y, + __UNUSED__ uint32_t time_msec) +{ + wlmtk_fake_surface_t *fake_surface_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_fake_surface_t, surface.super_element); + + return (0 <= x && x < fake_surface_ptr->surface.committed_width && + 0 <= y && y < fake_surface_ptr->surface.committed_height); +} + /* ------------------------------------------------------------------------- */ /** Fake for @ref wlmtk_element_vmt_t::pointer_button. Returns true. */ bool _wlmtk_fake_surface_element_pointer_button( From 335280e690b8b509aceb803987e7f7f7cf6f2d26 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 28 Dec 2023 22:09:29 +0200 Subject: [PATCH 327/390] Adds wlmtk_content_t as a layer to hold surfaces with popups. --- src/toolkit/CMakeLists.txt | 2 + src/toolkit/content.c | 177 +++++++++++++++++++++++++++++++++++++ src/toolkit/content.h | 126 ++++++++++++++++++++++++++ src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 5 files changed, 307 insertions(+) create mode 100644 src/toolkit/content.c create mode 100644 src/toolkit/content.h diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt index 3d1873b2..aacd623b 100644 --- a/src/toolkit/CMakeLists.txt +++ b/src/toolkit/CMakeLists.txt @@ -26,6 +26,7 @@ SET(PUBLIC_HEADER_FILES buffer.h button.h container.h + content.h element.h env.h fsm.h @@ -47,6 +48,7 @@ TARGET_SOURCES(toolkit PRIVATE buffer.c button.c container.c + content.c element.c env.c fsm.c diff --git a/src/toolkit/content.c b/src/toolkit/content.c new file mode 100644 index 00000000..0435c437 --- /dev/null +++ b/src/toolkit/content.c @@ -0,0 +1,177 @@ +/* ========================================================================= */ +/** + * @file content.c + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "content.h" + +#include "surface.h" + +/* == Declarations ========================================================= */ + +/* == Exported methods ===================================================== */ + +/* ------------------------------------------------------------------------- */ +bool wlmtk_content_init( + wlmtk_content_t *content_ptr, + wlmtk_surface_t *surface_ptr, + wlmtk_env_t *env_ptr) +{ + BS_ASSERT(NULL != content_ptr); + memset(content_ptr, 0, sizeof(wlmtk_content_t)); + + if (!wlmtk_container_init(&content_ptr->super_container, env_ptr)) { + return false; + } + + BS_ASSERT(NULL != surface_ptr); + wlmtk_container_add_element( + &content_ptr->super_container, + wlmtk_surface_element(surface_ptr)); + content_ptr->surface_ptr = surface_ptr; + + wlmtk_element_set_visible(wlmtk_surface_element(surface_ptr), true); + return true; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_fini( + wlmtk_content_t *content_ptr) +{ + if (NULL != content_ptr->surface_ptr) { + wlmtk_container_remove_element( + &content_ptr->super_container, + wlmtk_surface_element(content_ptr->surface_ptr)); + content_ptr->surface_ptr = NULL; + } + memset(content_ptr, 0, sizeof(wlmtk_content_t)); +} + +/* ------------------------------------------------------------------------- */ +uint32_t wlmtk_content_request_size( + wlmtk_content_t *content_ptr, + int width, + int height) +{ + return wlmtk_surface_request_size(content_ptr->surface_ptr, width, height); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_request_close(wlmtk_content_t *content_ptr) +{ + wlmtk_surface_request_close(content_ptr->surface_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_set_activated( + wlmtk_content_t *content_ptr, + bool activated) +{ + wlmtk_surface_set_activated(content_ptr->surface_ptr, activated); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr) +{ + wlmtk_surface_get_size(content_ptr->surface_ptr, width_ptr, height_ptr); +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_commit_size( + wlmtk_content_t *content_ptr, + uint32_t serial, + int width, + int height) +{ + wlmtk_surface_commit_size(content_ptr->surface_ptr, serial, width, height); + content_ptr->committed_width = width; + content_ptr->committed_height = height; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_content_set_window( + wlmtk_content_t *content_ptr, + wlmtk_window_t *window_ptr) +{ + content_ptr->window_ptr = window_ptr; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr) +{ + return &content_ptr->super_container.super_element; +} + +/* == Local (static) methods =============================================== */ + +/* == Unit tests =========================================================== */ + +static void test_init_fini(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_content_test_cases[] = { + { 1, "init_fini", test_init_fini }, + { 0, NULL, NULL } +}; + +/* ------------------------------------------------------------------------- */ +/** Tests setup and teardown. */ +void test_init_fini(bs_test_t *test_ptr) +{ + wlmtk_content_t content; + struct wlr_box box; + + wlmtk_fake_surface_t *fs_ptr = wlmtk_fake_surface_create(); + + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_content_init(&content, &fs_ptr->surface, NULL)); + wlmtk_element_t *element_ptr = wlmtk_content_element(&content); + + // Initial size is zero. + box = wlmtk_element_get_dimensions_box(element_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.height); + + // Pointer motion, should report to not be within the content. + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 10, 10, 0)); + + // Request & commit a sensible size, verifies the content reports it. + wlmtk_surface_request_size(&fs_ptr->surface, 200, 100); + wlmtk_fake_surface_commit(fs_ptr); + box = wlmtk_element_get_dimensions_box(element_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + // Pointer motion shouuld now report to be within the content. + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_element_pointer_motion(element_ptr, 10, 10, 0)); + + wlmtk_content_fini(&content); +} + +/* == End of content.c ===================================================== */ diff --git a/src/toolkit/content.h b/src/toolkit/content.h new file mode 100644 index 00000000..501eb5c0 --- /dev/null +++ b/src/toolkit/content.h @@ -0,0 +1,126 @@ +/* ========================================================================= */ +/** + * @file content.h + * + * @copyright + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WLMTK_CONTENT_H__ +#define __WLMTK_CONTENT_H__ + + +/** Forward declaration: Content state. */ +typedef struct _wlmtk_content_t wlmtk_content_t; +/** Forward declaration: Window. */ +typedef struct _wlmtk_window_t wlmtk_window_t +;/** Forward declaration: State of a toolkit's WLR surface. */ +typedef struct _wlmtk_surface_t wlmtk_surface_t; + +#include "container.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** State of window content. */ +struct _wlmtk_content_t { + /** Super class of the content: A container, holding surface & popups. */ + wlmtk_container_t super_container; + /** The principal surface of the content. */ + wlmtk_surface_t *surface_ptr; + + /** The window this content belongs to. Set when creating the window. */ + wlmtk_window_t *window_ptr; + + + /** Committed width of the surface, in pixels. */ + int committed_width; + /** Committed height of the surface, in pixels. */ + int committed_height; +}; + +/** + * Initializes the content with the given surface. + * + * @param content_ptr + * @param surface_ptr + * @param env_ptr + * + * @return true on success. + */ +bool wlmtk_content_init( + wlmtk_content_t *content_ptr, + wlmtk_surface_t *surface_ptr, + wlmtk_env_t *env_ptr); + +/** + * Un-initializes the content. + * + * @param content_ptr + */ +void wlmtk_content_fini( + wlmtk_content_t *content_ptr); + +/** Requests size: Forwards to @ref wlmtk_surface_request_size. */ +uint32_t wlmtk_content_request_size( + wlmtk_content_t *content_ptr, + int width, + int height); + +/** + * Sets the window for the content. + * + * Private: Should only be called by Window ctor (a friend). + * + * @param content_ptr + * @param window_ptr + */ +void wlmtk_content_set_window( + wlmtk_content_t *content_ptr, + wlmtk_window_t *window_ptr); + +/** Requests close: Forwards to @ref wlmtk_surface_request_close. */ +void wlmtk_content_request_close(wlmtk_content_t *content_ptr); + +/** Set activated: Forwards to @ref wlmtk_surface_set_activated. */ +void wlmtk_content_set_activated( + wlmtk_content_t *content_ptr, + bool activated); + +/** Gets size: Forwards to @ref wlmtk_surface_get_size. */ +void wlmtk_content_get_size( + wlmtk_content_t *content_ptr, + int *width_ptr, + int *height_ptr); + +/** Commits size: Forwards to @ref wlmtk_surface_commit_size. */ +void wlmtk_content_commit_size( + wlmtk_content_t *content_ptr, + uint32_t serial, + int width, + int height); + +/** Returns the superclass' instance of @ref wlmtk_element_t. */ +wlmtk_element_t *wlmtk_content_element(wlmtk_content_t *content_ptr); + +/** Content's unit tests. */ +extern const bs_test_case_t wlmtk_content_test_cases[]; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* __WLMTK_CONTENT_H__ */ +/* == End of content.h ===================================================== */ diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 9f31b361..1c1edf29 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -35,6 +35,7 @@ #include "buffer.h" #include "button.h" #include "container.h" +#include "content.h" #include "element.h" #include "env.h" #include "fsm.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 701974c7..886bc141 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -26,6 +26,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "box", wlmtk_box_test_cases }, { 1, "button", wlmtk_button_test_cases }, { 1, "container", wlmtk_container_test_cases }, + { 1, "content", wlmtk_content_test_cases }, { 1, "element", wlmtk_element_test_cases }, { 1, "fsm", wlmtk_fsm_test_cases }, { 1, "surface", wlmtk_surface_test_cases }, From cbcda1e3fce58977ff166f8d72944f30d717e4ca Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 14:17:37 +0200 Subject: [PATCH 328/390] Rebases XDG toplevel off content, rather than surface. --- src/toolkit/toolkit.md | 33 +++++++- src/toolkit/window.c | 166 +++++++++++++++++++++++++++++++-------- src/toolkit/window.h | 16 ++++ src/wlmtk_xdg_toplevel.c | 23 ++++-- 4 files changed, 198 insertions(+), 40 deletions(-) diff --git a/src/toolkit/toolkit.md b/src/toolkit/toolkit.md index 3fd32146..c9b4c8a9 100644 --- a/src/toolkit/toolkit.md +++ b/src/toolkit/toolkit.md @@ -99,18 +99,45 @@ class Box { } Container <|-- Box + + abstract class Surface { Element super_element + + request_size() + get_size() +} + + +abstract class Content { + Container super_container + Surface surface Surface popups[] + + init(surface) + fini() + + request_size() + get_size() + + request_close() + set_activated() } + + class Toplevel { - Surface super_surface; + Content super_content - request_close() - set_activated() + -- because: implement request_close, set_activated, ... + + -- but: Window ? +} + +class Popup { + Surface super_surface } diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 0b58d7d8..ec11549d 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -82,8 +82,13 @@ struct _wlmtk_window_t { /** Box: In `super_bordered`, holds surface, title bar and resizebar. */ wlmtk_box_t box; + /** FIXME: Element. */ + wlmtk_element_t *element_ptr; + /** Surface of this window. */ wlmtk_surface_t *surface_ptr; + /** Content of the window. */ + wlmtk_content_t *content_ptr; /** Titlebar. */ wlmtk_titlebar_t *titlebar_ptr; /** Resizebar. */ @@ -118,12 +123,14 @@ typedef struct { wlmtk_window_t window; /** Fake window - public state. */ wlmtk_fake_window_t fake_window; + /** Fake content. */ + wlmtk_content_t content; } wlmtk_fake_window_state_t; static bool _wlmtk_window_init( wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, - wlmtk_surface_t *surface_ptr); + wlmtk_element_t *element_ptr); static void _wlmtk_window_fini(wlmtk_window_t *window_ptr); static wlmtk_window_vmt_t _wlmtk_window_extend( wlmtk_window_t *window_ptr, @@ -231,10 +238,36 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; - if (!_wlmtk_window_init(window_ptr, env_ptr, surface_ptr)) { + if (!_wlmtk_window_init( + window_ptr, + env_ptr, + wlmtk_surface_element(surface_ptr))) { wlmtk_window_destroy(window_ptr); return NULL; } + window_ptr->surface_ptr = surface_ptr; + wlmtk_surface_set_window(surface_ptr, window_ptr); + + return window_ptr; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_window_create_content( + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr) +{ + wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); + if (NULL == window_ptr) return NULL; + + if (!_wlmtk_window_init( + window_ptr, + env_ptr, + wlmtk_content_element(content_ptr))) { + wlmtk_window_destroy(window_ptr); + return NULL; + } + window_ptr->content_ptr = content_ptr; + wlmtk_content_set_window(content_ptr, window_ptr); return window_ptr; } @@ -425,7 +458,13 @@ void wlmtk_window_get_size( int *height_ptr) { // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - wlmtk_surface_get_size(window_ptr->surface_ptr, width_ptr, height_ptr); + if (NULL != window_ptr->surface_ptr) { + wlmtk_surface_get_size(window_ptr->surface_ptr, width_ptr, height_ptr); + } else if (NULL != window_ptr->content_ptr) { + wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); + } else { + bs_log(BS_FATAL, "FIXME"); + } if (NULL != window_ptr->titlebar_ptr) { *height_ptr += titlebar_style.height + margin_style.width; @@ -445,7 +484,13 @@ void wlmtk_window_request_size( int height) { // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - wlmtk_surface_request_size(window_ptr->surface_ptr, width, height); + if (NULL != window_ptr->surface_ptr) { + wlmtk_surface_request_size(window_ptr->surface_ptr, width, height); + } else if (NULL != window_ptr->content_ptr) { + wlmtk_content_request_size(window_ptr->content_ptr, width, height); + } else { + bs_log(BS_FATAL, "FIXME"); + } // TODO(kaeser@gubbe.ch): For client surface (eg. a wlr_surface), setting // the size is an asynchronous operation and should be handled as such. @@ -505,13 +550,25 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) if (0 < delta) break; if (pending_update_ptr->serial == serial) { - if (window_ptr->surface_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (window_ptr->surface_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); + if (NULL != window_ptr->surface_ptr) { + if (window_ptr->surface_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (window_ptr->surface_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } + } else if (NULL != window_ptr->content_ptr && + NULL != window_ptr->content_ptr->surface_ptr) { + if (window_ptr->content_ptr->surface_ptr->committed_width != + pending_update_ptr->width) { + bs_log(BS_ERROR, "FIXME: width mismatch!"); + } + if (window_ptr->content_ptr->surface_ptr->committed_height != + pending_update_ptr->height) { + bs_log(BS_ERROR, "FIXME: height mismatch!"); + } } } @@ -531,14 +588,14 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) * * @param window_ptr * @param env_ptr - * @param surface_ptr + * @param element_ptr * * @return true on success. */ bool _wlmtk_window_init( wlmtk_window_t *window_ptr, wlmtk_env_t *env_ptr, - wlmtk_surface_t *surface_ptr) + wlmtk_element_t *element_ptr) { BS_ASSERT(NULL != window_ptr); memcpy(&window_ptr->vmt, &_wlmtk_window_vmt, sizeof(wlmtk_window_vmt_t)); @@ -570,15 +627,12 @@ bool _wlmtk_window_init( &window_element_vmt); window_ptr->orig_super_container_vmt = wlmtk_container_extend( &window_ptr->super_bordered.super_container, &window_container_vmt); + window_ptr->element_ptr = element_ptr; wlmtk_window_set_title(window_ptr, NULL); - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_surface_element(surface_ptr)); - window_ptr->surface_ptr = surface_ptr; - wlmtk_surface_set_window(surface_ptr, window_ptr); - wlmtk_element_set_visible(wlmtk_surface_element(surface_ptr), true); + wlmtk_box_add_element_front(&window_ptr->box, element_ptr); + wlmtk_element_set_visible(element_ptr, true); return true; } @@ -593,15 +647,18 @@ void _wlmtk_window_fini(wlmtk_window_t *window_ptr) wlmtk_window_set_server_side_decorated(window_ptr, false); if (NULL != window_ptr->surface_ptr) { - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_surface_element(window_ptr->surface_ptr)); - wlmtk_element_set_visible( - wlmtk_surface_element(window_ptr->surface_ptr), false); wlmtk_surface_set_window(window_ptr->surface_ptr, NULL); + } + if (NULL != window_ptr->content_ptr) { + wlmtk_content_set_window(window_ptr->content_ptr, NULL); + } - wlmtk_element_destroy(wlmtk_surface_element(window_ptr->surface_ptr)); - window_ptr->surface_ptr = NULL; + if (NULL != window_ptr->element_ptr) { + wlmtk_box_remove_element( + &window_ptr->box, window_ptr->element_ptr); + wlmtk_element_set_visible(window_ptr->element_ptr, false); + // FIXME wlmtk_element_destroy(window_ptr->element_ptr); + window_ptr->element_ptr = NULL; } if (NULL != window_ptr->title_ptr) { @@ -695,6 +752,15 @@ void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) if (NULL != window_ptr->resizebar_ptr) { wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); } + } else if (NULL != window_ptr->content_ptr) { + int width; + wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); + } + if (NULL != window_ptr->resizebar_ptr) { + wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); + } } } @@ -704,7 +770,11 @@ void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { - wlmtk_surface_set_activated(window_ptr->surface_ptr, activated); + if (NULL != window_ptr->surface_ptr) { + wlmtk_surface_set_activated(window_ptr->surface_ptr, activated); + } else if (NULL != window_ptr->content_ptr) { + wlmtk_content_set_activated(window_ptr->content_ptr, activated); + } if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); } @@ -714,7 +784,11 @@ void _wlmtk_window_set_activated( /** Default implementation of @ref wlmtk_window_request_close. */ void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) { - wlmtk_surface_request_close(window_ptr->surface_ptr); + if (NULL != window_ptr->surface_ptr) { + wlmtk_surface_request_close(window_ptr->surface_ptr); + } else if (NULL != window_ptr->content_ptr) { + wlmtk_content_request_close(window_ptr->content_ptr); + } } /* ------------------------------------------------------------------------- */ @@ -761,8 +835,14 @@ void _wlmtk_window_request_position_and_size( height = BS_MAX(0, height); width = BS_MAX(0, width); - uint32_t serial = wlmtk_surface_request_size( - window_ptr->surface_ptr, width, height); + uint32_t serial; + if (NULL != window_ptr->surface_ptr) { + serial = wlmtk_surface_request_size( + window_ptr->surface_ptr, width, height); + } else if (NULL != window_ptr->content_ptr) { + serial = wlmtk_content_request_size( + window_ptr->content_ptr, width, height); + } wlmtk_pending_update_t *pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); @@ -872,15 +952,36 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) return NULL; } + // FIXME + wlmtk_content_init( + &fake_window_state_ptr->content, + &fake_window_state_ptr->fake_window.fake_surface_ptr->surface, + NULL); + fake_window_state_ptr->fake_window.content_ptr = &fake_window_state_ptr->content; + if (!_wlmtk_window_init( &fake_window_state_ptr->window, NULL, - &fake_window_state_ptr->fake_window.fake_surface_ptr->surface)) { + //wlmtk_surface_element( + // &fake_window_state_ptr->fake_window.fake_surface_ptr->surface) + wlmtk_content_element(&fake_window_state_ptr->content) + )) { wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); return NULL; } fake_window_state_ptr->fake_window.window_ptr = &fake_window_state_ptr->window; + //fake_window_state_ptr->fake_window.window_ptr->surface_ptr = + // &fake_window_state_ptr->fake_window.fake_surface_ptr->surface; + fake_window_state_ptr->fake_window.window_ptr->content_ptr = + &fake_window_state_ptr->content; + + //wlmtk_surface_set_window( + // fake_window_state_ptr->fake_window.window_ptr->surface_ptr, + // fake_window_state_ptr->fake_window.window_ptr); + wlmtk_content_set_window( + &fake_window_state_ptr->content, + fake_window_state_ptr->fake_window.window_ptr); // Extend. We don't save the VMT, since it's for fake only. _wlmtk_window_extend(&fake_window_state_ptr->window, @@ -895,6 +996,9 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) fake_window_ptr, wlmtk_fake_window_state_t, fake_window); _wlmtk_window_fini(&fake_window_state_ptr->window); + + wlmtk_content_fini(&fake_window_state_ptr->content); + free(fake_window_state_ptr); } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 8a1ae74a..d85746c6 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -27,6 +27,7 @@ typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; #include "bordered.h" #include "box.h" +#include "content.h" #include "element.h" #include "resizebar.h" #include "surface.h" @@ -49,6 +50,19 @@ wlmtk_window_t *wlmtk_window_create( wlmtk_env_t *env_ptr, wlmtk_surface_t *surface_ptr); +/** + * Creates a window for the given content. + * + * @param env_ptr + * @param content_ptr + * + * @return Pointer to the window state, or NULL on error. Must be free'd + * by calling @ref wlmtk_window_destroy. + */ +wlmtk_window_t *wlmtk_window_create_content( + wlmtk_env_t *env_ptr, + wlmtk_content_t *content_ptr); + /** * Destroys the window. * @@ -278,6 +292,8 @@ typedef struct { wlmtk_window_t *window_ptr; /** Fake surface, to manipulate the fake window's surface. */ wlmtk_fake_surface_t *fake_surface_ptr; + /** Content, wraps the fake surface. */ + wlmtk_content_t *content_ptr; /** Argument to last @ref wlmtk_window_set_activated call. */ bool activated; diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 993b809b..db04b0c1 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -26,6 +26,8 @@ typedef struct { /** Super class. */ wlmtk_surface_t super_surface; + /** The... other super class. FIXME. */ + wlmtk_content_t super_content; /** Back-link to server. */ wlmaker_server_t *server_ptr; @@ -130,12 +132,13 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, server_ptr); if (NULL == surface_ptr) return NULL; - wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( - server_ptr->env_ptr, &surface_ptr->super_surface); + wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create_content( + server_ptr->env_ptr, &surface_ptr->super_content); if (NULL == wlmtk_window_ptr) { surface_element_destroy(&surface_ptr->super_surface.super_element); return NULL; } + wlmtk_surface_set_window(&surface_ptr->super_surface, wlmtk_window_ptr); return wlmtk_window_ptr; } @@ -167,6 +170,14 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( xdg_tl_surface_ptr->wlr_xdg_surface_ptr = wlr_xdg_surface_ptr; xdg_tl_surface_ptr->server_ptr = server_ptr; + if (!wlmtk_content_init( + &xdg_tl_surface_ptr->super_content, + &xdg_tl_surface_ptr->super_surface, + server_ptr->env_ptr)) { + xdg_toplevel_surface_destroy(xdg_tl_surface_ptr); + return NULL; + } + wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->events.destroy, &xdg_tl_surface_ptr->destroy_listener, @@ -446,8 +457,8 @@ void handle_surface_commit( if (NULL == xdg_tl_surface_ptr->wlr_xdg_surface_ptr) return; - wlmtk_surface_commit_size( - &xdg_tl_surface_ptr->super_surface, + wlmtk_content_commit_size( + &xdg_tl_surface_ptr->super_content, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.configure_serial, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.width, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.height); @@ -469,8 +480,8 @@ void handle_toplevel_request_maximize( wlmtk_xdg_toplevel_surface_t, toplevel_request_maximize_listener); wlmtk_window_request_maximize( - xdg_tl_surface_ptr->super_surface.window_ptr, - !wlmtk_window_maximized(xdg_tl_surface_ptr->super_surface.window_ptr)); + xdg_tl_surface_ptr->super_content.window_ptr, + !wlmtk_window_maximized(xdg_tl_surface_ptr->super_content.window_ptr)); } /* ------------------------------------------------------------------------- */ From af4b753958574dc4b6c287663dc79614fbe3ad0b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 14:20:54 +0200 Subject: [PATCH 329/390] Disambiguates the element's derived virtual methods in wlmtk_container_t. --- src/toolkit/container.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/toolkit/container.c b/src/toolkit/container.c index eb4424a1..e226619c 100644 --- a/src/toolkit/container.c +++ b/src/toolkit/container.c @@ -28,29 +28,29 @@ /* == Declarations ========================================================= */ -static struct wlr_scene_node *element_create_scene_node( +static struct wlr_scene_node *_wlmtk_container_element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr); -static void element_get_dimensions( +static void _wlmtk_container_element_get_dimensions( wlmtk_element_t *element_ptr, int *left_ptr, int *top_ptr, int *right_ptr, int *bottom_ptr); -static void element_get_pointer_area( +static void _wlmtk_container_element_get_pointer_area( wlmtk_element_t *element_ptr, int *left_ptr, int *top_ptr, int *right_ptr, int *bottom_ptr); -static bool element_pointer_motion( +static bool _wlmtk_container_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static bool element_pointer_button( +static bool _wlmtk_container_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); -static void element_pointer_enter( +static void _wlmtk_container_element_pointer_enter( wlmtk_element_t *element_ptr); static void handle_wlr_scene_tree_node_destroy( @@ -65,12 +65,12 @@ static void _wlmtk_container_update_layout(wlmtk_container_t *container_ptr); /** Virtual method table for the container's super class: Element. */ static const wlmtk_element_vmt_t container_element_vmt = { - .create_scene_node = element_create_scene_node, - .get_dimensions = element_get_dimensions, - .get_pointer_area = element_get_pointer_area, - .pointer_motion = element_pointer_motion, - .pointer_button = element_pointer_button, - .pointer_enter = element_pointer_enter, + .create_scene_node = _wlmtk_container_element_create_scene_node, + .get_dimensions = _wlmtk_container_element_get_dimensions, + .get_pointer_area = _wlmtk_container_element_get_pointer_area, + .pointer_motion = _wlmtk_container_element_pointer_motion, + .pointer_button = _wlmtk_container_element_pointer_button, + .pointer_enter = _wlmtk_container_element_pointer_enter, }; /** Default virtual method table. Initializes non-abstract methods. */ @@ -107,7 +107,7 @@ bool wlmtk_container_init_attached( if (!wlmtk_container_init(container_ptr, env_ptr)) return false; container_ptr->super_element.wlr_scene_node_ptr = - element_create_scene_node( + _wlmtk_container_element_create_scene_node( &container_ptr->super_element, root_wlr_scene_tree_ptr); if (NULL == container_ptr->super_element.wlr_scene_node_ptr) { wlmtk_container_fini(container_ptr); @@ -290,7 +290,7 @@ struct wlr_scene_tree *wlmtk_container_wlr_scene_tree( * * @return Pointer to the scene graph API node. */ -struct wlr_scene_node *element_create_scene_node( +struct wlr_scene_node *_wlmtk_container_element_create_scene_node( wlmtk_element_t *element_ptr, struct wlr_scene_tree *wlr_scene_tree_ptr) { @@ -329,7 +329,7 @@ struct wlr_scene_node *element_create_scene_node( * @param right_ptr Rightmost position. Ma be NULL. * @param bottom_ptr Bottommost position. May be NULL. */ -void element_get_dimensions( +void _wlmtk_container_element_get_dimensions( wlmtk_element_t *element_ptr, int *left_ptr, int *top_ptr, @@ -376,7 +376,7 @@ void element_get_dimensions( * @param right_ptr Rightmost position. Ma be NULL. * @param bottom_ptr Bottommost position. May be NULL. */ -void element_get_pointer_area( +void _wlmtk_container_element_get_pointer_area( wlmtk_element_t *element_ptr, int *left_ptr, int *top_ptr, @@ -424,7 +424,7 @@ void element_get_pointer_area( * * @return Whether this container has an element that accepts the emotion. */ -bool element_pointer_motion( +bool _wlmtk_container_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, @@ -448,7 +448,7 @@ bool element_pointer_motion( * * @return true if the button was handled. */ -bool element_pointer_button( +bool _wlmtk_container_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { @@ -517,7 +517,8 @@ bool element_pointer_button( /* ------------------------------------------------------------------------- */ /** Handler for when the pointer enters the area. Nothing for container. */ -void element_pointer_enter(__UNUSED__ wlmtk_element_t *element_ptr) +void _wlmtk_container_element_pointer_enter( + __UNUSED__ wlmtk_element_t *element_ptr) { // Nothing. Do not call parent. } From 045b693fcb8ff1b25e57771f7b834d6e07b762e7 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 14:22:39 +0200 Subject: [PATCH 330/390] Disambiguates the element's derived virtual methods in wlmtk_workspace_t. --- src/toolkit/workspace.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index f85700dd..26854f63 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -83,14 +83,14 @@ static void _wlmtk_workspace_element_get_pointer_area( int *y1_ptr, int *x2_ptr, int *y2_ptr); -static bool element_pointer_motion( +static bool _wlmtk_workspace_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec); -static bool element_pointer_button( +static bool _wlmtk_workspace_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr); -static void element_pointer_leave( +static void _wlmtk_workspace_element_pointer_leave( wlmtk_element_t *element_ptr); static bool pfsm_move_begin(wlmtk_fsm_t *fsm_ptr, void *ud_ptr); @@ -122,9 +122,9 @@ const wlmtk_element_vmt_t workspace_element_vmt = { .destroy = _wlmtk_workspace_element_destroy, .get_dimensions = _wlmtk_workspace_element_get_dimensions, .get_pointer_area = _wlmtk_workspace_element_get_pointer_area, - .pointer_motion = element_pointer_motion, - .pointer_button = element_pointer_button, - .pointer_leave = element_pointer_leave, + .pointer_motion = _wlmtk_workspace_element_pointer_motion, + .pointer_button = _wlmtk_workspace_element_pointer_button, + .pointer_leave = _wlmtk_workspace_element_pointer_leave, }; /** Finite state machine definition for pointer events. */ @@ -396,7 +396,7 @@ void _wlmtk_workspace_element_get_pointer_area( * * @return Always true. */ -bool element_pointer_motion( +bool _wlmtk_workspace_element_pointer_motion( wlmtk_element_t *element_ptr, double x, double y, uint32_t time_msec) @@ -428,7 +428,7 @@ bool element_pointer_motion( * * @return Whether the button event was consumed. */ -bool element_pointer_button( +bool _wlmtk_workspace_element_pointer_button( wlmtk_element_t *element_ptr, const wlmtk_button_event_t *button_event_ptr) { @@ -454,7 +454,7 @@ bool element_pointer_button( * * @param element_ptr */ -void element_pointer_leave( +void _wlmtk_workspace_element_pointer_leave( wlmtk_element_t *element_ptr) { wlmtk_workspace_t *workspace_ptr = BS_CONTAINER_OF( From ae357686876f1013d16557831a1291cb3d3b9725 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 14:48:34 +0200 Subject: [PATCH 331/390] Removes window creation from wlmtk_surface_t. --- src/toolkit/content.c | 4 +++ src/toolkit/surface.c | 1 - src/toolkit/window.c | 75 ++++++++++++++++++++--------------------- src/toolkit/window.h | 13 ------- src/toolkit/workspace.c | 40 +++++++++++++++------- 5 files changed, 68 insertions(+), 65 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 0435c437..52d16604 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -104,6 +104,10 @@ void wlmtk_content_commit_size( wlmtk_surface_commit_size(content_ptr->surface_ptr, serial, width, height); content_ptr->committed_width = width; content_ptr->committed_height = height; + + if (NULL != content_ptr->window_ptr) { + wlmtk_window_serial(content_ptr->window_ptr, serial); + } } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index bf2726b2..08ab39c3 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -162,7 +162,6 @@ void wlmtk_surface_commit_size( wlmtk_container_update_layout( surface_ptr->super_element.parent_container_ptr); } - } /* == Local (static) methods =============================================== */ diff --git a/src/toolkit/window.c b/src/toolkit/window.c index ec11549d..28fbea90 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -230,27 +230,6 @@ static const wlmtk_margin_style_t border_style = { /* == Exported methods ===================================================== */ -/* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create( - wlmtk_env_t *env_ptr, - wlmtk_surface_t *surface_ptr) -{ - wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); - if (NULL == window_ptr) return NULL; - - if (!_wlmtk_window_init( - window_ptr, - env_ptr, - wlmtk_surface_element(surface_ptr))) { - wlmtk_window_destroy(window_ptr); - return NULL; - } - window_ptr->surface_ptr = surface_ptr; - wlmtk_surface_set_window(surface_ptr, window_ptr); - - return window_ptr; -} - /* ------------------------------------------------------------------------- */ wlmtk_window_t *wlmtk_window_create_content( wlmtk_env_t *env_ptr, @@ -1096,11 +1075,11 @@ const bs_test_case_t wlmtk_window_test_cases[] = { void test_create_destroy(bs_test_t *test_ptr) { wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, window_ptr, - fake_surface_ptr->surface.window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, window_ptr, content.window_ptr); wlmtk_window_destroy(window_ptr); } @@ -1110,8 +1089,9 @@ void test_create_destroy(bs_test_t *test_ptr) void test_set_title(bs_test_t *test_ptr) { wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); wlmtk_window_set_title(window_ptr, "Title"); BS_TEST_VERIFY_STREQ( @@ -1133,8 +1113,9 @@ void test_set_title(bs_test_t *test_ptr) void test_request_close(bs_test_t *test_ptr) { wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); wlmtk_window_request_close(window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->request_close_called); @@ -1147,8 +1128,9 @@ void test_request_close(bs_test_t *test_ptr) void test_set_activated(bs_test_t *test_ptr) { wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); wlmtk_window_set_activated(window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); @@ -1164,8 +1146,10 @@ void test_set_activated(bs_test_t *test_ptr) void test_server_side_decorated(bs_test_t *test_ptr) { wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); @@ -1193,15 +1177,19 @@ void test_maximize(bs_test_t *test_ptr) BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); BS_ASSERT(NULL != window_ptr); // Window must be mapped to get maximized: Need workspace dimensions. wlmtk_workspace_map_window(workspace_ptr, window_ptr); // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); - wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); @@ -1227,7 +1215,10 @@ void test_maximize(bs_test_t *test_ptr) // Maximize. wlmtk_window_request_maximize(window_ptr, true); - wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); @@ -1236,11 +1227,17 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); // A second commit: should not overwrite the organic dimension. - wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); // Unmaximize. Restore earlier organic size and position. wlmtk_window_request_maximize(window_ptr, false); - wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index d85746c6..894c3edf 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -37,19 +37,6 @@ typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; extern "C" { #endif // __cplusplus -/** - * Creates a window for the given surface. - * - * @param env_ptr - * @param surface_ptr Will take ownership of surface_ptr. - * - * @return Pointer to the window state, or NULL on error. Must be free'd - * by calling @ref wlmtk_window_destroy. - */ -wlmtk_window_t *wlmtk_window_create( - wlmtk_env_t *env_ptr, - wlmtk_surface_t *surface_ptr); - /** * Creates a window for the given content. * diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 26854f63..97c66dfb 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -650,8 +650,9 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -751,8 +752,9 @@ void test_move(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -797,8 +799,9 @@ void test_unmap_during_move(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -841,11 +844,15 @@ void test_resize(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_ASSERT(NULL != workspace_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_window_t *window_ptr = wlmtk_window_create( - NULL, &fake_surface_ptr->surface); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); BS_ASSERT(NULL != window_ptr); wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); - wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); wlmtk_workspace_map_window(workspace_ptr, window_ptr); @@ -866,7 +873,10 @@ void test_resize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 37, fake_surface_ptr->requested_width); BS_TEST_VERIFY_EQ(test_ptr, 16, fake_surface_ptr->requested_height); // This updates for the given serial. - wlmtk_fake_surface_commit(fake_surface_ptr); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); wlmtk_window_get_size(window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); @@ -901,7 +911,10 @@ void test_activate(bs_test_t *test_ptr) // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_surface_request_size(&fw1_ptr->fake_surface_ptr->surface, 100, 100); - wlmtk_fake_surface_commit(fw1_ptr->fake_surface_ptr); + wlmtk_content_commit_size(fw1_ptr->content_ptr, + fw1_ptr->fake_surface_ptr->serial, + fw1_ptr->fake_surface_ptr->requested_width, + fw1_ptr->fake_surface_ptr->requested_height); wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); @@ -913,7 +926,10 @@ void test_activate(bs_test_t *test_ptr) // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_surface_request_size(&fw2_ptr->fake_surface_ptr->surface, 100, 100); - wlmtk_fake_surface_commit(fw2_ptr->fake_surface_ptr); + wlmtk_content_commit_size(fw2_ptr->content_ptr, + fw2_ptr->fake_surface_ptr->serial, + fw2_ptr->fake_surface_ptr->requested_width, + fw2_ptr->fake_surface_ptr->requested_height); wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); From aca748e00fbe40128532c23c9b2ed64813cb0da9 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 14:51:02 +0200 Subject: [PATCH 332/390] Removes the surface_ptr element from wlmtk_window_t. --- src/toolkit/window.c | 64 ++++++-------------------------------------- 1 file changed, 8 insertions(+), 56 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 28fbea90..8e81952a 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -85,8 +85,6 @@ struct _wlmtk_window_t { /** FIXME: Element. */ wlmtk_element_t *element_ptr; - /** Surface of this window. */ - wlmtk_surface_t *surface_ptr; /** Content of the window. */ wlmtk_content_t *content_ptr; /** Titlebar. */ @@ -437,13 +435,7 @@ void wlmtk_window_get_size( int *height_ptr) { // TODO(kaeser@gubbe.ch): Add decoration, if server-side-decorated. - if (NULL != window_ptr->surface_ptr) { - wlmtk_surface_get_size(window_ptr->surface_ptr, width_ptr, height_ptr); - } else if (NULL != window_ptr->content_ptr) { - wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); - } else { - bs_log(BS_FATAL, "FIXME"); - } + wlmtk_content_get_size(window_ptr->content_ptr, width_ptr, height_ptr); if (NULL != window_ptr->titlebar_ptr) { *height_ptr += titlebar_style.height + margin_style.width; @@ -463,13 +455,7 @@ void wlmtk_window_request_size( int height) { // TODO(kaeser@gubbe.ch): Adjust for decoration size, if server-side. - if (NULL != window_ptr->surface_ptr) { - wlmtk_surface_request_size(window_ptr->surface_ptr, width, height); - } else if (NULL != window_ptr->content_ptr) { - wlmtk_content_request_size(window_ptr->content_ptr, width, height); - } else { - bs_log(BS_FATAL, "FIXME"); - } + wlmtk_content_request_size(window_ptr->content_ptr, width, height); // TODO(kaeser@gubbe.ch): For client surface (eg. a wlr_surface), setting // the size is an asynchronous operation and should be handled as such. @@ -529,16 +515,7 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) if (0 < delta) break; if (pending_update_ptr->serial == serial) { - if (NULL != window_ptr->surface_ptr) { - if (window_ptr->surface_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (window_ptr->surface_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); - } - } else if (NULL != window_ptr->content_ptr && + if (NULL != window_ptr->content_ptr && NULL != window_ptr->content_ptr->surface_ptr) { if (window_ptr->content_ptr->surface_ptr->committed_width != pending_update_ptr->width) { @@ -625,9 +602,6 @@ void _wlmtk_window_fini(wlmtk_window_t *window_ptr) { wlmtk_window_set_server_side_decorated(window_ptr, false); - if (NULL != window_ptr->surface_ptr) { - wlmtk_surface_set_window(window_ptr->surface_ptr, NULL); - } if (NULL != window_ptr->content_ptr) { wlmtk_content_set_window(window_ptr->content_ptr, NULL); } @@ -722,16 +696,7 @@ void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) window_ptr->orig_super_container_vmt.update_layout(container_ptr); - if (NULL != window_ptr->surface_ptr) { - int width; - wlmtk_surface_get_size(window_ptr->surface_ptr, &width, NULL); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_width(window_ptr->titlebar_ptr, width); - } - if (NULL != window_ptr->resizebar_ptr) { - wlmtk_resizebar_set_width(window_ptr->resizebar_ptr, width); - } - } else if (NULL != window_ptr->content_ptr) { + if (NULL != window_ptr->content_ptr) { int width; wlmtk_content_get_size(window_ptr->content_ptr, &width, NULL); if (NULL != window_ptr->titlebar_ptr) { @@ -749,11 +714,7 @@ void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { - if (NULL != window_ptr->surface_ptr) { - wlmtk_surface_set_activated(window_ptr->surface_ptr, activated); - } else if (NULL != window_ptr->content_ptr) { - wlmtk_content_set_activated(window_ptr->content_ptr, activated); - } + wlmtk_content_set_activated(window_ptr->content_ptr, activated); if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); } @@ -763,11 +724,7 @@ void _wlmtk_window_set_activated( /** Default implementation of @ref wlmtk_window_request_close. */ void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) { - if (NULL != window_ptr->surface_ptr) { - wlmtk_surface_request_close(window_ptr->surface_ptr); - } else if (NULL != window_ptr->content_ptr) { - wlmtk_content_request_close(window_ptr->content_ptr); - } + wlmtk_content_request_close(window_ptr->content_ptr); } /* ------------------------------------------------------------------------- */ @@ -815,13 +772,8 @@ void _wlmtk_window_request_position_and_size( width = BS_MAX(0, width); uint32_t serial; - if (NULL != window_ptr->surface_ptr) { - serial = wlmtk_surface_request_size( - window_ptr->surface_ptr, width, height); - } else if (NULL != window_ptr->content_ptr) { - serial = wlmtk_content_request_size( - window_ptr->content_ptr, width, height); - } + serial = wlmtk_content_request_size( + window_ptr->content_ptr, width, height); wlmtk_pending_update_t *pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); From 5b2c335dceb1f34b6e3fed476116b47848566732 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 14:54:51 +0200 Subject: [PATCH 333/390] Renames wlmtk_window_create_content to wlmtk_window_create and aligns parameter order. --- src/toolkit/window.c | 20 ++++++++++---------- src/toolkit/window.h | 6 +++--- src/toolkit/workspace.c | 8 ++++---- src/wlmtk_xdg_toplevel.c | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 8e81952a..5cb9c0a1 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -51,7 +51,7 @@ struct _wlmtk_window_vmt_t { int x, int y, int width, int height); }; -/** Pending positional updates for @ref wlmtk_window_t::surface_ptr. */ +/** Pending positional updates for @ref wlmtk_window_t::content_ptr. */ typedef struct { /** Node within @ref wlmtk_window_t::pending_updates. */ bs_dllist_node_t dlnode; @@ -229,9 +229,9 @@ static const wlmtk_margin_style_t border_style = { /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -wlmtk_window_t *wlmtk_window_create_content( - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr) +wlmtk_window_t *wlmtk_window_create( + wlmtk_content_t *content_ptr, + wlmtk_env_t *env_ptr) { wlmtk_window_t *window_ptr = logged_calloc(1, sizeof(wlmtk_window_t)); if (NULL == window_ptr) return NULL; @@ -1029,7 +1029,7 @@ void test_create_destroy(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, window_ptr, content.window_ptr); @@ -1043,7 +1043,7 @@ void test_set_title(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); wlmtk_window_set_title(window_ptr, "Title"); BS_TEST_VERIFY_STREQ( @@ -1067,7 +1067,7 @@ void test_request_close(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); wlmtk_window_request_close(window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->request_close_called); @@ -1082,7 +1082,7 @@ void test_set_activated(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); wlmtk_window_set_activated(window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); @@ -1100,7 +1100,7 @@ void test_server_side_decorated(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); @@ -1131,7 +1131,7 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); // Window must be mapped to get maximized: Need workspace dimensions. wlmtk_workspace_map_window(workspace_ptr, window_ptr); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 894c3edf..1863d27e 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -46,9 +46,9 @@ extern "C" { * @return Pointer to the window state, or NULL on error. Must be free'd * by calling @ref wlmtk_window_destroy. */ -wlmtk_window_t *wlmtk_window_create_content( - wlmtk_env_t *env_ptr, - wlmtk_content_t *content_ptr); +wlmtk_window_t *wlmtk_window_create( + wlmtk_content_t *content_ptr, + wlmtk_env_t *env_ptr); /** * Destroys the window. diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 97c66dfb..72783b54 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -652,7 +652,7 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); @@ -754,7 +754,7 @@ void test_move(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -801,7 +801,7 @@ void test_unmap_during_move(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); @@ -846,7 +846,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create_content(NULL, &content); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); wlmtk_content_commit_size(&content, diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index db04b0c1..cd398637 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -132,8 +132,8 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, server_ptr); if (NULL == surface_ptr) return NULL; - wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create_content( - server_ptr->env_ptr, &surface_ptr->super_content); + wlmtk_window_t *wlmtk_window_ptr = wlmtk_window_create( + &surface_ptr->super_content, server_ptr->env_ptr); if (NULL == wlmtk_window_ptr) { surface_element_destroy(&surface_ptr->super_surface.super_element); return NULL; From 230ec64e3fd749ba309af5c5e6bc2f4f05be77c4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 19:58:44 +0200 Subject: [PATCH 334/390] Migrates to use content.window_ptr in XDG toplevel. --- src/toolkit/content.c | 5 +++++ src/toolkit/content.h | 10 ++++++++++ src/wlmtk_xdg_toplevel.c | 16 ++++++++-------- src/xdg_decoration.c | 12 ++++++------ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 52d16604..1b49f296 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -24,6 +24,10 @@ /* == Declarations ========================================================= */ +/* == Data ================================================================= */ + +void *wlmtk_content_identifier_ptr = wlmtk_content_init; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -44,6 +48,7 @@ bool wlmtk_content_init( &content_ptr->super_container, wlmtk_surface_element(surface_ptr)); content_ptr->surface_ptr = surface_ptr; + content_ptr->identifier_ptr = wlmtk_content_identifier_ptr; wlmtk_element_set_visible(wlmtk_surface_element(surface_ptr), true); return true; diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 501eb5c0..8bf76541 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -36,6 +36,9 @@ extern "C" { /** State of window content. */ struct _wlmtk_content_t { + /** Temporary: Identifier, to disambiguate from XDG nodes. */ + void *identifier_ptr; + /** Super class of the content: A container, holding surface & popups. */ wlmtk_container_t super_container; /** The principal surface of the content. */ @@ -51,6 +54,13 @@ struct _wlmtk_content_t { int committed_height; }; +/** + * Identifying pointer: Value unique to wlmtk_content. + * + * TODO(kaeser@gubbe.ch): Remove, once migrated to toolkit. + */ +extern void *wlmtk_content_identifier_ptr; + /** * Initializes the content with the given surface. * diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index cd398637..0452f7b1 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -138,7 +138,7 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( surface_element_destroy(&surface_ptr->super_surface.super_element); return NULL; } - wlmtk_surface_set_window(&surface_ptr->super_surface, wlmtk_window_ptr); + wlmtk_content_set_window(&surface_ptr->super_content, wlmtk_window_ptr); return wlmtk_window_ptr; } @@ -217,7 +217,7 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( handle_toplevel_set_title); xdg_tl_surface_ptr->wlr_xdg_surface_ptr->data = - &xdg_tl_surface_ptr->super_surface; + &xdg_tl_surface_ptr->super_content; return xdg_tl_surface_ptr; } @@ -374,7 +374,7 @@ void handle_destroy(struct wl_listener *listener_ptr, wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_surface_t, destroy_listener); // Destroy the window -> also destroys the surface. - wlmtk_window_destroy(xdg_tl_surface_ptr->super_surface.window_ptr); + wlmtk_window_destroy(xdg_tl_surface_ptr->super_content.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -417,7 +417,7 @@ void handle_surface_map( wlmtk_workspace_map_window( wlmtk_workspace_ptr, - xdg_tl_surface_ptr->super_surface.window_ptr); + xdg_tl_surface_ptr->super_content.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -434,7 +434,7 @@ void handle_surface_unmap( wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_surface_t, surface_unmap_listener); - wlmtk_window_t *window_ptr = xdg_tl_surface_ptr->super_surface.window_ptr; + wlmtk_window_t *window_ptr = xdg_tl_surface_ptr->super_content.window_ptr; wlmtk_workspace_unmap_window( wlmtk_workspace_from_container( wlmtk_window_element(window_ptr)->parent_container_ptr), @@ -499,7 +499,7 @@ void handle_toplevel_request_move( listener_ptr, wlmtk_xdg_toplevel_surface_t, toplevel_request_move_listener); - wlmtk_window_request_move(xdg_tl_surface_ptr->super_surface.window_ptr); + wlmtk_window_request_move(xdg_tl_surface_ptr->super_content.window_ptr); } /* ------------------------------------------------------------------------- */ @@ -519,7 +519,7 @@ void handle_toplevel_request_resize( toplevel_request_resize_listener); struct wlr_xdg_toplevel_resize_event *resize_event_ptr = data_ptr; wlmtk_window_request_resize( - xdg_tl_surface_ptr->super_surface.window_ptr, + xdg_tl_surface_ptr->super_content.window_ptr, resize_event_ptr->edges); } @@ -540,7 +540,7 @@ void handle_toplevel_set_title( toplevel_set_title_listener); wlmtk_window_set_title( - xdg_tl_surface_ptr->super_surface.window_ptr, + xdg_tl_surface_ptr->super_content.window_ptr, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->title); } diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 6e68a153..56d65cc7 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -222,7 +222,7 @@ void handle_decoration_request_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; - wlmtk_surface_t *surface_ptr = (wlmtk_surface_t*) + wlmtk_content_t *content_ptr = (wlmtk_content_t*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; enum wlr_xdg_toplevel_decoration_v1_mode mode = @@ -257,14 +257,14 @@ void handle_decoration_request_mode( wlr_xdg_toplevel_decoration_v1_set_mode( decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr, mode); - if (NULL != surface_ptr && - surface_ptr->identifier_ptr == wlmtk_surface_identifier_ptr) { + if (NULL != content_ptr && + content_ptr->identifier_ptr == wlmtk_content_identifier_ptr) { bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, " - "surface %p: Current %d, pending %d, scheduled %d, " + "content %p: Current %d, pending %d, scheduled %d, " "requested %d. Set: %d", decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, - surface_ptr, + content_ptr, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->scheduled_mode, @@ -272,7 +272,7 @@ void handle_decoration_request_mode( mode); wlmtk_window_set_server_side_decorated( - surface_ptr->window_ptr, + content_ptr->window_ptr, mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } else { From c044d9f1e01194a8c1543e6530da4ad18d3f747f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 19:59:41 +0200 Subject: [PATCH 335/390] Removes the type identifier in wlmtk_surface_t. No longer required. --- src/toolkit/surface.c | 3 --- src/toolkit/surface.h | 10 ---------- 2 files changed, 13 deletions(-) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 08ab39c3..1b5f0e32 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -65,8 +65,6 @@ static const wlmtk_element_vmt_t surface_element_vmt = { .pointer_button = _wlmtk_surface_element_pointer_button, }; -void *wlmtk_surface_identifier_ptr = wlmtk_surface_init; - /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -86,7 +84,6 @@ bool wlmtk_surface_init( &surface_ptr->super_element, &surface_element_vmt); surface_ptr->wlr_surface_ptr = wlr_surface_ptr; - surface_ptr->identifier_ptr = wlmtk_surface_identifier_ptr; return true; } diff --git a/src/toolkit/surface.h b/src/toolkit/surface.h index 884f6210..c3cd727a 100644 --- a/src/toolkit/surface.h +++ b/src/toolkit/surface.h @@ -54,9 +54,6 @@ struct _wlmtk_surface_vmt_t { /** State of a `struct wlr_surface`, encapsuled for toolkit. */ struct _wlmtk_surface_t { - /** Temporary: Identifier, to disambiguate from XDG nodes. */ - void *identifier_ptr; - /** Super class of the surface: An element. */ wlmtk_element_t super_element; /** Virtual method table of the super element before extending it. */ @@ -79,13 +76,6 @@ struct _wlmtk_surface_t { int committed_height; }; -/** - * Identifying pointer: Value unique to wlmtk_surface. - * - * TODO(kaeser@gubbe.ch): Remove, once migrated to toolkit. - */ -extern void *wlmtk_surface_identifier_ptr; - /** * Initializes the surface. * From 3ac628f07912f304a8c5b6a7d7da8d5c96c229e8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 20:16:48 +0200 Subject: [PATCH 336/390] Removes the reference to wlmtk_window_t from wlmtk_surface_t. --- src/toolkit/surface.c | 14 +------------- src/toolkit/surface.h | 17 ----------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 1b5f0e32..6d3ccdaa 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -94,14 +94,6 @@ void wlmtk_surface_fini(wlmtk_surface_t *surface_ptr) memset(surface_ptr, 0, sizeof(wlmtk_surface_t)); } -/* ------------------------------------------------------------------------- */ -void wlmtk_surface_set_window( - wlmtk_surface_t *surface_ptr, - wlmtk_window_t *window_ptr) -{ - surface_ptr->window_ptr = window_ptr; -} - /* ------------------------------------------------------------------------- */ wlmtk_surface_vmt_t wlmtk_surface_extend( wlmtk_surface_t *surface_ptr, @@ -141,7 +133,7 @@ void wlmtk_surface_get_size( /* ------------------------------------------------------------------------- */ void wlmtk_surface_commit_size( wlmtk_surface_t *surface_ptr, - uint32_t serial, + __UNUSED__ uint32_t serial, int width, int height) { @@ -151,10 +143,6 @@ void wlmtk_surface_commit_size( surface_ptr->committed_height = height; } - if (NULL != surface_ptr->window_ptr) { - wlmtk_window_serial(surface_ptr->window_ptr, serial); - } - if (NULL != surface_ptr->super_element.parent_container_ptr) { wlmtk_container_update_layout( surface_ptr->super_element.parent_container_ptr); diff --git a/src/toolkit/surface.h b/src/toolkit/surface.h index c3cd727a..728f0eda 100644 --- a/src/toolkit/surface.h +++ b/src/toolkit/surface.h @@ -62,11 +62,6 @@ struct _wlmtk_surface_t { /** The surface's virtual method table. */ wlmtk_surface_vmt_t vmt; - /** - * The window this surface belongs to. Will be set when creating - * the window. - */ - wlmtk_window_t *window_ptr; /** The `struct wlr_surface` wrapped. */ struct wlr_surface *wlr_surface_ptr; @@ -97,18 +92,6 @@ bool wlmtk_surface_init( */ void wlmtk_surface_fini(wlmtk_surface_t *surface_ptr); -/** - * Sets the window for the surface. - * - * Private: Should only be called by Window ctor (a friend). - * - * @param surface_ptr - * @param window_ptr - */ -void wlmtk_surface_set_window( - wlmtk_surface_t *surface_ptr, - wlmtk_window_t *window_ptr); - /** * Extends the surface's virtual methods. * From 4ed339ffab9248984d89a87e757126e8959cf5c0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 20:18:01 +0200 Subject: [PATCH 337/390] Removes committed_[width|height] from wlmtk_content_t. --- src/toolkit/content.c | 2 -- src/toolkit/content.h | 6 ------ 2 files changed, 8 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 1b49f296..46f848be 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -107,8 +107,6 @@ void wlmtk_content_commit_size( int height) { wlmtk_surface_commit_size(content_ptr->surface_ptr, serial, width, height); - content_ptr->committed_width = width; - content_ptr->committed_height = height; if (NULL != content_ptr->window_ptr) { wlmtk_window_serial(content_ptr->window_ptr, serial); diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 8bf76541..ff47f7ba 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -46,12 +46,6 @@ struct _wlmtk_content_t { /** The window this content belongs to. Set when creating the window. */ wlmtk_window_t *window_ptr; - - - /** Committed width of the surface, in pixels. */ - int committed_width; - /** Committed height of the surface, in pixels. */ - int committed_height; }; /** From 2ee27db30ae9d433a22a5ad4c6f61c70c589c0e1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 29 Dec 2023 20:36:15 +0200 Subject: [PATCH 338/390] Fixes a few memory leaks in tests. --- src/toolkit/content.h | 2 +- src/toolkit/window.c | 14 ++++++-------- src/toolkit/workspace.c | 8 ++++++++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/toolkit/content.h b/src/toolkit/content.h index ff47f7ba..9d184ad2 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -41,9 +41,9 @@ struct _wlmtk_content_t { /** Super class of the content: A container, holding surface & popups. */ wlmtk_container_t super_container; + /** The principal surface of the content. */ wlmtk_surface_t *surface_ptr; - /** The window this content belongs to. Set when creating the window. */ wlmtk_window_t *window_ptr; }; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 5cb9c0a1..038c649e 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -883,7 +883,6 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) return NULL; } - // FIXME wlmtk_content_init( &fake_window_state_ptr->content, &fake_window_state_ptr->fake_window.fake_surface_ptr->surface, @@ -893,8 +892,6 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) if (!_wlmtk_window_init( &fake_window_state_ptr->window, NULL, - //wlmtk_surface_element( - // &fake_window_state_ptr->fake_window.fake_surface_ptr->surface) wlmtk_content_element(&fake_window_state_ptr->content) )) { wlmtk_fake_window_destroy(&fake_window_state_ptr->fake_window); @@ -902,14 +899,9 @@ wlmtk_fake_window_t *wlmtk_fake_window_create(void) } fake_window_state_ptr->fake_window.window_ptr = &fake_window_state_ptr->window; - //fake_window_state_ptr->fake_window.window_ptr->surface_ptr = - // &fake_window_state_ptr->fake_window.fake_surface_ptr->surface; fake_window_state_ptr->fake_window.window_ptr->content_ptr = &fake_window_state_ptr->content; - //wlmtk_surface_set_window( - // fake_window_state_ptr->fake_window.window_ptr->surface_ptr, - // fake_window_state_ptr->fake_window.window_ptr); wlmtk_content_set_window( &fake_window_state_ptr->content, fake_window_state_ptr->fake_window.window_ptr); @@ -930,6 +922,12 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) wlmtk_content_fini(&fake_window_state_ptr->content); + if (NULL != fake_window_state_ptr->fake_window.fake_surface_ptr) { + wlmtk_fake_surface_destroy( + fake_window_state_ptr->fake_window.fake_surface_ptr); + fake_window_state_ptr->fake_window.fake_surface_ptr = NULL; + } + free(fake_window_state_ptr); } diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 72783b54..9bff23d7 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -679,6 +679,8 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } @@ -785,6 +787,8 @@ void test_move(bs_test_t *test_ptr) wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } @@ -830,6 +834,8 @@ void test_unmap_during_move(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } @@ -894,6 +900,8 @@ void test_resize(bs_test_t *test_ptr) wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } From 698e94d23f4c564cf3e64f490217c33191987e9f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 30 Dec 2023 22:17:01 +0100 Subject: [PATCH 339/390] Adds the --checkout command as reference, since that's what I usually want. --- dependencies/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index ca079997..95d165fd 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -34,6 +34,7 @@ ENDIF() # https://github.com/phkaeser/libbase # Initialize: git submodule update --init --recursive --merge +# Checkout: git submodule update --checkout --recursive --merge # Update: git submodule update --remote --merge # Update: (cd libbase && git pull) # ADD_SUBDIRECTORY(libbase) From 938415d44061fff0e668ba5404382c05e284ed04 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 30 Dec 2023 22:28:54 +0100 Subject: [PATCH 340/390] Fixes remaining leaks in tests. --- src/toolkit/content.c | 2 ++ src/toolkit/window.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 46f848be..903fee1c 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -179,6 +179,8 @@ void test_init_fini(bs_test_t *test_ptr) wlmtk_element_pointer_motion(element_ptr, 10, 10, 0)); wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fs_ptr); + } /* == End of content.c ===================================================== */ diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 038c649e..9aaf4a7b 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -1032,6 +1032,8 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, window_ptr, content.window_ptr); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); } /* ------------------------------------------------------------------------- */ @@ -1056,6 +1058,8 @@ void test_set_title(bs_test_t *test_ptr) "Unnamed window .*"); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); } /* ------------------------------------------------------------------------- */ @@ -1071,6 +1075,8 @@ void test_request_close(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->request_close_called); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); } /* ------------------------------------------------------------------------- */ @@ -1089,6 +1095,8 @@ void test_set_activated(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, fake_surface_ptr->activated); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); } /* ------------------------------------------------------------------------- */ @@ -1112,6 +1120,8 @@ void test_server_side_decorated(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); } /* ------------------------------------------------------------------------- */ @@ -1202,6 +1212,8 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } From 55d481af0bab4004cfb571e50a2832e8ee087aa2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 30 Dec 2023 22:45:32 +0100 Subject: [PATCH 341/390] Fixes teardown of XDG toplevel window & content. --- src/toolkit/window.c | 1 - src/wlmtk_xdg_toplevel.c | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 9aaf4a7b..d5c58691 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -610,7 +610,6 @@ void _wlmtk_window_fini(wlmtk_window_t *window_ptr) wlmtk_box_remove_element( &window_ptr->box, window_ptr->element_ptr); wlmtk_element_set_visible(window_ptr->element_ptr, false); - // FIXME wlmtk_element_destroy(window_ptr->element_ptr); window_ptr->element_ptr = NULL; } diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 0452f7b1..bcad22d6 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -138,7 +138,6 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( surface_element_destroy(&surface_ptr->super_surface.super_element); return NULL; } - wlmtk_content_set_window(&surface_ptr->super_content, wlmtk_window_ptr); return wlmtk_window_ptr; } @@ -238,6 +237,8 @@ void xdg_toplevel_surface_destroy( wl_list_remove(&xdg_tl_surface_ptr->new_popup_listener.link); wl_list_remove(&xdg_tl_surface_ptr->destroy_listener.link); + wlmtk_content_fini(&xdg_tl_surface_ptr->super_content); + wlmtk_surface_fini(&xdg_tl_surface_ptr->super_surface); free(xdg_tl_surface_ptr); } @@ -373,8 +374,9 @@ void handle_destroy(struct wl_listener *listener_ptr, { wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_surface_t, destroy_listener); - // Destroy the window -> also destroys the surface. + wlmtk_window_destroy(xdg_tl_surface_ptr->super_content.window_ptr); + xdg_toplevel_surface_destroy(xdg_tl_surface_ptr); } /* ------------------------------------------------------------------------- */ From 5b339749ec5eee52cc09926bf67e6f8fbceaa8aa Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 13:45:46 +0100 Subject: [PATCH 342/390] Adds some boilerplate for XDG popup creation. --- src/wlmtk_xdg_popup.c | 36 +++++++++++++++++++++++++++++++++--- src/wlmtk_xdg_popup.h | 33 ++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/wlmtk_xdg_popup.c b/src/wlmtk_xdg_popup.c index a8d51f9e..d7a5c956 100644 --- a/src/wlmtk_xdg_popup.c +++ b/src/wlmtk_xdg_popup.c @@ -25,10 +25,40 @@ /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ -void wlmtk_create_popup( - __UNUSED__ struct wlr_xdg_popup *wlr_xdg_popup_ptr, - __UNUSED__ wlmtk_window_t *window_ptr) +wlmtk_xdg_popup_t *wlmtk_xdg_popup_create( + struct wlr_xdg_popup *wlr_xdg_popup_ptr, + wlmtk_env_t *env_ptr) { + wlmtk_xdg_popup_t *xdg_popup_ptr = logged_calloc( + 1, sizeof(wlmtk_xdg_popup_t)); + if (NULL == xdg_popup_ptr) return NULL; + xdg_popup_ptr->wlr_xdg_popup_ptr = wlr_xdg_popup_ptr; + + if (!wlmtk_surface_init( + &xdg_popup_ptr->surface, + wlr_xdg_popup_ptr->base->surface, + env_ptr)) { + wlmtk_xdg_popup_destroy(xdg_popup_ptr); + return NULL; + } + + if (!wlmtk_content_init( + &xdg_popup_ptr->super_content, + &xdg_popup_ptr->surface, + env_ptr)) { + wlmtk_xdg_popup_destroy(xdg_popup_ptr); + return NULL; + } + + return xdg_popup_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_xdg_popup_destroy(wlmtk_xdg_popup_t *xdg_popup_ptr) +{ + wlmtk_content_fini(&xdg_popup_ptr->super_content); + wlmtk_surface_fini(&xdg_popup_ptr->surface); + free(xdg_popup_ptr); } /* == Local (static) methods =============================================== */ diff --git a/src/wlmtk_xdg_popup.h b/src/wlmtk_xdg_popup.h index ad040758..42a2d450 100644 --- a/src/wlmtk_xdg_popup.h +++ b/src/wlmtk_xdg_popup.h @@ -22,22 +22,45 @@ #include "toolkit/toolkit.h" -/** Forward declaration. */ -struct wlr_xdg_popup; +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE #ifdef __cplusplus extern "C" { #endif // __cplusplus +/** Forward declaration: State of the toolkit's XDG popup. */ +typedef struct _wlmtk_xdg_popup_t wlmtk_xdg_popup_t; + +/** State of toolkit popup. */ +struct _wlmtk_xdg_popup_t { + /** Super class: Content. */ + wlmtk_content_t super_content; + + /** Surface of the popup. */ + wlmtk_surface_t surface; + /** The WLR popup. */ + struct wlr_xdg_popup *wlr_xdg_popup_ptr; +}; + /** * Creates a popup. * * @param wlr_xdg_popup_ptr - * @param window_ptr + * @param env_ptr */ -void wlmtk_create_popup( +wlmtk_xdg_popup_t *wlmtk_xdg_popup_create( struct wlr_xdg_popup *wlr_xdg_popup_ptr, - wlmtk_window_t *window_ptr); + wlmtk_env_t *env_ptr); + +/** + * Destroys the popup. + * + * @param xdg_popup_ptr + */ +void wlmtk_xdg_popup_destroy( + wlmtk_xdg_popup_t *xdg_popup_ptr); #ifdef __cplusplus } // extern "C" From 4132f0954828f0c758adaf664fac68137451ff71 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 14:48:13 +0100 Subject: [PATCH 343/390] Wires up XDG popup creation, and have it working with Chrome. --- src/wlmtk_xdg_popup.c | 102 +++++++++++++++++++++++++++++++++++++++ src/wlmtk_xdg_popup.h | 7 +++ src/wlmtk_xdg_toplevel.c | 19 ++++++++ 3 files changed, 128 insertions(+) diff --git a/src/wlmtk_xdg_popup.c b/src/wlmtk_xdg_popup.c index d7a5c956..dd389fd0 100644 --- a/src/wlmtk_xdg_popup.c +++ b/src/wlmtk_xdg_popup.c @@ -20,8 +20,31 @@ #include "wlmtk_xdg_popup.h" +#define WLR_USE_UNSTABLE +#include +#undef WLR_USE_UNSTABLE + /* == Declarations ========================================================= */ +static struct wlr_scene_node *_wlmtk_xdg_popup_surface_element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr); + +/** Virtual methods for XDG popup surface, for the Element superclass. */ +const wlmtk_element_vmt_t _wlmtk_xdg_popup_surface_element_vmt = { + .create_scene_node = _wlmtk_xdg_popup_surface_element_create_scene_node, +}; + +static void handle_reposition( + struct wl_listener *listener_ptr, + void *data_ptr); +static void handle_destroy( + struct wl_listener *listener_ptr, + void *data_ptr); +static void handle_new_popup( + struct wl_listener *listener_ptr, + void *data_ptr); + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -41,6 +64,9 @@ wlmtk_xdg_popup_t *wlmtk_xdg_popup_create( wlmtk_xdg_popup_destroy(xdg_popup_ptr); return NULL; } + wlmtk_element_extend( + &xdg_popup_ptr->surface.super_element, + &_wlmtk_xdg_popup_surface_element_vmt); if (!wlmtk_content_init( &xdg_popup_ptr->super_content, @@ -50,12 +76,30 @@ wlmtk_xdg_popup_t *wlmtk_xdg_popup_create( return NULL; } + wlmtk_util_connect_listener_signal( + &wlr_xdg_popup_ptr->events.reposition, + &xdg_popup_ptr->reposition_listener, + handle_reposition); + + wlmtk_util_connect_listener_signal( + &wlr_xdg_popup_ptr->base->events.destroy, + &xdg_popup_ptr->destroy_listener, + handle_destroy); + wlmtk_util_connect_listener_signal( + &wlr_xdg_popup_ptr->base->events.new_popup, + &xdg_popup_ptr->new_popup_listener, + handle_new_popup); + return xdg_popup_ptr; } /* ------------------------------------------------------------------------- */ void wlmtk_xdg_popup_destroy(wlmtk_xdg_popup_t *xdg_popup_ptr) { + wl_list_remove(&xdg_popup_ptr->new_popup_listener.link); + wl_list_remove(&xdg_popup_ptr->destroy_listener.link); + wl_list_remove(&xdg_popup_ptr->reposition_listener.link); + wlmtk_content_fini(&xdg_popup_ptr->super_content); wlmtk_surface_fini(&xdg_popup_ptr->surface); free(xdg_popup_ptr); @@ -63,4 +107,62 @@ void wlmtk_xdg_popup_destroy(wlmtk_xdg_popup_t *xdg_popup_ptr) /* == Local (static) methods =============================================== */ +/* ------------------------------------------------------------------------- */ +/** Implements @ref wlmtk_element_vmt_t::create_scene_node. Create node. */ +struct wlr_scene_node *_wlmtk_xdg_popup_surface_element_create_scene_node( + wlmtk_element_t *element_ptr, + struct wlr_scene_tree *wlr_scene_tree_ptr) +{ + wlmtk_xdg_popup_t *xdg_popup_ptr = BS_CONTAINER_OF( + element_ptr, wlmtk_xdg_popup_t, surface.super_element); + + struct wlr_scene_tree *surface_wlr_scene_tree_ptr = + wlr_scene_xdg_surface_create( + wlr_scene_tree_ptr, + xdg_popup_ptr->wlr_xdg_popup_ptr->base); + return &surface_wlr_scene_tree_ptr->node; +} + +/* ------------------------------------------------------------------------- */ +/** Handles repositioning. Yet unimplemented. */ +void handle_reposition( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_popup_t *xdg_popup_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_popup_t, reposition_listener); + + bs_log(BS_WARNING, "Unhandled: reposition on XDG popup %p", xdg_popup_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Handles popup destruction: Removes from parent content, and destroy. */ +void handle_destroy( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_popup_t *xdg_popup_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_popup_t, destroy_listener); + + wlmtk_element_t *element_ptr = wlmtk_content_element( + &xdg_popup_ptr->super_content); + wlmtk_container_remove_element( + element_ptr->parent_container_ptr, + element_ptr); + + wlmtk_xdg_popup_destroy(xdg_popup_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Handles further popups. Yet unimplemented. */ +void handle_new_popup( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_popup_t *xdg_popup_ptr = BS_CONTAINER_OF( + listener_ptr, wlmtk_xdg_popup_t, new_popup_listener); + + bs_log(BS_WARNING, "Unhandled: new_popup on XDG popup %p", xdg_popup_ptr); +} + /* == End of wlmtk_xdg_popup.c ============================================= */ diff --git a/src/wlmtk_xdg_popup.h b/src/wlmtk_xdg_popup.h index 42a2d450..3fe036f6 100644 --- a/src/wlmtk_xdg_popup.h +++ b/src/wlmtk_xdg_popup.h @@ -42,6 +42,13 @@ struct _wlmtk_xdg_popup_t { wlmtk_surface_t surface; /** The WLR popup. */ struct wlr_xdg_popup *wlr_xdg_popup_ptr; + + /** Listener for the `reposition` signal of `wlr_xdg_popup::events` */ + struct wl_listener reposition_listener; + /** Listener for the `destroy` signal of `wlr_xdg_surface::events`. */ + struct wl_listener destroy_listener; + /** Listener for the `new_popup` signal of `wlr_xdg_surface::events`. */ + struct wl_listener new_popup_listener; }; /** diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index bcad22d6..c58cc31a 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -20,6 +20,8 @@ #include "xdg_toplevel.h" +#include "wlmtk_xdg_popup.h" + /* == Declarations ========================================================= */ /** State of the content for an XDG toplevel surface. */ @@ -392,6 +394,23 @@ void handle_new_popup( { wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_surface_t, new_popup_listener); + struct wlr_xdg_popup *wlr_xdg_popup_ptr = data_ptr; + + wlmtk_xdg_popup_t *xdg_popup_ptr = wlmtk_xdg_popup_create( + wlr_xdg_popup_ptr, xdg_tl_surface_ptr->server_ptr->env_ptr); + if (NULL == xdg_popup_ptr) { + bs_log(BS_ERROR, "Failed wlmtk_xdg_popup_create(%p, %p)", + wlr_xdg_popup_ptr, xdg_tl_surface_ptr->server_ptr->env_ptr); + return; + } + + // xdg_tl_surface_ptr->super_content -> super_container + + wlmtk_element_set_visible( + wlmtk_content_element(&xdg_popup_ptr->super_content), true); + wlmtk_container_add_element( + &xdg_tl_surface_ptr->super_content.super_container, + wlmtk_content_element(&xdg_popup_ptr->super_content)); bs_log(BS_WARNING, "FIXME: wlmtk_xdg_toplevel %p, New popup %p", xdg_tl_surface_ptr, data_ptr); From e00829f048281f030be68605a8d813aabb304126 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 14:59:26 +0100 Subject: [PATCH 344/390] Implements new_popup handler for wlmtk_xdg_popup_t. --- src/wlmtk_xdg_popup.c | 24 +++++++++++++++++++++--- src/wlmtk_xdg_toplevel.c | 6 ++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/wlmtk_xdg_popup.c b/src/wlmtk_xdg_popup.c index dd389fd0..87ffc131 100644 --- a/src/wlmtk_xdg_popup.c +++ b/src/wlmtk_xdg_popup.c @@ -154,15 +154,33 @@ void handle_destroy( } /* ------------------------------------------------------------------------- */ -/** Handles further popups. Yet unimplemented. */ +/** Handles further popups. Creates them and adds them to parent's content. */ void handle_new_popup( struct wl_listener *listener_ptr, - __UNUSED__ void *data_ptr) + void *data_ptr) { wlmtk_xdg_popup_t *xdg_popup_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_popup_t, new_popup_listener); + struct wlr_xdg_popup *wlr_xdg_popup_ptr = data_ptr; + + wlmtk_xdg_popup_t *new_xdg_popup_ptr = wlmtk_xdg_popup_create( + wlr_xdg_popup_ptr, + wlmtk_content_element(&xdg_popup_ptr->super_content)->env_ptr); + if (NULL == new_xdg_popup_ptr) { + bs_log(BS_ERROR, "Failed wlmtk_xdg_popup_create(%p, %p)", + wlr_xdg_popup_ptr, + wlmtk_content_element(&xdg_popup_ptr->super_content)->env_ptr); + return; + } + + wlmtk_element_set_visible( + wlmtk_content_element(&new_xdg_popup_ptr->super_content), true); + wlmtk_container_add_element( + &xdg_popup_ptr->super_content.super_container, + wlmtk_content_element(&new_xdg_popup_ptr->super_content)); - bs_log(BS_WARNING, "Unhandled: new_popup on XDG popup %p", xdg_popup_ptr); + bs_log(BS_INFO, "XDG popup %p: New popup %p", + xdg_popup_ptr, new_xdg_popup_ptr); } /* == End of wlmtk_xdg_popup.c ============================================= */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index c58cc31a..832e2c98 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -404,16 +404,14 @@ void handle_new_popup( return; } - // xdg_tl_surface_ptr->super_content -> super_container - wlmtk_element_set_visible( wlmtk_content_element(&xdg_popup_ptr->super_content), true); wlmtk_container_add_element( &xdg_tl_surface_ptr->super_content.super_container, wlmtk_content_element(&xdg_popup_ptr->super_content)); - bs_log(BS_WARNING, "FIXME: wlmtk_xdg_toplevel %p, New popup %p", - xdg_tl_surface_ptr, data_ptr); + bs_log(BS_INFO, "XDG toplevel %p: New popup %p", + xdg_tl_surface_ptr, xdg_popup_ptr); } /* ------------------------------------------------------------------------- */ From 6e45ae8303917ef6c7667b0460774377a64af63b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 15:02:40 +0100 Subject: [PATCH 345/390] Makes the wlmtk_bordered_t border elements go to the bottom of the scene graph API. --- src/toolkit/bordered.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c index b465f062..b2de0aa1 100644 --- a/src/toolkit/bordered.c +++ b/src/toolkit/bordered.c @@ -135,8 +135,9 @@ wlmtk_rectangle_t * _wlmtk_bordered_create_border_rectangle( if (NULL == rectangle_ptr) return NULL; wlmtk_element_set_visible(wlmtk_rectangle_element(rectangle_ptr), true); - wlmtk_container_add_element( + wlmtk_container_add_element_atop( &bordered_ptr->super_container, + NULL, wlmtk_rectangle_element(rectangle_ptr)); return rectangle_ptr; From 457b37df0ecb9825dc0b5558f7023143d4b08ca0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 22:01:49 +0100 Subject: [PATCH 346/390] Fixes issue where popup positions were set directly, and didn't update wlmtk_element_t coordinates. --- src/toolkit/element.c | 24 ++++++++++++++++-------- src/toolkit/element.h | 14 ++++++++++++-- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/toolkit/element.c b/src/toolkit/element.c index b042021a..5a2ff4db 100644 --- a/src/toolkit/element.c +++ b/src/toolkit/element.c @@ -218,6 +218,12 @@ void wlmtk_element_get_position( int *x_ptr, int *y_ptr) { + // The node may have been moved without us noticing... update it. + if (NULL != element_ptr->wlr_scene_node_ptr) { + element_ptr->x = element_ptr->wlr_scene_node_ptr->x; + element_ptr->y = element_ptr->wlr_scene_node_ptr->y; + } + if (NULL != x_ptr) *x_ptr = element_ptr->x; if (NULL != y_ptr) *y_ptr = element_ptr->y; } @@ -228,18 +234,15 @@ void wlmtk_element_set_position( int x, int y) { - // Optimization clause: No need for update, if coordinates didn't change. - if (element_ptr->x == x && element_ptr->y == y) return; + if (NULL != element_ptr->wlr_scene_node_ptr) { + wlr_scene_node_set_position(element_ptr->wlr_scene_node_ptr, x, y); + } + // Optimization clause: Can leave here, if coordinates didn't change. + if (element_ptr->x == x && element_ptr->y == y) return; element_ptr->x = x; element_ptr->y = y; - if (NULL != element_ptr->wlr_scene_node_ptr) { - wlr_scene_node_set_position(element_ptr->wlr_scene_node_ptr, - element_ptr->x, - element_ptr->y); - } - if (NULL != element_ptr->parent_container_ptr) { wlmtk_container_update_pointer_focus( element_ptr->parent_container_ptr); @@ -633,6 +636,11 @@ void test_set_get_position(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 30, element.wlr_scene_node_ptr->x); BS_TEST_VERIFY_EQ(test_ptr, 40, element.wlr_scene_node_ptr->y); + wlr_scene_node_set_position(element.wlr_scene_node_ptr, 50, 60); + wlmtk_element_get_position(&element, &x, &y); + BS_TEST_VERIFY_EQ(test_ptr, 50, x); + BS_TEST_VERIFY_EQ(test_ptr, 60, y); + wlmtk_element_set_parent_container(&element, NULL); wlmtk_element_fini(&element); wlmtk_container_destroy_fake_parent(fake_parent_ptr); diff --git a/src/toolkit/element.h b/src/toolkit/element.h index 9fbe5fd4..26e4867c 100644 --- a/src/toolkit/element.h +++ b/src/toolkit/element.h @@ -123,9 +123,19 @@ struct _wlmtk_element_vmt_t { /** State of an element. */ struct _wlmtk_element_t { - /** X position of the element, relative to the container. */ + /** + * X position of the element in pixels, relative to parent container. + * + * This value may be stale, if @ref wlmtk_element_t::wlr_scene_node_ptr is + * set and had been updated directly. Therefore, consider the value as + * "private", and access only through @ref wlmtk_element_get_position. + */ int x; - /** Y position of the element, relative to the container. */ + /** + * Y position of the element, relative to the container. + * + * Same observations apply as for @ref wlmtk_element_t::x. + */ int y; /** The container this element belongs to, if any. */ From 751fca2b10293ed4897aced4b2764d2d10e83efb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 22:24:24 +0100 Subject: [PATCH 347/390] Fixes layering of margin elements; they should be at the back. --- src/toolkit/box.c | 7 +++++-- src/toolkit/window.c | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/toolkit/box.c b/src/toolkit/box.c index 1106fe8e..3dfcc30a 100644 --- a/src/toolkit/box.c +++ b/src/toolkit/box.c @@ -66,8 +66,11 @@ bool wlmtk_box_init( return false; } wlmtk_element_set_visible(&box_ptr->margin_container.super_element, true); - wlmtk_container_add_element(&box_ptr->super_container, - &box_ptr->margin_container.super_element); + // Keep margins behind the box's elements. + wlmtk_container_add_element_atop( + &box_ptr->super_container, + NULL, + &box_ptr->margin_container.super_element); box_ptr->orientation = orientation; return true; diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d5c58691..d4b4ad09 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -299,6 +299,9 @@ void wlmtk_window_set_server_side_decorated( BS_ASSERT(NULL != window_ptr->titlebar_ptr); wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + // Hm, if the content has a popup that extends over the titlebar area, + // it'll be partially obscured. That will look odd... Well, let's + // address that problem once there's a situation. wlmtk_box_add_element_front( &window_ptr->box, wlmtk_titlebar_element(window_ptr->titlebar_ptr)); From 961f4b747c3864e387591cfb71268167051acde8 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sun, 31 Dec 2023 22:49:47 +0100 Subject: [PATCH 348/390] Adds Firefox to the list of toolkit-enabled Apps. There's an issue with keyboard event handling, though. --- src/xdg_shell.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 41631214..27fbed0f 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -134,7 +134,8 @@ void handle_new_surface(struct wl_listener *listener_ptr, } path_exe[rv] = '\0'; if (0 == strcmp(path_exe, "/usr/bin/foot") || - 0 == strcmp(path_exe, "/opt/google/chrome/chrome")) { + 0 == strcmp(path_exe, "/opt/google/chrome/chrome") || + 0 == strcmp(path_exe, "/usr/lib/firefox-esr/firefox-esr")) { wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", From f143924e914463e5b09ace4910f3be5570ba77c3 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 2 Jan 2024 11:21:02 +0100 Subject: [PATCH 349/390] Updates the README with build & compile instructions. --- README.md | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1fb849f5..a1211d95 100644 --- a/README.md +++ b/README.md @@ -16,22 +16,53 @@ for existing and planned features. ### To configure -```bash -cmake -Dconfig_DOXYGEN_CRITICAL=ON -DCMAKE_INSTALL_PREFIX="${HOME}/.local" -B build/ +Some of Wayland Maker's core dependencies are also in development and are a +moving target, hence these are referred to as git submodules. Build and install +these first (default to `${HOME}/.local`): + +``` bash +git submodule update --init --checkout --recursive --merge +(cd dependencies && + LD_LIBRARY_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)" \ + PKG_CONFIG_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/pkgconfig/:${HOME}/.local/share/pkgconfig/" \ + cmake -DCMAKE_INSTALL_PREFIX:PATH=${HOME}/.local -B build && + LD_LIBRARY_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)" \ + PKG_CONFIG_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/pkgconfig/:${HOME}/.local/share/pkgconfig/" \ + cd build && make) ``` -### To build +With the dependencies installed, proceed to configure wlmaker: ```bash -(cd build && make) +LD_LIBRARY_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)" \ +PKG_CONFIG_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/pkgconfig/:${HOME}/.local/share/pkgconfig/" \ +cmake -Dconfig_DOXYGEN_CRITICAL=ON -Dconfig_TOOLKIT_PROTOTYPE=ON -DCMAKE_INSTALL_PREFIX="${HOME}/.local" -B build/ +``` + +### To build and install + +``` bash +(cd build && \ + LD_LIBRARY_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)" \ + PKG_CONFIG_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/pkgconfig/:${HOME}/.local/share/pkgconfig/" \ + make && \ + make install) ``` -### To install +### To run it + +Since `wlmaker` is in early development, it's not recommended to use it as your +primary compositor. It should run fine in it's own window, though: ```bash -(cd build && make install) +LD_LIBRARY_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)" \ +PKG_CONFIG_PATH="${HOME}/.local/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/pkgconfig/:${HOME}/.local/share/pkgconfig/" \ +${HOME}/.local/bin/wlmaker ``` +Press `ctrl+window+alt T` to open a Terminal (`foot`), and `ctrl-window-alt Q` +to exit. + ## Contributing See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details, and From d64d6e1e35c3feac7491ca0c6c9f356ce055e2e2 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 2 Jan 2024 11:21:52 +0100 Subject: [PATCH 350/390] Updates roadmap with recent updates, and adds list of issues to fix for 0.2. --- doc/ROADMAP.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index 1ec73213..4c4d3992 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -65,6 +65,10 @@ Support for visual effects to improve usability, but not for pure show. ## Plan for 0.2 +* Issues to fix: + * [done] Fix out-of-sync display of server-side decoration and window content when resizing. + * Fix assertion crash when mouse is pressed, then moved to another toplevel, then released. + * Experimental support for Dock Apps * [done] Experimental wayland protocol for Apps to declare icon surfaces. * Surfaces will be shown in either tile container, clip or dock area, @@ -102,9 +106,9 @@ Support for visual effects to improve usability, but not for pure show. * Window actions, based on toolkit. * Move (drag via title bar, or window-alt-click) - * Resize windows, including a resize bar. + * [done] Resize windows, including a resize bar. * Fullscreen windows. - * Maximize windows. + * [done] Maximize windows. * Minimize (*iconify*) windows. * Roll up (*shade*) windows. * Raise window when activated. From 651380695bb90672bf3ae28f14aa96192111f7f0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 2 Jan 2024 13:18:24 +0100 Subject: [PATCH 351/390] Fixes typo. --- src/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.h b/src/config.h index 53076032..562976f3 100644 --- a/src/config.h +++ b/src/config.h @@ -38,9 +38,9 @@ typedef enum { WLMAKER_CONFIG_DECORATION_SUGGEST_CLIENT, /** Mode NONE will be set to SERVER; but other modes left unchanged. */ WLMAKER_CONFIG_DECORATION_SUGGEST_SERVER, - /** Will set all windows to CLIENT, no mather what they requested. */ + /** Will set all windows to CLIENT, no matter what they requested. */ WLMAKER_CONFIG_DECORATION_ENFORCE_CLIENT, - /** Will set all windows to SERVER, no mather what they requested. */ + /** Will set all windows to SERVER, no matter what they requested. */ WLMAKER_CONFIG_DECORATION_ENFORCE_SERVER } wlmaker_config_decoration_t; From 5c52f09405047c45a1e97ae6deac43527f521485 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 2 Jan 2024 13:18:59 +0100 Subject: [PATCH 352/390] Adds details about toolkit-based xdg_shell in roadmap. --- doc/ROADMAP.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index 4c4d3992..d1e99671 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -68,6 +68,8 @@ Support for visual effects to improve usability, but not for pure show. * Issues to fix: * [done] Fix out-of-sync display of server-side decoration and window content when resizing. * Fix assertion crash when mouse is pressed, then moved to another toplevel, then released. + * Hide window border when not having server-side decoration. + * Fix issue with Chrome: Enabling "Use system title and boders" will pick a slightly small decoration. * Experimental support for Dock Apps * [done] Experimental wayland protocol for Apps to declare icon surfaces. @@ -81,6 +83,15 @@ Support for visual effects to improve usability, but not for pure show. * Configurable keyboard map (in code or commandline arg) * Support `xdg_shell`, based on toolkit. + * [done] XDG Popups. + * [done] Move and Resize, compliant with asynchronous ops. + * [done] Maximize. + * [done] Set title. + * fullscreen. + * minimize. + * show window menu. + * set_parent. + * set app ID. * Support `layer_shell`, based on toolkit. From c7338fb7db91286566700073d2509493c1ca97e1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 2 Jan 2024 13:23:33 +0100 Subject: [PATCH 353/390] Enables toolkit window for all client (if configured). --- src/xdg_shell.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/src/xdg_shell.c b/src/xdg_shell.c index 27fbed0f..8168c5ac 100644 --- a/src/xdg_shell.c +++ b/src/xdg_shell.c @@ -103,9 +103,8 @@ void handle_new_surface(struct wl_listener *listener_ptr, __UNUSED__ void *data_ptr) { struct wlr_xdg_surface *wlr_xdg_surface_ptr; - wlmaker_xdg_toplevel_t *xdg_toplevel_ptr; - wlmaker_xdg_shell_t *xdg_shell_ptr = wl_container_of( - listener_ptr, xdg_shell_ptr, new_surface_listener); + wlmaker_xdg_shell_t *xdg_shell_ptr = BS_CONTAINER_OF( + listener_ptr, wlmaker_xdg_shell_t, new_surface_listener); wlr_xdg_surface_ptr = data_ptr; switch (wlr_xdg_surface_ptr->role) { @@ -119,35 +118,21 @@ void handle_new_surface(struct wl_listener *listener_ptr, case WLR_XDG_SURFACE_ROLE_TOPLEVEL: #if defined(ENABLE_TOOLKIT_PROTOTYPE) - pid_t pid; - wl_client_get_credentials( - wlr_xdg_surface_ptr->resource->client, &pid, NULL, NULL); - - char path_procps[PATH_MAX], path_exe[PATH_MAX]; - snprintf(path_procps, sizeof(path_procps), "/proc/%"PRIdMAX"/exe", - (intmax_t)pid); - ssize_t rv = readlink(path_procps, path_exe, sizeof(path_exe)); - if (0 > rv || (size_t)rv >= sizeof(path_exe)) { - bs_log(BS_WARNING | BS_ERRNO, "Failed readlink(%s, %p, %zu)", - path_procps, path_exe, sizeof(path_exe)); - break; - } - path_exe[rv] = '\0'; - if (0 == strcmp(path_exe, "/usr/bin/foot") || - 0 == strcmp(path_exe, "/opt/google/chrome/chrome") || - 0 == strcmp(path_exe, "/usr/lib/firefox-esr/firefox-esr")) { - wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( - wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); - bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", - window_ptr, wlr_xdg_surface_ptr); - break; - } -#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) - xdg_toplevel_ptr = wlmaker_xdg_toplevel_create( + wlmtk_window_t *window_ptr = wlmtk_window_create_from_xdg_toplevel( + wlr_xdg_surface_ptr, xdg_shell_ptr->server_ptr); + bs_log(BS_INFO, "XDG shell: Toolkit window %p for surface %p", + window_ptr, wlr_xdg_surface_ptr); + +#else // defined(ENABLE_TOOLKIT_PROTOTYPE) + + wlmaker_xdg_toplevel_t *xdg_toplevel_ptr = wlmaker_xdg_toplevel_create( xdg_shell_ptr, wlr_xdg_surface_ptr); bs_log(BS_INFO, "XDG shell: Surface %p created toplevel view %p", wlr_xdg_surface_ptr, xdg_toplevel_ptr); + +#endif // defined(ENABLE_TOOLKIT_PROTOTYPE) + break; default: From 5ed946aebc6699d8d7c81401052fa9adb11452de Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Tue, 2 Jan 2024 14:55:33 +0100 Subject: [PATCH 354/390] Adds a sub-container to workspace, as a window layer. --- src/toolkit/window.c | 37 ++++++++++++++++---------- src/toolkit/window.h | 16 ++++++++++++ src/toolkit/workspace.c | 56 ++++++++++++++++++++++++++-------------- src/toolkit/workspace.h | 17 +++--------- src/wlmtk_xdg_toplevel.c | 3 +-- 5 files changed, 79 insertions(+), 50 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index d4b4ad09..47c45f42 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -84,6 +84,8 @@ struct _wlmtk_window_t { /** FIXME: Element. */ wlmtk_element_t *element_ptr; + /** Points to the workspace, if mapped. */ + wlmtk_workspace_t *workspace_ptr; /** Content of the window. */ wlmtk_content_t *content_ptr; @@ -161,7 +163,6 @@ static wlmtk_pending_update_t *_wlmtk_window_prepare_update( static void _wlmtk_window_release_update( wlmtk_window_t *window_ptr, wlmtk_pending_update_t *update_ptr); -static wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr); /* == Data ================================================================= */ @@ -388,6 +389,7 @@ void wlmtk_window_request_maximize( wlmtk_window_t *window_ptr, bool maximized) { + BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); if (window_ptr->maximized == maximized) return; window_ptr->maximized = maximized; @@ -395,7 +397,7 @@ void wlmtk_window_request_maximize( struct wlr_box box; if (window_ptr->maximized) { box = wlmtk_workspace_get_maximize_extents( - _wlmtk_window_workspace(window_ptr)); + wlmtk_window_get_workspace(window_ptr)); } else { box = window_ptr->organic_size; } @@ -539,6 +541,20 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) } } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_set_workspace( + wlmtk_window_t *window_ptr, + wlmtk_workspace_t *workspace_ptr) +{ + window_ptr->workspace_ptr = workspace_ptr; +} + +/* ------------------------------------------------------------------------- */ +wlmtk_workspace_t *wlmtk_window_get_workspace(wlmtk_window_t *window_ptr) +{ + return window_ptr->workspace_ptr; +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -673,7 +689,7 @@ bool _wlmtk_window_element_pointer_button( element_ptr, wlmtk_window_t, super_bordered.super_container.super_element); // We shouldn't receive buttons when not mapped. - wlmtk_workspace_t *workspace_ptr = _wlmtk_window_workspace(window_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_window_get_workspace(window_ptr); wlmtk_workspace_activate_window(workspace_ptr, window_ptr); wlmtk_workspace_raise_window(workspace_ptr, window_ptr); @@ -740,16 +756,18 @@ void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) /** Default implementation of @ref wlmtk_window_request_move. */ void _wlmtk_window_request_move(wlmtk_window_t *window_ptr) { + BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); wlmtk_workspace_begin_window_move( - _wlmtk_window_workspace(window_ptr), window_ptr); + wlmtk_window_get_workspace(window_ptr), window_ptr); } /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_resize. */ void _wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) { + BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); wlmtk_workspace_begin_window_resize( - _wlmtk_window_workspace(window_ptr), window_ptr, edges); + wlmtk_window_get_workspace(window_ptr), window_ptr, edges); } /* ------------------------------------------------------------------------- */ @@ -833,15 +851,6 @@ void _wlmtk_window_release_update( bs_dllist_push_front(&window_ptr->available_updates, &update_ptr->dlnode); } -/* ------------------------------------------------------------------------- */ -/** Returns the workspace of the (mapped) window. */ -wlmtk_workspace_t *_wlmtk_window_workspace(wlmtk_window_t *window_ptr) -{ - BS_ASSERT(NULL != wlmtk_window_element(window_ptr)->parent_container_ptr); - return wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr); -} - /* == Implementation of the fake window ==================================== */ static void _wlmtk_fake_window_set_activated( diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 1863d27e..2685bbf0 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -32,6 +32,7 @@ typedef struct _wlmtk_window_vmt_t wlmtk_window_vmt_t; #include "resizebar.h" #include "surface.h" #include "titlebar.h" +#include "workspace.h" #ifdef __cplusplus extern "C" { @@ -271,6 +272,21 @@ void wlmtk_window_request_position_and_size( */ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial); +/** + * Sets @ref wlmtk_window_t::workspace_ptr. + * + * Protected method, to be called only from @ref wlmtk_workspace_t. + * + * @param window_ptr + * @param workspace_ptr + */ +void wlmtk_window_set_workspace( + wlmtk_window_t *window_ptr, + wlmtk_workspace_t *workspace_ptr); + +/** @return The value of @ref wlmtk_window_t::workspace_ptr. */ +wlmtk_workspace_t *wlmtk_window_get_workspace(wlmtk_window_t *window_ptr); + /* ------------------------------------------------------------------------- */ /** State of the fake window, for tests. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 9bff23d7..1bcca358 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -30,6 +30,13 @@ /* == Declarations ========================================================= */ +// fullscreen: a container, on top of all. +// -> workspace_make_fullscreen(workspace_ptr, window_ptr) +// => removes from the main container +// => adds to the fullscreen container +// => sets the window to fullscreen mode +// => activates the window. Request routing will go there *always*. + /** State of the workspace. */ struct _wlmtk_workspace_t { /** Superclass: Container. */ @@ -40,6 +47,9 @@ struct _wlmtk_workspace_t { /** Current FSM state. */ wlmtk_fsm_t fsm; + /** Container that holds the windows, ie. the window layer. */ + wlmtk_container_t window_container; + /** The activated window. */ wlmtk_window_t *activated_window_ptr; @@ -160,6 +170,17 @@ wlmtk_workspace_t *wlmtk_workspace_create( &workspace_ptr->super_container.super_element, &workspace_element_vmt); + if (!wlmtk_container_init(&workspace_ptr->window_container, env_ptr)) { + wlmtk_workspace_destroy(workspace_ptr); + return NULL; + } + wlmtk_element_set_visible( + &workspace_ptr->window_container.super_element, + true); + wlmtk_container_add_element( + &workspace_ptr->super_container, + &workspace_ptr->window_container.super_element); + wlmtk_fsm_init(&workspace_ptr->fsm, pfsm_transitions, PFSMS_PASSTHROUGH); return workspace_ptr; } @@ -167,6 +188,13 @@ wlmtk_workspace_t *wlmtk_workspace_create( /* ------------------------------------------------------------------------- */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) { + if (NULL != workspace_ptr->window_container.super_element.parent_container_ptr) { + wlmtk_container_remove_element( + &workspace_ptr->super_container, + &workspace_ptr->window_container.super_element); + } + wlmtk_container_fini(&workspace_ptr->window_container); + wlmtk_container_fini(&workspace_ptr->super_container); free(workspace_ptr); } @@ -200,8 +228,9 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, { wlmtk_element_set_visible(wlmtk_window_element(window_ptr), true); wlmtk_container_add_element( - &workspace_ptr->super_container, + &workspace_ptr->window_container, wlmtk_window_element(window_ptr)); + wlmtk_window_set_workspace(window_ptr, workspace_ptr); wlmtk_workspace_activate_window(workspace_ptr, window_ptr); } @@ -212,8 +241,8 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, { bool need_activation = false; - BS_ASSERT(workspace_ptr == wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr)); + BS_ASSERT(&workspace_ptr->window_container == + wlmtk_window_element(window_ptr)->parent_container_ptr); if (workspace_ptr->grabbed_window_ptr == window_ptr) { wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); @@ -227,13 +256,14 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); wlmtk_container_remove_element( - &workspace_ptr->super_container, + &workspace_ptr->window_container, wlmtk_window_element(window_ptr)); + wlmtk_window_set_workspace(window_ptr, NULL); if (need_activation) { // FIXME: What about raising? bs_dllist_node_t *dlnode_ptr = - workspace_ptr->super_container.elements.head_ptr; + workspace_ptr->window_container.elements.head_ptr; if (NULL != dlnode_ptr) { wlmtk_element_t *element_ptr = wlmtk_element_from_dlnode(dlnode_ptr); wlmtk_window_t *window_ptr = wlmtk_window_from_element(element_ptr); @@ -242,15 +272,6 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, } } -/* ------------------------------------------------------------------------- */ -wlmtk_workspace_t *wlmtk_workspace_from_container( - wlmtk_container_t *container_ptr) -{ - BS_ASSERT(container_ptr->super_element.vmt.destroy == - _wlmtk_workspace_element_destroy); - return BS_CONTAINER_OF(container_ptr, wlmtk_workspace_t, super_container); -} - /* ------------------------------------------------------------------------- */ bool wlmtk_workspace_motion( wlmtk_workspace_t *workspace_ptr, @@ -337,7 +358,7 @@ void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { - wlmtk_container_raise_element_to_top(&workspace_ptr->super_container, + wlmtk_container_raise_element_to_top(&workspace_ptr->window_container, wlmtk_window_element(window_ptr)); } @@ -614,11 +635,6 @@ void test_create_destroy(bs_test_t *test_ptr) NULL, fake_parent_ptr->wlr_scene_tree_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); - BS_TEST_VERIFY_EQ( - test_ptr, - workspace_ptr, - wlmtk_workspace_from_container(&workspace_ptr->super_container)); - struct wlr_box box = { .x = -10, .y = -20, .width = 100, .height = 200 }; wlmtk_workspace_set_extents(workspace_ptr, &box); int x1, y1, x2, y2; diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 0859f892..300a5fab 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -20,6 +20,9 @@ #ifndef __WLMTK_WORKSPACE_H__ #define __WLMTK_WORKSPACE_H__ +/** State of the workspace. */ +typedef struct _wlmtk_workspace_t wlmtk_workspace_t; + #include "container.h" #include "window.h" @@ -27,9 +30,6 @@ extern "C" { #endif // __cplusplus -/** State of the workspace. */ -typedef struct _wlmtk_workspace_t wlmtk_workspace_t; - /** Forward declaration. */ struct wlr_pointer_button_event; /** Forward declaration. */ @@ -95,17 +95,6 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); -/** - * Type conversion: Returns the @ref wlmtk_workspace_t from the container_ptr - * pointing to wlmtk_workspace_t::super_container. - * - * Asserts that the container is indeed from a wlmtk_workspace_t. - * - * @return Pointer to the workspace. - */ -wlmtk_workspace_t *wlmtk_workspace_from_container( - wlmtk_container_t *container_ptr); - /** * Handles a motion event. * diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 832e2c98..cf70c0c3 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -455,8 +455,7 @@ void handle_surface_unmap( wlmtk_window_t *window_ptr = xdg_tl_surface_ptr->super_content.window_ptr; wlmtk_workspace_unmap_window( - wlmtk_workspace_from_container( - wlmtk_window_element(window_ptr)->parent_container_ptr), + wlmtk_window_get_workspace(window_ptr), window_ptr); } From 89abe9de751ee1020aa08751431fa674421d5e44 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 4 Jan 2024 21:00:55 +0100 Subject: [PATCH 355/390] Adds code to verify listeners are called in order. Yay, they are../build/labwc -C . --- src/toolkit/util.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ src/toolkit/util.h | 4 ++++ 2 files changed, 57 insertions(+) diff --git a/src/toolkit/util.c b/src/toolkit/util.c index 5521e0b4..a75a3e3a 100644 --- a/src/toolkit/util.c +++ b/src/toolkit/util.c @@ -32,4 +32,57 @@ void wlmtk_util_connect_listener_signal( wl_signal_add(signal_ptr, listener_ptr); } +/* == Unit tests =========================================================== */ + +static void test_listener(bs_test_t *test_ptr); + +const bs_test_case_t wlmtk_util_test_cases[] = { + { 1, "listener", test_listener }, + { 0, NULL, NULL } +}; + +/** Struct for testing listener code. */ +typedef struct { + struct wl_listener listener; + int data; +} _wlmtk_util_listener; + +static void _wlmtk_util_listener_handler( + struct wl_listener *listener_ptr, + void *data_ptr); + +/* ------------------------------------------------------------------------- */ +/** A test to verify listener handlers are called in order of subscription. */ +static void test_listener(bs_test_t *test_ptr) +{ + struct wl_signal signal; + _wlmtk_util_listener l1 = {}, l2 = {}; + int i = 0; + + wl_signal_init(&signal); + wlmtk_util_connect_listener_signal( + &signal, &l1.listener, _wlmtk_util_listener_handler); + + BS_TEST_VERIFY_EQ(test_ptr, 0, l1.data); + wl_signal_emit(&signal, &i); + BS_TEST_VERIFY_EQ(test_ptr, 1, l1.data); + + wlmtk_util_connect_listener_signal( + &signal, &l2.listener, _wlmtk_util_listener_handler); + wl_signal_emit(&signal, &i); + BS_TEST_VERIFY_EQ(test_ptr, 2, l1.data); + BS_TEST_VERIFY_EQ(test_ptr, 3, l2.data); +} + +/** Test handler for the listener. */ +void _wlmtk_util_listener_handler( + struct wl_listener *listener_ptr, + void *data_ptr) +{ + _wlmtk_util_listener *wlmtk_util_listener_ptr = BS_CONTAINER_OF( + listener_ptr, _wlmtk_util_listener, listener); + int *i_ptr = data_ptr; + wlmtk_util_listener_ptr->data = ++(*i_ptr); +} + /* == End of util.c ======================================================== */ diff --git a/src/toolkit/util.h b/src/toolkit/util.h index 3a58aad8..f150d263 100644 --- a/src/toolkit/util.h +++ b/src/toolkit/util.h @@ -20,6 +20,7 @@ #ifndef __WLMTK_UTIL_H__ #define __WLMTK_UTIL_H__ +#include #include #ifdef __cplusplus @@ -43,6 +44,9 @@ void wlmtk_util_connect_listener_signal( struct wl_listener *listener_ptr, void (*notifier_func)(struct wl_listener *, void *)); +/** Unit test cases. */ +extern const bs_test_case_t wlmtk_util_test_cases[]; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus From e56b715267bceadde8e053538144e209a98df46f Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 19:21:45 +0100 Subject: [PATCH 356/390] Adds wlmtk_util test cases. --- src/toolkit/toolkit.h | 1 + src/toolkit/toolkit_test.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/toolkit/toolkit.h b/src/toolkit/toolkit.h index 1c1edf29..a150fe88 100644 --- a/src/toolkit/toolkit.h +++ b/src/toolkit/toolkit.h @@ -47,6 +47,7 @@ #include "titlebar.h" #include "titlebar_button.h" #include "titlebar_title.h" +#include "util.h" #include "window.h" #include "workspace.h" diff --git a/src/toolkit/toolkit_test.c b/src/toolkit/toolkit_test.c index 886bc141..f34355f9 100644 --- a/src/toolkit/toolkit_test.c +++ b/src/toolkit/toolkit_test.c @@ -36,6 +36,7 @@ const bs_test_set_t toolkit_tests[] = { { 1, "titlebar", wlmtk_titlebar_test_cases }, { 1, "titlebar_button", wlmtk_titlebar_button_test_cases }, { 1, "titlebar_title", wlmtk_titlebar_title_test_cases }, + { 1, "util", wlmtk_util_test_cases }, { 1, "window", wlmtk_window_test_cases }, { 1, "workspace", wlmtk_workspace_test_cases }, { 1, "primitives", wlmaker_primitives_test_cases }, From c75008e810e16604f128d9a27dab6143e24a5ddf Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 19:42:22 +0100 Subject: [PATCH 357/390] Adds a few doxygen fixes. --- src/toolkit/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/toolkit/util.c b/src/toolkit/util.c index a75a3e3a..92419400 100644 --- a/src/toolkit/util.c +++ b/src/toolkit/util.c @@ -43,7 +43,9 @@ const bs_test_case_t wlmtk_util_test_cases[] = { /** Struct for testing listener code. */ typedef struct { + /** Listener. */ struct wl_listener listener; + /** Data. */ int data; } _wlmtk_util_listener; From df58d300b1ca17c03d652dab8b5ee7d185905758 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 19:46:07 +0100 Subject: [PATCH 358/390] Documents an issue when resizing. --- doc/ROADMAP.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index d1e99671..52977727 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -70,6 +70,7 @@ Support for visual effects to improve usability, but not for pure show. * Fix assertion crash when mouse is pressed, then moved to another toplevel, then released. * Hide window border when not having server-side decoration. * Fix issue with Chrome: Enabling "Use system title and boders" will pick a slightly small decoration. + * Fix issue on resizing: When moving the mouse too quickly, focus is lost and the resizing stops. * Experimental support for Dock Apps * [done] Experimental wayland protocol for Apps to declare icon surfaces. From 4072f5e1d921c9a8eda8c1498b3981d5d8166acb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 19:47:03 +0100 Subject: [PATCH 359/390] Adds implementation for changing windows to fullscreen. Tests pending. --- doc/ROADMAP.md | 2 +- src/toolkit/content.c | 15 ++++++ src/toolkit/content.h | 42 ++++++++++++++++ src/toolkit/window.c | 100 ++++++++++++++++++++++++++++++++------- src/toolkit/window.h | 44 +++++++++++++++++ src/toolkit/workspace.c | 93 ++++++++++++++++++++++++++++++++---- src/toolkit/workspace.h | 28 +++++++++++ src/wlmaker.c | 19 ++++++-- src/wlmtk_xdg_toplevel.c | 31 ++++++++++++ 9 files changed, 343 insertions(+), 31 deletions(-) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index 52977727..8574ae81 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -88,7 +88,7 @@ Support for visual effects to improve usability, but not for pure show. * [done] Move and Resize, compliant with asynchronous ops. * [done] Maximize. * [done] Set title. - * fullscreen. + * [done] fullscreen. * minimize. * show window menu. * set_parent. diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 903fee1c..259c7089 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -67,6 +67,21 @@ void wlmtk_content_fini( memset(content_ptr, 0, sizeof(wlmtk_content_t)); } +/* ------------------------------------------------------------------------- */ +wlmtk_content_vmt_t wlmtk_content_extend( + wlmtk_content_t *content_ptr, + const wlmtk_content_vmt_t *content_vmt_ptr) +{ + wlmtk_content_vmt_t orig_vmt = content_ptr->vmt; + + if (NULL != content_vmt_ptr->request_fullscreen) { + content_ptr->vmt.request_fullscreen = + content_vmt_ptr->request_fullscreen; + } + + return orig_vmt; +} + /* ------------------------------------------------------------------------- */ uint32_t wlmtk_content_request_size( wlmtk_content_t *content_ptr, diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 9d184ad2..65a1b469 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -23,6 +23,8 @@ /** Forward declaration: Content state. */ typedef struct _wlmtk_content_t wlmtk_content_t; +/** Forward declaration: Content virtual method table. */ +typedef struct _wlmtk_content_vmt_t wlmtk_content_vmt_t; /** Forward declaration: Window. */ typedef struct _wlmtk_window_t wlmtk_window_t ;/** Forward declaration: State of a toolkit's WLR surface. */ @@ -34,6 +36,24 @@ typedef struct _wlmtk_surface_t wlmtk_surface_t; extern "C" { #endif // __cplusplus +/** Virtual method table of @ref wlmtk_content_t. */ +struct _wlmtk_content_vmt_t { + /** + * Requests the content to be set to fullscreen mode. + * + * Some contents may adjust the decoration suitably. Once the content has + * changed to fullscreen mode (potentially an asynchronous operation), + * @ref wlmtk_window_commit_fullscreen ought to be called, if the content + * belongs to a window. + * + * @param content_ptr + * @param fullscreen + * + * @return XDG toplevel configuration serial. + */ + uint32_t (*request_fullscreen)(wlmtk_content_t *content_ptr, bool fullscreen); +}; + /** State of window content. */ struct _wlmtk_content_t { /** Temporary: Identifier, to disambiguate from XDG nodes. */ @@ -41,6 +61,8 @@ struct _wlmtk_content_t { /** Super class of the content: A container, holding surface & popups. */ wlmtk_container_t super_container; + /** Virtual method table of the content. */ + wlmtk_content_vmt_t vmt; /** The principal surface of the content. */ wlmtk_surface_t *surface_ptr; @@ -77,12 +99,32 @@ bool wlmtk_content_init( void wlmtk_content_fini( wlmtk_content_t *content_ptr); +/** + * Extends the content by specifying virtual methods. + * + * @param content_ptr + * @param content_vmt_ptr + * + * @return The original virtual method table. + */ +wlmtk_content_vmt_t wlmtk_content_extend( + wlmtk_content_t *content_ptr, + const wlmtk_content_vmt_t *content_vmt_ptr); + /** Requests size: Forwards to @ref wlmtk_surface_request_size. */ uint32_t wlmtk_content_request_size( wlmtk_content_t *content_ptr, int width, int height); +/** Requests fullscreen mode. */ +static inline uint32_t wlmtk_content_request_fullscreen( + wlmtk_content_t *content_ptr, + bool fullscreen) { + if (NULL == content_ptr->vmt.request_fullscreen) return 0; + return content_ptr->vmt.request_fullscreen(content_ptr, fullscreen); +} + /** * Sets the window for the content. * diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 47c45f42..55aa722c 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -108,6 +108,16 @@ struct _wlmtk_window_t { struct wlr_box organic_size; /** Whether the window has been requested as maximized. */ bool maximized; + /** Whether the window has been requested as fullscreen. */ + bool fullscreen; + /** + * Whether an "inorganic" sizing operation is in progress, and thus size + * changes should not be recorded in @ref wlmtk_window_t::organic_size. + * + * This is eg. between @ref wlmtk_window_request_fullscreen and + * @ref wlmtk_window_commit_fullscreen. + */ + bool inorganic_sizing; /** * Stores whether the window is server-side decorated. @@ -392,6 +402,7 @@ void wlmtk_window_request_maximize( BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); if (window_ptr->maximized == maximized) return; + window_ptr->inorganic_sizing = maximized; window_ptr->maximized = maximized; struct wlr_box box; @@ -412,6 +423,71 @@ bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) return window_ptr->maximized; } +/* ------------------------------------------------------------------------- */ +void wlmtk_window_request_fullscreen( + wlmtk_window_t *window_ptr, + bool fullscreen) +{ + struct wlr_box box; + uint32_t serial; + wlmtk_pending_update_t *pending_update_ptr; + + // Must be mapped.x + BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); + + // FIXME: Oh gosh, this is ugly. + window_ptr->inorganic_sizing = fullscreen; + if (fullscreen) { + box = wlmtk_workspace_get_fullscreen_extents( + wlmtk_window_get_workspace(window_ptr)); + serial = wlmtk_content_request_size( + window_ptr->content_ptr, box.width, box.height); + pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = box.x; + pending_update_ptr->y = box.y; + pending_update_ptr->width = box.width; + pending_update_ptr->height = box.height; + + } else { + + wlmtk_window_set_server_side_decorated(window_ptr, true); + box = window_ptr->organic_size; + _wlmtk_window_request_position_and_size( + window_ptr, box.x, box.y, box.width, box.height); + } + + serial = wlmtk_content_request_fullscreen( + window_ptr->content_ptr, fullscreen); + pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); + pending_update_ptr->serial = serial; + pending_update_ptr->x = box.x; + pending_update_ptr->y = box.y; + pending_update_ptr->width = box.width; + pending_update_ptr->height = box.height; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_window_commit_fullscreen( + wlmtk_window_t *window_ptr, + bool fullscreen) +{ + // Guard clause: Nothing to do if we're already there. + if (window_ptr->fullscreen == fullscreen) return; + + wlmtk_window_set_server_side_decorated(window_ptr, !fullscreen); + window_ptr->fullscreen = fullscreen; + + wlmtk_workspace_window_to_fullscreen( + wlmtk_window_get_workspace(window_ptr), window_ptr, fullscreen); +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_is_fullscreen(wlmtk_window_t *window_ptr) +{ + return window_ptr->fullscreen; +} + /* ------------------------------------------------------------------------- */ void wlmtk_window_request_move(wlmtk_window_t *window_ptr) { @@ -504,7 +580,7 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) { bs_dllist_node_t *dlnode_ptr; - if (!window_ptr->maximized && + if (!window_ptr->inorganic_sizing && NULL == window_ptr->pending_updates.head_ptr) { wlmtk_window_get_size(window_ptr, &window_ptr->organic_size.width, @@ -519,20 +595,6 @@ void wlmtk_window_serial(wlmtk_window_t *window_ptr, uint32_t serial) int32_t delta = pending_update_ptr->serial - serial; if (0 < delta) break; - if (pending_update_ptr->serial == serial) { - if (NULL != window_ptr->content_ptr && - NULL != window_ptr->content_ptr->surface_ptr) { - if (window_ptr->content_ptr->surface_ptr->committed_width != - pending_update_ptr->width) { - bs_log(BS_ERROR, "FIXME: width mismatch!"); - } - if (window_ptr->content_ptr->surface_ptr->committed_height != - pending_update_ptr->height) { - bs_log(BS_ERROR, "FIXME: height mismatch!"); - } - } - } - wlmtk_element_set_position( wlmtk_window_element(window_ptr), pending_update_ptr->x, @@ -691,7 +753,10 @@ bool _wlmtk_window_element_pointer_button( // We shouldn't receive buttons when not mapped. wlmtk_workspace_t *workspace_ptr = wlmtk_window_get_workspace(window_ptr); wlmtk_workspace_activate_window(workspace_ptr, window_ptr); - wlmtk_workspace_raise_window(workspace_ptr, window_ptr); + + if (!window_ptr->fullscreen) { + wlmtk_workspace_raise_window(workspace_ptr, window_ptr); + } return window_ptr->orig_super_element_vmt.pointer_button( element_ptr, button_event_ptr); @@ -791,8 +856,7 @@ void _wlmtk_window_request_position_and_size( height = BS_MAX(0, height); width = BS_MAX(0, width); - uint32_t serial; - serial = wlmtk_content_request_size( + uint32_t serial = wlmtk_content_request_size( window_ptr->content_ptr, width, height); wlmtk_pending_update_t *pending_update_ptr = diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 2685bbf0..134b2e6a 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -219,6 +219,50 @@ void wlmtk_window_request_size( int width, int height); +/** + * Requests the window to be made fullscreen (or stops so). + * + * Requires the window to be mapped (to a workspace). This may be implemented + * as an asynchronous operation. Once the window content is ready, it should + * call @ref wlmtk_window_commit_fullscreen to complete the operation. + * + * @param window_ptr + * @param fullscreen Whether to enable fullscreen mode. + */ +void wlmtk_window_request_fullscreen( + wlmtk_window_t *window_ptr, + bool fullscreen); + +/** + * Commits the fullscreen mode for the window. + * + * This is the "commit" part of the potentially asynchronous operation. To be + * called by @ref wlmtk_content_t, after @ref wlmtk_content_request_fullscreen + * has completed by the client. + * + * The call is idempotent: Once the window is committed, further calls with + * the same `fullscreen` value will return straight away. + * + * @param window_ptr + * @param fullscreen + */ +void wlmtk_window_commit_fullscreen( + wlmtk_window_t *window_ptr, + bool fullscreen); + +/** + * Returns whether the window is currently in fullscreen mode. + * + * Will return the state after @ref wlmtk_window_commit_fullscreen has + * completed. + * + * @param window_ptr + * + * @return Whether it's in fullscreen mode or not. + */ +bool wlmtk_window_is_fullscreen(wlmtk_window_t *window_ptr); + + /** * Returns the current position and size of the window. * diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 1bcca358..d15a4e5d 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -30,13 +30,6 @@ /* == Declarations ========================================================= */ -// fullscreen: a container, on top of all. -// -> workspace_make_fullscreen(workspace_ptr, window_ptr) -// => removes from the main container -// => adds to the fullscreen container -// => sets the window to fullscreen mode -// => activates the window. Request routing will go there *always*. - /** State of the workspace. */ struct _wlmtk_workspace_t { /** Superclass: Container. */ @@ -49,6 +42,8 @@ struct _wlmtk_workspace_t { /** Container that holds the windows, ie. the window layer. */ wlmtk_container_t window_container; + /** Container that holds the fullscreen elements. Should have only one. */ + wlmtk_container_t fullscreen_container; /** The activated window. */ wlmtk_window_t *activated_window_ptr; @@ -181,6 +176,17 @@ wlmtk_workspace_t *wlmtk_workspace_create( &workspace_ptr->super_container, &workspace_ptr->window_container.super_element); + if (!wlmtk_container_init(&workspace_ptr->fullscreen_container, env_ptr)) { + wlmtk_workspace_destroy(workspace_ptr); + return NULL; + } + wlmtk_element_set_visible( + &workspace_ptr->fullscreen_container.super_element, + true); + wlmtk_container_add_element( + &workspace_ptr->super_container, + &workspace_ptr->fullscreen_container.super_element); + wlmtk_fsm_init(&workspace_ptr->fsm, pfsm_transitions, PFSMS_PASSTHROUGH); return workspace_ptr; } @@ -188,6 +194,13 @@ wlmtk_workspace_t *wlmtk_workspace_create( /* ------------------------------------------------------------------------- */ void wlmtk_workspace_destroy(wlmtk_workspace_t *workspace_ptr) { + if (NULL != workspace_ptr->fullscreen_container.super_element.parent_container_ptr) { + wlmtk_container_remove_element( + &workspace_ptr->super_container, + &workspace_ptr->fullscreen_container.super_element); + } + wlmtk_container_fini(&workspace_ptr->fullscreen_container); + if (NULL != workspace_ptr->window_container.super_element.parent_container_ptr) { wlmtk_container_remove_element( &workspace_ptr->super_container, @@ -222,6 +235,18 @@ struct wlr_box wlmtk_workspace_get_maximize_extents( return box; } +/* ------------------------------------------------------------------------- */ +struct wlr_box wlmtk_workspace_get_fullscreen_extents( + wlmtk_workspace_t *workspace_ptr) +{ + struct wlr_box box = { + .x = workspace_ptr->x1, + .y = workspace_ptr->y1, + .width = workspace_ptr->x2 - workspace_ptr->x1, + .height = workspace_ptr->y2 - workspace_ptr->y1 }; + return box; +} + /* ------------------------------------------------------------------------- */ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) @@ -241,8 +266,7 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, { bool need_activation = false; - BS_ASSERT(&workspace_ptr->window_container == - wlmtk_window_element(window_ptr)->parent_container_ptr); + BS_ASSERT(workspace_ptr == wlmtk_window_get_workspace(window_ptr)); if (workspace_ptr->grabbed_window_ptr == window_ptr) { wlmtk_fsm_event(&workspace_ptr->fsm, PFSME_RESET, NULL); @@ -272,6 +296,43 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, } } +/* ------------------------------------------------------------------------- */ +void wlmtk_workspace_window_to_fullscreen( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr, + bool fullscreen) +{ + BS_ASSERT(workspace_ptr == wlmtk_window_get_workspace(window_ptr)); + + if (fullscreen) { + BS_ASSERT( + bs_dllist_contains( + &workspace_ptr->window_container.elements, + wlmtk_dlnode_from_element(wlmtk_window_element(window_ptr)))); + + wlmtk_container_remove_element( + &workspace_ptr->window_container, + wlmtk_window_element(window_ptr)); + wlmtk_container_add_element( + &workspace_ptr->fullscreen_container, + wlmtk_window_element(window_ptr)); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + } else { + BS_ASSERT( + bs_dllist_contains( + &workspace_ptr->fullscreen_container.elements, + wlmtk_dlnode_from_element(wlmtk_window_element(window_ptr)))); + + wlmtk_container_remove_element( + &workspace_ptr->fullscreen_container, + wlmtk_window_element(window_ptr)); + wlmtk_container_add_element( + &workspace_ptr->window_container, + wlmtk_window_element(window_ptr)); + wlmtk_workspace_activate_window(workspace_ptr, window_ptr); + } +} + /* ------------------------------------------------------------------------- */ bool wlmtk_workspace_motion( wlmtk_workspace_t *workspace_ptr, @@ -353,11 +414,19 @@ void wlmtk_workspace_activate_window( } } +/* ------------------------------------------------------------------------- */ +wlmtk_window_t *wlmtk_workspace_get_activated_window( + wlmtk_workspace_t *workspace_ptr) +{ + return workspace_ptr->activated_window_ptr; +} + /* ------------------------------------------------------------------------- */ void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr) { + BS_ASSERT(workspace_ptr == wlmtk_window_get_workspace(window_ptr)); wlmtk_container_raise_element_to_top(&workspace_ptr->window_container, wlmtk_window_element(window_ptr)); } @@ -651,6 +720,12 @@ void test_create_destroy(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 36, box.width); BS_TEST_VERIFY_EQ(test_ptr, 136, box.height); + box = wlmtk_workspace_get_fullscreen_extents(workspace_ptr); + BS_TEST_VERIFY_EQ(test_ptr, -10, box.x); + BS_TEST_VERIFY_EQ(test_ptr, -20, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.height); + wlmtk_workspace_destroy(workspace_ptr); wlmtk_container_destroy_fake_parent(fake_parent_ptr); } diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 300a5fab..ff1dbd46 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -77,6 +77,16 @@ void wlmtk_workspace_set_extents(wlmtk_workspace_t *workspace_ptr, struct wlr_box wlmtk_workspace_get_maximize_extents( wlmtk_workspace_t *workspace_ptr); +/** + * Returns the extents of the workspace available for fullscreen windows. + * + * @param workspace_ptr + * + * @return A `struct wlr_box` that lines out the available space and position. + */ +struct wlr_box wlmtk_workspace_get_fullscreen_extents( + wlmtk_workspace_t *workspace_ptr); + /** * Maps the window: Adds it to the workspace container and makes it visible. * @@ -95,6 +105,20 @@ void wlmtk_workspace_map_window(wlmtk_workspace_t *workspace_ptr, void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); +/** + * Promotes the window to the fullscreen layer (or back). + * + * To be called by @ref wlmtk_window_commit_fullscreen. + * + * @param workspace_ptr + * @param window_ptr + * @param fullscreen + */ +void wlmtk_workspace_window_to_fullscreen( + wlmtk_workspace_t *workspace_ptr, + wlmtk_window_t *window_ptr, + bool fullscreen); + /** * Handles a motion event. * @@ -160,6 +184,10 @@ void wlmtk_workspace_activate_window( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); +/** @return Pointer to the activated @ref wlmtk_window_t, if any. */ +wlmtk_window_t *wlmtk_workspace_get_activated_window( + wlmtk_workspace_t *workspace_ptr); + /** Raises `window_ptr`: Will show it atop all other windows. */ void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, diff --git a/src/wlmaker.c b/src/wlmaker.c index 7ed03cc1..553fe94e 100644 --- a/src/wlmaker.c +++ b/src/wlmaker.c @@ -157,10 +157,23 @@ void toggle_fullscreen(wlmaker_server_t *server_ptr, __UNUSED__ void *arg_ptr) { wlmaker_workspace_t *workspace_ptr = wlmaker_server_get_current_workspace( server_ptr); - wlmaker_view_t *view_ptr = wlmaker_workspace_get_activated_view( + + wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( workspace_ptr); - if (NULL == view_ptr) return; // No activated view, nothing to do. - wlmaker_view_set_fullscreen(view_ptr, !view_ptr->fullscreen); + if (NULL != wlmtk_workspace_ptr) { + + wlmtk_window_t *window_ptr = wlmtk_workspace_get_activated_window( + wlmtk_workspace_ptr); + if (NULL == window_ptr) return; + wlmtk_window_request_fullscreen( + window_ptr, !wlmtk_window_is_fullscreen(window_ptr)); + + } else { + wlmaker_view_t *view_ptr = wlmaker_workspace_get_activated_view( + workspace_ptr); + if (NULL == view_ptr) return; // No activated view, nothing to do. + wlmaker_view_set_fullscreen(view_ptr, !view_ptr->fullscreen); + } } /* ------------------------------------------------------------------------- */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index cf70c0c3..ae4d1d2d 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -108,6 +108,10 @@ static void surface_set_activated( wlmtk_surface_t *surface_ptr, bool activated); +static uint32_t content_request_fullscreen( + wlmtk_content_t *content_ptr, + bool fullscreen); + /* == Data ================================================================= */ /** Virtual methods for XDG toplevel surface, for the Element superclass. */ @@ -123,6 +127,11 @@ const wlmtk_surface_vmt_t _wlmtk_xdg_toplevel_surface_vmt = { .set_activated = surface_set_activated, }; +/** Virtual methods for XDG toplevel surface, for the Content superclass. */ +const wlmtk_content_vmt_t _wlmtk_xdg_toplevel_content_vmt = { + .request_fullscreen = content_request_fullscreen, +}; + /* == Exported methods ===================================================== */ /* ------------------------------------------------------------------------- */ @@ -178,6 +187,9 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( xdg_toplevel_surface_destroy(xdg_tl_surface_ptr); return NULL; } + wlmtk_content_extend( + &xdg_tl_surface_ptr->super_content, + &_wlmtk_xdg_toplevel_content_vmt); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->events.destroy, @@ -320,6 +332,18 @@ uint32_t surface_request_size( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel, width, height); } +/* ------------------------------------------------------------------------- */ +uint32_t content_request_fullscreen( + wlmtk_content_t *content_ptr, + bool fullscreen) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_surface_t, super_content); + + return wlr_xdg_toplevel_set_fullscreen( + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel, fullscreen); +} + /* ------------------------------------------------------------------------- */ /** * Sets the keyboard activation status for the surface. @@ -474,12 +498,18 @@ void handle_surface_commit( listener_ptr, wlmtk_xdg_toplevel_surface_t, surface_commit_listener); if (NULL == xdg_tl_surface_ptr->wlr_xdg_surface_ptr) return; + BS_ASSERT(xdg_tl_surface_ptr->wlr_xdg_surface_ptr->role == + WLR_XDG_SURFACE_ROLE_TOPLEVEL); wlmtk_content_commit_size( &xdg_tl_surface_ptr->super_content, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.configure_serial, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.width, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.height); + + wlmtk_window_commit_fullscreen( + xdg_tl_surface_ptr->super_content.window_ptr, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.fullscreen); } /* ------------------------------------------------------------------------- */ @@ -500,6 +530,7 @@ void handle_toplevel_request_maximize( wlmtk_window_request_maximize( xdg_tl_surface_ptr->super_content.window_ptr, !wlmtk_window_maximized(xdg_tl_surface_ptr->super_content.window_ptr)); + // FIXME: This should be done with a set_maximize async op. } /* ------------------------------------------------------------------------- */ From d7fc5b2dd9e8f1dc5c76c3295264d2c62a87c4f4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 19:49:37 +0100 Subject: [PATCH 360/390] Removes a rather long-obsolete comment about building... --- src/wlmaker.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/wlmaker.c b/src/wlmaker.c index 553fe94e..7c4ca17e 100644 --- a/src/wlmaker.c +++ b/src/wlmaker.c @@ -16,12 +16,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * In the parent directory: - * - * * meson build/ --reconfigure - * * ninja -C build - * * doxygen */ /// setenv() is a POSIX extension. From 6d585aef49310c804d5a64d129e8dccd27d41409 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 20:47:20 +0100 Subject: [PATCH 361/390] Adds wlmtk_rectangle_set_color. --- src/toolkit/rectangle.c | 17 ++++++++++++++++- src/toolkit/rectangle.h | 10 ++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/toolkit/rectangle.c b/src/toolkit/rectangle.c index bf5fbed1..b2482d46 100644 --- a/src/toolkit/rectangle.c +++ b/src/toolkit/rectangle.c @@ -86,7 +86,7 @@ wlmtk_rectangle_t *wlmtk_rectangle_create( if (NULL == rectangle_ptr) return NULL; rectangle_ptr->width = width; rectangle_ptr->height = height; - rectangle_ptr->color = color; + wlmtk_rectangle_set_color(rectangle_ptr, color); if (!wlmtk_element_init(&rectangle_ptr->super_element, env_ptr)) { wlmtk_rectangle_destroy(rectangle_ptr); @@ -128,6 +128,21 @@ void wlmtk_rectangle_set_size( } } +/* ------------------------------------------------------------------------- */ +void wlmtk_rectangle_set_color( + wlmtk_rectangle_t *rectangle_ptr, + uint32_t color) +{ + rectangle_ptr->color = color; + + if (NULL != rectangle_ptr->wlr_scene_rect_ptr) { + float fcolor[4]; + bs_gfxbuf_argb8888_to_floats( + color, &fcolor[0], &fcolor[1], &fcolor[2], &fcolor[3]); + wlr_scene_rect_set_color(rectangle_ptr->wlr_scene_rect_ptr, fcolor); + } +} + /* ------------------------------------------------------------------------- */ wlmtk_element_t *wlmtk_rectangle_element(wlmtk_rectangle_t *rectangle_ptr) { diff --git a/src/toolkit/rectangle.h b/src/toolkit/rectangle.h index b41cdae8..a1ef9f60 100644 --- a/src/toolkit/rectangle.h +++ b/src/toolkit/rectangle.h @@ -65,6 +65,16 @@ void wlmtk_rectangle_set_size( int width, int height); +/** + * Sets (or updates) the color of the rectangle. + * + * @param rectangle_ptr + * @param color + */ +void wlmtk_rectangle_set_color( + wlmtk_rectangle_t *rectangle_ptr, + uint32_t color); + /** Returns the superclass @ref wlmtk_element_t of the rectangle. */ wlmtk_element_t *wlmtk_rectangle_element(wlmtk_rectangle_t *rectangle_ptr); From 7f9b21107b1dc8ed4eb307be2606b574f9bbd630 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 20:48:49 +0100 Subject: [PATCH 362/390] Adds wlmtk_borderdd_set_style. --- src/toolkit/bordered.c | 17 +++++++++++++++++ src/toolkit/bordered.h | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c index b2de0aa1..34421184 100644 --- a/src/toolkit/bordered.c +++ b/src/toolkit/bordered.c @@ -99,6 +99,23 @@ void wlmtk_bordered_fini(wlmtk_bordered_t *bordered_ptr) memset(bordered_ptr, 0, sizeof(wlmtk_bordered_t)); } +/* ------------------------------------------------------------------------- */ +void wlmtk_bordered_set_style(wlmtk_bordered_t *bordered_ptr, + const wlmtk_margin_style_t *style_ptr) +{ + memcpy(&bordered_ptr->style, style_ptr, sizeof(wlmtk_margin_style_t)); + + _wlmtk_bordered_container_update_layout(&bordered_ptr->super_container); + wlmtk_rectangle_set_color( + bordered_ptr->northern_border_rectangle_ptr, style_ptr->color); + wlmtk_rectangle_set_color( + bordered_ptr->eastern_border_rectangle_ptr, style_ptr->color); + wlmtk_rectangle_set_color( + bordered_ptr->southern_border_rectangle_ptr, style_ptr->color); + wlmtk_rectangle_set_color( + bordered_ptr->western_border_rectangle_ptr, style_ptr->color); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/bordered.h b/src/toolkit/bordered.h index 0bfeb517..797d9249 100644 --- a/src/toolkit/bordered.h +++ b/src/toolkit/bordered.h @@ -78,6 +78,15 @@ bool wlmtk_bordered_init(wlmtk_bordered_t *bordered_ptr, */ void wlmtk_bordered_fini(wlmtk_bordered_t *bordered_ptr); +/** + * Updates the style. + * + * @param bordered_ptr + * @param style_ptr + */ +void wlmtk_bordered_set_style(wlmtk_bordered_t *bordered_ptr, + const wlmtk_margin_style_t *style_ptr); + /** Unit test cases. */ extern const bs_test_case_t wlmtk_bordered_test_cases[]; From e5883239c1ae6e4c766e56c3b2ed34778873a075 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 21:32:09 +0100 Subject: [PATCH 363/390] Leave a TODO for later. --- src/toolkit/surface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/toolkit/surface.c b/src/toolkit/surface.c index 6d3ccdaa..4de9aa14 100644 --- a/src/toolkit/surface.c +++ b/src/toolkit/surface.c @@ -137,6 +137,8 @@ void wlmtk_surface_commit_size( int width, int height) { + // TODO(kaeser@gubbe.ch): don't update layout if size didn't change. + if (surface_ptr->committed_width != width || surface_ptr->committed_height != height) { surface_ptr->committed_width = width; From 8584997c649c8d71853ed5b15e8af96fcaf3ef47 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 5 Jan 2024 22:12:53 +0100 Subject: [PATCH 364/390] Adds handler for request_fullscreen, yet empty. --- src/wlmtk_xdg_toplevel.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index ae4d1d2d..d30d99f6 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -50,8 +50,10 @@ typedef struct { /** Listener for the `commit` signal of the `wlr_surface`. */ struct wl_listener surface_commit_listener; - /** Listener for `maximize` signal of `wlr_xdg_toplevel::events`. */ + /** Listener for `request_maximize` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_maximize_listener; + /** Listener for `request_fullscreen` signal of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_request_fullscreen_listener; /** Listener for `request_move` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_move_listener; /** Listener for `request_resize` signal of `wlr_xdg_toplevel::events`. */ @@ -84,6 +86,9 @@ static void handle_surface_commit( static void handle_toplevel_request_maximize( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_request_fullscreen( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_toplevel_request_move( struct wl_listener *listener_ptr, void *data_ptr); @@ -216,6 +221,10 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( &wlr_xdg_surface_ptr->toplevel->events.request_maximize, &xdg_tl_surface_ptr->toplevel_request_maximize_listener, handle_toplevel_request_maximize); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.request_fullscreen, + &xdg_tl_surface_ptr->toplevel_request_fullscreen_listener, + handle_toplevel_request_fullscreen); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_move, &xdg_tl_surface_ptr->toplevel_request_move_listener, @@ -243,6 +252,7 @@ void xdg_toplevel_surface_destroy( &xdg_tl_surface_ptr->toplevel_set_title_listener.link); wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_resize_listener.link); wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_move_listener.link); + wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_fullscreen_listener.link); wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_maximize_listener.link); wl_list_remove(&xdg_tl_surface_ptr->surface_commit_listener.link); @@ -507,6 +517,8 @@ void handle_surface_commit( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.width, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.height); + bs_log(BS_WARNING, "FIXME: commit fs %d", + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.fullscreen); wlmtk_window_commit_fullscreen( xdg_tl_surface_ptr->super_content.window_ptr, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.fullscreen); @@ -530,7 +542,30 @@ void handle_toplevel_request_maximize( wlmtk_window_request_maximize( xdg_tl_surface_ptr->super_content.window_ptr, !wlmtk_window_maximized(xdg_tl_surface_ptr->super_content.window_ptr)); - // FIXME: This should be done with a set_maximize async op. + + // TODO(kaeser@gubbe.ch): Check is a wlr_xdg_surface_schedule_configure() + // is required here. +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `request_fullscreen` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_request_fullscreen( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_surface_t, + toplevel_request_maximize_listener); + + bs_log(BS_WARNING, "Unimplemented: request fullscreen."); + wlr_xdg_surface_schedule_configure( + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->base); } /* ------------------------------------------------------------------------- */ From 7d4df6b96e6e1f304a5c40eb2d0ce6c989da0e90 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 13:35:22 +0100 Subject: [PATCH 365/390] Adds guard clause to wlmtk_bordered_set_style, and omit the explicit update_layout for the parent in wlmtk_bordered_t (it's already done in container). --- src/toolkit/bordered.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/toolkit/bordered.c b/src/toolkit/bordered.c index 34421184..113957cc 100644 --- a/src/toolkit/bordered.c +++ b/src/toolkit/bordered.c @@ -106,6 +106,10 @@ void wlmtk_bordered_set_style(wlmtk_bordered_t *bordered_ptr, memcpy(&bordered_ptr->style, style_ptr, sizeof(wlmtk_margin_style_t)); _wlmtk_bordered_container_update_layout(&bordered_ptr->super_container); + + // Guard clause. Actually, if *any* of the rectangles was not created. + if (NULL == bordered_ptr->western_border_rectangle_ptr) return; + wlmtk_rectangle_set_color( bordered_ptr->northern_border_rectangle_ptr, style_ptr->color); wlmtk_rectangle_set_color( @@ -133,12 +137,6 @@ void _wlmtk_bordered_container_update_layout( _wlmtk_bordered_set_positions(bordered_ptr); bordered_ptr->orig_super_container_vmt.update_layout(container_ptr); - - // configure parent container. - if (NULL != container_ptr->super_element.parent_container_ptr) { - wlmtk_container_update_layout( - container_ptr->super_element.parent_container_ptr); - } } /* ------------------------------------------------------------------------- */ From a8bdfc82c22b31bc8dd640e2b17014139123c730 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 13:49:24 +0100 Subject: [PATCH 366/390] Adds initial tests for fullscreen windows. --- src/toolkit/window.c | 100 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 55aa722c..a1ce508e 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -444,13 +444,14 @@ void wlmtk_window_request_fullscreen( window_ptr->content_ptr, box.width, box.height); pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); pending_update_ptr->serial = serial; - pending_update_ptr->x = box.x; - pending_update_ptr->y = box.y; + pending_update_ptr->x = box.x; // FIXME - border_style.width; + pending_update_ptr->y = box.y; // FIXME - border_style.width; pending_update_ptr->width = box.width; pending_update_ptr->height = box.height; } else { + // FIXME: Only set this if decoration was actually set! wlmtk_window_set_server_side_decorated(window_ptr, true); box = window_ptr->organic_size; _wlmtk_window_request_position_and_size( @@ -475,6 +476,16 @@ void wlmtk_window_commit_fullscreen( // Guard clause: Nothing to do if we're already there. if (window_ptr->fullscreen == fullscreen) return; + // TODO(kaeser@gubbe.ch): For whatever reason, the node isn't displayed + // when we zero out the border with, or hide the border elements. + // Figure out what causes that, then get rid of the border on fullscreen. + if (false) { + wlmtk_margin_style_t bstyle = border_style; + if (fullscreen) bstyle.width = 0; + wlmtk_bordered_set_style(&window_ptr->super_bordered, &bstyle); + } + + // FIXME: Actually we should only set decoration if this was requested. wlmtk_window_set_server_side_decorated(window_ptr, !fullscreen); window_ptr->fullscreen = fullscreen; @@ -524,9 +535,9 @@ void wlmtk_window_get_size( if (NULL != window_ptr->resizebar_ptr) { *height_ptr += resizebar_style.height + margin_style.width; } - *height_ptr += 2 * border_style.width; + *height_ptr += 2 * window_ptr->super_bordered.style.width; - *width_ptr += 2 * border_style.width; + *width_ptr += 2 * window_ptr->super_bordered.style.width; } /* ------------------------------------------------------------------------- */ @@ -1082,6 +1093,7 @@ static void test_request_close(bs_test_t *test_ptr); static void test_set_activated(bs_test_t *test_ptr); static void test_server_side_decorated(bs_test_t *test_ptr); static void test_maximize(bs_test_t *test_ptr); +static void test_fullscreen(bs_test_t *test_ptr); static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { @@ -1091,6 +1103,7 @@ const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "set_activated", test_set_activated }, { 1, "set_server_side_decorated", test_server_side_decorated }, { 1, "maximize", test_maximize }, + { 1, "fullscreen", test_fullscreen }, { 1, "fake", test_fake }, { 0, NULL, NULL } }; @@ -1293,6 +1306,85 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_container_destroy_fake_parent(fake_parent_ptr); } +/* ------------------------------------------------------------------------- */ +/** Tests turning a window to fullscreen and back. */ +void test_fullscreen(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + NULL, fake_parent_ptr->wlr_scene_tree_ptr); + struct wlr_box extents = { .width = 1024, .height = 768 }, box; + wlmtk_workspace_set_extents(workspace_ptr, &extents); + BS_ASSERT(NULL != workspace_ptr); + + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); + BS_ASSERT(NULL != window_ptr); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + + // Set up initial organic size, and verify. + wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_FALSE(test_ptr, window_ptr->inorganic_sizing); + + // Request fullscreen. Does not take immediate effect. + wlmtk_window_request_fullscreen(window_ptr, true); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + + // Only after "commit", it will take effect. + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 1024 + 2, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); + + // Request to end fullscreen. Not taking immediate effect. + wlmtk_window_request_fullscreen(window_ptr, false); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + + // Takes effect after commit. We'll want the same position as before. + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(window_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); + + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); +} + +// FIXME: Test to unmap a fullscreened window. +// FIXME: Test that the window remains activated. +// FIXME: Test that fullscreen keeps window decoration as it should. + /* ------------------------------------------------------------------------- */ /** Tests fake window ctor and dtor. */ void test_fake(bs_test_t *test_ptr) From 77662eb01bf70538d44ae261251f80a076293f90 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 13:51:40 +0100 Subject: [PATCH 367/390] Removes an obsolete commit log. --- src/wlmtk_xdg_toplevel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index d30d99f6..057cabb0 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -517,8 +517,6 @@ void handle_surface_commit( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.width, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.height); - bs_log(BS_WARNING, "FIXME: commit fs %d", - xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.fullscreen); wlmtk_window_commit_fullscreen( xdg_tl_surface_ptr->super_content.window_ptr, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.fullscreen); From fca4e1dc7b97ccec45ed1bd359b4ff387a94c460 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 13:51:55 +0100 Subject: [PATCH 368/390] Updates the roadmap with findings from the fullscreen trip. --- doc/ROADMAP.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index 8574ae81..c8a6114f 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -71,6 +71,7 @@ Support for visual effects to improve usability, but not for pure show. * Hide window border when not having server-side decoration. * Fix issue with Chrome: Enabling "Use system title and boders" will pick a slightly small decoration. * Fix issue on resizing: When moving the mouse too quickly, focus is lost and the resizing stops. + * Fix issue on fullscreen: The window border is kept, having the window off by 1 pixel. * Experimental support for Dock Apps * [done] Experimental wayland protocol for Apps to declare icon surfaces. @@ -170,6 +171,7 @@ Features for further versions, not ordered by priority nor timeline. * System Tray (potentially through a Dock App) * Icon Themes * Notifications (potentially through a Dock App) + * Fullscreen: Hide all other visuals when a window takes fullscreen. * Application launcher * Show icon from XDG desktop entry. From c7636a4d729ab207d19d53bedaf42e1e2748a428 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 13:56:59 +0100 Subject: [PATCH 369/390] Adds test for unmapping a fullscreen window, and fixes the workspace code. --- src/toolkit/window.c | 50 +++++++++++++++++++++++++++++++++++++++-- src/toolkit/workspace.c | 14 +++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index a1ce508e..9473d360 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -487,8 +487,8 @@ void wlmtk_window_commit_fullscreen( // FIXME: Actually we should only set decoration if this was requested. wlmtk_window_set_server_side_decorated(window_ptr, !fullscreen); - window_ptr->fullscreen = fullscreen; + window_ptr->fullscreen = fullscreen; wlmtk_workspace_window_to_fullscreen( wlmtk_window_get_workspace(window_ptr), window_ptr, fullscreen); } @@ -1094,6 +1094,7 @@ static void test_set_activated(bs_test_t *test_ptr); static void test_server_side_decorated(bs_test_t *test_ptr); static void test_maximize(bs_test_t *test_ptr); static void test_fullscreen(bs_test_t *test_ptr); +static void test_fullscreen_unmap(bs_test_t *test_ptr); static void test_fake(bs_test_t *test_ptr); const bs_test_case_t wlmtk_window_test_cases[] = { @@ -1104,6 +1105,7 @@ const bs_test_case_t wlmtk_window_test_cases[] = { { 1, "set_server_side_decorated", test_server_side_decorated }, { 1, "maximize", test_maximize }, { 1, "fullscreen", test_fullscreen }, + { 1, "fullscreen_unmap", test_fullscreen_unmap }, { 1, "fake", test_fake }, { 0, NULL, NULL } }; @@ -1381,7 +1383,51 @@ void test_fullscreen(bs_test_t *test_ptr) wlmtk_container_destroy_fake_parent(fake_parent_ptr); } -// FIXME: Test to unmap a fullscreened window. +/* ------------------------------------------------------------------------- */ +/** Tests that unmapping a fullscreen window works. */ +void test_fullscreen_unmap(bs_test_t *test_ptr) +{ + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + NULL, fake_parent_ptr->wlr_scene_tree_ptr); + struct wlr_box extents = { .width = 1024, .height = 768 }, box; + wlmtk_workspace_set_extents(workspace_ptr, &extents); + BS_ASSERT(NULL != workspace_ptr); + + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); + wlmtk_content_t content; + wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); + wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); + BS_ASSERT(NULL != window_ptr); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + + // Request fullscreen. Does not take immediate effect. + wlmtk_window_request_fullscreen(window_ptr, true); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + + // Only after "commit", it will take effect. + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + box = wlmtk_window_get_position_and_size(window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); + BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); + BS_TEST_VERIFY_EQ(test_ptr, 1024 + 2, box.width); + BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); + + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_window_destroy(window_ptr); + wlmtk_content_fini(&content); + wlmtk_fake_surface_destroy(fake_surface_ptr); + + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); +} + // FIXME: Test that the window remains activated. // FIXME: Test that fullscreen keeps window decoration as it should. diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index d15a4e5d..82233a10 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -279,9 +279,16 @@ void wlmtk_workspace_unmap_window(wlmtk_workspace_t *workspace_ptr, } wlmtk_element_set_visible(wlmtk_window_element(window_ptr), false); - wlmtk_container_remove_element( - &workspace_ptr->window_container, - wlmtk_window_element(window_ptr)); + + if (wlmtk_window_is_fullscreen(window_ptr)) { + wlmtk_container_remove_element( + &workspace_ptr->fullscreen_container, + wlmtk_window_element(window_ptr)); + } else { + wlmtk_container_remove_element( + &workspace_ptr->window_container, + wlmtk_window_element(window_ptr)); + } wlmtk_window_set_workspace(window_ptr, NULL); if (need_activation) { @@ -303,6 +310,7 @@ void wlmtk_workspace_window_to_fullscreen( bool fullscreen) { BS_ASSERT(workspace_ptr == wlmtk_window_get_workspace(window_ptr)); + BS_ASSERT(fullscreen == wlmtk_window_is_fullscreen(window_ptr)); if (fullscreen) { BS_ASSERT( From 7185a409feb61550637e71ff1a1d3a00690f3c86 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 14:17:14 +0100 Subject: [PATCH 370/390] Adds helper to check activation status to wlmtk_titlebar_t. --- src/toolkit/titlebar.c | 6 ++++++ src/toolkit/titlebar.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/toolkit/titlebar.c b/src/toolkit/titlebar.c index f34b20d9..f0d4f7fb 100644 --- a/src/toolkit/titlebar.c +++ b/src/toolkit/titlebar.c @@ -237,6 +237,12 @@ void wlmtk_titlebar_set_activated( titlebar_ptr->close_button_ptr, titlebar_ptr->activated); } +/* ------------------------------------------------------------------------- */ +bool wlmtk_titlebar_is_activated(wlmtk_titlebar_t *titlebar_ptr) +{ + return titlebar_ptr->activated; +} + /* ------------------------------------------------------------------------- */ void wlmtk_titlebar_set_title( wlmtk_titlebar_t *titlebar_ptr, diff --git a/src/toolkit/titlebar.h b/src/toolkit/titlebar.h index 49970c24..165b81a8 100644 --- a/src/toolkit/titlebar.h +++ b/src/toolkit/titlebar.h @@ -94,6 +94,9 @@ void wlmtk_titlebar_set_activated( wlmtk_titlebar_t *titlebar_ptr, bool activated); +/** Returns whether the title bar is activated. */ +bool wlmtk_titlebar_is_activated(wlmtk_titlebar_t *titlebar_ptr); + /** * Updates the title text of the titlebar. * From 44161035b102f68a4f9213375af58ad5be802988 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 14:17:49 +0100 Subject: [PATCH 371/390] Adds test about window and decoration activation with fullscreen and fixes an issue there. --- src/toolkit/window.c | 56 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 9473d360..81328b49 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -102,14 +102,14 @@ struct _wlmtk_window_t { /** List of udpates currently available. */ bs_dllist_t available_updates; /** Pre-alloocated updates. */ - wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; + wlmtk_pending_update_t pre_allocated_updates[WLMTK_WINDOW_MAX_PENDING]; /** Organic size of the window, ie. when not maximized. */ - struct wlr_box organic_size; + struct wlr_box organic_size; /** Whether the window has been requested as maximized. */ - bool maximized; + bool maximized; /** Whether the window has been requested as fullscreen. */ - bool fullscreen; + bool fullscreen; /** * Whether an "inorganic" sizing operation is in progress, and thus size * changes should not be recorded in @ref wlmtk_window_t::organic_size. @@ -117,14 +117,16 @@ struct _wlmtk_window_t { * This is eg. between @ref wlmtk_window_request_fullscreen and * @ref wlmtk_window_commit_fullscreen. */ - bool inorganic_sizing; + bool inorganic_sizing; /** * Stores whether the window is server-side decorated. * * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). */ - bool server_side_decorated; + bool server_side_decorated; + /** Stores whether the window is activated (keyboard focus). */ + bool activated; }; /** State of a fake window: Includes the public record and the window. */ @@ -308,6 +310,8 @@ void wlmtk_window_set_server_side_decorated( window_ptr->super_bordered.super_container.super_element.env_ptr, window_ptr, &titlebar_style); BS_ASSERT(NULL != window_ptr->titlebar_ptr); + wlmtk_titlebar_set_activated( + window_ptr->titlebar_ptr, window_ptr->activated); wlmtk_element_set_visible( wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); // Hm, if the content has a popup that extends over the titlebar area, @@ -808,6 +812,7 @@ void _wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { + window_ptr->activated = activated; wlmtk_content_set_activated(window_ptr->content_ptr, activated); if (NULL != window_ptr->titlebar_ptr) { wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); @@ -1325,8 +1330,15 @@ void test_fullscreen(bs_test_t *test_ptr) wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); + wlmtk_window_set_server_side_decorated(window_ptr, true); wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_EQ( + test_ptr, + window_ptr, + wlmtk_workspace_get_activated_window(workspace_ptr)); + // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); wlmtk_content_commit_size(&content, @@ -1343,6 +1355,9 @@ void test_fullscreen(bs_test_t *test_ptr) // Request fullscreen. Does not take immediate effect. wlmtk_window_request_fullscreen(window_ptr, true); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_titlebar_is_activated(window_ptr->titlebar_ptr)); // Only after "commit", it will take effect. wlmtk_content_commit_size(&content, @@ -1357,6 +1372,12 @@ void test_fullscreen(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 1024 + 2, box.width); BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_EQ( + test_ptr, + window_ptr, + wlmtk_workspace_get_activated_window(workspace_ptr)); + // Request to end fullscreen. Not taking immediate effect. wlmtk_window_request_fullscreen(window_ptr, false); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); @@ -1374,6 +1395,15 @@ void test_fullscreen(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_titlebar_is_activated(window_ptr->titlebar_ptr)); + BS_TEST_VERIFY_EQ( + test_ptr, + window_ptr, + wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); @@ -1402,6 +1432,12 @@ void test_fullscreen_unmap(bs_test_t *test_ptr) BS_ASSERT(NULL != window_ptr); wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_EQ( + test_ptr, + window_ptr, + wlmtk_workspace_get_activated_window(workspace_ptr)); + // Request fullscreen. Does not take immediate effect. wlmtk_window_request_fullscreen(window_ptr, true); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); @@ -1418,8 +1454,15 @@ void test_fullscreen_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); BS_TEST_VERIFY_EQ(test_ptr, 1024 + 2, box.width); BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); + BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_EQ( + test_ptr, + NULL, + wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); @@ -1428,7 +1471,6 @@ void test_fullscreen_unmap(bs_test_t *test_ptr) wlmtk_container_destroy_fake_parent(fake_parent_ptr); } -// FIXME: Test that the window remains activated. // FIXME: Test that fullscreen keeps window decoration as it should. /* ------------------------------------------------------------------------- */ From b0a807a4bfe4166fd5e13669cc76acc23b021ce5 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 14:33:22 +0100 Subject: [PATCH 372/390] Simplifies the request_fullscreen method a bit. --- src/toolkit/window.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 81328b49..b2664139 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -439,8 +439,11 @@ void wlmtk_window_request_fullscreen( // Must be mapped.x BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); - // FIXME: Oh gosh, this is ugly. + // Will not line up another pending update. + wlmtk_content_request_fullscreen(window_ptr->content_ptr, fullscreen); + window_ptr->inorganic_sizing = fullscreen; + if (fullscreen) { box = wlmtk_workspace_get_fullscreen_extents( wlmtk_window_get_workspace(window_ptr)); @@ -448,8 +451,8 @@ void wlmtk_window_request_fullscreen( window_ptr->content_ptr, box.width, box.height); pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); pending_update_ptr->serial = serial; - pending_update_ptr->x = box.x; // FIXME - border_style.width; - pending_update_ptr->y = box.y; // FIXME - border_style.width; + pending_update_ptr->x = box.x; + pending_update_ptr->y = box.y; pending_update_ptr->width = box.width; pending_update_ptr->height = box.height; @@ -462,14 +465,6 @@ void wlmtk_window_request_fullscreen( window_ptr, box.x, box.y, box.width, box.height); } - serial = wlmtk_content_request_fullscreen( - window_ptr->content_ptr, fullscreen); - pending_update_ptr = _wlmtk_window_prepare_update(window_ptr); - pending_update_ptr->serial = serial; - pending_update_ptr->x = box.x; - pending_update_ptr->y = box.y; - pending_update_ptr->width = box.width; - pending_update_ptr->height = box.height; } /* ------------------------------------------------------------------------- */ From 6db694e41ff8fd40efba6a71c42fdd2f4af2005b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 16:42:08 +0100 Subject: [PATCH 373/390] Adds wlmtk_content_request_maximized. --- src/toolkit/content.c | 4 +++ src/toolkit/content.h | 28 +++++++++++++++++++-- src/toolkit/window.c | 1 + src/toolkit/window.h | 57 ++++++++++++++++++++++++++++--------------- 4 files changed, 68 insertions(+), 22 deletions(-) diff --git a/src/toolkit/content.c b/src/toolkit/content.c index 259c7089..84bb034b 100644 --- a/src/toolkit/content.c +++ b/src/toolkit/content.c @@ -74,6 +74,10 @@ wlmtk_content_vmt_t wlmtk_content_extend( { wlmtk_content_vmt_t orig_vmt = content_ptr->vmt; + if (NULL != content_vmt_ptr->request_maximized) { + content_ptr->vmt.request_maximized = + content_vmt_ptr->request_maximized; + } if (NULL != content_vmt_ptr->request_fullscreen) { content_ptr->vmt.request_fullscreen = content_vmt_ptr->request_fullscreen; diff --git a/src/toolkit/content.h b/src/toolkit/content.h index 65a1b469..fc617f12 100644 --- a/src/toolkit/content.h +++ b/src/toolkit/content.h @@ -38,6 +38,21 @@ extern "C" { /** Virtual method table of @ref wlmtk_content_t. */ struct _wlmtk_content_vmt_t { + /** + * Requests the content to be set to maximized mode. + * + * Once the content has changed to `maximized` mode (potentially an + * asynchronous operation), @ref wlmtk_window_commit_maximized ought to be + * called, if the content belongs to a window. + * + * @param content_ptr + * @param maximized + * + * @return XDG toplevel configuration serial. + */ + uint32_t (*request_maximized)(wlmtk_content_t *content_ptr, + bool maximized); + /** * Requests the content to be set to fullscreen mode. * @@ -51,7 +66,8 @@ struct _wlmtk_content_vmt_t { * * @return XDG toplevel configuration serial. */ - uint32_t (*request_fullscreen)(wlmtk_content_t *content_ptr, bool fullscreen); + uint32_t (*request_fullscreen)(wlmtk_content_t *content_ptr, + bool fullscreen); }; /** State of window content. */ @@ -117,7 +133,15 @@ uint32_t wlmtk_content_request_size( int width, int height); -/** Requests fullscreen mode. */ +/** Requests maximized. See @ref wlmtk_content_vmt_t::request_maximized. */ +static inline uint32_t wlmtk_content_request_maximized( + wlmtk_content_t *content_ptr, + bool maximized) { + if (NULL == content_ptr->vmt.request_maximized) return 0; + return content_ptr->vmt.request_maximized(content_ptr, maximized); +} + +/** Requests fullscreen. See @ref wlmtk_content_vmt_t::request_fullscreen. */ static inline uint32_t wlmtk_content_request_fullscreen( wlmtk_content_t *content_ptr, bool fullscreen) { diff --git a/src/toolkit/window.c b/src/toolkit/window.c index b2664139..7a699dd0 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -405,6 +405,7 @@ void wlmtk_window_request_maximize( { BS_ASSERT(NULL != wlmtk_window_get_workspace(window_ptr)); if (window_ptr->maximized == maximized) return; + if (window_ptr->fullscreen) return; window_ptr->inorganic_sizing = maximized; window_ptr->maximized = maximized; diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 134b2e6a..55acc8e8 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -141,26 +141,6 @@ void wlmtk_window_request_close(wlmtk_window_t *window_ptr); */ void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); -/** - * Reuests the window to be maximized. - * - * Requires the window to be mapped (to a workspace). Will lookup the maximize - * extents from the workspace, and request a corresponding updated position and - * size for the window. @ref wlmtk_window_t::organic_size will not be updated. - * - * This may be implemented as an asynchronous operation. Maximization will be - * applied once the size change has been committed by the surface. - * - * @param window_ptr - * @param maximized - */ -void wlmtk_window_request_maximize( - wlmtk_window_t *window_ptr, - bool maximized); - -/** Returns whether the window is currently (requested to be) maximized. */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); - /** * Requests a move for the window. * @@ -219,6 +199,43 @@ void wlmtk_window_request_size( int width, int height); +/** + * Reuests the window to be maximized. + * + * Requires the window to be mapped (to a workspace). Will lookup the maximize + * extents from the workspace, and request a corresponding updated position and + * size for the window. @ref wlmtk_window_t::organic_size will not be updated. + * + * This may be implemented as an asynchronous operation. Maximization will be + * applied once the size change has been committed by the surface. + * + * @param window_ptr + * @param maximized + */ +void wlmtk_window_request_maximize( + wlmtk_window_t *window_ptr, + bool maximized); + +/** + * Commits the `maximized` mode for the window. + * + * This is the "commit" part of the potentially asynchronous operation. To be + * called by @ref wlmtk_content_t, after @ref wlmtk_content_request_maximized + * has completed by the client. + * + * The call is idempotent: Once the window is committed, further calls with + * the same `maximized` value will return straight away. + * + * @param window_ptr + * @param maximized + */ +void wlmtk_window_commit_maximized( + wlmtk_window_t *window_ptr, + bool maximized); + +/** Returns whether the window is currently (requested to be) maximized. */ +bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); + /** * Requests the window to be made fullscreen (or stops so). * From ef2c73f13dc092f73b5ee251b3b8bc2d3e3061d4 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 17:09:19 +0100 Subject: [PATCH 374/390] Applies the same request+commit flow to maximized as is for fullscreen. --- src/toolkit/window.c | 34 +++++++++++++++++++++++++--------- src/toolkit/window.h | 6 +++--- src/wlmaker.c | 19 ++++++++++++++++--- src/wlmtk_xdg_toplevel.c | 26 ++++++++++++++++++++++++-- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7a699dd0..43e8f45e 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -399,7 +399,7 @@ void wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) } /* ------------------------------------------------------------------------- */ -void wlmtk_window_request_maximize( +void wlmtk_window_request_maximized( wlmtk_window_t *window_ptr, bool maximized) { @@ -408,22 +408,34 @@ void wlmtk_window_request_maximize( if (window_ptr->fullscreen) return; window_ptr->inorganic_sizing = maximized; - window_ptr->maximized = maximized; struct wlr_box box; - if (window_ptr->maximized) { + if (maximized) { box = wlmtk_workspace_get_maximize_extents( wlmtk_window_get_workspace(window_ptr)); } else { box = window_ptr->organic_size; } + wlmtk_content_request_maximized(window_ptr->content_ptr, maximized); + _wlmtk_window_request_position_and_size( window_ptr, box.x, box.y, box.width, box.height); } /* ------------------------------------------------------------------------- */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr) +void wlmtk_window_commit_maximized( + wlmtk_window_t *window_ptr, + bool maximized) +{ + // Guard clause: Nothing to do if already as committed. + if (window_ptr->maximized == maximized) return; + + window_ptr->maximized = maximized; +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_is_maximized(wlmtk_window_t *window_ptr) { return window_ptr->maximized; } @@ -1246,7 +1258,7 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(window_ptr)); // Re-position the window. wlmtk_window_set_position(window_ptr, 50, 30); @@ -1265,17 +1277,19 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); // Maximize. - wlmtk_window_request_maximize(window_ptr, true); + wlmtk_window_request_maximized(window_ptr, true); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(window_ptr)); wlmtk_content_commit_size(&content, fake_surface_ptr->serial, fake_surface_ptr->requested_width, fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(window_ptr, true); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_maximized(window_ptr)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(window_ptr)); // A second commit: should not overwrite the organic dimension. wlmtk_content_commit_size(&content, @@ -1284,17 +1298,19 @@ void test_maximize(bs_test_t *test_ptr) fake_surface_ptr->requested_height); // Unmaximize. Restore earlier organic size and position. - wlmtk_window_request_maximize(window_ptr, false); + wlmtk_window_request_maximized(window_ptr, false); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(window_ptr)); wlmtk_content_commit_size(&content, fake_surface_ptr->serial, fake_surface_ptr->requested_width, fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(window_ptr, false); box = wlmtk_window_get_position_and_size(window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_maximized(window_ptr)); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(window_ptr)); // TODO(kaeser@gubbe.ch): Define what should happen when a maximized // window is moved. Should it lose maximization? Should it not move? diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 55acc8e8..7a39e104 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -212,7 +212,7 @@ void wlmtk_window_request_size( * @param window_ptr * @param maximized */ -void wlmtk_window_request_maximize( +void wlmtk_window_request_maximized( wlmtk_window_t *window_ptr, bool maximized); @@ -234,7 +234,7 @@ void wlmtk_window_commit_maximized( bool maximized); /** Returns whether the window is currently (requested to be) maximized. */ -bool wlmtk_window_maximized(wlmtk_window_t *window_ptr); +bool wlmtk_window_is_maximized(wlmtk_window_t *window_ptr); /** * Requests the window to be made fullscreen (or stops so). @@ -326,7 +326,7 @@ void wlmtk_window_request_position_and_size( * @ref wlmtk_window_t::organic_size will be updated, if there was no pending * update: Meaning that the commit originated not from an earlier * @ref wlmtk_window_request_position_and_size or @ref - * wlmtk_window_request_maximize call. + * wlmtk_window_request_maximized call. * * @param window_ptr * @param serial diff --git a/src/wlmaker.c b/src/wlmaker.c index 7c4ca17e..c8c4d2f3 100644 --- a/src/wlmaker.c +++ b/src/wlmaker.c @@ -176,10 +176,23 @@ void toggle_maximize(wlmaker_server_t *server_ptr, __UNUSED__ void *arg_ptr) { wlmaker_workspace_t *workspace_ptr = wlmaker_server_get_current_workspace( server_ptr); - wlmaker_view_t *view_ptr = wlmaker_workspace_get_activated_view( + + wlmtk_workspace_t *wlmtk_workspace_ptr = wlmaker_workspace_wlmtk( workspace_ptr); - if (NULL == view_ptr) return; // No activated view, nothing to do. - wlmaker_view_set_maximized(view_ptr, !view_ptr->maximized); + if (NULL != wlmtk_workspace_ptr) { + + wlmtk_window_t *window_ptr = wlmtk_workspace_get_activated_window( + wlmtk_workspace_ptr); + if (NULL == window_ptr) return; + wlmtk_window_request_maximized( + window_ptr, !wlmtk_window_is_maximized(window_ptr)); + + } else { + wlmaker_view_t *view_ptr = wlmaker_workspace_get_activated_view( + workspace_ptr); + if (NULL == view_ptr) return; // No activated view, nothing to do. + wlmaker_view_set_maximized(view_ptr, !view_ptr->maximized); + } } /* == Main program ========================================================= */ diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 057cabb0..cf38fb33 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -113,6 +113,9 @@ static void surface_set_activated( wlmtk_surface_t *surface_ptr, bool activated); +static uint32_t content_request_maximized( + wlmtk_content_t *content_ptr, + bool maximized); static uint32_t content_request_fullscreen( wlmtk_content_t *content_ptr, bool fullscreen); @@ -134,6 +137,7 @@ const wlmtk_surface_vmt_t _wlmtk_xdg_toplevel_surface_vmt = { /** Virtual methods for XDG toplevel surface, for the Content superclass. */ const wlmtk_content_vmt_t _wlmtk_xdg_toplevel_content_vmt = { + .request_maximized = content_request_maximized, .request_fullscreen = content_request_fullscreen, }; @@ -342,6 +346,18 @@ uint32_t surface_request_size( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel, width, height); } +/* ------------------------------------------------------------------------- */ +uint32_t content_request_maximized( + wlmtk_content_t *content_ptr, + bool maximized) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + content_ptr, wlmtk_xdg_toplevel_surface_t, super_content); + + return wlr_xdg_toplevel_set_maximized( + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel, maximized); +} + /* ------------------------------------------------------------------------- */ uint32_t content_request_fullscreen( wlmtk_content_t *content_ptr, @@ -517,6 +533,9 @@ void handle_surface_commit( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.width, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->current.geometry.height); + wlmtk_window_commit_maximized( + xdg_tl_surface_ptr->super_content.window_ptr, + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.maximized); wlmtk_window_commit_fullscreen( xdg_tl_surface_ptr->super_content.window_ptr, xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->current.fullscreen); @@ -537,12 +556,15 @@ void handle_toplevel_request_maximize( listener_ptr, wlmtk_xdg_toplevel_surface_t, toplevel_request_maximize_listener); - wlmtk_window_request_maximize( + wlmtk_window_request_maximized( xdg_tl_surface_ptr->super_content.window_ptr, - !wlmtk_window_maximized(xdg_tl_surface_ptr->super_content.window_ptr)); + !wlmtk_window_is_maximized( + xdg_tl_surface_ptr->super_content.window_ptr)); // TODO(kaeser@gubbe.ch): Check is a wlr_xdg_surface_schedule_configure() // is required here. + wlr_xdg_surface_schedule_configure( + xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->base); } /* ------------------------------------------------------------------------- */ From 2e6d7bd4ebcecdd375fd5e77535c384c2f550631 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 17:12:21 +0100 Subject: [PATCH 375/390] Minor alignment changes in XDG toplevel. --- src/wlmtk_xdg_toplevel.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index cf38fb33..9bb837e8 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -561,8 +561,9 @@ void handle_toplevel_request_maximize( !wlmtk_window_is_maximized( xdg_tl_surface_ptr->super_content.window_ptr)); - // TODO(kaeser@gubbe.ch): Check is a wlr_xdg_surface_schedule_configure() - // is required here. + // Protocol expects an `ack_configure`. Depending on current state, that + // may not have been sent throught @ref wlmtk_window_request_maximized, + // hence adding an explicit `ack_configure` here. wlr_xdg_surface_schedule_configure( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->base); } @@ -583,7 +584,14 @@ void handle_toplevel_request_fullscreen( wlmtk_xdg_toplevel_surface_t, toplevel_request_maximize_listener); - bs_log(BS_WARNING, "Unimplemented: request fullscreen."); + wlmtk_window_request_fullscreen( + xdg_tl_surface_ptr->super_content.window_ptr, + !wlmtk_window_is_fullscreen( + xdg_tl_surface_ptr->super_content.window_ptr)); + + // Protocol expects an `ack_configure`. Depending on current state, that + // may not have been sent throught @ref wlmtk_window_request_maximized, + // hence adding an explicit `ack_configure` here. wlr_xdg_surface_schedule_configure( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->base); } From effbe6f85542e81c30f65515120ed4a3d2c42be0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Sat, 6 Jan 2024 17:12:39 +0100 Subject: [PATCH 376/390] Updates on roadmap with details on Wayland protocol adherence. --- doc/ROADMAP.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index c8a6114f..2595eecb 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -140,6 +140,10 @@ Support for visual effects to improve usability, but not for pure show. Features for further versions, not ordered by priority nor timeline. +* Wayland protocol adherence. + * Support XDG `wm_capabilities` and advertise the compositor features. + * Fullscreen: Hide all other visuals when a window takes fullscreen. + * XWayland support (X11 clients). * Dock Apps. @@ -171,7 +175,6 @@ Features for further versions, not ordered by priority nor timeline. * System Tray (potentially through a Dock App) * Icon Themes * Notifications (potentially through a Dock App) - * Fullscreen: Hide all other visuals when a window takes fullscreen. * Application launcher * Show icon from XDG desktop entry. From d58da9cdae8a2c0290f0241026e0375d158b1a52 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Wed, 10 Jan 2024 21:56:49 +0100 Subject: [PATCH 377/390] Refactors how window decorations are applied, and fixes the issue that decoration got always applied after fullscreen. --- src/toolkit/window.c | 255 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 53 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 43e8f45e..7e678877 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -122,7 +122,10 @@ struct _wlmtk_window_t { /** * Stores whether the window is server-side decorated. * - * This is equivalent to (titlebar_ptr != NULL && resizebar_ptr != NULL). + * If the window is NOT fullscreen, then this is equivalent to + * (titlebar_ptr != NULL && resizebar_ptr != NULL). For a fullscreen + * window, titlebar and resizebar would be NULL, but the flag stores + * whether decoration should be enabled on organic/maximized modes. */ bool server_side_decorated; /** Stores whether the window is activated (keyboard focus). */ @@ -170,6 +173,20 @@ static void _wlmtk_window_request_position_and_size( int width, int height); +static void _wlmtk_window_create_titlebar(wlmtk_window_t *window_ptr); +static void _wlmtk_window_create_resizebar(wlmtk_window_t *window_ptr); +static void _wlmtk_window_destroy_titlebar(wlmtk_window_t *window_ptr); +static void _wlmtk_window_destroy_resizebar(wlmtk_window_t *window_ptr); +static void _wlmtk_window_apply_decoration(wlmtk_window_t *window_ptr); +static void _wlmtk_window_request_position_and_size_decorated( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height, + bool include_titlebar, + bool include_resizebar); + static wlmtk_pending_update_t *_wlmtk_window_prepare_update( wlmtk_window_t *window_ptr); static void _wlmtk_window_release_update( @@ -303,49 +320,9 @@ void wlmtk_window_set_server_side_decorated( window_ptr, decorated); if (window_ptr->server_side_decorated == decorated) return; - - if (decorated) { - // Create decoration. - window_ptr->titlebar_ptr = wlmtk_titlebar_create( - window_ptr->super_bordered.super_container.super_element.env_ptr, - window_ptr, &titlebar_style); - BS_ASSERT(NULL != window_ptr->titlebar_ptr); - wlmtk_titlebar_set_activated( - window_ptr->titlebar_ptr, window_ptr->activated); - wlmtk_element_set_visible( - wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); - // Hm, if the content has a popup that extends over the titlebar area, - // it'll be partially obscured. That will look odd... Well, let's - // address that problem once there's a situation. - wlmtk_box_add_element_front( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - - window_ptr->resizebar_ptr = wlmtk_resizebar_create( - window_ptr->super_bordered.super_container.super_element.env_ptr, - window_ptr, &resizebar_style); - BS_ASSERT(NULL != window_ptr->resizebar_ptr); - wlmtk_element_set_visible( - wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); - wlmtk_box_add_element_back( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - } else { - // Remove & destroy the decoration. - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_titlebar_element(window_ptr->titlebar_ptr)); - wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); - window_ptr->titlebar_ptr = NULL; - - wlmtk_box_remove_element( - &window_ptr->box, - wlmtk_resizebar_element(window_ptr->resizebar_ptr)); - wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); - window_ptr->resizebar_ptr = NULL; - } - window_ptr->server_side_decorated = decorated; + + _wlmtk_window_apply_decoration(window_ptr); } /* ------------------------------------------------------------------------- */ @@ -471,11 +448,11 @@ void wlmtk_window_request_fullscreen( } else { - // FIXME: Only set this if decoration was actually set! - wlmtk_window_set_server_side_decorated(window_ptr, true); box = window_ptr->organic_size; - _wlmtk_window_request_position_and_size( - window_ptr, box.x, box.y, box.width, box.height); + _wlmtk_window_request_position_and_size_decorated( + window_ptr, box.x, box.y, box.width, box.height, + window_ptr->server_side_decorated, + window_ptr->server_side_decorated); } } @@ -497,10 +474,9 @@ void wlmtk_window_commit_fullscreen( wlmtk_bordered_set_style(&window_ptr->super_bordered, &bstyle); } - // FIXME: Actually we should only set decoration if this was requested. - wlmtk_window_set_server_side_decorated(window_ptr, !fullscreen); - window_ptr->fullscreen = fullscreen; + _wlmtk_window_apply_decoration(window_ptr); + wlmtk_workspace_window_to_fullscreen( wlmtk_window_get_workspace(window_ptr), window_ptr, fullscreen); } @@ -698,7 +674,7 @@ bool _wlmtk_window_init( /* ------------------------------------------------------------------------- */ /** - * Uninitializes the winodw. + * Uninitializes the window. * * @param window_ptr */ @@ -867,12 +843,128 @@ void _wlmtk_window_request_position_and_size( int y, int width, int height) +{ + _wlmtk_window_request_position_and_size_decorated( + window_ptr, x, y, width, height, + NULL != window_ptr->titlebar_ptr, + NULL != window_ptr->resizebar_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** Creates the titlebar. Expects server_side_decorated to be set. */ +void _wlmtk_window_create_titlebar(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(window_ptr->server_side_decorated && !window_ptr->fullscreen); + + // Guard clause: Don't add decoration. + if (NULL != window_ptr->titlebar_ptr) return; + + // Create decoration. + window_ptr->titlebar_ptr = wlmtk_titlebar_create( + window_ptr->super_bordered.super_container.super_element.env_ptr, + window_ptr, &titlebar_style); + BS_ASSERT(NULL != window_ptr->titlebar_ptr); + wlmtk_titlebar_set_activated( + window_ptr->titlebar_ptr, window_ptr->activated); + wlmtk_element_set_visible( + wlmtk_titlebar_element(window_ptr->titlebar_ptr), true); + // Hm, if the content has a popup that extends over the titlebar area, + // it'll be partially obscured. That will look odd... Well, let's + // address that problem once there's a situation. + wlmtk_box_add_element_front( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); +} + +/* ------------------------------------------------------------------------- */ +/** Creates the resizebar. Expects server_side_decorated to be set. */ +void _wlmtk_window_create_resizebar(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(window_ptr->server_side_decorated && !window_ptr->fullscreen); + + // Guard clause: Don't add decoration. + if (NULL != window_ptr->resizebar_ptr) return; + + window_ptr->resizebar_ptr = wlmtk_resizebar_create( + window_ptr->super_bordered.super_container.super_element.env_ptr, + window_ptr, &resizebar_style); + BS_ASSERT(NULL != window_ptr->resizebar_ptr); + wlmtk_element_set_visible( + wlmtk_resizebar_element(window_ptr->resizebar_ptr), true); + wlmtk_box_add_element_back( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); +} + +/* ------------------------------------------------------------------------- */ +/** Destroys the titlebar. */ +void _wlmtk_window_destroy_titlebar(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(!window_ptr->server_side_decorated || window_ptr->fullscreen); + + if (NULL == window_ptr->titlebar_ptr) return; + + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_titlebar_element(window_ptr->titlebar_ptr)); + wlmtk_titlebar_destroy(window_ptr->titlebar_ptr); + window_ptr->titlebar_ptr = NULL; +} + +/* ------------------------------------------------------------------------- */ +/** Destroys the resizebar. */ +void _wlmtk_window_destroy_resizebar(wlmtk_window_t *window_ptr) +{ + BS_ASSERT(!window_ptr->server_side_decorated || window_ptr->fullscreen); + + if (NULL == window_ptr->resizebar_ptr) return; + + wlmtk_box_remove_element( + &window_ptr->box, + wlmtk_resizebar_element(window_ptr->resizebar_ptr)); + wlmtk_resizebar_destroy(window_ptr->resizebar_ptr); + window_ptr->resizebar_ptr = NULL; +} + +/* ------------------------------------------------------------------------- */ +/** Applies window decoration depending on current state. */ +void _wlmtk_window_apply_decoration(wlmtk_window_t *window_ptr) +{ + if (window_ptr->server_side_decorated && !window_ptr->fullscreen) { + _wlmtk_window_create_titlebar(window_ptr); + _wlmtk_window_create_resizebar(window_ptr); + } else { + _wlmtk_window_destroy_titlebar(window_ptr); + _wlmtk_window_destroy_resizebar(window_ptr); + } +} + +/* ------------------------------------------------------------------------- */ +/** + * Helper: Requests position and size, factoring in decoration. + * + * @param window_ptr + * @param x + * @param y + * @param width + * @param height + * @param include_titlebar + * @param include_resizebar + */ +void _wlmtk_window_request_position_and_size_decorated( + wlmtk_window_t *window_ptr, + int x, + int y, + int width, + int height, + bool include_titlebar, + bool include_resizebar) { // Correct for borders, margin and decoration. - if (NULL != window_ptr->titlebar_ptr) { + if (include_titlebar) { height -= titlebar_style.height + margin_style.width; } - if (NULL != window_ptr->resizebar_ptr) { + if (include_resizebar) { height -= resizebar_style.height + margin_style.width; } height -= 2 * border_style.width; @@ -1206,25 +1298,74 @@ void test_set_activated(bs_test_t *test_ptr) /** Tests enabling and disabling server-side decoration. */ void test_server_side_decorated(bs_test_t *test_ptr) { + wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); + BS_ASSERT(NULL != fake_parent_ptr); + wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( + NULL, fake_parent_ptr->wlr_scene_tree_ptr); + struct wlr_box extents = { .width = 1024, .height = 768 }; + wlmtk_workspace_set_extents(workspace_ptr, &extents); + BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); + wlmtk_workspace_map_window(workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); wlmtk_window_set_server_side_decorated(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + // Maximize the window: We keep the decoration. + wlmtk_window_request_maximized(window_ptr, true); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + // Make the window fullscreen: Hide the decoration. + wlmtk_window_request_fullscreen(window_ptr, true); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(window_ptr, false); + wlmtk_window_commit_fullscreen(window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + + // Back to organic size: Decoration is on. + wlmtk_window_request_fullscreen(window_ptr, false); + wlmtk_content_commit_size(&content, + fake_surface_ptr->serial, + fake_surface_ptr->requested_width, + fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(window_ptr, false); + BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + // Disable decoration. wlmtk_window_set_server_side_decorated(window_ptr, false); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_workspace_destroy(workspace_ptr); + wlmtk_container_destroy_fake_parent(fake_parent_ptr); } /* ------------------------------------------------------------------------- */ @@ -1390,6 +1531,10 @@ void test_fullscreen(bs_test_t *test_ptr) window_ptr, wlmtk_workspace_get_activated_window(workspace_ptr)); + BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + // Request to end fullscreen. Not taking immediate effect. wlmtk_window_request_fullscreen(window_ptr, false); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); @@ -1416,6 +1561,10 @@ void test_fullscreen(bs_test_t *test_ptr) window_ptr, wlmtk_workspace_get_activated_window(workspace_ptr)); + BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); From 6779185e1087a9bc9591e7bd8c236ed7d2e4760d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 19:34:10 +0100 Subject: [PATCH 378/390] Adds some recent updates to the roadmap. --- doc/ROADMAP.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/ROADMAP.md b/doc/ROADMAP.md index 2595eecb..413e35de 100644 --- a/doc/ROADMAP.md +++ b/doc/ROADMAP.md @@ -118,9 +118,9 @@ Support for visual effects to improve usability, but not for pure show. * Configurable (in code). * Window actions, based on toolkit. - * Move (drag via title bar, or window-alt-click) + * Move ([done] drag via title bar, or [pending] window-alt-click) * [done] Resize windows, including a resize bar. - * Fullscreen windows. + * [done] Fullscreen windows. * [done] Maximize windows. * Minimize (*iconify*) windows. * Roll up (*shade*) windows. @@ -164,6 +164,8 @@ Features for further versions, not ordered by priority nor timeline. * Determine how to detect client preferences. * Configurable and overridable (titlebar, resizebar, buttons, ...). * Scaling factor per application. + * Build and test a clear model for `organic`/`maximized`/`fullscreen` state + switches and precedence. * Application support. * Icons retrieved and used for iconified windows. See [themes](https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html). From d33a3b3f69dcf83e819d356606008bfbcedaaca1 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 19:54:52 +0100 Subject: [PATCH 379/390] Adds wlmtk_fake_workspace_t to simplify tests. --- src/toolkit/window.c | 81 ++++++++---------- src/toolkit/workspace.c | 176 ++++++++++++++++++++++------------------ src/toolkit/workspace.h | 13 +++ 3 files changed, 143 insertions(+), 127 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 7e678877..afabd5e1 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -1298,20 +1298,15 @@ void test_set_activated(bs_test_t *test_ptr) /** Tests enabling and disabling server-side decoration. */ void test_server_side_decorated(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - struct wlr_box extents = { .width = 1024, .height = 768 }; - wlmtk_workspace_set_extents(workspace_ptr, &extents); - BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); @@ -1360,25 +1355,22 @@ void test_server_side_decorated(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests maximizing and un-maximizing a window. */ void test_maximize(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - struct wlr_box extents = { .width = 1024, .height = 768 }, box; - wlmtk_workspace_set_extents(workspace_ptr, &extents); - BS_ASSERT(NULL != workspace_ptr); + struct wlr_box box; + + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; @@ -1386,7 +1378,7 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); // Window must be mapped to get maximized: Need workspace dimensions. - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); @@ -1458,25 +1450,21 @@ void test_maximize(bs_test_t *test_ptr) // Or just move on? // Window Maker keeps maximization, but it's ... odd. - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests turning a window to fullscreen and back. */ void test_fullscreen(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - struct wlr_box extents = { .width = 1024, .height = 768 }, box; - wlmtk_workspace_set_extents(workspace_ptr, &extents); - BS_ASSERT(NULL != workspace_ptr); + struct wlr_box box; + + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; @@ -1484,13 +1472,13 @@ void test_fullscreen(bs_test_t *test_ptr) wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); wlmtk_window_set_server_side_decorated(window_ptr, true); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, window_ptr, - wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); @@ -1529,7 +1517,7 @@ void test_fullscreen(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, window_ptr, - wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); @@ -1559,45 +1547,41 @@ void test_fullscreen(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ( test_ptr, window_ptr, - wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests that unmapping a fullscreen window works. */ void test_fullscreen_unmap(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - struct wlr_box extents = { .width = 1024, .height = 768 }, box; - wlmtk_workspace_set_extents(workspace_ptr, &extents); - BS_ASSERT(NULL != workspace_ptr); + struct wlr_box box; + + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, window_ptr, - wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); // Request fullscreen. Does not take immediate effect. wlmtk_window_request_fullscreen(window_ptr, true); @@ -1617,19 +1601,18 @@ void test_fullscreen_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_workspace_get_activated_window(workspace_ptr)); + wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } // FIXME: Test that fullscreen keeps window decoration as it should. diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 82233a10..56d9c50f 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -439,6 +439,49 @@ void wlmtk_workspace_raise_window( wlmtk_window_element(window_ptr)); } +/* == Fake workspace methods, useful for tests ============================= */ + +/* ------------------------------------------------------------------------- */ +wlmtk_fake_workspace_t *wlmtk_fake_workspace_create(int width, int height) +{ + wlmtk_fake_workspace_t *fw_ptr = logged_calloc( + 1, sizeof(wlmtk_fake_workspace_t)); + if (NULL == fw_ptr) return NULL; + + fw_ptr->fake_parent_ptr = wlmtk_container_create_fake_parent(); + if (NULL == fw_ptr->fake_parent_ptr) { + wlmtk_fake_workspace_destroy(fw_ptr); + return NULL; + } + + fw_ptr->workspace_ptr = wlmtk_workspace_create( + NULL, fw_ptr->fake_parent_ptr->wlr_scene_tree_ptr); + if (NULL == fw_ptr->workspace_ptr) { + wlmtk_fake_workspace_destroy(fw_ptr); + return NULL; + } + struct wlr_box extents = { .width = width, .height = height }; + wlmtk_workspace_set_extents(fw_ptr->workspace_ptr, &extents); + + return fw_ptr; +} + +/* ------------------------------------------------------------------------- */ +void wlmtk_fake_workspace_destroy(wlmtk_fake_workspace_t *fw_ptr) +{ + if (NULL != fw_ptr->workspace_ptr) { + wlmtk_workspace_destroy(fw_ptr->workspace_ptr); + fw_ptr->workspace_ptr = NULL; + } + + if (NULL != fw_ptr->fake_parent_ptr) { + wlmtk_container_destroy_fake_parent(fw_ptr->fake_parent_ptr); + fw_ptr->fake_parent_ptr = NULL; + } + + free(fw_ptr); +} + /* == Local (static) methods =============================================== */ /* ------------------------------------------------------------------------- */ @@ -742,11 +785,8 @@ void test_create_destroy(bs_test_t *test_ptr) /** Verifies that mapping and unmapping windows works. */ void test_map_unmap(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; @@ -755,7 +795,7 @@ void test_map_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, @@ -766,7 +806,7 @@ void test_map_unmap(bs_test_t *test_ptr) fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, @@ -780,29 +820,25 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests wlmtk_workspace_button. */ void test_button(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_element_t *fake_element_ptr = wlmtk_fake_element_create(); wlmtk_element_set_visible(&fake_element_ptr->element, true); BS_ASSERT(NULL != fake_element_ptr); wlmtk_container_add_element( - &workspace_ptr->super_container, &fake_element_ptr->element); + &fws_ptr->workspace_ptr->super_container, &fake_element_ptr->element); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_workspace_motion(workspace_ptr, 0, 0, 1234)); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 1234)); BS_TEST_VERIFY_TRUE( test_ptr, fake_element_ptr->pointer_motion_called); @@ -813,7 +849,7 @@ void test_button(bs_test_t *test_ptr) .state = WLR_BUTTON_PRESSED, .time_msec = 4321, }; - wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); + wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_pointer_button_event); wlmtk_button_event_t expected_event = { .button = 42, .type = WLMTK_BUTTON_DOWN, @@ -827,7 +863,7 @@ void test_button(bs_test_t *test_ptr) // The button up event should trigger a click. wlr_pointer_button_event.state = WLR_BUTTON_RELEASED; - wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); + wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_pointer_button_event); expected_event.type = WLMTK_BUTTON_CLICK; BS_TEST_VERIFY_MEMEQ( test_ptr, @@ -836,36 +872,32 @@ void test_button(bs_test_t *test_ptr) sizeof(wlmtk_button_event_t)); wlmtk_container_remove_element( - &workspace_ptr->super_container, &fake_element_ptr->element); + &fws_ptr->workspace_ptr->super_container, &fake_element_ptr->element); wlmtk_element_destroy(&fake_element_ptr->element); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests moving a window. */ void test_move(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); - wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); // Starts a move for the window. Will move it... - wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); - wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); + wlmtk_workspace_begin_window_move(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 1, 2, 43); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); @@ -875,79 +907,72 @@ void test_move(bs_test_t *test_ptr) .state = WLR_BUTTON_RELEASED, .time_msec = 44, }; - wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_pointer_button_event); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fws_ptr->workspace_ptr->grabbed_window_ptr); // More motion, no longer updates the position. - wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 3, 4, 45); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests moving a window that unmaps during the move. */ void test_unmap_during_move(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); BS_ASSERT(NULL != window_ptr); - wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); // Starts a move for the window. Will move it... - wlmtk_workspace_begin_window_move(workspace_ptr, window_ptr); - wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); + wlmtk_workspace_begin_window_move(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 1, 2, 43); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fws_ptr->workspace_ptr->grabbed_window_ptr); // More motion, no longer updates the position. - wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 3, 4, 45); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); // More motion, no longer updates the position. - wlmtk_workspace_motion(workspace_ptr, 3, 4, 45); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 3, 4, 45); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests resizing a window. */ void test_resize(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); + wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); wlmtk_content_t content; wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); @@ -958,9 +983,9 @@ void test_resize(bs_test_t *test_ptr) fake_surface_ptr->serial, fake_surface_ptr->requested_width, fake_surface_ptr->requested_height); - wlmtk_workspace_motion(workspace_ptr, 0, 0, 42); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); int width, height; @@ -970,9 +995,9 @@ void test_resize(bs_test_t *test_ptr) // Starts a resize for the window. Will resize & move it... wlmtk_workspace_begin_window_resize( - workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); + fws_ptr->workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); fake_surface_ptr->serial = 1; // The serial. - wlmtk_workspace_motion(workspace_ptr, 1, 2, 43); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 1, 2, 43); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 37, fake_surface_ptr->requested_width); @@ -994,26 +1019,22 @@ void test_resize(bs_test_t *test_ptr) .state = WLR_BUTTON_RELEASED, .time_msec = 44, }; - wlmtk_workspace_button(workspace_ptr, &wlr_pointer_button_event); - BS_TEST_VERIFY_EQ(test_ptr, NULL, workspace_ptr->grabbed_window_ptr); + wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_pointer_button_event); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fws_ptr->workspace_ptr->grabbed_window_ptr); - wlmtk_workspace_unmap_window(workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); wlmtk_window_destroy(window_ptr); wlmtk_content_fini(&content); wlmtk_fake_surface_destroy(fake_surface_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* ------------------------------------------------------------------------- */ /** Tests window activation. */ void test_activate(bs_test_t *test_ptr) { - wlmtk_container_t *fake_parent_ptr = wlmtk_container_create_fake_parent(); - BS_ASSERT(NULL != fake_parent_ptr); - wlmtk_workspace_t *workspace_ptr = wlmtk_workspace_create( - NULL, fake_parent_ptr->wlr_scene_tree_ptr); - BS_ASSERT(NULL != workspace_ptr); + wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); + BS_ASSERT(NULL != fws_ptr); // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); @@ -1026,7 +1047,7 @@ void test_activate(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); // Window 1 is mapped => it's activated. - wlmtk_workspace_map_window(workspace_ptr, fw1_ptr->window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw1_ptr->window_ptr); BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); // Window 2: from (200, 0) to (300, 100). @@ -1039,14 +1060,14 @@ void test_activate(bs_test_t *test_ptr) fw2_ptr->fake_surface_ptr->requested_height); wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); - wlmtk_workspace_map_window(workspace_ptr, fw2_ptr->window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); // Pointer move, over window 1. Nothing happens: We have click-to-focus. BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_workspace_motion(workspace_ptr, 50, 50, 0)); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 50, 50, 0)); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); @@ -1054,23 +1075,22 @@ void test_activate(bs_test_t *test_ptr) struct wlr_pointer_button_event wlr_button_event = { .button = BTN_RIGHT, .state = WLR_BUTTON_PRESSED }; - wlmtk_workspace_button(workspace_ptr, &wlr_button_event); + wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_button_event); BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); // Unmap window 1. Now window 2 gets activated. - wlmtk_workspace_unmap_window(workspace_ptr, fw1_ptr->window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw1_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); // Unmap the remaining window 2. Nothing is activated. - wlmtk_workspace_unmap_window(workspace_ptr, fw2_ptr->window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw2_ptr->window_ptr); BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); wlmtk_fake_window_destroy(fw2_ptr); wlmtk_fake_window_destroy(fw1_ptr); - wlmtk_workspace_destroy(workspace_ptr); - wlmtk_container_destroy_fake_parent(fake_parent_ptr); + wlmtk_fake_workspace_destroy(fws_ptr); } /* == End of workspace.c =================================================== */ diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index ff1dbd46..5d04e724 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -193,6 +193,19 @@ void wlmtk_workspace_raise_window( wlmtk_workspace_t *workspace_ptr, wlmtk_window_t *window_ptr); +/** Fake workspace: A real workspace, but with a fake parent. For testing. */ +typedef struct { + /** The workspace. */ + wlmtk_workspace_t *workspace_ptr; + /** The (fake) parent container. */ + wlmtk_container_t *fake_parent_ptr; +} wlmtk_fake_workspace_t; + +/** Creates a fake workspace with specified extents. */ +wlmtk_fake_workspace_t *wlmtk_fake_workspace_create(int width, int height); +/** Destroys the fake workspace. */ +void wlmtk_fake_workspace_destroy(wlmtk_fake_workspace_t *fake_workspace_ptr); + /** Unit tests for the workspace. */ extern const bs_test_case_t wlmtk_workspace_test_cases[]; From d4d48336b2df280740d758b4e4db703859407984 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:20:31 +0100 Subject: [PATCH 380/390] Makes wlmtk_window_set_activated no longer virtual, and uses fake window in a workspace test. --- src/toolkit/window.c | 91 +++++++++++++---------------------------- src/toolkit/window.h | 11 ++++- src/toolkit/workspace.c | 48 ++++++++++++++++------ 3 files changed, 74 insertions(+), 76 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index afabd5e1..5e29e36a 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -34,9 +34,6 @@ struct _wlmtk_window_vmt_t { /** Destructor. */ void (*destroy)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_set_activated. */ - void (*set_activated)(wlmtk_window_t *window_ptr, - bool activated); /** Virtual method for @ref wlmtk_window_request_close. */ void (*request_close)(wlmtk_window_t *window_ptr); /** Virtual method for @ref wlmtk_window_request_minimize. */ @@ -157,9 +154,6 @@ static bool _wlmtk_window_element_pointer_button( static void _wlmtk_window_container_update_layout( wlmtk_container_t *container_ptr); -static void _wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated); static void _wlmtk_window_request_close(wlmtk_window_t *window_ptr); static void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); static void _wlmtk_window_request_move(wlmtk_window_t *window_ptr); @@ -205,7 +199,6 @@ static const wlmtk_container_vmt_t window_container_vmt = { }; /** Virtual method table for the window itself. */ static const wlmtk_window_vmt_t _wlmtk_window_vmt = { - .set_activated = _wlmtk_window_set_activated, .request_close = _wlmtk_window_request_close, .request_minimize = _wlmtk_window_request_minimize, .request_move = _wlmtk_window_request_move, @@ -307,7 +300,17 @@ void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated) { - window_ptr->vmt.set_activated(window_ptr, activated); + window_ptr->activated = activated; + wlmtk_content_set_activated(window_ptr->content_ptr, activated); + if (NULL != window_ptr->titlebar_ptr) { + wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); + } +} + +/* ------------------------------------------------------------------------- */ +bool wlmtk_window_is_activated(wlmtk_window_t *window_ptr) +{ + return window_ptr->activated; } /* ------------------------------------------------------------------------- */ @@ -717,9 +720,6 @@ wlmtk_window_vmt_t _wlmtk_window_extend( { wlmtk_window_vmt_t orig_vmt = window_ptr->vmt; - if (NULL != window_vmt_ptr->set_activated) { - window_ptr->vmt.set_activated = window_vmt_ptr->set_activated; - } if (NULL != window_vmt_ptr->request_close) { window_ptr->vmt.request_close = window_vmt_ptr->request_close; } @@ -790,19 +790,6 @@ void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) } } -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_set_activated. */ -void _wlmtk_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated) -{ - window_ptr->activated = activated; - wlmtk_content_set_activated(window_ptr->content_ptr, activated); - if (NULL != window_ptr->titlebar_ptr) { - wlmtk_titlebar_set_activated(window_ptr->titlebar_ptr, activated); - } -} - /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_close. */ void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) @@ -1033,9 +1020,6 @@ void _wlmtk_window_release_update( /* == Implementation of the fake window ==================================== */ -static void _wlmtk_fake_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated); static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); @@ -1051,7 +1035,6 @@ static void _wlmtk_fake_window_request_position_and_size( /** Virtual method table for the fake window itself. */ static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { - .set_activated = _wlmtk_fake_window_set_activated, .request_close = _wlmtk_fake_window_request_close, .request_minimize = _wlmtk_fake_window_request_minimize, .request_move = _wlmtk_fake_window_request_move, @@ -1122,17 +1105,6 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) free(fake_window_state_ptr); } -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_set_activated. Records call. */ -void _wlmtk_fake_window_set_activated( - wlmtk_window_t *window_ptr, - bool activated) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.activated = activated; -} - /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_close. Records call. */ void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr) @@ -1570,47 +1542,42 @@ void test_fullscreen_unmap(bs_test_t *test_ptr) wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_ASSERT(NULL != window_ptr); - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, - window_ptr, + fw_ptr->window_ptr, wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); // Request fullscreen. Does not take immediate effect. - wlmtk_window_request_fullscreen(window_ptr, true); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + wlmtk_window_request_fullscreen(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); // Only after "commit", it will take effect. - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_fullscreen(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); BS_TEST_VERIFY_EQ(test_ptr, 1024 + 2, box.width); BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->activated); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, fake_surface_ptr->activated); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, fw_ptr->fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, NULL, wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 7a39e104..5d642afa 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -94,6 +94,15 @@ void wlmtk_window_set_activated( wlmtk_window_t *window_ptr, bool activated); +/** + * Returns whether the window is activated (has keyboard focus). + * + * @param window_ptr + * + * @return activation status. + */ +bool wlmtk_window_is_activated(wlmtk_window_t *window_ptr); + /** * Sets whether to have server-side decorations for this window. * @@ -359,8 +368,6 @@ typedef struct { /** Content, wraps the fake surface. */ wlmtk_content_t *content_ptr; - /** Argument to last @ref wlmtk_window_set_activated call. */ - bool activated; /** Whether @ref wlmtk_window_request_close was called. */ bool request_close_called; /** Whether @ref wlmtk_window_request_minimize was called. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 56d9c50f..61370a3d 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -1044,11 +1044,15 @@ void test_activate(bs_test_t *test_ptr) fw1_ptr->fake_surface_ptr->requested_width, fw1_ptr->fake_surface_ptr->requested_height); wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); - BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw1_ptr->window_ptr)); // Window 1 is mapped => it's activated. wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw1_ptr->window_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_window_is_activated(fw1_ptr->window_ptr)); // Window 2: from (200, 0) to (300, 100). // Window 2 is mapped: Will get activated, and 1st one de-activated. @@ -1059,34 +1063,54 @@ void test_activate(bs_test_t *test_ptr) fw2_ptr->fake_surface_ptr->requested_width, fw2_ptr->fake_surface_ptr->requested_height); wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); - BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw2_ptr->window_ptr)); wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw2_ptr->window_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); - BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw1_ptr->window_ptr)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_window_is_activated(fw2_ptr->window_ptr)); // Pointer move, over window 1. Nothing happens: We have click-to-focus. BS_TEST_VERIFY_TRUE( test_ptr, wlmtk_workspace_motion(fws_ptr->workspace_ptr, 50, 50, 0)); - BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); - BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw1_ptr->window_ptr)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_window_is_activated(fw2_ptr->window_ptr)); // Click on window 1: Gets activated. struct wlr_pointer_button_event wlr_button_event = { .button = BTN_RIGHT, .state = WLR_BUTTON_PRESSED }; wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_button_event); - BS_TEST_VERIFY_TRUE(test_ptr, fw1_ptr->activated); - BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_window_is_activated(fw1_ptr->window_ptr)); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw2_ptr->window_ptr)); // Unmap window 1. Now window 2 gets activated. wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw1_ptr->window_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, fw1_ptr->activated); - BS_TEST_VERIFY_TRUE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw1_ptr->window_ptr)); + BS_TEST_VERIFY_TRUE( + test_ptr, + wlmtk_window_is_activated(fw2_ptr->window_ptr)); // Unmap the remaining window 2. Nothing is activated. wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw2_ptr->window_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, fw2_ptr->activated); + BS_TEST_VERIFY_FALSE( + test_ptr, + wlmtk_window_is_activated(fw2_ptr->window_ptr)); wlmtk_fake_window_destroy(fw2_ptr); wlmtk_fake_window_destroy(fw1_ptr); From a1f97e3c889d99729e6e6fa59cb91bf257c98242 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:26:52 +0100 Subject: [PATCH 381/390] Make wlmtk_window_request_position_and_size no longer virtual. --- src/toolkit/window.c | 66 +++++------------------------------------ src/toolkit/window.h | 10 ------- src/toolkit/workspace.c | 57 ++++++++++++++++------------------- 3 files changed, 34 insertions(+), 99 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 5e29e36a..1839b1f1 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -43,9 +43,6 @@ struct _wlmtk_window_vmt_t { /** Virtual method for @ref wlmtk_window_request_resize. */ void (*request_resize)(wlmtk_window_t *window_ptr, uint32_t edges); - /** Virtual method for @ref wlmtk_window_request_position_and_size. */ - void (*request_position_and_size)(wlmtk_window_t *window_ptr, - int x, int y, int width, int height); }; /** Pending positional updates for @ref wlmtk_window_t::content_ptr. */ @@ -160,12 +157,6 @@ static void _wlmtk_window_request_move(wlmtk_window_t *window_ptr); static void _wlmtk_window_request_resize( wlmtk_window_t *window_ptr, uint32_t edges); -static void _wlmtk_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height); static void _wlmtk_window_create_titlebar(wlmtk_window_t *window_ptr); static void _wlmtk_window_create_resizebar(wlmtk_window_t *window_ptr); @@ -203,7 +194,6 @@ static const wlmtk_window_vmt_t _wlmtk_window_vmt = { .request_minimize = _wlmtk_window_request_minimize, .request_move = _wlmtk_window_request_move, .request_resize = _wlmtk_window_request_resize, - .request_position_and_size = _wlmtk_window_request_position_and_size, }; /** Style of the title bar. */ @@ -399,8 +389,10 @@ void wlmtk_window_request_maximized( wlmtk_content_request_maximized(window_ptr->content_ptr, maximized); - _wlmtk_window_request_position_and_size( - window_ptr, box.x, box.y, box.width, box.height); + _wlmtk_window_request_position_and_size_decorated( + window_ptr, box.x, box.y, box.width, box.height, + window_ptr->server_side_decorated, + window_ptr->server_side_decorated); } /* ------------------------------------------------------------------------- */ @@ -568,8 +560,10 @@ void wlmtk_window_request_position_and_size( int width, int height) { - window_ptr->vmt.request_position_and_size( - window_ptr, x, y, width, height); + _wlmtk_window_request_position_and_size_decorated( + window_ptr, x, y, width, height, + NULL != window_ptr->titlebar_ptr, + NULL != window_ptr->resizebar_ptr); window_ptr->organic_size.x = x; window_ptr->organic_size.y = y; @@ -732,10 +726,6 @@ wlmtk_window_vmt_t _wlmtk_window_extend( if (NULL != window_vmt_ptr->request_resize) { window_ptr->vmt.request_resize = window_vmt_ptr->request_resize; } - if (NULL != window_vmt_ptr->request_position_and_size) { - window_ptr->vmt.request_position_and_size = - window_vmt_ptr->request_position_and_size; - } return orig_vmt; } @@ -822,21 +812,6 @@ void _wlmtk_window_request_resize(wlmtk_window_t *window_ptr, uint32_t edges) wlmtk_window_get_workspace(window_ptr), window_ptr, edges); } -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_position_and_size. */ -void _wlmtk_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height) -{ - _wlmtk_window_request_position_and_size_decorated( - window_ptr, x, y, width, height, - NULL != window_ptr->titlebar_ptr, - NULL != window_ptr->resizebar_ptr); -} - /* ------------------------------------------------------------------------- */ /** Creates the titlebar. Expects server_side_decorated to be set. */ void _wlmtk_window_create_titlebar(wlmtk_window_t *window_ptr) @@ -1026,12 +1001,6 @@ static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); static void _wlmtk_fake_window_request_resize( wlmtk_window_t *window_ptr, uint32_t edges); -static void _wlmtk_fake_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height); /** Virtual method table for the fake window itself. */ static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { @@ -1039,7 +1008,6 @@ static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { .request_minimize = _wlmtk_fake_window_request_minimize, .request_move = _wlmtk_fake_window_request_move, .request_resize = _wlmtk_fake_window_request_resize, - .request_position_and_size = _wlmtk_fake_window_request_position_and_size, }; @@ -1144,24 +1112,6 @@ void _wlmtk_fake_window_request_resize( fake_window_state_ptr->fake_window.request_resize_edges = edges; } -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_position_and_size. */ -void _wlmtk_fake_window_request_position_and_size( - wlmtk_window_t *window_ptr, - int x, - int y, - int width, - int height) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_position_and_size_called = true; - fake_window_state_ptr->fake_window.x = x; - fake_window_state_ptr->fake_window.y = y; - fake_window_state_ptr->fake_window.width = width; - fake_window_state_ptr->fake_window.height = height; -} - /* == Unit tests =========================================================== */ static void test_create_destroy(bs_test_t *test_ptr); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index 5d642afa..d169ac85 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -378,16 +378,6 @@ typedef struct { bool request_resize_called; /** Argument to last @ref wlmtk_window_request_resize call. */ uint32_t request_resize_edges; - /** Whether @ref wlmtk_window_request_position_and_size was called. */ - bool request_position_and_size_called; - /** Argument to last @ref wlmtk_window_request_size call. */ - int x; - /** Argument to last @ref wlmtk_window_request_size call. */ - int y; - /** Argument to last @ref wlmtk_window_request_size call. */ - int width; - /** Argument to last @ref wlmtk_window_request_size call. */ - int height; } wlmtk_fake_window_t; /** Ctor. */ diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 61370a3d..c5fa66a7 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -973,43 +973,40 @@ void test_resize(bs_test_t *test_ptr) wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_ASSERT(NULL != window_ptr); - wlmtk_window_request_position_and_size(window_ptr, 0, 0, 40, 20); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); + wlmtk_window_request_position_and_size(fw_ptr->window_ptr, 0, 0, 40, 20); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->y); int width, height; - wlmtk_window_get_size(window_ptr, &width, &height); + wlmtk_window_get_size(fw_ptr->window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 40, width); BS_TEST_VERIFY_EQ(test_ptr, 20, height); // Starts a resize for the window. Will resize & move it... wlmtk_workspace_begin_window_resize( - fws_ptr->workspace_ptr, window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); - fake_surface_ptr->serial = 1; // The serial. + fws_ptr->workspace_ptr, fw_ptr->window_ptr, WLR_EDGE_TOP | WLR_EDGE_LEFT); + fw_ptr->fake_surface_ptr->serial = 1; // The serial. wlmtk_workspace_motion(fws_ptr->workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); - BS_TEST_VERIFY_EQ(test_ptr, 37, fake_surface_ptr->requested_width); - BS_TEST_VERIFY_EQ(test_ptr, 16, fake_surface_ptr->requested_height); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 37, fw_ptr->fake_surface_ptr->requested_width); + BS_TEST_VERIFY_EQ(test_ptr, 16, fw_ptr->fake_surface_ptr->requested_height); // This updates for the given serial. - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_get_size(window_ptr, &width, &height); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_get_size(fw_ptr->window_ptr, &width, &height); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); BS_TEST_VERIFY_EQ(test_ptr, 39, width); BS_TEST_VERIFY_EQ(test_ptr, 18, height); @@ -1022,10 +1019,8 @@ void test_resize(bs_test_t *test_ptr) wlmtk_workspace_button(fws_ptr->workspace_ptr, &wlr_pointer_button_event); BS_TEST_VERIFY_EQ(test_ptr, NULL, fws_ptr->workspace_ptr->grabbed_window_ptr); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } From 707f640728a3be42525a66aea3409477a52b1ddb Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:30:35 +0100 Subject: [PATCH 382/390] Uses wlmtk_fake_window_t in all of wlmtk_workspace_t tests. --- src/toolkit/workspace.c | 95 ++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index c5fa66a7..33190810 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -788,38 +788,33 @@ void test_map_unmap(bs_test_t *test_ptr) wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr); - - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); + + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(fw_ptr->window_ptr)->visible); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, - wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); + wlmtk_window_element(fw_ptr->window_ptr)->wlr_scene_node_ptr); BS_TEST_VERIFY_NEQ( test_ptr, NULL, - fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(window_ptr)->visible); + fw_ptr->fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_element(fw_ptr->window_ptr)->visible); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, - wlmtk_window_element(window_ptr)->wlr_scene_node_ptr); + wlmtk_window_element(fw_ptr->window_ptr)->wlr_scene_node_ptr); BS_TEST_VERIFY_EQ( test_ptr, NULL, - fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(window_ptr)->visible); + fw_ptr->fake_surface_ptr->surface.super_element.wlr_scene_node_ptr); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_element(fw_ptr->window_ptr)->visible); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } @@ -884,22 +879,20 @@ void test_move(bs_test_t *test_ptr) { wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_ASSERT(NULL != window_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->y); // Starts a move for the window. Will move it... - wlmtk_workspace_begin_window_move(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_begin_window_move(fws_ptr->workspace_ptr, fw_ptr->window_ptr); wlmtk_workspace_motion(fws_ptr->workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); // Releases the button. Should end the move. struct wlr_pointer_button_event wlr_pointer_button_event = { @@ -912,14 +905,12 @@ void test_move(bs_test_t *test_ptr) // More motion, no longer updates the position. wlmtk_workspace_motion(fws_ptr->workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } @@ -929,40 +920,36 @@ void test_unmap_during_move(bs_test_t *test_ptr) { wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_ASSERT(NULL != window_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); + wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(window_ptr)->y); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 0, wlmtk_window_element(fw_ptr->window_ptr)->y); // Starts a move for the window. Will move it... - wlmtk_workspace_begin_window_move(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_begin_window_move(fws_ptr->workspace_ptr, fw_ptr->window_ptr); wlmtk_workspace_motion(fws_ptr->workspace_ptr, 1, 2, 43); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, NULL, fws_ptr->workspace_ptr->grabbed_window_ptr); // More motion, no longer updates the position. wlmtk_workspace_motion(fws_ptr->workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); // More motion, no longer updates the position. wlmtk_workspace_motion(fws_ptr->workspace_ptr, 3, 4, 45); - BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(window_ptr)->x); - BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(window_ptr)->y); + BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); + BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } From e2c22bf8945b09d2a2f7d7a51aa216252b5368a0 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:33:56 +0100 Subject: [PATCH 383/390] Make wlmtk_window_request_close no longer virtual. --- src/toolkit/titlebar_button.c | 4 +-- src/toolkit/window.c | 59 ++++++++--------------------------- src/toolkit/window.h | 2 -- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/src/toolkit/titlebar_button.c b/src/toolkit/titlebar_button.c index c70ba9dd..99a123ac 100644 --- a/src/toolkit/titlebar_button.c +++ b/src/toolkit/titlebar_button.c @@ -336,7 +336,7 @@ void test_button(bs_test_t *test_ptr) // Click: To be passed along, no change to visual. BS_TEST_VERIFY_FALSE( test_ptr, - fake_window_ptr->request_close_called); + fake_window_ptr->fake_surface_ptr->request_close_called); button.type = WLMTK_BUTTON_CLICK; BS_TEST_VERIFY_TRUE( test_ptr, @@ -347,7 +347,7 @@ void test_button(bs_test_t *test_ptr) "toolkit/title_button_focussed_released.png"); BS_TEST_VERIFY_TRUE( test_ptr, - fake_window_ptr->request_close_called); + fake_window_ptr->fake_surface_ptr->request_close_called); // De-activate: Show as blurred. wlmtk_titlebar_button_set_activated(button_ptr, false); diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 1839b1f1..f298ce19 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -34,8 +34,6 @@ struct _wlmtk_window_vmt_t { /** Destructor. */ void (*destroy)(wlmtk_window_t *window_ptr); - /** Virtual method for @ref wlmtk_window_request_close. */ - void (*request_close)(wlmtk_window_t *window_ptr); /** Virtual method for @ref wlmtk_window_request_minimize. */ void (*request_minimize)(wlmtk_window_t *window_ptr); /** Virtual method for @ref wlmtk_window_request_move. */ @@ -151,7 +149,6 @@ static bool _wlmtk_window_element_pointer_button( static void _wlmtk_window_container_update_layout( wlmtk_container_t *container_ptr); -static void _wlmtk_window_request_close(wlmtk_window_t *window_ptr); static void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr); static void _wlmtk_window_request_move(wlmtk_window_t *window_ptr); static void _wlmtk_window_request_resize( @@ -190,7 +187,6 @@ static const wlmtk_container_vmt_t window_container_vmt = { }; /** Virtual method table for the window itself. */ static const wlmtk_window_vmt_t _wlmtk_window_vmt = { - .request_close = _wlmtk_window_request_close, .request_minimize = _wlmtk_window_request_minimize, .request_move = _wlmtk_window_request_move, .request_resize = _wlmtk_window_request_resize, @@ -359,7 +355,7 @@ const char *wlmtk_window_get_title(wlmtk_window_t *window_ptr) /* ------------------------------------------------------------------------- */ void wlmtk_window_request_close(wlmtk_window_t *window_ptr) { - window_ptr->vmt.request_close(window_ptr); + wlmtk_content_request_close(window_ptr->content_ptr); } /* ------------------------------------------------------------------------- */ @@ -714,9 +710,6 @@ wlmtk_window_vmt_t _wlmtk_window_extend( { wlmtk_window_vmt_t orig_vmt = window_ptr->vmt; - if (NULL != window_vmt_ptr->request_close) { - window_ptr->vmt.request_close = window_vmt_ptr->request_close; - } if (NULL != window_vmt_ptr->request_minimize) { window_ptr->vmt.request_minimize = window_vmt_ptr->request_minimize; } @@ -780,13 +773,6 @@ void _wlmtk_window_container_update_layout(wlmtk_container_t *container_ptr) } } -/* ------------------------------------------------------------------------- */ -/** Default implementation of @ref wlmtk_window_request_close. */ -void _wlmtk_window_request_close(wlmtk_window_t *window_ptr) -{ - wlmtk_content_request_close(window_ptr->content_ptr); -} - /* ------------------------------------------------------------------------- */ /** Default implementation of @ref wlmtk_window_request_minimize. */ void _wlmtk_window_request_minimize(wlmtk_window_t *window_ptr) @@ -995,7 +981,6 @@ void _wlmtk_window_release_update( /* == Implementation of the fake window ==================================== */ -static void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr); static void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr); static void _wlmtk_fake_window_request_move(wlmtk_window_t *window_ptr); static void _wlmtk_fake_window_request_resize( @@ -1004,7 +989,6 @@ static void _wlmtk_fake_window_request_resize( /** Virtual method table for the fake window itself. */ static const wlmtk_window_vmt_t _wlmtk_fake_window_vmt = { - .request_close = _wlmtk_fake_window_request_close, .request_minimize = _wlmtk_fake_window_request_minimize, .request_move = _wlmtk_fake_window_request_move, .request_resize = _wlmtk_fake_window_request_resize, @@ -1073,15 +1057,6 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) free(fake_window_state_ptr); } -/* ------------------------------------------------------------------------- */ -/** Fake implementation of @ref wlmtk_window_request_close. Records call. */ -void _wlmtk_fake_window_request_close(wlmtk_window_t *window_ptr) -{ - wlmtk_fake_window_state_t *fake_window_state_ptr = BS_CONTAINER_OF( - window_ptr, wlmtk_fake_window_state_t, window); - fake_window_state_ptr->fake_window.request_close_called = true; -} - /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_minimize. Records call. */ void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr) @@ -1157,43 +1132,35 @@ void test_create_destroy(bs_test_t *test_ptr) /** Tests title. */ void test_set_title(bs_test_t *test_ptr) { - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); - wlmtk_window_set_title(window_ptr, "Title"); + wlmtk_window_set_title(fw_ptr->window_ptr, "Title"); BS_TEST_VERIFY_STREQ( test_ptr, "Title", - wlmtk_window_get_title(window_ptr)); + wlmtk_window_get_title(fw_ptr->window_ptr)); - wlmtk_window_set_title(window_ptr, NULL); + wlmtk_window_set_title(fw_ptr->window_ptr, NULL); BS_TEST_VERIFY_STRMATCH( test_ptr, - wlmtk_window_get_title(window_ptr), + wlmtk_window_get_title(fw_ptr->window_ptr), "Unnamed window .*"); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); } /* ------------------------------------------------------------------------- */ /** Tests activation. */ void test_request_close(bs_test_t *test_ptr) { - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); - wlmtk_window_request_close(window_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->request_close_called); + wlmtk_window_request_close(fw_ptr->window_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->request_close_called); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/window.h b/src/toolkit/window.h index d169ac85..bc776744 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -368,8 +368,6 @@ typedef struct { /** Content, wraps the fake surface. */ wlmtk_content_t *content_ptr; - /** Whether @ref wlmtk_window_request_close was called. */ - bool request_close_called; /** Whether @ref wlmtk_window_request_minimize was called. */ bool request_minimize_called; /** Whether @ref wlmtk_window_request_move was called. */ From 6739c256423f84d2c814c1b6f584b9e3e9843d7e Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:38:02 +0100 Subject: [PATCH 384/390] Uses fake window in more of the wlmtk_window_t tests. --- src/toolkit/window.c | 188 ++++++++++++++++++++----------------------- 1 file changed, 87 insertions(+), 101 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index f298ce19..2c3ddd56 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -1167,20 +1167,16 @@ void test_request_close(bs_test_t *test_ptr) /** Tests activation. */ void test_set_activated(bs_test_t *test_ptr) { - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); - wlmtk_window_set_activated(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + wlmtk_window_set_activated(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->activated); - wlmtk_window_set_activated(window_ptr, false); - BS_TEST_VERIFY_FALSE(test_ptr, fake_surface_ptr->activated); + wlmtk_window_set_activated(fw_ptr->window_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, fw_ptr->fake_surface_ptr->activated); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_fake_window_destroy(fw_ptr); } /* ------------------------------------------------------------------------- */ @@ -1189,66 +1185,61 @@ void test_server_side_decorated(bs_test_t *test_ptr) { wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); - wlmtk_window_set_server_side_decorated(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_window_set_server_side_decorated(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); // Maximize the window: We keep the decoration. - wlmtk_window_request_maximized(window_ptr, true); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_maximized(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_window_request_maximized(fw_ptr->window_ptr, true); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); // Make the window fullscreen: Hide the decoration. - wlmtk_window_request_fullscreen(window_ptr, true); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_maximized(window_ptr, false); - wlmtk_window_commit_fullscreen(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_window_request_fullscreen(fw_ptr->window_ptr, true); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(fw_ptr->window_ptr, false); + wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); // Back to organic size: Decoration is on. - wlmtk_window_request_fullscreen(window_ptr, false); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_fullscreen(window_ptr, false); - BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_window_request_fullscreen(fw_ptr->window_ptr, false); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, false); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); // Disable decoration. - wlmtk_window_set_server_side_decorated(window_ptr, false); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + wlmtk_window_set_server_side_decorated(fw_ptr->window_ptr, false); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } @@ -1260,89 +1251,84 @@ void test_maximize(bs_test_t *test_ptr) wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_ASSERT(NULL != window_ptr); // Window must be mapped to get maximized: Need workspace dimensions. - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); // Set up initial organic size, and verify. - wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_window_request_position_and_size(fw_ptr->window_ptr, 20, 10, 200, 100); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(window_ptr)); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); // Re-position the window. - wlmtk_window_set_position(window_ptr, 50, 30); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_window_set_position(fw_ptr->window_ptr, 50, 30); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); // Trigger another serial update. Should not change position nor size. - wlmtk_window_serial(window_ptr, 1234); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_window_serial(fw_ptr->window_ptr, 1234); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); // Maximize. - wlmtk_window_request_maximized(window_ptr, true); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(window_ptr)); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_maximized(window_ptr, true); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_window_request_maximized(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(fw_ptr->window_ptr, true); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); BS_TEST_VERIFY_EQ(test_ptr, 960, box.width); BS_TEST_VERIFY_EQ(test_ptr, 704, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(window_ptr)); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); // A second commit: should not overwrite the organic dimension. - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); // Unmaximize. Restore earlier organic size and position. - wlmtk_window_request_maximized(window_ptr, false); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(window_ptr)); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_maximized(window_ptr, false); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_window_request_maximized(fw_ptr->window_ptr, false); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_maximized(fw_ptr->window_ptr, false); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); BS_TEST_VERIFY_EQ(test_ptr, 30, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(window_ptr)); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); // TODO(kaeser@gubbe.ch): Define what should happen when a maximized // window is moved. Should it lose maximization? Should it not move? // Or just move on? // Window Maker keeps maximization, but it's ... odd. - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } From 95dd06d1d621b1eb84edad000f24f410cefddf85 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:40:00 +0100 Subject: [PATCH 385/390] Uses fake window in the remaining of the wlmtk_window_t tests. --- src/toolkit/window.c | 95 +++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index 2c3ddd56..fdc1e86d 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -1340,98 +1340,93 @@ void test_fullscreen(bs_test_t *test_ptr) wlmtk_fake_workspace_t *fws_ptr = wlmtk_fake_workspace_create(1024, 768); BS_ASSERT(NULL != fws_ptr); + wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); + BS_ASSERT(NULL != fw_ptr); - wlmtk_fake_surface_t *fake_surface_ptr = wlmtk_fake_surface_create(); - wlmtk_content_t content; - wlmtk_content_init(&content, &fake_surface_ptr->surface, NULL); - wlmtk_window_t *window_ptr = wlmtk_window_create(&content, NULL); - BS_ASSERT(NULL != window_ptr); - wlmtk_window_set_server_side_decorated(window_ptr, true); - wlmtk_workspace_map_window(fws_ptr->workspace_ptr, window_ptr); + wlmtk_window_set_server_side_decorated(fw_ptr->window_ptr, true); + wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, - window_ptr, + fw_ptr->window_ptr, wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); // Set up initial organic size, and verify. - wlmtk_window_request_position_and_size(window_ptr, 20, 10, 200, 100); - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_window_request_position_and_size(fw_ptr->window_ptr, 20, 10, 200, 100); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_FALSE(test_ptr, window_ptr->inorganic_sizing); + BS_TEST_VERIFY_FALSE(test_ptr, fw_ptr->window_ptr->inorganic_sizing); // Request fullscreen. Does not take immediate effect. - wlmtk_window_request_fullscreen(window_ptr, true); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + wlmtk_window_request_fullscreen(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_titlebar_is_activated(window_ptr->titlebar_ptr)); + wlmtk_titlebar_is_activated(fw_ptr->window_ptr->titlebar_ptr)); // Only after "commit", it will take effect. - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_fullscreen(window_ptr, true); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, true); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); BS_TEST_VERIFY_EQ(test_ptr, 0, box.y); BS_TEST_VERIFY_EQ(test_ptr, 1024 + 2, box.width); BS_TEST_VERIFY_EQ(test_ptr, 768 + 2, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->activated); BS_TEST_VERIFY_EQ( test_ptr, - window_ptr, + fw_ptr->window_ptr, wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); - BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_EQ(test_ptr, NULL, window_ptr->resizebar_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_EQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); // Request to end fullscreen. Not taking immediate effect. - wlmtk_window_request_fullscreen(window_ptr, false); - BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); + wlmtk_window_request_fullscreen(fw_ptr->window_ptr, false); + BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); // Takes effect after commit. We'll want the same position as before. - wlmtk_content_commit_size(&content, - fake_surface_ptr->serial, - fake_surface_ptr->requested_width, - fake_surface_ptr->requested_height); - wlmtk_window_commit_fullscreen(window_ptr, false); - BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(window_ptr)); - box = wlmtk_window_get_position_and_size(window_ptr); + wlmtk_content_commit_size(fw_ptr->content_ptr, + fw_ptr->fake_surface_ptr->serial, + fw_ptr->fake_surface_ptr->requested_width, + fw_ptr->fake_surface_ptr->requested_height); + wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, false); + BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); + box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); BS_TEST_VERIFY_EQ(test_ptr, 200, box.width); BS_TEST_VERIFY_EQ(test_ptr, 100, box.height); - BS_TEST_VERIFY_TRUE(test_ptr, fake_surface_ptr->activated); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->fake_surface_ptr->activated); BS_TEST_VERIFY_TRUE( test_ptr, - wlmtk_titlebar_is_activated(window_ptr->titlebar_ptr)); + wlmtk_titlebar_is_activated(fw_ptr->window_ptr->titlebar_ptr)); BS_TEST_VERIFY_EQ( test_ptr, - window_ptr, + fw_ptr->window_ptr, wlmtk_workspace_get_activated_window(fws_ptr->workspace_ptr)); - BS_TEST_VERIFY_TRUE(test_ptr, window_ptr->server_side_decorated); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->titlebar_ptr); - BS_TEST_VERIFY_NEQ(test_ptr, NULL, window_ptr->resizebar_ptr); + BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); + BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->resizebar_ptr); - wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, window_ptr); - wlmtk_window_destroy(window_ptr); - wlmtk_content_fini(&content); - wlmtk_fake_surface_destroy(fake_surface_ptr); + wlmtk_workspace_unmap_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); + wlmtk_fake_window_destroy(fw_ptr); wlmtk_fake_workspace_destroy(fws_ptr); } From 6591fd1378454b49fdd1c0af70b728793459438c Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Thu, 11 Jan 2024 20:45:09 +0100 Subject: [PATCH 386/390] Simplifies test through using wlmtk_fake_window_commit_size throughout. --- src/toolkit/window.c | 66 ++++++++++++++--------------------------- src/toolkit/window.h | 2 ++ src/toolkit/workspace.c | 20 +++---------- 3 files changed, 28 insertions(+), 60 deletions(-) diff --git a/src/toolkit/window.c b/src/toolkit/window.c index fdc1e86d..620013a0 100644 --- a/src/toolkit/window.c +++ b/src/toolkit/window.c @@ -1057,6 +1057,17 @@ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr) free(fake_window_state_ptr); } +/* ------------------------------------------------------------------------- */ +/** Calls commit_size with the fake surface's serial and dimensions. */ +void wlmtk_fake_window_commit_size(wlmtk_fake_window_t *fake_window_ptr) +{ + wlmtk_content_commit_size( + fake_window_ptr->content_ptr, + fake_window_ptr->fake_surface_ptr->serial, + fake_window_ptr->fake_surface_ptr->requested_width, + fake_window_ptr->fake_surface_ptr->requested_height); +} + /* ------------------------------------------------------------------------- */ /** Fake implementation of @ref wlmtk_window_request_minimize. Records call. */ void _wlmtk_fake_window_request_minimize(wlmtk_window_t *window_ptr) @@ -1200,10 +1211,7 @@ void test_server_side_decorated(bs_test_t *test_ptr) // Maximize the window: We keep the decoration. wlmtk_window_request_maximized(fw_ptr->window_ptr, true); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_maximized(fw_ptr->window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); @@ -1211,10 +1219,7 @@ void test_server_side_decorated(bs_test_t *test_ptr) // Make the window fullscreen: Hide the decoration. wlmtk_window_request_fullscreen(fw_ptr->window_ptr, true); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_maximized(fw_ptr->window_ptr, false); wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); @@ -1223,10 +1228,7 @@ void test_server_side_decorated(bs_test_t *test_ptr) // Back to organic size: Decoration is on. wlmtk_window_request_fullscreen(fw_ptr->window_ptr, false); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, false); BS_TEST_VERIFY_TRUE(test_ptr, fw_ptr->window_ptr->server_side_decorated); BS_TEST_VERIFY_NEQ(test_ptr, NULL, fw_ptr->window_ptr->titlebar_ptr); @@ -1259,10 +1261,7 @@ void test_maximize(bs_test_t *test_ptr) // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(fw_ptr->window_ptr, 20, 10, 200, 100); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); @@ -1289,10 +1288,7 @@ void test_maximize(bs_test_t *test_ptr) // Maximize. wlmtk_window_request_maximized(fw_ptr->window_ptr, true); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_maximized(fw_ptr->window_ptr, true); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 0, box.x); @@ -1302,18 +1298,12 @@ void test_maximize(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); // A second commit: should not overwrite the organic dimension. - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); // Unmaximize. Restore earlier organic size and position. wlmtk_window_request_maximized(fw_ptr->window_ptr, false); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_maximized(fw_ptr->window_ptr)); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_maximized(fw_ptr->window_ptr, false); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 50, box.x); @@ -1354,10 +1344,7 @@ void test_fullscreen(bs_test_t *test_ptr) // Set up initial organic size, and verify. wlmtk_window_request_position_and_size(fw_ptr->window_ptr, 20, 10, 200, 100); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); BS_TEST_VERIFY_EQ(test_ptr, 20, box.x); BS_TEST_VERIFY_EQ(test_ptr, 10, box.y); @@ -1373,10 +1360,7 @@ void test_fullscreen(bs_test_t *test_ptr) wlmtk_titlebar_is_activated(fw_ptr->window_ptr->titlebar_ptr)); // Only after "commit", it will take effect. - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); @@ -1400,10 +1384,7 @@ void test_fullscreen(bs_test_t *test_ptr) BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); // Takes effect after commit. We'll want the same position as before. - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, false); BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); @@ -1455,10 +1436,7 @@ void test_fullscreen_unmap(bs_test_t *test_ptr) BS_TEST_VERIFY_FALSE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); // Only after "commit", it will take effect. - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_commit_fullscreen(fw_ptr->window_ptr, true); BS_TEST_VERIFY_TRUE(test_ptr, wlmtk_window_is_fullscreen(fw_ptr->window_ptr)); box = wlmtk_window_get_position_and_size(fw_ptr->window_ptr); diff --git a/src/toolkit/window.h b/src/toolkit/window.h index bc776744..52d8e565 100644 --- a/src/toolkit/window.h +++ b/src/toolkit/window.h @@ -382,6 +382,8 @@ typedef struct { wlmtk_fake_window_t *wlmtk_fake_window_create(void); /** Dtor. */ void wlmtk_fake_window_destroy(wlmtk_fake_window_t *fake_window_ptr); +/** Calls commit_size with the fake surface's serial and dimensions. */ +void wlmtk_fake_window_commit_size(wlmtk_fake_window_t *fake_window_ptr); /** Unit tests for window. */ extern const bs_test_case_t wlmtk_window_test_cases[]; diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index 33190810..e8c30b8b 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -963,10 +963,7 @@ void test_resize(bs_test_t *test_ptr) wlmtk_fake_window_t *fw_ptr = wlmtk_fake_window_create(); BS_ASSERT(NULL != fw_ptr); wlmtk_window_request_position_and_size(fw_ptr->window_ptr, 0, 0, 40, 20); - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_workspace_motion(fws_ptr->workspace_ptr, 0, 0, 42); wlmtk_workspace_map_window(fws_ptr->workspace_ptr, fw_ptr->window_ptr); @@ -987,10 +984,7 @@ void test_resize(bs_test_t *test_ptr) BS_TEST_VERIFY_EQ(test_ptr, 37, fw_ptr->fake_surface_ptr->requested_width); BS_TEST_VERIFY_EQ(test_ptr, 16, fw_ptr->fake_surface_ptr->requested_height); // This updates for the given serial. - wlmtk_content_commit_size(fw_ptr->content_ptr, - fw_ptr->fake_surface_ptr->serial, - fw_ptr->fake_surface_ptr->requested_width, - fw_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw_ptr); wlmtk_window_get_size(fw_ptr->window_ptr, &width, &height); BS_TEST_VERIFY_EQ(test_ptr, 1, wlmtk_window_element(fw_ptr->window_ptr)->x); BS_TEST_VERIFY_EQ(test_ptr, 2, wlmtk_window_element(fw_ptr->window_ptr)->y); @@ -1021,10 +1015,7 @@ void test_activate(bs_test_t *test_ptr) // Window 1: from (0, 0) to (100, 100) wlmtk_fake_window_t *fw1_ptr = wlmtk_fake_window_create(); wlmtk_surface_request_size(&fw1_ptr->fake_surface_ptr->surface, 100, 100); - wlmtk_content_commit_size(fw1_ptr->content_ptr, - fw1_ptr->fake_surface_ptr->serial, - fw1_ptr->fake_surface_ptr->requested_width, - fw1_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw1_ptr); wlmtk_window_set_position(fw1_ptr->window_ptr, 0, 0); BS_TEST_VERIFY_FALSE( test_ptr, @@ -1040,10 +1031,7 @@ void test_activate(bs_test_t *test_ptr) // Window 2 is mapped: Will get activated, and 1st one de-activated. wlmtk_fake_window_t *fw2_ptr = wlmtk_fake_window_create(); wlmtk_surface_request_size(&fw2_ptr->fake_surface_ptr->surface, 100, 100); - wlmtk_content_commit_size(fw2_ptr->content_ptr, - fw2_ptr->fake_surface_ptr->serial, - fw2_ptr->fake_surface_ptr->requested_width, - fw2_ptr->fake_surface_ptr->requested_height); + wlmtk_fake_window_commit_size(fw2_ptr); wlmtk_window_set_position(fw2_ptr->window_ptr, 200, 0); BS_TEST_VERIFY_FALSE( test_ptr, From 59ae72410904e801b13849270201d31d3716ab8b Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 12 Jan 2024 16:38:20 +0200 Subject: [PATCH 387/390] Adds remaining handlers for XDG toplevel, as 'unimplemented' stubs. --- src/wlmtk_xdg_toplevel.c | 170 ++++++++++++++++++++++++++++++++++----- 1 file changed, 150 insertions(+), 20 deletions(-) diff --git a/src/wlmtk_xdg_toplevel.c b/src/wlmtk_xdg_toplevel.c index 9bb837e8..1cc86dc8 100644 --- a/src/wlmtk_xdg_toplevel.c +++ b/src/wlmtk_xdg_toplevel.c @@ -50,16 +50,24 @@ typedef struct { /** Listener for the `commit` signal of the `wlr_surface`. */ struct wl_listener surface_commit_listener; - /** Listener for `request_maximize` signal of `wlr_xdg_toplevel::events`. */ + /** Listener for `request_maximize` of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_maximize_listener; - /** Listener for `request_fullscreen` signal of `wlr_xdg_toplevel::events`. */ + /** Listener for `request_fullscreen` of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_fullscreen_listener; + /** Listener for `request_minimize` of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_request_minimize_listener; /** Listener for `request_move` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_move_listener; /** Listener for `request_resize` signal of `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_request_resize_listener; - /** Listener for the `set_title` signal of the `wlr_xdg_toplevel`. */ + /** Listener for `show_window_menu` of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_request_show_window_menu_listener; + /** Listener for `set_parent` of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_set_parent_listener; + /** Listener for `set_title` of the `wlr_xdg_toplevel::events`. */ struct wl_listener toplevel_set_title_listener; + /** Listener for `set_app_id` of `wlr_xdg_toplevel::events`. */ + struct wl_listener toplevel_set_app_id_listener; } wlmtk_xdg_toplevel_surface_t; static wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( @@ -89,15 +97,27 @@ static void handle_toplevel_request_maximize( static void handle_toplevel_request_fullscreen( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_request_minimize( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_toplevel_request_move( struct wl_listener *listener_ptr, void *data_ptr); static void handle_toplevel_request_resize( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_request_show_window_menu( + struct wl_listener *listener_ptr, + void *data_ptr); +static void handle_toplevel_set_parent( + struct wl_listener *listener_ptr, + void *data_ptr); static void handle_toplevel_set_title( struct wl_listener *listener_ptr, void *data_ptr); +static void handle_toplevel_set_app_id( + struct wl_listener *listener_ptr, + void *data_ptr); static void surface_element_destroy(wlmtk_element_t *element_ptr); static struct wlr_scene_node *surface_element_create_scene_node( @@ -159,6 +179,9 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel( return NULL; } + bs_log(BS_INFO, "Created window %p for wlmtk XDG toplevel surface %p", + wlmtk_window_ptr, surface_ptr); + return wlmtk_window_ptr; } @@ -229,6 +252,10 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( &wlr_xdg_surface_ptr->toplevel->events.request_fullscreen, &xdg_tl_surface_ptr->toplevel_request_fullscreen_listener, handle_toplevel_request_fullscreen); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.request_minimize, + &xdg_tl_surface_ptr->toplevel_request_minimize_listener, + handle_toplevel_request_minimize); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_move, &xdg_tl_surface_ptr->toplevel_request_move_listener, @@ -237,10 +264,22 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( &wlr_xdg_surface_ptr->toplevel->events.request_resize, &xdg_tl_surface_ptr->toplevel_request_resize_listener, handle_toplevel_request_resize); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.request_show_window_menu, + &xdg_tl_surface_ptr->toplevel_request_show_window_menu_listener, + handle_toplevel_request_show_window_menu); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.set_parent, + &xdg_tl_surface_ptr->toplevel_set_parent_listener, + handle_toplevel_set_parent); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.set_title, &xdg_tl_surface_ptr->toplevel_set_title_listener, handle_toplevel_set_title); + wlmtk_util_connect_listener_signal( + &wlr_xdg_surface_ptr->toplevel->events.set_app_id, + &xdg_tl_surface_ptr->toplevel_set_app_id_listener, + handle_toplevel_set_app_id); xdg_tl_surface_ptr->wlr_xdg_surface_ptr->data = &xdg_tl_surface_ptr->super_content; @@ -252,23 +291,27 @@ wlmtk_xdg_toplevel_surface_t *xdg_toplevel_surface_create( void xdg_toplevel_surface_destroy( wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr) { - wl_list_remove( - &xdg_tl_surface_ptr->toplevel_set_title_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_resize_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_move_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_fullscreen_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->toplevel_request_maximize_listener.link); - - wl_list_remove(&xdg_tl_surface_ptr->surface_commit_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->surface_map_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->surface_unmap_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->new_popup_listener.link); - wl_list_remove(&xdg_tl_surface_ptr->destroy_listener.link); - - wlmtk_content_fini(&xdg_tl_surface_ptr->super_content); - - wlmtk_surface_fini(&xdg_tl_surface_ptr->super_surface); - free(xdg_tl_surface_ptr); + wlmtk_xdg_toplevel_surface_t *xts_ptr = xdg_tl_surface_ptr; + wl_list_remove(&xts_ptr->toplevel_set_app_id_listener.link); + wl_list_remove(&xts_ptr->toplevel_set_title_listener.link); + wl_list_remove(&xts_ptr->toplevel_set_parent_listener.link); + wl_list_remove(&xts_ptr->toplevel_request_show_window_menu_listener.link); + wl_list_remove(&xts_ptr->toplevel_request_resize_listener.link); + wl_list_remove(&xts_ptr->toplevel_request_move_listener.link); + wl_list_remove(&xts_ptr->toplevel_request_fullscreen_listener.link); + wl_list_remove(&xts_ptr->toplevel_request_maximize_listener.link); + wl_list_remove(&xts_ptr->toplevel_request_minimize_listener.link); + + wl_list_remove(&xts_ptr->surface_commit_listener.link); + wl_list_remove(&xts_ptr->surface_map_listener.link); + wl_list_remove(&xts_ptr->surface_unmap_listener.link); + wl_list_remove(&xts_ptr->new_popup_listener.link); + wl_list_remove(&xts_ptr->destroy_listener.link); + + wlmtk_content_fini(&xts_ptr->super_content); + + wlmtk_surface_fini(&xts_ptr->super_surface); + free(xts_ptr); } /* ------------------------------------------------------------------------- */ @@ -427,6 +470,9 @@ void handle_destroy(struct wl_listener *listener_ptr, wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( listener_ptr, wlmtk_xdg_toplevel_surface_t, destroy_listener); + bs_log(BS_INFO, "Destroying window %p for wlmtk XDG surface %p", + xdg_tl_surface_ptr, xdg_tl_surface_ptr->super_content.window_ptr); + wlmtk_window_destroy(xdg_tl_surface_ptr->super_content.window_ptr); xdg_toplevel_surface_destroy(xdg_tl_surface_ptr); } @@ -596,6 +642,27 @@ void handle_toplevel_request_fullscreen( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->base); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `request_minimize` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_request_minimize( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_surface_t, + toplevel_request_minimize_listener); + + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_WARNING, "Unimplemented: request_minimize for XDG toplevel %p", + xdg_tl_surface_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `request_move` signal. @@ -635,6 +702,48 @@ void handle_toplevel_request_resize( resize_event_ptr->edges); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `request_show_window_menu` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_request_show_window_menu( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_surface_t, + toplevel_request_show_window_menu_listener); + + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_WARNING, "Unimplemented: request_show_window_menu for XDG " + "toplevel %p", xdg_tl_surface_ptr); +} + +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `set_parent` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_set_parent( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_surface_t, + toplevel_set_parent_listener); + + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_WARNING, "Unimplemented: set_parent_menu for XDG toplevel %p", + xdg_tl_surface_ptr); +} + /* ------------------------------------------------------------------------- */ /** * Handler for the `set_title` signal. @@ -656,4 +765,25 @@ void handle_toplevel_set_title( xdg_tl_surface_ptr->wlr_xdg_surface_ptr->toplevel->title); } +/* ------------------------------------------------------------------------- */ +/** + * Handler for the `set_app_id` signal. + * + * @param listener_ptr + * @param data_ptr + */ +void handle_toplevel_set_app_id( + struct wl_listener *listener_ptr, + __UNUSED__ void *data_ptr) +{ + wlmtk_xdg_toplevel_surface_t *xdg_tl_surface_ptr = BS_CONTAINER_OF( + listener_ptr, + wlmtk_xdg_toplevel_surface_t, + toplevel_set_app_id_listener); + + // TODO(kaeser@gubbe.ch): Implement. + bs_log(BS_WARNING, "Unimplemented: set_parent_menu for XDG toplevel %p", + xdg_tl_surface_ptr); +} + /* == End of xdg_toplevel.c ================================================ */ From 08c4dde3bbd59d86ba6f8df08a75eb9e66ad9031 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 12 Jan 2024 16:54:58 +0200 Subject: [PATCH 388/390] Removes legacy move/resize code, and let pointer events go to layers. --- src/cursor.c | 204 +--------------------------------------- src/cursor.h | 62 ------------ src/resizebar.c | 5 - src/titlebar.c | 3 - src/toolkit/workspace.c | 15 +-- src/toolkit/workspace.h | 4 +- src/view.c | 2 - src/xdg_toplevel.c | 55 ----------- 8 files changed, 16 insertions(+), 334 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index ae50e0e3..e1905270 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -107,7 +107,6 @@ wlmaker_cursor_t *wlmaker_cursor_create(wlmaker_server_t *server_ptr) // // https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html - // TODO: Need a mode for 'normal', 'move', 'resize'. wlmtk_util_connect_listener_signal( &cursor_ptr->wlr_cursor_ptr->events.motion, &cursor_ptr->motion_listener, @@ -164,71 +163,6 @@ void wlmaker_cursor_attach_input_device( wlr_input_device_ptr); } -/* ------------------------------------------------------------------------- */ -void wlmaker_cursor_begin_move( - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr) -{ - if (view_ptr != wlmaker_workspace_get_activated_view( - wlmaker_server_get_current_workspace(cursor_ptr->server_ptr))) { - bs_log(BS_WARNING, "Denying move request from non-activated view."); - return; - } - - cursor_ptr->grabbed_view_ptr = view_ptr; - int x, y; - wlmaker_view_get_position(cursor_ptr->grabbed_view_ptr, &x, &y); - // TODO(kaeser@gubbe.ch): Inconsistent to have separate meaning of grab_x - // and grab_y for MOVE vs RESIZE. Should be cleaned up. - cursor_ptr->grab_x = cursor_ptr->wlr_cursor_ptr->x - x; - cursor_ptr->grab_y = cursor_ptr->wlr_cursor_ptr->y - y; - cursor_ptr->mode = WLMAKER_CURSOR_MOVE; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_cursor_begin_resize( - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - uint32_t edges) -{ - if (view_ptr != wlmaker_workspace_get_activated_view( - wlmaker_server_get_current_workspace(cursor_ptr->server_ptr))) { - bs_log(BS_WARNING, "Denying resize request from non-activated view."); - return; - } - - cursor_ptr->grabbed_view_ptr = view_ptr; - cursor_ptr->grab_x = cursor_ptr->wlr_cursor_ptr->x; - cursor_ptr->grab_y = cursor_ptr->wlr_cursor_ptr->y; - cursor_ptr->mode = WLMAKER_CURSOR_RESIZE; - - uint32_t width, height; - wlmaker_view_get_size(view_ptr, &width, &height); - cursor_ptr->grabbed_geobox.width = width; - cursor_ptr->grabbed_geobox.height = height; - wlmaker_view_get_position(view_ptr, - &cursor_ptr->grabbed_geobox.x, - &cursor_ptr->grabbed_geobox.y); - cursor_ptr->resize_edges = edges; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_cursor_unmap_view( - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr) -{ - if (cursor_ptr->grabbed_view_ptr == view_ptr) { - cursor_ptr->grabbed_view_ptr = NULL; - cursor_ptr->mode = WLMAKER_CURSOR_PASSTHROUGH; - } - - if (cursor_ptr->under_cursor_view_ptr == view_ptr) { - // TODO(kaeser@gubbe.ch): Should eavluate which of the view is now - // below the cursor and update "pointer focus" accordingly. - update_under_cursor_view(cursor_ptr, NULL); - } -} - /* ------------------------------------------------------------------------- */ void wlmaker_cursor_get_position( const wlmaker_cursor_t *cursor_ptr, @@ -306,44 +240,14 @@ void handle_button(struct wl_listener *listener_ptr, listener_ptr, cursor_ptr, button_listener); struct wlr_pointer_button_event *wlr_pointer_button_event_ptr = data_ptr; - wlmtk_workspace_button( + bool consumed = wlmtk_workspace_button( wlmaker_workspace_wlmtk(wlmaker_server_get_current_workspace( cursor_ptr->server_ptr)), wlr_pointer_button_event_ptr); - if (true) return; // FIXME - - struct wlr_keyboard *wlr_keyboard_ptr = wlr_seat_get_keyboard( - cursor_ptr->server_ptr->wlr_seat_ptr); - if (NULL != wlr_keyboard_ptr) { - uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_keyboard_ptr); - if (wlmaker_config_window_drag_modifiers != 0 && - wlmaker_config_window_drag_modifiers == modifiers && - wlr_pointer_button_event_ptr->state == WLR_BUTTON_PRESSED) { - struct wlr_surface *wlr_surface_ptr; - double rel_x, rel_y; - wlmaker_view_t *view_ptr = wlmaker_view_at( - cursor_ptr->server_ptr, - cursor_ptr->wlr_cursor_ptr->x, - cursor_ptr->wlr_cursor_ptr->y, - &wlr_surface_ptr, - &rel_x, - &rel_y); - if (NULL != view_ptr) { - wlmaker_workspace_raise_view( - wlmaker_server_get_current_workspace( - cursor_ptr->server_ptr), - view_ptr); - wlmaker_workspace_activate_view( - wlmaker_server_get_current_workspace( - cursor_ptr->server_ptr), - view_ptr); - update_under_cursor_view(cursor_ptr, view_ptr); - wlmaker_cursor_begin_move(cursor_ptr, view_ptr); - return; - } - } - } + // TODO(kaeser@gubbe.ch): The code below is for the pre-toolkit version. + // Remove it, once we're fully on toolkit. + if (consumed) return; // Notify the client with pointer focus that a button press has occurred. wlr_seat_pointer_notify_button( @@ -373,7 +277,6 @@ void handle_button(struct wl_listener *listener_ptr, if (wlr_pointer_button_event_ptr->state == WLR_BUTTON_RELEASED) { wl_signal_emit(&cursor_ptr->button_release_event, data_ptr); - cursor_ptr->mode = WLMAKER_CURSOR_PASSTHROUGH; } } @@ -481,109 +384,12 @@ void handle_seat_request_set_cursor( */ void process_motion(wlmaker_cursor_t *cursor_ptr, uint32_t time_msec) { - bool rv = wlmtk_workspace_motion( + wlmtk_workspace_motion( wlmaker_workspace_wlmtk(wlmaker_server_get_current_workspace( cursor_ptr->server_ptr)), cursor_ptr->wlr_cursor_ptr->x, cursor_ptr->wlr_cursor_ptr->y, time_msec); - - if (!rv) { // FIXME - wlr_cursor_set_xcursor( - cursor_ptr->wlr_cursor_ptr, - cursor_ptr->wlr_xcursor_manager_ptr, - "left_ptr"); - } - - if (true) return; - - if (cursor_ptr->mode == WLMAKER_CURSOR_MOVE) { - wlmaker_view_set_position( - cursor_ptr->grabbed_view_ptr, - cursor_ptr->wlr_cursor_ptr->x - cursor_ptr->grab_x, - cursor_ptr->wlr_cursor_ptr->y - cursor_ptr->grab_y); - return; - } else if (cursor_ptr->mode == WLMAKER_CURSOR_RESIZE) { - - // The geometry describes the overall shell geometry *relative* to the - // node position. This may eg. include client-side decoration, that - // may be placed in an extra surface above the nominal window (and - // node). - // - // Thus the position and dimensions of the visible area is given by - // the geobox position (relative to the node position) and with x height. - - double x = cursor_ptr->wlr_cursor_ptr->x - cursor_ptr->grab_x; - double y = cursor_ptr->wlr_cursor_ptr->y - cursor_ptr->grab_y; - - // Update new boundaries by the relative movement. - int top = cursor_ptr->grabbed_geobox.y; - int bottom = cursor_ptr->grabbed_geobox.y + cursor_ptr->grabbed_geobox.height; - if (cursor_ptr->resize_edges & WLR_EDGE_TOP) { - top += y; - if (top >= bottom) top = bottom - 1; - } else if (cursor_ptr->resize_edges & WLR_EDGE_BOTTOM) { - bottom += y; - if (bottom <= top) bottom = top + 1; - } - - int left = cursor_ptr->grabbed_geobox.x; - int right = cursor_ptr->grabbed_geobox.x + cursor_ptr->grabbed_geobox.width; - if (cursor_ptr->resize_edges & WLR_EDGE_LEFT) { - left += x; - if (left >= right) left = right - 1 ; - } else if (cursor_ptr->resize_edges & WLR_EDGE_RIGHT) { - right += x; - if (right <= left) right = left + 1; - } - - wlmaker_view_set_position(cursor_ptr->grabbed_view_ptr, left, top); - wlmaker_view_set_size(cursor_ptr->grabbed_view_ptr, - right - left, bottom - top); - return; - } - - double rel_x, rel_y; - struct wlr_surface *wlr_surface_ptr = NULL; - wlmaker_view_t *view_ptr = wlmaker_view_at( - cursor_ptr->server_ptr, - cursor_ptr->wlr_cursor_ptr->x, - cursor_ptr->wlr_cursor_ptr->y, - &wlr_surface_ptr, - &rel_x, - &rel_y); - update_under_cursor_view(cursor_ptr, view_ptr); - if (NULL == view_ptr) { - wlr_cursor_set_xcursor( - cursor_ptr->wlr_cursor_ptr, - cursor_ptr->wlr_xcursor_manager_ptr, - "left_ptr"); - } else { - wlmaker_view_handle_motion( - view_ptr, - cursor_ptr->wlr_cursor_ptr->x, - cursor_ptr->wlr_cursor_ptr->y); - } - - if (NULL == wlr_surface_ptr) { - // Clear pointer focus, so that future button events are no longer sent - // to the surface that had the focus. - wlr_seat_pointer_clear_focus(cursor_ptr->server_ptr->wlr_seat_ptr); - - } else { - // The notify_enter() function gives the pointer focus to the specified - // surface. The seat will send future button events there. - wlr_seat_pointer_notify_enter( - cursor_ptr->server_ptr->wlr_seat_ptr, - wlr_surface_ptr, - rel_x, - rel_y); - wlr_seat_pointer_notify_motion( - cursor_ptr->server_ptr->wlr_seat_ptr, - time_msec, - rel_x, - rel_y); - } } /* ------------------------------------------------------------------------- */ diff --git a/src/cursor.h b/src/cursor.h index 7ca85439..3d658e08 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -30,16 +30,6 @@ typedef struct _wlmaker_cursor_t wlmaker_cursor_t; extern "C" { #endif // __cplusplus -/** Mode of the cursor. */ -typedef enum { - /** Cursor movements are passed on to the client. */ - WLMAKER_CURSOR_PASSTHROUGH, - /** View-move mode. Movements kept and used to propel the view. */ - WLMAKER_CURSOR_MOVE, - /** Resize mode. Movements kept and used to resize the view. */ - WLMAKER_CURSOR_RESIZE, -} wlmaker_cursor_mode_t; - /** State and tools for handling wlmaker cursors. */ struct _wlmaker_cursor_t { /** Back-link to wlmaker_server_t. */ @@ -64,27 +54,8 @@ struct _wlmaker_cursor_t { /** Listener for the `request_set_cursor` event of `wlr_seat`. */ struct wl_listener seat_request_set_cursor_listener; - /** Mode that the cursor is in, eg. moving or resizing. */ - wlmaker_cursor_mode_t mode; - /** The currently grabbed view, when in "move" mode. */ - wlmaker_view_t *grabbed_view_ptr; /** The view that is currently active and under the cursor. */ wlmaker_view_t *under_cursor_view_ptr; - /** - * Horizontal position of when the move was activated, relative to the - * grabbed view. - */ - double grab_x; - /** - * Vertical position of when the move was activated, relative to the - * grabbed view. - */ - double grab_y; - /** Geometry at the time the move was initiated. */ - struct wlr_box grabbed_geobox; - /** Edges to resize along. */ - uint32_t resize_edges; - /** wlmaker internal: catch 'release' events of cursors. */ struct wl_signal button_release_event; @@ -116,39 +87,6 @@ void wlmaker_cursor_attach_input_device( wlmaker_cursor_t *cursor_ptr, struct wlr_input_device *wlr_input_device_ptr); -/** - * Begins a "move" interaction for the given view. - * - * @param cursor_ptr - * @param view_ptr - */ -void wlmaker_cursor_begin_move( - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr); - -/** - * Begins a "resize" interaction for the given view. - * - * @param cursor_ptr - * @param view_ptr - * @param edges - */ -void wlmaker_cursor_begin_resize( - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - uint32_t edges); - -/** - * Reports |view_ptr| as unmapped. Removes it from the set of views that can - * be called back, etc. - * - * @param cursor_ptr - * @param view_ptr - */ -void wlmaker_cursor_unmap_view( - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr); - /** * Retrieves the current pointer's position into |*x_ptr|, |*y_ptr|. * diff --git a/src/resizebar.c b/src/resizebar.c index 1fc71a06..5bbb414c 100644 --- a/src/resizebar.c +++ b/src/resizebar.c @@ -228,11 +228,6 @@ void _resizebar_button( case WLR_BUTTON_PRESSED: if (wlmaker_interactive_contains(&resizebar_ptr->interactive, x, y)) { resizebar_ptr->pressed = true; - - wlmaker_cursor_begin_resize( - resizebar_ptr->interactive.cursor_ptr, - resizebar_ptr->view_ptr, - resizebar_ptr->edges); } break; diff --git a/src/titlebar.c b/src/titlebar.c index b1f55a0c..99395349 100644 --- a/src/titlebar.c +++ b/src/titlebar.c @@ -223,9 +223,6 @@ void _titlebar_motion( (fabs(titlebar_ptr->clicked_x - x) > minimal_move || fabs(titlebar_ptr->clicked_y - y) > minimal_move)) { titlebar_ptr->state = TITLEBAR_MOVING; - wlmaker_cursor_begin_move( - titlebar_ptr->interactive.cursor_ptr, - titlebar_ptr->view_ptr); wlr_cursor_set_xcursor( interactive_ptr->cursor_ptr->wlr_cursor_ptr, diff --git a/src/toolkit/workspace.c b/src/toolkit/workspace.c index e8c30b8b..0314a634 100644 --- a/src/toolkit/workspace.c +++ b/src/toolkit/workspace.c @@ -355,7 +355,7 @@ bool wlmtk_workspace_motion( /* ------------------------------------------------------------------------- */ // TODO(kaeser@gubbe.ch): Improve this, has multiple bugs: It won't keep // different buttons apart, and there's currently no test associated. -void wlmtk_workspace_button( +bool wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, const struct wlr_pointer_button_event *event_ptr) { @@ -366,7 +366,7 @@ void wlmtk_workspace_button( event.time_msec = event_ptr->time_msec; if (WLR_BUTTON_PRESSED == event_ptr->state) { event.type = WLMTK_BUTTON_DOWN; - wlmtk_element_pointer_button( + return wlmtk_element_pointer_button( &workspace_ptr->super_container.super_element, &event); } else if (WLR_BUTTON_RELEASED == event_ptr->state) { @@ -374,14 +374,15 @@ void wlmtk_workspace_button( wlmtk_element_pointer_button( &workspace_ptr->super_container.super_element, &event); event.type = WLMTK_BUTTON_CLICK; - wlmtk_element_pointer_button( + return wlmtk_element_pointer_button( &workspace_ptr->super_container.super_element, &event); - } else { - bs_log(BS_WARNING, - "Workspace %p: Unhandled state 0x%x for button 0x%x", - workspace_ptr, event_ptr->state, event_ptr->button); } + + bs_log(BS_WARNING, + "Workspace %p: Unhandled state 0x%x for button 0x%x", + workspace_ptr, event_ptr->state, event_ptr->button); + return false; } /* ------------------------------------------------------------------------- */ diff --git a/src/toolkit/workspace.h b/src/toolkit/workspace.h index 5d04e724..6676c477 100644 --- a/src/toolkit/workspace.h +++ b/src/toolkit/workspace.h @@ -152,8 +152,10 @@ bool wlmtk_workspace_motion( * * @param workspace_ptr * @param event_ptr + * + * @return Whether the button was consumed. */ -void wlmtk_workspace_button( +bool wlmtk_workspace_button( wlmtk_workspace_t *workspace_ptr, const struct wlr_pointer_button_event *event_ptr); diff --git a/src/view.c b/src/view.c index 9507d9cf..dc7ec88b 100644 --- a/src/view.c +++ b/src/view.c @@ -705,8 +705,6 @@ void wlmaker_view_unmap(wlmaker_view_t *view_ptr) view_ptr->workspace_ptr = NULL; wlmaker_view_apply_decoration(view_ptr); - wlmaker_cursor_unmap_view(view_ptr->server_ptr->cursor_ptr, view_ptr); - wl_signal_emit(&view_ptr->server_ptr->view_unmapped_event, view_ptr); } diff --git a/src/xdg_toplevel.c b/src/xdg_toplevel.c index 107738fc..36acd050 100644 --- a/src/xdg_toplevel.c +++ b/src/xdg_toplevel.c @@ -110,12 +110,6 @@ static void handle_toplevel_fullscreen( static void handle_toplevel_minimize( struct wl_listener *listener_ptr, void *data_ptr); -static void handle_toplevel_move( - struct wl_listener *listener_ptr, - void *data_ptr); -static void handle_toplevel_resize( - struct wl_listener *listener_ptr, - void *data_ptr); static void handle_toplevel_show_window_menu( struct wl_listener *listener_ptr, void *data_ptr); @@ -206,14 +200,6 @@ wlmaker_xdg_toplevel_t *wlmaker_xdg_toplevel_create( &wlr_xdg_surface_ptr->toplevel->events.request_minimize, &xdg_toplevel_ptr->toplevel_request_minimize_listener, handle_toplevel_minimize); - wlmtk_util_connect_listener_signal( - &wlr_xdg_surface_ptr->toplevel->events.request_move, - &xdg_toplevel_ptr->toplevel_request_move_listener, - handle_toplevel_move); - wlmtk_util_connect_listener_signal( - &wlr_xdg_surface_ptr->toplevel->events.request_resize, - &xdg_toplevel_ptr->toplevel_request_resize_listener, - handle_toplevel_resize); wlmtk_util_connect_listener_signal( &wlr_xdg_surface_ptr->toplevel->events.request_show_window_menu, &xdg_toplevel_ptr->toplevel_request_show_window_menu_listener, @@ -575,47 +561,6 @@ void handle_toplevel_minimize( wlmaker_view_set_iconified(&xdg_toplevel_ptr->view, true); } -/* ------------------------------------------------------------------------- */ -/** - * Handler for the `move` signal of the `struct wlr_xdg_toplevel`. - * - * @param listener_ptr - * @param data_ptr - */ -void handle_toplevel_move( - struct wl_listener *listener_ptr, - __UNUSED__ void *data_ptr) -{ - wlmaker_xdg_toplevel_t *xdg_toplevel_ptr = wl_container_of( - listener_ptr, xdg_toplevel_ptr, toplevel_request_move_listener); - - wlmaker_cursor_begin_move( - xdg_toplevel_ptr->view.server_ptr->cursor_ptr, - &xdg_toplevel_ptr->view); -} - -/* ------------------------------------------------------------------------- */ -/** - * Handler for the `resize` signal of the `struct wlr_xdg_toplevel`. - * - * @param listener_ptr - * @param data_ptr - */ -void handle_toplevel_resize( - struct wl_listener *listener_ptr, - void *data_ptr) -{ - wlmaker_xdg_toplevel_t *xdg_toplevel_ptr = wl_container_of( - listener_ptr, xdg_toplevel_ptr, toplevel_request_resize_listener); - struct wlr_xdg_toplevel_resize_event *wlr_xdg_toplevel_resize_event_ptr = - data_ptr; - - wlmaker_cursor_begin_resize( - xdg_toplevel_ptr->view.server_ptr->cursor_ptr, - &xdg_toplevel_ptr->view, - wlr_xdg_toplevel_resize_event_ptr->edges); -} - /* ------------------------------------------------------------------------- */ /** * Handler for the `show_window_menu` signal of the `struct wlr_xdg_toplevel`. From 6453c107aaa32dcb263ac3ff540b21319431d42d Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 12 Jan 2024 17:06:22 +0200 Subject: [PATCH 389/390] Removes the old-style decorations code. At least most of it. --- src/CMakeLists.txt | 12 +- src/config.c | 14 - src/config.h | 12 - src/decorations.h | 26 -- src/decorations/CMakeLists.txt | 44 -- src/decorations/element.c | 449 ------------------- src/decorations/element.h | 219 --------- src/decorations/margin.c | 295 ------------- src/decorations/margin.h | 94 ---- src/decorations/resizebar.c | 312 ------------- src/decorations/resizebar.h | 86 ---- src/decorations/titlebar.c | 634 --------------------------- src/decorations/titlebar.h | 90 ---- src/decorations/window_decorations.c | 230 ---------- src/decorations/window_decorations.h | 125 ------ src/resizebar.c | 273 ------------ src/resizebar.h | 77 ---- src/titlebar.c | 340 -------------- src/titlebar.h | 74 ---- src/view.c | 131 +----- src/view.h | 42 -- src/xdg_decoration.c | 20 - 22 files changed, 7 insertions(+), 3592 deletions(-) delete mode 100644 src/decorations/CMakeLists.txt delete mode 100644 src/decorations/element.c delete mode 100644 src/decorations/element.h delete mode 100644 src/decorations/margin.c delete mode 100644 src/decorations/margin.h delete mode 100644 src/decorations/resizebar.c delete mode 100644 src/decorations/resizebar.h delete mode 100644 src/decorations/titlebar.c delete mode 100644 src/decorations/titlebar.h delete mode 100644 src/decorations/window_decorations.c delete mode 100644 src/decorations/window_decorations.h delete mode 100644 src/resizebar.c delete mode 100644 src/resizebar.h delete mode 100644 src/titlebar.c delete mode 100644 src/titlebar.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c7a1a4ab..05f4896d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,13 +32,11 @@ SET(SOURCES menu.c menu_item.c output.c - resizebar.c server.c subprocess_monitor.c task_list.c tile.c tile_container.c - titlebar.c view.c wlmtk_xdg_popup.c wlmtk_xdg_toplevel.c @@ -67,13 +65,11 @@ SET(HEADERS menu.h menu_item.h output.h - resizebar.h server.h subprocess_monitor.h task_list.h tile_container.h tile.h - titlebar.h view.h wlmtk_xdg_popup.h wlmtk_xdg_toplevel.h @@ -85,7 +81,7 @@ SET(HEADERS ) ADD_EXECUTABLE(wlmaker wlmaker.c ${SOURCES} ${HEADERS}) -ADD_DEPENDENCIES(wlmaker protocol_headers decorations toolkit) +ADD_DEPENDENCIES(wlmaker protocol_headers toolkit) TARGET_COMPILE_DEFINITIONS( wlmaker PRIVATE WLMAKER_ICON_DATA_DIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/wlmaker") @@ -115,7 +111,7 @@ TARGET_INCLUDE_DIRECTORIES( TARGET_LINK_LIBRARIES( wlmaker PRIVATE base - decorations + toolkit wlmaker_protocols PkgConfig::CAIRO PkgConfig::LIBDRM @@ -126,7 +122,7 @@ TARGET_LINK_LIBRARIES( ) ADD_EXECUTABLE(wlmaker_test wlmaker_test.c ${SOURCES} ${HEADERS}) -ADD_DEPENDENCIES(wlmaker_test protocol_headers decorations toolkit) +ADD_DEPENDENCIES(wlmaker_test protocol_headers toolkit) TARGET_INCLUDE_DIRECTORIES( wlmaker_test PRIVATE ${PROJECT_BINARY_DIR}/third_party/protocols @@ -142,7 +138,7 @@ TARGET_INCLUDE_DIRECTORIES( TARGET_LINK_LIBRARIES( wlmaker_test PRIVATE base - decorations + toolkit wlmaker_protocols PkgConfig::CAIRO PkgConfig::LIBDRM diff --git a/src/config.c b/src/config.c index 32de7f12..e16b654f 100644 --- a/src/config.c +++ b/src/config.c @@ -72,20 +72,6 @@ const wlmaker_config_theme_t wlmaker_config_theme = { .window_margin_color = 0xff000000, // Pich black, opaque. .window_margin_width = 1, - .titlebar_focussed_fill = { - .type = WLMTK_STYLE_COLOR_HGRADIENT, - .param = { .hgradient = { .from = 0xff505a5e,.to = 0xff202a2e }} - }, - .titlebar_focussed_text_color = 0xffffffff, - .titlebar_blurred_fill = { - .type = WLMTK_STYLE_COLOR_HGRADIENT, - .param = { .hgradient = { .from = 0xffc2c0c5,.to = 0xff828085 }} - }, - .titlebar_blurred_text_color = 0xff000000, - .resizebar_fill = { - .type = WLMTK_STYLE_COLOR_SOLID, - .param = { .solid = { .color = 0xffc2c0c5 }} - }, .tile_fill = { .type = WLMTK_STYLE_COLOR_DGRADIENT, .param = { .hgradient = { .from = 0xffa6a6b6,.to = 0xff515561 }} diff --git a/src/config.h b/src/config.h index 562976f3..b75d82ad 100644 --- a/src/config.h +++ b/src/config.h @@ -51,18 +51,6 @@ typedef struct { /** Width of the window margin, in pixels. */ uint32_t window_margin_width; - /** Color of the title text when focussed. */ - uint32_t titlebar_focussed_text_color; - /** Color of the title text when blurred. */ - uint32_t titlebar_blurred_text_color; - - /** Fill style of the title bar, when focussed. Including buttons. */ - wlmtk_style_fill_t titlebar_focussed_fill; - /** Fill style of the title bar, when blurred. Including buttons. */ - wlmtk_style_fill_t titlebar_blurred_fill; - - /** Fill style of the resize bar. */ - wlmtk_style_fill_t resizebar_fill; /** Fill style of a tile. */ wlmtk_style_fill_t tile_fill; /** File style of the title element of an iconified. */ diff --git a/src/decorations.h b/src/decorations.h index b40f79e1..b11dd389 100644 --- a/src/decorations.h +++ b/src/decorations.h @@ -39,32 +39,6 @@ extern const uint32_t wlmaker_decorations_tile_size; /** Size of the clip button (length of the catheti) */ extern const uint32_t wlmaker_decorations_clip_button_size; -/** - * Creates a cairo image surface for the background of the title bar. - * - * @param width Full with of the title bar. The width depends on - * the window size; the height of the title bar is - * hardcoded. - * @param fill_ptr Specification for the fill. - * - * @return a `cairo_surface_t` image target, filled as specificed. - */ -cairo_surface_t *wlmaker_decorations_titlebar_create_background( - uint32_t width, const wlmtk_style_fill_t *fill_ptr); - -/** - * Creates a cairo image surface for the background of the resize bar. - * - * @param width Full with of the resize bar. The width depends on - * the window size; the height of the reizse bar is - * hardcoded. - * @param fill_ptr Specification for the fill. - * - * @return a `cairo_surface_t` image target, filled as specificed. - */ -cairo_surface_t *wlmaker_decorations_resizebar_create_background( - uint32_t width, const wlmtk_style_fill_t *fill_ptr); - /** * Draws a tile into the `cairo_t`. * diff --git a/src/decorations/CMakeLists.txt b/src/decorations/CMakeLists.txt deleted file mode 100644 index f098a798..00000000 --- a/src/decorations/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -CMAKE_MINIMUM_REQUIRED(VERSION 3.13) - -ADD_LIBRARY(decorations - element.c - margin.c - resizebar.c - titlebar.c - window_decorations.c - element.h - margin.h - resizebar.h - titlebar.h - window_decorations.h) - -TARGET_COMPILE_OPTIONS( - decorations PRIVATE - ${WAYLAND_CFLAGS} - ${WAYLAND_CFLAGS_OTHER} -) - -TARGET_INCLUDE_DIRECTORIES( - decorations PRIVATE - ${CAIRO_INCLUDE_DIRS} - # TODO(kaeser@gubbe.ch): These should not be required. - ${PROJECT_BINARY_DIR}/third_party/protocols - ${PIXMAN_INCLUDE_DIRS} -) - -TARGET_LINK_LIBRARIES( - decorations base toolkit) diff --git a/src/decorations/element.c b/src/decorations/element.c deleted file mode 100644 index 2972e84a..00000000 --- a/src/decorations/element.c +++ /dev/null @@ -1,449 +0,0 @@ -/* ========================================================================= */ -/** - * @file element.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "element.h" - -#include - -#include "../button.h" -#include "../resizebar.h" -#include "../titlebar.h" - -/* == Declarations ========================================================= */ - -/** Decorations element. */ -struct _wlmaker_decorations_element_t { - /** Scene graph node holding the element. */ - struct wlr_scene_buffer *wlr_scene_buffer_ptr; - - /** - * Interactive for the element. To be created by instantiated element, will - * be destroyed in @ref wlmaker_decorations_element_fini. - */ - wlmaker_interactive_t *interactive_ptr; - - /** - * Margin of the element, or NULL. - * - * TODO(kaeser@gubbe.ch): Consider moving this to the "container". - */ - wlmaker_decorations_margin_t *margin_ptr; -}; - -/** State of a button. */ -struct _wlmaker_decorations_button_t { - /** The base element. */ - wlmaker_decorations_element_t element; - /** Back-link. */ - wlmaker_view_t *view_ptr; -}; - -/** State of a title. */ -struct _wlmaker_decorations_title_t { - /** The base element. */ - wlmaker_decorations_element_t element; - /** Back-link. */ - wlmaker_view_t *view_ptr; -}; - -/** State of a resize. */ -struct _wlmaker_decorations_resize_t { - /** The base element. */ - wlmaker_decorations_element_t element; - /** Back-link. */ - wlmaker_view_t *view_ptr; -}; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -bool wlmaker_decorations_element_init( - wlmaker_decorations_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr, - void *data_ptr, - unsigned width, - unsigned height, - uint32_t edges) -{ - BS_ASSERT(NULL == element_ptr->wlr_scene_buffer_ptr); - - element_ptr->wlr_scene_buffer_ptr = wlr_scene_buffer_create( - wlr_scene_tree_ptr, NULL); - if (NULL == element_ptr->wlr_scene_buffer_ptr) { - wlmaker_decorations_element_fini(element_ptr); - return false; - } - element_ptr->wlr_scene_buffer_ptr->node.data = data_ptr; - - if (0 != edges) { - element_ptr->margin_ptr = wlmaker_decorations_margin_create( - wlr_scene_tree_ptr, - 0, 0, width, height, // element_ptr->width, element_ptr->height, - edges); - } - - return true; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_element_fini( - wlmaker_decorations_element_t *element_ptr) -{ - if (NULL != element_ptr->margin_ptr) { - wlmaker_decorations_margin_destroy(element_ptr->margin_ptr); - element_ptr->margin_ptr = NULL; - } - - if (NULL != element_ptr->interactive_ptr) { - wlmaker_interactive_node_destroy( - &element_ptr->interactive_ptr->avlnode); - element_ptr->interactive_ptr = NULL; - } - - if (NULL != element_ptr->wlr_scene_buffer_ptr) { - wlr_scene_node_destroy(&element_ptr->wlr_scene_buffer_ptr->node); - element_ptr->wlr_scene_buffer_ptr = NULL; - } -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_element_set_position( - wlmaker_decorations_element_t *element_ptr, - int x, - int y) -{ - wlr_scene_node_set_position( - &element_ptr->wlr_scene_buffer_ptr->node, x, y); - if (NULL != element_ptr->margin_ptr) { - wlmaker_decorations_margin_set_position( - element_ptr->margin_ptr, x, y); - } -} - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_button_t *wlmaker_decorations_button_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_interactive_callback_t callback, - wlmaker_view_t *view_ptr, - struct wlr_buffer *button_released_ptr, - struct wlr_buffer *button_pressed_ptr, - struct wlr_buffer *button_blurred_ptr, - uint32_t edges) -{ - BS_ASSERT(button_released_ptr->width == button_pressed_ptr->width); - BS_ASSERT(button_released_ptr->width == button_blurred_ptr->width); - BS_ASSERT(button_released_ptr->height == button_pressed_ptr->height); - BS_ASSERT(button_released_ptr->height == button_blurred_ptr->height); - - wlmaker_decorations_button_t *button_ptr = logged_calloc( - 1, sizeof(wlmaker_decorations_button_t)); - if (NULL == button_ptr) return NULL; - if (!wlmaker_decorations_element_init( - &button_ptr->element, - wlr_scene_tree_ptr, - view_ptr, - button_released_ptr->width, - button_released_ptr->height, - edges)) { - wlmaker_decorations_button_destroy(button_ptr); - return NULL; - } - - button_ptr->element.interactive_ptr = wlmaker_button_create( - button_ptr->element.wlr_scene_buffer_ptr, - cursor_ptr, - callback, - view_ptr, - button_released_ptr, - button_pressed_ptr, - button_blurred_ptr); - if (NULL == button_ptr->element.interactive_ptr) { - wlmaker_decorations_button_destroy(button_ptr); - return NULL; - } - - wlmaker_interactive_focus( - button_ptr->element.interactive_ptr, - view_ptr->active); - - if (!bs_avltree_insert( - view_ptr->interactive_tree_ptr, - &button_ptr->element.interactive_ptr->wlr_scene_buffer_ptr->node, - &button_ptr->element.interactive_ptr->avlnode, - false)) { - bs_log(BS_ERROR, "Unexpected: Fail to insert into tree."); - wlmaker_decorations_button_destroy(button_ptr); - return NULL; - } - button_ptr->view_ptr = view_ptr; - - return button_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_button_destroy( - wlmaker_decorations_button_t *button_ptr) -{ - if (NULL != button_ptr->view_ptr) { - bs_avltree_delete( - button_ptr->view_ptr->interactive_tree_ptr, - &button_ptr->element.interactive_ptr->wlr_scene_buffer_ptr->node); - button_ptr->view_ptr = NULL; - } - - // The interactive is deleted in element_fini(). - - wlmaker_decorations_element_fini(&button_ptr->element); - free(button_ptr); -} - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_element_t *wlmaker_decorations_element_from_button( - wlmaker_decorations_button_t *button_ptr) -{ - return &button_ptr->element; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_button_set_textures( - wlmaker_decorations_button_t *button_ptr, - struct wlr_buffer *button_released_ptr, - struct wlr_buffer *button_pressed_ptr, - struct wlr_buffer *button_blurred_ptr) -{ - BS_ASSERT(button_released_ptr->width == button_pressed_ptr->width); - BS_ASSERT(button_released_ptr->width == button_blurred_ptr->width); - BS_ASSERT(button_released_ptr->height == button_pressed_ptr->height); - BS_ASSERT(button_released_ptr->height == button_blurred_ptr->height); - - wlmaker_button_set_textures( - button_ptr->element.interactive_ptr, - button_released_ptr, - button_pressed_ptr, - button_blurred_ptr); - - if (NULL != button_ptr->element.margin_ptr) { - wlmaker_decorations_margin_set_size( - button_ptr->element.margin_ptr, - button_released_ptr->width, - button_released_ptr->height); - } -} - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_title_t *wlmaker_decorations_title_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *title_buffer_ptr, - struct wlr_buffer *title_blurred_buffer_ptr) -{ - BS_ASSERT(title_buffer_ptr->width == title_blurred_buffer_ptr->width); - BS_ASSERT(title_buffer_ptr->height == title_blurred_buffer_ptr->height); - - wlmaker_decorations_title_t *title_ptr = logged_calloc( - 1, sizeof(wlmaker_decorations_title_t)); - if (NULL == title_ptr) return NULL; - if (!wlmaker_decorations_element_init( - &title_ptr->element, - wlr_scene_tree_ptr, - view_ptr, - title_buffer_ptr->width, - title_buffer_ptr->height, - WLR_EDGE_LEFT | WLR_EDGE_TOP | WLR_EDGE_RIGHT)) { - wlmaker_decorations_title_destroy(title_ptr); - return NULL; - } - - title_ptr->element.interactive_ptr = wlmaker_titlebar_create( - title_ptr->element.wlr_scene_buffer_ptr, - cursor_ptr, - view_ptr, - title_buffer_ptr, - title_blurred_buffer_ptr); - if (NULL == title_ptr->element.interactive_ptr) { - wlmaker_decorations_title_destroy(title_ptr); - return NULL; - } - - wlmaker_interactive_focus( - title_ptr->element.interactive_ptr, - view_ptr->active); - - if (!bs_avltree_insert( - view_ptr->interactive_tree_ptr, - &title_ptr->element.interactive_ptr->wlr_scene_buffer_ptr->node, - &title_ptr->element.interactive_ptr->avlnode, - false)) { - bs_log(BS_ERROR, "Unexpected: Fail to insert into tree."); - wlmaker_decorations_title_destroy(title_ptr); - return NULL; - } - title_ptr->view_ptr = view_ptr; - - return title_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_title_destroy( - wlmaker_decorations_title_t *title_ptr) -{ - if (NULL != title_ptr->view_ptr) { - bs_avltree_delete( - title_ptr->view_ptr->interactive_tree_ptr, - &title_ptr->element.interactive_ptr->wlr_scene_buffer_ptr->node); - title_ptr->view_ptr = NULL; - } - - // The interactive is deleted in element_fini(). - - wlmaker_decorations_element_fini(&title_ptr->element); - free(title_ptr); -} - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_element_t *wlmaker_decorations_element_from_title( - wlmaker_decorations_title_t *title_ptr) -{ - return &title_ptr->element; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_title_set_textures( - wlmaker_decorations_title_t *title_ptr, - struct wlr_buffer *title_buffer_ptr, - struct wlr_buffer *title_blurred_buffer_ptr) -{ - BS_ASSERT(title_buffer_ptr->width == title_blurred_buffer_ptr->width); - BS_ASSERT(title_buffer_ptr->height == title_blurred_buffer_ptr->height); - - wlmaker_title_set_texture( - title_ptr->element.interactive_ptr, - title_buffer_ptr, - title_blurred_buffer_ptr); - - if (NULL != title_ptr->element.margin_ptr) { - wlmaker_decorations_margin_set_size( - title_ptr->element.margin_ptr, - title_buffer_ptr->width, - title_buffer_ptr->height); - } -} - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_resize_t *wlmaker_decorations_resize_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *resize_buffer_ptr, - struct wlr_buffer *resize_pressed_buffer_ptr, - uint32_t edges) -{ - BS_ASSERT(resize_buffer_ptr->width == resize_pressed_buffer_ptr->width); - BS_ASSERT(resize_buffer_ptr->height == resize_pressed_buffer_ptr->height); - - wlmaker_decorations_resize_t *resize_ptr = logged_calloc( - 1, sizeof(wlmaker_decorations_resize_t)); - if (NULL == resize_ptr) return NULL; - if (!wlmaker_decorations_element_init( - &resize_ptr->element, - wlr_scene_tree_ptr, - view_ptr, - resize_buffer_ptr->width, - resize_buffer_ptr->height, - edges)) { - wlmaker_decorations_resize_destroy(resize_ptr); - return NULL; - } - - resize_ptr->element.interactive_ptr = wlmaker_resizebar_create( - resize_ptr->element.wlr_scene_buffer_ptr, - cursor_ptr, - view_ptr, - resize_buffer_ptr, - resize_pressed_buffer_ptr, - edges); - if (NULL == resize_ptr->element.interactive_ptr) { - wlmaker_decorations_resize_destroy(resize_ptr); - return NULL; - } - - if (!bs_avltree_insert( - view_ptr->interactive_tree_ptr, - &resize_ptr->element.interactive_ptr->wlr_scene_buffer_ptr->node, - &resize_ptr->element.interactive_ptr->avlnode, - false)) { - bs_log(BS_ERROR, "Unexpected: Fail to insert into tree."); - wlmaker_decorations_resize_destroy(resize_ptr); - return NULL; - } - resize_ptr->view_ptr = view_ptr; - - return resize_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_resize_destroy( - wlmaker_decorations_resize_t *resize_ptr) -{ - if (NULL != resize_ptr->view_ptr) { - bs_avltree_delete( - resize_ptr->view_ptr->interactive_tree_ptr, - &resize_ptr->element.interactive_ptr->wlr_scene_buffer_ptr->node); - resize_ptr->view_ptr = NULL; - } - - // The interactive is deleted in element_fini(). - - wlmaker_decorations_element_fini(&resize_ptr->element); - free(resize_ptr); -} - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_element_t *wlmaker_decorations_element_from_resize( - wlmaker_decorations_resize_t *resize_ptr) -{ - return &resize_ptr->element; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_resize_set_textures( - wlmaker_decorations_resize_t *resize_ptr, - struct wlr_buffer *resize_buffer_ptr, - struct wlr_buffer *resize_pressed_buffer_ptr) -{ - BS_ASSERT(resize_buffer_ptr->width == resize_pressed_buffer_ptr->width); - BS_ASSERT(resize_buffer_ptr->height == resize_pressed_buffer_ptr->height); - - wlmaker_resizebar_set_textures( - resize_ptr->element.interactive_ptr, - resize_buffer_ptr, - resize_pressed_buffer_ptr); - - if (NULL != resize_ptr->element.margin_ptr) { - wlmaker_decorations_margin_set_size( - resize_ptr->element.margin_ptr, - resize_buffer_ptr->width, - resize_buffer_ptr->height); - } -} - -/* == End of element.c ===================================================== */ diff --git a/src/decorations/element.h b/src/decorations/element.h deleted file mode 100644 index d1fd2676..00000000 --- a/src/decorations/element.h +++ /dev/null @@ -1,219 +0,0 @@ -/* ========================================================================= */ -/** - * @file element.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ELEMENT_H__ -#define __ELEMENT_H__ - -#include "../view.h" - -#include "margin.h" - -#define WLR_USE_UNSTABLE -#include -#undef WLR_USE_UNSTABLE - -/** Forward declaration: Abstract base "class", the element. */ -typedef struct _wlmaker_decorations_element_t wlmaker_decorations_element_t; -/** Forward declaration: Button. */ -typedef struct _wlmaker_decorations_button_t wlmaker_decorations_button_t; -/** Forward declaration: Title. */ -typedef struct _wlmaker_decorations_title_t wlmaker_decorations_title_t; -/** Forward declaration: An element of the resize bar. */ -typedef struct _wlmaker_decorations_resize_t wlmaker_decorations_resize_t; - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Initializes the element. - * - * An element is a wrapper around an "interactive", and adds the scene graph - * node and optionally margins. On the long run, this should be unified with - * the interactive. - * - * @param element_ptr - * @param wlr_scene_tree_ptr The container's scene graph tree. - * @param data_ptr Data to set in the scene node's `data` field. - * @param width Of the element, used for adding margins. - * @param height Of the element, used for adding margins. - * @param edges Which edges to add as margins, or 0 for none. - */ -bool wlmaker_decorations_element_init( - wlmaker_decorations_element_t *element_ptr, - struct wlr_scene_tree *wlr_scene_tree_ptr, - void *data_ptr, - unsigned width, - unsigned height, - uint32_t edges); - -/** - * Releases all resources for the element. - * - * @param element_ptr - */ -void wlmaker_decorations_element_fini( - wlmaker_decorations_element_t *element_ptr); - -/** - * Sets position of the element, relative to the parent's scene graph tree. - * - * @param element_ptr - * @param x - * @param y - */ -void wlmaker_decorations_element_set_position( - wlmaker_decorations_element_t *element_ptr, - int x, - int y); - -/** - * Creates a button element, wrapping an "element" on the button interactive. - * - * @param wlr_scene_tree_ptr - * @param cursor_ptr - * @param callback - * @param view_ptr - * @param button_released_ptr - * @param button_pressed_ptr - * @param button_blurred_ptr - * @param edges - * - * @return A pointer to the button, or NULL on error. Must be free-d via - * @ref wlmaker_decorations_button_destroy. - */ -wlmaker_decorations_button_t *wlmaker_decorations_button_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_interactive_callback_t callback, - wlmaker_view_t *view_ptr, - struct wlr_buffer *button_released_ptr, - struct wlr_buffer *button_pressed_ptr, - struct wlr_buffer *button_blurred_ptr, - uint32_t edges); - -/** Destroys the button element. */ -void wlmaker_decorations_button_destroy( - wlmaker_decorations_button_t *button_ptr); - -/** Returns the base "element" for the button. */ -wlmaker_decorations_element_t *wlmaker_decorations_element_from_button( - wlmaker_decorations_button_t *button_ptr); - -/** - * Updates the textures used for the button. - * - * @param button_ptr - * @param button_released_ptr - * @param button_pressed_ptr - * @param button_blurred_ptr - */ -void wlmaker_decorations_button_set_textures( - wlmaker_decorations_button_t *button_ptr, - struct wlr_buffer *button_released_ptr, - struct wlr_buffer *button_pressed_ptr, - struct wlr_buffer *button_blurred_ptr); - -/** - * Creates a title element, wrapping an "element" on the titlebar interactive. - * - * @param wlr_scene_tree_ptr - * @param cursor_ptr - * @param view_ptr - * @param title_buffer_ptr - * @param title_blurred_buffer_ptr - * - * @return A pointer to the title, must be free-d via - * @ref wlmaker_decorations_title_destroy. - */ -wlmaker_decorations_title_t *wlmaker_decorations_title_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *title_buffer_ptr, - struct wlr_buffer *title_blurred_buffer_ptr); - -/** Destroys the title element. */ -void wlmaker_decorations_title_destroy( - wlmaker_decorations_title_t *title_ptr); - -/** Returns the base "element" for the title. */ -wlmaker_decorations_element_t *wlmaker_decorations_element_from_title( - wlmaker_decorations_title_t *title_ptr); - -/** - * Updates the textures used for the title. - * - * @param title_ptr - * @param title_buffer_ptr - * @param title_blurred_buffer_ptr - */ -void wlmaker_decorations_title_set_textures( - wlmaker_decorations_title_t *title_ptr, - struct wlr_buffer *title_buffer_ptr, - struct wlr_buffer *title_blurred_buffer_ptr); - -/** - * Creates a resizebar, wrapping an "element" on the resizebar interactive. - * - * @param wlr_scene_tree_ptr - * @param cursor_ptr - * @param view_ptr - * @param resize_buffer_ptr - * @param resize_pressed_buffer_ptr - * @param edges Edges controlled by this resizebar. Also used - * to deduce edges for the margins. - * - * @return A pointer to the resizebar, must be free-d via - * @ref wlmaker_decorations_resize_destroy. - */ -wlmaker_decorations_resize_t *wlmaker_decorations_resize_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *resize_buffer_ptr, - struct wlr_buffer *resize_pressed_buffer_ptr, - uint32_t edges); - -/** Destroys the resize element. */ -void wlmaker_decorations_resize_destroy( - wlmaker_decorations_resize_t *resize_ptr); - -/** Returns the base "element" for the resize. */ -wlmaker_decorations_element_t *wlmaker_decorations_element_from_resize( - wlmaker_decorations_resize_t *resize_ptr); - -/** - * Updates the textures used for the resize. - * - * @param resize_ptr - * @param resize_buffer_ptr - * @param resize_pressed_buffer_ptr - */ -void wlmaker_decorations_resize_set_textures( - wlmaker_decorations_resize_t *resize_ptr, - struct wlr_buffer *resize_buffer_ptr, - struct wlr_buffer *resize_pressed_buffer_ptr); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __ELEMENT_H__ */ -/* == End of element.h ===================================================== */ diff --git a/src/decorations/margin.c b/src/decorations/margin.c deleted file mode 100644 index 593a492f..00000000 --- a/src/decorations/margin.c +++ /dev/null @@ -1,295 +0,0 @@ -/* ========================================================================= */ -/** - * @file margin.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "margin.h" - -#include "../config.h" - -#include - -/* == Declarations ========================================================= */ - -/** Handle for margin. */ -struct _wlmaker_decorations_margin_t { - /** Parent's WLR scene tree. */ - struct wlr_scene_tree *parent_wlr_scene_tree_ptr; - - /** Width of the element surrounded by the margin(s). */ - unsigned width; - /** Height of the surrounded element. */ - unsigned height; - /** X-coordinate of the top-left corner of the decorated area. */ - int x; - /** Y-coordinate of the top-left corner of the decorated area. */ - int y; - /** Which edges of the margin should be drawn. */ - uint32_t edges; - - /** Scene rectangle holding the left edge of the margin. If any. */ - struct wlr_scene_rect *left_rect_ptr; - /** Scene rectangle holding the top edge of the margin. If any. */ - struct wlr_scene_rect *top_rect_ptr; - /** Scene rectangle holding the right edge of the margin. If any. */ - struct wlr_scene_rect *right_rect_ptr; - /** Scene rectangle holding the bottom edge of the margin. If any. */ - struct wlr_scene_rect *bottom_rect_ptr; -}; - -static bool recreate_edges( - wlmaker_decorations_margin_t *margin_ptr, - uint32_t edges); -static struct wlr_scene_rect *create_rect( - struct wlr_scene_tree *decoration_wlr_scene_tree_ptr, - uint32_t color); -static void rect_set_size( - struct wlr_scene_rect *wlr_scene_rect_ptr, - unsigned width, - unsigned height); -static void rect_set_position( - struct wlr_scene_rect *wlr_scene_rect_ptr, - int x, - int y); - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_margin_t *wlmaker_decorations_margin_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - int x, int y, - unsigned width, unsigned height, - uint32_t edges) -{ - wlmaker_decorations_margin_t *margin_ptr = logged_calloc( - 1, sizeof(wlmaker_decorations_margin_t)); - if (NULL == margin_ptr) return NULL; - margin_ptr->parent_wlr_scene_tree_ptr = wlr_scene_tree_ptr; - - if (!recreate_edges(margin_ptr, edges)) { - wlmaker_decorations_margin_destroy(margin_ptr); - return NULL; - } - wlmaker_decorations_margin_set_position(margin_ptr, x, y); - wlmaker_decorations_margin_set_size(margin_ptr, width, height); - return margin_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_margin_destroy( - wlmaker_decorations_margin_t *margin_ptr) -{ - if (NULL != margin_ptr->bottom_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->bottom_rect_ptr->node); - margin_ptr->bottom_rect_ptr = NULL; - } - if (NULL != margin_ptr->right_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->right_rect_ptr->node); - margin_ptr->right_rect_ptr = NULL; - } - if (NULL != margin_ptr->top_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->top_rect_ptr->node); - margin_ptr->top_rect_ptr = NULL; - } - if (NULL != margin_ptr->left_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->left_rect_ptr->node); - margin_ptr->left_rect_ptr = NULL; - } - - free(margin_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_margin_set_position( - wlmaker_decorations_margin_t *margin_ptr, - int x, - int y) -{ - unsigned margin_width = wlmaker_config_theme.window_margin_width; - - int hx = 0; - if (margin_ptr->edges & WLR_EDGE_LEFT) { - hx -= margin_width; - } - - rect_set_position(margin_ptr->left_rect_ptr, - x - margin_width, y); - rect_set_position(margin_ptr->top_rect_ptr, - x + hx, y - margin_width); - rect_set_position(margin_ptr->right_rect_ptr, - x + margin_ptr->width, y); - rect_set_position(margin_ptr->bottom_rect_ptr, - x + hx, y + margin_ptr->height); - - margin_ptr->x = x; - margin_ptr->y = y; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_margin_set_size( - wlmaker_decorations_margin_t *margin_ptr, - unsigned width, - unsigned height) -{ - unsigned margin_width = wlmaker_config_theme.window_margin_width; - - // Horizontal margin area will cover the "corner" area if both margins - // are set. - unsigned hwidth = width; - if (margin_ptr->edges & WLR_EDGE_LEFT) { - hwidth += wlmaker_config_theme.window_margin_width; - } - if (margin_ptr->edges & WLR_EDGE_RIGHT) { - hwidth += wlmaker_config_theme.window_margin_width; - } - rect_set_size(margin_ptr->left_rect_ptr, margin_width, height); - rect_set_size(margin_ptr->top_rect_ptr, hwidth, margin_width); - rect_set_size(margin_ptr->right_rect_ptr, margin_width, height); - rect_set_size(margin_ptr->bottom_rect_ptr, hwidth, margin_width); - - margin_ptr->width = width; - margin_ptr->height = height; - - // Need to update the position of the margins. - wlmaker_decorations_margin_set_position( - margin_ptr, margin_ptr->x, margin_ptr->y); - -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_margin_set_edges( - wlmaker_decorations_margin_t *margin_ptr, - uint32_t edges) -{ - BS_ASSERT(recreate_edges(margin_ptr, edges)); - wlmaker_decorations_margin_set_position( - margin_ptr, margin_ptr->x, margin_ptr->y); - wlmaker_decorations_margin_set_size( - margin_ptr, margin_ptr->width, margin_ptr->height); -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** Re-creates the rectangles for the specified edges. */ -bool recreate_edges( - wlmaker_decorations_margin_t *margin_ptr, - uint32_t edges) -{ - uint32_t col = wlmaker_config_theme.window_margin_color; - struct wlr_scene_tree *wlr_scene_tree_ptr = - margin_ptr->parent_wlr_scene_tree_ptr; - - if (edges & WLR_EDGE_LEFT) { - margin_ptr->left_rect_ptr = create_rect(wlr_scene_tree_ptr, col); - if (NULL == margin_ptr->left_rect_ptr) return false; - } else if (NULL != margin_ptr->left_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->left_rect_ptr->node); - margin_ptr->left_rect_ptr = NULL; - } - - if (edges & WLR_EDGE_TOP) { - margin_ptr->top_rect_ptr = create_rect(wlr_scene_tree_ptr, col); - if (NULL == margin_ptr->top_rect_ptr) return false; - } else if (NULL != margin_ptr->top_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->top_rect_ptr->node); - margin_ptr->top_rect_ptr = NULL; - } - - if (edges & WLR_EDGE_RIGHT) { - margin_ptr->right_rect_ptr = create_rect(wlr_scene_tree_ptr, col); - if (NULL == margin_ptr->right_rect_ptr) return false; - } else if (NULL != margin_ptr->right_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->right_rect_ptr->node); - margin_ptr->right_rect_ptr = NULL; - } - - if (edges & WLR_EDGE_BOTTOM) { - margin_ptr->bottom_rect_ptr = create_rect(wlr_scene_tree_ptr, col); - if (NULL == margin_ptr->bottom_rect_ptr) return false; - } else if (NULL != margin_ptr->bottom_rect_ptr) { - wlr_scene_node_destroy(&margin_ptr->bottom_rect_ptr->node); - margin_ptr->bottom_rect_ptr = NULL; - } - margin_ptr->edges = edges; - return true; -} -/* ------------------------------------------------------------------------- */ -/** - * Helper: Creates a `wlr_scene_rect` with the given `color`. - * - * The rectangle will not be set to correct size nor position. Use - * @ref rect_set_size and @ref rect_set_position for that. - * - * @param decoration_wlr_scene_tree_ptr - * @param color As an ARGB8888 32-bit value. - */ -struct wlr_scene_rect *create_rect( - struct wlr_scene_tree *decoration_wlr_scene_tree_ptr, uint32_t color) -{ - float fcolor[4]; - bs_gfxbuf_argb8888_to_floats( - color, &fcolor[0], &fcolor[1], &fcolor[2], &fcolor[3]); - struct wlr_scene_rect *wlr_scene_rect_ptr = wlr_scene_rect_create( - decoration_wlr_scene_tree_ptr, 1, 1, fcolor); - if (NULL == wlr_scene_rect_ptr) { - bs_log(BS_ERROR, "Failed wlr_scene_rect_create(%p, 1, 1, %"PRIx32")", - decoration_wlr_scene_tree_ptr, color); - return NULL; - } - wlr_scene_node_set_enabled(&wlr_scene_rect_ptr->node, true); - return wlr_scene_rect_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Helper: Updates dimensions of the `wlr_scene_rect`. - * - * @param wlr_scene_rect_ptr The rectangle to update. May be NULL. - * @param width - * @param height - */ -static void rect_set_size( - struct wlr_scene_rect *wlr_scene_rect_ptr, - unsigned width, - unsigned height) -{ - if (NULL == wlr_scene_rect_ptr) return; - wlr_scene_rect_set_size( - wlr_scene_rect_ptr, width, height); -} - -/* ------------------------------------------------------------------------- */ -/** - * Helper: Updates position of the `wlr_scene_rect`. - * - * @param wlr_scene_rect_ptr The rectangle to update. May be NULL. - * @param x Position relative to the decorated window. - * @param y - */ -static void rect_set_position( - struct wlr_scene_rect *wlr_scene_rect_ptr, - int x, - int y) -{ - if (NULL == wlr_scene_rect_ptr) return; - wlr_scene_node_set_position( - &wlr_scene_rect_ptr->node, x, y); -} - -/* == End of margin.c ====================================================== */ diff --git a/src/decorations/margin.h b/src/decorations/margin.h deleted file mode 100644 index 8cc64564..00000000 --- a/src/decorations/margin.h +++ /dev/null @@ -1,94 +0,0 @@ -/* ========================================================================= */ -/** - * @file margin.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MARGIN_H__ -#define __MARGIN_H__ - -#include - -#include - -#define WLR_USE_UNSTABLE -#include -#undef WLR_USE_UNSTABLE - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** Forward definition: Handle for margin. */ -typedef struct _wlmaker_decorations_margin_t wlmaker_decorations_margin_t; - -/** Creates margin. */ -wlmaker_decorations_margin_t *wlmaker_decorations_margin_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - int x, int y, - unsigned width, unsigned height, - uint32_t edges); - -/** Destroys margin. */ -void wlmaker_decorations_margin_destroy( - wlmaker_decorations_margin_t *margin_ptr); - -/** - * Sets the position of the margins. - * - * The given (x, y) coordinates are defining the top-left corner of the - * decorated area, not including the margin itself. - * - * @param margin_ptr - * @param x - * @param y - */ -void wlmaker_decorations_margin_set_position( - wlmaker_decorations_margin_t *margin_ptr, - int x, - int y); - -/** - * Resizes the margins. - * - * `width` and `height` are describing the dimensions of the decorated element, - * excluding the added dimensions of the margin. - * - * @param margin_ptr - * @param width - * @param height - */ -void wlmaker_decorations_margin_set_size( - wlmaker_decorations_margin_t *margin_ptr, - unsigned width, - unsigned height); - -/** - * (re)configures which edges to show for the margin. - * - * @param margin_ptr - * @param edges - */ -void wlmaker_decorations_margin_set_edges( - wlmaker_decorations_margin_t *margin_ptr, - uint32_t edges); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __MARGIN_H__ */ -/* == End of margin.h ====================================================== */ diff --git a/src/decorations/resizebar.c b/src/decorations/resizebar.c deleted file mode 100644 index 0a630763..00000000 --- a/src/decorations/resizebar.c +++ /dev/null @@ -1,312 +0,0 @@ -/* ========================================================================= */ -/** - * @file resizebar.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "resizebar.h" - -#include "element.h" -#include "../config.h" -#include "../resizebar.h" - -/* == Declarations ========================================================= */ - -/** State of a window's resize bar. */ -struct _wlmaker_decorations_resizebar_t { - /** Back-link to the view it decorates. */ - wlmaker_view_t *view_ptr; - - /** Scene tree, for just the resize bar elements and margin. */ - struct wlr_scene_tree *wlr_scene_tree_ptr; - - /** Left element of the resize bar, or NULL if not set. */ - wlmaker_decorations_resize_t *left_resize_ptr; - /** Center element of the resize bar, or NULL if not set. */ - wlmaker_decorations_resize_t *center_resize_ptr; - /** Right element of the resize bar. */ - wlmaker_decorations_resize_t *right_resize_ptr; - - /** Width of the left element, or 0 if not set. */ - unsigned left_width; - /** Width of the center element, or 0 if not set. */ - unsigned center_width; - /** Width of the right element. */ - unsigned right_width; - - /** Overall width of the decorated window. */ - unsigned width; - /** Height of the decorated window. */ - unsigned height; -}; - -/** Hardcoded: Width of bezel. */ -static const uint32_t bezel_width = 1; -/** Hardcoded: Height of the resize bar. */ -static const uint32_t resizebar_height = 7; -/** Hardcoded: Width of the corner elements of the resize bar. */ -static const uint32_t resizebar_corner_width = 29; - -static void set_width( - wlmaker_decorations_resizebar_t *resizebar_ptr, - unsigned width); -static bs_gfxbuf_t *create_background(unsigned width); -static void create_or_update_resize( - wlmaker_decorations_resizebar_t *resizebar_ptr, - wlmaker_decorations_resize_t **resize_ptr_ptr, - bs_gfxbuf_t *background_gfxbuf_ptr, - int pos, unsigned width, - uint32_t edges); - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_resizebar_t *wlmaker_decorations_resizebar_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - unsigned width, - unsigned height, - wlmaker_view_t *view_ptr) -{ - wlmaker_decorations_resizebar_t *resizebar_ptr = logged_calloc( - 1, sizeof(wlmaker_decorations_resizebar_t)); - if (NULL == resizebar_ptr) return NULL; - resizebar_ptr->view_ptr = view_ptr; - - resizebar_ptr->wlr_scene_tree_ptr = wlr_scene_tree_create( - wlr_scene_tree_ptr); - if (NULL == resizebar_ptr->wlr_scene_tree_ptr) { - wlmaker_decorations_resizebar_destroy(resizebar_ptr); - return NULL; - } - wlr_scene_node_set_position( - &resizebar_ptr->wlr_scene_tree_ptr->node, - 0, height + wlmaker_config_theme.window_margin_width); - - wlmaker_decorations_resizebar_set_size(resizebar_ptr, width, height); - return resizebar_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_resizebar_destroy( - wlmaker_decorations_resizebar_t *resizebar_ptr) -{ - if (NULL != resizebar_ptr->right_resize_ptr) { - wlmaker_decorations_resize_destroy(resizebar_ptr->right_resize_ptr); - resizebar_ptr->right_resize_ptr = NULL; - } - if (NULL != resizebar_ptr->center_resize_ptr) { - wlmaker_decorations_resize_destroy(resizebar_ptr->center_resize_ptr); - resizebar_ptr->center_resize_ptr = NULL; - } - if (NULL != resizebar_ptr->left_resize_ptr) { - wlmaker_decorations_resize_destroy(resizebar_ptr->left_resize_ptr); - resizebar_ptr->left_resize_ptr = NULL; - } - - if (NULL != resizebar_ptr->wlr_scene_tree_ptr) { - wlr_scene_node_destroy(&resizebar_ptr->wlr_scene_tree_ptr->node); - resizebar_ptr->wlr_scene_tree_ptr = NULL; - } - - free(resizebar_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_resizebar_set_size( - wlmaker_decorations_resizebar_t *resizebar_ptr, - unsigned width, - unsigned height) -{ - if (width == resizebar_ptr->width && - height == resizebar_ptr->height) return; - set_width(resizebar_ptr, width); - - wlr_scene_node_set_position( - &resizebar_ptr->wlr_scene_tree_ptr->node, - 0, height + wlmaker_config_theme.window_margin_width); - - unsigned bar_y = 0; - - if (0 < resizebar_ptr->left_width) { - wlmaker_decorations_element_set_position( - wlmaker_decorations_element_from_resize( - resizebar_ptr->left_resize_ptr), - 0, bar_y); - } - - if (0 < resizebar_ptr->center_width) { - wlmaker_decorations_element_set_position( - wlmaker_decorations_element_from_resize( - resizebar_ptr->center_resize_ptr), - resizebar_ptr->left_width, bar_y); - } - - wlmaker_decorations_element_set_position( - wlmaker_decorations_element_from_resize( - resizebar_ptr->right_resize_ptr), - width - resizebar_ptr->right_width, bar_y); - - resizebar_ptr->height = height; - return; -} - -/* ------------------------------------------------------------------------- */ -unsigned wlmaker_decorations_resizebar_get_height( - __UNUSED__ wlmaker_decorations_resizebar_t *resizebar_ptr) -{ - return resizebar_height + wlmaker_config_theme.window_margin_width; -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** Applies the width to the resizebar, re-creating elements if needed. */ -static void set_width( - wlmaker_decorations_resizebar_t *resizebar_ptr, - unsigned width) -{ - if (width == resizebar_ptr->width) return; - - resizebar_ptr->left_width = resizebar_corner_width; - resizebar_ptr->right_width = resizebar_corner_width; - if (width > 2 * resizebar_corner_width) { - resizebar_ptr->center_width = width - 2 * resizebar_corner_width; - } else if (width > resizebar_corner_width) { - resizebar_ptr->center_width = 0; - resizebar_ptr->left_width = width - resizebar_corner_width; - } else { - resizebar_ptr->left_width = 0; - resizebar_ptr->right_width = width; - } - - BS_ASSERT(resizebar_ptr->left_width + - resizebar_ptr->right_width + - resizebar_ptr->center_width == width); - - bs_gfxbuf_t *gfxbuf_ptr = create_background(width); - BS_ASSERT(NULL != gfxbuf_ptr); - - if (0 < resizebar_ptr->left_width) { - create_or_update_resize( - resizebar_ptr, - &resizebar_ptr->left_resize_ptr, - gfxbuf_ptr, - 0, resizebar_ptr->left_width, - WLR_EDGE_LEFT | WLR_EDGE_BOTTOM); - } else if (NULL != resizebar_ptr->left_resize_ptr) { - wlmaker_decorations_resize_destroy(resizebar_ptr->left_resize_ptr); - resizebar_ptr->left_resize_ptr = NULL; - } - - if (0 < resizebar_ptr->center_width) { - create_or_update_resize( - resizebar_ptr, - &resizebar_ptr->center_resize_ptr, - gfxbuf_ptr, - resizebar_ptr->left_width, resizebar_ptr->center_width, - WLR_EDGE_BOTTOM); - } else if (NULL != resizebar_ptr->center_resize_ptr) { - wlmaker_decorations_resize_destroy(resizebar_ptr->center_resize_ptr); - resizebar_ptr->center_resize_ptr = NULL; - } - - create_or_update_resize( - resizebar_ptr, - &resizebar_ptr->right_resize_ptr, - gfxbuf_ptr, - width - resizebar_ptr->right_width, resizebar_ptr->right_width, - WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); - - bs_gfxbuf_destroy(gfxbuf_ptr); - resizebar_ptr->width = width; -} - -/* ------------------------------------------------------------------------- */ -/** Creates the background texture at givenm width. */ -bs_gfxbuf_t *create_background(unsigned width) -{ - bs_gfxbuf_t *gfxbuf_ptr = bs_gfxbuf_create(width, resizebar_height); - if (NULL == gfxbuf_ptr) return NULL; - - cairo_t *cairo_ptr = cairo_create_from_bs_gfxbuf(gfxbuf_ptr); - if (NULL == cairo_ptr) { - bs_gfxbuf_destroy(gfxbuf_ptr); - return false; - } - wlmaker_primitives_cairo_fill( - cairo_ptr, &wlmaker_config_theme.resizebar_fill); - cairo_destroy(cairo_ptr); - - return gfxbuf_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** Creates or updates a resizebar element. */ -void create_or_update_resize( - wlmaker_decorations_resizebar_t *resizebar_ptr, - wlmaker_decorations_resize_t **resize_ptr_ptr, - bs_gfxbuf_t *background_gfxbuf_ptr, - int pos, unsigned width, - uint32_t edges) -{ - cairo_t *cairo_ptr; - - struct wlr_buffer *released_wlrbuf_ptr = bs_gfxbuf_create_wlr_buffer( - width, resizebar_height); - BS_ASSERT(NULL != released_wlrbuf_ptr); - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(released_wlrbuf_ptr), 0, 0, - background_gfxbuf_ptr, pos, 0, - width, resizebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(released_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel(cairo_ptr, bezel_width, true); - cairo_destroy(cairo_ptr); - - struct wlr_buffer *pressed_wlrbuf_ptr = bs_gfxbuf_create_wlr_buffer( - width, resizebar_height); - BS_ASSERT(NULL != released_wlrbuf_ptr); - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(pressed_wlrbuf_ptr), 0, 0, - background_gfxbuf_ptr, pos, 0, - width, resizebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(pressed_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel(cairo_ptr, bezel_width, false); - cairo_destroy(cairo_ptr); - - if (NULL == *resize_ptr_ptr) { - *resize_ptr_ptr = wlmaker_decorations_resize_create( - resizebar_ptr->wlr_scene_tree_ptr, - resizebar_ptr->view_ptr->server_ptr->cursor_ptr, - resizebar_ptr->view_ptr, - released_wlrbuf_ptr, - pressed_wlrbuf_ptr, - edges); - BS_ASSERT(NULL != *resize_ptr_ptr); - } else { - wlmaker_decorations_resize_set_textures( - *resize_ptr_ptr, - released_wlrbuf_ptr, - pressed_wlrbuf_ptr); - } - - wlr_buffer_drop(pressed_wlrbuf_ptr); - wlr_buffer_drop(released_wlrbuf_ptr); -} - -/* == End of resizebar.c =================================================== */ diff --git a/src/decorations/resizebar.h b/src/decorations/resizebar.h deleted file mode 100644 index 47174dd2..00000000 --- a/src/decorations/resizebar.h +++ /dev/null @@ -1,86 +0,0 @@ -/* ========================================================================= */ -/** - * @file resizebar.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __RESIZEBAR_H__ -#define __RESIZEBAR_H__ - -#define WLR_USE_UNSTABLE -#include -#undef WLR_USE_UNSTABLE - -#include "../view.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** Forward declaration: Resizebar of window decoration. */ -typedef struct _wlmaker_decorations_resizebar_t wlmaker_decorations_resizebar_t; - -/** - * Creates the title bar for window decoration. - * - * @param wlr_scene_tree_ptr - * @param width - * @param height - * @param view_ptr - * - * @return A resizebar handle, or NULL on error. Must be free-d by calling - * @ref wlmaker_decorations_resizebar_destroy. - */ -wlmaker_decorations_resizebar_t *wlmaker_decorations_resizebar_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - unsigned width, - unsigned height, - wlmaker_view_t *view_ptr); - -/** - * Destroys a window decoration resize bar. - * - * @param resizebar_ptr - */ -void wlmaker_decorations_resizebar_destroy( - wlmaker_decorations_resizebar_t *resizebar_ptr); - -/** - * Sets the width of the resizebar. - * - * @param resizebar_ptr - * @param width - * @param height - */ -void wlmaker_decorations_resizebar_set_size( - wlmaker_decorations_resizebar_t *resizebar_ptr, - unsigned width, - unsigned height); - -/** - * Returns the height of the resizebar. Includes the bottom margin. - * - * @param resizebar_ptr - */ -unsigned wlmaker_decorations_resizebar_get_height( - wlmaker_decorations_resizebar_t *resizebar_ptr); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __RESIZEBAR_H__ */ -/* == End of resizebar.h =================================================== */ diff --git a/src/decorations/titlebar.c b/src/decorations/titlebar.c deleted file mode 100644 index e0ae949e..00000000 --- a/src/decorations/titlebar.c +++ /dev/null @@ -1,634 +0,0 @@ -/* ========================================================================= */ -/** - * @file titlebar.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "titlebar.h" - -#include - -#include "element.h" -#include "../config.h" -#include "toolkit/toolkit.h" - -/* == Declarations ========================================================= */ - -/** State of a window's titlebar, including buttons and title area. */ -struct _wlmaker_decorations_titlebar_t { - /** Back-link to the view it decorates. */ - wlmaker_view_t *view_ptr; - - /** Scene tree, for just the title bar elements and margin. */ - struct wlr_scene_tree *wlr_scene_tree_ptr; - - /** "Minimize" button element. */ - wlmaker_decorations_button_t *minimize_button_ptr; - /** "Close" button element. */ - wlmaker_decorations_button_t *close_button_ptr; - /** "Title" element. */ - wlmaker_decorations_title_t *title_ptr; - - /** Background graphics buffer, focussed window. */ - bs_gfxbuf_t *background_focussed_gfxbuf_ptr; - /** Background graphics buffer, blurred window. */ - bs_gfxbuf_t *background_blurred_gfxbuf_ptr; - - /** Currently configured width, excluding the outer margins. */ - unsigned width; - /** Position of the title element, relative to the scene tree. */ - int title_pos; - /** Width of the title element. */ - unsigned title_width; - /** Position of the "close" button, relative to the scene tree. */ - int close_pos; -}; - -/** Holder for a few `struct wlr_buffer` textures, for buttons & title. */ -typedef struct { - /** Texture in released state. */ - struct wlr_buffer *released_wlrbuf_ptr; - /** Texture in pressed state, or NULL. */ - struct wlr_buffer *pressed_wlrbuf_ptr; - /** Texture in blurred state. */ - struct wlr_buffer *blurred_wlrbuf_ptr; -} wlr_buffer_holder_t; - -static bool recreate_backgrounds( - wlmaker_decorations_titlebar_t *titlebar_ptr, - unsigned width); - -static bool create_wlr_buffers( - wlr_buffer_holder_t *buffer_holder_ptr, - unsigned width, - bool press); -static void drop_wlr_buffers(wlr_buffer_holder_t *buffer_holder_ptr); - -static void create_or_update_minimize_button( - wlmaker_decorations_titlebar_t *titlebar_ptr); -static void create_or_update_close_button( - wlmaker_decorations_titlebar_t *titlebar_ptr); -static void create_or_update_title( - wlmaker_decorations_titlebar_t *titlebar_ptr); - -static void button_minimize_callback( - wlmaker_interactive_t *interactive_ptr, - void *data_ptr); -static void button_close_callback( - wlmaker_interactive_t *interactive_ptr, - void *data_ptr); - -/** Hardcoded: Width of the window buttons. */ -static const unsigned wlmaker_decorations_button_width = 22; -/** Hardcoded: Height of the title bar, in pixels. */ -static const unsigned wlmaker_decorations_titlebar_height = 22; - -/** Hardcoded: Width of the bezel for buttons. */ -static const unsigned wlmaker_decorations_button_bezel_width = 1; - -/** - * Attempted minimal width of the title. If the title width falls below that - * value, buttons will be dropped instead. - */ -static const unsigned title_min_width = wlmaker_decorations_button_width; - -/* == Exported methods ===================================================== */ - - -/* ------------------------------------------------------------------------- */ -wlmaker_decorations_titlebar_t *wlmaker_decorations_titlebar_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - unsigned width, - wlmaker_view_t *view_ptr) -{ - wlmaker_decorations_titlebar_t *titlebar_ptr = logged_calloc( - 1, sizeof(wlmaker_decorations_titlebar_t)); - if (NULL == titlebar_ptr) return NULL; - titlebar_ptr->view_ptr = view_ptr; - - titlebar_ptr->wlr_scene_tree_ptr = wlr_scene_tree_create( - wlr_scene_tree_ptr); - if (NULL == titlebar_ptr->wlr_scene_tree_ptr) { - wlmaker_decorations_titlebar_destroy(titlebar_ptr); - return NULL; - } - wlr_scene_node_set_position( - &titlebar_ptr->wlr_scene_tree_ptr->node, - 0, - wlmaker_decorations_titlebar_height - - wlmaker_config_theme.window_margin_width); - - wlmaker_decorations_titlebar_set_width(titlebar_ptr, width); - return titlebar_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_titlebar_destroy( - wlmaker_decorations_titlebar_t *titlebar_ptr) -{ - if (NULL != titlebar_ptr->title_ptr) { - wlmaker_decorations_title_destroy(titlebar_ptr->title_ptr); - titlebar_ptr->title_ptr = NULL; - } - - if (NULL != titlebar_ptr->close_button_ptr) { - wlmaker_decorations_button_destroy(titlebar_ptr->close_button_ptr); - titlebar_ptr->close_button_ptr = NULL; - } - - if (NULL != titlebar_ptr->minimize_button_ptr) { - wlmaker_decorations_button_destroy(titlebar_ptr->minimize_button_ptr); - titlebar_ptr->minimize_button_ptr = NULL; - } - - if (NULL != titlebar_ptr->background_focussed_gfxbuf_ptr) { - bs_gfxbuf_destroy(titlebar_ptr->background_focussed_gfxbuf_ptr); - titlebar_ptr->background_focussed_gfxbuf_ptr = NULL; - } - if (NULL != titlebar_ptr->background_blurred_gfxbuf_ptr) { - bs_gfxbuf_destroy(titlebar_ptr->background_blurred_gfxbuf_ptr); - titlebar_ptr->background_blurred_gfxbuf_ptr = NULL; - } - - if (NULL != titlebar_ptr->wlr_scene_tree_ptr) { - wlr_scene_node_destroy(&titlebar_ptr->wlr_scene_tree_ptr->node); - titlebar_ptr->wlr_scene_tree_ptr = NULL; - } - - free(titlebar_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_titlebar_set_width( - wlmaker_decorations_titlebar_t *titlebar_ptr, - unsigned width) -{ - bool has_close, has_minimize; - - if (width == titlebar_ptr->width) return; - - // The 'minimize' button is shown only if there's space for everything. - if (width > title_min_width + - 2 * wlmaker_decorations_button_width + - 2 * wlmaker_config_theme.window_margin_width) { - titlebar_ptr->title_pos = - wlmaker_decorations_button_width + - wlmaker_config_theme.window_margin_width; - has_minimize = true; - } else { - has_minimize = false; - titlebar_ptr->title_pos = 0; - } - - // The 'close' button is shown as long as there's space for title and - // one button, at least. - if (width > title_min_width + - wlmaker_decorations_button_width + - wlmaker_config_theme.window_margin_width) { - titlebar_ptr->close_pos = - width - wlmaker_decorations_button_width; - has_close = true; - } else { - // Won't be shown, but simplifies computation... - titlebar_ptr->close_pos = - width + wlmaker_config_theme.window_margin_width; - has_close = false; - } - - BS_ASSERT( - titlebar_ptr->close_pos >= - (int)wlmaker_config_theme.window_margin_width + titlebar_ptr->title_pos); - titlebar_ptr->title_width = - titlebar_ptr->close_pos - wlmaker_config_theme.window_margin_width - - titlebar_ptr->title_pos; - titlebar_ptr->width = width; - - BS_ASSERT(recreate_backgrounds(titlebar_ptr, width)); - - if (has_minimize) { - create_or_update_minimize_button(titlebar_ptr); - wlmaker_decorations_element_set_position( - wlmaker_decorations_element_from_button( - titlebar_ptr->minimize_button_ptr), - 0, 0); - } else if (NULL != titlebar_ptr->minimize_button_ptr) { - wlmaker_decorations_button_destroy(titlebar_ptr->minimize_button_ptr); - titlebar_ptr->minimize_button_ptr = NULL; - } - - create_or_update_title(titlebar_ptr); - wlmaker_decorations_element_set_position( - wlmaker_decorations_element_from_title(titlebar_ptr->title_ptr), - titlebar_ptr->title_pos, 0); - - if (has_close) { - create_or_update_close_button(titlebar_ptr); - wlmaker_decorations_element_set_position( - wlmaker_decorations_element_from_button( - titlebar_ptr->close_button_ptr), - titlebar_ptr->close_pos, 0); - } else if (NULL != titlebar_ptr->close_button_ptr) { - wlmaker_decorations_button_destroy(titlebar_ptr->close_button_ptr); - titlebar_ptr->close_button_ptr = NULL; - } - - titlebar_ptr->width = width; -} - -/* ------------------------------------------------------------------------- */ -unsigned wlmaker_decorations_titlebar_get_height( - __UNUSED__ wlmaker_decorations_titlebar_t *titlebar_ptr) -{ - return wlmaker_decorations_titlebar_height + - wlmaker_config_theme.window_margin_width; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_decorations_titlebar_update_title( - wlmaker_decorations_titlebar_t *titlebar_ptr) -{ - create_or_update_title(titlebar_ptr); -} - -/* == Local (static) methods =============================================== */ - -/** - * (Re)creates the backgrounds for the title bar. - * - * @param titlebar_ptr - * @param width - * - * @return true on success. - */ -static bool recreate_backgrounds( - wlmaker_decorations_titlebar_t *titlebar_ptr, - unsigned width) -{ - bs_gfxbuf_t *focussed_ptr, *blurred_ptr; - cairo_t *cairo_ptr; - - focussed_ptr = bs_gfxbuf_create( - width, wlmaker_decorations_titlebar_height); - if (NULL == focussed_ptr) return false; - cairo_ptr = cairo_create_from_bs_gfxbuf(focussed_ptr); - if (NULL == cairo_ptr) { - bs_gfxbuf_destroy(focussed_ptr); - return false; - } - wlmaker_primitives_cairo_fill( - cairo_ptr, - &wlmaker_config_theme.titlebar_focussed_fill); - cairo_destroy(cairo_ptr); - - blurred_ptr = bs_gfxbuf_create( - width, wlmaker_decorations_titlebar_height); - if (NULL == blurred_ptr) { - bs_gfxbuf_destroy(focussed_ptr); - return false; - } - cairo_ptr = cairo_create_from_bs_gfxbuf(blurred_ptr); - if (NULL == cairo_ptr) { - bs_gfxbuf_destroy(focussed_ptr); - bs_gfxbuf_destroy(blurred_ptr); - return false; - } - wlmaker_primitives_cairo_fill( - cairo_ptr, - &wlmaker_config_theme.titlebar_blurred_fill); - cairo_destroy(cairo_ptr); - - if (NULL != titlebar_ptr->background_focussed_gfxbuf_ptr) { - bs_gfxbuf_destroy(titlebar_ptr->background_focussed_gfxbuf_ptr); - } - titlebar_ptr->background_focussed_gfxbuf_ptr = focussed_ptr; - if (NULL != titlebar_ptr->background_blurred_gfxbuf_ptr) { - bs_gfxbuf_destroy(titlebar_ptr->background_blurred_gfxbuf_ptr); - } - titlebar_ptr->background_blurred_gfxbuf_ptr = blurred_ptr; - - return true; -} - -/* ------------------------------------------------------------------------- */ -/** Creates WLR buffers of `buffer_holder_ptr`. */ -bool create_wlr_buffers( - wlr_buffer_holder_t *buffer_holder_ptr, - unsigned width, - bool press) -{ - memset(buffer_holder_ptr, 0, sizeof(wlr_buffer_holder_t)); - - buffer_holder_ptr->released_wlrbuf_ptr = bs_gfxbuf_create_wlr_buffer( - width, wlmaker_decorations_titlebar_height); - if (NULL == buffer_holder_ptr->released_wlrbuf_ptr) { - drop_wlr_buffers(buffer_holder_ptr); - return false; - } - - if (press) { - buffer_holder_ptr->pressed_wlrbuf_ptr = bs_gfxbuf_create_wlr_buffer( - width, wlmaker_decorations_titlebar_height); - if (NULL == buffer_holder_ptr->pressed_wlrbuf_ptr) { - drop_wlr_buffers(buffer_holder_ptr); - return false; - } - } - - buffer_holder_ptr->blurred_wlrbuf_ptr = bs_gfxbuf_create_wlr_buffer( - width, wlmaker_decorations_titlebar_height); - if (NULL == buffer_holder_ptr->blurred_wlrbuf_ptr) { - drop_wlr_buffers(buffer_holder_ptr); - return false; - } - - return true; -} - -/* ------------------------------------------------------------------------- */ -/** Drops the WLR buffers of `buffer_holder_ptr`. */ -void drop_wlr_buffers(wlr_buffer_holder_t *buffer_holder_ptr) -{ - if (NULL != buffer_holder_ptr->blurred_wlrbuf_ptr) { - wlr_buffer_drop(buffer_holder_ptr->blurred_wlrbuf_ptr); - buffer_holder_ptr->blurred_wlrbuf_ptr = NULL; - } - - if (NULL != buffer_holder_ptr->pressed_wlrbuf_ptr) { - wlr_buffer_drop(buffer_holder_ptr->pressed_wlrbuf_ptr); - buffer_holder_ptr->pressed_wlrbuf_ptr = NULL; - } - - if (NULL != buffer_holder_ptr->released_wlrbuf_ptr) { - wlr_buffer_drop(buffer_holder_ptr->released_wlrbuf_ptr); - buffer_holder_ptr->released_wlrbuf_ptr = NULL; - } -} - -/* ------------------------------------------------------------------------- */ -/** - * Creates (or updates) the "Minimize" button and textures. - * - * @param titlebar_ptr - */ -void create_or_update_minimize_button( - wlmaker_decorations_titlebar_t *titlebar_ptr) -{ - cairo_t *cairo_ptr; - wlr_buffer_holder_t buf_holder; - - BS_ASSERT(create_wlr_buffers( - &buf_holder, wlmaker_decorations_button_width, true)); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.released_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_focussed_gfxbuf_ptr, - 0, 0, - wlmaker_decorations_button_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.released_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, true); - wlmaker_primitives_draw_minimize_icon( - cairo_ptr, wlmaker_config_theme.titlebar_focussed_text_color); - cairo_destroy(cairo_ptr); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.pressed_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_focussed_gfxbuf_ptr, - 0, 0, - wlmaker_decorations_button_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.pressed_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, false); - wlmaker_primitives_draw_minimize_icon( - cairo_ptr, wlmaker_config_theme.titlebar_focussed_text_color); - cairo_destroy(cairo_ptr); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.blurred_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_blurred_gfxbuf_ptr, - 0, 0, - wlmaker_decorations_button_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.blurred_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, true); - wlmaker_primitives_draw_minimize_icon( - cairo_ptr, wlmaker_config_theme.titlebar_blurred_text_color); - cairo_destroy(cairo_ptr); - - if (NULL == titlebar_ptr->minimize_button_ptr) { - titlebar_ptr->minimize_button_ptr = wlmaker_decorations_button_create( - titlebar_ptr->wlr_scene_tree_ptr, - titlebar_ptr->view_ptr->server_ptr->cursor_ptr, - button_minimize_callback, - titlebar_ptr->view_ptr, - buf_holder.released_wlrbuf_ptr, - buf_holder.pressed_wlrbuf_ptr, - buf_holder.blurred_wlrbuf_ptr, - WLR_EDGE_LEFT | WLR_EDGE_TOP); - BS_ASSERT(NULL != titlebar_ptr->minimize_button_ptr); - } else { - wlmaker_decorations_button_set_textures( - titlebar_ptr->minimize_button_ptr, - buf_holder.released_wlrbuf_ptr, - buf_holder.pressed_wlrbuf_ptr, - buf_holder.blurred_wlrbuf_ptr); - } - - drop_wlr_buffers(&buf_holder); -} - -/* ------------------------------------------------------------------------- */ -/** - * Creates (or updates) the "Close" button and textures. - * - * @param titlebar_ptr - */ -void create_or_update_close_button( - wlmaker_decorations_titlebar_t *titlebar_ptr) -{ - cairo_t *cairo_ptr; - wlr_buffer_holder_t buf_holder; - - BS_ASSERT(create_wlr_buffers( - &buf_holder, wlmaker_decorations_button_width, true)); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.released_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_focussed_gfxbuf_ptr, - titlebar_ptr->close_pos, 0, - wlmaker_decorations_button_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.released_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, true); - wlmaker_primitives_draw_close_icon( - cairo_ptr, wlmaker_config_theme.titlebar_focussed_text_color); - cairo_destroy(cairo_ptr); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.pressed_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_focussed_gfxbuf_ptr, - titlebar_ptr->close_pos, 0, - wlmaker_decorations_button_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.pressed_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, false); - wlmaker_primitives_draw_close_icon( - cairo_ptr, wlmaker_config_theme.titlebar_focussed_text_color); - cairo_destroy(cairo_ptr); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.blurred_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_blurred_gfxbuf_ptr, - titlebar_ptr->close_pos, 0, - wlmaker_decorations_button_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.blurred_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, true); - wlmaker_primitives_draw_close_icon( - cairo_ptr, wlmaker_config_theme.titlebar_blurred_text_color); - cairo_destroy(cairo_ptr); - - if (NULL == titlebar_ptr->close_button_ptr) { - titlebar_ptr->close_button_ptr = wlmaker_decorations_button_create( - titlebar_ptr->wlr_scene_tree_ptr, - titlebar_ptr->view_ptr->server_ptr->cursor_ptr, - button_close_callback, - titlebar_ptr->view_ptr, - buf_holder.released_wlrbuf_ptr, - buf_holder.pressed_wlrbuf_ptr, - buf_holder.blurred_wlrbuf_ptr, - WLR_EDGE_RIGHT | WLR_EDGE_TOP); - BS_ASSERT(NULL != titlebar_ptr->close_button_ptr); - } else { - wlmaker_decorations_button_set_textures( - titlebar_ptr->close_button_ptr, - buf_holder.released_wlrbuf_ptr, - buf_holder.pressed_wlrbuf_ptr, - buf_holder.blurred_wlrbuf_ptr); - } - - drop_wlr_buffers(&buf_holder); -} - -/* ------------------------------------------------------------------------- */ -/** - * Creates (or updates) the title element and textures of the title bar. - * - * @param titlebar_ptr - */ -void create_or_update_title(wlmaker_decorations_titlebar_t *titlebar_ptr) -{ - cairo_t *cairo_ptr; - wlr_buffer_holder_t buf_holder; - - BS_ASSERT(create_wlr_buffers( - &buf_holder, titlebar_ptr->title_width, false)); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.released_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_focussed_gfxbuf_ptr, - titlebar_ptr->title_pos, 0, - titlebar_ptr->title_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.released_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, true); - wlmaker_primitives_draw_window_title( - cairo_ptr, - wlmaker_view_get_title(titlebar_ptr->view_ptr), - wlmaker_config_theme.titlebar_focussed_text_color); - cairo_destroy(cairo_ptr); - - bs_gfxbuf_copy_area( - bs_gfxbuf_from_wlr_buffer(buf_holder.blurred_wlrbuf_ptr), - 0, 0, - titlebar_ptr->background_blurred_gfxbuf_ptr, - titlebar_ptr->title_pos, 0, - titlebar_ptr->title_width, wlmaker_decorations_titlebar_height); - cairo_ptr = cairo_create_from_wlr_buffer(buf_holder.blurred_wlrbuf_ptr); - BS_ASSERT(NULL != cairo_ptr); - wlmaker_primitives_draw_bezel( - cairo_ptr, wlmaker_decorations_button_bezel_width, true); - wlmaker_primitives_draw_window_title( - cairo_ptr, - wlmaker_view_get_title(titlebar_ptr->view_ptr), - wlmaker_config_theme.titlebar_blurred_text_color); - cairo_destroy(cairo_ptr); - - if (NULL == titlebar_ptr->title_ptr) { - titlebar_ptr->title_ptr = wlmaker_decorations_title_create( - titlebar_ptr->wlr_scene_tree_ptr, - titlebar_ptr->view_ptr->server_ptr->cursor_ptr, - titlebar_ptr->view_ptr, - buf_holder.released_wlrbuf_ptr, - buf_holder.blurred_wlrbuf_ptr); - BS_ASSERT(NULL != titlebar_ptr->title_ptr); - } else { - wlmaker_decorations_title_set_textures( - titlebar_ptr->title_ptr, - buf_holder.released_wlrbuf_ptr, - buf_holder.blurred_wlrbuf_ptr); - } - - drop_wlr_buffers(&buf_holder); -} - -/* ------------------------------------------------------------------------- */ -/** - * Callback for the "minimize" button action. - * - * @param interactive_ptr Points to the interactive that triggered the - * action. Unused. - * @param data_ptr This view. - */ -void button_minimize_callback( - __UNUSED__ wlmaker_interactive_t *interactive_ptr, - void *data_ptr) -{ - wlmaker_view_t *view_ptr = (wlmaker_view_t*)data_ptr; - wlmaker_view_set_iconified(view_ptr, true); -} - -/* ------------------------------------------------------------------------- */ -/** - * Callback for the close button action. - * - * @param interactive_ptr Points to the interactive that triggered the - * action. Unused. - * @param data_ptr This view. - */ -void button_close_callback( - __UNUSED__ wlmaker_interactive_t *interactive_ptr, - void *data_ptr) -{ - wlmaker_view_t *view_ptr = (wlmaker_view_t*)data_ptr; - view_ptr->send_close_callback(view_ptr); -} - -/* == End of titlebar.c ==================================================== */ diff --git a/src/decorations/titlebar.h b/src/decorations/titlebar.h deleted file mode 100644 index b767c486..00000000 --- a/src/decorations/titlebar.h +++ /dev/null @@ -1,90 +0,0 @@ -/* ========================================================================= */ -/** - * @file titlebar.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __TITLEBAR_H__ -#define __TITLEBAR_H__ - -#define WLR_USE_UNSTABLE -#include -#undef WLR_USE_UNSTABLE - -#include "../view.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** Forward declaration: Titlebar of window decoration. */ -typedef struct _wlmaker_decorations_titlebar_t wlmaker_decorations_titlebar_t; - -/** - * Creates the title bar for window decoration. - * - * @param wlr_scene_tree_ptr - * @param width - * @param view_ptr - * - * @return A titlebar handle, or NULL on error. Must be free-d by calling - * @ref wlmaker_decorations_titlebar_destroy. - */ -wlmaker_decorations_titlebar_t *wlmaker_decorations_titlebar_create( - struct wlr_scene_tree *wlr_scene_tree_ptr, - unsigned width, - wlmaker_view_t *view_ptr); - -/** - * Destroys a window decoration title bar. - * - * @param titlebar_ptr - */ -void wlmaker_decorations_titlebar_destroy( - wlmaker_decorations_titlebar_t *titlebar_ptr); - -/** - * Sets the width of the titlebar. - * - * @param titlebar_ptr - * @param width - */ -void wlmaker_decorations_titlebar_set_width( - wlmaker_decorations_titlebar_t *titlebar_ptr, - unsigned width); - -/** - * Returns the height of the titlebar. Includes the top margin. - * - * @param titlebar_ptr - */ -unsigned wlmaker_decorations_titlebar_get_height( - wlmaker_decorations_titlebar_t *titlebar_ptr); - -/** - * Sets the title of the titlebar. Will pull it from the view. - * - * @param titlebar_ptr - */ -void wlmaker_decorations_titlebar_update_title( - wlmaker_decorations_titlebar_t *titlebar_ptr); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __TITLEBAR_H__ */ -/* == End of titlebar.h ==================================================== */ diff --git a/src/decorations/window_decorations.c b/src/decorations/window_decorations.c deleted file mode 100644 index dd57f4f8..00000000 --- a/src/decorations/window_decorations.c +++ /dev/null @@ -1,230 +0,0 @@ -/* ========================================================================= */ -/** - * @file window_decorations.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "window_decorations.h" - -#include "../config.h" -#include "margin.h" -#include "resizebar.h" -#include "titlebar.h" - -/* == Declarations ========================================================= */ - -/** State of the decoration of a window. */ -struct _wlmaker_window_decorations_t { - /** Back-link to the view. */ - wlmaker_view_t *view_ptr; - - /** Scene tree holding all decoration elements. */ - struct wlr_scene_tree *wlr_scene_tree_ptr; - - /** Window margins. */ - wlmaker_decorations_margin_t *margin_ptr; - - /** The titlebar, including buttons. */ - wlmaker_decorations_titlebar_t *titlebar_ptr; - - /** The resizebar, including all resize elements and margin. */ - wlmaker_decorations_resizebar_t *resizebar_ptr; -}; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmaker_window_decorations_t *wlmaker_window_decorations_create( - wlmaker_view_t *view_ptr) -{ - wlmaker_window_decorations_t *decorations_ptr = logged_calloc( - 1, sizeof(wlmaker_window_decorations_t)); - if (NULL == decorations_ptr) return NULL; - decorations_ptr->view_ptr = view_ptr; - - // Must be mapped. TODO(kaeser@gubbe.ch): Don't rely on internals! - BS_ASSERT(NULL != view_ptr->workspace_ptr); - BS_ASSERT(view_ptr->server_side_decoration_enabled); - BS_ASSERT(!view_ptr->fullscreen); - // TODO(kaeser@gubbe.ch): Shouldn't need to access the internals. - uint32_t width, height; - view_ptr->impl_ptr->get_size(view_ptr, &width, &height); - - decorations_ptr->wlr_scene_tree_ptr = wlr_scene_tree_create( - view_ptr->elements_wlr_scene_tree_ptr); - if (NULL == decorations_ptr->wlr_scene_tree_ptr) { - wlmaker_window_decorations_destroy(decorations_ptr); - return NULL; - } - - // Margins around the window itself (not including title or resize bar). - decorations_ptr->margin_ptr = wlmaker_decorations_margin_create( - decorations_ptr->wlr_scene_tree_ptr, 0, 0, width, height, - WLR_EDGE_LEFT | WLR_EDGE_TOP | WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); - if (NULL == decorations_ptr->margin_ptr) { - wlmaker_window_decorations_destroy(decorations_ptr); - return NULL; - } - - decorations_ptr->titlebar_ptr = wlmaker_decorations_titlebar_create( - decorations_ptr->wlr_scene_tree_ptr, width, view_ptr); - if (NULL == decorations_ptr->titlebar_ptr) { - wlmaker_window_decorations_destroy(decorations_ptr); - return NULL; - } - - decorations_ptr->resizebar_ptr = wlmaker_decorations_resizebar_create( - decorations_ptr->wlr_scene_tree_ptr, width, height, view_ptr); - if (NULL == decorations_ptr->resizebar_ptr) { - wlmaker_window_decorations_destroy(decorations_ptr); - return NULL; - } - - - return decorations_ptr; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_window_decorations_destroy( - wlmaker_window_decorations_t *decorations_ptr) -{ - if (NULL != decorations_ptr->resizebar_ptr) { - wlmaker_decorations_resizebar_destroy(decorations_ptr->resizebar_ptr); - decorations_ptr->resizebar_ptr = NULL; - } - - if (NULL != decorations_ptr->titlebar_ptr) { - wlmaker_decorations_titlebar_destroy(decorations_ptr->titlebar_ptr); - decorations_ptr->titlebar_ptr = NULL; - } - - if (NULL != decorations_ptr->margin_ptr) { - wlmaker_decorations_margin_destroy(decorations_ptr->margin_ptr); - decorations_ptr->margin_ptr = NULL; - } - - if (NULL != decorations_ptr->wlr_scene_tree_ptr) { - wlr_scene_node_destroy(&decorations_ptr->wlr_scene_tree_ptr->node); - decorations_ptr->wlr_scene_tree_ptr = NULL; - } - - free(decorations_ptr); -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_window_decorations_set_inner_size( - wlmaker_window_decorations_t *decorations_ptr, - uint32_t width, - uint32_t height) -{ - if (NULL != decorations_ptr->margin_ptr) { - wlmaker_decorations_margin_set_size( - decorations_ptr->margin_ptr, width, height); - } - - if (NULL != decorations_ptr->titlebar_ptr) { - wlmaker_decorations_titlebar_set_width( - decorations_ptr->titlebar_ptr, width); - } - - if (NULL != decorations_ptr->resizebar_ptr) { - wlmaker_decorations_resizebar_set_size( - decorations_ptr->resizebar_ptr, width, height); - } -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_window_decorations_get_added_size( - wlmaker_window_decorations_t *decorations_ptr, - uint32_t *width_ptr, - uint32_t *height_ptr) -{ - if (NULL != width_ptr) { - *width_ptr = 2 * wlmaker_config_theme.window_margin_width; - } - - if (NULL != height_ptr) { - *height_ptr = 2 * wlmaker_config_theme.window_margin_width; - if (NULL != decorations_ptr->titlebar_ptr) { - *height_ptr += wlmaker_decorations_titlebar_get_height( - decorations_ptr->titlebar_ptr); - } - - if (NULL != decorations_ptr->resizebar_ptr) { - *height_ptr += wlmaker_decorations_resizebar_get_height( - decorations_ptr->resizebar_ptr); - } - } -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_window_decorations_relative_position( - wlmaker_window_decorations_t *decorations_ptr, - int *relx_ptr, - int *rely_ptr) -{ - if (NULL != relx_ptr) { - *relx_ptr = -wlmaker_config_theme.window_margin_width; - } - - if (NULL != rely_ptr) { - *rely_ptr = -wlmaker_config_theme.window_margin_width; - if (NULL != decorations_ptr->titlebar_ptr) { - *rely_ptr -= wlmaker_decorations_titlebar_get_height( - decorations_ptr->titlebar_ptr); - } - } -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_window_decorations_update_title( - wlmaker_window_decorations_t *decorations_ptr) -{ - if (NULL != decorations_ptr->titlebar_ptr) { - wlmaker_decorations_titlebar_update_title( - decorations_ptr->titlebar_ptr); - } -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_window_decorations_set_shade( - wlmaker_window_decorations_t *decorations_ptr, - bool shaded) -{ - if (shaded && NULL != decorations_ptr->resizebar_ptr) { - wlmaker_decorations_resizebar_destroy(decorations_ptr->resizebar_ptr); - decorations_ptr->resizebar_ptr = NULL; - } - - if (!shaded && NULL == decorations_ptr->resizebar_ptr) { - uint32_t width, height; - decorations_ptr->view_ptr->impl_ptr->get_size( - decorations_ptr->view_ptr, &width, &height); - decorations_ptr->resizebar_ptr = wlmaker_decorations_resizebar_create( - decorations_ptr->wlr_scene_tree_ptr, - width, height, - decorations_ptr->view_ptr); - } - - wlmaker_decorations_margin_set_edges( - decorations_ptr->margin_ptr, - shaded ? - WLR_EDGE_TOP : - WLR_EDGE_LEFT | WLR_EDGE_TOP | WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM); -} - -/* == End of window_decorations.c ========================================== */ diff --git a/src/decorations/window_decorations.h b/src/decorations/window_decorations.h deleted file mode 100644 index 5c874130..00000000 --- a/src/decorations/window_decorations.h +++ /dev/null @@ -1,125 +0,0 @@ -/* ========================================================================= */ -/** - * @file window_decorations.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __WINDOW_DECORATIONS_H__ -#define __WINDOW_DECORATIONS_H__ - -/** Forward declaration: Handle for decorations for a window. */ -typedef struct _wlmaker_window_decorations_t wlmaker_window_decorations_t; - -#include "../view.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Creates window decorations for the provided window (view). - * - * Will create a margin, title bar and resize bar. Decorations should only - * be created when the view (1) has decorations enabled, (2) is mapped - * and (3) is not in fullscreen mode. - * - * => TODO: Take flags as to which elements are on. (resizing? - * menu bar elements?) - * - * @param view_ptr - * - * @return A handle for the window's decorations. Must be free'd by calling - * @ref wlmaker_window_decorations_destroy(). - */ -wlmaker_window_decorations_t *wlmaker_window_decorations_create( - wlmaker_view_t *view_ptr); - -/** - * Destroys the window decorations. - * - * @param decorations_ptr - */ -void wlmaker_window_decorations_destroy( - wlmaker_window_decorations_t *decorations_ptr); - -/** - * Sets (or updates) the size of the decorated (inner) window. - * - * `width` and `height` are specifying the dimensions of the decorated window, - * ie. without the added size of the decorations. - * - * @param decorations_ptr - * @param width - * @param height - */ -void wlmaker_window_decorations_set_inner_size( - wlmaker_window_decorations_t *decorations_ptr, - uint32_t width, - uint32_t height); - -/** - * Retrieves the size added by the decoration. - * - * @param decorations_ptr - * @param width_ptr - * @param height_ptr - */ -void wlmaker_window_decorations_get_added_size( - wlmaker_window_decorations_t *decorations_ptr, - uint32_t *width_ptr, - uint32_t *height_ptr); - -/** - * Returns the relative position of the decoration to the inner window. - * - * The top-left corner of the decoration of an inner window is placed at - * `x-position of inner window` plus `*relx_ptr`. Same for Y position. - * - * @param decorations_ptr - * @param relx_ptr - * @param rely_ptr - */ -void wlmaker_window_decorations_relative_position( - wlmaker_window_decorations_t *decorations_ptr, - int *relx_ptr, - int *rely_ptr); - -/** - * Updates the title used for the windo decoration. Wraps to titlebar. - * - * @param decorations_ptr - */ -void wlmaker_window_decorations_update_title( - wlmaker_window_decorations_t *decorations_ptr); - -/** - * Sets the "shade" status for decorations. When shaded, the resizebar is - * hidden. - * - * @param decorations_ptr - * @param shaded - */ -void wlmaker_window_decorations_set_shade( - wlmaker_window_decorations_t *decorations_ptr, - bool shaded); - - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __WINDOW_DECORATIONS_H__ */ -/* == End of window_decorations.h ========================================== */ diff --git a/src/resizebar.c b/src/resizebar.c deleted file mode 100644 index 5bbb414c..00000000 --- a/src/resizebar.c +++ /dev/null @@ -1,273 +0,0 @@ -/* ========================================================================= */ -/** - * @file resizebar.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "resizebar.h" - -#include -#include - -#define WLR_USE_UNSTABLE -#include -#undef WLR_USE_UNSTABLE - -/* == Declarations ========================================================= */ - -/** State of an interactive resizebar element. */ -typedef struct { - /** The interactive (parent structure). */ - wlmaker_interactive_t interactive; - - /** Back-link to the view. */ - wlmaker_view_t *view_ptr; - /** Texture of the resize bar, not pressed. */ - struct wlr_buffer *resizebar_buffer_ptr; - /** Texture of the resize bar, pressed. */ - struct wlr_buffer *resizebar_pressed_buffer_ptr; - /** Which edges will be controlled by this element. */ - uint32_t edges; - - /** Status of the element. */ - bool pressed; -} wlmaker_resizebar_t; - -static wlmaker_resizebar_t *resizebar_from_interactive( - wlmaker_interactive_t *interactive_ptr); - -static void _resizebar_enter( - wlmaker_interactive_t *interactive_ptr); -static void _resizebar_leave( - wlmaker_interactive_t *interactive_ptr); -static void _resizebar_motion( - wlmaker_interactive_t *interactive_ptr, - double x, - double y); -static void _resizebar_button( - wlmaker_interactive_t *interactive_ptr, - double x, double y, - struct wlr_pointer_button_event *wlr_pointer_button_event_ptr); -static void _resizebar_destroy(wlmaker_interactive_t *interactive_ptr); - -/* == Data ================================================================= */ - -/** Implementation: callbacks for the interactive. */ -static const wlmaker_interactive_impl_t wlmaker_interactive_resizebar_impl = { - .enter = _resizebar_enter, - .leave = _resizebar_leave, - .motion = _resizebar_motion, - .button = _resizebar_button, - .destroy = _resizebar_destroy -}; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmaker_interactive_t *wlmaker_resizebar_create( - struct wlr_scene_buffer *wlr_scene_buffer_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *resizebar_buffer_ptr, - struct wlr_buffer *resizebar_pressed_buffer_ptr, - uint32_t edges) -{ - wlmaker_resizebar_t *resizebar_ptr = logged_calloc( - 1, sizeof(wlmaker_resizebar_t)); - if (NULL == resizebar_ptr) return NULL; - resizebar_ptr->view_ptr = view_ptr; - resizebar_ptr->resizebar_buffer_ptr = - wlr_buffer_lock(resizebar_buffer_ptr); - resizebar_ptr->resizebar_pressed_buffer_ptr = - wlr_buffer_lock(resizebar_pressed_buffer_ptr); - resizebar_ptr->edges = edges; - - wlmaker_interactive_init( - &resizebar_ptr->interactive, - &wlmaker_interactive_resizebar_impl, - wlr_scene_buffer_ptr, - cursor_ptr, - resizebar_buffer_ptr); - - return &resizebar_ptr->interactive; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_resizebar_set_textures( - wlmaker_interactive_t *interactive_ptr, - struct wlr_buffer *resizebar_buffer_ptr, - struct wlr_buffer *resizebar_pressed_buffer_ptr) -{ - wlmaker_resizebar_t *resizebar_ptr = resizebar_from_interactive( - interactive_ptr); - - // This only updates the internal references... - wlr_buffer_unlock(resizebar_ptr->resizebar_buffer_ptr); - resizebar_ptr->resizebar_buffer_ptr = - wlr_buffer_lock(resizebar_buffer_ptr); - wlr_buffer_unlock(resizebar_ptr->resizebar_pressed_buffer_ptr); - resizebar_ptr->resizebar_pressed_buffer_ptr = - wlr_buffer_lock(resizebar_pressed_buffer_ptr); - - // ... and we also need to set the current texture in appropriate state. - wlmaker_interactive_set_texture( - interactive_ptr, - resizebar_ptr->pressed ? - resizebar_ptr->resizebar_pressed_buffer_ptr : - resizebar_ptr->resizebar_buffer_ptr); -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** - * Cast (with assertion) |interactive_ptr| to the |wlmaker_resizebar_t|. - * - * @param interactive_ptr - */ -wlmaker_resizebar_t *resizebar_from_interactive( - wlmaker_interactive_t *interactive_ptr) -{ - if (NULL != interactive_ptr && - interactive_ptr->impl != &wlmaker_interactive_resizebar_impl) { - bs_log(BS_FATAL, "Not a resizebar: %p", interactive_ptr); - abort(); - } - return (wlmaker_resizebar_t*)interactive_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Cursor enters the resizebar area. - * - * @param interactive_ptr - */ -void _resizebar_enter( - wlmaker_interactive_t *interactive_ptr) -{ - wlmaker_resizebar_t *resizebar_ptr = resizebar_from_interactive( - interactive_ptr); - - const char *xcursor_name_ptr = "left_ptr"; // Default. - if (resizebar_ptr->edges == WLR_EDGE_BOTTOM) { - xcursor_name_ptr = "s-resize"; - } else if (resizebar_ptr->edges == (WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT)) { - xcursor_name_ptr = "se-resize"; - } else if (resizebar_ptr->edges == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) { - xcursor_name_ptr = "sw-resize"; - } - - wlr_cursor_set_xcursor( - interactive_ptr->cursor_ptr->wlr_cursor_ptr, - interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - xcursor_name_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Cursor leaves the resizebar area. - * - * @param interactive_ptr - */ -void _resizebar_leave( - __UNUSED__ wlmaker_interactive_t *interactive_ptr) -{ - // Nothing to do. -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Cursor motion in the resizebar area. - * - * - * @param interactive_ptr - * @param x - * @param y - */ -void _resizebar_motion( - __UNUSED__ wlmaker_interactive_t *interactive_ptr, - __UNUSED__ double x, - __UNUSED__ double y) -{ - // Nothing to do. -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Handle cursor button, ie. button press or release. - * - * @param interactive_ptr - * @param x - * @param y - * @param wlr_pointer_button_event_ptr - */ -void _resizebar_button( - wlmaker_interactive_t *interactive_ptr, - double x, double y, - struct wlr_pointer_button_event *wlr_pointer_button_event_ptr) -{ - wlmaker_resizebar_t *resizebar_ptr = resizebar_from_interactive( - interactive_ptr); - - if (wlr_pointer_button_event_ptr->button != BTN_LEFT) return; - switch (wlr_pointer_button_event_ptr->state) { - case WLR_BUTTON_PRESSED: - if (wlmaker_interactive_contains(&resizebar_ptr->interactive, x, y)) { - resizebar_ptr->pressed = true; - } - break; - - case WLR_BUTTON_RELEASED: - resizebar_ptr->pressed = false; - break; - - default: - /* huh, that's unexpected... */ - break; - } - - wlmaker_interactive_set_texture( - interactive_ptr, - resizebar_ptr->pressed ? - resizebar_ptr->resizebar_pressed_buffer_ptr : - resizebar_ptr->resizebar_buffer_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Destroys resizebar interactive. - * - * @param interactive_ptr - */ -void _resizebar_destroy(wlmaker_interactive_t *interactive_ptr) -{ - wlmaker_resizebar_t *resizebar_ptr = resizebar_from_interactive( - interactive_ptr); - - if (NULL != resizebar_ptr->resizebar_buffer_ptr) { - wlr_buffer_unlock(resizebar_ptr->resizebar_buffer_ptr); - resizebar_ptr->resizebar_buffer_ptr = NULL; - } - if (NULL != resizebar_ptr->resizebar_pressed_buffer_ptr) { - wlr_buffer_unlock(resizebar_ptr->resizebar_pressed_buffer_ptr); - resizebar_ptr->resizebar_pressed_buffer_ptr = NULL; - } - - free(resizebar_ptr); -} - -/* == End of resizebar.c =================================================== */ diff --git a/src/resizebar.h b/src/resizebar.h deleted file mode 100644 index 8e16021e..00000000 --- a/src/resizebar.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ========================================================================= */ -/** - * @file resizebar.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __RESIZEBAR_H__ -#define __RESIZEBAR_H__ - -#include "cursor.h" -#include "interactive.h" - -#define WLR_USE_UNSTABLE -#include -#include -#undef WLR_USE_UNSTABLE - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Creates a resizebar interactive. - * - * @param wlr_scene_buffer_ptr Buffer scene node to contain the button. - * @param cursor_ptr Cursor. Must outlive the resizebar. - * @param view_ptr View owning the resizebar. Must outlive this. - * @param resizebar_buffer_ptr WLR buffer, resize bar texture. This resizebar - * interactive will hold a consumer lock on it. - * @param resizebar_pressed_buffer_ptr WLR buffer, resize bar texture when - * pressed. - * @param edges Edges that are controlled by this element. - * - * @return A pointer to the interactive. Must be destroyed via - * |_resizebar_destroy|. - */ -wlmaker_interactive_t *wlmaker_resizebar_create( - struct wlr_scene_buffer *wlr_scene_buffer_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *resizebar_buffer_ptr, - struct wlr_buffer *resizebar_pressed_buffer_ptr, - uint32_t edges); - -/** - * Sets (replaces) the textures for the resizebar interactive. - * - * @param interactive_ptr - * @param resizebar_buffer_ptr WLR buffer, resize bar texture. This resizebar - * interactive will hold a consumer lock on it. - * @param resizebar_pressed_buffer_ptr WLR buffer, resize bar texture when - * pressed. - */ -void wlmaker_resizebar_set_textures( - wlmaker_interactive_t *interactive_ptr, - struct wlr_buffer *resizebar_buffer_ptr, - struct wlr_buffer *resizebar_pressed_buffer_ptr); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __RESIZEBAR_H__ */ -/* == End of resizebar.h =================================================== */ diff --git a/src/titlebar.c b/src/titlebar.c deleted file mode 100644 index 99395349..00000000 --- a/src/titlebar.c +++ /dev/null @@ -1,340 +0,0 @@ -/* ========================================================================= */ -/** - * @file titlebar.c - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "config.h" -#include "titlebar.h" - -#include -#include - -#define WLR_USE_UNSTABLE -#include -#include -#undef WLR_USE_UNSTABLE - -/* == Declarations ========================================================= */ - -/** Titlebar state, with respect to moves. */ -typedef enum { - /** Idle */ - TITLEBAR_IDLE, - /** Clicked, waiting to initiate move. */ - TITLEBAR_CLICKED, - /** Actively moving. */ - TITLEBAR_MOVING -} titlebar_state_t; - -/** State of the interactive titlebar. */ -typedef struct { - /** The interactive (parent structure). */ - wlmaker_interactive_t interactive; - - /** Back-link to the view owning this titlebar. */ - wlmaker_view_t *view_ptr; - - /** WLR buffer, contains texture for the title bar when focussed. */ - struct wlr_buffer *titlebar_buffer_ptr; - /** WLR buffer, contains texture for the title bar when blurred. */ - struct wlr_buffer *titlebar_blurred_buffer_ptr; - - /** Titlebar state. */ - titlebar_state_t state; - /** X-Position of where the click happened. */ - double clicked_x; - /** Y-Position of where the click happened. */ - double clicked_y; - - /** Nanosecond of last mouse-click, to catch double-clicks. */ - uint64_t last_click_nsec; -} wlmaker_titlebar_t; - -static wlmaker_titlebar_t *titlebar_from_interactive( - wlmaker_interactive_t *interactive_ptr); - -static void _titlebar_enter( - wlmaker_interactive_t *interactive_ptr); -static void _titlebar_leave( - wlmaker_interactive_t *interactive_ptr); -static void _titlebar_motion( - wlmaker_interactive_t *interactive_ptr, - double x, double y); -static void _titlebar_focus( - wlmaker_interactive_t *interactive_ptr); -static void _titlebar_button( - wlmaker_interactive_t *interactive_ptr, - double x, double y, - struct wlr_pointer_button_event *wlr_pointer_button_event_ptr); -static void _titlebar_destroy( - wlmaker_interactive_t *interactive_ptr); - -/* == Data ================================================================= */ - -/** Implementation: callbacks for the interactive. */ -static const wlmaker_interactive_impl_t wlmaker_interactive_titlebar_impl = { - .enter = _titlebar_enter, - .leave = _titlebar_leave, - .motion = _titlebar_motion, - .focus = _titlebar_focus, - .button = _titlebar_button, - .destroy = _titlebar_destroy -}; - -/** Default xcursor to use. */ -static const char *xcursor_name_default = "left_ptr"; -/** Xcursor to show when in MOVING state. */ -static const char *xcursor_name_move = "move"; -/** Minimum cursor move to enable MOVING afer CLICKED. */ -static const double minimal_move = 2; - -/* == Exported methods ===================================================== */ - -/* ------------------------------------------------------------------------- */ -wlmaker_interactive_t *wlmaker_titlebar_create( - struct wlr_scene_buffer *wlr_scene_buffer_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *titlebar_buffer_ptr, - struct wlr_buffer *titlebar_blurred_buffer_ptr) -{ - wlmaker_titlebar_t *titlebar_ptr = logged_calloc( - 1, sizeof(wlmaker_titlebar_t)); - if (NULL == titlebar_ptr) return NULL; - titlebar_ptr->view_ptr = view_ptr; - titlebar_ptr->titlebar_buffer_ptr = wlr_buffer_lock(titlebar_buffer_ptr); - titlebar_ptr->titlebar_blurred_buffer_ptr = - wlr_buffer_lock(titlebar_blurred_buffer_ptr); - titlebar_ptr->state = TITLEBAR_IDLE; - - wlmaker_interactive_init( - &titlebar_ptr->interactive, - &wlmaker_interactive_titlebar_impl, - wlr_scene_buffer_ptr, - cursor_ptr, - titlebar_buffer_ptr); - - return &titlebar_ptr->interactive; -} - -/* ------------------------------------------------------------------------- */ -void wlmaker_title_set_texture( - wlmaker_interactive_t *interactive_ptr, - struct wlr_buffer *titlebar_buffer_ptr, - struct wlr_buffer *titlebar_blurred_buffer_ptr) -{ - wlmaker_titlebar_t *titlebar_ptr = titlebar_from_interactive( - interactive_ptr); - wlr_buffer_unlock(titlebar_ptr->titlebar_buffer_ptr); - wlr_buffer_unlock(titlebar_ptr->titlebar_blurred_buffer_ptr); - titlebar_ptr->titlebar_buffer_ptr = wlr_buffer_lock(titlebar_buffer_ptr); - titlebar_ptr->titlebar_blurred_buffer_ptr = - wlr_buffer_lock(titlebar_blurred_buffer_ptr); - wlmaker_interactive_set_texture( - interactive_ptr, - interactive_ptr->focussed ? - titlebar_ptr->titlebar_buffer_ptr : - titlebar_ptr->titlebar_blurred_buffer_ptr); -} - -/* == Local (static) methods =============================================== */ - -/* ------------------------------------------------------------------------- */ -/** - * Cast (with assertion) |interactive_ptr| to the |wlmaker_titlebar_t|. - * - * @param interactive_ptr - */ -wlmaker_titlebar_t *titlebar_from_interactive( - wlmaker_interactive_t *interactive_ptr) -{ - if (NULL != interactive_ptr && - interactive_ptr->impl != &wlmaker_interactive_titlebar_impl) { - bs_log(BS_FATAL, "Not a titlebar: %p", interactive_ptr); - abort(); - } - return (wlmaker_titlebar_t*)interactive_ptr; -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Cursor enters the button area. - * - * @param interactive_ptr - */ -void _titlebar_enter(wlmaker_interactive_t *interactive_ptr) -{ - wlmaker_titlebar_t *titlebar_ptr = titlebar_from_interactive( - interactive_ptr); - - const char *cursor_name_ptr = xcursor_name_default; - if (titlebar_ptr->state == TITLEBAR_MOVING) { - cursor_name_ptr = xcursor_name_move; - } - - wlr_cursor_set_xcursor( - interactive_ptr->cursor_ptr->wlr_cursor_ptr, - interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - cursor_name_ptr); -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Cursor leaves the button area. - * - * @param interactive_ptr - */ -void _titlebar_leave(__UNUSED__ wlmaker_interactive_t *interactive_ptr) -{ - // Nothing to do. -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Handle cursor motion. - * - * @param interactive_ptr - * @param x - * @param y - */ -void _titlebar_motion( - wlmaker_interactive_t *interactive_ptr, - double x, double y) -{ - wlmaker_titlebar_t *titlebar_ptr = titlebar_from_interactive( - interactive_ptr); - - if (titlebar_ptr->state == TITLEBAR_CLICKED && - (fabs(titlebar_ptr->clicked_x - x) > minimal_move || - fabs(titlebar_ptr->clicked_y - y) > minimal_move)) { - titlebar_ptr->state = TITLEBAR_MOVING; - - wlr_cursor_set_xcursor( - interactive_ptr->cursor_ptr->wlr_cursor_ptr, - interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - xcursor_name_move); - } -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Focus state changes. - * - * @param interactive_ptr - */ -static void _titlebar_focus(wlmaker_interactive_t *interactive_ptr) -{ - wlmaker_titlebar_t *titlebar_ptr = titlebar_from_interactive( - interactive_ptr); - - wlmaker_interactive_set_texture( - interactive_ptr, - interactive_ptr->focussed ? - titlebar_ptr->titlebar_buffer_ptr : - titlebar_ptr->titlebar_blurred_buffer_ptr); - if (!interactive_ptr->focussed) { - titlebar_ptr->state = TITLEBAR_IDLE; - } -} - -/* ------------------------------------------------------------------------- */ -/** - * Interactive callback: Handle cursor button, ie. button press or release. - * - * @param interactive_ptr - * @param x - * @param y - * @param wlr_pointer_button_event_ptr - */ -void _titlebar_button( - wlmaker_interactive_t *interactive_ptr, - double x, - double y, - __UNUSED__ struct wlr_pointer_button_event *wlr_pointer_button_event_ptr) -{ - wlmaker_titlebar_t *titlebar_ptr = titlebar_from_interactive( - interactive_ptr); - uint64_t now_nsec; - - if (wlr_pointer_button_event_ptr->button == BTN_RIGHT && - wlr_pointer_button_event_ptr->state == WLR_BUTTON_PRESSED) { - wlmaker_view_window_menu_show(titlebar_ptr->view_ptr); - } - - if (wlr_pointer_button_event_ptr->button != BTN_LEFT) return; - - switch (wlr_pointer_button_event_ptr->state) { - case WLR_BUTTON_PRESSED: - now_nsec = bs_mono_nsec(); - if (now_nsec - titlebar_ptr->last_click_nsec < - wlmaker_config_double_click_wait_msec * 1000000ull) { - // two clicks! will take it! - titlebar_ptr->state = TITLEBAR_IDLE; - wlmaker_view_shade(titlebar_ptr->view_ptr); - break; - } - - if (titlebar_ptr->state == TITLEBAR_IDLE) { - titlebar_ptr->state = TITLEBAR_CLICKED; - titlebar_ptr->clicked_x = x; - titlebar_ptr->clicked_y = y; - } - titlebar_ptr->last_click_nsec = now_nsec; - break; - - case WLR_BUTTON_RELEASED: - titlebar_ptr->state = TITLEBAR_IDLE; - // Reset cursor to default, if it is within our bounds. - if (wlmaker_interactive_contains(&titlebar_ptr->interactive, x, y)) { - wlr_cursor_set_xcursor( - interactive_ptr->cursor_ptr->wlr_cursor_ptr, - interactive_ptr->cursor_ptr->wlr_xcursor_manager_ptr, - xcursor_name_default); - } - break; - - default: - /* huh, that's unexpected... */ - break; - } -} - -/* ------------------------------------------------------------------------- */ -/** - * Destroys the titlebar interactive. - * - * @param interactive_ptr - */ -void _titlebar_destroy( - wlmaker_interactive_t *interactive_ptr) -{ - wlmaker_titlebar_t *titlebar_ptr = titlebar_from_interactive( - interactive_ptr); - - if (NULL != titlebar_ptr->titlebar_buffer_ptr) { - wlr_buffer_unlock(titlebar_ptr->titlebar_buffer_ptr); - titlebar_ptr->titlebar_buffer_ptr = NULL; - } - if (NULL != titlebar_ptr->titlebar_blurred_buffer_ptr) { - wlr_buffer_unlock(titlebar_ptr->titlebar_blurred_buffer_ptr); - titlebar_ptr->titlebar_blurred_buffer_ptr = NULL; - } - free(titlebar_ptr); -} - -/* == End of titlebar.c ==================================================== */ diff --git a/src/titlebar.h b/src/titlebar.h deleted file mode 100644 index 2f44017d..00000000 --- a/src/titlebar.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ========================================================================= */ -/** - * @file titlebar.h - * - * @copyright - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __TITLEBAR_H__ -#define __TITLEBAR_H__ - -#include "cursor.h" -#include "interactive.h" - -#define WLR_USE_UNSTABLE -#include -#include -#undef WLR_USE_UNSTABLE - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Creates a titlebar interactive. - * - * @param wlr_scene_buffer_ptr Buffer scene node to contain the button. - * @param cursor_ptr Cursor. Must outlive the titlebar. - * @param view_ptr View owning the titlebar. Must outlive titlebar. - * @param titlebar_buffer_ptr WLR buffer, title bar texture when focussed. This - * titlebar interactive will hold a consumer lock on - * it. - * @param titlebar_blurred_buffer_ptr WLR buffer, texture when blurred. This - * titlebar interactive will hold a consumer lock. - * - * @return A pointer to the interactive. Must be destroyed via - * |_titlebar_destroy|. - */ -wlmaker_interactive_t *wlmaker_titlebar_create( - struct wlr_scene_buffer *wlr_scene_buffer_ptr, - wlmaker_cursor_t *cursor_ptr, - wlmaker_view_t *view_ptr, - struct wlr_buffer *titlebar_buffer_ptr, - struct wlr_buffer *titlebar_blurred_buffer_ptr); - -/** - * Sets (replaces) the texture for the titlebar interactive. - * - * @param interactive_ptr - * @param titlebar_buffer_ptr - * @param titlebar_blurred_buffer_ptr - */ -void wlmaker_title_set_texture( - wlmaker_interactive_t *interactive_ptr, - struct wlr_buffer *titlebar_buffer_ptr, - struct wlr_buffer *titlebar_blurred_buffer_ptr); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif /* __TITLEBAR_H__ */ -/* == End of titlebar.h ==================================================== */ diff --git a/src/view.c b/src/view.c index dc7ec88b..ea8b270e 100644 --- a/src/view.c +++ b/src/view.c @@ -24,8 +24,6 @@ #include "config.h" #include "decorations.h" #include "menu.h" -#include "resizebar.h" -#include "titlebar.h" #include "toolkit/toolkit.h" #include @@ -51,8 +49,6 @@ static void window_menu_callback_move_to_workspace1(void *ud_ptr); static void window_menu_callback_move_to_workspace2(void *ud_ptr); static void window_menu_callback_close(void *ud_ptr); -static void wlmaker_view_apply_decoration(wlmaker_view_t *view_ptr); - /* == Data ================================================================= */ /** Descriptors for the menu entries of the view's "Window menu". */ @@ -154,11 +150,6 @@ void wlmaker_view_fini(wlmaker_view_t *view_ptr) view_ptr->interactive_tree_ptr = NULL; } - if (NULL != view_ptr->window_decorations_ptr) { - wlmaker_window_decorations_destroy(view_ptr->window_decorations_ptr); - view_ptr->window_decorations_ptr = NULL; - } - if (NULL != view_ptr->elements_wlr_scene_tree_ptr) { wlr_scene_node_destroy(&view_ptr->elements_wlr_scene_tree_ptr->node); view_ptr->elements_wlr_scene_tree_ptr = NULL; @@ -339,17 +330,6 @@ void wlmaker_view_handle_axis( } } -/* ------------------------------------------------------------------------- */ -void wlmaker_view_set_server_side_decoration( - wlmaker_view_t *view_ptr, - bool enabled) -{ - // Don't act if there's nothing to do... - if (view_ptr->server_side_decoration_enabled == enabled) return; - view_ptr->server_side_decoration_enabled = enabled; - wlmaker_view_apply_decoration(view_ptr); -} - /* ------------------------------------------------------------------------- */ void wlmaker_view_window_menu_show(wlmaker_view_t *view_ptr) { @@ -444,21 +424,10 @@ void wlmaker_view_cursor_leave(wlmaker_view_t *view_ptr) } /* ------------------------------------------------------------------------- */ -void wlmaker_view_shade(wlmaker_view_t *view_ptr) +void wlmaker_view_shade(__UNUSED__ wlmaker_view_t *view_ptr) { - if (!view_ptr->server_side_decorated) { - bs_log(BS_INFO, "Shade only available when server-side-decorated."); - return; - } - BS_ASSERT(NULL != view_ptr->view_wlr_scene_tree_ptr); - - view_ptr->shaded ^= true; - wlr_scene_node_set_enabled( - &view_ptr->view_wlr_scene_tree_ptr->node, !view_ptr->shaded); - if (NULL != view_ptr->window_decorations_ptr) { - wlmaker_window_decorations_set_shade( - view_ptr->window_decorations_ptr, view_ptr->shaded); - } + bs_log(BS_INFO, "Shade only available when server-side-decorated."); + return; } /* ------------------------------------------------------------------------- */ @@ -467,19 +436,6 @@ void wlmaker_view_get_size(wlmaker_view_t *view_ptr, uint32_t *height_ptr) { view_ptr->impl_ptr->get_size(view_ptr, width_ptr, height_ptr); - if (view_ptr->server_side_decorated) { - if (NULL != view_ptr->window_decorations_ptr) { - uint32_t deco_width, deco_height; - wlmaker_window_decorations_get_added_size( - view_ptr->window_decorations_ptr, &deco_width, &deco_height); - if (NULL != width_ptr) { - *width_ptr += deco_width; - } - if (NULL != height_ptr) { - *height_ptr += deco_height; - } - } - } } /* ------------------------------------------------------------------------- */ @@ -488,21 +444,6 @@ void wlmaker_view_set_size(wlmaker_view_t *view_ptr, int width, int height) width = BS_MAX(1, width); height = BS_MAX(1, height); - if (view_ptr->server_side_decorated) { - BS_ASSERT(NULL != view_ptr->window_decorations_ptr); - - uint32_t deco_width, deco_height; - wlmaker_window_decorations_get_added_size( - view_ptr->window_decorations_ptr, &deco_width, &deco_height); - width -= deco_width; - height -= deco_height; - - width = BS_MAX(1, width); - height = BS_MAX(1, height); - - wlmaker_window_decorations_set_inner_size( - view_ptr->window_decorations_ptr, width, height); - } view_ptr->impl_ptr->set_size(view_ptr, width, height); } @@ -512,30 +453,12 @@ void wlmaker_view_get_position(wlmaker_view_t *view_ptr, { *x_ptr = view_ptr->elements_wlr_scene_tree_ptr->node.x; *y_ptr = view_ptr->elements_wlr_scene_tree_ptr->node.y; - - if (NULL != view_ptr->window_decorations_ptr) { - int relx, rely; - wlmaker_window_decorations_relative_position( - view_ptr->window_decorations_ptr, &relx, &rely); - *x_ptr += relx; - *y_ptr += rely; - } } /* ------------------------------------------------------------------------- */ void wlmaker_view_set_position(wlmaker_view_t *view_ptr, int x, int y) { - if (NULL != view_ptr->window_decorations_ptr) { - // Adjust position by the top-left decoration elements, since the node - // position does not factor in these. - int relx, rely; - wlmaker_window_decorations_relative_position( - view_ptr->window_decorations_ptr, &relx, &rely); - x -= relx; - y -= rely; - } - if (x != view_ptr->elements_wlr_scene_tree_ptr->node.x || y != view_ptr->elements_wlr_scene_tree_ptr->node.y) { wlr_scene_node_set_position( @@ -612,7 +535,6 @@ void wlmaker_view_set_fullscreen(wlmaker_view_t *view_ptr, bool fullscreen) wlmaker_workspace_demote_view_from_fullscreen( view_ptr->workspace_ptr, view_ptr); } - wlmaker_view_apply_decoration(view_ptr); wlmaker_view_set_position(view_ptr, new_box.x, new_box.y); wlmaker_view_set_size(view_ptr, new_box.width, new_box.height); @@ -646,11 +568,6 @@ void wlmaker_view_set_title(wlmaker_view_t *view_ptr, const char *title_ptr) if (NULL != title_ptr) { view_ptr->title_ptr = logged_strdup(title_ptr); } - - if (NULL != view_ptr->window_decorations_ptr) { - wlmaker_window_decorations_update_title( - view_ptr->window_decorations_ptr); - } } /* ------------------------------------------------------------------------- */ @@ -692,7 +609,6 @@ void wlmaker_view_map(wlmaker_view_t *view_ptr, view_ptr->workspace_ptr, view_ptr, layer); - wlmaker_view_apply_decoration(view_ptr); wl_signal_emit(&view_ptr->server_ptr->view_mapped_event, view_ptr); } @@ -703,7 +619,6 @@ void wlmaker_view_unmap(wlmaker_view_t *view_ptr) BS_ASSERT(NULL != view_ptr->workspace_ptr); // Should be mapped. wlmaker_workspace_remove_view(view_ptr->workspace_ptr, view_ptr); view_ptr->workspace_ptr = NULL; - wlmaker_view_apply_decoration(view_ptr); wl_signal_emit(&view_ptr->server_ptr->view_unmapped_event, view_ptr); } @@ -896,44 +811,4 @@ void window_menu_callback_close(void *ud_ptr) view_ptr->send_close_callback(view_ptr); } -/* ------------------------------------------------------------------------- */ -/** - * Apply server-side decoration, if view is configured and in suitable state. - * - * Will set `wlmaker_view_t.server_side_decorated` suitably. - * - * @param view_ptr - */ -void wlmaker_view_apply_decoration(wlmaker_view_t *view_ptr) -{ - // We won't have the view decorated if it's (1) disabled, (2) unmapped, - // or (3) currently in fullscreen mode. - if ((!view_ptr->server_side_decoration_enabled) || - (NULL == view_ptr->workspace_ptr) || - view_ptr->fullscreen) { - - if (NULL != view_ptr->window_decorations_ptr) { - wlmaker_window_decorations_destroy( - view_ptr->window_decorations_ptr); - view_ptr->window_decorations_ptr = NULL; - } - view_ptr->server_side_decorated = false; - - return; - } - - // Store, then later: re-adjust position of the view. - int pos_x, pos_y; - wlmaker_view_get_position(view_ptr, &pos_x, &pos_y); - - // Well: Decoration is enabled, we're mapped, and not in fullscreen. There - // should be decoration elements... - view_ptr->window_decorations_ptr = wlmaker_window_decorations_create( - view_ptr); - BS_ASSERT(NULL != view_ptr->window_decorations_ptr); - view_ptr->server_side_decorated = true; - - wlmaker_view_set_position(view_ptr, pos_x, pos_y); -} - /* == End of view.c ======================================================== */ diff --git a/src/view.h b/src/view.h index 896d0069..30e33a77 100644 --- a/src/view.h +++ b/src/view.h @@ -63,8 +63,6 @@ typedef struct _wlmaker_view_t wlmaker_view_t; #include "server.h" #include "workspace.h" -#include "decorations/window_decorations.h" - #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -194,33 +192,6 @@ struct _wlmaker_view_t { /** Anchor of the view. */ uint32_t anchor; - /** - * Whether this view is configured to have server-side decoration. - * - * This value conforms to the result of the protocol negotiation of the - * "XDG Decoration" extension. The decoration may be enabled, but - * currently not visible -- for example, if the view is not mapped, or - * if the view is in fullscreen mode. - * - * See @ref server_side_decorated. - */ - bool server_side_decoration_enabled; - /** - * Whether this view is currently server-side decorated. - * - * Is true iff server-side decoration elements are currently visible. - * Implies that @ref server_side_decoration_enabled, that the view is - * currently mapped and not in fullscreen mode. - */ - bool server_side_decorated; - - /** - * All window decorations. Will be set only if decorations are enabled - * (@ref server_side_decoration_enabled), the view is mapped, - * and not currently in fullscreen mode. - */ - wlmaker_window_decorations_t *window_decorations_ptr; - /** Whether this view is currently active (focussed). */ bool active; /** @@ -407,19 +378,6 @@ void wlmaker_view_handle_axis( double y, struct wlr_pointer_axis_event *event_ptr); -/** - * Enables, respectively disables server-side decoration for the view. - * - * If the view is already mapped, this will trigger creation of the decoration - * elements. Otherwise, elements will be created when the view gets mapped. - * - * @param view_ptr - * @param enabled - */ -void wlmaker_view_set_server_side_decoration( - wlmaker_view_t *view_ptr, - bool enabled); - /** * Shows the "window menu" for this view. * diff --git a/src/xdg_decoration.c b/src/xdg_decoration.c index 56d65cc7..c3134a1c 100644 --- a/src/xdg_decoration.c +++ b/src/xdg_decoration.c @@ -218,10 +218,6 @@ void handle_decoration_request_mode( wlmaker_xdg_decoration_t *decoration_ptr = wl_container_of( listener_ptr, decoration_ptr, request_mode_listener); - struct wlr_scene_tree *wlr_scene_tree_ptr = (struct wlr_scene_tree*) - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; - wlmaker_view_t *view_ptr = (wlmaker_view_t*)wlr_scene_tree_ptr->node.data; - wlmtk_content_t *content_ptr = (wlmtk_content_t*) decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->data; @@ -274,22 +270,6 @@ void handle_decoration_request_mode( wlmtk_window_set_server_side_decorated( content_ptr->window_ptr, mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); - - } else { - - bs_log(BS_INFO, "XDG decoration request_mode for XDG surface %p, view %p: " - "Current %d, pending %d, scheduled %d, requested %d. Set: %d", - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->toplevel->base->surface, - view_ptr, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->current.mode, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->pending.mode, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->scheduled_mode, - decoration_ptr->wlr_xdg_toplevel_decoration_v1_ptr->requested_mode, - mode); - - wlmaker_view_set_server_side_decoration( - view_ptr, - mode != WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); } } From 63cac02a84e62516e11fded50467b74cbda64b05 Mon Sep 17 00:00:00 2001 From: Philipp Kaeser Date: Fri, 12 Jan 2024 17:07:32 +0200 Subject: [PATCH 390/390] Also removes the decorations dependency from the toplevel build file. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f597fb51..8eed6230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,6 @@ ADD_SUBDIRECTORY(icons) ADD_SUBDIRECTORY(protocols) ADD_SUBDIRECTORY(third_party/protocols) ADD_SUBDIRECTORY(src) -ADD_SUBDIRECTORY(src/decorations) ADD_SUBDIRECTORY(src/toolkit) # Adds submodules last, to permit checking on already-existing targets.