1 /*
2 * This file is part of mpv.
3 *
4 * mpv is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * mpv is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "win_state.h"
19 #include "vo.h"
20
21 #include "video/mp_image.h"
22
calc_monitor_aspect(struct mp_vo_opts * opts,int scr_w,int scr_h,double * pixelaspect,int * w,int * h)23 static void calc_monitor_aspect(struct mp_vo_opts *opts, int scr_w, int scr_h,
24 double *pixelaspect, int *w, int *h)
25 {
26 *pixelaspect = 1.0 / opts->monitor_pixel_aspect;
27
28 if (scr_w > 0 && scr_h > 0 && opts->force_monitor_aspect)
29 *pixelaspect = 1.0 / (opts->force_monitor_aspect * scr_h / scr_w);
30
31 if (*pixelaspect < 1) {
32 *h /= *pixelaspect;
33 } else {
34 *w *= *pixelaspect;
35 }
36 }
37
38 // Fit *w/*h into the size specified by geo.
apply_autofit(int * w,int * h,int scr_w,int scr_h,struct m_geometry * geo,bool allow_up,bool allow_down)39 static void apply_autofit(int *w, int *h, int scr_w, int scr_h,
40 struct m_geometry *geo, bool allow_up, bool allow_down)
41 {
42 if (!geo->wh_valid)
43 return;
44
45 int dummy = 0;
46 int n_w = *w, n_h = *h;
47 m_geometry_apply(&dummy, &dummy, &n_w, &n_h, scr_w, scr_h, geo);
48
49 if (!allow_up && *w <= n_w && *h <= n_h)
50 return;
51 if (!allow_down && *w >= n_w && *h >= n_h)
52 return;
53
54 // If aspect mismatches, always make the window smaller than the fit box
55 // (Or larger, if allow_down==false.)
56 double asp = (double)*w / *h;
57 double n_asp = (double)n_w / n_h;
58 if ((n_asp <= asp) == allow_down) {
59 *w = n_w;
60 *h = n_w / asp;
61 } else {
62 *w = n_h * asp;
63 *h = n_h;
64 }
65 }
66
67 // Compute the "suggested" window size and position and return it in *out_geo.
68 // screen is the bounding box of the current screen within the virtual desktop.
69 // Does not change *vo.
70 // screen: position of the area on virtual desktop on which the video-content
71 // should be placed (maybe after excluding decorations, taskbars, etc)
72 // monitor: position of the monitor on virtual desktop (used for pixelaspect).
73 // dpi_scale: the DPI multiplier to get from virtual to real coordinates
74 // (>1 for "hidpi")
75 // Use vo_apply_window_geometry() to copy the result into the vo.
76 // NOTE: currently, all windowing backends do their own handling of window
77 // geometry additional to this code. This is to deal with initial window
78 // placement, fullscreen handling, avoiding resize on reconfig() with no
79 // size change, multi-monitor stuff, and possibly more.
vo_calc_window_geometry3(struct vo * vo,const struct mp_rect * screen,const struct mp_rect * monitor,double dpi_scale,struct vo_win_geometry * out_geo)80 void vo_calc_window_geometry3(struct vo *vo, const struct mp_rect *screen,
81 const struct mp_rect *monitor,
82 double dpi_scale, struct vo_win_geometry *out_geo)
83 {
84 struct mp_vo_opts *opts = vo->opts;
85
86 *out_geo = (struct vo_win_geometry){0};
87
88 // The case of calling this function even though no video was configured
89 // yet (i.e. vo->params==NULL) happens when vo_gpu creates a hidden window
90 // in order to create a rendering context.
91 struct mp_image_params params = { .w = 320, .h = 200 };
92 if (vo->params)
93 params = *vo->params;
94
95 if (!opts->hidpi_window_scale)
96 dpi_scale = 1;
97
98 int d_w, d_h;
99 mp_image_params_get_dsize(¶ms, &d_w, &d_h);
100 if ((vo->driver->caps & VO_CAP_ROTATE90) && params.rotate % 180 == 90)
101 MPSWAP(int, d_w, d_h);
102 d_w = MPCLAMP(d_w * opts->window_scale * dpi_scale, 1, 16000);
103 d_h = MPCLAMP(d_h * opts->window_scale * dpi_scale, 1, 16000);
104
105 int scr_w = screen->x1 - screen->x0;
106 int scr_h = screen->y1 - screen->y0;
107
108 int mon_w = monitor->x1 - monitor->x0;
109 int mon_h = monitor->y1 - monitor->y0;
110
111 MP_DBG(vo, "max content size: %dx%d\n", scr_w, scr_h);
112 MP_DBG(vo, "monitor size: %dx%d\n", mon_w, mon_h);
113
114 calc_monitor_aspect(opts, mon_w, mon_h, &out_geo->monitor_par, &d_w, &d_h);
115
116 apply_autofit(&d_w, &d_h, scr_w, scr_h, &opts->autofit, true, true);
117 apply_autofit(&d_w, &d_h, scr_w, scr_h, &opts->autofit_smaller, true, false);
118 apply_autofit(&d_w, &d_h, scr_w, scr_h, &opts->autofit_larger, false, true);
119
120 out_geo->win.x0 = (int)(scr_w - d_w) / 2;
121 out_geo->win.y0 = (int)(scr_h - d_h) / 2;
122 m_geometry_apply(&out_geo->win.x0, &out_geo->win.y0, &d_w, &d_h,
123 scr_w, scr_h, &opts->geometry);
124
125 out_geo->win.x0 += screen->x0;
126 out_geo->win.y0 += screen->y0;
127 out_geo->win.x1 = out_geo->win.x0 + d_w;
128 out_geo->win.y1 = out_geo->win.y0 + d_h;
129
130 if (opts->geometry.xy_valid || opts->force_window_position)
131 out_geo->flags |= VO_WIN_FORCE_POS;
132 }
133
134 // same as vo_calc_window_geometry3 with monitor assumed same as screen
vo_calc_window_geometry2(struct vo * vo,const struct mp_rect * screen,double dpi_scale,struct vo_win_geometry * out_geo)135 void vo_calc_window_geometry2(struct vo *vo, const struct mp_rect *screen,
136 double dpi_scale, struct vo_win_geometry *out_geo)
137 {
138 vo_calc_window_geometry3(vo, screen, screen, dpi_scale, out_geo);
139 }
140
vo_calc_window_geometry(struct vo * vo,const struct mp_rect * screen,struct vo_win_geometry * out_geo)141 void vo_calc_window_geometry(struct vo *vo, const struct mp_rect *screen,
142 struct vo_win_geometry *out_geo)
143 {
144 vo_calc_window_geometry2(vo, screen, 1.0, out_geo);
145 }
146
147 // Copy the parameters in *geo to the vo fields.
148 // (Doesn't do anything else - windowing backends should trigger VO_EVENT_RESIZE
149 // to ensure that the VO reinitializes rendering properly.)
vo_apply_window_geometry(struct vo * vo,const struct vo_win_geometry * geo)150 void vo_apply_window_geometry(struct vo *vo, const struct vo_win_geometry *geo)
151 {
152 vo->dwidth = geo->win.x1 - geo->win.x0;
153 vo->dheight = geo->win.y1 - geo->win.y0;
154 vo->monitor_par = geo->monitor_par;
155 }
156