mirror of
https://github.com/labwc/labwc.git
synced 2025-11-02 09:01:47 -05:00
commit
050af96d57
20 changed files with 729 additions and 71 deletions
|
|
@ -66,6 +66,14 @@ Actions are used in menus and keyboard/mouse bindings.
|
|||
*<action name="ToggleAlwaysOnTop">*
|
||||
Toggle always-on-top of focused window.
|
||||
|
||||
*<action name="GoToDesktop"><to>*
|
||||
Switch to workspace. Supported values are "left", "right" or the full
|
||||
name of a workspace or its index (starting at 1) as configured in rc.xml.
|
||||
|
||||
*<action name="SendToDesktop"><to>*
|
||||
Send active window to workspace.
|
||||
Supported values are the same as for GoToDesktop.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
labwc(1), labwc-config(5), labwc-theme(5)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ The rest of this man page describes configuration options.
|
|||
Raise window to top when focused. Default is no.
|
||||
|
||||
## WINDOW SNAPPING
|
||||
|
||||
*<snapping><range>*
|
||||
The distance in pixels from the edge of an ouput for window Move
|
||||
operations to trigger SnapToEdge. A range of 0 disables window snapping.
|
||||
|
|
@ -96,6 +97,18 @@ The rest of this man page describes configuration options.
|
|||
*<snapping><topMaximize>* [yes|no]
|
||||
Maximize window if Move operation ends on the top edge. Default is yes.
|
||||
|
||||
## WORKSPACES
|
||||
|
||||
*<desktops><names><name>*
|
||||
Define workspaces. A workspace covers all outputs. The OSD only shows
|
||||
windows on the current workspace. Workspaces can be switched to with
|
||||
GoToDesktop and windows can be moved with SendToDesktop. See
|
||||
labwc-actions(5) for more information about their arguments.
|
||||
|
||||
*<desktops><popupTime>*
|
||||
Define the timeout after which to hide the workspace OSD.
|
||||
A setting of 0 disables the OSD. Default is 1000 ms.
|
||||
|
||||
## THEME
|
||||
|
||||
*<theme><name>*
|
||||
|
|
|
|||
|
|
@ -17,6 +17,16 @@
|
|||
<item label="AlwaysOnTop">
|
||||
<action name="ToggleAlwaysOnTop" />
|
||||
</item>
|
||||
<menu id="workspaces" label="Workspace">
|
||||
<item label="Move left">
|
||||
<action name="SendToDesktop" to="left" />
|
||||
<action name="GoToDesktop" to="left" />
|
||||
</item>
|
||||
<item label="Move right">
|
||||
<action name="SendToDesktop" to="right" />
|
||||
<action name="GoToDesktop" to="right" />
|
||||
</item>
|
||||
</menu>
|
||||
<item label="Close">
|
||||
<action name="Close" />
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,32 @@
|
|||
<topMaximize>yes</topMaximize>
|
||||
</snapping>
|
||||
|
||||
<!--
|
||||
Use GoToDesktop left | right to switch workspaces.
|
||||
Use SendToDesktop left | right to move windows.
|
||||
See man labwc-actions for futher information.
|
||||
|
||||
Workspaces can be configured like this:
|
||||
<desktops>
|
||||
<popupTime>1000</popupTime>
|
||||
<names>
|
||||
<name>Workspace 1</name>
|
||||
<name>Workspace 2</name>
|
||||
<name>Workspace 3</name>
|
||||
</names>
|
||||
</desktops>
|
||||
-->
|
||||
<desktops>
|
||||
<!--
|
||||
popupTime defaults to 1000 so could be left out.
|
||||
Set to 0 to completely disable the workspace OSD.
|
||||
-->
|
||||
<popupTime>1000</popupTime>
|
||||
<names>
|
||||
<name>Default</name>
|
||||
</names>
|
||||
</desktops>
|
||||
|
||||
<!--
|
||||
Keybind actions are specified in labwc-actions(5)
|
||||
The following keybind modifiers are supported:
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ struct rcxml {
|
|||
|
||||
/* cycle view (alt+tab) */
|
||||
bool cycle_preview_contents;
|
||||
|
||||
struct {
|
||||
int popuptime;
|
||||
struct wl_list workspaces; /* struct workspace.link */
|
||||
} workspace_config;
|
||||
};
|
||||
|
||||
extern struct rcxml rc;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ struct seat {
|
|||
struct wlr_idle *wlr_idle;
|
||||
struct wlr_idle_inhibit_manager_v1 *wlr_idle_inhibit_manager;
|
||||
|
||||
/* Used to hide the workspace OSD after switching workspaces */
|
||||
struct wl_event_source *workspace_osd_timer;
|
||||
bool workspace_osd_shown_by_modifier;
|
||||
|
||||
/* if set, views cannot receive focus */
|
||||
struct wlr_layer_surface_v1 *focused_layer;
|
||||
|
||||
|
|
@ -143,9 +147,11 @@ struct seat {
|
|||
};
|
||||
|
||||
struct lab_data_buffer;
|
||||
struct workspace;
|
||||
|
||||
struct server {
|
||||
struct wl_display *wl_display;
|
||||
struct wl_event_loop *wl_event_loop; /* Can be used for timer events */
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_backend *backend;
|
||||
|
|
@ -194,6 +200,10 @@ struct server {
|
|||
/* Tree for built in menu */
|
||||
struct wlr_scene_tree *menu_tree;
|
||||
|
||||
/* Workspaces */
|
||||
struct wl_list workspaces; /* struct workspace.link */
|
||||
struct workspace *workspace_current;
|
||||
|
||||
struct wl_list outputs;
|
||||
struct wl_listener new_output;
|
||||
struct wlr_output_layout *output_layout;
|
||||
|
|
@ -234,6 +244,7 @@ struct output {
|
|||
struct wlr_scene_tree *layer_tree[LAB_NR_LAYERS];
|
||||
struct wlr_scene_tree *layer_popup_tree;
|
||||
struct wlr_scene_tree *osd_tree;
|
||||
struct wlr_scene_buffer *workspace_osd;
|
||||
struct wlr_box usable_area;
|
||||
|
||||
struct lab_data_buffer *osd_buffer;
|
||||
|
|
@ -276,6 +287,7 @@ struct view {
|
|||
const struct view_impl *impl;
|
||||
struct wl_list link;
|
||||
struct output *output;
|
||||
struct workspace *workspace;
|
||||
|
||||
union {
|
||||
struct wlr_xdg_surface *xdg_surface;
|
||||
|
|
|
|||
28
include/workspaces.h
Normal file
28
include/workspaces.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef __LABWC_WORKSPACES_H
|
||||
#define __LABWC_WORKSPACES_H
|
||||
|
||||
struct seat;
|
||||
struct view;
|
||||
struct server;
|
||||
struct wl_list;
|
||||
|
||||
/* Double use: as config in config/rcxml.c and as instance in workspaces.c */
|
||||
struct workspace {
|
||||
struct wl_list link; /* struct server.workspaces
|
||||
struct rcxml.workspace_config.workspaces */
|
||||
struct server *server;
|
||||
|
||||
char *name;
|
||||
struct wlr_scene_tree *tree;
|
||||
};
|
||||
|
||||
|
||||
void workspaces_init(struct server *server);
|
||||
void workspaces_switch_to(struct workspace *target);
|
||||
void workspaces_send_to(struct view *view, struct workspace *target);
|
||||
void workspaces_destroy(struct server *server);
|
||||
void workspaces_osd_hide(struct seat *seat);
|
||||
struct workspace * workspaces_find(struct workspace *anchor, const char *name);
|
||||
|
||||
#endif /* __LABWC_WORKSPACES_H */
|
||||
23
src/action.c
23
src/action.c
|
|
@ -9,6 +9,7 @@
|
|||
#include "menu/menu.h"
|
||||
#include "ssd.h"
|
||||
#include "action.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
enum action_type {
|
||||
ACTION_TYPE_NONE = 0,
|
||||
|
|
@ -31,6 +32,8 @@ enum action_type {
|
|||
ACTION_TYPE_MOVE,
|
||||
ACTION_TYPE_RAISE,
|
||||
ACTION_TYPE_RESIZE,
|
||||
ACTION_TYPE_GO_TO_DESKTOP,
|
||||
ACTION_TYPE_SEND_TO_DESKTOP,
|
||||
};
|
||||
|
||||
const char *action_names[] = {
|
||||
|
|
@ -54,6 +57,8 @@ const char *action_names[] = {
|
|||
"Move",
|
||||
"Raise",
|
||||
"Resize",
|
||||
"GoToDesktop",
|
||||
"SendToDesktop",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -255,6 +260,24 @@ actions_run(struct view *activator, struct server *server,
|
|||
resize_edges);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_GO_TO_DESKTOP:
|
||||
{
|
||||
struct workspace *target;
|
||||
target = workspaces_find(server->workspace_current, action->arg);
|
||||
if (target) {
|
||||
workspaces_switch_to(target);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SEND_TO_DESKTOP:
|
||||
if (view) {
|
||||
struct workspace *target;
|
||||
target = workspaces_find(view->workspace, action->arg);
|
||||
if (target) {
|
||||
workspaces_send_to(view, target);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_NONE:
|
||||
wlr_log(WLR_ERROR,
|
||||
"Not executing unknown action with arg %s",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "config/libinput.h"
|
||||
#include "config/mousebind.h"
|
||||
#include "config/rcxml.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
static bool in_keybind;
|
||||
static bool in_mousebind;
|
||||
|
|
@ -74,10 +75,16 @@ fill_keybind(char *nodename, char *content)
|
|||
wlr_log(WLR_ERROR, "Action argument already set: %s",
|
||||
current_keybind_action->arg);
|
||||
} else if (!strcmp(nodename, "command.action")) {
|
||||
/* Execute */
|
||||
current_keybind_action->arg = strdup(content);
|
||||
} else if (!strcmp(nodename, "direction.action")) {
|
||||
/* MoveToEdge, SnapToEdge */
|
||||
current_keybind_action->arg = strdup(content);
|
||||
} else if (!strcmp(nodename, "menu.action")) {
|
||||
/* ShowMenu */
|
||||
current_keybind_action->arg = strdup(content);
|
||||
} else if (!strcmp(nodename, "to.action")) {
|
||||
/* GoToDesktop, SendToDesktop */
|
||||
current_keybind_action->arg = strdup(content);
|
||||
}
|
||||
}
|
||||
|
|
@ -387,6 +394,12 @@ entry(xmlNode *node, char *nodename, char *content)
|
|||
rc.snap_top_maximize = get_bool(content);
|
||||
} else if (!strcasecmp(nodename, "cycleViewPreview.core")) {
|
||||
rc.cycle_preview_contents = get_bool(content);
|
||||
} else if (!strcasecmp(nodename, "name.names.desktops")) {
|
||||
struct workspace *workspace = calloc(1, sizeof(struct workspace));
|
||||
workspace->name = strdup(content);
|
||||
wl_list_insert(rc.workspace_config.workspaces.prev, &workspace->link);
|
||||
} else if (!strcasecmp(nodename, "popupTime.desktops")) {
|
||||
rc.workspace_config.popuptime = atoi(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -486,6 +499,8 @@ rcxml_init()
|
|||
rc.snap_edge_range = 1;
|
||||
rc.snap_top_maximize = true;
|
||||
rc.cycle_preview_contents = false;
|
||||
rc.workspace_config.popuptime = INT_MIN;
|
||||
wl_list_init(&rc.workspace_config.workspaces);
|
||||
}
|
||||
|
||||
static struct {
|
||||
|
|
@ -620,6 +635,14 @@ post_processing(void)
|
|||
struct libinput_category *l = libinput_category_create();
|
||||
l->type = TOUCH_DEVICE;
|
||||
}
|
||||
if (!wl_list_length(&rc.workspace_config.workspaces)) {
|
||||
struct workspace *workspace = calloc(1, sizeof(struct workspace));
|
||||
workspace->name = strdup("Default");
|
||||
wl_list_insert(rc.workspace_config.workspaces.prev, &workspace->link);
|
||||
}
|
||||
if (rc.workspace_config.popuptime == INT_MIN) {
|
||||
rc.workspace_config.popuptime = 1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -718,6 +741,13 @@ rcxml_finish(void)
|
|||
zfree(l);
|
||||
}
|
||||
|
||||
struct workspace *w, *w_tmp;
|
||||
wl_list_for_each_safe(w, w_tmp, &rc.workspace_config.workspaces, link) {
|
||||
wl_list_remove(&w->link);
|
||||
zfree(w->name);
|
||||
zfree(w);
|
||||
}
|
||||
|
||||
/* Reset state vars for starting fresh when Reload is triggered */
|
||||
current_keybind = NULL;
|
||||
current_mousebind = NULL;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
#include "common/scene-helpers.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
static void
|
||||
move_to_front(struct view *view)
|
||||
|
|
@ -162,73 +163,80 @@ isfocusable(struct view *view)
|
|||
return (view->mapped || view->minimized);
|
||||
}
|
||||
|
||||
static bool
|
||||
has_focusable_view(struct wl_list *wl_list)
|
||||
static struct wl_list *
|
||||
get_prev_item(struct wl_list *item)
|
||||
{
|
||||
struct view *view;
|
||||
wl_list_for_each (view, wl_list, link) {
|
||||
if (isfocusable(view)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return item->prev;
|
||||
}
|
||||
|
||||
static struct wl_list *
|
||||
get_next_item(struct wl_list *item)
|
||||
{
|
||||
return item->next;
|
||||
}
|
||||
|
||||
static struct view *
|
||||
first_view(struct server *server)
|
||||
{
|
||||
struct view *view;
|
||||
view = wl_container_of(server->views.next, view, link);
|
||||
return view;
|
||||
struct wlr_scene_node *node;
|
||||
struct wl_list *list_head =
|
||||
&server->workspace_current->tree->children;
|
||||
wl_list_for_each_reverse(node, list_head, link) {
|
||||
return node_view_from_node(node);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct view *
|
||||
desktop_cycle_view(struct server *server, struct view *current,
|
||||
desktop_cycle_view(struct server *server, struct view *start_view,
|
||||
enum lab_cycle_dir dir)
|
||||
{
|
||||
if (!has_focusable_view(&server->views)) {
|
||||
struct view *view = start_view ? start_view : first_view(server);
|
||||
if (!view) {
|
||||
return NULL;
|
||||
}
|
||||
start_view = view;
|
||||
struct wlr_scene_node *node = &view->scene_tree->node;
|
||||
|
||||
struct view *view = current ? current : first_view(server);
|
||||
if (dir == LAB_CYCLE_DIR_FORWARD) {
|
||||
/* Replacement for wl_list_for_each_from() */
|
||||
do {
|
||||
view = wl_container_of(view->link.next, view, link);
|
||||
} while (&view->link == &server->views || !isfocusable(view));
|
||||
} else if (dir == LAB_CYCLE_DIR_BACKWARD) {
|
||||
do {
|
||||
view = wl_container_of(view->link.prev, view, link);
|
||||
} while (&view->link == &server->views || !isfocusable(view));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
assert(node->parent);
|
||||
struct wl_list *list_head = &node->parent->children;
|
||||
struct wl_list *list_item = &node->link;
|
||||
struct wl_list *(*iter)(struct wl_list *);
|
||||
|
||||
static bool
|
||||
has_mapped_view(struct wl_list *wl_list)
|
||||
{
|
||||
struct view *view;
|
||||
wl_list_for_each (view, wl_list, link) {
|
||||
if (view->mapped) {
|
||||
return true;
|
||||
/* Scene nodes are ordered like last node == displayed topmost */
|
||||
iter = dir == LAB_CYCLE_DIR_FORWARD ? get_prev_item : get_next_item;
|
||||
|
||||
do {
|
||||
list_item = iter(list_item);
|
||||
if (list_item == list_head) {
|
||||
/* Start / End of list reached. Roll over */
|
||||
list_item = iter(list_item);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
node = wl_container_of(list_item, node, link);
|
||||
view = node_view_from_node(node);
|
||||
if (isfocusable(view)) {
|
||||
return view;
|
||||
}
|
||||
} while (view != start_view);
|
||||
|
||||
/* No focusable views found, including the one we started with */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct view *
|
||||
topmost_mapped_view(struct server *server)
|
||||
{
|
||||
if (!has_mapped_view(&server->views)) {
|
||||
return NULL;
|
||||
struct view *view;
|
||||
struct wl_list *node_list;
|
||||
struct wlr_scene_node *node;
|
||||
node_list = &server->workspace_current->tree->children;
|
||||
wl_list_for_each_reverse(node, node_list, link) {
|
||||
view = node_view_from_node(node);
|
||||
if (view->mapped) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
/* start from tail of server->views */
|
||||
struct view *view = wl_container_of(server->views.prev, view, link);
|
||||
do {
|
||||
view = wl_container_of(view->link.next, view, link);
|
||||
} while (&view->link == &server->views || !view->mapped);
|
||||
return view;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct view *
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include "labwc.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
static void
|
||||
handle_toplevel_handle_request_minimize(struct wl_listener *listener, void *data)
|
||||
|
|
@ -42,6 +43,9 @@ handle_toplevel_handle_request_activate(struct wl_listener *listener, void *data
|
|||
// struct wlr_foreign_toplevel_handle_v1_activated_event *event = data;
|
||||
/* In a multi-seat world we would select seat based on event->seat here. */
|
||||
if (view) {
|
||||
if (view->workspace != view->server->workspace_current) {
|
||||
workspaces_switch_to(view->workspace);
|
||||
}
|
||||
desktop_focus_and_activate_view(&view->server->seat, view);
|
||||
desktop_move_to_front(view);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "buffer.h"
|
||||
#include "key-state.h"
|
||||
#include "labwc.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
static void
|
||||
change_vt(struct server *server, unsigned int vt)
|
||||
|
|
@ -38,17 +39,23 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data)
|
|||
struct seat *seat = wl_container_of(listener, seat, keyboard_modifiers);
|
||||
struct server *server = seat->server;
|
||||
|
||||
if (server->cycle_view) {
|
||||
if (server->cycle_view || seat->workspace_osd_shown_by_modifier) {
|
||||
struct wlr_keyboard_key_event *event = data;
|
||||
struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard;
|
||||
|
||||
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED
|
||||
&& !keyboard_any_modifiers_pressed(keyboard)) {
|
||||
/* end cycle */
|
||||
desktop_focus_and_activate_view(&server->seat,
|
||||
server->cycle_view);
|
||||
desktop_move_to_front(server->cycle_view);
|
||||
server->cycle_view = NULL;
|
||||
osd_finish(server);
|
||||
if (server->cycle_view) {
|
||||
/* end cycle */
|
||||
desktop_focus_and_activate_view(&server->seat,
|
||||
server->cycle_view);
|
||||
desktop_move_to_front(server->cycle_view);
|
||||
server->cycle_view = NULL;
|
||||
osd_finish(server);
|
||||
}
|
||||
if (seat->workspace_osd_shown_by_modifier) {
|
||||
workspaces_osd_hide(seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -203,9 +203,20 @@ fill_item(char *nodename, char *content)
|
|||
* compatibility with old openbox-menu generators
|
||||
*/
|
||||
current_item_action->arg = strdup(content);
|
||||
} else if (!strcmp(nodename, "to.action")) {
|
||||
current_item_action->arg = strdup(content);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
item_destroy(struct menuitem *item)
|
||||
{
|
||||
wl_list_remove(&item->link);
|
||||
action_list_free(&item->actions);
|
||||
wlr_scene_node_destroy(&item->tree->node);
|
||||
free(item);
|
||||
}
|
||||
|
||||
static void
|
||||
entry(xmlNode *node, char *nodename, char *content)
|
||||
{
|
||||
|
|
@ -447,6 +458,38 @@ menu_configure(struct menu *menu, int lx, int ly, enum menu_align align)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
menu_hide_submenu(const char *id)
|
||||
{
|
||||
struct menu *menu, *hide_menu;
|
||||
hide_menu = menu_get_by_id(id);
|
||||
if (!hide_menu) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < nr_menus; ++i) {
|
||||
menu = menus + i;
|
||||
size_t item_index = 0;
|
||||
size_t items_destroyed = 0;
|
||||
struct menuitem *item, *item_tmp;
|
||||
wl_list_for_each_reverse_safe(item, item_tmp, &menu->menuitems, link) {
|
||||
if (item->submenu == hide_menu) {
|
||||
item_destroy(item);
|
||||
items_destroyed++;
|
||||
item_index++;
|
||||
continue;
|
||||
}
|
||||
if (items_destroyed) {
|
||||
int y = (item_index - items_destroyed) * menu->item_height;
|
||||
wlr_scene_node_set_position(&item->tree->node, 0, y);
|
||||
}
|
||||
item_index++;
|
||||
}
|
||||
if (items_destroyed) {
|
||||
menu->size.height -= items_destroyed * menu->item_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
menu_init_rootmenu(struct server *server)
|
||||
{
|
||||
|
|
@ -487,9 +530,29 @@ menu_init_windowmenu(struct server *server)
|
|||
fill_item("name.action", "ToggleDecorations");
|
||||
current_item = item_create(menu, _("AlwaysOnTop"));
|
||||
fill_item("name.action", "ToggleAlwaysOnTop");
|
||||
|
||||
/* Workspace sub-menu */
|
||||
struct menu *workspace_menu = menu_create(server, "workspaces", "");
|
||||
current_item = item_create(workspace_menu, _("Move left"));
|
||||
fill_item("name.action", "SendToDesktop");
|
||||
fill_item("to.action", "left");
|
||||
fill_item("name.action", "GoToDesktop");
|
||||
fill_item("to.action", "left");
|
||||
current_item = item_create(workspace_menu, _("Move right"));
|
||||
fill_item("name.action", "SendToDesktop");
|
||||
fill_item("to.action", "right");
|
||||
fill_item("name.action", "GoToDesktop");
|
||||
fill_item("to.action", "right");
|
||||
current_item = item_create(menu, _("Workspace"));
|
||||
current_item->submenu = workspace_menu;
|
||||
|
||||
current_item = item_create(menu, _("Close"));
|
||||
fill_item("name.action", "Close");
|
||||
}
|
||||
|
||||
if (wl_list_length(&rc.workspace_config.workspaces) == 1) {
|
||||
menu_hide_submenu("workspaces");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -500,9 +563,7 @@ menu_finish(void)
|
|||
menu = menus + i;
|
||||
struct menuitem *item, *next;
|
||||
wl_list_for_each_safe(item, next, &menu->menuitems, link) {
|
||||
wl_list_remove(&item->link);
|
||||
action_list_free(&item->actions);
|
||||
free(item);
|
||||
item_destroy(item);
|
||||
}
|
||||
/**
|
||||
* Destroying the root node will destroy everything,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ labwc_sources = files(
|
|||
'theme.c',
|
||||
'view.c',
|
||||
'view-impl.c',
|
||||
'workspaces.c',
|
||||
'xdg.c',
|
||||
'xdg-deco.c',
|
||||
'xdg-popup.c',
|
||||
|
|
|
|||
61
src/osd.c
61
src/osd.c
|
|
@ -10,6 +10,8 @@
|
|||
#include "config/rcxml.h"
|
||||
#include "labwc.h"
|
||||
#include "theme.h"
|
||||
#include "node.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
#define OSD_ITEM_HEIGHT (20)
|
||||
#define OSD_ITEM_WIDTH (600)
|
||||
|
|
@ -78,11 +80,13 @@ get_formatted_app_id(struct view *view)
|
|||
}
|
||||
|
||||
static int
|
||||
get_osd_height(struct wl_list *views)
|
||||
get_osd_height(struct wl_list *node_list)
|
||||
{
|
||||
int height = 0;
|
||||
struct view *view;
|
||||
wl_list_for_each(view, views, link) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, node_list, link) {
|
||||
view = node_view_from_node(node);
|
||||
if (!isfocusable(view)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -115,21 +119,32 @@ osd_finish(struct server *server)
|
|||
void
|
||||
osd_update(struct server *server)
|
||||
{
|
||||
if (wl_list_empty(&server->views)) {
|
||||
struct wl_list *node_list =
|
||||
&server->workspace_current->tree->children;
|
||||
|
||||
if (wl_list_empty(node_list)) {
|
||||
osd_finish(server);
|
||||
return;
|
||||
}
|
||||
|
||||
struct theme *theme = server->theme;
|
||||
bool show_workspace = wl_list_length(&rc.workspace_config.workspaces) > 1;
|
||||
|
||||
struct buf buf;
|
||||
buf_init(&buf);
|
||||
|
||||
struct view *view;
|
||||
struct output *output;
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
destroy_osd_nodes(output);
|
||||
float scale = output->wlr_output->scale;
|
||||
int w = (OSD_ITEM_WIDTH + (2 * OSD_BORDER_WIDTH));
|
||||
int h = get_osd_height(&server->views);
|
||||
int w = OSD_ITEM_WIDTH + (2 * OSD_BORDER_WIDTH);
|
||||
int h = get_osd_height(node_list);
|
||||
if (show_workspace) {
|
||||
/* workspace indicator */
|
||||
h += OSD_ITEM_HEIGHT;
|
||||
}
|
||||
|
||||
if (output->osd_buffer) {
|
||||
wlr_buffer_drop(&output->osd_buffer->base);
|
||||
|
|
@ -148,10 +163,16 @@ osd_update(struct server *server)
|
|||
set_source(cairo, theme->osd_border_color);
|
||||
draw_border(cairo, w, h, theme->osd_border_width);
|
||||
|
||||
/* highlight current window */
|
||||
int y = OSD_BORDER_WIDTH;
|
||||
struct view *view;
|
||||
wl_list_for_each(view, &server->views, link) {
|
||||
|
||||
if (show_workspace) {
|
||||
/* workspace indicator */
|
||||
y += OSD_ITEM_HEIGHT;
|
||||
}
|
||||
|
||||
/* highlight current window */
|
||||
wl_list_for_each_reverse(node, node_list, link) {
|
||||
view = node_view_from_node(node);
|
||||
if (!isfocusable(view)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -179,7 +200,6 @@ osd_update(struct server *server)
|
|||
pango_font_description_set_family(desc, font.name);
|
||||
pango_font_description_set_size(desc, font.size * PANGO_SCALE);
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
pango_font_description_free(desc);
|
||||
|
||||
PangoTabArray *tabs = pango_tab_array_new_with_positions(2, TRUE,
|
||||
PANGO_TAB_LEFT, OSD_TAB1, PANGO_TAB_LEFT, OSD_TAB2);
|
||||
|
|
@ -189,9 +209,28 @@ osd_update(struct server *server)
|
|||
pango_cairo_update_layout(cairo, layout);
|
||||
|
||||
y = OSD_BORDER_WIDTH;
|
||||
y += (OSD_ITEM_HEIGHT - font_height(&font)) / 2;
|
||||
|
||||
wl_list_for_each(view, &server->views, link) {
|
||||
/* Center text entries on the y axis */
|
||||
int y_offset = (OSD_ITEM_HEIGHT - font_height(&font)) / 2;
|
||||
y += y_offset;
|
||||
|
||||
if (show_workspace) {
|
||||
/* Center workspace indicator on the x axis */
|
||||
int x = font_width(&font, server->workspace_current->name);
|
||||
x = (OSD_ITEM_WIDTH - x) / 2;
|
||||
cairo_move_to(cairo, x, y);
|
||||
pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
pango_layout_set_text(layout, server->workspace_current->name, -1);
|
||||
pango_cairo_show_layout(cairo, layout);
|
||||
pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL);
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
y += OSD_ITEM_HEIGHT;
|
||||
}
|
||||
pango_font_description_free(desc);
|
||||
|
||||
wl_list_for_each_reverse(node, node_list, link) {
|
||||
view = node_view_from_node(node);
|
||||
if (!isfocusable(view)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "menu/menu.h"
|
||||
#include "ssd.h"
|
||||
#include "theme.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
#define LAB_XDG_SHELL_VERSION (2)
|
||||
|
||||
|
|
@ -181,6 +182,7 @@ server_init(struct server *server)
|
|||
event_loop, SIGINT, handle_sigterm, server->wl_display);
|
||||
sigterm_source = wl_event_loop_add_signal(
|
||||
event_loop, SIGTERM, handle_sigterm, server->wl_display);
|
||||
server->wl_event_loop = event_loop;
|
||||
|
||||
/*
|
||||
* The backend is a feature which abstracts the underlying input and
|
||||
|
|
@ -245,6 +247,8 @@ server_init(struct server *server)
|
|||
#endif
|
||||
server->menu_tree = wlr_scene_tree_create(&server->scene->tree);
|
||||
|
||||
workspaces_init(server);
|
||||
|
||||
output_init(server);
|
||||
|
||||
/*
|
||||
|
|
@ -452,7 +456,7 @@ server_start(struct server *server)
|
|||
void
|
||||
server_finish(struct server *server)
|
||||
{
|
||||
/* TODO: clean up various scene_tree nodes */
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
wlr_xwayland_destroy(server->xwayland);
|
||||
#endif
|
||||
|
|
@ -465,4 +469,7 @@ server_finish(struct server *server)
|
|||
wlr_output_layout_destroy(server->output_layout);
|
||||
|
||||
wl_display_destroy(server->wl_display);
|
||||
|
||||
/* TODO: clean up various scene_tree nodes */
|
||||
workspaces_destroy(server);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "labwc.h"
|
||||
#include "ssd.h"
|
||||
#include "menu/menu.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
|
|
@ -336,8 +337,8 @@ void
|
|||
view_toggle_always_on_top(struct view *view)
|
||||
{
|
||||
if (is_always_on_top(view)) {
|
||||
wlr_scene_node_reparent(&view->scene_tree->node,
|
||||
view->server->view_tree);
|
||||
view->workspace = view->server->workspace_current;
|
||||
wlr_scene_node_reparent(&view->scene_tree->node, view->workspace->tree);
|
||||
} else {
|
||||
wlr_scene_node_reparent(&view->scene_tree->node,
|
||||
view->server->view_tree_always_on_top);
|
||||
|
|
|
|||
371
src/workspaces.c
Normal file
371
src/workspaces.c
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include "labwc.h"
|
||||
#include "common/font.h"
|
||||
#include "common/zfree.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
/* Internal helpers */
|
||||
static size_t
|
||||
parse_workspace_index(const char *name)
|
||||
{
|
||||
/*
|
||||
* We only want to get positive numbers which span the whole string.
|
||||
*
|
||||
* More detailed requirement:
|
||||
* .---------------.--------------.
|
||||
* | Input | Return value |
|
||||
* |---------------+--------------|
|
||||
* | "2nd desktop" | 0 |
|
||||
* | "-50" | 0 |
|
||||
* | "0" | 0 |
|
||||
* | "124" | 124 |
|
||||
* | "1.24" | 0 |
|
||||
* `------------------------------´
|
||||
*
|
||||
* As atoi() happily parses any numbers until it hits a non-number we
|
||||
* can't really use it for this case. Instead, we use strtol() combined
|
||||
* with further checks for the endptr (remaining non-number characters)
|
||||
* and returned negative numbers.
|
||||
*/
|
||||
long index;
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
index = strtol(name, &endptr, 10);
|
||||
if (errno || *endptr != '\0' || index < 0) {
|
||||
return 0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: set_source and draw_border are straight up copies from src/osd.c
|
||||
* find some proper place for them instead of duplicating stuff.
|
||||
*/
|
||||
static void
|
||||
set_source(cairo_t *cairo, float *c)
|
||||
{
|
||||
cairo_set_source_rgba(cairo, c[0], c[1], c[2], c[3]);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_border(cairo_t *cairo, double width, double height, double line_width)
|
||||
{
|
||||
cairo_save(cairo);
|
||||
|
||||
double x, y, w, h;
|
||||
/* The anchor point of a line is in the center */
|
||||
x = y = line_width / 2;
|
||||
w = width - line_width;
|
||||
h = height - line_width;
|
||||
cairo_set_line_width(cairo, line_width);
|
||||
cairo_rectangle(cairo, x, y, w, h);
|
||||
cairo_stroke(cairo);
|
||||
|
||||
cairo_restore(cairo);
|
||||
}
|
||||
|
||||
static void
|
||||
_osd_update(struct server *server)
|
||||
{
|
||||
|
||||
struct theme *theme = server->theme;
|
||||
|
||||
/* Settings */
|
||||
uint16_t margin = 10;
|
||||
uint16_t padding = 2;
|
||||
uint16_t rect_height = 20;
|
||||
uint16_t rect_width = 20;
|
||||
struct font font = {
|
||||
.name = rc.font_name_osd,
|
||||
.size = rc.font_size_osd,
|
||||
};
|
||||
|
||||
/* Dimensions */
|
||||
size_t workspace_count = wl_list_length(&server->workspaces);
|
||||
uint16_t marker_width = workspace_count * (rect_width + padding) - padding;
|
||||
uint16_t width = margin * 2 + (marker_width < 200 ? 200 : marker_width);
|
||||
uint16_t height = margin * 3 + rect_height + font_height(&font);
|
||||
|
||||
cairo_t *cairo;
|
||||
cairo_surface_t *surface;
|
||||
struct workspace *workspace;
|
||||
|
||||
struct output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
struct lab_data_buffer *buffer = buffer_create_cairo(width, height,
|
||||
output->wlr_output->scale, true);
|
||||
if (!buffer) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate buffer for workspace OSD");
|
||||
continue;
|
||||
}
|
||||
|
||||
cairo = buffer->cairo;
|
||||
|
||||
/* Background */
|
||||
set_source(cairo, theme->osd_bg_color);
|
||||
cairo_rectangle(cairo, 0, 0, width, height);
|
||||
cairo_fill(cairo);
|
||||
|
||||
/* Border */
|
||||
set_source(cairo, theme->osd_border_color);
|
||||
draw_border(cairo, width, height, theme->osd_border_width);
|
||||
|
||||
uint16_t x = (width - marker_width) / 2;
|
||||
wl_list_for_each(workspace, &server->workspaces, link) {
|
||||
bool active = workspace == server->workspace_current;
|
||||
set_source(cairo, server->theme->osd_label_text_color);
|
||||
cairo_rectangle(cairo, x, margin,
|
||||
rect_width - padding, rect_height);
|
||||
cairo_stroke(cairo);
|
||||
if (active) {
|
||||
cairo_rectangle(cairo, x, margin,
|
||||
rect_width - padding, rect_height);
|
||||
cairo_fill(cairo);
|
||||
}
|
||||
x += rect_width + padding;
|
||||
}
|
||||
|
||||
/* Text */
|
||||
set_source(cairo, server->theme->osd_label_text_color);
|
||||
PangoLayout *layout = pango_cairo_create_layout(cairo);
|
||||
pango_layout_set_width(layout, (width - 2 * margin) * PANGO_SCALE);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||
|
||||
PangoFontDescription *desc = pango_font_description_new();
|
||||
pango_font_description_set_family(desc, font.name);
|
||||
pango_font_description_set_size(desc, font.size * PANGO_SCALE);
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
|
||||
/* Center workspace indicator on the x axis */
|
||||
x = font_width(&font, server->workspace_current->name);
|
||||
x = (width - x) / 2;
|
||||
cairo_move_to(cairo, x, margin * 2 + rect_height);
|
||||
//pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
pango_font_description_free(desc);
|
||||
pango_layout_set_text(layout, server->workspace_current->name, -1);
|
||||
pango_cairo_show_layout(cairo, layout);
|
||||
|
||||
g_object_unref(layout);
|
||||
surface = cairo_get_target(cairo);
|
||||
cairo_surface_flush(surface);
|
||||
|
||||
if (!output->workspace_osd) {
|
||||
output->workspace_osd = wlr_scene_buffer_create(
|
||||
&server->scene->tree, NULL);
|
||||
}
|
||||
/* Position the whole thing */
|
||||
struct wlr_box output_box;
|
||||
wlr_output_layout_get_box(output->server->output_layout,
|
||||
output->wlr_output, &output_box);
|
||||
int lx = output->usable_area.x
|
||||
+ (output->usable_area.width - width) / 2
|
||||
+ output_box.x;
|
||||
int ly = output->usable_area.y
|
||||
+ (output->usable_area.height - height ) / 2
|
||||
+ output_box.y;
|
||||
wlr_scene_node_set_position(&output->workspace_osd->node, lx, ly);
|
||||
wlr_scene_buffer_set_buffer(output->workspace_osd, &buffer->base);
|
||||
wlr_scene_buffer_set_dest_size(output->workspace_osd,
|
||||
buffer->unscaled_width, buffer->unscaled_height);
|
||||
|
||||
/* And finally drop the buffer so it will get destroyed on OSD hide */
|
||||
wlr_buffer_drop(&buffer->base);
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal API */
|
||||
static void
|
||||
add_workspace(struct server *server, const char *name)
|
||||
{
|
||||
struct workspace *workspace = calloc(1, sizeof(struct workspace));
|
||||
workspace->server = server;
|
||||
workspace->name = strdup(name);
|
||||
workspace->tree = wlr_scene_tree_create(server->view_tree);
|
||||
wl_list_insert(server->workspaces.prev, &workspace->link);
|
||||
if (!server->workspace_current) {
|
||||
server->workspace_current = workspace;
|
||||
} else {
|
||||
wlr_scene_node_set_enabled(&workspace->tree->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
static struct workspace *
|
||||
get_prev(struct workspace *current, struct wl_list *workspaces)
|
||||
{
|
||||
struct wl_list *target_link = current->link.prev;
|
||||
if (target_link == workspaces) {
|
||||
/* Current workspace is the first one, roll over */
|
||||
target_link = target_link->prev;
|
||||
}
|
||||
return wl_container_of(target_link, current, link);
|
||||
}
|
||||
|
||||
static struct workspace *
|
||||
get_next(struct workspace *current, struct wl_list *workspaces)
|
||||
{
|
||||
struct wl_list *target_link = current->link.next;
|
||||
if (target_link == workspaces) {
|
||||
/* Current workspace is the last one, roll over */
|
||||
target_link = target_link->next;
|
||||
}
|
||||
return wl_container_of(target_link, current, link);
|
||||
}
|
||||
|
||||
static int
|
||||
_osd_handle_timeout(void *data)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
workspaces_osd_hide(seat);
|
||||
/* Don't re-check */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_osd_show(struct server *server)
|
||||
{
|
||||
if (!rc.workspace_config.popuptime) {
|
||||
return;
|
||||
}
|
||||
|
||||
_osd_update(server);
|
||||
struct output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
wlr_scene_node_set_enabled(&output->workspace_osd->node, true);
|
||||
}
|
||||
struct wlr_keyboard *keyboard = &server->seat.keyboard_group->keyboard;
|
||||
if (keyboard_any_modifiers_pressed(keyboard)) {
|
||||
/* Hidden by release of all modifiers */
|
||||
server->seat.workspace_osd_shown_by_modifier = true;
|
||||
} else {
|
||||
/* Hidden by timer */
|
||||
if (!server->seat.workspace_osd_timer) {
|
||||
server->seat.workspace_osd_timer = wl_event_loop_add_timer(
|
||||
server->wl_event_loop, _osd_handle_timeout, &server->seat);
|
||||
}
|
||||
wl_event_source_timer_update(server->seat.workspace_osd_timer,
|
||||
rc.workspace_config.popuptime);
|
||||
}
|
||||
}
|
||||
|
||||
/* Public API */
|
||||
void
|
||||
workspaces_init(struct server *server)
|
||||
{
|
||||
wl_list_init(&server->workspaces);
|
||||
|
||||
struct workspace *conf;
|
||||
wl_list_for_each(conf, &rc.workspace_config.workspaces, link) {
|
||||
add_workspace(server, conf->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
workspaces_switch_to(struct workspace *target)
|
||||
{
|
||||
assert(target);
|
||||
if (target == target->server->workspace_current) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable the old workspace */
|
||||
wlr_scene_node_set_enabled(
|
||||
&target->server->workspace_current->tree->node, false);
|
||||
|
||||
/* Enable the new workspace */
|
||||
wlr_scene_node_set_enabled(&target->tree->node, true);
|
||||
|
||||
/* Make sure new views will spawn on the new workspace */
|
||||
target->server->workspace_current = target;
|
||||
|
||||
/**
|
||||
* Make sure we are focusing what the user sees.
|
||||
*
|
||||
* TODO: This is an issue for always-on-top views as they will
|
||||
* loose keyboard focus once switching to another workspace.
|
||||
*/
|
||||
desktop_focus_topmost_mapped_view(target->server);
|
||||
|
||||
/* And finally show the OSD */
|
||||
_osd_show(target->server);
|
||||
}
|
||||
|
||||
void
|
||||
workspaces_send_to(struct view *view, struct workspace *target)
|
||||
{
|
||||
assert(view);
|
||||
assert(target);
|
||||
if (view->workspace == target) {
|
||||
return;
|
||||
}
|
||||
wlr_scene_node_reparent(&view->scene_tree->node, target->tree);
|
||||
view->workspace = target;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
workspaces_osd_hide(struct seat *seat)
|
||||
{
|
||||
assert(seat);
|
||||
struct output *output;
|
||||
struct server *server = seat->server;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
wlr_scene_node_set_enabled(&output->workspace_osd->node, false);
|
||||
wlr_scene_buffer_set_buffer(output->workspace_osd, NULL);
|
||||
}
|
||||
seat->workspace_osd_shown_by_modifier = false;
|
||||
}
|
||||
|
||||
struct workspace *
|
||||
workspaces_find(struct workspace *anchor, const char *name)
|
||||
{
|
||||
assert(anchor);
|
||||
if (!name) {
|
||||
return NULL;
|
||||
}
|
||||
size_t index = 0;
|
||||
struct workspace *target;
|
||||
size_t wants_index = parse_workspace_index(name);
|
||||
struct wl_list *workspaces = &anchor->server->workspaces;
|
||||
|
||||
if (wants_index) {
|
||||
wl_list_for_each(target, workspaces, link) {
|
||||
if (wants_index == ++index) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(name, "left")) {
|
||||
return get_prev(anchor, workspaces);
|
||||
} else if (!strcasecmp(name, "right")) {
|
||||
return get_next(anchor, workspaces);
|
||||
} else {
|
||||
wl_list_for_each(target, workspaces, link) {
|
||||
if (!strcasecmp(target->name, name)) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
wlr_log(WLR_ERROR, "Workspace '%s' not found", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
workspaces_destroy(struct server *server)
|
||||
{
|
||||
struct workspace *workspace, *tmp;
|
||||
wl_list_for_each_safe(workspace, tmp, &server->workspaces, link) {
|
||||
wlr_scene_node_destroy(&workspace->tree->node);
|
||||
zfree(workspace->name);
|
||||
wl_list_remove(&workspace->link);
|
||||
free(workspace);
|
||||
}
|
||||
assert(wl_list_empty(&server->workspaces));
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
static void
|
||||
handle_new_xdg_popup(struct wl_listener *listener, void *data)
|
||||
|
|
@ -374,7 +375,8 @@ xdg_surface_new(struct wl_listener *listener, void *data)
|
|||
view->impl = &xdg_toplevel_view_impl;
|
||||
view->xdg_surface = xdg_surface;
|
||||
|
||||
view->scene_tree = wlr_scene_tree_create(view->server->view_tree);
|
||||
view->workspace = server->workspace_current;
|
||||
view->scene_tree = wlr_scene_tree_create(view->workspace->tree);
|
||||
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
||||
|
||||
struct wlr_scene_tree *tree = wlr_scene_xdg_surface_create(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
static void
|
||||
handle_commit(struct wl_listener *listener, void *data)
|
||||
|
|
@ -434,7 +435,8 @@ xwayland_surface_new(struct wl_listener *listener, void *data)
|
|||
view->impl = &xwl_view_impl;
|
||||
view->xwayland_surface = xsurface;
|
||||
|
||||
view->scene_tree = wlr_scene_tree_create(view->server->view_tree);
|
||||
view->workspace = server->workspace_current;
|
||||
view->scene_tree = wlr_scene_tree_create(view->workspace->tree);
|
||||
node_descriptor_create(&view->scene_tree->node,
|
||||
LAB_NODE_DESC_VIEW, view);
|
||||
xsurface->data = view;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue