Merge branch 'development' of https://github.com/project-repo/cagebreak into development

This commit is contained in:
project-repo 2022-10-02 08:26:19 +02:00
commit cd01274710
13 changed files with 224 additions and 84 deletions

View file

@ -1,5 +1,9 @@
# Cagebreak: A Wayland Tiling Compositor Inspired by Ratpoison
[![Packaging status](https://repology.org/badge/tiny-repos/cagebreak.svg)](https://repology.org/project/cagebreak/versions)
[![AUR package](https://repology.org/badge/version-for-repo/aur/cagebreak.svg?minversion=2.0.0)](https://repology.org/project/cagebreak/versions)
This is Cagebreak, a Wayland tiling compositor.
The goal of this project is to provide a successor to ratpoison for Wayland
@ -118,17 +122,20 @@ occur.
* [ ] `git pull origin development`
* [ ] `git push origin development`
* [ ] `ninja -C build clang-format` makes no changes
* [ ] `ninja -C build scan-build` shows no issues
* [ ] New version number determined according to [semantic versioning](https://semver.org) guidelines
* [ ] Relevant Documentation completed
* [ ] New features
* [ ] man pages
* [ ] man/cagebreak
* [ ] man/cagebreak-config
* [ ] man/cagebreak-socket
* [ ] Set EPOCH to release day in man generation in meson.build
* [ ] FAQ.md
* [ ] Changelog.md for major and minor releases but not patches
* [ ] Check features for SECURITY.md relevance (changes to socket scope
for example)
* [ ] Synchronize any socket changes to cagebreak-socket man page
* [ ] Fixed bugs documented in Bugs.md
* [ ] Include issue description from github
* [ ] Testing
@ -139,6 +146,7 @@ occur.
* [ ] meson.build
* [ ] git tag
* [ ] man pages
* [ ] README.md repology badges minversion
* [ ] meson.build reproducible build versions are current archlinux libraries and gcc
* [ ] Cagebreak is reproducible on multiple machines
* [ ] Documented reproducible build artefacts
@ -148,6 +156,7 @@ occur.
* [ ] `gpg --detach-sign -u keyid cagebreak`
* [ ] `gpg --detach-sign -u keyid cagebreak.1`
* [ ] `gpg --detach-sign -u keyid cagebreak-config.5`
* [ ] `gpg --detach-sign -u keyid cagebreak-socket.7`
* [ ] `git add` relevant files
* [ ] `git commit`
* [ ] `git push origin development`
@ -160,9 +169,12 @@ occur.
* [ ] `git tag -u keyid version HEAD` and insert message
* [ ] `git tag -v version` and check output
* [ ] `git push --tags origin master`
* [ ] `git checkout development`
* [ ] `git checkout development` (merge to development depends on whether release was a hotfix)
* [ ] `git merge master`
* [ ] `git push --tags origin development`
* [ ] `git checkout hotfix` (hotfix is to be kept current with master after releases)
* [ ] `git merge master`
* [ ] `git push --tags origin hotfix`
* [ ] `git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version .`
* [ ] Create release-artefacts_version.tar.gz
* [ ] `mkdir release-artefacts_version`
@ -172,6 +184,8 @@ occur.
* [ ] `cp build/cagebreak.1.sig release-artefacts_version/`
* [ ] `cp build/cagebreak-config.5 release-artefacts_version/`
* [ ] `cp build/cagebreak-config.5.sig release-artefacts_version/`
* [ ] `cp build/cagebreak-socket.7 release-artefacts_version/`
* [ ] `cp build/cagebreak-socket.7.sig release-artefacts_version/`
* [ ] `cp LICENSE release-artefacts_version/`
* [ ] `cp README.md release-artefacts_version/`
* [ ] `cp SECURITY.md release-artefacts_version/`
@ -341,5 +355,5 @@ See [Changelog.md](Changelog.md)
## License
Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE# Cagebreak: A Wayland Tiling Compositor Inspired by Ratpoison
Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE) Cagebreak: A Wayland Tiling Compositor Inspired by Ratpoison

View file

@ -1,10 +1,12 @@
# Security
The main possibility for security bugs to occur in cagebreak is by privilege
escalation using the socket. Indeed, any program with access to the socket
immediately gains arbitrary code execution rights. As of right now, the socket
is world-writable. If you disagree with this threat model, you may contact
us via email (See section Email Contact below.) or [open an issue on github](https://github.com/project-repo/cagebreak/issues/new).
The main possibility for security bugs in cagebreak is by privilege
escalation through the socket. Any program with access to the socket
immediately gains arbitrary code execution rights. The socket
is restricted to the user of the cagebreak process (700).
If you disagree with this threat model, you may contact us via email (See
section Email Contact below.) or [open an issue on github](https://github.com/project-repo/cagebreak/issues/new).
Should any problem with the github issue system arise or any other reason
for (potentially confidential) contact with the Cagebreak authors appear,
@ -12,9 +14,9 @@ you may contact us via email (See section Email Contact below.).
## Supported Versions
The latest release always contains the latest bug fixes and features.
There are no official backports for security vulnerabilities. Builds
are reproducible under conditions outlined in [README.md](README.md).
The most recent release always contains the latest bug fixes and features.
There are no official backports for security vulnerabilities.
Builds are reproducible under conditions outlined in [README.md](README.md).
## Bug Reports
@ -25,11 +27,11 @@ is available below.
## Email Contact
Should you want to get in touch with the developers of cagebreak to report
If you want to get in touch with the developers of cagebreak to report
a security vulnerability or anything else via email, contact
`cagebreak @ project-repo . co`.
We will try to respond to everything that is not obvious spam.
We try to respond to everything that is not obvious spam.
### GPG-Encrypted Emails
@ -47,21 +49,23 @@ public key or provide the fingerprint and directions to obtain the key.
## Threat Model
Cagebreak is a wayland compositor, which is run by the user of the system
Cagebreak is a wayland compositor run by the user of the system
and thus has access to whichever resources this user has access to.
Cagebreak can restrict other programs in no way, because this would hamper
usability (consider a web browser unable to write a downloaded file to disk
for instance). There is no transmission of information by cagebreak other
than to the screens, ipc and potentially other documented local channels.
for instance).
There is no transmission of information by cagebreak other than to the
screens, ipc and potentially other documented local channels.
### STRIDE Threat List
This is not a thorough analysis, just an overview of the ways in which cagebreak
has/does not have an attack surface.
has (no) attack surface.
#### Spoofing
Not applicable - Using cagebreak already requires a login as a user.
Not applicable - Using Cagebreak already requires a login as a user.
#### Tampering
@ -84,7 +88,7 @@ and any software run by the user may exfiltrate any data the user has access to.
Not applicable - Cagebreak offers functionality to terminate itself, which is
available to all user software over the socket.
#### Elevation of privilege
#### Elevation of Privilege
Software may gain arbitrary code execution rights if it has access to the
Cagebreak socket. Privilege escalation to root is unlikely since privileges

View file

@ -476,10 +476,12 @@ resize_tile(struct cg_server *server, int hpixs, int vpixs) {
void
keybinding_workspace_fullscreen(struct cg_server *server) {
output_make_workspace_fullscreen(server->curr_output,server->curr_output->curr_workspace);
output_make_workspace_fullscreen(server->curr_output,
server->curr_output->curr_workspace);
struct cg_output *output = server->curr_output;
ipc_send_event(server,
"{\"event_name\":\"fullscreen\",\"tile_id\":\"%d\",\"workspace\":\"%d\",\"output\":\"%s\"}",
"{\"event_name\":\"fullscreen\",\"tile_id\":\"%d\","
"\"workspace\":\"%d\",\"output\":\"%s\"}",
output->workspaces[output->curr_workspace]->focused_tile->id,
output->workspaces[output->curr_workspace]->num + 1,
output->wlr_output->name);

View file

@ -1,4 +1,4 @@
cagebreak-config(5) "Version 1.9.0" "Cagebreak Manual"
cagebreak-config(5) "Version 2.0.0" "Cagebreak Manual"
# NAME
@ -50,13 +50,13 @@ definekey root <key> <command>
configure_message [font <font description>|[f|b]g_color <r> <g> b> <a>|display_time <n>]
Configure message characteristics -
- font <font description> sets
- <font description> is
- X core font description or
- FreeType font description via pango
- fg_color <r> <g> <b> <a> sets RGBA of foreground
- bg_color <r> <g> <b> <a> sets RGBA of background
- display_time <n> sets display time in seconds
- font <font description> sets
- <font description> is
- X core font description or
- FreeType font description via pango
- fg_color <r> <g> <b> <a> sets RGBA of foreground
- bg_color <r> <g> <b> <a> sets RGBA of background
- display_time <n> sets display time in seconds
```
# Set font
@ -218,21 +218,26 @@ message <text>
*movetonextscreen*
Move currently focused window to next screen
See *output* for differences between screen and output.
*movetoprevscreen*
Move currently focused window to previous screen
See *output* for differences between screen and output.
*movetoscreen <n>*
Move currently focused window to <n>-th screen
See *output* for differences between screen and output.
*movetoworkspace <n>*
Move currently focused window to <n>-th workspace
See *output* for differences between screen and output.
*next*
Focus next window in current tile
*nextscreen*
Focus next screen
See *output* for differences between screen and output.
*only*
Remove all splits and make current window fill the entire screen
@ -252,6 +257,14 @@ message <text>
to set priorities for outputs, where <n> >= 1. The larger <n> is,
the higher the priority is, that is to say, the earlier the output
will appear in the list of outputs.
*output* and the *screen* familiy of commands are similar in dealing
with monitors on some level.
- *output* addresses outputs by their name and is vaguely symmetric
to *input*.
- Any *screen* command deals with the number identifying a
monitor within a Cagebreak session either explicitely or
implicitly by changing it in some way (i.e. the
commands containing next and prev).
*prev*
Focus previous window in current tile
@ -276,6 +289,7 @@ message <text>
*screen <n>*
Change to <n>-th screen
See *output* for differences between screen and output.
*show_info*
Display information about the current setup - In particular, print the identifiers
@ -355,6 +369,7 @@ is used.
# SEE ALSO
*cagebreak(1)*
*cagebreak-socket(7)*
# BUGS

72
man/cagebreak-socket.7.md Normal file
View file

@ -0,0 +1,72 @@
cagebreak-socket(7) "Version 2.0.0" "Cagebreak Manual"
# NAME
*cagebreak-socket* — Cagebreak socket
# SYNOPSIS
*ipc-socket-capable-tool \$CAGEBREAK_SOCKET*
# DESCRIPTION
The cagebreak socket is an ipc socket.
The socket accepts cagebreak commands as input (see *cagebreak-config(5)* for more information).
Events are provided as output as specified in this man page.
## EVENTS
*foo <arg>*
Set x of y - <[x|y|z]> are foos
between 0 and 1.
This is a full sentence.
```
# Comment
example
```
## SECURITY
The socket is restricted to the user for reading, writing and execution (700).
All user software can execute arbitrary code while cagebreak is running.
## EXAMPLES
*nc -U $CAGEBREAK_SOCKET*
*ncat -U $CAGEBREAK_SOCKET*
# SEE ALSO
*cagebreak(1)*
*cagebreak-config(5)*
# BUGS
See GitHub Issues: <https://github.com/project-repo/cagebreak/issues>
# LICENSE
Copyright (c) 2022 The Cagebreak authors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,4 +1,4 @@
cagebreak(1) "Version 1.9.0" "Cagebreak Manual"
cagebreak(1) "Version 2.0.0" "Cagebreak Manual"
# NAME
@ -68,6 +68,7 @@ are displayed in a message box at the top right of the screen.
# SEE ALSO
*cagebreak-config(5)*
*cagebreak-socket(7)*
# BUGS

View file

@ -1,5 +1,5 @@
project('cagebreak', 'c',
version: '1.8.2',
version: '2.0.0',
license: 'MIT',
default_options: [
'c_std=c11',
@ -200,17 +200,17 @@ cagebreak_dependencies_dict = {
reproducible_build_versions = {
'server_protos': '-1',
'wayland_server': '1.19.0',
'wayland_client': '1.19.0',
'wayland_cursor': '1.19.0',
'wlroots': '0.14.1',
'xkbcommon': '1.3.1',
'fontconfig': '2.13.94',
'libinput': '1.19.2',
'libevdev': '1.12.0',
'libudev': '249',
'pango': '1.50.0',
'cairo': '1.17.4',
'pangocairo': '1.50.0',
'wayland_client': '1.21.0',
'wayland_cursor': '1.21.0',
'wlroots': '0.15.1',
'xkbcommon': '1.4.1',
'fontconfig': '2.14.0',
'libinput': '1.21.0',
'libevdev': '1.13.0',
'libudev': '251',
'pango': '1.50.10',
'cairo': '1.17.6',
'pangocairo': '1.50.10',
'math': '-1'
}
@ -236,7 +236,7 @@ foreach name, dep : cagebreak_dependencies_dict
endforeach
reproducible_build_compiler = 'gcc'
reproducible_build_compiler_version = '11.1.0'
reproducible_build_compiler_version = '12.2.0'
if cc.get_id() != reproducible_build_compiler
warning('The compiler "' + cc.get_id() + '" differs from the one used to generate to binary specified in Hashes.md (' + reproducible_build_compiler + ').')
@ -257,15 +257,18 @@ install_data('examples/config', install_dir : '/etc/xdg/cagebreak')
if get_option('man-pages')
scdoc = find_program('scdoc')
secssinceepoch = 1664566469
shcommand = 'export SOURCE_DATE_EPOCH=' + secssinceepoch.to_string() + ' ; @0@ < @INPUT@'.format(scdoc.path())
sh = find_program('sh')
mandir1 = join_paths(get_option('mandir'), 'man1')
mandir5 = join_paths(get_option('mandir'), 'man5')
mandir7 = join_paths(get_option('mandir'), 'man7')
cagebreak_man = custom_target('cagebreak_man',
output : 'cagebreak.1',
input : 'man/cagebreak.1.md',
capture : true,
command : [sh, '-c', 'export SOURCE_DATE_EPOCH=1638785664 ; @0@ < @INPUT@'.format(scdoc.path())],
capture : true,
command : [sh, '-c', shcommand],
install: true,
install_dir: mandir1
)
@ -273,11 +276,20 @@ if get_option('man-pages')
cagebreak_man = custom_target('cagebreak_config_man',
output : 'cagebreak-config.5',
input : 'man/cagebreak-config.5.md',
capture : true,
command : [sh, '-c', 'export SOURCE_DATE_EPOCH=1638785664 ; @0@ < @INPUT@'.format(scdoc.path())],
capture : true,
command : [sh, '-c', shcommand],
install: true,
install_dir: mandir5
)
cagebreak_man = custom_target('cagebreak_socket_man',
output : 'cagebreak-socket.7',
input : 'man/cagebreak-socket.7.md',
capture : true,
command : [sh, '-c', shcommand],
install: true,
install_dir: mandir7
)
endif
if get_option('fuzz')

View file

@ -224,11 +224,13 @@ message_set_output(struct cg_output *output, const char *string,
break;
}
struct wlr_scene_output *scene_output = wlr_scene_get_scene_output(output->server->scene,output->wlr_output);
struct wlr_scene_output *scene_output =
wlr_scene_get_scene_output(output->server->scene, output->wlr_output);
if(scene_output == NULL) {
return;
}
message->message=wlr_scene_buffer_create(&scene_output->scene->node,&buf->base);
message->message =
wlr_scene_buffer_create(&scene_output->scene->node, &buf->base);
wlr_scene_node_raise_to_top(&message->message->node);
wlr_scene_node_set_enabled(&message->message->node, true);
struct wlr_box *outp_box = wlr_output_layout_get_box(

View file

@ -153,7 +153,8 @@ handle_output_frame(struct wl_listener *listener, void *data) {
if(!output->wlr_output->enabled) {
return;
}
struct wlr_scene_output *scene_output=wlr_scene_get_scene_output(output->server->scene,output->wlr_output);
struct wlr_scene_output *scene_output =
wlr_scene_get_scene_output(output->server->scene, output->wlr_output);
if(scene_output == NULL) {
return;
}
@ -292,19 +293,22 @@ output_configure(struct cg_server *server, struct cg_output *output) {
}
if(config->pos.x != -1) {
if(output_set_mode(wlr_output, config->pos.width,
config->pos.height, config->refresh_rate)!=0) {
wlr_log(WLR_ERROR,"Setting output mode failed, disabling output.");
config->pos.height,
config->refresh_rate) != 0) {
wlr_log(WLR_ERROR,
"Setting output mode failed, disabling output.");
output_clear(output);
wl_list_insert(&server->disabled_outputs,&output->link);
wl_list_insert(&server->disabled_outputs, &output->link);
wlr_output_enable(wlr_output, false);
wlr_output_commit(wlr_output);
return;
}
wlr_output_layout_add(server->output_layout, wlr_output,
config->pos.x, config->pos.y);
/* Since the size of the output may have changed, we reinitialize all workspaces with a fullscreen layout */
/* Since the size of the output may have changed, we
* reinitialize all workspaces with a fullscreen layout */
for(unsigned int i = 0; i < output->server->nws; ++i) {
output_make_workspace_fullscreen(output,i);
output_make_workspace_fullscreen(output, i);
}
}
wl_list_remove(&output->link);
@ -313,17 +317,20 @@ output_configure(struct cg_server *server, struct cg_output *output) {
wlr_output_commit(wlr_output);
}
}
if(output->bg!=NULL) {
if(output->bg != NULL) {
wlr_scene_node_destroy(&output->bg->node);
output->bg=NULL;
output->bg = NULL;
}
struct wlr_scene_output *scene_output = wlr_scene_get_scene_output(output->server->scene,output->wlr_output);
struct wlr_scene_output *scene_output =
wlr_scene_get_scene_output(output->server->scene, output->wlr_output);
if(scene_output == NULL) {
return;
}
output->bg=wlr_scene_rect_create(&scene_output->scene->node, output->wlr_output->width,output->wlr_output->height, server->bg_color);
struct wlr_box *box = wlr_output_layout_get_box(
server->output_layout, output->wlr_output);
output->bg = wlr_scene_rect_create(
&scene_output->scene->node, output->wlr_output->width,
output->wlr_output->height, server->bg_color);
struct wlr_box *box =
wlr_output_layout_get_box(server->output_layout, output->wlr_output);
wlr_scene_node_set_position(&output->bg->node, box->x, box->y);
wlr_scene_node_lower_to_bottom(&output->bg->node);
}
@ -367,14 +374,13 @@ handle_output_mode(struct wl_listener *listener, void *data) {
}
void
output_make_workspace_fullscreen(struct cg_output *output,int ws) {
struct cg_server *server=output->server;
output_make_workspace_fullscreen(struct cg_output *output, int ws) {
struct cg_server *server = output->server;
struct cg_view *current_view = seat_get_focus(server->seat);
if(current_view == NULL||ws != output->curr_workspace) {
if(current_view == NULL || ws != output->curr_workspace) {
struct cg_view *it = NULL;
wl_list_for_each(it, &output->workspaces[ws]->views,
link) {
wl_list_for_each(it, &output->workspaces[ws]->views, link) {
if(view_is_visible(it)) {
current_view = it;
break;
@ -400,8 +406,6 @@ output_make_workspace_fullscreen(struct cg_output *output,int ws) {
}
}
#if CG_HAS_FANALYZE
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"

View file

@ -56,5 +56,5 @@ output_configure(struct cg_server *server, struct cg_output *output);
void
output_set_window_title(struct cg_output *output, const char *title);
void
output_make_workspace_fullscreen(struct cg_output *output,int ws);
output_make_workspace_fullscreen(struct cg_output *output, int ws);
#endif

30
seat.c
View file

@ -636,29 +636,39 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) {
wlr_idle_notify_activity(seat->server->idle, seat->seat);
/* Check if cursor switched tile */
struct wlr_output *c_outp = wlr_output_layout_output_at(seat->server->output_layout,seat->cursor->x,seat->cursor->y);
struct wlr_output *c_outp = wlr_output_layout_output_at(
seat->server->output_layout, seat->cursor->x, seat->cursor->y);
struct cg_output *cg_outp = NULL;
wl_list_for_each(cg_outp,&seat->server->outputs,link) {
wl_list_for_each(cg_outp, &seat->server->outputs, link) {
if(cg_outp->wlr_output == c_outp) {
break;
}
}
struct cg_tile *c_tile;
bool first=true;
bool first = true;
for(c_tile = cg_outp->workspaces[cg_outp->curr_workspace]->focused_tile;
first || c_tile != cg_outp->workspaces[cg_outp->curr_workspace]->focused_tile; c_tile = c_tile->next) {
first ||
c_tile != cg_outp->workspaces[cg_outp->curr_workspace]->focused_tile;
c_tile = c_tile->next) {
first = false;
double ox=seat->cursor->x,oy=seat->cursor->y;
wlr_output_layout_output_coords(seat->server->output_layout,c_outp,&ox,&oy);
if(c_tile->tile.x<=ox&&c_tile->tile.y<=oy&&c_tile->tile.x+c_tile->tile.width>=ox&&c_tile->tile.y+c_tile->tile.height>=oy) {
double ox = seat->cursor->x, oy = seat->cursor->y;
wlr_output_layout_output_coords(seat->server->output_layout, c_outp,
&ox, &oy);
if(c_tile->tile.x <= ox && c_tile->tile.y <= oy &&
c_tile->tile.x + c_tile->tile.width >= ox &&
c_tile->tile.y + c_tile->tile.height >= oy) {
break;
}
}
if(seat->cursor_tile != NULL && seat->cursor_tile != c_tile) {
ipc_send_event(seat->server, "{\"event_name\":\"cursor_switch_tile\",\"old_output\":\"%s\",\"old_tile\":\"%d\",\"new_output\":\"%s\",\"new_tile\":\"%d\"}",
seat->cursor_tile->workspace->output->wlr_output->name, seat->cursor_tile->id,c_outp->name,c_tile->id);
ipc_send_event(
seat->server,
"{\"event_name\":\"cursor_switch_tile\",\"old_output\":\"%s\","
"\"old_tile\":\"%d\",\"new_output\":\"%s\",\"new_tile\":\"%d\"}",
seat->cursor_tile->workspace->output->wlr_output->name,
seat->cursor_tile->id, c_outp->name, c_tile->id);
}
seat->cursor_tile=c_tile;
seat->cursor_tile = c_tile;
}
static void

View file

@ -16,8 +16,8 @@
#include <wlr/util/log.h>
#include "message.h"
#include "seat.h"
#include "output.h"
#include "seat.h"
#include "server.h"
#include "workspace.h"
@ -57,7 +57,8 @@ full_screen_workspace(struct cg_output *output) {
if(!workspace) {
return NULL;
}
struct wlr_scene_output *scene_output=wlr_scene_get_scene_output(output->server->scene,output->wlr_output);
struct wlr_scene_output *scene_output =
wlr_scene_get_scene_output(output->server->scene, output->wlr_output);
if(scene_output == NULL) {
free(workspace);
return NULL;
@ -92,8 +93,10 @@ void
workspace_free_tiles(struct cg_workspace *workspace) {
workspace->focused_tile->prev->next = NULL;
while(workspace->focused_tile != NULL) {
if(workspace->output->server->running&&workspace->output->server->seat->cursor_tile==workspace->focused_tile) {
workspace->output->server->seat->cursor_tile=NULL;
if(workspace->output->server->running &&
workspace->output->server->seat->cursor_tile ==
workspace->focused_tile) {
workspace->output->server->seat->cursor_tile = NULL;
}
struct cg_tile *next = workspace->focused_tile->next;
free(workspace->focused_tile);

View file

@ -64,7 +64,8 @@ activate(struct cg_view *view, bool activate) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
wlr_xwayland_surface_activate(xwayland_view->xwayland_surface, activate);
if(activate) {
wlr_xwayland_surface_restack(xwayland_view->xwayland_surface, NULL, XCB_STACK_MODE_ABOVE);
wlr_xwayland_surface_restack(xwayland_view->xwayland_surface, NULL,
XCB_STACK_MODE_ABOVE);
}
}