bool move_focus(enum movement_direction direction) { swayc_t *old_view = get_focused_container(&root_container); swayc_t *new_view = get_swayc_in_direction(old_view, direction); if (!new_view) { return false; } else if (new_view->type == C_ROOT) { sway_log(L_DEBUG, "Not setting focus above the workspace level"); return false; } else if (new_view->type == C_OUTPUT) { return set_focused_container(swayc_active_workspace_for(new_view)); } else if (direction == MOVE_PARENT || direction == MOVE_CHILD) { return set_focused_container(new_view); } else if (config->mouse_warping) { swayc_t *old_op = old_view->type == C_OUTPUT ? old_view : swayc_parent_by_type(old_view, C_OUTPUT); swayc_t *focused = get_focused_view(new_view); if (set_focused_container(focused)) { if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) { center_pointer_on(focused); } return true; } } else { return set_focused_container(get_focused_view(new_view)); } return false; }
/* XXX:DEBUG:XXX */ static void container_log(const swayc_t *c) { fprintf(stderr, "focus:%c|", c == get_focused_view(&root_container) ? 'K': c == get_focused_container(&root_container) ? 'F' : // Focused c == swayc_active_workspace() ? 'W' : // active workspace c == &root_container ? 'R' : // root 'X');// not any others fprintf(stderr,"(%p)",c); fprintf(stderr,"(p:%p)",c->parent); fprintf(stderr,"(f:%p)",c->focused); fprintf(stderr,"(h:%ld)",c->handle); fprintf(stderr,"Type:"); fprintf(stderr, c->type == C_ROOT ? "Root|" : c->type == C_OUTPUT ? "Output|" : c->type == C_WORKSPACE ? "Workspace|" : c->type == C_CONTAINER ? "Container|" : c->type == C_VIEW ? "View|" : "Unknown|"); fprintf(stderr,"layout:"); fprintf(stderr, c->layout == L_NONE ? "NONE|" : c->layout == L_HORIZ ? "Horiz|": c->layout == L_VERT ? "Vert|": c->layout == L_STACKED ? "Stacked|": c->layout == L_FLOATING ? "Floating|": "Unknown|"); fprintf(stderr, "w:%.f|h:%.f|", c->width, c->height); fprintf(stderr, "x:%.f|y:%.f|", c->x, c->y); fprintf(stderr, "g:%d|",c->gaps); fprintf(stderr, "vis:%c|", c->visible?'t':'f'); fprintf(stderr, "name:%.16s|", c->name); fprintf(stderr, "children:%d\n",c->children?c->children->length:0); }
static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, uint32_t button, enum wlc_button_state state) { swayc_t *focused = get_focused_container(&root_container); if (state == WLC_BUTTON_STATE_PRESSED) { sway_log(L_DEBUG, "Mouse button %u pressed", button); if (button == 272) { m1_held = true; } if (button == 273) { m2_held = true; } swayc_t *pointer = container_under_pointer(); set_focused_container(pointer); return (pointer && pointer != focused); } else { sway_log(L_DEBUG, "Mouse button %u released", button); if (button == 272) { m1_held = false; } if (button == 273) { m2_held = false; } } return false; }
static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, uint32_t button, enum wlc_button_state state) { swayc_t *focused = get_focused_container(&root_container); if (state == WLC_BUTTON_STATE_PRESSED) { swayc_t *pointer = focus_pointer(); return (pointer && pointer != focused); } return false; }
bool move_focus(enum movement_direction direction) { swayc_t *view = get_focused_container(&root_container); view = get_swayc_in_direction(view, direction); if (view) { if (direction == MOVE_PARENT) { return set_focused_container(view); } else { return set_focused_container(get_focused_view(view)); } } return false; }
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 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; }
bool move_focus(enum movement_direction direction) { swayc_t *old_view = get_focused_container(&root_container); swayc_t *new_view = get_swayc_in_direction(old_view, direction); if (!new_view) { return false; } else if (direction == MOVE_PARENT) { return set_focused_container(new_view); } else if (config->mouse_warping) { swayc_t *old_op = old_view->type == C_OUTPUT ? old_view : swayc_parent_by_type(old_view, C_OUTPUT); swayc_t *focused = get_focused_view(new_view); if (set_focused_container(focused)) { if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) { center_pointer_on(focused); } return true; } } else { return set_focused_container(get_focused_view(new_view)); } return false; }
static void handle_view_destroyed(wlc_handle handle) { sway_log(L_DEBUG, "Destroying window %u", (unsigned int)handle); // Properly handle unmanaged views uint32_t type = wlc_view_get_type(handle); if (type) { wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); sway_log(L_DEBUG,"Unmanaged window of type %x was destroyed", type); if (type & WLC_BIT_UNMANAGED) { // We need to call focus_view() on focus_pointer because unmanaged windows // do not alter the focus structure of the container tree. This makes focus_pointer() // think that it doesn't need to do anything, so we manually focus the result. focus_view(focus_pointer()); return; } if (type & WLC_BIT_OVERRIDE_REDIRECT) { override_redirect = false; focus_view(focus_pointer()); return; } // WLC_BIT_POPUP doesn't need to be dealt with since it's // treated as a floating view. } swayc_t *view = get_swayc_for_handle(handle, &root_container); swayc_t *parent; swayc_t *focused = get_focused_container(&root_container); if (view) { parent = destroy_view(view); arrange_windows(parent, -1, -1); } if (!focused || focused == view) { focus_pointer(); } }
/* XXX:DEBUG:XXX */ static void container_log(const swayc_t *c, int depth) { fprintf(stderr, "focus:%c", c == get_focused_view(&root_container) ? 'K': c == get_focused_container(&root_container) ? 'F' : // Focused c == swayc_active_workspace() ? 'W' : // active workspace c == &root_container ? 'R' : // root 'X');// not any others for (int i = 6; i > depth; i--) { fprintf(stderr, " "); } fprintf(stderr,"|(%p)",c); fprintf(stderr,"(p:%-8p)",c->parent); fprintf(stderr,"(f:%-8p)",c->focused); fprintf(stderr,"(h:%2" PRIuPTR ")",c->handle); fprintf(stderr,"Type:%-4s|", c->type == C_ROOT ? "root" : c->type == C_OUTPUT ? "op" : c->type == C_WORKSPACE ? "ws" : c->type == C_CONTAINER ? "cont" : c->type == C_VIEW ? "view" : "?"); fprintf(stderr,"layout:%-5s|", c->layout == L_NONE ? "-" : c->layout == L_HORIZ ? "Horiz": c->layout == L_VERT ? "Vert": c->layout == L_STACKED ? "Stack": c->layout == L_TABBED ? "Tab": c->layout == L_FLOATING ? "Float": c->layout == L_AUTO_LEFT ? "A_lft": c->layout == L_AUTO_RIGHT ? "A_rgt": c->layout == L_AUTO_TOP ? "A_top": c->layout == L_AUTO_BOTTOM ? "A_bot": "Unknown"); fprintf(stderr, "w:%4.f|h:%4.f|", c->width, c->height); fprintf(stderr, "x:%4.f|y:%4.f|", c->x, c->y); fprintf(stderr, "g:%3d|",c->gaps); fprintf(stderr, "vis:%c|", c->visible?'t':'f'); fprintf(stderr, "children:%2d|",c->children?c->children->length:0); fprintf(stderr, "name:%.16s\n", c->name); }
static bool handle_view_created(wlc_handle handle) { swayc_t *focused = get_focused_container(&root_container); swayc_t *newview = NULL; 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; // takes keyboard focus case WLC_BIT_OVERRIDE_REDIRECT: sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT", handle); locked_view_focus = true; wlc_view_focus(handle); wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); wlc_view_bring_to_front(handle); break; // Takes container focus case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: sway_log(L_DEBUG, "view %ld with OVERRIDE_REDIRECT|WLC_BIT_MANAGED", handle); wlc_view_bring_to_front(handle); locked_container_focus = true; break; // set modals as floating containers case WLC_BIT_MODAL: wlc_view_bring_to_front(handle); newview = new_floating_view(handle); case WLC_BIT_POPUP: break; } if (newview) { set_focused_container(newview); arrange_windows(newview->parent, -1, -1); } return true; }
swayc_t *workspace_create(const char* name) { swayc_t *parent; // Search for workspace<->output pair int i, e = config->workspace_outputs->length; for (i = 0; i < e; ++i) { struct workspace_output *wso = config->workspace_outputs->items[i]; if (strcasecmp(wso->workspace, name) == 0) { // Find output to use if it exists e = root_container.children->length; for (i = 0; i < e; ++i) { parent = root_container.children->items[i]; if (strcmp(parent->name, wso->output) == 0) { return new_workspace(parent, name); } } break; } } // Otherwise create a new one parent = get_focused_container(&root_container); parent = swayc_parent_by_type(parent, C_OUTPUT); return new_workspace(parent, name); }
static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) { // Update view pointer is on pointer_state.view = container_under_pointer(); // Update pointer origin pointer_state.origin.x = origin->x; pointer_state.origin.y = origin->y; // Update pointer_state switch (button) { case M_LEFT_CLICK: if (state == WLC_BUTTON_STATE_PRESSED) { pointer_state.left.held = true; pointer_state.left.x = origin->x; pointer_state.left.y = origin->y; pointer_state.left.view = pointer_state.view; } else { pointer_state.left.held = false; } break; case M_RIGHT_CLICK: if (state == WLC_BUTTON_STATE_PRESSED) { pointer_state.right.held = true; pointer_state.right.x = origin->x; pointer_state.right.y = origin->y; pointer_state.right.view = pointer_state.view; } else { pointer_state.right.held = false; } break; case M_SCROLL_CLICK: if (state == WLC_BUTTON_STATE_PRESSED) { pointer_state.scroll.held = true; pointer_state.scroll.x = origin->x; pointer_state.scroll.y = origin->y; pointer_state.scroll.view = pointer_state.view; } else { pointer_state.scroll.held = false; } break; //TODO scrolling behavior case M_SCROLL_UP: case M_SCROLL_DOWN: break; } // get focused window and check if to change focus on mouse click swayc_t *focused = get_focused_container(&root_container); // dont change focus or mode if fullscreen if (swayc_is_fullscreen(focused)) { return EVENT_PASSTHROUGH; } // set pointer mode only if floating mod has been set if (config->floating_mod) { pointer_mode_set(button, !(modifiers->mods ^ config->floating_mod)); } // Check whether to change focus swayc_t *pointer = pointer_state.view; if (pointer) { if (focused != pointer) { set_focused_container(pointer_state.view); } // Send to front if floating if (pointer->is_floating) { int i; for (i = 0; i < pointer->parent->floating->length; i++) { if (pointer->parent->floating->items[i] == pointer) { list_del(pointer->parent->floating, i); list_add(pointer->parent->floating, pointer); break; } } wlc_view_bring_to_front(pointer->handle); } } // Return if mode has been set if (pointer_state.mode) { return EVENT_HANDLED; } // Always send mouse release if (state == WLC_BUTTON_STATE_RELEASED) { return EVENT_PASSTHROUGH; } // Finally send click return EVENT_PASSTHROUGH; }
swayc_t *workspace_create(const char* name) { swayc_t *parent = get_focused_container(&root_container); parent = swayc_parent_by_type(parent, C_OUTPUT); return new_workspace(parent, name); }
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; }
struct cmd_results *cmd_layout(int argc, char **argv) { struct cmd_results *error = NULL; if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); if (!config->active) return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running."); if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { return error; } swayc_t *parent = get_focused_container(&root_container); if (parent->is_floating) { return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); } while (parent->type == C_VIEW) { parent = parent->parent; } enum swayc_layouts old_layout = parent->layout; if (strcasecmp(argv[0], "default") == 0) { swayc_change_layout(parent, parent->prev_layout); if (parent->layout == L_NONE) { swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT); swayc_change_layout(parent, default_layout(output)); } } else { if (parent->layout != L_TABBED && parent->layout != L_STACKED) { parent->prev_layout = parent->layout; } if (strcasecmp(argv[0], "tabbed") == 0) { if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)){ parent = new_container(parent, L_TABBED); } swayc_change_layout(parent, L_TABBED); } else if (strcasecmp(argv[0], "stacking") == 0) { if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)) { parent = new_container(parent, L_STACKED); } swayc_change_layout(parent, L_STACKED); } else if (strcasecmp(argv[0], "splith") == 0) { swayc_change_layout(parent, L_HORIZ); } else if (strcasecmp(argv[0], "splitv") == 0) { swayc_change_layout(parent, L_VERT); } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE || parent->workspace_layout == L_HORIZ)) { swayc_change_layout(parent, L_VERT); } else { swayc_change_layout(parent, L_HORIZ); } } } update_layout_geometry(parent, old_layout); update_geometry(parent); arrange_windows(parent, parent->width, parent->height); return cmd_results_new(CMD_SUCCESS, NULL, NULL); }
int move_focus(enum movement_direction direction) { swayc_t *current = get_focused_container(&root_container); swayc_t *parent = current->parent; if (direction == MOVE_PARENT) { current = parent; parent = parent->parent; if (parent->type == C_ROOT) { sway_log(L_DEBUG, "Focus cannot move to parent"); return 1; } else { sway_log(L_DEBUG, "Moving focus away from %p", current); unfocus_all(parent); focus_view(parent); return 0; } } while (true) { sway_log(L_DEBUG, "Moving focus away from %p", current); // Test if we can even make a difference here bool can_move = false; int diff = 0; if (direction == MOVE_LEFT || direction == MOVE_RIGHT) { if (parent->layout == L_HORIZ) { can_move = true; diff = direction == MOVE_LEFT ? -1 : 1; } } else { if (parent->layout == L_VERT) { can_move = true; diff = direction == MOVE_UP ? -1 : 1; } } sway_log(L_DEBUG, "Can move? %s", can_move ? "yes" : "no"); if (can_move) { int i; for (i = 0; i < parent->children->length; ++i) { swayc_t *child = parent->children->items[i]; if (child == current) { break; } } int desired = i + diff; sway_log(L_DEBUG, "Moving from %d to %d", i, desired); if (desired < 0 || desired >= parent->children->length) { can_move = false; } else { unfocus_all(&root_container); focus_view(parent->children->items[desired]); return 0; } } if (!can_move) { sway_log(L_DEBUG, "Can't move at current level, moving up tree"); current = parent; parent = parent->parent; if (parent->type == C_ROOT) { // Nothing we can do return 1; } } } }