mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
view: implement separate horizontal/vertical maximize
This is a useful (if lesser-known) feature of at least a few popular X11 window managers, for example Openbox and XFWM4. Typically right-click on the maximize button toggles horizontal maximize, while middle-click toggles vertical maximize. Support in labwc uses the same configuration syntax as Openbox, where the Maximize/ToggleMaximize actions have an optional "direction" argument: horizontal, vertical, or both (default). The default mouse bindings match the XFWM4 defaults (not sure what Openbox has by default). Most of the external protocols still assume "maximized" is a Boolean, which is no longer true internally. For the sake of the outside world, a view is only "maximized" if maximized in both directions. Internally, I've taken the following approach: - SSD code decorates the view as "maximized" (i.e. hiding borders) only if maximized in both directions. - Layout code (interactive move/resize, tiling, etc.) generally treats the view as "maximized" (with the restrictions that entails) if maximized in either direction. For example, moving a vertically- maximized view first restores the natural geometry (this differs from Openbox, which instead allows the view to move only horizontally.) v2: use enum view_axis for view->maximized v3: - update docs - allow resizing if partly maximized - add TODOs & corrections noted by Consolatis
This commit is contained in:
parent
7b644b3b94
commit
0430f6f818
15 changed files with 193 additions and 78 deletions
|
|
@ -112,11 +112,13 @@ Actions are used in menus and keyboard/mouse bindings.
|
|||
*<action name="ToggleFullscreen" />*
|
||||
Toggle fullscreen state of focused window.
|
||||
|
||||
*<action name="ToggleMaximize" />*
|
||||
Toggle maximize state of focused window.
|
||||
*<action name="ToggleMaximize" direction="value" />*
|
||||
Toggle maximize state of focused window. Supported directions are
|
||||
"both" (default), "horizontal", and "vertical".
|
||||
|
||||
*<action name="Maximize" />*
|
||||
Maximize focused window.
|
||||
*<action name="Maximize" direction="value" />*
|
||||
Maximize focused window. Supported directions are "both" (default),
|
||||
"horizontal", and "vertical".
|
||||
|
||||
*<action name="ToggleAlwaysOnTop" />*
|
||||
Toggle always-on-top of focused window.
|
||||
|
|
|
|||
|
|
@ -298,7 +298,6 @@
|
|||
<mousebind button="Right" action="Click">
|
||||
<action name="Focus" />
|
||||
<action name="Raise" />
|
||||
<action name="ShowMenu" menu="client-menu" />
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
|
|
@ -309,20 +308,30 @@
|
|||
<mousebind button="Left" action="DoubleClick">
|
||||
<action name="ToggleMaximize" />
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Click">
|
||||
<action name="ShowMenu" menu="client-menu" />
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Maximize">
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="Focus" />
|
||||
<action name="Raise" />
|
||||
<action name="ToggleMaximize" />
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Click">
|
||||
<action name="ToggleMaximize" direction="horizontal" />
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Click">
|
||||
<action name="ToggleMaximize" direction="vertical" />
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="WindowMenu">
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ShowMenu" menu="client-menu" />
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Click">
|
||||
<action name="ShowMenu" menu="client-menu" />
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Iconify">
|
||||
|
|
|
|||
|
|
@ -29,6 +29,18 @@ enum ssd_preference {
|
|||
LAB_SSD_PREF_SERVER,
|
||||
};
|
||||
|
||||
/**
|
||||
* Directions in which a view can be maximized. "None" is used
|
||||
* internally to mean "not maximized" but is not valid in rc.xml.
|
||||
* Therefore when parsing rc.xml, "None" means "Invalid".
|
||||
*/
|
||||
enum view_axis {
|
||||
VIEW_AXIS_NONE = 0,
|
||||
VIEW_AXIS_HORIZONTAL = (1 << 0),
|
||||
VIEW_AXIS_VERTICAL = (1 << 1),
|
||||
VIEW_AXIS_BOTH = (VIEW_AXIS_HORIZONTAL | VIEW_AXIS_VERTICAL),
|
||||
};
|
||||
|
||||
enum view_edge {
|
||||
VIEW_EDGE_INVALID = 0,
|
||||
|
||||
|
|
@ -127,7 +139,7 @@ struct view {
|
|||
bool ssd_titlebar_hidden;
|
||||
enum ssd_preference ssd_preference;
|
||||
bool minimized;
|
||||
bool maximized;
|
||||
enum view_axis maximized;
|
||||
bool fullscreen;
|
||||
uint32_t tiled; /* private, enum view_edge in src/view.c */
|
||||
bool inhibits_keybinds;
|
||||
|
|
@ -353,10 +365,10 @@ void view_store_natural_geometry(struct view *view);
|
|||
void view_center(struct view *view, const struct wlr_box *ref);
|
||||
void view_restore_to(struct view *view, struct wlr_box geometry);
|
||||
void view_set_untiled(struct view *view);
|
||||
void view_maximize(struct view *view, bool maximize,
|
||||
void view_maximize(struct view *view, enum view_axis axis,
|
||||
bool store_natural_geometry);
|
||||
void view_set_fullscreen(struct view *view, bool fullscreen);
|
||||
void view_toggle_maximize(struct view *view);
|
||||
void view_toggle_maximize(struct view *view, enum view_axis axis);
|
||||
void view_toggle_decorations(struct view *view);
|
||||
|
||||
bool view_is_always_on_top(struct view *view);
|
||||
|
|
@ -400,6 +412,7 @@ void view_evacuate_region(struct view *view);
|
|||
void view_on_output_destroy(struct view *view);
|
||||
void view_destroy(struct view *view);
|
||||
|
||||
enum view_axis view_axis_parse(const char *direction);
|
||||
enum view_edge view_edge_parse(const char *direction);
|
||||
|
||||
/* xdg.c */
|
||||
|
|
|
|||
22
src/action.c
22
src/action.c
|
|
@ -296,6 +296,19 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
|
|||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_MAXIMIZE:
|
||||
case ACTION_TYPE_MAXIMIZE:
|
||||
if (!strcmp(argument, "direction")) {
|
||||
enum view_axis axis = view_axis_parse(content);
|
||||
if (axis == VIEW_AXIS_NONE) {
|
||||
wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)",
|
||||
action_names[action->type], argument, content);
|
||||
} else {
|
||||
action_arg_add_int(action, argument, axis);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZE_RELATIVE:
|
||||
if (!strcmp(argument, "left") || !strcmp(argument, "right") ||
|
||||
!strcmp(argument, "top") || !strcmp(argument, "bottom")) {
|
||||
|
|
@ -694,12 +707,17 @@ actions_run(struct view *activator, struct server *server,
|
|||
break;
|
||||
case ACTION_TYPE_TOGGLE_MAXIMIZE:
|
||||
if (view) {
|
||||
view_toggle_maximize(view);
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_toggle_maximize(view, axis);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MAXIMIZE:
|
||||
if (view) {
|
||||
view_maximize(view, true, /*store_natural_geometry*/ true);
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_maximize(view, axis,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_FULLSCREEN:
|
||||
|
|
|
|||
|
|
@ -1064,11 +1064,14 @@ static struct mouse_combos {
|
|||
{ "Title", "Left", "DoubleClick", "ToggleMaximize", NULL, NULL },
|
||||
{ "TitleBar", "Right", "Click", "Focus", NULL, NULL},
|
||||
{ "TitleBar", "Right", "Click", "Raise", NULL, NULL},
|
||||
{ "TitleBar", "Right", "Click", "ShowMenu", "menu", "client-menu"},
|
||||
{ "Title", "Right", "Click", "ShowMenu", "menu", "client-menu"},
|
||||
{ "Close", "Left", "Click", "Close", NULL, NULL },
|
||||
{ "Iconify", "Left", "Click", "Iconify", NULL, NULL},
|
||||
{ "Maximize", "Left", "Click", "ToggleMaximize", NULL, NULL},
|
||||
{ "Maximize", "Right", "Click", "ToggleMaximize", "direction", "horizontal"},
|
||||
{ "Maximize", "Middle", "Click", "ToggleMaximize", "direction", "vertical"},
|
||||
{ "WindowMenu", "Left", "Click", "ShowMenu", "menu", "client-menu"},
|
||||
{ "WindowMenu", "Right", "Click", "ShowMenu", "menu", "client-menu"},
|
||||
{ "Root", "Left", "Press", "ShowMenu", "menu", "root-menu"},
|
||||
{ "Root", "Right", "Press", "ShowMenu", "menu", "root-menu"},
|
||||
{ "Root", "Middle", "Press", "ShowMenu", "menu", "root-menu"},
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ handle_request_maximize(struct wl_listener *listener, void *data)
|
|||
{
|
||||
struct view *view = wl_container_of(listener, view, toplevel.maximize);
|
||||
struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data;
|
||||
view_maximize(view, event->maximized, /*store_natural_geometry*/ true);
|
||||
view_maximize(view, event->maximized ? VIEW_AXIS_BOTH : VIEW_AXIS_NONE,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
|
|||
*/
|
||||
return;
|
||||
}
|
||||
if (view->maximized || view_is_tiled(view)) {
|
||||
if (!view_is_floating(view)) {
|
||||
/*
|
||||
* Un-maximize and restore natural width/height.
|
||||
* Don't reset tiled state yet since we may want
|
||||
|
|
@ -71,18 +71,20 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
|
|||
cursor_set(seat, LAB_CURSOR_GRAB);
|
||||
break;
|
||||
case LAB_INPUT_STATE_RESIZE:
|
||||
if (view->maximized || view->fullscreen) {
|
||||
if (view->fullscreen || view->maximized == VIEW_AXIS_BOTH) {
|
||||
/*
|
||||
* We don't allow resizing while maximized or
|
||||
* fullscreen.
|
||||
* We don't allow resizing while fullscreen or
|
||||
* maximized in both directions.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Reset tiled state but keep the same geometry as the
|
||||
* starting point for the resize.
|
||||
* If tiled or maximized in only one direction, reset
|
||||
* tiled/maximized state but keep the same geometry as
|
||||
* the starting point for the resize.
|
||||
*/
|
||||
view_set_untiled(view);
|
||||
view_restore_to(view, view->pending);
|
||||
cursor_set(seat, cursor_get_from_edge(edges));
|
||||
break;
|
||||
default:
|
||||
|
|
@ -130,7 +132,7 @@ snap_to_edge(struct view *view)
|
|||
/*store_natural_geometry*/ false);
|
||||
} else if (cursor_y <= area->y + snap_range) {
|
||||
if (rc.snap_top_maximize) {
|
||||
view_maximize(view, true,
|
||||
view_maximize(view, VIEW_AXIS_BOTH,
|
||||
/*store_natural_geometry*/ false);
|
||||
} else {
|
||||
view_snap_to_edge(view, VIEW_EDGE_UP,
|
||||
|
|
|
|||
|
|
@ -102,7 +102,8 @@ _snap_next_edge(struct view *view, int start_pos, const struct snap_search def,
|
|||
struct view *v;
|
||||
int p = max;
|
||||
for_each_view(v, &server->views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE) {
|
||||
if (v == view || v->output != output || v->minimized || v->maximized) {
|
||||
if (v == view || v->output != output || v->minimized
|
||||
|| v->maximized == VIEW_AXIS_BOTH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ ssd_thickness(struct view *view)
|
|||
|
||||
struct theme *theme = view->server->theme;
|
||||
|
||||
if (view->maximized) {
|
||||
if (view->maximized == VIEW_AXIS_BOTH) {
|
||||
struct border thickness = { 0 };
|
||||
if (!view->ssd_titlebar_hidden) {
|
||||
thickness.top += theme->title_height;
|
||||
|
|
@ -226,7 +226,8 @@ ssd_update_geometry(struct ssd *ssd)
|
|||
ssd_extents_update(ssd);
|
||||
ssd->state.geometry = current;
|
||||
}
|
||||
if (ssd->state.squared_corners != ssd->view->maximized) {
|
||||
bool maximized = (ssd->view->maximized == VIEW_AXIS_BOTH);
|
||||
if (ssd->state.squared_corners != maximized) {
|
||||
ssd_border_update(ssd);
|
||||
ssd_titlebar_update(ssd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ ssd_border_create(struct ssd *ssd)
|
|||
-(ssd->titlebar.height + theme->border_width), color);
|
||||
} FOR_EACH_END
|
||||
|
||||
if (view->maximized) {
|
||||
if (view->maximized == VIEW_AXIS_BOTH) {
|
||||
wlr_scene_node_set_enabled(&ssd->border.tree->node, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,13 +65,14 @@ ssd_border_update(struct ssd *ssd)
|
|||
assert(ssd->border.tree);
|
||||
|
||||
struct view *view = ssd->view;
|
||||
if (view->maximized && ssd->border.tree->node.enabled) {
|
||||
if (view->maximized == VIEW_AXIS_BOTH
|
||||
&& ssd->border.tree->node.enabled) {
|
||||
/* Disable borders on maximize */
|
||||
wlr_scene_node_set_enabled(&ssd->border.tree->node, false);
|
||||
ssd->margin = ssd_thickness(ssd->view);
|
||||
}
|
||||
|
||||
if (view->maximized) {
|
||||
if (view->maximized == VIEW_AXIS_BOTH) {
|
||||
return;
|
||||
} else if (!ssd->border.tree->node.enabled) {
|
||||
/* And re-enabled them when unmaximized */
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ ssd_extents_create(struct ssd *ssd)
|
|||
|
||||
ssd->extents.tree = wlr_scene_tree_create(ssd->tree);
|
||||
struct wlr_scene_tree *parent = ssd->extents.tree;
|
||||
if (view->maximized || view->fullscreen) {
|
||||
if (view->fullscreen || view->maximized == VIEW_AXIS_BOTH) {
|
||||
wlr_scene_node_set_enabled(&parent->node, false);
|
||||
}
|
||||
wl_list_init(&ssd->extents.parts);
|
||||
|
|
@ -89,7 +89,7 @@ void
|
|||
ssd_extents_update(struct ssd *ssd)
|
||||
{
|
||||
struct view *view = ssd->view;
|
||||
if (view->maximized || view->fullscreen) {
|
||||
if (view->fullscreen || view->maximized == VIEW_AXIS_BOTH) {
|
||||
wlr_scene_node_set_enabled(&ssd->extents.tree->node, false);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ ssd_titlebar_create(struct ssd *ssd)
|
|||
|
||||
ssd_update_title(ssd);
|
||||
|
||||
if (view->maximized) {
|
||||
set_squared_corners(ssd, view->maximized);
|
||||
if (view->maximized == VIEW_AXIS_BOTH) {
|
||||
set_squared_corners(ssd, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,8 +133,9 @@ ssd_titlebar_update(struct ssd *ssd)
|
|||
int width = view->current.width;
|
||||
struct theme *theme = view->server->theme;
|
||||
|
||||
if (view->maximized != ssd->state.squared_corners) {
|
||||
set_squared_corners(ssd, view->maximized);
|
||||
bool maximized = (view->maximized == VIEW_AXIS_BOTH);
|
||||
if (ssd->state.squared_corners != maximized) {
|
||||
set_squared_corners(ssd, maximized);
|
||||
}
|
||||
|
||||
if (width == ssd->state.geometry.width) {
|
||||
|
|
|
|||
125
src/view.c
125
src/view.c
|
|
@ -337,7 +337,7 @@ void
|
|||
view_resize_relative(struct view *view, int left, int right, int top, int bottom)
|
||||
{
|
||||
assert(view);
|
||||
if (view->fullscreen || view->maximized) {
|
||||
if (view->fullscreen || view->maximized != VIEW_AXIS_NONE) {
|
||||
return;
|
||||
}
|
||||
struct wlr_box newgeo = view->pending;
|
||||
|
|
@ -356,7 +356,7 @@ view_move_relative(struct view *view, int x, int y)
|
|||
if (view->fullscreen) {
|
||||
return;
|
||||
}
|
||||
view_maximize(view, false, /*store_natural_geometry*/ false);
|
||||
view_maximize(view, VIEW_AXIS_NONE, /*store_natural_geometry*/ false);
|
||||
if (view_is_tiled(view)) {
|
||||
view_set_untiled(view);
|
||||
view_restore_to(view, view->natural_geometry);
|
||||
|
|
@ -373,12 +373,8 @@ view_move_to_cursor(struct view *view)
|
|||
if (!output_is_usable(pending_output)) {
|
||||
return;
|
||||
}
|
||||
if (view->fullscreen) {
|
||||
view_set_fullscreen(view, false);
|
||||
}
|
||||
if (view->maximized) {
|
||||
view_maximize(view, false, /*store_natural_geometry*/ false);
|
||||
}
|
||||
view_set_fullscreen(view, false);
|
||||
view_maximize(view, VIEW_AXIS_NONE, /*store_natural_geometry*/ false);
|
||||
if (view_is_tiled(view)) {
|
||||
view_set_untiled(view);
|
||||
view_restore_to(view, view->natural_geometry);
|
||||
|
|
@ -739,7 +735,7 @@ static void
|
|||
view_apply_maximized_geometry(struct view *view)
|
||||
{
|
||||
assert(view);
|
||||
assert(view->maximized);
|
||||
assert(view->maximized != VIEW_AXIS_NONE);
|
||||
struct output *output = view->output;
|
||||
assert(output_is_usable(output));
|
||||
|
||||
|
|
@ -753,6 +749,23 @@ view_apply_maximized_geometry(struct view *view)
|
|||
box.width /= output->wlr_output->scale;
|
||||
}
|
||||
|
||||
/*
|
||||
* If one axis (horizontal or vertical) is unmaximized, it
|
||||
* should use the natural geometry. But if that geometry is not
|
||||
* on-screen on the output where the view is maximized, then
|
||||
* center the unmaximized axis.
|
||||
*/
|
||||
struct wlr_box natural = view->natural_geometry;
|
||||
if (view->maximized != VIEW_AXIS_BOTH) {
|
||||
struct wlr_box intersect;
|
||||
wlr_box_intersection(&intersect, &box, &natural);
|
||||
if (wlr_box_empty(&intersect)) {
|
||||
view_compute_centered_position(view, NULL,
|
||||
natural.width, natural.height,
|
||||
&natural.x, &natural.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (view->ssd_enabled) {
|
||||
struct border border = ssd_thickness(view);
|
||||
box.x += border.left;
|
||||
|
|
@ -760,6 +773,15 @@ view_apply_maximized_geometry(struct view *view)
|
|||
box.width -= border.right + border.left;
|
||||
box.height -= border.top + border.bottom;
|
||||
}
|
||||
|
||||
if (view->maximized == VIEW_AXIS_VERTICAL) {
|
||||
box.x = natural.x;
|
||||
box.width = natural.width;
|
||||
} else if (view->maximized == VIEW_AXIS_HORIZONTAL) {
|
||||
box.y = natural.y;
|
||||
box.height = natural.height;
|
||||
}
|
||||
|
||||
view_move_resize(view, box);
|
||||
}
|
||||
|
||||
|
|
@ -775,7 +797,7 @@ view_apply_special_geometry(struct view *view)
|
|||
|
||||
if (view->fullscreen) {
|
||||
view_apply_fullscreen_geometry(view);
|
||||
} else if (view->maximized) {
|
||||
} else if (view->maximized != VIEW_AXIS_NONE) {
|
||||
view_apply_maximized_geometry(view);
|
||||
} else if (view->tiled) {
|
||||
view_apply_tiled_geometry(view);
|
||||
|
|
@ -788,14 +810,14 @@ view_apply_special_geometry(struct view *view)
|
|||
|
||||
/* For internal use only. Does not update geometry. */
|
||||
static void
|
||||
set_maximized(struct view *view, bool maximized)
|
||||
set_maximized(struct view *view, enum view_axis maximized)
|
||||
{
|
||||
if (view->impl->maximize) {
|
||||
view->impl->maximize(view, maximized);
|
||||
view->impl->maximize(view, (maximized == VIEW_AXIS_BOTH));
|
||||
}
|
||||
if (view->toplevel.handle) {
|
||||
wlr_foreign_toplevel_handle_v1_set_maximized(
|
||||
view->toplevel.handle, maximized);
|
||||
view->toplevel.handle, (maximized == VIEW_AXIS_BOTH));
|
||||
}
|
||||
view->maximized = maximized;
|
||||
|
||||
|
|
@ -818,8 +840,8 @@ view_restore_to(struct view *view, struct wlr_box geometry)
|
|||
if (view->fullscreen) {
|
||||
return;
|
||||
}
|
||||
if (view->maximized) {
|
||||
set_maximized(view, false);
|
||||
if (view->maximized != VIEW_AXIS_NONE) {
|
||||
set_maximized(view, VIEW_AXIS_NONE);
|
||||
}
|
||||
view_move_resize(view, geometry);
|
||||
}
|
||||
|
|
@ -836,8 +858,8 @@ bool
|
|||
view_is_floating(struct view *view)
|
||||
{
|
||||
assert(view);
|
||||
return !(view->fullscreen || view->maximized || view->tiled
|
||||
|| view->tiled_region || view->tiled_region_evacuate);
|
||||
return !(view->fullscreen || (view->maximized != VIEW_AXIS_NONE)
|
||||
|| view_is_tiled(view));
|
||||
}
|
||||
|
||||
/* Reset tiled state of view without changing geometry */
|
||||
|
|
@ -851,27 +873,28 @@ view_set_untiled(struct view *view)
|
|||
}
|
||||
|
||||
void
|
||||
view_maximize(struct view *view, bool maximize, bool store_natural_geometry)
|
||||
view_maximize(struct view *view, enum view_axis axis,
|
||||
bool store_natural_geometry)
|
||||
{
|
||||
assert(view);
|
||||
if (view->maximized == maximize) {
|
||||
if (view->maximized == axis) {
|
||||
return;
|
||||
}
|
||||
if (view->fullscreen) {
|
||||
return;
|
||||
}
|
||||
if (maximize) {
|
||||
if (axis != VIEW_AXIS_NONE) {
|
||||
/*
|
||||
* Maximize via keybind or client request cancels
|
||||
* interactive move/resize since we can't move/resize
|
||||
* a maximized view.
|
||||
*/
|
||||
interactive_cancel(view);
|
||||
if (store_natural_geometry) {
|
||||
if (store_natural_geometry && view_is_floating(view)) {
|
||||
view_store_natural_geometry(view);
|
||||
}
|
||||
}
|
||||
set_maximized(view, maximize);
|
||||
set_maximized(view, axis);
|
||||
if (view_is_floating(view)) {
|
||||
view_apply_natural_geometry(view);
|
||||
} else {
|
||||
|
|
@ -880,11 +903,28 @@ view_maximize(struct view *view, bool maximize, bool store_natural_geometry)
|
|||
}
|
||||
|
||||
void
|
||||
view_toggle_maximize(struct view *view)
|
||||
view_toggle_maximize(struct view *view, enum view_axis axis)
|
||||
{
|
||||
assert(view);
|
||||
view_maximize(view, !view->maximized,
|
||||
/*store_natural_geometry*/ true);
|
||||
switch (axis) {
|
||||
case VIEW_AXIS_HORIZONTAL:
|
||||
case VIEW_AXIS_VERTICAL:
|
||||
/* Toggle one axis (XOR) */
|
||||
view_maximize(view, view->maximized ^ axis,
|
||||
/*store_natural_geometry*/ true);
|
||||
break;
|
||||
case VIEW_AXIS_BOTH:
|
||||
/*
|
||||
* Maximize in both directions if unmaximized or partially
|
||||
* maximized, otherwise unmaximize.
|
||||
*/
|
||||
view_maximize(view, (view->maximized == VIEW_AXIS_BOTH) ?
|
||||
VIEW_AXIS_NONE : VIEW_AXIS_BOTH,
|
||||
/*store_natural_geometry*/ true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1167,7 +1207,8 @@ void
|
|||
view_grow_to_edge(struct view *view, enum view_edge direction)
|
||||
{
|
||||
assert(view);
|
||||
if (view->fullscreen || view->maximized) {
|
||||
/* TODO: allow grow to edge if maximized along the other axis */
|
||||
if (view->fullscreen || view->maximized != VIEW_AXIS_NONE) {
|
||||
return;
|
||||
}
|
||||
if (!output_is_usable(view->output)) {
|
||||
|
|
@ -1184,7 +1225,8 @@ void
|
|||
view_shrink_to_edge(struct view *view, enum view_edge direction)
|
||||
{
|
||||
assert(view);
|
||||
if (view->fullscreen || view->maximized) {
|
||||
/* TODO: allow shrink to edge if maximized along the other axis */
|
||||
if (view->fullscreen || view->maximized != VIEW_AXIS_NONE) {
|
||||
return;
|
||||
}
|
||||
if (!output_is_usable(view->output)) {
|
||||
|
|
@ -1197,6 +1239,23 @@ view_shrink_to_edge(struct view *view, enum view_edge direction)
|
|||
view_move_resize(view, geo);
|
||||
}
|
||||
|
||||
enum view_axis
|
||||
view_axis_parse(const char *direction)
|
||||
{
|
||||
if (!direction) {
|
||||
return VIEW_AXIS_NONE;
|
||||
}
|
||||
if (!strcasecmp(direction, "horizontal")) {
|
||||
return VIEW_AXIS_HORIZONTAL;
|
||||
} else if (!strcasecmp(direction, "vertical")) {
|
||||
return VIEW_AXIS_VERTICAL;
|
||||
} else if (!strcasecmp(direction, "both")) {
|
||||
return VIEW_AXIS_BOTH;
|
||||
} else {
|
||||
return VIEW_AXIS_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
enum view_edge
|
||||
view_edge_parse(const char *direction)
|
||||
{
|
||||
|
|
@ -1231,7 +1290,7 @@ view_snap_to_edge(struct view *view, enum view_edge edge, bool store_natural_geo
|
|||
return;
|
||||
}
|
||||
|
||||
if (view->tiled == edge && !view->maximized) {
|
||||
if (view->tiled == edge && view->maximized == VIEW_AXIS_NONE) {
|
||||
/* We are already tiled for this edge and thus should switch outputs */
|
||||
struct wlr_output *new_output = NULL;
|
||||
struct wlr_output *current_output = output->wlr_output;
|
||||
|
|
@ -1285,9 +1344,10 @@ view_snap_to_edge(struct view *view, enum view_edge edge, bool store_natural_geo
|
|||
}
|
||||
}
|
||||
|
||||
if (view->maximized) {
|
||||
if (view->maximized != VIEW_AXIS_NONE) {
|
||||
/* Unmaximize + keep using existing natural_geometry */
|
||||
view_maximize(view, false, /*store_natural_geometry*/ false);
|
||||
view_maximize(view, VIEW_AXIS_NONE,
|
||||
/*store_natural_geometry*/ false);
|
||||
} else if (store_natural_geometry) {
|
||||
/* store current geometry as new natural_geometry */
|
||||
view_store_natural_geometry(view);
|
||||
|
|
@ -1313,9 +1373,10 @@ view_snap_to_region(struct view *view, struct region *region,
|
|||
return;
|
||||
}
|
||||
|
||||
if (view->maximized) {
|
||||
if (view->maximized != VIEW_AXIS_NONE) {
|
||||
/* Unmaximize + keep using existing natural_geometry */
|
||||
view_maximize(view, false, /*store_natural_geometry*/ false);
|
||||
view_maximize(view, VIEW_AXIS_NONE,
|
||||
/*store_natural_geometry*/ false);
|
||||
} else if (store_natural_geometry) {
|
||||
/* store current geometry as new natural_geometry */
|
||||
view_store_natural_geometry(view);
|
||||
|
|
|
|||
13
src/xdg.c
13
src/xdg.c
|
|
@ -226,7 +226,8 @@ handle_request_maximize(struct wl_listener *listener, void *data)
|
|||
if (!view->mapped && !view->output) {
|
||||
view_set_output(view, output_nearest_to_cursor(view->server));
|
||||
}
|
||||
view_maximize(view, xdg_toplevel_from_view(view)->requested.maximized,
|
||||
bool maximized = xdg_toplevel_from_view(view)->requested.maximized;
|
||||
view_maximize(view, maximized ? VIEW_AXIS_BOTH : VIEW_AXIS_NONE,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
|
||||
|
|
@ -503,12 +504,10 @@ xdg_toplevel_view_map(struct view *view)
|
|||
position_xdg_toplevel_view(view);
|
||||
}
|
||||
|
||||
if (!view->fullscreen && requested->fullscreen) {
|
||||
set_fullscreen_from_request(view, requested);
|
||||
} else if (!view->maximized && requested->maximized) {
|
||||
view_maximize(view, true,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
set_fullscreen_from_request(view, requested);
|
||||
view_maximize(view, requested->maximized ?
|
||||
VIEW_AXIS_BOTH : VIEW_AXIS_NONE,
|
||||
/*store_natural_geometry*/ true);
|
||||
|
||||
/*
|
||||
* Set initial "current" position directly before
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ handle_request_maximize(struct wl_listener *listener, void *data)
|
|||
view_set_decorations(view,
|
||||
want_deco(xwayland_surface_from_view(view)));
|
||||
}
|
||||
view_toggle_maximize(view);
|
||||
view_toggle_maximize(view, VIEW_AXIS_BOTH);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -540,14 +540,17 @@ xwayland_view_map(struct view *view)
|
|||
* 1. set fullscreen state
|
||||
* 2. set decorations (depends on fullscreen state)
|
||||
* 3. set maximized (geometry depends on decorations)
|
||||
*
|
||||
* TODO: support separate horizontal/vertical maximize
|
||||
*/
|
||||
bool maximize = xwayland_surface->maximized_horz
|
||||
&& xwayland_surface->maximized_vert;
|
||||
view_set_fullscreen(view, xwayland_surface->fullscreen);
|
||||
view_set_decorations(view, want_deco(xwayland_surface));
|
||||
view_maximize(view, maximize, /*store_natural_geometry*/ true);
|
||||
enum view_axis axis = VIEW_AXIS_NONE;
|
||||
if (xwayland_surface->maximized_horz) {
|
||||
axis |= VIEW_AXIS_HORIZONTAL;
|
||||
}
|
||||
if (xwayland_surface->maximized_vert) {
|
||||
axis |= VIEW_AXIS_VERTICAL;
|
||||
}
|
||||
view_maximize(view, axis, /*store_natural_geometry*/ true);
|
||||
|
||||
if (view->surface != xwayland_surface->surface) {
|
||||
if (view->surface) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue