Send correct surface bounds to xdg_toplevel resources

* compositor.h (struct _RoleFuncs)
(struct _XdgRoleImplementationFuncs): New role functions
`outputs_changed'.
* output.c (NoticeOutputsMaybeChanged): Call surface
outputs_changed hook if it exists.
(XLGetMaxOutputBounds): New function.
* xdg_surface.c (OutputsChanged): New function.
(XLGetXdgSurface): Add new role function.
* xdg_toplevel.c (CurrentWindowGeometry): New function.
(SendStates): Factor out geometry calculation to that function.
(SendOutputBounds): New function.
(Commit, OutputsChanged): Send output bounds whenever
appropriate.
(XLGetXdgToplevel): Add new impl func.
This commit is contained in:
hujianwei 2022-10-23 01:07:34 +00:00
parent 6e062e2e2f
commit 276445926e
4 changed files with 129 additions and 10 deletions

View file

@ -1083,6 +1083,7 @@ struct _RoleFuncs
void (*note_child_synced) (Surface *, Role *); void (*note_child_synced) (Surface *, Role *);
void (*select_extra_events) (Surface *, Role *, unsigned long); void (*select_extra_events) (Surface *, Role *, unsigned long);
void (*note_focus) (Surface *, Role *, FocusMode); void (*note_focus) (Surface *, Role *, FocusMode);
void (*outputs_changed) (Surface *, Role *);
}; };
struct _Role struct _Role
@ -1156,6 +1157,7 @@ extern void *XLAddScaleChangeCallback (void *, void (*) (void *, int));
extern void XLRemoveScaleChangeCallback (void *); extern void XLRemoveScaleChangeCallback (void *);
extern void XLClearOutputs (Surface *); extern void XLClearOutputs (Surface *);
extern void XLOutputSetChangeFunction (void (*) (Time)); extern void XLOutputSetChangeFunction (void (*) (Time));
extern void XLGetMaxOutputBounds (int *, int *, int *, int *);
/* Defined in atoms.c. */ /* Defined in atoms.c. */
@ -1275,6 +1277,7 @@ struct _XdgRoleImplementationFuncs
void (*commit_inside_frame) (Role *, XdgRoleImplementation *); void (*commit_inside_frame) (Role *, XdgRoleImplementation *);
Bool (*is_window_mapped) (Role *, XdgRoleImplementation *); Bool (*is_window_mapped) (Role *, XdgRoleImplementation *);
void (*note_focus) (Role *, XdgRoleImplementation *, FocusMode); void (*note_focus) (Role *, XdgRoleImplementation *, FocusMode);
void (*outputs_changed) (Role *, XdgRoleImplementation *);
}; };
struct _XdgRoleImplementation struct _XdgRoleImplementation

View file

@ -653,7 +653,13 @@ NoticeOutputsMaybeChanged (void)
surface = all_surfaces.next; surface = all_surfaces.next;
for (; surface != &all_surfaces; surface = surface->next) for (; surface != &all_surfaces; surface = surface->next)
pixman_region32_clear (&surface->output_region); {
pixman_region32_clear (&surface->output_region);
if (surface->role
&& surface->role->funcs.outputs_changed)
surface->role->funcs.outputs_changed (surface, surface->role);
}
} }
} }
@ -1091,6 +1097,51 @@ XLOutputSetChangeFunction (void (*change_func) (Time))
change_hook = change_func; change_hook = change_func;
} }
void
XLGetMaxOutputBounds (int *x_min, int *y_min, int *x_max,
int *y_max)
{
int x1, y1, x2, y2;
Output *output;
XLList *tem;
x1 = y1 = INT_MAX;
x2 = y2 = INT_MIN;
if (!all_outputs)
{
*x_min = 0;
*y_min = 0;
*x_max = DisplayWidth (compositor.display,
DefaultScreen (compositor.display)) - 1;
*y_max = DisplayHeight (compositor.display,
DefaultScreen (compositor.display)) - 1;
return;
}
for (tem = all_outputs; tem; tem = tem->next)
{
output = tem->data;
if (output->x < x1)
x1 = output->x;
if (output->y < y1)
y1 = output->y;
if (output->x + output->width - 1 > x2)
x2 = output->x + output->width - 1;
if (output->y + output->height - 1 > y2)
y2 = output->y + output->height - 1;
}
*x_min = x1;
*y_min = y1;
*x_max = x2;
*y_max = y2;
}
void void
XLInitRROutputs (void) XLInitRROutputs (void)
{ {
@ -1153,3 +1204,4 @@ XLInitRROutputs (void)
all_outputs = BuildOutputTree (); all_outputs = BuildOutputTree ();
MakeGlobalsForOutputTree (all_outputs); MakeGlobalsForOutputTree (all_outputs);
} }

View file

@ -1457,6 +1457,17 @@ NoteFocus (Surface *surface, Role *role, FocusMode focus)
focus); focus);
} }
static void
OutputsChanged (Surface *surface, Role *role)
{
XdgRole *xdg_role;
xdg_role = XdgRoleFromRole (role);
if (xdg_role->impl && xdg_role->impl->funcs.outputs_changed)
xdg_role->impl->funcs.outputs_changed (role, xdg_role->impl);
}
void void
XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource, XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
uint32_t id, struct wl_resource *surface_resource) uint32_t id, struct wl_resource *surface_resource)
@ -1543,6 +1554,7 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
role->role.funcs.note_child_synced = NoteChildSynced; role->role.funcs.note_child_synced = NoteChildSynced;
role->role.funcs.select_extra_events = SelectExtraEvents; role->role.funcs.select_extra_events = SelectExtraEvents;
role->role.funcs.note_focus = NoteFocus; role->role.funcs.note_focus = NoteFocus;
role->role.funcs.outputs_changed = OutputsChanged;
attrs.colormap = compositor.colormap; attrs.colormap = compositor.colormap;
attrs.border_pixel = border_pixel; attrs.border_pixel = border_pixel;

View file

@ -572,6 +572,22 @@ WriteStates (XdgToplevel *toplevel)
AddState (toplevel, XDG_TOPLEVEL_STATE_RESIZING); AddState (toplevel, XDG_TOPLEVEL_STATE_RESIZING);
} }
static void
CurrentWindowGeometry (XdgToplevel *toplevel,
int *width, int *height)
{
/* Calculate the current window geometry for sending a configure
event. */
TruncateScaleToSurface (toplevel->role->surface,
toplevel->width,
toplevel->height,
width, height);
XLXdgRoleCalcNewWindowSize (toplevel->role, *width,
*height, width, height);
}
static void static void
SendStates (XdgToplevel *toplevel) SendStates (XdgToplevel *toplevel)
{ {
@ -579,16 +595,9 @@ SendStates (XdgToplevel *toplevel)
WriteStates (toplevel); WriteStates (toplevel);
/* Adjust the width and height we're sending by the window geometry. /* toplevel->role->surface should not be NULL here. */
toplevel->role->surface should not be NULL here. */
TruncateScaleToSurface (toplevel->role->surface,
toplevel->width, toplevel->height,
&width, &height);
XLXdgRoleCalcNewWindowSize (toplevel->role, width,
height, &width, &height);
CurrentWindowGeometry (toplevel, &width, &height);
SendConfigure (toplevel, width, height); SendConfigure (toplevel, width, height);
} }
@ -1218,6 +1227,17 @@ AckConfigure (Role *role, XdgRoleImplementation *impl, uint32_t serial)
toplevel->conf_reply = False; toplevel->conf_reply = False;
} }
static void
SendOutputBounds (XdgToplevel *toplevel)
{
int x_min, y_min, x_max, y_max;
XLGetMaxOutputBounds (&x_min, &y_min, &x_max, &y_max);
xdg_toplevel_send_configure_bounds (toplevel->resource,
x_max - x_min + 1,
y_max - y_min + 1);
}
static void static void
Commit (Role *role, Surface *surface, XdgRoleImplementation *impl) Commit (Role *role, Surface *surface, XdgRoleImplementation *impl)
{ {
@ -1255,6 +1275,14 @@ Commit (Role *role, Surface *surface, XdgRoleImplementation *impl)
Unmap (toplevel); Unmap (toplevel);
FlushConfigurationTimer (toplevel); FlushConfigurationTimer (toplevel);
if (wl_resource_get_version (toplevel->resource) >= 4)
/* Send the maximum bounds of the window to the client. It
isn't possible to predict where the window will be mapped,
so unfortunately the precise output bounds can't be used
here. */
SendOutputBounds (toplevel);
SendConfigure (toplevel, 0, 0); SendConfigure (toplevel, 0, 0);
} }
else if (!toplevel->conf_reply) else if (!toplevel->conf_reply)
@ -2181,6 +2209,29 @@ NoteFocus (Role *role, XdgRoleImplementation *impl, FocusMode mode)
} }
} }
static void
OutputsChanged (Role *role, XdgRoleImplementation *impl)
{
XdgToplevel *toplevel;
int width, height;
toplevel = ToplevelFromRoleImpl (impl);
/* The list of outputs changed. Send the new bounds to the
client. */
if (toplevel->resource)
{
if (wl_resource_get_version (toplevel->resource) < 4)
/* The client is too old to accept configure_bounds. */
return;
/* Send the updated bounds to the toplevel. */
SendOutputBounds (toplevel);
CurrentWindowGeometry (toplevel, &width, &height);
SendConfigure (toplevel, width, height);
}
}
static const struct xdg_toplevel_interface xdg_toplevel_impl = static const struct xdg_toplevel_interface xdg_toplevel_impl =
{ {
.destroy = Destroy, .destroy = Destroy,
@ -2242,6 +2293,7 @@ XLGetXdgToplevel (struct wl_client *client, struct wl_resource *resource,
toplevel->impl.funcs.post_resize = PostResize; toplevel->impl.funcs.post_resize = PostResize;
toplevel->impl.funcs.commit_inside_frame = CommitInsideFrame; toplevel->impl.funcs.commit_inside_frame = CommitInsideFrame;
toplevel->impl.funcs.is_window_mapped = IsWindowMapped; toplevel->impl.funcs.is_window_mapped = IsWindowMapped;
toplevel->impl.funcs.outputs_changed = OutputsChanged;
if (!XLWmSupportsHint (_NET_WM_STATE_FOCUSED)) if (!XLWmSupportsHint (_NET_WM_STATE_FOCUSED))
/* If _NET_WM_STATE_FOCUSED is unsupported, fall back to utilizing /* If _NET_WM_STATE_FOCUSED is unsupported, fall back to utilizing