aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/FbWinFrame.cc132
-rw-r--r--src/FbWinFrame.hh28
-rw-r--r--src/WinClient.cc132
-rw-r--r--src/WinClient.hh29
-rw-r--r--src/Window.cc6
5 files changed, 167 insertions, 160 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;
diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh
index e24612e..d2a27c9 100644
--- a/src/FbWinFrame.hh
+++ b/src/FbWinFrame.hh
@@ -95,6 +95,21 @@ public:
95 DECOR_TAB = DECORM_BORDER|DECORM_MENU|DECORM_TAB 95 DECOR_TAB = DECORM_BORDER|DECORM_MENU|DECORM_TAB
96 }; 96 };
97 97
98 typedef struct SizeHints {
99 unsigned int min_width;
100 unsigned int max_width;
101 unsigned int min_height;
102 unsigned int max_height;
103 unsigned int width_inc;
104 unsigned int height_inc;
105 unsigned int min_aspect_x;
106 unsigned int max_aspect_x;
107 unsigned int min_aspect_y;
108 unsigned int max_aspect_y;
109 unsigned int base_width;
110 unsigned int base_height;
111 } SizeHints;
112
98 /// create a top level window 113 /// create a top level window
99 FbWinFrame(BScreen &screen, FocusableTheme<FbWinFrameTheme> &theme, 114 FbWinFrame(BScreen &screen, FocusableTheme<FbWinFrameTheme> &theme,
100 FbTk::ImageControl &imgctrl, 115 FbTk::ImageControl &imgctrl,
@@ -185,6 +200,18 @@ public:
185 /// remove any handler for the windows 200 /// remove any handler for the windows
186 void removeEventHandler(); 201 void removeEventHandler();
187 202
203 /**
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; }
214
188 void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; } 215 void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; }
189 void applyDecorations(); 216 void applyDecorations();
190 217
@@ -392,6 +419,7 @@ private:
392 // last gravity that this window was *actively* placed with 419 // last gravity that this window was *actively* placed with
393 int m_active_gravity; 420 int m_active_gravity;
394 unsigned int m_active_orig_client_bw; 421 unsigned int m_active_orig_client_bw;
422 SizeHints m_size_hints;
395 423
396 bool m_need_render; 424 bool m_need_render;
397 int m_button_size; ///< size for all titlebar buttons 425 int m_button_size; ///< size for all titlebar buttons
diff --git a/src/WinClient.cc b/src/WinClient.cc
index 9aac38d..b9602ec 100644
--- a/src/WinClient.cc
+++ b/src/WinClient.cc
@@ -690,138 +690,6 @@ void WinClient::updateWMProtocols() {
690 690
691} 691}
692 692
693/* For aspect ratios
694 Note that its slightly simplified in that only the
695 line gradient is given - this is because for aspect
696 ratios, we always have the line going through the origin
697
698 * Based on this formula:
699 http://astronomy.swin.edu.au/~pbourke/geometry/pointline/
700
701 Note that a gradient from origin goes through ( grad , 1 )
702 */
703
704void closestPointToLine(double &ret_x, double &ret_y,
705 double point_x, double point_y,
706 double gradient) {
707 double u = (point_x * gradient + point_y) /
708 (gradient*gradient + 1);
709
710 ret_x = u*gradient;
711 ret_y = u;
712}
713
714/**
715 * Changes width and height to the nearest (lower) value
716 * that conforms to it's size hints.
717 *
718 * display_* give the values that would be displayed
719 * to the user when resizing.
720 * We use pointers for display_* since they are optional.
721 *
722 * See ICCCM section 4.1.2.3
723 */
724void WinClient::applySizeHints(int &width, int &height,
725 int *display_width, int *display_height,
726 bool maximizing) {
727
728 int i = width, j = height;
729
730 // Check minimum size
731 if (width < 0 || width < static_cast<signed>(m_size_hints.min_width))
732 width = m_size_hints.min_width;
733
734 if (height < 0 || height < static_cast<signed>(m_size_hints.min_height))
735 height = m_size_hints.min_height;
736
737 // Check maximum size
738 if (m_size_hints.max_width > 0 && width > static_cast<signed>(m_size_hints.max_width))
739 width = m_size_hints.max_width;
740
741 if (m_size_hints.max_height > 0 && height > static_cast<signed>(m_size_hints.max_height))
742 height = m_size_hints.max_height;
743
744 // we apply aspect ratios before incrementals
745 // Too difficult to exactly satisfy both incremental+aspect
746 // in most situations
747 // (they really shouldn't happen at the same time anyway).
748
749 /* aspect ratios are applied exclusive to the m_size_hints.base_width
750 *
751 * m_size_hints.min_aspect_x width m_size_hints.max_aspect_x
752 * ------------ < ------- < ------------
753 * m_size_hints.min_aspect_y height m_size_hints.max_aspect_y
754 *
755 * beware of integer maximum (so I'll use doubles instead and divide)
756 *
757 * The trick is how to get back to the aspect ratio with minimal
758 * change - do we modify x, y or both?
759 * A: we minimise the distance between the current point, and
760 * the target aspect ratio (consider them as x,y coordinates)
761 * Consider that the aspect ratio is a line, and the current
762 * w/h is a point, so we're just using the formula for
763 * shortest distance from a point to a line!
764 *
765 * When maximizing, we must not increase any of the sizes, because we
766 * would end up with the window partly off a screen, so a simpler formula
767 * is used in that case.
768 */
769
770 if (m_size_hints.min_aspect_y > 0 && m_size_hints.max_aspect_y > 0 &&
771 (height - m_size_hints.base_height) > 0) {
772 double widthd = static_cast<double>(width - m_size_hints.base_width);
773 double heightd = static_cast<double>(height - m_size_hints.base_height);
774
775 double min = static_cast<double>(m_size_hints.min_aspect_x) /
776 static_cast<double>(m_size_hints.min_aspect_y);
777
778 double max = static_cast<double>(m_size_hints.max_aspect_x) /
779 static_cast<double>(m_size_hints.max_aspect_y);
780
781 double actual = widthd / heightd;
782
783 if (max > 0 && min > 0 && actual > 0) { // don't even try otherwise
784 bool changed = false;
785 if (actual < min) {
786 changed = true;
787 if (maximizing)
788 heightd = widthd / min;
789 else
790 closestPointToLine(widthd, heightd, widthd, heightd, min);
791 } else if (actual > max) {
792 changed = true;
793 if (maximizing)
794 widthd = heightd * max;
795 else
796 closestPointToLine(widthd, heightd, widthd, heightd, max);
797 }
798
799 if (changed) {
800 width = static_cast<int>(widthd) + m_size_hints.base_width;
801 height = static_cast<int>(heightd) + m_size_hints.base_height;
802 }
803 }
804 }
805
806 // enforce incremental size limits, wrt base size
807 // only calculate this if we really need to
808 i = (width - static_cast<signed>(m_size_hints.base_width)) /
809 static_cast<signed>(m_size_hints.width_inc);
810 width = i*static_cast<signed>(m_size_hints.width_inc) +
811 static_cast<signed>(m_size_hints.base_width);
812
813 j = (height - static_cast<signed>(m_size_hints.base_height)) /
814 static_cast<signed>(m_size_hints.height_inc);
815 height = j*static_cast<signed>(m_size_hints.height_inc) +
816 static_cast<signed>(m_size_hints.base_height);
817
818 if (display_width)
819 *display_width = i;
820
821 if (display_height)
822 *display_height = j;
823}
824
825// check if the given width and height satisfy the size hints 693// check if the given width and height satisfy the size hints
826bool WinClient::checkSizeHints(unsigned int width, unsigned int height) { 694bool WinClient::checkSizeHints(unsigned int width, unsigned int height) {
827 if (width < m_size_hints.min_width || height < m_size_hints.min_height) 695 if (width < m_size_hints.min_width || height < m_size_hints.min_height)
diff --git a/src/WinClient.hh b/src/WinClient.hh
index 51d3b3e..9c6dc9e 100644
--- a/src/WinClient.hh
+++ b/src/WinClient.hh
@@ -22,6 +22,7 @@
22#ifndef WINCLIENT_HH 22#ifndef WINCLIENT_HH
23#define WINCLIENT_HH 23#define WINCLIENT_HH
24 24
25#include "FbWinFrame.hh"
25#include "Window.hh" 26#include "Window.hh"
26#include "FbTk/FbWindow.hh" 27#include "FbTk/FbWindow.hh"
27#include "FbTk/FbString.hh" 28#include "FbTk/FbString.hh"
@@ -43,21 +44,6 @@ public:
43 unsigned long decorations; // Motif wm decorations 44 unsigned long decorations; // Motif wm decorations
44 } MwmHints; 45 } MwmHints;
45 46
46 typedef struct SizeHints {
47 unsigned int min_width;
48 unsigned int max_width;
49 unsigned int min_height;
50 unsigned int max_height;
51 unsigned int width_inc;
52 unsigned int height_inc;
53 unsigned int min_aspect_x;
54 unsigned int max_aspect_x;
55 unsigned int min_aspect_y;
56 unsigned int max_aspect_y;
57 unsigned int base_width;
58 unsigned int base_height;
59 } SizeHints;
60
61 WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin = 0); 47 WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin = 0);
62 48
63 ~WinClient(); 49 ~WinClient();
@@ -95,16 +81,6 @@ public:
95 void setAttentionState(bool value); 81 void setAttentionState(bool value);
96 const std::string &title() const { return m_title; } 82 const std::string &title() const { return m_title; }
97 83
98 /**
99 * Changes width and height to the nearest (lower) value
100 * that conforms to it's size hints.
101 *
102 * display_* give the values that would be displayed
103 * to the user when resizing.
104 * We use pointers for display_* since they are optional.
105 */
106 void applySizeHints(int &width, int &height, int *display_width = 0,
107 int *display_height = 0, bool maximizing = false);
108 bool checkSizeHints(unsigned int width, unsigned int height); 84 bool checkSizeHints(unsigned int width, unsigned int height);
109 85
110 void setGroupLeftWindow(Window win); 86 void setGroupLeftWindow(Window win);
@@ -143,6 +119,7 @@ public:
143 Window getGroupLeftWindow() const; 119 Window getGroupLeftWindow() const;
144 120
145 const MwmHints *getMwmHint() const { return m_mwm_hint; } 121 const MwmHints *getMwmHint() const { return m_mwm_hint; }
122 const FbWinFrame::SizeHints &sizeHints() const { return m_size_hints; }
146 123
147 unsigned int minWidth() const { return m_size_hints.min_width; } 124 unsigned int minWidth() const { return m_size_hints.min_width; }
148 unsigned int minHeight() const { return m_size_hints.min_height; } 125 unsigned int minHeight() const { return m_size_hints.min_height; }
@@ -187,7 +164,7 @@ private:
187 164
188 Focusable::WindowType m_window_type; 165 Focusable::WindowType m_window_type;
189 MwmHints *m_mwm_hint; 166 MwmHints *m_mwm_hint;
190 SizeHints m_size_hints; 167 FbWinFrame::SizeHints m_size_hints;
191 168
192 Strut *m_strut; 169 Strut *m_strut;
193 // map transient_for X window to winclient transient 170 // map transient_for X window to winclient transient
diff --git a/src/Window.cc b/src/Window.cc
index 651b995..45c1e9d 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -552,7 +552,7 @@ void FluxboxWindow::init() {
552 552
553 int real_width = frame().width(); 553 int real_width = frame().width();
554 int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight(); 554 int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight();
555 m_client->applySizeHints(real_width, real_height); 555 frame().applySizeHints(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)
@@ -1066,6 +1066,7 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
1066 // frame focused doesn't necessarily mean input focused 1066 // frame focused doesn't necessarily mean input focused
1067 frame().setLabelButtonFocus(*button); 1067 frame().setLabelButtonFocus(*button);
1068 frame().setShapingClient(&client, false); 1068 frame().setShapingClient(&client, false);
1069 frame().setSizeHints(client.sizeHints());
1069 return ret; 1070 return ret;
1070} 1071}
1071 1072
@@ -1090,6 +1091,7 @@ void FluxboxWindow::associateClientWindow(bool use_attrs,
1090 frame().resizeForClient(m_client->width(), m_client->height()); 1091 frame().resizeForClient(m_client->width(), m_client->height());
1091 1092
1092 frame().setActiveGravity(m_client->gravity(), m_client->old_bw); 1093 frame().setActiveGravity(m_client->gravity(), m_client->old_bw);
1094 frame().setSizeHints(m_client->sizeHints());
1093 frame().setClientWindow(*m_client); 1095 frame().setClientWindow(*m_client);
1094} 1096}
1095 1097
@@ -3728,7 +3730,7 @@ void FluxboxWindow::fixsize(int *user_w, int *user_h, bool maximizing) {
3728 // dy = new height (w/o decorations), similarly 3730 // dy = new height (w/o decorations), similarly
3729 int dh = m_last_resize_h - decoration_height; 3731 int dh = m_last_resize_h - decoration_height;
3730 3732
3731 m_client->applySizeHints(dw, dh, user_w, user_h, maximizing); 3733 frame().applySizeHints(dw, dh, user_w, user_h, maximizing);
3732 3734
3733 // update last resize 3735 // update last resize
3734 m_last_resize_w = dw; 3736 m_last_resize_w = dw;