diff options
-rw-r--r-- | src/FbWinFrame.cc | 253 | ||||
-rw-r--r-- | src/FbWinFrame.hh | 16 | ||||
-rw-r--r-- | src/WinClient.cc | 25 | ||||
-rw-r--r-- | src/WinClient.hh | 2 | ||||
-rw-r--r-- | src/Window.cc | 20 |
5 files changed, 138 insertions, 178 deletions
diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc index 4734b2b..d044dd7 100644 --- a/src/FbWinFrame.cc +++ b/src/FbWinFrame.cc | |||
@@ -1459,138 +1459,6 @@ void FbWinFrame::applyDecorations() { | |||
1459 | frameExtentSig().notify(); | 1459 | frameExtentSig().notify(); |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | /* For aspect ratios | ||
1463 | Note that its slightly simplified in that only the | ||
1464 | line gradient is given - this is because for aspect | ||
1465 | ratios, we always have the line going through the origin | ||
1466 | |||
1467 | * Based on this formula: | ||
1468 | http://astronomy.swin.edu.au/~pbourke/geometry/pointline/ | ||
1469 | |||
1470 | Note that a gradient from origin goes through ( grad , 1 ) | ||
1471 | */ | ||
1472 | |||
1473 | void closestPointToLine(double &ret_x, double &ret_y, | ||
1474 | double point_x, double point_y, | ||
1475 | double gradient) { | ||
1476 | double u = (point_x * gradient + point_y) / | ||
1477 | (gradient*gradient + 1); | ||
1478 | |||
1479 | ret_x = u*gradient; | ||
1480 | ret_y = u; | ||
1481 | } | ||
1482 | |||
1483 | /** | ||
1484 | * Changes width and height to the nearest (lower) value | ||
1485 | * that conforms to it's size hints. | ||
1486 | * | ||
1487 | * display_* give the values that would be displayed | ||
1488 | * to the user when resizing. | ||
1489 | * We use pointers for display_* since they are optional. | ||
1490 | * | ||
1491 | * See ICCCM section 4.1.2.3 | ||
1492 | */ | ||
1493 | void FbWinFrame::applySizeHints(int &width, int &height, | ||
1494 | int *display_width, int *display_height, | ||
1495 | bool maximizing) { | ||
1496 | |||
1497 | int i = width, j = height; | ||
1498 | |||
1499 | // Check minimum size | ||
1500 | if (width < 0 || width < static_cast<signed>(m_size_hints.min_width)) | ||
1501 | width = m_size_hints.min_width; | ||
1502 | |||
1503 | if (height < 0 || height < static_cast<signed>(m_size_hints.min_height)) | ||
1504 | height = m_size_hints.min_height; | ||
1505 | |||
1506 | // Check maximum size | ||
1507 | if (m_size_hints.max_width > 0 && width > static_cast<signed>(m_size_hints.max_width)) | ||
1508 | width = m_size_hints.max_width; | ||
1509 | |||
1510 | if (m_size_hints.max_height > 0 && height > static_cast<signed>(m_size_hints.max_height)) | ||
1511 | height = m_size_hints.max_height; | ||
1512 | |||
1513 | // we apply aspect ratios before incrementals | ||
1514 | // Too difficult to exactly satisfy both incremental+aspect | ||
1515 | // in most situations | ||
1516 | // (they really shouldn't happen at the same time anyway). | ||
1517 | |||
1518 | /* aspect ratios are applied exclusive to the m_size_hints.base_width | ||
1519 | * | ||
1520 | * m_size_hints.min_aspect_x width m_size_hints.max_aspect_x | ||
1521 | * ------------ < ------- < ------------ | ||
1522 | * m_size_hints.min_aspect_y height m_size_hints.max_aspect_y | ||
1523 | * | ||
1524 | * beware of integer maximum (so I'll use doubles instead and divide) | ||
1525 | * | ||
1526 | * The trick is how to get back to the aspect ratio with minimal | ||
1527 | * change - do we modify x, y or both? | ||
1528 | * A: we minimise the distance between the current point, and | ||
1529 | * the target aspect ratio (consider them as x,y coordinates) | ||
1530 | * Consider that the aspect ratio is a line, and the current | ||
1531 | * w/h is a point, so we're just using the formula for | ||
1532 | * shortest distance from a point to a line! | ||
1533 | * | ||
1534 | * When maximizing, we must not increase any of the sizes, because we | ||
1535 | * would end up with the window partly off a screen, so a simpler formula | ||
1536 | * is used in that case. | ||
1537 | */ | ||
1538 | |||
1539 | if (m_size_hints.min_aspect_y > 0 && m_size_hints.max_aspect_y > 0 && | ||
1540 | (height - m_size_hints.base_height) > 0) { | ||
1541 | double widthd = static_cast<double>(width - m_size_hints.base_width); | ||
1542 | double heightd = static_cast<double>(height - m_size_hints.base_height); | ||
1543 | |||
1544 | double min = static_cast<double>(m_size_hints.min_aspect_x) / | ||
1545 | static_cast<double>(m_size_hints.min_aspect_y); | ||
1546 | |||
1547 | double max = static_cast<double>(m_size_hints.max_aspect_x) / | ||
1548 | static_cast<double>(m_size_hints.max_aspect_y); | ||
1549 | |||
1550 | double actual = widthd / heightd; | ||
1551 | |||
1552 | if (max > 0 && min > 0 && actual > 0) { // don't even try otherwise | ||
1553 | bool changed = false; | ||
1554 | if (actual < min) { | ||
1555 | changed = true; | ||
1556 | if (maximizing) | ||
1557 | heightd = widthd / min; | ||
1558 | else | ||
1559 | closestPointToLine(widthd, heightd, widthd, heightd, min); | ||
1560 | } else if (actual > max) { | ||
1561 | changed = true; | ||
1562 | if (maximizing) | ||
1563 | widthd = heightd * max; | ||
1564 | else | ||
1565 | closestPointToLine(widthd, heightd, widthd, heightd, max); | ||
1566 | } | ||
1567 | |||
1568 | if (changed) { | ||
1569 | width = static_cast<int>(widthd) + m_size_hints.base_width; | ||
1570 | height = static_cast<int>(heightd) + m_size_hints.base_height; | ||
1571 | } | ||
1572 | } | ||
1573 | } | ||
1574 | |||
1575 | // enforce incremental size limits, wrt base size | ||
1576 | // only calculate this if we really need to | ||
1577 | i = (width - static_cast<signed>(m_size_hints.base_width)) / | ||
1578 | static_cast<signed>(m_size_hints.width_inc); | ||
1579 | width = i*static_cast<signed>(m_size_hints.width_inc) + | ||
1580 | static_cast<signed>(m_size_hints.base_width); | ||
1581 | |||
1582 | j = (height - static_cast<signed>(m_size_hints.base_height)) / | ||
1583 | static_cast<signed>(m_size_hints.height_inc); | ||
1584 | height = j*static_cast<signed>(m_size_hints.height_inc) + | ||
1585 | static_cast<signed>(m_size_hints.base_height); | ||
1586 | |||
1587 | if (display_width) | ||
1588 | *display_width = i; | ||
1589 | |||
1590 | if (display_height) | ||
1591 | *display_height = j; | ||
1592 | } | ||
1593 | |||
1594 | bool FbWinFrame::setBorderWidth(bool do_move) { | 1462 | bool FbWinFrame::setBorderWidth(bool do_move) { |
1595 | unsigned int border_width = theme()->border().width(); | 1463 | unsigned int border_width = theme()->border().width(); |
1596 | unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0; | 1464 | unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0; |
@@ -1800,3 +1668,124 @@ int FbWinFrame::yOffset() const { | |||
1800 | return 0; | 1668 | return 0; |
1801 | } | 1669 | } |
1802 | 1670 | ||
1671 | /* For aspect ratios | ||
1672 | Note that its slightly simplified in that only the | ||
1673 | line gradient is given - this is because for aspect | ||
1674 | ratios, we always have the line going through the origin | ||
1675 | |||
1676 | * Based on this formula: | ||
1677 | http://astronomy.swin.edu.au/~pbourke/geometry/pointline/ | ||
1678 | |||
1679 | Note that a gradient from origin goes through ( grad , 1 ) | ||
1680 | */ | ||
1681 | |||
1682 | void closestPointToAspect(unsigned int &ret_x, unsigned int &ret_y, | ||
1683 | unsigned int point_x, unsigned int point_y, | ||
1684 | unsigned int aspect_x, unsigned int aspect_y) { | ||
1685 | double u = static_cast<double>(point_x * aspect_x + point_y * aspect_y) / | ||
1686 | static_cast<double>(aspect_x * aspect_x + aspect_y * aspect_y); | ||
1687 | |||
1688 | ret_x = static_cast<unsigned int>(u * aspect_x); | ||
1689 | ret_y = static_cast<unsigned int>(u * aspect_y); | ||
1690 | } | ||
1691 | |||
1692 | /** | ||
1693 | * Changes width and height to the nearest (lower) value | ||
1694 | * that conforms to it's size hints. | ||
1695 | * | ||
1696 | * display_* give the values that would be displayed | ||
1697 | * to the user when resizing. | ||
1698 | * We use pointers for display_* since they are optional. | ||
1699 | * | ||
1700 | * See ICCCM section 4.1.2.3 | ||
1701 | */ | ||
1702 | void FbWinFrame::SizeHints::apply(unsigned int &width, unsigned int &height, | ||
1703 | bool maximizing) const { | ||
1704 | |||
1705 | // we apply aspect ratios before incrementals | ||
1706 | // Too difficult to exactly satisfy both incremental+aspect | ||
1707 | // in most situations | ||
1708 | // (they really shouldn't happen at the same time anyway). | ||
1709 | |||
1710 | /* aspect ratios are applied exclusive to the base size | ||
1711 | * | ||
1712 | * min_aspect_x width max_aspect_x | ||
1713 | * ------------ < ------- < ------------ | ||
1714 | * min_aspect_y height max_aspect_y | ||
1715 | * | ||
1716 | * beware of integer maximum (so I'll use doubles instead and divide) | ||
1717 | * | ||
1718 | * The trick is how to get back to the aspect ratio with minimal | ||
1719 | * change - do we modify x, y or both? | ||
1720 | * A: we minimise the distance between the current point, and | ||
1721 | * the target aspect ratio (consider them as x,y coordinates) | ||
1722 | * Consider that the aspect ratio is a line, and the current | ||
1723 | * w/h is a point, so we're just using the formula for | ||
1724 | * shortest distance from a point to a line! | ||
1725 | * | ||
1726 | * When maximizing, we must not increase any of the sizes, because we | ||
1727 | * would end up with the window partly off a screen, so a simpler formula | ||
1728 | * is used in that case. | ||
1729 | */ | ||
1730 | |||
1731 | if (min_aspect_y > 0 && width*min_aspect_y < min_aspect_x*height) { | ||
1732 | if (maximizing) | ||
1733 | height = width * min_aspect_y / min_aspect_x; | ||
1734 | else | ||
1735 | closestPointToAspect(width, height, width, height, | ||
1736 | min_aspect_x, min_aspect_y); | ||
1737 | } else if (max_aspect_x > 0 && width*max_aspect_y > max_aspect_x*height) { | ||
1738 | if (maximizing) | ||
1739 | width = height * max_aspect_x / max_aspect_y; | ||
1740 | else | ||
1741 | closestPointToAspect(width, height, width, height, | ||
1742 | max_aspect_x, max_aspect_y); | ||
1743 | } | ||
1744 | |||
1745 | // Check minimum size | ||
1746 | if (width < min_width) | ||
1747 | width = min_width; | ||
1748 | |||
1749 | if (height < min_height) | ||
1750 | height = min_height; | ||
1751 | |||
1752 | // Check maximum size | ||
1753 | if (max_width > 0 && width > max_width) | ||
1754 | width = max_width; | ||
1755 | |||
1756 | if (max_height > 0 && height > max_height) | ||
1757 | height = max_height; | ||
1758 | |||
1759 | // enforce incremental size limits, wrt base size | ||
1760 | width -= (width - base_width) % width_inc; | ||
1761 | height -= (height - base_height) % height_inc; | ||
1762 | } | ||
1763 | |||
1764 | // check if the given width and height satisfy the size hints | ||
1765 | bool FbWinFrame::SizeHints::valid(unsigned int w, unsigned int h) const { | ||
1766 | if (w < min_width || h < min_height) | ||
1767 | return false; | ||
1768 | |||
1769 | if (w > max_width || h > max_height) | ||
1770 | return false; | ||
1771 | |||
1772 | if ((w - base_width) % width_inc != 0) | ||
1773 | return false; | ||
1774 | |||
1775 | if ((h - base_height) % height_inc != 0) | ||
1776 | return false; | ||
1777 | |||
1778 | if (min_aspect_x * h > w * min_aspect_y) | ||
1779 | return false; | ||
1780 | |||
1781 | if (max_aspect_x * h < w * max_aspect_y) | ||
1782 | return false; | ||
1783 | |||
1784 | return true; | ||
1785 | } | ||
1786 | |||
1787 | void FbWinFrame::SizeHints::displaySize(int &i, int &j, | ||
1788 | unsigned int width, unsigned int height) const { | ||
1789 | i = static_cast<signed>(width - base_width) / width_inc; | ||
1790 | j = static_cast<signed>(height - base_height) / height_inc; | ||
1791 | } | ||
diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh index d2a27c9..70f0a4c 100644 --- a/src/FbWinFrame.hh +++ b/src/FbWinFrame.hh | |||
@@ -96,6 +96,11 @@ public: | |||
96 | }; | 96 | }; |
97 | 97 | ||
98 | typedef struct SizeHints { | 98 | typedef struct SizeHints { |
99 | void apply(unsigned int &w, unsigned int &h, | ||
100 | bool maximizing = false) const; | ||
101 | bool valid(unsigned int width, unsigned int height) const; | ||
102 | void displaySize(int &i, int &j, | ||
103 | unsigned int width, unsigned int height) const; | ||
99 | unsigned int min_width; | 104 | unsigned int min_width; |
100 | unsigned int max_width; | 105 | unsigned int max_width; |
101 | unsigned int min_height; | 106 | unsigned int min_height; |
@@ -200,16 +205,7 @@ public: | |||
200 | /// remove any handler for the windows | 205 | /// remove any handler for the windows |
201 | void removeEventHandler(); | 206 | void removeEventHandler(); |
202 | 207 | ||
203 | /** | 208 | const SizeHints &sizeHints() const { return m_size_hints; } |
204 | * Changes width and height to the nearest (lower) value | ||
205 | * that conforms to it's size hints. | ||
206 | * | ||
207 | * display_* give the values that would be displayed | ||
208 | * to the user when resizing. | ||
209 | * We use pointers for display_* since they are optional. | ||
210 | */ | ||
211 | void applySizeHints(int &width, int &height, int *display_width = 0, | ||
212 | int *display_height = 0, bool maximizing = false); | ||
213 | void setSizeHints(const SizeHints &hint) { m_size_hints = hint; } | 209 | void setSizeHints(const SizeHints &hint) { m_size_hints = hint; } |
214 | 210 | ||
215 | void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; } | 211 | void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; } |
diff --git a/src/WinClient.cc b/src/WinClient.cc index b9602ec..f421013 100644 --- a/src/WinClient.cc +++ b/src/WinClient.cc | |||
@@ -690,31 +690,6 @@ void WinClient::updateWMProtocols() { | |||
690 | 690 | ||
691 | } | 691 | } |
692 | 692 | ||
693 | // check if the given width and height satisfy the size hints | ||
694 | bool WinClient::checkSizeHints(unsigned int width, unsigned int height) { | ||
695 | if (width < m_size_hints.min_width || height < m_size_hints.min_height) | ||
696 | return false; | ||
697 | |||
698 | if (width > m_size_hints.max_width || height > m_size_hints.max_height) | ||
699 | return false; | ||
700 | |||
701 | if ((width - m_size_hints.base_width) % m_size_hints.width_inc != 0) | ||
702 | return false; | ||
703 | |||
704 | if ((height - m_size_hints.base_height) % m_size_hints.height_inc != 0) | ||
705 | return false; | ||
706 | |||
707 | double ratio = (double)width / (double)height; | ||
708 | |||
709 | if (m_size_hints.min_aspect_y > 0 && (double)m_size_hints.min_aspect_x / (double)m_size_hints.min_aspect_y > ratio) | ||
710 | return false; | ||
711 | |||
712 | if (m_size_hints.max_aspect_y > 0 && (double)m_size_hints.max_aspect_x / (double)m_size_hints.max_aspect_y < ratio) | ||
713 | return false; | ||
714 | |||
715 | return true; | ||
716 | } | ||
717 | |||
718 | void WinClient::removeTransientFromWaitingList() { | 693 | void WinClient::removeTransientFromWaitingList() { |
719 | 694 | ||
720 | // holds the windows that dont have empty | 695 | // holds the windows that dont have empty |
diff --git a/src/WinClient.hh b/src/WinClient.hh index 9c6dc9e..54c431d 100644 --- a/src/WinClient.hh +++ b/src/WinClient.hh | |||
@@ -81,8 +81,6 @@ public: | |||
81 | void setAttentionState(bool value); | 81 | void setAttentionState(bool value); |
82 | const std::string &title() const { return m_title; } | 82 | const std::string &title() const { return m_title; } |
83 | 83 | ||
84 | bool checkSizeHints(unsigned int width, unsigned int height); | ||
85 | |||
86 | void setGroupLeftWindow(Window win); | 84 | void setGroupLeftWindow(Window win); |
87 | 85 | ||
88 | void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements); | 86 | void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements); |
diff --git a/src/Window.cc b/src/Window.cc index 45c1e9d..2a2dbd9 100644 --- a/src/Window.cc +++ b/src/Window.cc | |||
@@ -550,9 +550,9 @@ void FluxboxWindow::init() { | |||
550 | } | 550 | } |
551 | #endif // DEBUG | 551 | #endif // DEBUG |
552 | 552 | ||
553 | int real_width = frame().width(); | 553 | unsigned int real_width = frame().width(); |
554 | int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight(); | 554 | unsigned int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight(); |
555 | frame().applySizeHints(real_width, real_height); | 555 | frame().sizeHints().apply(real_width, real_height); |
556 | real_height += frame().titlebarHeight() + frame().handleHeight(); | 556 | real_height += frame().titlebarHeight() + frame().handleHeight(); |
557 | 557 | ||
558 | if (m_placed) | 558 | if (m_placed) |
@@ -2483,12 +2483,12 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) { | |||
2483 | // make sure the new width/height would be ok with all clients, or else they | 2483 | // make sure the new width/height would be ok with all clients, or else they |
2484 | // could try to resize the window back and forth | 2484 | // could try to resize the window back and forth |
2485 | if (cr.value_mask & CWWidth || cr.value_mask & CWHeight) { | 2485 | if (cr.value_mask & CWWidth || cr.value_mask & CWHeight) { |
2486 | int new_w = (cr.value_mask & CWWidth) ? cr.width : cw; | 2486 | unsigned int new_w = (cr.value_mask & CWWidth) ? cr.width : cw; |
2487 | int new_h = (cr.value_mask & CWHeight) ? cr.height : ch; | 2487 | unsigned int new_h = (cr.value_mask & CWHeight) ? cr.height : ch; |
2488 | ClientList::iterator it = clientList().begin(); | 2488 | ClientList::iterator it = clientList().begin(); |
2489 | ClientList::iterator it_end = clientList().end(); | 2489 | ClientList::iterator it_end = clientList().end(); |
2490 | for (; it != it_end; ++it) { | 2490 | for (; it != it_end; ++it) { |
2491 | if (*it != client && !(*it)->checkSizeHints(new_w, new_h)) | 2491 | if (*it != client && !(*it)->sizeHints().valid(new_w, new_h)) |
2492 | cr.value_mask = cr.value_mask & ~(CWWidth | CWHeight); | 2492 | cr.value_mask = cr.value_mask & ~(CWWidth | CWHeight); |
2493 | } | 2493 | } |
2494 | } | 2494 | } |
@@ -3725,12 +3725,14 @@ void FluxboxWindow::fixsize(int *user_w, int *user_h, bool maximizing) { | |||
3725 | 3725 | ||
3726 | // dx is new width = current width + difference between new and old x values | 3726 | // dx is new width = current width + difference between new and old x values |
3727 | //int dx = frame().width() + frame().x() - m_last_resize_x; | 3727 | //int dx = frame().width() + frame().x() - m_last_resize_x; |
3728 | int dw = m_last_resize_w; | 3728 | unsigned int dw = m_last_resize_w; |
3729 | 3729 | ||
3730 | // dy = new height (w/o decorations), similarly | 3730 | // dy = new height (w/o decorations), similarly |
3731 | int dh = m_last_resize_h - decoration_height; | 3731 | unsigned int dh = m_last_resize_h - decoration_height; |
3732 | 3732 | ||
3733 | frame().applySizeHints(dw, dh, user_w, user_h, maximizing); | 3733 | frame().sizeHints().apply(dw, dh, maximizing); |
3734 | if (user_w && user_h) | ||
3735 | frame().sizeHints().displaySize(*user_w, *user_h, dw, dh); | ||
3734 | 3736 | ||
3735 | // update last resize | 3737 | // update last resize |
3736 | m_last_resize_w = dw; | 3738 | m_last_resize_w = dw; |