swayc_t *focus_pointer(void) { swayc_t *focused = get_focused_container(&root_container); if (!(wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN)) { swayc_t *pointer = find_container(&root_container, pointer_test, &mouse_origin); if (pointer && focused != pointer) { unfocus_all(&root_container); focus_view(pointer); } else if (!focused) { focus_view(active_workspace); } focused = pointer; } return focused; }
static void relayout(struct wlc_space *space) { if (!space) return; struct wl_list *views; if (!(views = wlc_space_get_userdata(space))) return; uint32_t rwidth, rheight; struct wlc_output *output = wlc_space_get_output(space); wlc_output_get_resolution(output, &rwidth, &rheight); struct wlc_view *v; uint32_t count = 0; wlc_view_for_each_user(v, views) if (is_tiled(v)) ++count; bool toggle = false; uint32_t y = 0, height = rheight / (count > 1 ? count - 1 : 1); uint32_t fheight = (rheight > height * (count - 1) ? height + (rheight - height * (count - 1)) : height); wlc_view_for_each_user(v, views) { if (wlc_view_get_state(v) & WLC_BIT_FULLSCREEN) { wlc_view_resize(v, rwidth, rheight); wlc_view_position(v, 0, 0); } if (wlc_view_get_type(v) & WLC_BIT_SPLASH) wlc_view_position(v, rwidth * 0.5 - wlc_view_get_width(v) * 0.5, rheight * 0.5 - wlc_view_get_height(v) * 0.5); struct wlc_view *parent; if (is_managed(v) && !is_or(v) && (parent = wlc_view_get_parent(v))) layout_parent(v, parent, wlc_view_get_width(v), wlc_view_get_height(v)); if (!is_tiled(v)) continue; uint32_t slave = rwidth * loliwm.cut; wlc_view_set_state(v, WLC_BIT_MAXIMIZED, true); wlc_view_resize(v, (count > 1 ? (toggle ? slave : rwidth - slave) : rwidth), (toggle ? (y == 0 ? fheight : height) : rheight)); wlc_view_position(v, (toggle ? rwidth - slave : 0), y); if (toggle) y += (y == 0 ? fheight : height); toggle = true; } }
static bool handle_view_created(wlc_handle handle) { swayc_t *focused = get_focused_container(&root_container); uint32_t type = wlc_view_get_type(handle); // If override_redirect/unmanaged/popup/modal/splach if (type) { sway_log(L_DEBUG,"Unmanaged window of type %x left alone", type); wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); if (type & WLC_BIT_UNMANAGED) { return true; } // For things like Dmenu if (type & WLC_BIT_OVERRIDE_REDIRECT) { override_redirect = true; wlc_view_focus(handle); } // Float popups if (type & WLC_BIT_POPUP) { swayc_t *view = new_floating_view(handle); wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, false); focus_view(view); arrange_windows(active_workspace, -1, -1); } } else { swayc_t *view = new_view(focused, handle); //Set maximize flag for windows. //TODO: floating windows have this unset wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); unfocus_all(&root_container); focus_view(view); arrange_windows(view->parent, -1, -1); } if (wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) { unfocus_all(&root_container); focus_view(focused); arrange_windows(focused, -1, -1); } return true; }
static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { static struct wlc_origin prev_pos; static wlc_handle prev_handle = 0; mouse_origin = *origin; bool changed_floating = false; bool changed_tiling = false; int min_sane_w = 100; int min_sane_h = 60; if (!active_workspace) { return false; } // Do checks to determine if proper keys are being held swayc_t *view = container_under_pointer(); uint32_t edge = 0; if (pointer_state.floating.drag && view) { if (view->is_floating) { int dx = mouse_origin.x - prev_pos.x; int dy = mouse_origin.y - prev_pos.y; view->x += dx; view->y += dy; changed_floating = true; } } else if (pointer_state.floating.resize && view) { if (view->is_floating) { int dx = mouse_origin.x - prev_pos.x; int dy = mouse_origin.y - prev_pos.y; // Move and resize the view based on the dx/dy and mouse position int midway_x = view->x + view->width/2; int midway_y = view->y + view->height/2; if (dx < 0) { if (!pointer_state.lock.right) { if (view->width > min_sane_w) { changed_floating = true; view->width += dx; edge += WLC_RESIZE_EDGE_RIGHT; } } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) { changed_floating = true; view->x += dx; view->width -= dx; edge += WLC_RESIZE_EDGE_LEFT; } } else if (dx > 0) { if (mouse_origin.x > midway_x && !pointer_state.lock.right) { changed_floating = true; view->width += dx; edge += WLC_RESIZE_EDGE_RIGHT; } else if (!pointer_state.lock.left) { if (view->width > min_sane_w) { changed_floating = true; view->x += dx; view->width -= dx; edge += WLC_RESIZE_EDGE_LEFT; } } } if (dy < 0) { if (!pointer_state.lock.bottom) { if (view->height > min_sane_h) { changed_floating = true; view->height += dy; edge += WLC_RESIZE_EDGE_BOTTOM; } } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) { changed_floating = true; view->y += dy; view->height -= dy; edge += WLC_RESIZE_EDGE_TOP; } } else if (dy > 0) { if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) { changed_floating = true; view->height += dy; edge += WLC_RESIZE_EDGE_BOTTOM; } else if (!pointer_state.lock.top) { if (view->height > min_sane_h) { changed_floating = true; view->y += dy; view->height -= dy; edge += WLC_RESIZE_EDGE_TOP; } } } } } else if (pointer_state.tiling.resize && view) { bool valid = true; double dx = mouse_origin.x - prev_pos.x; double dy = mouse_origin.y - prev_pos.y; if ((dx < 0 || mouse_origin.x < pointer_state.tiling.lock_pos.x) && pointer_state.lock.temp_left) { changed_tiling = true; valid = false; } else if (dx > 0 && pointer_state.lock.temp_left) { pointer_state.lock.temp_left = false; } if ((dx > 0 || mouse_origin.x > pointer_state.tiling.lock_pos.x) && pointer_state.lock.temp_right) { changed_tiling = true; valid = false; } else if (dx < 0 && pointer_state.lock.temp_right) { pointer_state.lock.temp_right = false; } if ((dy < 0 || mouse_origin.y < pointer_state.tiling.lock_pos.y) && pointer_state.lock.temp_up) { changed_tiling = true; valid = false; } else if (dy > 0 && pointer_state.lock.temp_up) { pointer_state.lock.temp_up = false; } if ((dy > 0 || mouse_origin.y > pointer_state.tiling.lock_pos.y) && pointer_state.lock.temp_down) { changed_tiling = true; valid = false; } else if (dy < 0 && pointer_state.lock.temp_down) { pointer_state.lock.temp_down = false; } if (!view->is_floating && valid) { // Handle layout resizes -- Find the biggest parent container then apply resizes to that // and its bordering siblings swayc_t *parent = view; if (!pointer_state.lock.bottom) { while (parent->type != C_WORKSPACE) { // TODO: Absolute value is a bad hack here to compensate for rounding. Find a better // way of doing this. if (fabs(parent->parent->y + parent->parent->height - (view->y + view->height)) <= 1) { parent = parent->parent; } else { break; } } if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) { swayc_t *sibling = get_swayc_in_direction(parent, MOVE_DOWN); if (sibling) { if ((parent->height > min_sane_h || dy > 0) && (sibling->height > min_sane_h || dy < 0)) { recursive_resize(parent, dy, WLC_RESIZE_EDGE_BOTTOM); recursive_resize(sibling, -1 * dy, WLC_RESIZE_EDGE_TOP); changed_tiling = true; } else { pointer_state.tiling.lock_pos.y = mouse_origin.y; if (parent->height < min_sane_h) { pointer_state.lock.temp_up = true; } else if (sibling->height < min_sane_h) { pointer_state.lock.temp_down = true; } } } } } else if (!pointer_state.lock.top) { while (parent->type != C_WORKSPACE) { if (fabs(parent->parent->y - view->y) <= 1) { parent = parent->parent; } else { break; } } if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) { swayc_t *sibling = get_swayc_in_direction(parent, MOVE_UP); if (sibling) { if ((parent->height > min_sane_h || dy < 0) && (sibling->height > min_sane_h || dy > 0)) { recursive_resize(parent, -1 * dy, WLC_RESIZE_EDGE_TOP); recursive_resize(sibling, dy, WLC_RESIZE_EDGE_BOTTOM); changed_tiling = true; } else { pointer_state.tiling.lock_pos.y = mouse_origin.y; if (parent->height < min_sane_h) { pointer_state.lock.temp_down = true; } else if (sibling->height < min_sane_h) { pointer_state.lock.temp_up = true; } } } } } parent = view; if (!pointer_state.lock.right) { while (parent->type != C_WORKSPACE) { if (fabs(parent->parent->x + parent->parent->width - (view->x + view->width)) <= 1) { parent = parent->parent; } else { sway_log(L_DEBUG, "view: %f vs parent: %f", view->x + view->width, parent->parent->x + parent->parent->width); break; } } if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) { swayc_t *sibling = get_swayc_in_direction(parent, MOVE_RIGHT); if (sibling) { if ((parent->width > min_sane_w || dx > 0) && (sibling->width > min_sane_w || dx < 0)) { recursive_resize(parent, dx, WLC_RESIZE_EDGE_RIGHT); recursive_resize(sibling, -1 * dx, WLC_RESIZE_EDGE_LEFT); changed_tiling = true; } else { pointer_state.tiling.lock_pos.x = mouse_origin.x; if (parent->width < min_sane_w) { pointer_state.lock.temp_left = true; } else if (sibling->width < min_sane_w) { pointer_state.lock.temp_right = true; } } } } } else if (!pointer_state.lock.left) { while (parent->type != C_WORKSPACE) { if (fabs(parent->parent->x - view->x) <= 1 && parent->parent) { parent = parent->parent; } else { break; } } if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) { swayc_t *sibling = get_swayc_in_direction(parent, MOVE_LEFT); if (sibling) { if ((parent->width > min_sane_w || dx < 0) && (sibling->width > min_sane_w || dx > 0)) { recursive_resize(parent, -1 * dx, WLC_RESIZE_EDGE_LEFT); recursive_resize(sibling, dx, WLC_RESIZE_EDGE_RIGHT); changed_tiling = true; } else { pointer_state.tiling.lock_pos.x = mouse_origin.x; if (parent->width < min_sane_w) { pointer_state.lock.temp_right = true; } else if (sibling->width < min_sane_w) { pointer_state.lock.temp_left = true; } } } } } arrange_windows(active_workspace, -1, -1); } } if (config->focus_follows_mouse && prev_handle != handle) { // Dont change focus if fullscreen swayc_t *focused = get_focused_view(view); if (!(focused->type == C_VIEW && wlc_view_get_state(focused->handle) & WLC_BIT_FULLSCREEN) && !(pointer_state.l_held || pointer_state.r_held)) { set_focused_container(container_under_pointer()); } } prev_handle = handle; prev_pos = mouse_origin; if (changed_floating) { struct wlc_geometry geometry = { .origin = { .x = view->x, .y = view->y }, .size = { .w = view->width, .h = view->height } }; wlc_view_set_geometry(view->handle, edge, &geometry); return true; }
static bool handle_view_created(wlc_handle handle) { // if view is child of another view, the use that as focused container wlc_handle parent = wlc_view_get_parent(handle); swayc_t *focused = NULL; swayc_t *newview = NULL; // Get parent container, to add view in if (parent) { focused = get_swayc_for_handle(parent, &root_container); } if (!focused || focused->type == C_OUTPUT) { focused = get_focused_container(&root_container); } sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld " "mask:%d (x:%d y:%d w:%d h:%d) title:%s " "class:%s appid:%s", handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent, wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x, wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w, wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle), wlc_view_get_class(handle), wlc_view_get_app_id(handle)); // TODO properly figure out how each window should be handled. switch (wlc_view_get_type(handle)) { // regular view created regularly case 0: newview = new_view(focused, handle); wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); break; // Dmenu keeps viewfocus, but others with this flag dont, for now simulate // dmenu case WLC_BIT_OVERRIDE_REDIRECT: // locked_view_focus = true; wlc_view_focus(handle); wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); wlc_view_bring_to_front(handle); break; // Firefox popups have this flag set. case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: wlc_view_bring_to_front(handle); locked_container_focus = true; break; // Modals, get focus, popups do not case WLC_BIT_MODAL: wlc_view_focus(handle); wlc_view_bring_to_front(handle); newview = new_floating_view(handle); case WLC_BIT_POPUP: wlc_view_bring_to_front(handle); break; } if (newview) { set_focused_container(newview); swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT); arrange_windows(output, -1, -1); } return true; }
static bool is_tiled(struct wlc_view *view) { uint32_t state = wlc_view_get_state(view); return !(state & WLC_BIT_FULLSCREEN) && !wlc_view_get_parent(view) && is_managed(view) && !is_or(view) && !is_modal(view); }
static bool is_or(struct wlc_view *view) { return (wlc_view_get_type(view) & WLC_BIT_OVERRIDE_REDIRECT) || (wlc_view_get_state(view) & BIT_BEMENU); }
void arrange_windows(swayc_t *container, int width, int height) { int i; if (width == -1 || height == -1) { sway_log(L_DEBUG, "Arranging layout for %p", container); width = container->width; height = container->height; } int x = 0, y = 0; switch (container->type) { case C_ROOT: for (i = 0; i < container->children->length; ++i) { swayc_t *child = container->children->items[i]; sway_log(L_DEBUG, "Arranging output at %d", x); child->x = x; child->y = y; arrange_windows(child, -1, -1); // Removed for now because wlc works with relative positions // Addition can be reconsidered once wlc positions are changed // x += child->width; } return; case C_OUTPUT: container->width = width; container->height = height; // These lines make x/y negative and result in stuff glitching out // Their addition can be reconsidered once wlc positions are changed // x -= container->x; // y -= container->y; for (i = 0; i < container->children->length; ++i) { swayc_t *child = container->children->items[i]; child->x = x + container->gaps; child->y = y + container->gaps; child->width = width - container->gaps * 2; child->height = height - container->gaps * 2; sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y); arrange_windows(child, -1, -1); } return; case C_VIEW: { struct wlc_geometry geometry = { .origin = { .x = container->x + container->gaps, .y = container->y + container->gaps }, .size = { .w = width - container->gaps * 2, .h = height - container->gaps * 2 } }; if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { swayc_t *parent = container; while (parent->type != C_OUTPUT) { parent = parent->parent; } geometry.origin.x = 0; geometry.origin.y = 0; geometry.size.w = parent->width; geometry.size.h = parent->height; wlc_view_set_geometry(container->handle, 0, &geometry); wlc_view_bring_to_front(container->handle); } else { wlc_view_set_geometry(container->handle, 0, &geometry); container->width = width; container->height = height; } sway_log(L_DEBUG, "Set view to %d x %d @ %d, %d", geometry.size.w, geometry.size.h, geometry.origin.x, geometry.origin.y); } return; default: container->width = width; container->height = height; break; }