diff --git a/compositor.h b/compositor.h index 616e8f0..f63a19c 100644 --- a/compositor.h +++ b/compositor.h @@ -1083,6 +1083,7 @@ struct _RoleFuncs void (*note_child_synced) (Surface *, Role *); void (*select_extra_events) (Surface *, Role *, unsigned long); void (*note_focus) (Surface *, Role *, FocusMode); + void (*outputs_changed) (Surface *, Role *); }; struct _Role @@ -1156,6 +1157,7 @@ extern void *XLAddScaleChangeCallback (void *, void (*) (void *, int)); extern void XLRemoveScaleChangeCallback (void *); extern void XLClearOutputs (Surface *); extern void XLOutputSetChangeFunction (void (*) (Time)); +extern void XLGetMaxOutputBounds (int *, int *, int *, int *); /* Defined in atoms.c. */ @@ -1275,6 +1277,7 @@ struct _XdgRoleImplementationFuncs void (*commit_inside_frame) (Role *, XdgRoleImplementation *); Bool (*is_window_mapped) (Role *, XdgRoleImplementation *); void (*note_focus) (Role *, XdgRoleImplementation *, FocusMode); + void (*outputs_changed) (Role *, XdgRoleImplementation *); }; struct _XdgRoleImplementation diff --git a/output.c b/output.c index b37f3bc..d8402fb 100644 --- a/output.c +++ b/output.c @@ -653,7 +653,13 @@ NoticeOutputsMaybeChanged (void) surface = all_surfaces.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; } +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 XLInitRROutputs (void) { @@ -1153,3 +1204,4 @@ XLInitRROutputs (void) all_outputs = BuildOutputTree (); MakeGlobalsForOutputTree (all_outputs); } + diff --git a/xdg_surface.c b/xdg_surface.c index 0b30eaa..4701381 100644 --- a/xdg_surface.c +++ b/xdg_surface.c @@ -1457,6 +1457,17 @@ NoteFocus (Surface *surface, Role *role, FocusMode 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 XLGetXdgSurface (struct wl_client *client, struct wl_resource *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.select_extra_events = SelectExtraEvents; role->role.funcs.note_focus = NoteFocus; + role->role.funcs.outputs_changed = OutputsChanged; attrs.colormap = compositor.colormap; attrs.border_pixel = border_pixel; diff --git a/xdg_toplevel.c b/xdg_toplevel.c index bcd2227..7757387 100644 --- a/xdg_toplevel.c +++ b/xdg_toplevel.c @@ -572,6 +572,22 @@ WriteStates (XdgToplevel *toplevel) 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 SendStates (XdgToplevel *toplevel) { @@ -579,16 +595,9 @@ SendStates (XdgToplevel *toplevel) WriteStates (toplevel); - /* Adjust the width and height we're sending by the window geometry. - 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); + /* toplevel->role->surface should not be NULL here. */ + CurrentWindowGeometry (toplevel, &width, &height); SendConfigure (toplevel, width, height); } @@ -1218,6 +1227,17 @@ AckConfigure (Role *role, XdgRoleImplementation *impl, uint32_t serial) 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 Commit (Role *role, Surface *surface, XdgRoleImplementation *impl) { @@ -1255,6 +1275,14 @@ Commit (Role *role, Surface *surface, XdgRoleImplementation *impl) Unmap (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); } 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 = { .destroy = Destroy, @@ -2242,6 +2293,7 @@ XLGetXdgToplevel (struct wl_client *client, struct wl_resource *resource, toplevel->impl.funcs.post_resize = PostResize; toplevel->impl.funcs.commit_inside_frame = CommitInsideFrame; toplevel->impl.funcs.is_window_mapped = IsWindowMapped; + toplevel->impl.funcs.outputs_changed = OutputsChanged; if (!XLWmSupportsHint (_NET_WM_STATE_FOCUSED)) /* If _NET_WM_STATE_FOCUSED is unsupported, fall back to utilizing