#define _POSIX_C_SOURCE 200112L #include #include #include "desktop.h" #include "node.h" #include "seat.h" #include "output.h" void diyac_focus_view(struct diyac_view *toplevel) { /* Note: this function only deals with keyboard focus. */ if (toplevel == NULL) { 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. */ return; } if (prev_surface) { /* * Deactivate the previously focused surface. This lets the client know * it no longer has focus and the client will repaint accordingly, e.g. * stop displaying a caret. */ struct wlr_xdg_toplevel *prev_toplevel = wlr_xdg_toplevel_try_from_wlr_surface(prev_surface); if (prev_toplevel != NULL) { 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); /* * Tell the seat to have the keyboard enter this surface. wlroots will keep * track of this and automatically send key events to the appropriate * clients without additional work on your part. */ diyac_seat_focus_surface(&server->seat, toplevel->xdg_toplevel->base->surface); } 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; if (!node_descriptor || node_descriptor->type != DIYAC_NODE_VIEW) { return NULL; } return node_descriptor->data; } void diyac_focus_topmost_view(struct diyac_server *server) { struct diyac_view *view = diyac_topmost_focusable_view(server); if (view) { diyac_focus_view(view); } else { /* * Defocus previous focused surface/view if no longer * focusable (e.g. unmapped or on a different workspace). */ diyac_seat_focus_surface(&server->seat, NULL); } } struct diyac_view *diyac_topmost_focusable_view(struct diyac_server *server) { struct wlr_surface *prev = server->seat.wlr_seat->keyboard_state.focused_surface; struct diyac_view *view; struct wl_list *node_list; struct wlr_scene_node *node; node_list = &server->view_tree->children; wl_list_for_each_reverse(node, node_list, link) { if (!node->data) { /* We found some non-view, most likely the region overlay */ continue; } view = diyac_view_from_node(node); return view; /* if (view->mapped && view_is_focusable_from(view, prev)) { return view; }*/ } return NULL; } void diyac_arrange_all_views(struct diyac_server *server) { /* * Adjust window positions/sizes. Skip views with no size since * we can't do anything useful with them; they will presumably * be initialized with valid positions/sizes later. * * We do not simply check view->mapped/been_mapped here because * views can have maximized/fullscreen geometry applied while * still unmapped. We do want to adjust the geometry of those * views. */ struct diyac_view *view; wl_list_for_each(view, &server->views, link) { diyac_view_update_geometry(view, true); } } bool diyac_view_update_geometry(struct diyac_view *view, bool resize) { assert(view); bool adjusted = false; struct wlr_box geo_box; struct wlr_box* geometry = &view->current; // if (wlr_output_layout_intersects(view->server->output_layout, // view->output->wlr_output, &view->current)) //{ struct wlr_box usable = diyac_output_usable_area(view->output); 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); switch (view->state) { case DIYAC_VIEW_MAXIMIZE: /** * We dont change the current_view geometry in maximize state * */ 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"); return false; case DIYAC_VIEW_FULL_SCREEN: wlr_log(WLR_INFO, "diyac_view_update_geometry: full-screen ignore"); return false; default: wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box); if(!wlr_box_equal(geometry, &geo_box)) { adjusted = true; } /**Normal state, recalculate current geometry*/ if (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) { geometry->y = usable.y; adjusted = true; } if((! resize) && (geometry->y + geometry->height > usable.height)) { geometry->y = usable.height - geometry->height; adjusted = true; } if (resize && geometry->width > usable.width) { geometry->width = usable.width; adjusted = true; } if (resize && geometry->height > usable.height) { geometry->height = usable.height; adjusted = true; } if (adjusted) { wlr_log(WLR_INFO, "diyac_view_update_geometry: updating geometry"); 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; } }