summaryrefslogtreecommitdiff
path: root/src/FbWinFrame.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbWinFrame.cc')
-rw-r--r--src/FbWinFrame.cc132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc
index afd5fb5..4734b2b 100644
--- a/src/FbWinFrame.cc
+++ b/src/FbWinFrame.cc
@@ -1459,6 +1459,138 @@ 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
1462bool FbWinFrame::setBorderWidth(bool do_move) { 1594bool FbWinFrame::setBorderWidth(bool do_move) {
1463 unsigned int border_width = theme()->border().width(); 1595 unsigned int border_width = theme()->border().width();
1464 unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0; 1596 unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0;