Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds a toplevel window menu, for both XDG and X11 windows. #155

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Support for visual effects to improve usability, but not for pure show.
* [done] Menu shown on right-button-down, items trigger on right-button-up.
* [done] When invoked on unclaimed button, exits menu on button release.
* [done] Available as window menu in windows.
* Available also for X11 windows.
* [done] Available also for X11 windows.
* Available as (hardcoded) application menu.
* Menu with submenus.
* Window menu adapting to window state.
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ SET(PUBLIC_HEADER_FILES
server.h
subprocess_monitor.h
task_list.h
tl_menu.h
xdg_decoration.h
xdg_popup.h
xdg_shell.h
Expand Down Expand Up @@ -66,6 +67,7 @@ TARGET_SOURCES(wlmaker_lib PRIVATE
server.c
subprocess_monitor.c
task_list.c
tl_menu.c
xdg_decoration.c
xdg_popup.c
xdg_shell.c
Expand Down
97 changes: 97 additions & 0 deletions src/tl_menu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* ========================================================================= */
/**
* @file tl_menu.c
*
* @copyright
* Copyright 2025 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 "tl_menu.h"

#include "action_item.h"

/* == Declarations ========================================================= */

/** State of a toplevel's window menu. */
struct _wlmaker_tl_menu_t {
/** Pointer to the window's @ref wlmtk_menu_t. */
wlmtk_menu_t *menu_ptr;
};

/** Temporary: Struct for defining an item for the window menu. */
typedef struct {
/** Text to use for the menu item. */
const char *text_ptr;
/** Action to be executed for that menu item. */
wlmaker_action_t action;
} wlmaker_window_menu_item_t;

/* == Data ================================================================= */
/** Menu items for the XDG toplevel's window menu. */
static const wlmaker_window_menu_item_t _xdg_toplevel_menu_items[] = {
{ "Maximize", WLMAKER_ACTION_WINDOW_MAXIMIZE },
{ "Unmaximize", WLMAKER_ACTION_WINDOW_UNMAXIMIZE },
{ "Fullscreen", WLMAKER_ACTION_WINDOW_TOGGLE_FULLSCREEN },
{ "Shade", WLMAKER_ACTION_WINDOW_SHADE },
{ "Unshade", WLMAKER_ACTION_WINDOW_UNSHADE },
{ "To prev. workspace", WLMAKER_ACTION_WINDOW_TO_PREVIOUS_WORKSPACE },
{ "To next workspace", WLMAKER_ACTION_WINDOW_TO_NEXT_WORKSPACE },
{ "Close", WLMAKER_ACTION_WINDOW_CLOSE },
{ NULL, 0 } // Sentinel.
};

/* == Exported methods ===================================================== */

/* ------------------------------------------------------------------------- */
wlmaker_tl_menu_t *wlmaker_tl_menu_create(
wlmtk_window_t *window_ptr,
wlmaker_server_t *server_ptr)
{
wlmaker_tl_menu_t *tl_menu_ptr = logged_calloc(
1, sizeof(wlmaker_tl_menu_t));
if (NULL == tl_menu_ptr) return NULL;
tl_menu_ptr->menu_ptr = wlmtk_window_menu(window_ptr);

for (const wlmaker_window_menu_item_t *i_ptr = &_xdg_toplevel_menu_items[0];
i_ptr->text_ptr != NULL;
++i_ptr) {

wlmaker_action_item_t *action_item_ptr = wlmaker_action_item_create(
i_ptr->text_ptr,
&server_ptr->style.menu.item,
i_ptr->action,
server_ptr,
server_ptr->env_ptr);
if (NULL == action_item_ptr) {
wlmaker_tl_menu_destroy(tl_menu_ptr);
return NULL;
}
wlmtk_menu_add_item(
tl_menu_ptr->menu_ptr,
wlmaker_action_item_menu_item(action_item_ptr));
}

return tl_menu_ptr;
}

/* ------------------------------------------------------------------------- */
void wlmaker_tl_menu_destroy(wlmaker_tl_menu_t *tl_menu_ptr)
{
free(tl_menu_ptr);
}

/* == Local (static) methods =============================================== */

/* == End of tl_menu.c ===================================================== */
58 changes: 58 additions & 0 deletions src/tl_menu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* ========================================================================= */
/**
* @file tl_menu.h
*
* @copyright
* Copyright 2025 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 __WLMAKER_TL_MENU_H__
#define __WLMAKER_TL_MENU_H__

#include "toolkit/toolkit.h"

#include "server.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

/** Forward declaration: State of a toplevel's menu. */
typedef struct _wlmaker_tl_menu_t wlmaker_tl_menu_t;

/**
* Creates a (window) menu for a toplevel (window).
*
* @param window_ptr
* @param server_ptr
*
* @return pointer to the toplevel's menu state or NULL on error.
*/
wlmaker_tl_menu_t *wlmaker_tl_menu_create(
wlmtk_window_t *window_ptr,
wlmaker_server_t *server_ptr);

/**
* Destroys the toplevel's menu.
*
* @param tl_menu_ptr
*/
void wlmaker_tl_menu_destroy(wlmaker_tl_menu_t *tl_menu_ptr);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif /* __TL_MENU_H__ */
/* == End of tl_menu.h ===================================================== */
8 changes: 6 additions & 2 deletions src/toolkit/content.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ bool wlmtk_content_init(
&content_ptr->super_container.super_element,
&_wlmtk_content_element_vmt);

wlmtk_content_set_element(content_ptr, element_ptr);

if (!wlmtk_container_init(&content_ptr->popup_container, env_ptr)) {
wlmtk_content_fini(content_ptr);
return false;
Expand All @@ -73,6 +71,8 @@ bool wlmtk_content_init(
&content_ptr->popup_container.super_element,
true);

wlmtk_content_set_element(content_ptr, element_ptr);

return true;
}

Expand Down Expand Up @@ -123,6 +123,10 @@ void wlmtk_content_set_element(
content_ptr->element_ptr = element_ptr;
wlmtk_element_set_visible(element_ptr, true);

// FIXME
wlmtk_container_raise_element_to_top(
&content_ptr->super_container,
&content_ptr->popup_container.super_element);
}
}

Expand Down
60 changes: 17 additions & 43 deletions src/xdg_toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include "xdg_shell.h"

#include "action_item.h"
#include "tl_menu.h"
#include "xdg_popup.h"

#include <wlr/version.h>
Expand All @@ -41,6 +41,9 @@ typedef struct {
/** The corresponding wlroots XDG toplevel. */
struct wlr_xdg_toplevel *wlr_xdg_toplevel_ptr;

/** The toplevel's window menu. */
wlmaker_tl_menu_t *tl_menu_ptr;

/** Listener for the `destroy` signal of the `wlr_xdg_toplevel::events`. */
struct wl_listener destroy_listener;
/** Listener for the `new_popup` signal of the `wlr_xdg_surface`. */
Expand Down Expand Up @@ -72,14 +75,6 @@ typedef struct {
struct wl_listener toplevel_set_app_id_listener;
} xdg_toplevel_surface_t;

/** Temporary: Struct for defining an item for the window menu. */
typedef struct {
/** Text to use for the menu item. */
const char *text_ptr;
/** Action to be executed for that menu item. */
wlmaker_action_t action;
} wlmaker_window_menu_item_t;

static xdg_toplevel_surface_t *xdg_toplevel_surface_create(
struct wlr_xdg_toplevel *wlr_xdg_toplevel_ptr,
wlmaker_server_t *server_ptr);
Expand Down Expand Up @@ -156,19 +151,6 @@ const wlmtk_content_vmt_t _xdg_toplevel_content_vmt = {
.set_activated = content_set_activated,
};

/** Menu items for the XDG toplevel's window menu. */
static const wlmaker_window_menu_item_t _xdg_toplevel_menu_items[] = {
{ "Maximize", WLMAKER_ACTION_WINDOW_MAXIMIZE },
{ "Unmaximize", WLMAKER_ACTION_WINDOW_UNMAXIMIZE },
{ "Fullscreen", WLMAKER_ACTION_WINDOW_TOGGLE_FULLSCREEN },
{ "Shade", WLMAKER_ACTION_WINDOW_SHADE },
{ "Unshade", WLMAKER_ACTION_WINDOW_UNSHADE },
{ "To prev. workspace", WLMAKER_ACTION_WINDOW_TO_PREVIOUS_WORKSPACE },
{ "To next workspace", WLMAKER_ACTION_WINDOW_TO_NEXT_WORKSPACE },
{ "Close", WLMAKER_ACTION_WINDOW_CLOSE },
{ NULL, 0 } // Sentinel.
};

/* == Exported methods ===================================================== */

/* ------------------------------------------------------------------------- */
Expand All @@ -189,30 +171,17 @@ wlmtk_window_t *wlmtk_window_create_from_xdg_toplevel(
xdg_toplevel_surface_destroy(surface_ptr);
return NULL;
}
wl_signal_emit(&server_ptr->window_created_event, wlmtk_window_ptr);

bs_log(BS_INFO, "Created window %p for wlmtk XDG toplevel surface %p",
wlmtk_window_ptr, surface_ptr);

for (const wlmaker_window_menu_item_t *i_ptr = &_xdg_toplevel_menu_items[0];
i_ptr->text_ptr != NULL;
++i_ptr) {

wlmaker_action_item_t *action_item_ptr = wlmaker_action_item_create(
i_ptr->text_ptr,
&server_ptr->style.menu.item,
i_ptr->action,
server_ptr,
server_ptr->env_ptr);
if (NULL == action_item_ptr) {
wlmtk_window_destroy(wlmtk_window_ptr);
return NULL;
}
wlmtk_menu_add_item(
wlmtk_window_menu(wlmtk_window_ptr),
wlmaker_action_item_menu_item(action_item_ptr));
surface_ptr->tl_menu_ptr = wlmaker_tl_menu_create(
wlmtk_window_ptr, server_ptr);
if (NULL == surface_ptr->tl_menu_ptr) {
xdg_toplevel_surface_destroy(surface_ptr);
return NULL;
}

wl_signal_emit(&server_ptr->window_created_event, wlmtk_window_ptr);
bs_log(BS_INFO, "Created window %p for wlmtk XDG toplevel surface %p",
wlmtk_window_ptr, surface_ptr);
return wlmtk_window_ptr;
}

Expand Down Expand Up @@ -351,6 +320,11 @@ void xdg_toplevel_surface_destroy(
wl_list_remove(&xts_ptr->new_popup_listener.link);
wl_list_remove(&xts_ptr->destroy_listener.link);

if (NULL != xdg_tl_surface_ptr->tl_menu_ptr) {
wlmaker_tl_menu_destroy(xdg_tl_surface_ptr->tl_menu_ptr);
xdg_tl_surface_ptr->tl_menu_ptr = NULL;
}

wlmtk_content_fini(&xts_ptr->super_content);

if (NULL != xdg_tl_surface_ptr->surface_ptr) {
Expand Down
19 changes: 19 additions & 0 deletions src/xwl_toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

#include "xwl_toplevel.h"

#include "tl_menu.h"

/* == Declarations ========================================================= */

/** State of a XWayland toplevel window. */
Expand All @@ -31,6 +33,9 @@ struct _wlmaker_xwl_toplevel_t {
/** Back-link to server. */
wlmaker_server_t *server_ptr;

/** The toplevel's window menu. */
wlmaker_tl_menu_t *tl_menu_ptr;

/** Listener for `map` event of the surface. */
struct wl_listener surface_map_listener;
/** Listener for `unmap` event of the surface. */
Expand Down Expand Up @@ -66,6 +71,15 @@ wlmaker_xwl_toplevel_t *wlmaker_xwl_toplevel_create(
wlmaker_xwl_toplevel_destroy(xwl_toplevel_ptr);
return NULL;
}

xwl_toplevel_ptr->tl_menu_ptr = wlmaker_tl_menu_create(
xwl_toplevel_ptr->window_ptr,
server_ptr);
if (NULL == xwl_toplevel_ptr->tl_menu_ptr) {
wlmaker_xwl_toplevel_destroy(xwl_toplevel_ptr);
return NULL;
}

wl_signal_emit(&server_ptr->window_created_event,
xwl_toplevel_ptr->window_ptr);

Expand Down Expand Up @@ -98,6 +112,11 @@ void wlmaker_xwl_toplevel_destroy(
wl_list_remove(&xwl_toplevel_ptr->surface_unmap_listener.link);
wl_list_remove(&xwl_toplevel_ptr->surface_map_listener.link);

if (NULL != xwl_toplevel_ptr->tl_menu_ptr) {
wlmaker_tl_menu_destroy(xwl_toplevel_ptr->tl_menu_ptr);
xwl_toplevel_ptr->tl_menu_ptr = NULL;
}

free(xwl_toplevel_ptr);
}

Expand Down
Loading