Skip to content

Commit

Permalink
wayland: rewrite fullscreen detection
Browse files Browse the repository at this point in the history
  • Loading branch information
fwsmit committed Oct 11, 2021
1 parent 72b2509 commit d2b4930
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 68 deletions.
63 changes: 40 additions & 23 deletions src/wayland/foreign_toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
/* #include "protocols/wlr-foreign-toplevel-management-unstable-v1.h" */

#include "foreign_toplevel.h"
#include "../dunst.h"
#include "wl_output.h"
#include "wl.h"

struct wl_list toplevel_list;

Expand Down Expand Up @@ -33,16 +36,6 @@ static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) {
}

static void print_toplevel_state(struct toplevel_v1 *toplevel, bool print_endl) {
if (toplevel->current.state & TOPLEVEL_STATE_MAXIMIZED) {
printf(" maximized");
} else {
printf(" unmaximized");
}
if (toplevel->current.state & TOPLEVEL_STATE_MINIMIZED) {
printf(" minimized");
} else {
printf(" unminimized");
}
if (toplevel->current.state & TOPLEVEL_STATE_ACTIVATED) {
printf(" active");
} else {
Expand All @@ -59,30 +52,42 @@ static void print_toplevel_state(struct toplevel_v1 *toplevel, bool print_endl)

static void toplevel_handle_output_enter(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel,
struct wl_output *output) {
struct wl_output *wl_output) {
struct toplevel_v1 *toplevel = data;
struct toplevel_output *toplevel_output = calloc(1, sizeof(struct toplevel_output));
struct dunst_output *dunst_output = wl_output_get_user_data(wl_output);
toplevel_output->dunst_output = dunst_output;

print_toplevel(toplevel, false);
printf(" enter output %u\n",
(uint32_t)(size_t)wl_output_get_user_data(output));
printf(" enter output %u\n", dunst_output->global_name);
wl_list_insert(&toplevel->output_list, &toplevel_output->link);
struct toplevel_output *pos;
printf("Output list size %i\n", wl_list_length(&toplevel->output_list));
wl_list_for_each(pos, &toplevel->output_list, link) {
printf("Testing fullscreen output %i\n", pos->dunst_output->global_name);
}
}

static void toplevel_handle_output_leave(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel,
struct wl_output *output) {
struct wl_output *wl_output) {
struct toplevel_v1 *toplevel = data;
print_toplevel(toplevel, false);
printf(" leave output %u\n",
(uint32_t)(size_t)wl_output_get_user_data(output));

struct dunst_output *output = wl_output_get_user_data(wl_output);
printf(" leave output %u\n", output->global_name);
struct toplevel_output *pos, *tmp;
wl_list_for_each_safe(pos, tmp, &toplevel->output_list, link){
if (pos->dunst_output->name == output->name){
wl_list_remove(&pos->link);
}
}
}

static uint32_t array_to_state(struct wl_array *array) {
uint32_t state = 0;
uint32_t *entry;
wl_array_for_each(entry, array) {
if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED)
state |= TOPLEVEL_STATE_MAXIMIZED;
if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED)
state |= TOPLEVEL_STATE_MINIMIZED;
if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED)
state |= TOPLEVEL_STATE_ACTIVATED;
if (*entry == ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN)
Expand All @@ -102,13 +107,17 @@ static void toplevel_handle_state(void *data,
static void toplevel_handle_done(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
struct toplevel_v1 *toplevel = data;
bool state_changed = toplevel->current.state != toplevel->pending.state;

bool was_fullscreen = wl_have_fullscreen_window();
copy_state(&toplevel->current, &toplevel->pending);
bool is_fullscreen = wl_have_fullscreen_window();

print_toplevel(toplevel, !state_changed);
if (state_changed) {
/* print_toplevel(toplevel, !state_changed); */
if (was_fullscreen != is_fullscreen) {
print_toplevel(toplevel, false);
print_toplevel_state(toplevel, true);
// TODO only wake up when important
wake_up();
}
}

Expand All @@ -118,6 +127,12 @@ static void toplevel_handle_closed(void *data,
print_toplevel(toplevel, false);
printf(" closed\n");

wl_list_remove(&toplevel->link);
struct toplevel_output *pos, *tmp;
wl_list_for_each_safe(pos, tmp, &toplevel->output_list, link){
free(pos);
}
free(toplevel);
zwlr_foreign_toplevel_handle_v1_destroy(zwlr_toplevel);
}

Expand All @@ -144,6 +159,7 @@ static void toplevel_manager_handle_toplevel(void *data,
toplevel->id = global_id++;
toplevel->zwlr_toplevel = zwlr_toplevel;
wl_list_insert(&toplevel_list, &toplevel->link);
wl_list_init(&toplevel->output_list);

zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl,
toplevel);
Expand All @@ -158,3 +174,4 @@ const struct zwlr_foreign_toplevel_manager_v1_listener toplevel_manager_impl = {
.toplevel = toplevel_manager_handle_toplevel,
.finished = toplevel_manager_handle_finished,
};
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
15 changes: 10 additions & 5 deletions src/wayland/foreign_toplevel.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
#include <wayland-client.h>

enum toplevel_state_field {
TOPLEVEL_STATE_MAXIMIZED = (1 << 0),
TOPLEVEL_STATE_MINIMIZED = (1 << 1),
TOPLEVEL_STATE_ACTIVATED = (1 << 2),
TOPLEVEL_STATE_FULLSCREEN = (1 << 3),
TOPLEVEL_STATE_INVALID = (1 << 4),
TOPLEVEL_STATE_ACTIVATED = (1 << 0),
TOPLEVEL_STATE_FULLSCREEN = (1 << 1),
TOPLEVEL_STATE_INVALID = (1 << 2),
};

struct toplevel_state {
Expand All @@ -17,12 +15,19 @@ struct toplevel_state {
struct toplevel_v1 {
struct wl_list link;
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel;
struct wl_list output_list;

uint32_t id;
struct toplevel_state current, pending;
};

struct toplevel_output {
struct dunst_output *dunst_output;
struct wl_list link;
};

extern const struct zwlr_foreign_toplevel_manager_v1_listener toplevel_manager_impl;

extern struct wl_list toplevel_list;
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
72 changes: 32 additions & 40 deletions src/wayland/wl.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "../input.h"
#include "libgwater-wayland.h"
#include "foreign_toplevel.h"
#include "wl_output.h"

#define MAX_TOUCHPOINTS 10

Expand Down Expand Up @@ -61,6 +62,7 @@ struct wl_ctx {
struct wl_callback *frame_callback;
struct org_kde_kwin_idle *idle_handler;
struct org_kde_kwin_idle_timeout *idle_timeout;
uint32_t toplevel_manager_name;
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager;
bool configured;
bool dirty;
Expand Down Expand Up @@ -89,18 +91,6 @@ struct wl_ctx {
struct wl_surface *cursor_surface;
};

struct dunst_output {
uint32_t global_name;
char *name;
struct wl_output *wl_output;
struct wl_list link;

uint32_t scale;
uint32_t subpixel; // TODO do something with it
bool fullscreen;
struct zwlr_foreign_toplevel_handle_v1 *fullscreen_toplevel; // the toplevel that is fullscreened on this output
};

struct wl_ctx ctx;

static void noop() {
Expand Down Expand Up @@ -414,12 +404,8 @@ static void handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, zwlr_foreign_toplevel_manager_v1_interface.name) == 0 &&
version >= ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN_SINCE_VERSION) {
LOG_W("Found toplevel manager %i", name);
ctx.toplevel_manager = wl_registry_bind(registry, name,
&zwlr_foreign_toplevel_manager_v1_interface,
2);
wl_list_init(&toplevel_list);
zwlr_foreign_toplevel_manager_v1_add_listener(ctx.toplevel_manager,
&toplevel_manager_impl, NULL);
ctx.toplevel_manager_name = name;
wl_list_init(&toplevel_list);
}
}

Expand Down Expand Up @@ -450,10 +436,19 @@ bool wl_init() {
return false;
}

ctx.toplevel_manager_name = UINT32_MAX;

ctx.registry = wl_display_get_registry(ctx.display);
wl_registry_add_listener(ctx.registry, &registry_listener, NULL);
LOG_W("First roundtrip");
wl_display_roundtrip(ctx.display);
if (ctx.toplevel_manager_name != UINT32_MAX) {
ctx.toplevel_manager = wl_registry_bind(ctx.registry, ctx.toplevel_manager_name,
&zwlr_foreign_toplevel_manager_v1_interface,
2);
zwlr_foreign_toplevel_manager_v1_add_listener(ctx.toplevel_manager,
&toplevel_manager_impl, NULL);
}
LOG_W("Second roundtrip");
wl_display_roundtrip(ctx.display); // load list of toplevels
LOG_W("Third roundtrip");
Expand Down Expand Up @@ -827,33 +822,30 @@ bool wl_is_idle(void) {
}

bool wl_have_fullscreen_window(void) {
bool have_fullscreen = false;
struct dunst_output *current_output = get_configured_output();
uint32_t output_name = UINT32_MAX;
if (current_output)
output_name = current_output->global_name;

struct toplevel_v1 *toplevel;
wl_list_for_each(toplevel, &toplevel_list, link) {
if (toplevel->current.state & TOPLEVEL_STATE_FULLSCREEN) {
LOG_D("Fullscreen queried: true");
return true;
}
}

struct dunst_output *current_output = get_configured_output();

if (!current_output) {
// Cannot detect focused output, so return true if any of the
// outputs is fullscreen. This will work even when unfocused
// outputs have fullscreen toplevels, since a toplevel has to
// be fullscreen and activate to consider an output fullscreen.
struct dunst_output *output;
wl_list_for_each(output, &ctx.outputs, link) {
have_fullscreen |= output->fullscreen;
if (!(toplevel->current.state & TOPLEVEL_STATE_FULLSCREEN &&
toplevel->current.state &
TOPLEVEL_STATE_ACTIVATED))
continue;

struct toplevel_output *pos;
wl_list_for_each(pos, &toplevel->output_list, link) {
if (output_name == UINT32_MAX ||
pos->dunst_output->global_name ==
output_name) {
LOG_D("Fullscreen queried: 1");
return true;
}
}
} else {
have_fullscreen = current_output->fullscreen;
}

LOG_D("Fullscreen queried: %i", have_fullscreen);
return have_fullscreen;
LOG_D("Fullscreen queried: 0");
return false;
}

double wl_get_scale(void) {
Expand Down

0 comments on commit d2b4930

Please sign in to comment.