aboutsummaryrefslogtreecommitdiff
path: root/src/FbWinFrame.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbWinFrame.cc')
-rw-r--r--src/FbWinFrame.cc253
1 files changed, 121 insertions, 132 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
1473void 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 */
1493void 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
1594bool FbWinFrame::setBorderWidth(bool do_move) { 1462bool 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
1682void 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 */
1702void 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
1765bool 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
1787void 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}