From a54dcb682c6d2cc3ed447f815e9b7c3d4ae4e8a7 Mon Sep 17 00:00:00 2001 From: DanyLE Date: Mon, 1 Apr 2024 15:38:57 +0200 Subject: [PATCH] improve xdg + layer shell support --- Makefile | 2 +- cursor.c | 68 ++++++++++++---- cursor.h | 1 + desktop.h | 12 --- diyac.h | 15 ++-- layer.c | 13 +-- node.c | 30 +++++++ node.h | 1 + output.c | 2 +- seat.c | 6 +- desktop.c => view.c | 187 +++++++++++++++++++++++++++++--------------- view.h | 15 ++++ xdg.c | 144 ++++++++++++++++++++++++++-------- 13 files changed, 355 insertions(+), 141 deletions(-) delete mode 100644 desktop.h rename desktop.c => view.c (56%) create mode 100644 view.h diff --git a/Makefile b/Makefile index e916472..6d3eddc 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ OBJS=\ output.c \ seat.c \ node.c \ - desktop.c \ + view.c \ xdg.c \ xdg-shell-protocol.c \ layer.c \ diff --git a/cursor.c b/cursor.c index 5ab8f55..836ca4d 100644 --- a/cursor.c +++ b/cursor.c @@ -2,23 +2,60 @@ #include #include #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); + } } diff --git a/cursor.h b/cursor.h index 334e74c..e96a9fc 100644 --- a/cursor.h +++ b/cursor.h @@ -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 \ No newline at end of file diff --git a/desktop.h b/desktop.h deleted file mode 100644 index 07ca32c..0000000 --- a/desktop.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/diyac.h b/diyac.h index 4c1ccc2..775da04 100644 --- a/diyac.h +++ b/diyac.h @@ -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; diff --git a/layer.c b/layer.c index cf54c72..b005e70 100644 --- a/layer.c +++ b/layer.c @@ -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); diff --git a/node.c b/node.c index 3aa608b..5faae26 100644 --- a/node.c +++ b/node.c @@ -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; } \ No newline at end of file diff --git a/node.h b/node.h index 09ee32d..710850c 100644 --- a/node.h +++ b/node.h @@ -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 diff --git a/output.c b/output.c index 621020c..4df26e9 100644 --- a/output.c +++ b/output.c @@ -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, diff --git a/seat.c b/seat.c index 29f1ccf..ae5f998 100644 --- a/seat.c +++ b/seat.c @@ -4,7 +4,7 @@ #include #include #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; diff --git a/desktop.c b/view.c similarity index 56% rename from desktop.c rename to view.c index 843a36d..0aa8760 100644 --- a/desktop.c +++ b/view.c @@ -1,23 +1,35 @@ #define _POSIX_C_SOURCE 200112L #include #include -#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; + } } \ No newline at end of file diff --git a/view.h b/view.h new file mode 100644 index 0000000..93778ad --- /dev/null +++ b/view.h @@ -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 \ No newline at end of file diff --git a/xdg.c b/xdg.c index 87bffed..0087867 100644 --- a/xdg.c +++ b/xdg.c @@ -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); } \ No newline at end of file