/** * 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>(); }
/** * Stops resizing a window, and fixes its position. */ void ClientModel::stop_resizing(Window client, Dimension2D size) { Desktop* old_desktop = m_desktops.get_category_of(client); if (!old_desktop->is_resizing_desktop()) return; if (m_was_stuck[client]) move_to_desktop(client, ALL_DESKTOPS, false); else move_to_desktop(client, m_current_desktop, false); change_size(client, DIM2D_WIDTH(size), DIM2D_HEIGHT(size)); focus(client); }
/** * This event is only ever called on icon windows, and causes the icon * window to be redrawn. */ void XEvents::handle_expose() { Icon *the_icon = m_xmodel.find_icon_from_icon_window( m_event.xexpose.window); if (!the_icon) return; // Avoid drawing over the current contents of the icon the_icon->gc->clear(); int text_x_offset; if (m_config.show_icons) { // Get the application's pixmap icon, and figure out where to place // the text (since the icon goes to the left) XWMHints hints; bool has_hints = m_xdata.get_wm_hints(the_icon->client, hints); if (has_hints && hints.flags & IconPixmapHint) { // Copy the pixmap into the left side of the icon, keeping // its size. The width of the pixmap is the same as the // X offset of the window name (no padding is done here). Dimension2D pixmap_size = the_icon->gc->copy_pixmap( hints.icon_pixmap, 0, 0); text_x_offset = DIM2D_WIDTH(pixmap_size); } else text_x_offset = 0; } else text_x_offset = 0; std::string preferred_icon_name; m_xdata.get_icon_name(the_icon->client, preferred_icon_name); // The one thing that is strange here is that the Y offset is the entire // icon's height. This is because Xlib draws the text, starting at the // Y offset, from *bottom* to *top*. I don't know why. the_icon->gc->draw_string(text_x_offset, m_config.icon_height, preferred_icon_name); }
/** * Repacks the clients at the given corner. */ void ClientModel::repack_corner(PackCorner corner) { // We only need X because SmallWM doesn't currently support the vertical // packing case int x_incr_sign; int x_coord, y_coord; // For east/south side packings, we have to subtract the width/height of // the window from the current coordinate bool subtract_width_first, subtract_height_first; const Box &screen = get_root_screen(); switch (corner) { case PACK_NORTHWEST: x_incr_sign = 1; subtract_width_first = false; subtract_height_first = false; x_coord = screen.x; y_coord = screen.y; break; case PACK_NORTHEAST: x_incr_sign = -1; subtract_width_first = true; subtract_height_first = false; x_coord = screen.width; y_coord = screen.y; break; case PACK_SOUTHWEST: x_incr_sign = 1; subtract_width_first = false; subtract_height_first = true; x_coord = 0; y_coord = screen.height; break; case PACK_SOUTHEAST: x_incr_sign = -1; subtract_width_first = true; subtract_height_first = true; x_coord = screen.width; y_coord = screen.height; break; } // We need to collect all the windows so that we can sort them by layout // order (low priority closest to the corner, higher priority farther // away) std::vector<Window> windows_on_this_corner; for (std::map<Window, PackCorner>::iterator iter = m_pack_corners.begin(); iter != m_pack_corners.end(); iter++) { if (iter->second == corner) windows_on_this_corner.push_back(iter->first); } MapSorter<Window, unsigned long> sorter(m_pack_priority); std::sort(windows_on_this_corner.begin(), windows_on_this_corner.end(), sorter); Dimension border = m_border_width * 2; for (std::vector<Window>::iterator iter = windows_on_this_corner.begin(); iter != windows_on_this_corner.end(); iter++) { Dimension2D &size = m_size[*iter]; int real_x, real_y; if (subtract_width_first) real_x = x_coord - (DIM2D_WIDTH(size) + border); else real_x = x_coord; if (subtract_height_first) real_y = y_coord - (DIM2D_HEIGHT(size) + border); else real_y = y_coord; change_location(*iter, real_x, real_y); x_coord += x_incr_sign * (DIM2D_WIDTH(size) + border); } }
/** * 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"; } }