workspace.cc (11629B)
1 #include "../winsys/util.hh" 2 #include "context.hh" 3 #include "cycle.t.hh" 4 #include "workspace.hh" 5 6 #include <algorithm> 7 #include <optional> 8 9 bool 10 Buffer::is_occupied() const 11 { 12 return m_client; 13 } 14 15 16 Client_ptr 17 Buffer::client() const 18 { 19 return m_client; 20 } 21 22 std::optional<winsys::Grip> 23 Buffer::grip() const 24 { 25 return m_grip; 26 } 27 28 std::optional<winsys::Pos> 29 Buffer::grip_pos() const 30 { 31 return m_grip_pos; 32 } 33 34 std::optional<winsys::Region> 35 Buffer::client_region() const 36 { 37 return m_client_region; 38 } 39 40 41 void 42 Buffer::set_grip_pos(winsys::Pos pos) 43 { 44 m_grip_pos = pos; 45 } 46 47 void 48 Buffer::set_client_region(winsys::Region region) 49 { 50 m_client_region = region; 51 } 52 53 void 54 Buffer::set(Client_ptr client, winsys::Grip grip, winsys::Pos pos, winsys::Region region) 55 { 56 m_client = client; 57 m_grip = grip; 58 m_grip_pos = pos; 59 m_client_region = region; 60 } 61 62 void 63 Buffer::unset() 64 { 65 m_client = nullptr; 66 m_grip.reset(); 67 m_grip_pos.reset(); 68 m_client_region.reset(); 69 } 70 71 72 bool 73 Workspace::empty() const 74 { 75 return m_clients.empty(); 76 } 77 78 bool 79 Workspace::contains(Client_ptr client) const 80 { 81 return m_clients.contains(client); 82 } 83 84 85 bool 86 Workspace::focus_follows_mouse() const 87 { 88 return m_focus_follows_mouse; 89 } 90 91 void 92 Workspace::set_focus_follows_mouse(bool focus_follows_mouse) 93 { 94 m_focus_follows_mouse = focus_follows_mouse; 95 } 96 97 98 bool 99 Workspace::layout_is_free() const 100 { 101 return m_layout_handler.layout_is_free(); 102 } 103 104 bool 105 Workspace::layout_has_margin() const 106 { 107 return m_layout_handler.layout_has_margin(); 108 } 109 110 bool 111 Workspace::layout_has_gap() const 112 { 113 return m_layout_handler.layout_has_gap(); 114 } 115 116 bool 117 Workspace::layout_is_persistent() const 118 { 119 return m_layout_handler.layout_is_persistent(); 120 } 121 122 bool 123 Workspace::layout_is_single() const 124 { 125 return m_layout_handler.layout_is_single(); 126 } 127 128 bool 129 Workspace::layout_wraps() const 130 { 131 return m_layout_handler.layout_wraps(); 132 } 133 134 135 std::size_t 136 Workspace::size() const 137 { 138 return m_clients.size(); 139 } 140 141 std::size_t 142 Workspace::length() const 143 { 144 return m_clients.length(); 145 } 146 147 std::size_t 148 Workspace::main_count() const 149 { 150 return m_layout_handler.main_count(); 151 } 152 153 154 Context_ptr 155 Workspace::context() const 156 { 157 return mp_context; 158 } 159 160 161 Index 162 Workspace::index() const 163 { 164 return m_index; 165 } 166 167 std::string const& 168 Workspace::name() const 169 { 170 return m_name; 171 } 172 173 std::string 174 Workspace::identifier() const 175 { 176 if (!m_name.empty()) 177 return mp_context->name() 178 + ":" 179 + std::to_string(m_index) 180 + ":" 181 + m_name; 182 183 return mp_context->name() 184 + ":" 185 + std::to_string(m_index); 186 } 187 188 Client_ptr 189 Workspace::active() const 190 { 191 return mp_active; 192 } 193 194 195 Cycle<Client_ptr> const& 196 Workspace::clients() const 197 { 198 return m_clients; 199 } 200 201 std::vector<Client_ptr> 202 Workspace::stack_after_focus() const 203 { 204 std::vector<Client_ptr> stack = m_clients.stack(); 205 206 if (mp_active) { 207 Util::erase_remove(stack, mp_active); 208 stack.push_back(mp_active); 209 } 210 211 return stack; 212 } 213 214 215 Client_ptr 216 Workspace::next_client() const 217 { 218 std::optional<Client_ptr> client 219 = m_clients.next_element(winsys::Direction::Forward); 220 221 if (client != mp_active) 222 return *client; 223 224 return nullptr; 225 } 226 227 Client_ptr 228 Workspace::prev_client() const 229 { 230 std::optional<Client_ptr> client 231 = m_clients.next_element(winsys::Direction::Backward); 232 233 if (client != mp_active) 234 return *client; 235 236 return nullptr; 237 } 238 239 240 std::optional<Client_ptr> 241 Workspace::find_client(ClientSelector const& selector) const 242 { 243 if (m_clients.empty()) 244 return std::nullopt; 245 246 switch (selector.criterium()) { 247 case ClientSelector::SelectionCriterium::AtFirst: 248 { 249 return m_clients[0]; 250 } 251 case ClientSelector::SelectionCriterium::AtLast: 252 { 253 return m_clients[Util::last_index(m_clients.as_deque())]; 254 } 255 case ClientSelector::SelectionCriterium::AtMain: 256 { 257 std::size_t main_count = m_layout_handler.main_count(); 258 259 if (main_count <= m_clients.size()) 260 return m_clients[main_count]; 261 262 break; 263 } 264 case ClientSelector::SelectionCriterium::AtIndex: 265 { 266 std::size_t index = selector.index(); 267 268 if (index <= m_clients.size()) 269 return m_clients[index]; 270 271 break; 272 } 273 } 274 275 return std::nullopt; 276 } 277 278 279 void 280 Workspace::cycle(winsys::Direction direction) 281 { 282 switch (direction) { 283 case winsys::Direction::Forward: 284 { 285 if (!layout_wraps() && m_clients.active_index() == m_clients.last_index()) 286 return; 287 288 break; 289 } 290 case winsys::Direction::Backward: 291 { 292 if (!layout_wraps() && m_clients.active_index() == 0) 293 return; 294 295 break; 296 } 297 } 298 299 m_clients.cycle_active(direction); 300 mp_active = m_clients.active_element().value_or(nullptr); 301 } 302 303 void 304 Workspace::drag(winsys::Direction direction) 305 { 306 switch (direction) { 307 case winsys::Direction::Forward: 308 { 309 if (!layout_wraps() && m_clients.active_index() == m_clients.last_index()) 310 return; 311 312 break; 313 } 314 case winsys::Direction::Backward: 315 { 316 if (!layout_wraps() && m_clients.active_index() == 0) 317 return; 318 319 break; 320 } 321 } 322 323 m_clients.drag_active(direction); 324 mp_active = m_clients.active_element().value_or(nullptr); 325 } 326 327 void 328 Workspace::reverse() 329 { 330 m_clients.reverse(); 331 mp_active = m_clients.active_element().value_or(nullptr); 332 } 333 334 void 335 Workspace::rotate(winsys::Direction direction) 336 { 337 m_clients.rotate(direction); 338 mp_active = m_clients.active_element().value_or(nullptr); 339 } 340 341 void 342 Workspace::shuffle_main(winsys::Direction direction) 343 { 344 m_clients.rotate_range(direction, 0, m_layout_handler.main_count()); 345 mp_active = m_clients.active_element().value_or(nullptr); 346 } 347 348 void 349 Workspace::shuffle_stack(winsys::Direction direction) 350 { 351 m_clients.rotate_range(direction, m_layout_handler.main_count(), m_clients.size()); 352 mp_active = m_clients.active_element().value_or(nullptr); 353 } 354 355 356 void 357 Workspace::activate_client(Client_ptr client) 358 { 359 if (m_clients.contains(client)) { 360 m_clients.activate_element(client); 361 mp_active = client; 362 } 363 } 364 365 366 void 367 Workspace::add_client(Client_ptr client) 368 { 369 if (m_clients.contains(client)) 370 return; 371 372 m_clients.insert_at_back(client); 373 mp_active = client; 374 } 375 376 void 377 Workspace::remove_client(Client_ptr client) 378 { 379 m_clients.remove_element(client); 380 mp_active = m_clients.active_element().value_or(nullptr); 381 } 382 383 void 384 Workspace::replace_client(Client_ptr client, Client_ptr replacement) 385 { 386 bool was_active 387 = m_clients.active_element().value_or(nullptr) == client; 388 389 m_clients.replace_element(client, replacement); 390 391 if (was_active) { 392 m_clients.activate_element(replacement); 393 mp_active = replacement; 394 } 395 } 396 397 398 void 399 Workspace::client_to_icon(Client_ptr client) 400 { 401 if (m_clients.remove_element(client)) 402 m_icons.insert_at_back(client); 403 404 mp_active = m_clients.active_element().value_or(nullptr); 405 } 406 407 void 408 Workspace::icon_to_client(Client_ptr client) 409 { 410 if (m_icons.remove_element(client)) 411 m_clients.insert_at_back(client); 412 413 mp_active = m_clients.active_element().value_or(nullptr); 414 } 415 416 void 417 Workspace::add_icon(Client_ptr client) 418 { 419 if (m_icons.contains(client)) 420 return; 421 422 m_icons.insert_at_back(client); 423 } 424 425 void 426 Workspace::remove_icon(Client_ptr client) 427 { 428 m_icons.remove_element(client); 429 } 430 431 std::optional<Client_ptr> 432 Workspace::pop_icon() 433 { 434 return m_icons.empty() 435 ? std::nullopt 436 : std::optional(m_icons[m_icons.size() - 1]); 437 } 438 439 440 void 441 Workspace::client_to_disowned(Client_ptr client) 442 { 443 if (m_clients.remove_element(client)) 444 m_disowned.insert_at_back(client); 445 446 mp_active = m_clients.active_element().value_or(nullptr); 447 } 448 449 void 450 Workspace::disowned_to_client(Client_ptr client) 451 { 452 if (m_disowned.remove_element(client)) 453 m_clients.insert_at_back(client); 454 455 mp_active = m_clients.active_element().value_or(nullptr); 456 } 457 458 void 459 Workspace::add_disowned(Client_ptr client) 460 { 461 if (m_disowned.contains(client)) 462 return; 463 464 m_disowned.insert_at_back(client); 465 } 466 467 void 468 Workspace::remove_disowned(Client_ptr client) 469 { 470 m_disowned.remove_element(client); 471 } 472 473 474 void 475 Workspace::save_layout(std::size_t number) const 476 { 477 m_layout_handler.save_layout(number); 478 } 479 480 void 481 Workspace::load_layout(std::size_t number) 482 { 483 m_layout_handler.load_layout(number); 484 } 485 486 487 void 488 Workspace::toggle_layout_data() 489 { 490 m_layout_handler.set_prev_layout_data(); 491 } 492 493 void 494 Workspace::cycle_layout_data(winsys::Direction direction) 495 { 496 m_layout_handler.cycle_layout_data(direction); 497 } 498 499 void 500 Workspace::copy_data_from_prev_layout() 501 { 502 m_layout_handler.copy_data_from_prev_layout(); 503 } 504 505 506 void 507 Workspace::change_gap_size(Util::Change<int> change) 508 { 509 m_layout_handler.change_gap_size(change); 510 } 511 512 void 513 Workspace::change_main_count(Util::Change<int> change) 514 { 515 m_layout_handler.change_main_count(change); 516 } 517 518 void 519 Workspace::change_main_factor(Util::Change<float> change) 520 { 521 m_layout_handler.change_main_factor(change); 522 } 523 524 void 525 Workspace::change_margin(Util::Change<int> change) 526 { 527 m_layout_handler.change_margin(change); 528 } 529 530 void 531 Workspace::change_margin(winsys::Edge edge, Util::Change<int> change) 532 { 533 m_layout_handler.change_margin(edge, change); 534 } 535 536 void 537 Workspace::reset_gap_size() 538 { 539 m_layout_handler.reset_gap_size(); 540 } 541 542 void 543 Workspace::reset_margin() 544 { 545 m_layout_handler.reset_margin(); 546 } 547 548 void 549 Workspace::reset_layout_data() 550 { 551 m_layout_handler.reset_layout_data(); 552 } 553 554 555 void 556 Workspace::toggle_layout() 557 { 558 m_layout_handler.set_prev_kind(); 559 } 560 561 void 562 Workspace::set_layout(LayoutHandler::LayoutKind layout) 563 { 564 m_layout_handler.set_kind(layout); 565 } 566 567 std::vector<Placement> 568 Workspace::arrange(winsys::Region region) const 569 { 570 std::deque<Client_ptr> clients = m_clients.as_deque(); 571 std::vector<Placement> placements; 572 placements.reserve(clients.size()); 573 574 auto fullscreen_iter = std::stable_partition( 575 clients.begin(), 576 clients.end(), 577 [](const Client_ptr client) -> bool { 578 return client->fullscreen && !client->contained; 579 } 580 ); 581 582 auto free_iter = std::stable_partition( 583 fullscreen_iter, 584 clients.end(), 585 [=,this](const Client_ptr client) -> bool { 586 return !layout_is_free() && Client::is_free(client); 587 } 588 ); 589 590 std::transform( 591 clients.begin(), 592 fullscreen_iter, 593 std::back_inserter(placements), 594 [region](const Client_ptr client) -> Placement { 595 return Placement { 596 Placement::PlacementMethod::Tile, 597 client, 598 winsys::Decoration::NO_DECORATION, 599 region 600 }; 601 } 602 ); 603 604 std::transform( 605 fullscreen_iter, 606 free_iter, 607 std::back_inserter(placements), 608 [](const Client_ptr client) -> Placement { 609 return Placement { 610 Placement::PlacementMethod::Free, 611 client, 612 winsys::Decoration::FREE_DECORATION, 613 client->free_region 614 }; 615 } 616 ); 617 618 m_layout_handler.arrange( 619 region, 620 placements, 621 free_iter, 622 clients.end() 623 ); 624 625 if (layout_is_single()) { 626 std::for_each( 627 placements.begin(), 628 placements.end(), 629 [](Placement& placement) { 630 if (!placement.client->focused) 631 placement.region = std::nullopt; 632 } 633 ); 634 } 635 636 return placements; 637 }