improve xdg + layer shell support

This commit is contained in:
DanyLE 2024-04-01 15:38:57 +02:00
parent 55719d6dba
commit a54dcb682c
13 changed files with 355 additions and 141 deletions

View File

@ -11,7 +11,7 @@ OBJS=\
output.c \
seat.c \
node.c \
desktop.c \
view.c \
xdg.c \
xdg-shell-protocol.c \
layer.c \

View File

@ -2,23 +2,60 @@
#include <wlr/util/log.h>
#include <assert.h>
#include "cursor.h"
#include "desktop.h"
#include "view.h"
#include "seat.h"
#include "node.h"
void diyac_cursor_focus(struct diyac_server *server)
{
double sx, sy;
struct wlr_surface *surface = NULL;
struct diyac_node_descriptor *desc = diyac_node_at(server,
server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy);
struct diyac_layer_surface * layer;
if(!desc)
{
return;
}
/* Focus that client if the button was _pressed_ */
switch (desc->type)
{
case DIYAC_NODE_VIEW:
diyac_focus_view(desc->data, true);
break;
case DIYAC_NODE_LAYER_SURFACE:
layer = desc->data;
assert(layer);
assert(layer->scene_layer_surface);
diyac_seat_focus_layer(&server->seat,layer->scene_layer_surface->layer_surface);
break;
default:
break;
}
}
void diyac_reset_cursor_mode(struct diyac_server *server)
{
/* Reset the cursor mode to passthrough. */
server->seat.cursor_mode = DIYAC_CURSOR_PASSTHROUGH;
server->grabbed_view = NULL;
//struct diyac_view * view = diyac_view_at()
}
static void process_cursor_move(struct diyac_server *server, uint32_t time)
{
/* Move the grabbed toplevel to the new position. */
struct diyac_view *toplevel = server->grabbed_view;
toplevel->current.x = server->seat.cursor->x - server->grab_x;
toplevel->current.y = server->seat.cursor->y - server->grab_y;
if(toplevel->state != DIYAC_VIEW_NORMAL)
{
// move the windows to cursor
server->grab_x = toplevel->original.width * server->grab_x / toplevel->output->usable_area.width;
}
toplevel->state = DIYAC_VIEW_NORMAL;
diyac_view_update_geometry(toplevel, false);
toplevel->original.y = server->seat.cursor->y - server->grab_y;
toplevel->original.x = server->seat.cursor->x - server->grab_x;
diyac_view_update_geometry(toplevel, true);
/*
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->current.x ,
@ -81,14 +118,14 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
toplevel->current.x = new_left - geo_box.x;
toplevel->current.y = new_top - geo_box.y;
toplevel->original.x = new_left - geo_box.x;
toplevel->original.y = new_top - geo_box.y;
int new_width = new_right - new_left;
int new_height = new_bottom - new_top;
toplevel->current.width = new_width;
toplevel->current.height = new_height;
toplevel->original.width = new_width;
toplevel->original.height = new_height;
toplevel->state = DIYAC_VIEW_NORMAL;
diyac_view_update_geometry(toplevel, true);
diyac_view_update_geometry(toplevel, false);
/*
wlr_scene_node_set_position(&toplevel->scene_tree->node,
toplevel->current.x, toplevel->current.y);
@ -114,9 +151,9 @@ static void process_cursor_motion(struct diyac_server *server, uint32_t time)
double sx, sy;
struct wlr_seat *seat = server->seat.wlr_seat;
struct wlr_surface *surface = NULL;
struct diyac_view *toplevel = diyac_view_at(server,
struct diyac_node_descriptor *desc = diyac_node_at(server,
server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy);
if (!toplevel)
if (!desc)
{
/* If there's no toplevel under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it
@ -191,10 +228,7 @@ static void server_cursor_button(struct wl_listener *listener, void *data)
/* Notify the client with pointer focus that a button press has occurred */
wlr_seat_pointer_notify_button(seat->wlr_seat,
event->time_msec, event->button, event->state);
double sx, sy;
struct wlr_surface *surface = NULL;
struct diyac_view *toplevel = diyac_view_at(seat->server,
seat->cursor->x, seat->cursor->y, &surface, &sx, &sy);
if (event->state == WLR_BUTTON_RELEASED)
{
/* If you released any buttons, we exit interactive move/resize mode. */
@ -202,8 +236,8 @@ static void server_cursor_button(struct wl_listener *listener, void *data)
}
else
{
/* Focus that client if the button was _pressed_ */
diyac_focus_view(toplevel);
diyac_cursor_focus(seat->server);
}
}

View File

@ -5,4 +5,5 @@
void diyac_init_cursor_manager(struct diyac_server * server);
void diyac_reset_cursor_mode(struct diyac_server *server);
void diyac_cursor_focus(struct diyac_server *server);
#endif

View File

@ -1,12 +0,0 @@
#ifndef DIYAC_DESKTOP_H
#define DIYAC_DESKTOP_H
#include "diyac.h"
void diyac_focus_view(struct diyac_view *toplevel);
struct diyac_view *diyac_view_at(
struct diyac_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy);
void diyac_focus_topmost_view(struct diyac_server *server);
struct diyac_view * diyac_topmost_focusable_view(struct diyac_server *server);
bool diyac_view_update_geometry(struct diyac_view *view, bool resize);
void diyac_arrange_all_views(struct diyac_server *server);
#endif

15
diyac.h
View File

@ -163,19 +163,20 @@ struct diyac_view
struct wlr_scene_tree *scene_tree;
enum diyac_view_state state;
/*
* Geometry of the wlr_surface contained within the view, as
* currently displayed. Should be kept in sync with the
* scene-graph at all times.
*/
struct wlr_box current;
struct diyac_output* output;
* Geometry of the wlr_surface contained within the view, as
* currently displayed. Should be kept in sync with the
* scene-graph at all times.
*/
struct wlr_box original;
bool mapped;
struct diyac_output *output;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener request_move;
struct wl_listener request_resize;
struct wl_listener request_minimize;
struct wl_listener request_maximize;
struct wl_listener request_fullscreen;

13
layer.c
View File

@ -6,6 +6,7 @@
#include "node.h"
#include "output.h"
#include "seat.h"
#include "cursor.h"
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
static struct diyac_popup *create_layer_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent);
@ -76,7 +77,6 @@ static void layer_surface_commit(struct wl_listener *listener, void *data)
/* Process keyboard-interactivity change */
if (committed & WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY)
{
wlr_log(WLR_INFO, "Process keyboard");
process_keyboard_interactivity(layer);
}
@ -89,7 +89,7 @@ static void layer_surface_commit(struct wl_listener *listener, void *data)
* enter a new/moved/resized layer surface.
*/
// cursor_update_focus(layer->server);
wlr_log(WLR_INFO, "update focus");
diyac_cursor_focus(layer->server);
}
}
static void
@ -172,10 +172,13 @@ static void popup_handle_commit(struct wl_listener *listener, void *data)
{
struct diyac_popup *popup =
wl_container_of(listener, popup, commit);
if (popup->wlr_popup->base->initial_commit)
struct wlr_box popup_box ;
wlr_xdg_surface_get_geometry(popup->wlr_popup->base, &popup_box);
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &popup->output_toplevel_sx_box);
if (!wlr_box_empty(&popup_box))
//if (popup->wlr_popup->base->initial_commit)
{
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &popup->output_toplevel_sx_box);
/* Prevent getting called over and over again */
wl_list_remove(&popup->commit.link);

30
node.c
View File

@ -34,4 +34,34 @@ struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node)
struct diyac_node_descriptor *node_descriptor = wlr_scene_node->data;
assert(node_descriptor->type == DIYAC_NODE_VIEW || node_descriptor->type == DIYAC_NODE_XDG_POPUP);
return (struct diyac_view *)node_descriptor->data;
}
struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
{
/* This returns the topmost node in the scene at the given layout coords.
* We only care about surface nodes as we are specifically looking for a
* surface in the surface tree of a diyac_view. */
struct wlr_scene_node *node = wlr_scene_node_at(
&server->scene->tree.node, lx, ly, sx, sy);
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER)
{
return NULL;
}
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(scene_buffer);
if (!scene_surface)
{
return NULL;
}
*surface = scene_surface->surface;
/* Find the node corresponding to the diyac_view at the root of this
* surface tree, it is the only one for which we set the data field. */
struct wlr_scene_tree *tree = node->parent;
while (tree != NULL && tree->node.data == NULL)
{
tree = tree->node.parent;
}
return tree->node.data;
}

1
node.h
View File

@ -5,4 +5,5 @@
void diyac_node_descriptor_create(struct wlr_scene_node *scene_node,enum diyac_node_descriptor_type type, void *data);
struct diyac_layer_surface * diyac_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node);
struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node);
struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy);
#endif

View File

@ -5,7 +5,7 @@
#include "output.h"
#include "layer.h"
#include "node.h"
#include "desktop.h"
#include "view.h"
static void output_frame(struct wl_listener *listener, void *data)
{
/* This function is called every time an output is ready to display a frame,

6
seat.c
View File

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <wlr/util/log.h>
#include "seat.h"
#include "desktop.h"
#include "view.h"
static void keyboard_handle_modifiers(
@ -48,7 +48,7 @@ static bool handle_keybinding(struct diyac_server *server, xkb_keysym_t sym)
}
struct diyac_view *next_toplevel =
wl_container_of(server->views.prev, next_toplevel, link);
diyac_focus_view(next_toplevel);
diyac_focus_view(next_toplevel, true);
break;
default:
return false;
@ -291,7 +291,7 @@ void diyac_seat_focus_surface(struct diyac_seat *seat, struct wlr_surface *surfa
}
void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1 *layer)
{
{ wlr_log(WLR_INFO, "diyac_seat_focus_layer");
if (!layer)
{
seat->focused_layer = NULL;

View File

@ -1,23 +1,35 @@
#define _POSIX_C_SOURCE 200112L
#include <wlr/util/log.h>
#include <assert.h>
#include "desktop.h"
#include "view.h"
#include "node.h"
#include "seat.h"
#include "output.h"
void diyac_focus_view(struct diyac_view *toplevel)
static void raise_to_front(struct diyac_view *view)
{
/* Move the toplevel to the front */
wlr_scene_node_raise_to_top(&view->scene_tree->node);
wl_list_remove(&view->link);
wl_list_insert(&view->server->views, &view->link);
/* Activate the new surface */
wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
}
void diyac_focus_view(struct diyac_view *toplevel, bool raise)
{
/* Note: this function only deals with keyboard focus. */
if (toplevel == NULL)
{
return;
}
if(!toplevel->mapped)
{
return;
}
struct diyac_server *server = toplevel->server;
struct wlr_surface *prev_surface = server->seat.wlr_seat->keyboard_state.focused_surface;
if (prev_surface == toplevel->xdg_toplevel->base->surface)
{
/* Don't re-focus an already focused surface. */
// Don't re-focus an already focused surface.
return;
}
if (prev_surface)
@ -34,12 +46,20 @@ void diyac_focus_view(struct diyac_view *toplevel)
wlr_xdg_toplevel_set_activated(prev_toplevel, false);
}
}
/* Move the toplevel to the front */
wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
wl_list_remove(&toplevel->link);
wl_list_insert(&server->views, &toplevel->link);
/* Activate the new surface */
wlr_xdg_toplevel_set_activated(toplevel->xdg_toplevel, true);
raise_to_front(toplevel);
if (raise)
{
struct diyac_view **subview = NULL;
struct wl_array subviews;
wl_array_init(&subviews);
diyac_get_children_views(toplevel, &subviews);
wl_array_for_each(subview, &subviews)
{
raise_to_front(*subview);
}
wl_array_release(&subviews);
}
/*
* Tell the seat to have the keyboard enter this surface. wlroots will keep
* track of this and automatically send key events to the appropriate
@ -52,46 +72,21 @@ struct diyac_view *diyac_view_at(
struct diyac_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy)
{
/* This returns the topmost node in the scene at the given layout coords.
* We only care about surface nodes as we are specifically looking for a
* surface in the surface tree of a diyac_view. */
struct wlr_scene_node *node = wlr_scene_node_at(
&server->scene->tree.node, lx, ly, sx, sy);
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER)
{
return NULL;
}
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(scene_buffer);
if (!scene_surface)
{
return NULL;
}
*surface = scene_surface->surface;
/* Find the node corresponding to the diyac_view at the root of this
* surface tree, it is the only one for which we set the data field. */
struct wlr_scene_tree *tree = node->parent;
while (tree != NULL && tree->node.data == NULL)
{
tree = tree->node.parent;
}
struct diyac_node_descriptor *node_descriptor = tree->node.data;
struct diyac_node_descriptor *node_descriptor = diyac_node_at(server,lx,ly,surface,sx,sy);
if (!node_descriptor || node_descriptor->type != DIYAC_NODE_VIEW)
{
return NULL;
}
return node_descriptor->data;
}
void diyac_focus_topmost_view(struct diyac_server *server)
{
wlr_log(WLR_INFO, "diyac_focus_topmost_view");
struct diyac_view *view = diyac_topmost_focusable_view(server);
if (view)
{
diyac_focus_view(view);
diyac_focus_view(view, false);
}
else
{
@ -120,11 +115,11 @@ struct diyac_view *diyac_topmost_focusable_view(struct diyac_server *server)
}
view = diyac_view_from_node(node);
return view;
/*
if (view->mapped && view_is_focusable_from(view, prev))
if (view->mapped /*&& view_is_focusable_from(view, prev)*/)
{
return view;
}*/
}
}
return NULL;
}
@ -144,15 +139,15 @@ void diyac_arrange_all_views(struct diyac_server *server)
struct diyac_view *view;
wl_list_for_each(view, &server->views, link)
{
diyac_view_update_geometry(view, true);
diyac_view_update_geometry(view, false);
}
}
bool diyac_view_update_geometry(struct diyac_view *view, bool resize)
bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
{
assert(view);
bool adjusted = false;
struct wlr_box geo_box;
struct wlr_box* geometry = &view->current;
struct wlr_box *geometry = &view->original;
// if (wlr_output_layout_intersects(view->server->output_layout,
// view->output->wlr_output, &view->current))
//{
@ -160,67 +155,133 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool resize)
wlr_log(WLR_INFO, "diyac_view_update_geometry: current: [%d,%d,%d,%d], usable: [%d,%d,%d,%d] ",
geometry->x, geometry->y, geometry->width, geometry->height,
usable.x, usable.y, usable.width, usable.height);
struct diyac_server *server = view->server;
if (!view->mapped)
{
wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, false);
wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, false);
// the view has not yet be mapped, don't maximize it
wlr_log(WLR_INFO, "The view has not yet be mapped, ignore request");
view->state = DIYAC_VIEW_NORMAL;
return false;
}
switch (view->state)
{
case DIYAC_VIEW_MAXIMIZE:
/**
* We dont change the current_view geometry in maximize state
*
*
*/
wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, true);
wlr_scene_node_set_position(&view->scene_tree->node, usable.x, usable.y);
wlr_xdg_toplevel_set_size(view->xdg_toplevel, usable.width, usable.height);
return true;
case DIYAC_VIEW_MINIMIZE:
wlr_log(WLR_INFO, "diyac_view_update_geometry: minimize ignore");
view->state = DIYAC_VIEW_NORMAL;
wlr_log(WLR_INFO, "diyac_view_update_geometry: minimize ignore");
return false;
case DIYAC_VIEW_FULL_SCREEN:
/*TODO: implement full-screen */
//view->state = DIYAC_VIEW_NORMAL;
wlr_log(WLR_INFO, "diyac_view_update_geometry: full-screen ignore");
wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, false);
return false;
default:
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
if(!wlr_box_equal(geometry, &geo_box))
if (!wlr_box_equal(geometry, &geo_box))
{
adjusted = true;
}
// if (wlr_output_layout_intersects(view->server->output_layout,
// view->output->wlr_output, &view->current))
//{
/**Normal state, recalculate current geometry*/
if (geometry->x < usable.x)
if (!grabbed && geometry->x < usable.x)
{
geometry->x = usable.x;
adjusted = true;
}
if((! resize) && (geometry->x + geometry->width > usable.width))
{
geometry->x = usable.width - geometry->width;
adjusted = true;
}
if (geometry->y < usable.y)
if (!grabbed && geometry->y < usable.y)
{
geometry->y = usable.y;
adjusted = true;
}
if((! resize) && (geometry->y + geometry->height > usable.height))
if (grabbed && server->seat.cursor->x <= usable.x)
{
geometry->y = usable.height - geometry->height;
geometry->x = usable.x - server->grab_x;
adjusted = true;
}
if (resize && geometry->width > usable.width)
if (grabbed && server->seat.cursor->y <= usable.y)
{
geometry->width = usable.width;
geometry->y = usable.y;
adjusted = true;
}
if (resize && geometry->height > usable.height)
if (grabbed && server->seat.cursor->x >= usable.x + usable.width)
{
geometry->height = usable.height;
geometry->x = usable.x + usable.width - server->grab_x;
adjusted = true;
}
if (grabbed && server->seat.cursor->y >= usable.y + usable.height)
{
geometry->y = usable.y + usable.height - server->grab_y;
adjusted = true;
}
if (adjusted)
{
wlr_log(WLR_INFO, "diyac_view_update_geometry: updating geometry");
wlr_log(WLR_INFO, "diyac_view_update_geometry: updating geometry: %d %d %d %d", geometry->x, geometry->y, geometry->width, geometry->height);
wlr_scene_node_set_position(&view->scene_tree->node, geometry->x, geometry->y);
wlr_xdg_toplevel_set_size(view->xdg_toplevel, geometry->width, geometry->height);
}
return adjusted;
}
}
void diyac_get_children_views(struct diyac_view *view, struct wl_array *children)
{
struct diyac_view *child;
wl_list_for_each_reverse(child, &view->server->views, link)
{
if (child == view)
{
continue;
}
if (!child->mapped /*&& !view->minimized*/)
{
continue;
}
if (diyac_get_root_view(child) != view)
{
continue;
}
struct diyac_view **item = wl_array_add(children, sizeof(*item));
*item = child;
}
}
struct diyac_view *diyac_get_root_view(struct diyac_view *view)
{
struct wlr_xdg_toplevel *toplevel = view->xdg_toplevel;
while (toplevel->parent)
{
toplevel = toplevel->parent;
}
return toplevel->base->data;
}
struct wlr_box diyac_view_get_geometry(struct diyac_view *view)
{
struct wlr_box box;
switch(view->state)
{
case DIYAC_VIEW_FULL_SCREEN:
wlr_output_layout_get_box(view->server->output_layout, view->output->wlr_output, &box);
return box;
case DIYAC_VIEW_MAXIMIZE:
return view->output->usable_area;
default:
return view->original;
}
}

15
view.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef DIYAC_VIEW_H
#define DIYAC_VIEW_H
#include "diyac.h"
void diyac_focus_view(struct diyac_view *toplevel, bool raise);
struct diyac_view *diyac_view_at(
struct diyac_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy);
void diyac_focus_topmost_view(struct diyac_server *server);
struct diyac_view * diyac_topmost_focusable_view(struct diyac_server *server);
bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed);
void diyac_arrange_all_views(struct diyac_server *server);
struct diyac_view *diyac_get_root_view(struct diyac_view *view);
void diyac_get_children_views(struct diyac_view *view, struct wl_array *children);
struct wlr_box diyac_view_get_geometry(struct diyac_view *view);
#endif

144
xdg.c
View File

@ -5,7 +5,7 @@
#include "xdg.h"
#include "cursor.h"
#include "node.h"
#include "desktop.h"
#include "view.h"
#include "output.h"
static void xdg_popup_create(struct diyac_view *view, struct wlr_xdg_popup *wlr_popup);
@ -14,7 +14,7 @@ static void begin_interactive(struct diyac_view *toplevel,
enum diyac_cursor_mode mode, uint32_t edges)
{
/* This function sets up an interactive move or resize operation, where the
* compositor stops propegating pointer events to clients and instead
* compositor stops propagating pointer events to clients and instead
* consumes them itself, to move or resize windows. */
struct diyac_server *server = toplevel->server;
struct wlr_surface *focused_surface =
@ -57,24 +57,52 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data)
{
/* Called when the surface is mapped, or ready to display on-screen. */
struct diyac_view *toplevel = wl_container_of(listener, toplevel, map);
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &toplevel->current);
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &toplevel->original);
wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true);
toplevel->mapped = true;
wl_list_insert(&toplevel->server->views, &toplevel->link);
diyac_focus_view(toplevel);
toplevel->original.x = (toplevel->output->usable_area.width - toplevel->original.width) / 2;
toplevel->original.y = (toplevel->output->usable_area.height - toplevel->original.height) / 2;
if(toplevel->original.width > toplevel->output->usable_area.width)
{
toplevel->original.width = toplevel->output->usable_area.width;
}
if(toplevel->original.height > toplevel->output->usable_area.height)
{
toplevel->original.height = toplevel->output->usable_area.height;
}
diyac_view_update_geometry(toplevel, false);
if (toplevel->state != DIYAC_VIEW_MINIMIZE)
{
diyac_focus_view(toplevel, false);
}
}
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
{
/* Called when the surface is unmapped, and should no longer be shown. */
struct diyac_view *toplevel = wl_container_of(listener, toplevel, unmap);
toplevel->mapped = false;
/* Reset the cursor mode if the grabbed toplevel was unmapped. */
if (toplevel == toplevel->server->grabbed_view)
{
diyac_reset_cursor_mode(toplevel->server);
}
if(toplevel->server->grabbed_view == toplevel)
{
toplevel->server->grabbed_view = NULL;
}
struct diyac_view * root = diyac_get_root_view(toplevel);
wl_list_remove(&toplevel->link);
if(root)
{
diyac_focus_view(root, true);
}
else
{
diyac_cursor_focus(toplevel->server);
}
}
static void xdg_toplevel_request_move(
@ -128,35 +156,60 @@ static void xdg_toplevel_request_maximize(
}
struct diyac_output * target_output = output->data;
*/
if(toplevel->state == DIYAC_VIEW_MAXIMIZE)
wlr_log(WLR_INFO, "Request maximize");
diyac_reset_cursor_mode(toplevel->server);
if (toplevel->state == DIYAC_VIEW_MAXIMIZE)
{
toplevel->state = DIYAC_VIEW_NORMAL;
wlr_xdg_toplevel_set_maximized(toplevel->xdg_toplevel, false);
// restore its default geometry
}
else
{
toplevel->state = DIYAC_VIEW_MAXIMIZE;
}
diyac_view_update_geometry(toplevel, true);
// wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
diyac_view_update_geometry(toplevel, false);
//wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
}
static void xdg_toplevel_request_fullscreen(
struct wl_listener *listener, void *data)
{
/* Just as with request_maximize, we must send a configure here. */
struct diyac_view *toplevel =
wl_container_of(listener, toplevel, request_fullscreen);
if(toplevel->state == DIYAC_VIEW_FULL_SCREEN)
wlr_log(WLR_INFO, "Request fullscreen");
/*
diyac_reset_cursor_mode(toplevel->server);
if (toplevel->state == DIYAC_VIEW_FULL_SCREEN)
{
toplevel->state = DIYAC_VIEW_NORMAL;
wlr_xdg_toplevel_set_fullscreen(toplevel->xdg_toplevel, false);
// restore its default geometry
}
else
{
toplevel->state = DIYAC_VIEW_FULL_SCREEN;
}
diyac_view_update_geometry(toplevel, true);
*/
diyac_view_update_geometry(toplevel, false);
}
static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data)
{
struct diyac_view *toplevel =
wl_container_of(listener, toplevel, request_minimize);
if (toplevel->state == DIYAC_VIEW_MINIMIZE)
{
toplevel->state = DIYAC_VIEW_NORMAL;
// restore its default geometry
}
else
{
toplevel->state = DIYAC_VIEW_MINIMIZE;
}
diyac_view_update_geometry(toplevel, false);
wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
}
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
@ -171,7 +224,6 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&toplevel->request_resize.link);
wl_list_remove(&toplevel->request_maximize.link);
wl_list_remove(&toplevel->request_fullscreen.link);
free(toplevel);
}
@ -189,40 +241,51 @@ static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
free(popup);
}
static void
popup_unconstrain(struct diyac_popup *popup)
static void popup_unconstrain(struct diyac_popup *popup)
{
struct diyac_view *view = popup->parent;
struct diyac_server *server = view->server;
struct wlr_box *popup_box = &popup->wlr_popup->current.geometry;
struct wlr_output_layout *output_layout = server->output_layout;
struct wlr_output *wlr_output = wlr_output_layout_output_at(
output_layout, view->current.x + popup_box->x,
view->current.y + popup_box->y);
struct wlr_output *wlr_output = view->output->wlr_output;
struct wlr_box output_box;
wlr_output_layout_get_box(output_layout, wlr_output, &output_box);
struct wlr_box geo_box = diyac_view_get_geometry(view);
struct wlr_box output_toplevel_box = {
.x = output_box.x - view->current.x,
.y = output_box.y - view->current.y,
.width = output_box.width,
.height = output_box.height,
.x = view->output->usable_area.x - geo_box.x,
.y = view->output->usable_area.y - geo_box.y,
.width = view->output->usable_area.width,
.height = view->output->usable_area.height,
};
wlr_log(WLR_INFO, "Un constrain popup geometry: current x %d, y %d, popup [%d, %d, %d, %d] output_box: [%d, %d, %d, %d], caculate_box: [%d, %d, %d, %d]",
view->original.x, view->original.y,
geo_box.x, geo_box.y, geo_box.width, geo_box.height,
output_box.x, output_box.y, output_box.width, output_box.height,
output_toplevel_box.x, output_toplevel_box.y, output_toplevel_box.width, output_toplevel_box.height
);
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box);
}
static void handle_xdg_popup_commit(struct wl_listener *listener, void *data)
{
struct diyac_popup *popup = wl_container_of(listener, popup, commit);
if (popup->wlr_popup->base->initial_commit)
struct wlr_box popup_box ;
wlr_xdg_surface_get_geometry(popup->wlr_popup->base, &popup_box);
popup_unconstrain(popup);
if (!wlr_box_empty(&popup_box))
//if (popup->wlr_popup->base->initial_commit)
{
popup_unconstrain(popup);
struct diyac_view *view = popup->parent;
//wlr_output_commit(view->output->wlr_output);
/* Prevent getting called over and over again */
wl_list_remove(&popup->commit.link);
popup->commit.notify = NULL;
// force commit output
}
else
{
wlr_log(WLR_INFO, "ignore commit 2");
}
}
@ -230,6 +293,7 @@ static void handle_xdg_popup_new(struct wl_listener *listener, void *data)
{
struct diyac_popup *popup = wl_container_of(listener, popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
xdg_popup_create(popup->parent, wlr_popup);
}
@ -275,15 +339,25 @@ static void xdg_popup_create(struct diyac_view *view, struct wlr_xdg_popup *wlr_
else
{
parent_tree = view->server->xdg_popup_tree;
struct wlr_box box = diyac_view_get_geometry(view);
wlr_scene_node_set_position(&view->server->xdg_popup_tree->node,
view->current.x, view->current.y);
box.x, box.y);
}
wlr_popup->base->surface->data =
wlr_scene_xdg_surface_create(parent_tree, wlr_popup->base);
struct wlr_scene_tree* tree= wlr_scene_xdg_surface_create(parent_tree, wlr_popup->base);
wlr_popup->base->surface->data = tree;
//wlr_scene_node_set_enabled(&parent_tree->node, false);
diyac_node_descriptor_create(wlr_popup->base->surface->data,
DIYAC_NODE_XDG_POPUP, view);
}
static void xdg_set_appid_notify(struct wl_listener *listener, void *data)
{
struct diyac_view *xdg_toplevel_view =
wl_container_of(listener, xdg_toplevel_view, set_app_id);
wlr_log(WLR_INFO, "set application id");
}
static void xdg_new_popup_notify(struct wl_listener *listener, void *data)
{
wlr_log(WLR_INFO, "xdg_new_popup_notify: Creating new dialog");
@ -328,12 +402,14 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
toplevel->server = server;
toplevel->xdg_toplevel = xdg_surface->toplevel;
toplevel->xdg_surface = xdg_surface;
toplevel->mapped = false;
toplevel->output = diyac_output_from_cursor(server);
toplevel->scene_tree = wlr_scene_xdg_surface_create(
toplevel->server->view_tree, toplevel->xdg_toplevel->base);
xdg_surface->data = toplevel;
wlr_scene_node_set_enabled(&toplevel->scene_tree->node, false);
diyac_node_descriptor_create(&toplevel->scene_tree->node,
DIYAC_NODE_VIEW, toplevel);
DIYAC_NODE_VIEW, toplevel);
/* Listen to the various events it can emit */
toplevel->map.notify = xdg_toplevel_map;
wl_signal_add(&xdg_surface->surface->events.map, &toplevel->map);
@ -348,6 +424,8 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move);
toplevel->request_resize.notify = xdg_toplevel_request_resize;
wl_signal_add(&xdg_toplevel->events.request_resize, &toplevel->request_resize);
toplevel->request_minimize.notify = xdg_toplevel_request_minimize;
wl_signal_add(&xdg_toplevel->events.request_minimize, &toplevel->request_minimize);
toplevel->request_maximize.notify = xdg_toplevel_request_maximize;
wl_signal_add(&xdg_toplevel->events.request_maximize,
&toplevel->request_maximize);
@ -356,4 +434,6 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
&toplevel->request_fullscreen);
toplevel->new_popup.notify = xdg_new_popup_notify;
wl_signal_add(&xdg_surface->events.new_popup, &toplevel->new_popup);
toplevel->set_app_id.notify = xdg_set_appid_notify;
wl_signal_add(&xdg_toplevel->events.set_app_id, &toplevel->set_app_id);
}