void BuildAction::update_in_range(unsigned int time, Unit *target_unit) { if (target_unit->has_attribute(attr_type::building)) { auto &build = target_unit->get_attribute<attr_type::building>(); // upgrade floating outlines auto target_location = target_unit->location.get(); if (target_location->is_floating()) { // try to place the object if (target_location->place(object_state::placed)) { // modify ground terrain if (build.foundation_terrain > 0) { target_location->set_ground(build.foundation_terrain, 0); } } else { // failed to start construction this->complete = 1.0f; return; } } // increment building completion build.completed += build_rate * time; this->complete = build.completed; if (this->complete >= 1.0f) { target_location->place(build.completion_state); } } else { this->complete = 1.0f; } // inc frame this->frame += time * this->frame_rate / 2.5f; }
void grab_pointer(pointer_action_t pac) { PRINTF("grab pointer %u\n", pac); xcb_window_t win = XCB_NONE; xcb_point_t pos; query_pointer(&win, &pos); coordinates_t loc; if (locate_window(win, &loc)) { client_t *c = NULL; frozen_pointer->position = pos; frozen_pointer->action = pac; c = loc.node->client; frozen_pointer->monitor = loc.monitor; frozen_pointer->desktop = loc.desktop; frozen_pointer->node = loc.node; frozen_pointer->client = c; frozen_pointer->window = c->window; frozen_pointer->horizontal_fence = NULL; frozen_pointer->vertical_fence = NULL; switch (pac) { case ACTION_FOCUS: if (loc.node != mon->desk->focus) { bool backup = pointer_follows_monitor; pointer_follows_monitor = false; focus_node(loc.monitor, loc.desktop, loc.node); pointer_follows_monitor = backup; } else if (focus_follows_pointer) { stack(loc.node, STACK_ABOVE); } frozen_pointer->action = ACTION_NONE; break; case ACTION_MOVE: case ACTION_RESIZE_SIDE: case ACTION_RESIZE_CORNER: if (is_tiled(c)) { frozen_pointer->rectangle = c->tiled_rectangle; frozen_pointer->is_tiled = true; } else if (is_floating(c)) { frozen_pointer->rectangle = c->floating_rectangle; frozen_pointer->is_tiled = false; } else { frozen_pointer->action = ACTION_NONE; return; } if (pac == ACTION_RESIZE_SIDE) { float W = frozen_pointer->rectangle.width; float H = frozen_pointer->rectangle.height; float ratio = W / H; float x = pos.x - frozen_pointer->rectangle.x; float y = pos.y - frozen_pointer->rectangle.y; float diag_a = ratio * y; float diag_b = W - diag_a; if (x < diag_a) { if (x < diag_b) frozen_pointer->side = SIDE_LEFT; else frozen_pointer->side = SIDE_BOTTOM; } else { if (x < diag_b) frozen_pointer->side = SIDE_TOP; else frozen_pointer->side = SIDE_RIGHT; } } else if (pac == ACTION_RESIZE_CORNER) { int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2); int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2); if (pos.x > mid_x) { if (pos.y > mid_y) frozen_pointer->corner = CORNER_BOTTOM_RIGHT; else frozen_pointer->corner = CORNER_TOP_RIGHT; } else { if (pos.y > mid_y) frozen_pointer->corner = CORNER_BOTTOM_LEFT; else frozen_pointer->corner = CORNER_TOP_LEFT; } } if (frozen_pointer->is_tiled) { if (pac == ACTION_RESIZE_SIDE) { switch (frozen_pointer->side) { case SIDE_TOP: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); break; case SIDE_RIGHT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case SIDE_BOTTOM: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); break; case SIDE_LEFT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; } } else if (pac == ACTION_RESIZE_CORNER) { switch (frozen_pointer->corner) { case CORNER_TOP_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; case CORNER_TOP_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case CORNER_BOTTOM_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case CORNER_BOTTOM_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; } } if (frozen_pointer->horizontal_fence != NULL) frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio; if (frozen_pointer->vertical_fence != NULL) frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio; } break; case ACTION_NONE: break; } } else { if (pac == ACTION_FOCUS) { monitor_t *m = monitor_from_point(pos); if (m != NULL && m != mon) focus_node(m, m->desk, m->desk->focus); } frozen_pointer->action = ACTION_NONE; } }
void configure_request(xcb_generic_event_t *evt) { xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt; PRINTF("configure request %X\n", e->window); coordinates_t loc; bool is_managed = locate_window(e->window, &loc); client_t *c = (is_managed ? loc.node->client : NULL); int w = 0, h = 0; if (is_managed && !is_floating(c)) { if (e->value_mask & XCB_CONFIG_WINDOW_X) c->floating_rectangle.x = e->x; if (e->value_mask & XCB_CONFIG_WINDOW_Y) c->floating_rectangle.y = e->y; if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) w = e->width; if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) h = e->height; if (w != 0) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } if (h != 0) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } xcb_configure_notify_event_t evt; xcb_rectangle_t rect; xcb_window_t win = c->window; unsigned int bw = c->border_width; if (c->fullscreen) rect = loc.monitor->rectangle; else rect = c->tiled_rectangle; evt.response_type = XCB_CONFIGURE_NOTIFY; evt.event = win; evt.window = win; evt.above_sibling = XCB_NONE; evt.x = rect.x; evt.y = rect.y; evt.width = rect.width; evt.height = rect.height; evt.border_width = bw; evt.override_redirect = false; xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt); if (c->pseudo_tiled) arrange(loc.monitor, loc.desktop); } else { uint16_t mask = 0; uint32_t values[7]; unsigned short i = 0; if (e->value_mask & XCB_CONFIG_WINDOW_X) { mask |= XCB_CONFIG_WINDOW_X; values[i++] = e->x; if (is_managed) c->floating_rectangle.x = e->x; } if (e->value_mask & XCB_CONFIG_WINDOW_Y) { mask |= XCB_CONFIG_WINDOW_Y; values[i++] = e->y; if (is_managed) c->floating_rectangle.y = e->y; } if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) { mask |= XCB_CONFIG_WINDOW_WIDTH; w = e->width; if (is_managed) { restrain_floating_width(c, &w); c->floating_rectangle.width = w; } values[i++] = w; } if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { mask |= XCB_CONFIG_WINDOW_HEIGHT; h = e->height; if (is_managed) { restrain_floating_height(c, &h); c->floating_rectangle.height = h; } values[i++] = h; } if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH; values[i++] = e->border_width; } if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) { mask |= XCB_CONFIG_WINDOW_SIBLING; values[i++] = e->sibling; } if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) { mask |= XCB_CONFIG_WINDOW_STACK_MODE; values[i++] = e->stack_mode; } xcb_configure_window(dpy, e->window, mask, values); } if (is_managed) translate_client(monitor_from_client(c), loc.monitor, c); }
void CL_CSSUsedValues::set_width(const CL_CSSBoxProperties &properties) { margin.left = get_margin_width(properties.margin_width_left); margin.right = get_margin_width(properties.margin_width_right); border.left = properties.border_width_left.length.value; border.right = properties.border_width_right.length.value; padding.left = get_padding_width(properties.padding_width_left); padding.right = get_padding_width(properties.padding_width_right); width = 0; undetermined_width = false; if (replaced) { if (properties.width.type == CL_CSSBoxWidth::type_auto && properties.height.type == CL_CSSBoxHeight::type_auto && intrinsic.has_width) { width = intrinsic.width; } else if (properties.width.type == CL_CSSBoxWidth::type_auto && properties.height.type == CL_CSSBoxHeight::type_auto && intrinsic.has_height && intrinsic.has_ratio) { width = intrinsic.height / intrinsic.ratio; } else if (properties.width.type == CL_CSSBoxWidth::type_auto && properties.height.type == CL_CSSBoxHeight::type_auto && intrinsic.has_ratio) { if (containing.undetermined_width) { width = 0; undetermined_width = true; } else { width = containing.width - margin.left - margin.right - border.left - border.right - padding.left - padding.right; } } else if (properties.width.type == CL_CSSBoxWidth::type_auto && intrinsic.has_width) { width = intrinsic.width; } else if (properties.width.type == CL_CSSBoxWidth::type_auto) { width = 300; // bug: Should be 300px (css physical length) /*if (width > device.width) { width = largest_2_1_ratio_rect(); }*/ } } else if (is_inline(properties)) { // width property does not apply. width = 0; undetermined_width = true; } else if (is_absolute(properties)) { if (properties.width.type == CL_CSSBoxWidth::type_length) { width = properties.width.length.value; } else if (properties.width.type == CL_CSSBoxWidth::type_percentage) { if (containing.undetermined_width) { width = 0; undetermined_width = true; } else { width = properties.width.percentage * containing.width / 100.0f; } } else if (properties.width.type == CL_CSSBoxWidth::type_auto && properties.left.type != CL_CSSBoxLeft::type_auto && properties.right.type != CL_CSSBoxRight::type_auto) { if (containing.undetermined_width) { width = 0; undetermined_width = true; } else { // To do: Handle the cases where the length property is a percentage. Also determine what the containing box is (the viewport/page-area?) width = containing.width - properties.left.length.value - properties.right.length.value - margin.left - margin.right - border.left - border.right - padding.left - padding.right; } } else if (properties.width.type == CL_CSSBoxWidth::type_auto) { width = 0.0f; undetermined_width = true; // shrink-to-fit } } else if (is_floating(properties) || is_inline_block(properties)) { if (properties.width.type == CL_CSSBoxWidth::type_length) { width = properties.width.length.value; } else if (properties.width.type == CL_CSSBoxWidth::type_percentage) { if (containing.undetermined_width) { width = 0; undetermined_width = true; } else { width = properties.width.percentage * containing.width / 100.0f; } } else if (properties.width.type == CL_CSSBoxWidth::type_auto) { width = 0.0f; undetermined_width = true; // shrink-to-fit } } else if (is_block(properties)) { if (properties.width.type == CL_CSSBoxWidth::type_length) { width = properties.width.length.value; } else if (properties.width.type == CL_CSSBoxWidth::type_percentage) { if (containing.undetermined_width) { width = 0; undetermined_width = true; } else { width = properties.width.percentage * containing.width / 100.0f; } } else if (properties.width.type == CL_CSSBoxWidth::type_auto) { if (containing.undetermined_width) { width = 0; undetermined_width = true; } else { width = cl_max(0.0f, containing.width - margin.left - margin.right - border.left - border.right - padding.left - padding.right); } } } if (!undetermined_width) { if (properties.max_width.type == CL_CSSBoxMaxWidth::type_length) { width = cl_min(width, properties.max_width.length.value); } else if (properties.max_width.type == CL_CSSBoxMaxWidth::type_percentage && !containing.undetermined_width) { width = cl_min(width, properties.max_width.percentage * containing.width / 100.0f); } if (properties.min_width.type == CL_CSSBoxMinWidth::type_length) { width = cl_max(width, properties.min_width.length.value); } else if (properties.min_width.type == CL_CSSBoxMinWidth::type_percentage && !containing.undetermined_width) { width = cl_max(width, properties.min_width.percentage * containing.width / 100.0f); } } calc_noncontent_width(properties); }
void CL_CSSUsedValues::calc_noncontent_width(const CL_CSSBoxProperties &properties) { margin.left = get_margin_width(properties.margin_width_left); margin.right = get_margin_width(properties.margin_width_right); border.left = properties.border_width_left.length.value; border.right = properties.border_width_right.length.value; padding.left = get_padding_width(properties.padding_width_left); padding.right = get_padding_width(properties.padding_width_right); if (is_inline(properties) || is_inline_block(properties) || is_floating(properties)) { // Do nothing. Correct values already set by get_margin_width. } else if (is_block(properties)) { if (properties.margin_width_left.type == CL_CSSBoxMarginWidth::type_auto && properties.margin_width_right.type == CL_CSSBoxMarginWidth::type_auto) { margin.left = cl_max(0.0f, (containing.width-border.left-border.right-padding.left-padding.right-width)/2.0f); margin.right = cl_max(0.0f, containing.width-border.left-border.right-padding.left-padding.right-width-margin.left); } else if (properties.margin_width_left.type == CL_CSSBoxMarginWidth::type_auto) { margin.left = cl_max(0.0f, containing.width-margin.right-border.left-border.right-padding.left-padding.right-width); } else if (properties.margin_width_right.type == CL_CSSBoxMarginWidth::type_auto) { margin.right = cl_max(0.0f, containing.width-margin.left-border.left-border.right-padding.left-padding.right-width); } if (margin.left + border.left + width + border.right + padding.right + margin.right > containing.width) { if (properties.direction.type == CL_CSSBoxDirection::type_ltr) margin.right = cl_max(0.0f, containing.width-margin.left-border.left-border.right-padding.left-padding.right-width); else margin.left = cl_max(0.0f, containing.width-margin.right-border.left-border.right-padding.left-padding.right-width); } } else if (is_absolute(properties) && !replaced) { // Lots of annoying calculations here using 'left', 'right', 'width', 'direction' and the margin+border+padding+width=containing.width constraint } else if (is_absolute(properties) && replaced) { if (properties.margin_width_left.type == CL_CSSBoxMarginWidth::type_auto) { if (properties.left.type == CL_CSSBoxLeft::type_auto || properties.right.type == CL_CSSBoxRight::type_auto) { margin.left = 0; } else { // solve using margin+border+padding+width=containing.width constraint } } if (properties.margin_width_right.type == CL_CSSBoxMarginWidth::type_auto) { if (properties.left.type == CL_CSSBoxLeft::type_auto || properties.right.type == CL_CSSBoxRight::type_auto) { margin.right = 0; } else { // solve using margin+border+padding+width=containing.width constraint } } } }
void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect) { if (n == NULL) return; n->rectangle = rect; if (is_leaf(n)) { if (n->client->fullscreen) return; if (is_floating(n->client) && n->client->border_width != border_width) { int ds = 2 * (border_width - n->client->border_width); n->client->floating_rectangle.width += ds; n->client->floating_rectangle.height += ds; } if (borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE) n->client->border_width = 0; else n->client->border_width = border_width; xcb_rectangle_t r; if (is_tiled(n->client)) { if (d->layout == LAYOUT_TILED) r = rect; else if (d->layout == LAYOUT_MONOCLE) r = root_rect; int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : window_gap); int bleed = wg + 2 * n->client->border_width; r.width = (bleed < r.width ? r.width - bleed : 1); r.height = (bleed < r.height ? r.height - bleed : 1); n->client->tiled_rectangle = r; } else { r = n->client->floating_rectangle; } window_move_resize(n->client->window, r.x, r.y, r.width, r.height); window_border_width(n->client->window, n->client->border_width); window_draw_border(n, n == d->focus, m == mon); } else { xcb_rectangle_t first_rect; xcb_rectangle_t second_rect; if (n->first_child->vacant || n->second_child->vacant) { first_rect = second_rect = rect; } else { unsigned int fence; if (n->split_type == TYPE_VERTICAL) { fence = rect.width * n->split_ratio; first_rect = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height}; second_rect = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height}; } else if (n->split_type == TYPE_HORIZONTAL) { fence = rect.height * n->split_ratio; first_rect = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence}; second_rect = (xcb_rectangle_t) {rect.x, rect.y + fence, rect.width, rect.height - fence}; } } apply_layout(m, d, n->first_child, first_rect, root_rect); apply_layout(m, d, n->second_child, second_rect, root_rect); } }