#define _POSIX_C_SOURCE 200112L #include #include #include "view.h" #include "node.h" #include "seat.h" #include "output.h" #include "cursor.h" static void diyac_view_set_activated(struct diyac_view * view, bool activated) { struct diyac_server *server = view->server; wlr_xdg_toplevel_set_activated(view->xdg_toplevel, activated); if(view->toplevel.handle) { wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel.handle, activated); } server->active_view = NULL; if(activated) { diyac_seat_focus_surface(&server->seat, view->xdg_toplevel->base->surface); server->active_view = view; } } 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 */ } 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) { // dont focus unmapped view return; } if(toplevel == toplevel->server->active_view) { // Don't re-focus an already focused surface. wlr_log(WLR_DEBUG, "Don't re-focus an already focused surface"); return; } if(toplevel->server->active_view) { diyac_view_set_activated(toplevel->server->active_view, false); } 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); } diyac_view_set_activated(toplevel, true); //diyac_seat_focus_surface(&server->seat, toplevel->xdg_toplevel->base->surface); /*if(toplevel->toplevel.handle) { wlr_foreign_toplevel_handle_v1_set_activated(toplevel->toplevel.handle, true); }*/ } struct diyac_view *diyac_view_at( struct diyac_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { 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, bool raise) { struct diyac_view *view = diyac_topmost_focusable_view(server); if (view) { if(raise) { struct diyac_view * root = diyac_get_root_view(view); if(root) { diyac_focus_view(root, true); return; } } diyac_focus_view(view, false); } else { wlr_log(WLR_INFO, "No view found"); /* * 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); 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, false); } } bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed) { assert(view); struct wlr_box geo_box, intersect_box; struct wlr_box *geometry = &view->original; // if (wlr_output_layout_intersects(view->server->output_layout, // view->output->wlr_output, &view->current)) //{ if (!view->mapped) { wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base); return false; } struct wlr_box usable = diyac_output_usable_area(view->output); wlr_log(WLR_DEBUG, "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; wlr_box_intersection(&intersect_box,geometry, &usable); wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box); if ( wlr_box_equal(geometry, &geo_box) && diyac_view_state_equal(view->state,view->requested) && wlr_box_empty(&intersect_box)) { wlr_log(WLR_INFO, "No geometry update needed"); return false; } // invalidate old state if change state if(view->state.fullscreen && !view->requested.fullscreen) { wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, false); if(view->toplevel.handle) { wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, false); } wlr_scene_node_set_enabled(&view->output->scenes.top->node, true); view->state.fullscreen = false; } if(view->state.maximized && !view->requested.maximized) { wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, false); if(view->toplevel.handle) { wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel.handle, false); } view->state.maximized = false; } view->state = view->requested; if(view->requested.minimized) { // TODO implement minimize return false; } else if(view->requested.fullscreen) { wlr_scene_node_set_enabled(&view->output->scenes.top->node, false); wlr_scene_node_set_position(&view->scene_tree->node, 0, 0); wlr_xdg_toplevel_set_size(view->xdg_toplevel, view->output->wlr_output->width, view->output->wlr_output->height); wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, false); if(view->toplevel.handle) { wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, true); } return true; } else if(view->requested.maximized) { 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); wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, true); if(view->toplevel.handle) { wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel.handle, true); } return true; } else { // if (wlr_output_layout_intersects(view->server->output_layout, // view->output->wlr_output, &view->current)) //{ /**Normal state, recalculate current geometry*/ struct diyac_view * root = diyac_get_root_view(view); if(!root) { root = view; } if(!root->state.fullscreen) { // Only adjust position only when not in fullscreen mode if (!grabbed && geometry->x < usable.x) { geometry->x = usable.x; } if (!grabbed && geometry->y < usable.y) { geometry->y = usable.y; } if (grabbed && server->seat.cursor->x <= usable.x) { geometry->x = usable.x - server->grab_x; } if (grabbed && server->seat.cursor->y <= usable.y) { geometry->y = usable.y; } if (grabbed && server->seat.cursor->x >= usable.x + usable.width) { geometry->x = usable.x + usable.width - server->grab_x; } if (grabbed && server->seat.cursor->y >= usable.y + usable.height) { geometry->y = usable.y + usable.height - server->grab_y; } } wlr_log(WLR_DEBUG, "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 true; } } 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; if(view->state.fullscreen) { wlr_output_layout_get_box(view->server->output_layout, view->output->wlr_output, &box); return box; } if(view->state.maximized) { return view->output->usable_area; } return view->original; } void diyac_view_set_maximize(struct diyac_view * view, bool activated) { view->requested.maximized = activated; diyac_reset_cursor_mode(view->server); diyac_view_update_geometry(view, false); } void diyac_view_set_fullscreen(struct diyac_view * view, bool activated) { view->requested.fullscreen = activated; /** * TODO: use client specific output for fullscreen * toplevel->xdg_toplevel->requested.fullscreen_output */ diyac_reset_cursor_mode(view->server); diyac_view_update_geometry(view, false); } void diyac_view_set_mimimize(struct diyac_view * view, bool activated) { // view->requested.minimized = activated; //TODO implement minimize wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base); } void diyac_view_update_title(struct diyac_view * view) { struct wlr_xdg_toplevel *xdg_toplevel = view->xdg_toplevel; if (!xdg_toplevel) { return; } const char *title = xdg_toplevel->title; wlr_log(WLR_INFO, "diyac_view_update_title: %s", title ? title : ""); if (!view->toplevel.handle || !title) { return; } wlr_foreign_toplevel_handle_v1_set_title(view->toplevel.handle, title); } void diyac_view_update_app_id(struct diyac_view * view) { struct wlr_xdg_toplevel *xdg_toplevel = view->xdg_toplevel; if (!xdg_toplevel) { return; } const char *appid = xdg_toplevel->app_id; wlr_log(WLR_INFO, "diyac_view_update_app_id: %s", appid ? appid : ""); if (!view->toplevel.handle || !appid) { return; } wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel.handle, appid); }