/** * Adds a new client with some basic initial state. */ void ClientModel::add_client(Window client, InitialState state, Dimension2D location, Dimension2D size, bool autofocus) { if (DIM2D_WIDTH(size) <= 0 || DIM2D_HEIGHT(size) <= 0) return; // Special care is given to honor the initial state, since it is // mandated by the ICCCM switch (state) { case IS_VISIBLE: m_desktops.add_member(m_current_desktop, client); m_changes.push(new ChangeClientDesktop(client, 0, m_current_desktop)); break; case IS_HIDDEN: m_desktops.add_member(ICON_DESKTOP, client); m_changes.push(new ChangeClientDesktop(client, 0, ICON_DESKTOP)); break; } m_layers.add_member(DEF_LAYER, client); m_changes.push(new ChangeLayer(client, DEF_LAYER)); // Since the size and locations are already current, don't put out // an event now that they're set m_location[client] = location; m_size[client] = size; m_cps_mode[client] = CPS_FLOATING; Crt *current_screen = m_crt_manager.screen_of_coord(DIM2D_X(location), DIM2D_Y(location)); if (!current_screen) { // No monitor ever contains a negative screen const Box invalid_box(-1, -1, 0, 0); m_screen.insert(std::pair<Window, const Box>(client, invalid_box)); } else { const Box &screen_box = m_crt_manager.box_of_screen(current_screen); m_screen.insert(std::pair<Window, const Box>(client, screen_box)); } if (autofocus) { m_current_desktop->focus_cycle.add(client); set_autofocus(client, true); focus(client); } else set_autofocus(client, false); m_children[client] = new std::set<Window>(); }
/** * Handles the motion of the pointer. The only time that this ever applies is * when the user has moved the placeholder window - at all other times, this * event is ignored. */ void XEvents::handle_motionnotify() { // Get the placeholder's current geometry, since we need to modify the // placeholder relative to the way it is now Window placeholder = m_xmodel.get_move_resize_placeholder(); if (placeholder == None) return; XWindowAttributes attr; m_xdata.get_attributes(placeholder, attr); // Avoid needless updates by getting the most recent version of this // event m_xdata.get_latest_event(m_event, MotionNotify); // Get the difference relative to the previous position Dimension ptr_x, ptr_y; m_xdata.get_pointer_location(ptr_x, ptr_y); Dimension2D relative_change = m_xmodel.update_pointer(ptr_x, ptr_y); switch (m_xmodel.get_move_resize_state()) { case MR_MOVE: // Update the position of the placeholder m_xdata.move_window(placeholder, attr.x + DIM2D_X(relative_change), attr.y + DIM2D_Y(relative_change)); break; case MR_RESIZE: // Update the location being careful to avoid making the placeholder // have a negative size if (attr.width + DIM2D_X(relative_change) <= 0) DIM2D_X(relative_change) = 0; if (attr.height + DIM2D_Y(relative_change) <= 0) DIM2D_Y(relative_change) = 0; m_xdata.resize_window(placeholder, attr.width + DIM2D_X(relative_change), attr.height + DIM2D_Y(relative_change)); break; } }
/** * Stops moving a window, and fixes its position. */ void ClientModel::stop_moving(Window client, Dimension2D location) { Desktop* old_desktop = m_desktops.get_category_of(client); if (!old_desktop->is_moving_desktop()) return; if (m_was_stuck[client]) move_to_desktop(client, ALL_DESKTOPS, false); else move_to_desktop(client, m_current_desktop, false); change_location(client, DIM2D_X(location), DIM2D_Y(location)); focus(client); }
/** * Updates the screen configuration, as well as the screen property of every * client window. */ void ClientModel::update_screens(std::vector<Box> &bounds) { m_crt_manager.rebuild_graph(bounds); // Now, translate the location of every client back into its updated screen for (std::map<Window, Dimension2D>::iterator client_location = m_location.begin(); client_location != m_location.end(); client_location++) { Window client = client_location->first; Dimension2D &location = client_location->second; // Although this technically *should* occur, the way that this is handled would // cause the client to be moved outside of our control, and we don't want that if (is_packed_client(client)) continue; // Keep the old screen - if the new screen is the same, we don't want // to send out a change notification const Box &old_box = m_screen[client]; Box new_box(-1, -1, 0, 0); Crt *new_screen = m_crt_manager.screen_of_coord( DIM2D_X(location), DIM2D_Y(location)); if (new_screen) new_box = m_crt_manager.box_of_screen(new_screen); if (new_box != old_box) { m_screen.erase(client); m_screen.insert(std::pair<Window, const Box>(client, new_box)); // Why do the ref like this? Well, if it is done as a reference // to new_box directly, then new_box will go out of scope and // our data will be thoroughly shat over. Thankfully the unit // tests caught this one. m_changes.push(new ChangeScreen(client, m_screen[client])); } } // Since the location of the primary screen's corners may have changed, we // have to repack everything repack_corner(PACK_NORTHEAST); repack_corner(PACK_NORTHWEST); repack_corner(PACK_SOUTHEAST); repack_corner(PACK_SOUTHWEST); }
/** * Converts all the information about a client window to a textual * representation, which is written to the output stream. */ void ClientModel::dump_client_info(Window client, std::ostream &output) { output << " Window: " << std::hex << client << "\n"; output << " Screen: " << std::dec << m_screen[client] << "\n"; output << " Layer: " << std::dec << static_cast<int>(m_layers.get_category_of(client)) << "\n"; Dimension2D &location = m_location[client]; output << " Location: X=" << DIM2D_X(location) << " Y=" << DIM2D_Y(location) << "\n"; Dimension2D &size = m_size[client]; output << " Size: W=" << DIM2D_WIDTH(size) << " H=" << DIM2D_HEIGHT(size) << "\n"; ClientPosScale mode = m_cps_mode[client]; output << " Mode: "; switch (mode) { case CPS_FLOATING: output << "floating"; break; case CPS_SPLIT_LEFT: output << "left-split"; break; case CPS_SPLIT_RIGHT: output << "right-split"; break; case CPS_SPLIT_TOP: output << "top-split"; break; case CPS_SPLIT_BOTTOM: output << "bottom-split"; break; case CPS_MAX: output << "maximized"; break; } output << "\n"; output << " Can autofocus? " << (m_autofocus[client] ? "yes" : "no") << "\n"; output << " Packing info: "; if (m_pack_corners.count(client) == 0) { output << "not packed"; } else { output << "Dir="; switch (m_pack_corners[client]) { case PACK_NORTHEAST: output << "NE"; break; case PACK_NORTHWEST: output << "NW"; break; case PACK_SOUTHEAST: output << "SE"; break; case PACK_SOUTHWEST: output << "SW"; break; } output << " Priority=" << m_pack_priority[client]; } output << "\n"; std::vector<Window> children; output << " Children\n"; get_children_of(client, children); for (std::vector<Window>::iterator childiter = children.begin(); childiter != children.end(); childiter++) { output << " " << std::hex << *childiter << "\n"; } }