mirror of
https://github.com/labwc/labwc.git
synced 2026-04-10 08:21:07 -04:00
Merge branch 'master' into master
This commit is contained in:
commit
6003c62c1f
20 changed files with 446 additions and 249 deletions
|
|
@ -2,19 +2,23 @@
|
||||||
#ifndef __LABWC_ACTION_H
|
#ifndef __LABWC_ACTION_H
|
||||||
#define __LABWC_ACTION_H
|
#define __LABWC_ACTION_H
|
||||||
|
|
||||||
struct server;
|
|
||||||
struct view;
|
struct view;
|
||||||
|
struct server;
|
||||||
|
struct wl_list;
|
||||||
|
|
||||||
struct action {
|
struct action {
|
||||||
uint32_t type;
|
struct wl_list link; /* struct keybinding.actions,
|
||||||
char *arg;
|
* struct mousebinding.actions,
|
||||||
struct wl_list link;
|
* struct menuitem.actions */
|
||||||
|
|
||||||
|
uint32_t type; /* enum action_type */
|
||||||
|
struct wl_list args; /* struct action_arg.link */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct action *action_create(const char *action_name);
|
struct action *action_create(const char *action_name);
|
||||||
void action_list_free(struct wl_list *action_list);
|
void action_arg_add_str(struct action *action, char *key, const char *value);
|
||||||
|
|
||||||
void actions_run(struct view *activator, struct server *server,
|
void actions_run(struct view *activator, struct server *server,
|
||||||
struct wl_list *actions, uint32_t resize_edges);
|
struct wl_list *actions, uint32_t resize_edges);
|
||||||
|
void action_list_free(struct wl_list *action_list);
|
||||||
|
|
||||||
#endif
|
#endif /* __LABWC_ACTION_H */
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ struct keybind {
|
||||||
uint32_t modifiers;
|
uint32_t modifiers;
|
||||||
xkb_keysym_t *keysyms;
|
xkb_keysym_t *keysyms;
|
||||||
size_t keysyms_len;
|
size_t keysyms_len;
|
||||||
struct wl_list actions;
|
struct wl_list actions; /* struct action.link */
|
||||||
struct wl_list link;
|
struct wl_list link; /* struct rcxml.keybinds */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ struct mousebind {
|
||||||
|
|
||||||
/* ex: doubleclick, press, drag */
|
/* ex: doubleclick, press, drag */
|
||||||
enum mouse_event mouse_event;
|
enum mouse_event mouse_event;
|
||||||
struct wl_list actions;
|
struct wl_list actions; /* struct action.link */
|
||||||
|
|
||||||
struct wl_list link; /* rcxml::mousebinds */
|
struct wl_list link; /* struct rcxml.mousebinds */
|
||||||
bool pressed_in_context; /* used in click events */
|
bool pressed_in_context; /* used in click events */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ struct rcxml {
|
||||||
/* keyboard */
|
/* keyboard */
|
||||||
int repeat_rate;
|
int repeat_rate;
|
||||||
int repeat_delay;
|
int repeat_delay;
|
||||||
struct wl_list keybinds;
|
struct wl_list keybinds; /* struct keybind.link */
|
||||||
|
|
||||||
/* mouse */
|
/* mouse */
|
||||||
long doubleclick_time; /* in ms */
|
long doubleclick_time; /* in ms */
|
||||||
struct wl_list mousebinds;
|
struct wl_list mousebinds; /* struct mousebind.link */
|
||||||
|
|
||||||
/* libinput */
|
/* libinput */
|
||||||
struct wl_list libinput_categories;
|
struct wl_list libinput_categories;
|
||||||
|
|
|
||||||
|
|
@ -306,13 +306,14 @@ struct view {
|
||||||
bool been_mapped;
|
bool been_mapped;
|
||||||
bool minimized;
|
bool minimized;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
|
uint32_t tiled; /* private, enum view_edge in src/view.c */
|
||||||
struct wlr_output *fullscreen;
|
struct wlr_output *fullscreen;
|
||||||
|
|
||||||
/* geometry of the wlr_surface contained within the view */
|
/* geometry of the wlr_surface contained within the view */
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
|
|
||||||
/* geometry before maximize */
|
/* user defined geometry before maximize / tiling / fullscreen */
|
||||||
struct wlr_box unmaximized_geometry;
|
struct wlr_box natural_geometry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* margin refers to the space between the extremities of the
|
* margin refers to the space between the extremities of the
|
||||||
|
|
@ -364,6 +365,7 @@ struct view {
|
||||||
struct xwayland_unmanaged {
|
struct xwayland_unmanaged {
|
||||||
struct server *server;
|
struct server *server;
|
||||||
struct wlr_xwayland_surface *xwayland_surface;
|
struct wlr_xwayland_surface *xwayland_surface;
|
||||||
|
struct wlr_scene_node *node;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
int lx, ly;
|
int lx, ly;
|
||||||
|
|
||||||
|
|
@ -460,6 +462,7 @@ void foreign_toplevel_handle_create(struct view *view);
|
||||||
void desktop_move_to_front(struct view *view);
|
void desktop_move_to_front(struct view *view);
|
||||||
void desktop_move_to_back(struct view *view);
|
void desktop_move_to_back(struct view *view);
|
||||||
void desktop_focus_and_activate_view(struct seat *seat, struct view *view);
|
void desktop_focus_and_activate_view(struct seat *seat, struct view *view);
|
||||||
|
void desktop_arrange_all_views(struct server *server);
|
||||||
|
|
||||||
enum lab_cycle_dir {
|
enum lab_cycle_dir {
|
||||||
LAB_CYCLE_DIR_NONE,
|
LAB_CYCLE_DIR_NONE,
|
||||||
|
|
|
||||||
24
include/private/action.h
Normal file
24
include/private/action.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
#ifndef __LABWC_PRIVATE_ACTION_H
|
||||||
|
#define __LABWC_PRIVATE_ACTION_H
|
||||||
|
|
||||||
|
/* Don't include ourself as search path starts at current directory */
|
||||||
|
#include "../action.h"
|
||||||
|
|
||||||
|
enum action_arg_type {
|
||||||
|
LAB_ACTION_ARG_STR = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct action_arg {
|
||||||
|
struct wl_list link; /* struct action.args */
|
||||||
|
|
||||||
|
const char *key; /* May be NULL if there is just one arg */
|
||||||
|
enum action_arg_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct action_arg_str {
|
||||||
|
struct action_arg base;
|
||||||
|
char *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __LABWC_PRIVATE_ACTION_H */
|
||||||
|
|
@ -134,8 +134,10 @@ struct ssd_hover_state {
|
||||||
|
|
||||||
/* Public SSD API */
|
/* Public SSD API */
|
||||||
void ssd_create(struct view *view);
|
void ssd_create(struct view *view);
|
||||||
|
|
||||||
void ssd_hide(struct view *view);
|
void ssd_hide(struct view *view);
|
||||||
void ssd_set_active(struct view *view, bool activated);
|
void ssd_set_active(struct view *view, bool activated);
|
||||||
|
|
||||||
void ssd_update_title(struct view *view);
|
void ssd_update_title(struct view *view);
|
||||||
void ssd_update_geometry(struct view *view);
|
void ssd_update_geometry(struct view *view);
|
||||||
void ssd_reload(struct view *view);
|
void ssd_reload(struct view *view);
|
||||||
|
|
|
||||||
117
src/action.c
117
src/action.c
|
|
@ -1,6 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <assert.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
@ -9,8 +11,8 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "labwc.h"
|
#include "labwc.h"
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
|
#include "private/action.h"
|
||||||
#include "ssd.h"
|
#include "ssd.h"
|
||||||
#include "action.h"
|
|
||||||
#include "workspaces.h"
|
#include "workspaces.h"
|
||||||
|
|
||||||
enum action_type {
|
enum action_type {
|
||||||
|
|
@ -64,6 +66,24 @@ const char *action_names[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static char *
|
||||||
|
action_str_from_arg(struct action_arg *arg)
|
||||||
|
{
|
||||||
|
assert(arg->type == LAB_ACTION_ARG_STR);
|
||||||
|
return ((struct action_arg_str *)arg)->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct action_arg *
|
||||||
|
action_get_first_arg(struct action *action)
|
||||||
|
{
|
||||||
|
struct action_arg *arg;
|
||||||
|
struct wl_list *item = action->args.next;
|
||||||
|
if (item == &action->args) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return wl_container_of(item, arg, link);
|
||||||
|
}
|
||||||
|
|
||||||
static enum action_type
|
static enum action_type
|
||||||
action_type_from_str(const char *action_name)
|
action_type_from_str(const char *action_name)
|
||||||
{
|
{
|
||||||
|
|
@ -85,15 +105,26 @@ action_create(const char *action_name)
|
||||||
}
|
}
|
||||||
struct action *action = calloc(1, sizeof(struct action));
|
struct action *action = calloc(1, sizeof(struct action));
|
||||||
action->type = action_type_from_str(action_name);
|
action->type = action_type_from_str(action_name);
|
||||||
|
wl_list_init(&action->args);
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_list_free(struct wl_list *action_list)
|
void action_list_free(struct wl_list *action_list)
|
||||||
{
|
{
|
||||||
|
struct action_arg *arg, *arg_tmp;
|
||||||
struct action *action, *action_tmp;
|
struct action *action, *action_tmp;
|
||||||
|
/* Free actions */
|
||||||
wl_list_for_each_safe(action, action_tmp, action_list, link) {
|
wl_list_for_each_safe(action, action_tmp, action_list, link) {
|
||||||
wl_list_remove(&action->link);
|
wl_list_remove(&action->link);
|
||||||
zfree(action->arg);
|
/* Free args */
|
||||||
|
wl_list_for_each_safe(arg, arg_tmp, &action->args, link) {
|
||||||
|
wl_list_remove(&arg->link);
|
||||||
|
zfree(arg->key);
|
||||||
|
if (arg->type == LAB_ACTION_ARG_STR) {
|
||||||
|
free(action_str_from_arg(arg));
|
||||||
|
}
|
||||||
|
zfree(arg);
|
||||||
|
}
|
||||||
zfree(action);
|
zfree(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -151,9 +182,13 @@ actions_run(struct view *activator, struct server *server,
|
||||||
|
|
||||||
struct view *view;
|
struct view *view;
|
||||||
struct action *action;
|
struct action *action;
|
||||||
|
struct action_arg *arg;
|
||||||
wl_list_for_each(action, actions, link) {
|
wl_list_for_each(action, actions, link) {
|
||||||
wlr_log(WLR_DEBUG, "Handling action %s (%u) with arg %s",
|
wlr_log(WLR_DEBUG, "Handling action %s (%u)",
|
||||||
action_names[action->type], action->type, action->arg);
|
action_names[action->type], action->type);
|
||||||
|
|
||||||
|
/* Get arg now so we don't have to repeat every time we only need one */
|
||||||
|
arg = action_get_first_arg(action);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Refetch view because it may have been changed due to the
|
* Refetch view because it may have been changed due to the
|
||||||
|
|
@ -171,28 +206,30 @@ actions_run(struct view *activator, struct server *server,
|
||||||
debug_dump_scene(server);
|
debug_dump_scene(server);
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_EXECUTE:
|
case ACTION_TYPE_EXECUTE:
|
||||||
{
|
if (!arg) {
|
||||||
struct buf cmd;
|
wlr_log(WLR_ERROR, "Missing argument for Execute");
|
||||||
buf_init(&cmd);
|
break;
|
||||||
buf_add(&cmd, action->arg);
|
|
||||||
buf_expand_shell_variables(&cmd);
|
|
||||||
spawn_async_no_shell(cmd.buf);
|
|
||||||
free(cmd.buf);
|
|
||||||
}
|
}
|
||||||
|
struct buf cmd;
|
||||||
|
buf_init(&cmd);
|
||||||
|
buf_add(&cmd, action_str_from_arg(arg));
|
||||||
|
buf_expand_shell_variables(&cmd);
|
||||||
|
spawn_async_no_shell(cmd.buf);
|
||||||
|
free(cmd.buf);
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_EXIT:
|
case ACTION_TYPE_EXIT:
|
||||||
wl_display_terminate(server->wl_display);
|
wl_display_terminate(server->wl_display);
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_MOVE_TO_EDGE:
|
case ACTION_TYPE_MOVE_TO_EDGE:
|
||||||
if (action->arg) {
|
if (arg) {
|
||||||
view_move_to_edge(view, action->arg);
|
view_move_to_edge(view, action_str_from_arg(arg));
|
||||||
} else {
|
} else {
|
||||||
wlr_log(WLR_ERROR, "Missing argument for MoveToEdge");
|
wlr_log(WLR_ERROR, "Missing argument for MoveToEdge");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_SNAP_TO_EDGE:
|
case ACTION_TYPE_SNAP_TO_EDGE:
|
||||||
if (action->arg) {
|
if (arg) {
|
||||||
view_snap_to_edge(view, action->arg);
|
view_snap_to_edge(view, action_str_from_arg(arg));
|
||||||
} else {
|
} else {
|
||||||
wlr_log(WLR_ERROR, "Missing argument for SnapToEdge");
|
wlr_log(WLR_ERROR, "Missing argument for SnapToEdge");
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +248,11 @@ actions_run(struct view *activator, struct server *server,
|
||||||
kill(getpid(), SIGHUP);
|
kill(getpid(), SIGHUP);
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_SHOW_MENU:
|
case ACTION_TYPE_SHOW_MENU:
|
||||||
show_menu(server, view, action->arg);
|
if (arg) {
|
||||||
|
show_menu(server, view, action_str_from_arg(arg));
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_ERROR, "Missing argument for ShowMenu");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_TOGGLE_MAXIMIZE:
|
case ACTION_TYPE_TOGGLE_MAXIMIZE:
|
||||||
if (view) {
|
if (view) {
|
||||||
|
|
@ -263,27 +304,33 @@ actions_run(struct view *activator, struct server *server,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_GO_TO_DESKTOP:
|
case ACTION_TYPE_GO_TO_DESKTOP:
|
||||||
{
|
if (!arg) {
|
||||||
struct workspace *target;
|
wlr_log(WLR_ERROR, "Missing argument for GoToDesktop");
|
||||||
target = workspaces_find(server->workspace_current, action->arg);
|
break;
|
||||||
if (target) {
|
}
|
||||||
workspaces_switch_to(target);
|
struct workspace *target;
|
||||||
}
|
char *target_name = action_str_from_arg(arg);
|
||||||
|
target = workspaces_find(server->workspace_current, target_name);
|
||||||
|
if (target) {
|
||||||
|
workspaces_switch_to(target);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_SEND_TO_DESKTOP:
|
case ACTION_TYPE_SEND_TO_DESKTOP:
|
||||||
|
if (!arg) {
|
||||||
|
wlr_log(WLR_ERROR, "Missing argument for SendToDesktop");
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (view) {
|
if (view) {
|
||||||
struct workspace *target;
|
struct workspace *target;
|
||||||
target = workspaces_find(view->workspace, action->arg);
|
char *target_name = action_str_from_arg(arg);
|
||||||
|
target = workspaces_find(view->workspace, target_name);
|
||||||
if (target) {
|
if (target) {
|
||||||
workspaces_send_to(view, target);
|
workspaces_send_to(view, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_NONE:
|
case ACTION_TYPE_NONE:
|
||||||
wlr_log(WLR_ERROR,
|
wlr_log(WLR_ERROR, "Not executing unknown action");
|
||||||
"Not executing unknown action with arg %s",
|
|
||||||
action->arg);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
|
|
@ -292,9 +339,21 @@ actions_run(struct view *activator, struct server *server,
|
||||||
* adding a new action without installing a handler here.
|
* adding a new action without installing a handler here.
|
||||||
*/
|
*/
|
||||||
wlr_log(WLR_ERROR,
|
wlr_log(WLR_ERROR,
|
||||||
"Not executing invalid action (%u) with arg %s"
|
"Not executing invalid action (%u)"
|
||||||
" This is a BUG. Please report.",
|
" This is a BUG. Please report.", action->type);
|
||||||
action->type, action->arg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
action_arg_add_str(struct action *action, char *key, const char *value)
|
||||||
|
{
|
||||||
|
assert(value && "Tried to add NULL action string argument");
|
||||||
|
struct action_arg_str *arg = calloc(1, sizeof(*arg));
|
||||||
|
arg->base.type = LAB_ACTION_ARG_STR;
|
||||||
|
if (key) {
|
||||||
|
arg->base.key = strdup(key);
|
||||||
|
}
|
||||||
|
arg->value = strdup(value);
|
||||||
|
wl_list_insert(action->args.prev, &arg->base.link);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,21 +71,18 @@ fill_keybind(char *nodename, char *content)
|
||||||
} else if (!current_keybind_action) {
|
} else if (!current_keybind_action) {
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else if (current_keybind_action->arg) {
|
|
||||||
wlr_log(WLR_ERROR, "Action argument already set: %s",
|
|
||||||
current_keybind_action->arg);
|
|
||||||
} else if (!strcmp(nodename, "command.action")) {
|
} else if (!strcmp(nodename, "command.action")) {
|
||||||
/* Execute */
|
/* Execute */
|
||||||
current_keybind_action->arg = strdup(content);
|
action_arg_add_str(current_keybind_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "direction.action")) {
|
} else if (!strcmp(nodename, "direction.action")) {
|
||||||
/* MoveToEdge, SnapToEdge */
|
/* MoveToEdge, SnapToEdge */
|
||||||
current_keybind_action->arg = strdup(content);
|
action_arg_add_str(current_keybind_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "menu.action")) {
|
} else if (!strcmp(nodename, "menu.action")) {
|
||||||
/* ShowMenu */
|
/* ShowMenu */
|
||||||
current_keybind_action->arg = strdup(content);
|
action_arg_add_str(current_keybind_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "to.action")) {
|
} else if (!strcmp(nodename, "to.action")) {
|
||||||
/* GoToDesktop, SendToDesktop */
|
/* GoToDesktop, SendToDesktop */
|
||||||
current_keybind_action->arg = strdup(content);
|
action_arg_add_str(current_keybind_action, NULL, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,15 +131,12 @@ fill_mousebind(char *nodename, char *content)
|
||||||
} else if (!current_mousebind_action) {
|
} else if (!current_mousebind_action) {
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else if (current_mousebind_action->arg) {
|
|
||||||
wlr_log(WLR_ERROR, "Action argument already set: %s",
|
|
||||||
current_mousebind_action->arg);
|
|
||||||
} else if (!strcmp(nodename, "command.action")) {
|
} else if (!strcmp(nodename, "command.action")) {
|
||||||
current_mousebind_action->arg = strdup(content);
|
action_arg_add_str(current_mousebind_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "direction.action")) {
|
} else if (!strcmp(nodename, "direction.action")) {
|
||||||
current_mousebind_action->arg = strdup(content);
|
action_arg_add_str(current_mousebind_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "menu.action")) {
|
} else if (!strcmp(nodename, "menu.action")) {
|
||||||
current_mousebind_action->arg = strdup(content);
|
action_arg_add_str(current_mousebind_action, NULL, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -544,7 +538,7 @@ load_default_key_bindings(void)
|
||||||
wl_list_insert(k->actions.prev, &action->link);
|
wl_list_insert(k->actions.prev, &action->link);
|
||||||
|
|
||||||
if (key_combos[i].command) {
|
if (key_combos[i].command) {
|
||||||
action->arg = strdup(key_combos[i].command);
|
action_arg_add_str(action, NULL, key_combos[i].command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -604,7 +598,7 @@ load_default_mouse_bindings(void)
|
||||||
wl_list_insert(m->actions.prev, &action->link);
|
wl_list_insert(m->actions.prev, &action->link);
|
||||||
|
|
||||||
if (mouse_combos[i].command) {
|
if (mouse_combos[i].command) {
|
||||||
action->arg = strdup(mouse_combos[i].command);
|
action_arg_add_str(action, NULL, mouse_combos[i].command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,16 @@ deactivate_all_views(struct server *server)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
desktop_arrange_all_views(struct server *server)
|
||||||
|
{
|
||||||
|
/* Adjust window positions/sizes */
|
||||||
|
struct view *view;
|
||||||
|
wl_list_for_each(view, &server->views, link) {
|
||||||
|
view_adjust_for_layout_change(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
desktop_focus_and_activate_view(struct seat *seat, struct view *view)
|
desktop_focus_and_activate_view(struct seat *seat, struct view *view)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,30 +17,51 @@ max_move_scale(double pos_cursor, double pos_current,
|
||||||
void
|
void
|
||||||
interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
|
interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
|
||||||
{
|
{
|
||||||
if (view->maximized) {
|
if (mode == LAB_INPUT_STATE_MOVE && view->fullscreen) {
|
||||||
|
/**
|
||||||
|
* We don't allow moving fullscreen windows.
|
||||||
|
*
|
||||||
|
* If you think there is a good reason to allow it
|
||||||
|
* feel free to open an issue explaining your use-case.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode == LAB_INPUT_STATE_RESIZE
|
||||||
|
&& (view->fullscreen || view->maximized)) {
|
||||||
|
/* We don't allow resizing while in maximized or fullscreen state */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (view->maximized || view->tiled) {
|
||||||
if (mode == LAB_INPUT_STATE_MOVE) {
|
if (mode == LAB_INPUT_STATE_MOVE) {
|
||||||
|
/* Exit maximized or tiled mode */
|
||||||
int new_x = max_move_scale(view->server->seat.cursor->x,
|
int new_x = max_move_scale(view->server->seat.cursor->x,
|
||||||
view->x, view->w, view->unmaximized_geometry.width);
|
view->x, view->w, view->natural_geometry.width);
|
||||||
int new_y = max_move_scale(view->server->seat.cursor->y,
|
int new_y = max_move_scale(view->server->seat.cursor->y,
|
||||||
view->y, view->h, view->unmaximized_geometry.height);
|
view->y, view->h, view->natural_geometry.height);
|
||||||
view->unmaximized_geometry.x = new_x;
|
view->natural_geometry.x = new_x;
|
||||||
view->unmaximized_geometry.y = new_y;
|
view->natural_geometry.y = new_y;
|
||||||
view_maximize(view, false);
|
if (view->maximized) {
|
||||||
/*
|
view_maximize(view, false);
|
||||||
* view_maximize() indirectly calls view->impl->configure
|
}
|
||||||
* which is async but we are using the current values in
|
if (view->tiled) {
|
||||||
* server->grab_box. We pretend the configure already
|
view_move_resize(view, view->natural_geometry);
|
||||||
* happened by setting them manually.
|
}
|
||||||
|
/**
|
||||||
|
* view_maximize() / view_move_resize() indirectly calls
|
||||||
|
* view->impl->configure which is async but we are using
|
||||||
|
* the current values in server->grab_box. We pretend the
|
||||||
|
* configure already happened by setting them manually.
|
||||||
*/
|
*/
|
||||||
view->x = new_x;
|
view->x = new_x;
|
||||||
view->y = new_y;
|
view->y = new_y;
|
||||||
view->w = view->unmaximized_geometry.width;
|
view->w = view->natural_geometry.width;
|
||||||
view->h = view->unmaximized_geometry.height;
|
view->h = view->natural_geometry.height;
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Moving or resizing always resets tiled state */
|
||||||
|
view->tiled = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function sets up an interactive move or resize operation, where
|
* This function sets up an interactive move or resize operation, where
|
||||||
* the compositor stops propagating pointer events to clients and
|
* the compositor stops propagating pointer events to clients and
|
||||||
|
|
@ -101,9 +122,9 @@ interactive_end(struct view *view)
|
||||||
* When unmaximizing later on restore
|
* When unmaximizing later on restore
|
||||||
* original position
|
* original position
|
||||||
*/
|
*/
|
||||||
view->unmaximized_geometry.x =
|
view->natural_geometry.x =
|
||||||
view->server->grab_box.x;
|
view->server->grab_box.x;
|
||||||
view->unmaximized_geometry.y =
|
view->natural_geometry.y =
|
||||||
view->server->grab_box.y;
|
view->server->grab_box.y;
|
||||||
} else {
|
} else {
|
||||||
view_snap_to_edge(view, "up");
|
view_snap_to_edge(view, "up");
|
||||||
|
|
|
||||||
32
src/layers.c
32
src/layers.c
|
|
@ -25,6 +25,7 @@ layers_arrange(struct output *output)
|
||||||
wlr_output_effective_resolution(output->wlr_output,
|
wlr_output_effective_resolution(output->wlr_output,
|
||||||
&full_area.width, &full_area.height);
|
&full_area.width, &full_area.height);
|
||||||
struct wlr_box usable_area = full_area;
|
struct wlr_box usable_area = full_area;
|
||||||
|
struct wlr_box old_usable_area = output->usable_area;
|
||||||
|
|
||||||
struct server *server = output->server;
|
struct server *server = output->server;
|
||||||
struct wlr_scene_output *scene_output =
|
struct wlr_scene_output *scene_output =
|
||||||
|
|
@ -37,11 +38,29 @@ layers_arrange(struct output *output)
|
||||||
int nr_layers = sizeof(output->layers) / sizeof(output->layers[0]);
|
int nr_layers = sizeof(output->layers) / sizeof(output->layers[0]);
|
||||||
for (int i = 0; i < nr_layers; i++) {
|
for (int i = 0; i < nr_layers; i++) {
|
||||||
struct lab_layer_surface *lab_layer_surface;
|
struct lab_layer_surface *lab_layer_surface;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First we go over the list of surfaces that have
|
||||||
|
* exclusive_zone set (e.g. statusbars) because we have to
|
||||||
|
* determine the usable area before processing regular layouts.
|
||||||
|
*/
|
||||||
wl_list_for_each(lab_layer_surface, &output->layers[i], link) {
|
wl_list_for_each(lab_layer_surface, &output->layers[i], link) {
|
||||||
struct wlr_scene_layer_surface_v1 *scene_layer_surface =
|
struct wlr_scene_layer_surface_v1 *scene_layer_surface =
|
||||||
lab_layer_surface->scene_layer_surface;
|
lab_layer_surface->scene_layer_surface;
|
||||||
wlr_scene_layer_surface_v1_configure(
|
if (scene_layer_surface->layer_surface->current.exclusive_zone) {
|
||||||
scene_layer_surface, &full_area, &usable_area);
|
wlr_scene_layer_surface_v1_configure(
|
||||||
|
scene_layer_surface, &full_area, &usable_area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we process regular layouts */
|
||||||
|
wl_list_for_each(lab_layer_surface, &output->layers[i], link) {
|
||||||
|
struct wlr_scene_layer_surface_v1 *scene_layer_surface =
|
||||||
|
lab_layer_surface->scene_layer_surface;
|
||||||
|
if (!scene_layer_surface->layer_surface->current.exclusive_zone) {
|
||||||
|
wlr_scene_layer_surface_v1_configure(
|
||||||
|
scene_layer_surface, &full_area, &usable_area);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_scene_node_set_position(&output->layer_tree[i]->node,
|
wlr_scene_node_set_position(&output->layer_tree[i]->node,
|
||||||
|
|
@ -80,7 +99,12 @@ layers_arrange(struct output *output)
|
||||||
!seat->focused_layer->current.keyboard_interactive) {
|
!seat->focused_layer->current.keyboard_interactive) {
|
||||||
seat_set_focus_layer(seat, NULL);
|
seat_set_focus_layer(seat, NULL);
|
||||||
}
|
}
|
||||||
/* FIXME: should we call a desktop_arrange_all_views() here? */
|
|
||||||
|
/* Finally re-arrange all views based on usable_area */
|
||||||
|
if (old_usable_area.width != output->usable_area.width
|
||||||
|
|| old_usable_area.height != output->usable_area.height) {
|
||||||
|
desktop_arrange_all_views(server);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -350,7 +374,7 @@ new_layer_surface_notify(struct wl_listener *listener, void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_insert(&output->layers[layer_surface->pending.layer],
|
wl_list_insert(output->layers[layer_surface->pending.layer].prev,
|
||||||
&surface->link);
|
&surface->link);
|
||||||
/*
|
/*
|
||||||
* Temporarily set the layer's current state to pending so that
|
* Temporarily set the layer's current state to pending so that
|
||||||
|
|
|
||||||
|
|
@ -238,16 +238,16 @@ fill_item(char *nodename, char *content)
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else if (!strcmp(nodename, "command.action")) {
|
} else if (!strcmp(nodename, "command.action")) {
|
||||||
current_item_action->arg = strdup(content);
|
action_arg_add_str(current_item_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "execute.action")) {
|
} else if (!strcmp(nodename, "execute.action")) {
|
||||||
/*
|
/*
|
||||||
* <action name="Execute"><execute>foo</execute></action>
|
* <action name="Execute"><execute>foo</execute></action>
|
||||||
* is deprecated, but we support it anyway for backward
|
* is deprecated, but we support it anyway for backward
|
||||||
* compatibility with old openbox-menu generators
|
* compatibility with old openbox-menu generators
|
||||||
*/
|
*/
|
||||||
current_item_action->arg = strdup(content);
|
action_arg_add_str(current_item_action, NULL, content);
|
||||||
} else if (!strcmp(nodename, "to.action")) {
|
} else if (!strcmp(nodename, "to.action")) {
|
||||||
current_item_action->arg = strdup(content);
|
action_arg_add_str(current_item_action, NULL, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,10 +209,7 @@ static void
|
||||||
output_update_for_layout_change(struct server *server)
|
output_update_for_layout_change(struct server *server)
|
||||||
{
|
{
|
||||||
/* Adjust window positions/sizes */
|
/* Adjust window positions/sizes */
|
||||||
struct view *view;
|
desktop_arrange_all_views(server);
|
||||||
wl_list_for_each(view, &server->views, link) {
|
|
||||||
view_adjust_for_layout_change(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Move" each wlr_output_cursor (in per-output coordinates) to
|
* "Move" each wlr_output_cursor (in per-output coordinates) to
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ reload_config_and_theme(void)
|
||||||
if (!view->mapped || !view->ssd.enabled) {
|
if (!view->mapped || !view->ssd.enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
view->margin = ssd_thickness(view);
|
|
||||||
ssd_reload(view);
|
ssd_reload(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
struct border
|
struct border
|
||||||
ssd_thickness(struct view *view)
|
ssd_thickness(struct view *view)
|
||||||
{
|
{
|
||||||
|
if (!view->ssd.enabled) {
|
||||||
|
struct border border = { 0 };
|
||||||
|
return border;
|
||||||
|
}
|
||||||
struct theme *theme = view->server->theme;
|
struct theme *theme = view->server->theme;
|
||||||
struct border border = {
|
struct border border = {
|
||||||
.top = theme->title_height + theme->border_width,
|
.top = theme->title_height + theme->border_width,
|
||||||
|
|
@ -159,6 +163,7 @@ ssd_create(struct view *view)
|
||||||
ssd_extents_create(view);
|
ssd_extents_create(view);
|
||||||
ssd_border_create(view);
|
ssd_border_create(view);
|
||||||
ssd_titlebar_create(view);
|
ssd_titlebar_create(view);
|
||||||
|
view->margin = ssd_thickness(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -171,10 +176,12 @@ ssd_update_geometry(struct view *view)
|
||||||
if (!view->ssd.enabled) {
|
if (!view->ssd.enabled) {
|
||||||
if (view->ssd.tree->node.enabled) {
|
if (view->ssd.tree->node.enabled) {
|
||||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
|
wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
|
||||||
|
view->margin = ssd_thickness(view);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (!view->ssd.tree->node.enabled) {
|
} else if (!view->ssd.tree->node.enabled) {
|
||||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, true);
|
wlr_scene_node_set_enabled(&view->ssd.tree->node, true);
|
||||||
|
view->margin = ssd_thickness(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = view->w;
|
int width = view->w;
|
||||||
|
|
@ -198,15 +205,6 @@ ssd_update_geometry(struct view *view)
|
||||||
view->ssd.state.y = view->y;
|
view->ssd.state.y = view->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ssd_hide(struct view *view)
|
|
||||||
{
|
|
||||||
if (!view->ssd.tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssd_reload(struct view *view)
|
void ssd_reload(struct view *view)
|
||||||
{
|
{
|
||||||
if (!view->ssd.tree) {
|
if (!view->ssd.tree) {
|
||||||
|
|
|
||||||
331
src/view.c
331
src/view.c
|
|
@ -8,8 +8,93 @@
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
#include "workspaces.h"
|
#include "workspaces.h"
|
||||||
|
|
||||||
|
#define LAB_FALLBACK_WIDTH 640
|
||||||
|
#define LAB_FALLBACK_HEIGHT 480
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All view_apply_xxx_geometry() functions must *not* modify
|
||||||
|
* any state besides repositioning or resizing the view.
|
||||||
|
*
|
||||||
|
* They may be called repeatably during output layout changes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum view_edge {
|
||||||
|
VIEW_EDGE_INVALID = 0,
|
||||||
|
|
||||||
|
VIEW_EDGE_LEFT,
|
||||||
|
VIEW_EDGE_RIGHT,
|
||||||
|
VIEW_EDGE_UP,
|
||||||
|
VIEW_EDGE_DOWN,
|
||||||
|
VIEW_EDGE_CENTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum view_edge
|
||||||
|
view_edge_invert(enum view_edge edge)
|
||||||
|
{
|
||||||
|
switch (edge) {
|
||||||
|
case VIEW_EDGE_LEFT:
|
||||||
|
return VIEW_EDGE_RIGHT;
|
||||||
|
case VIEW_EDGE_RIGHT:
|
||||||
|
return VIEW_EDGE_LEFT;
|
||||||
|
case VIEW_EDGE_UP:
|
||||||
|
return VIEW_EDGE_DOWN;
|
||||||
|
case VIEW_EDGE_DOWN:
|
||||||
|
return VIEW_EDGE_UP;
|
||||||
|
case VIEW_EDGE_CENTER:
|
||||||
|
case VIEW_EDGE_INVALID:
|
||||||
|
default:
|
||||||
|
return VIEW_EDGE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_box
|
||||||
|
view_get_edge_snap_box(struct view *view, struct output *output,
|
||||||
|
enum view_edge edge)
|
||||||
|
{
|
||||||
|
struct wlr_box usable = output_usable_area_in_layout_coords(output);
|
||||||
|
if (usable.height == output->wlr_output->height
|
||||||
|
&& output->wlr_output->scale != 1) {
|
||||||
|
usable.height /= output->wlr_output->scale;
|
||||||
|
}
|
||||||
|
if (usable.width == output->wlr_output->width
|
||||||
|
&& output->wlr_output->scale != 1) {
|
||||||
|
usable.width /= output->wlr_output->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x_offset = edge == VIEW_EDGE_RIGHT
|
||||||
|
? (usable.width + rc.gap) / 2 : rc.gap;
|
||||||
|
int y_offset = edge == VIEW_EDGE_DOWN
|
||||||
|
? (usable.height + rc.gap) / 2 : rc.gap;
|
||||||
|
|
||||||
|
int base_width, base_height;
|
||||||
|
switch (edge) {
|
||||||
|
case VIEW_EDGE_LEFT:
|
||||||
|
case VIEW_EDGE_RIGHT:
|
||||||
|
base_width = (usable.width - 3 * rc.gap) / 2;
|
||||||
|
base_height = usable.height - 2 * rc.gap;
|
||||||
|
break;
|
||||||
|
case VIEW_EDGE_UP:
|
||||||
|
case VIEW_EDGE_DOWN:
|
||||||
|
base_width = usable.width - 2 * rc.gap;
|
||||||
|
base_height = (usable.height - 3 * rc.gap) / 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case VIEW_EDGE_CENTER:
|
||||||
|
base_width = usable.width - 2 * rc.gap;
|
||||||
|
base_height = usable.height - 2 * rc.gap;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
struct wlr_box dst = {
|
||||||
|
.x = x_offset + usable.x + view->margin.left,
|
||||||
|
.y = y_offset + usable.y + view->margin.top,
|
||||||
|
.width = base_width - view->margin.left - view->margin.right,
|
||||||
|
.height = base_height - view->margin.top - view->margin.bottom,
|
||||||
|
};
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
view_set_activated(struct view *view, bool activated)
|
view_set_activated(struct view *view, bool activated)
|
||||||
{
|
{
|
||||||
|
|
@ -176,6 +261,38 @@ view_compute_centered_position(struct view *view, int w, int h, int *x, int *y)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_fallback_geometry(struct view *view)
|
||||||
|
{
|
||||||
|
view->natural_geometry.width = LAB_FALLBACK_WIDTH;
|
||||||
|
view->natural_geometry.height = LAB_FALLBACK_HEIGHT;
|
||||||
|
view_compute_centered_position(view,
|
||||||
|
view->natural_geometry.width,
|
||||||
|
view->natural_geometry.height,
|
||||||
|
&view->natural_geometry.x,
|
||||||
|
&view->natural_geometry.y);
|
||||||
|
}
|
||||||
|
#undef LAB_FALLBACK_WIDTH
|
||||||
|
#undef LAB_FALLBACK_HEIGHT
|
||||||
|
|
||||||
|
static void
|
||||||
|
view_store_natural_geometry(struct view *view)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* If an application was started maximized or fullscreened, its
|
||||||
|
* natural_geometry width/height may still be zero in which case we set
|
||||||
|
* some fallback values. This is the case with foot and Qt applications.
|
||||||
|
*/
|
||||||
|
if (!view->w || !view->h) {
|
||||||
|
set_fallback_geometry(view);
|
||||||
|
} else {
|
||||||
|
view->natural_geometry.x = view->x;
|
||||||
|
view->natural_geometry.y = view->y;
|
||||||
|
view->natural_geometry.width = view->w;
|
||||||
|
view->natural_geometry.height = view->h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
view_center(struct view *view)
|
view_center(struct view *view)
|
||||||
{
|
{
|
||||||
|
|
@ -185,6 +302,27 @@ view_center(struct view *view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
view_apply_tiled_geometry(struct view *view, struct output *output)
|
||||||
|
{
|
||||||
|
assert(view->tiled);
|
||||||
|
if (!output) {
|
||||||
|
output = view_output(view);
|
||||||
|
}
|
||||||
|
if (!output) {
|
||||||
|
wlr_log(WLR_ERROR, "Can't tile: no output");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box dst = view_get_edge_snap_box(view, output, view->tiled);
|
||||||
|
if (view->w == dst.width && view->h == dst.height) {
|
||||||
|
/* move horizontally/vertically without changing size */
|
||||||
|
view_move(view, dst.x, dst.y);
|
||||||
|
} else {
|
||||||
|
view_move_resize(view, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
view_apply_fullscreen_geometry(struct view *view, struct wlr_output *wlr_output)
|
view_apply_fullscreen_geometry(struct view *view, struct wlr_output *wlr_output)
|
||||||
{
|
{
|
||||||
|
|
@ -234,41 +372,17 @@ view_apply_maximized_geometry(struct view *view)
|
||||||
view_move_resize(view, box);
|
view_move_resize(view, box);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LAB_FALLBACK_WIDTH (640)
|
|
||||||
#define LAB_FALLBACK_HEIGHT (480)
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_fallback_geometry(struct view *view)
|
|
||||||
{
|
|
||||||
view->unmaximized_geometry.width = LAB_FALLBACK_WIDTH;
|
|
||||||
view->unmaximized_geometry.height = LAB_FALLBACK_HEIGHT;
|
|
||||||
view_compute_centered_position(view,
|
|
||||||
view->unmaximized_geometry.width,
|
|
||||||
view->unmaximized_geometry.height,
|
|
||||||
&view->unmaximized_geometry.x,
|
|
||||||
&view->unmaximized_geometry.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
view_apply_unmaximized_geometry(struct view *view)
|
view_apply_unmaximized_geometry(struct view *view)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* If an application was started maximized, its unmaximized_geometry
|
|
||||||
* width/height may still be zero in which case we set some fallback
|
|
||||||
* values. This is the case with foot and Qt applications.
|
|
||||||
*/
|
|
||||||
if (wlr_box_empty(&view->unmaximized_geometry)) {
|
|
||||||
set_fallback_geometry(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wlr_output_layout *layout = view->server->output_layout;
|
struct wlr_output_layout *layout = view->server->output_layout;
|
||||||
if (wlr_output_layout_intersects(layout, NULL,
|
if (wlr_output_layout_intersects(layout, NULL,
|
||||||
&view->unmaximized_geometry)) {
|
&view->natural_geometry)) {
|
||||||
/* restore to original geometry */
|
/* restore to original geometry */
|
||||||
view_move_resize(view, view->unmaximized_geometry);
|
view_move_resize(view, view->natural_geometry);
|
||||||
} else {
|
} else {
|
||||||
/* reposition if original geometry is offscreen */
|
/* reposition if original geometry is offscreen */
|
||||||
struct wlr_box box = view->unmaximized_geometry;
|
struct wlr_box box = view->natural_geometry;
|
||||||
if (view_compute_centered_position(view, box.width, box.height,
|
if (view_compute_centered_position(view, box.width, box.height,
|
||||||
&box.x, &box.y)) {
|
&box.x, &box.y)) {
|
||||||
view_move_resize(view, box);
|
view_move_resize(view, box);
|
||||||
|
|
@ -294,16 +408,18 @@ view_maximize(struct view *view, bool maximize)
|
||||||
}
|
}
|
||||||
if (maximize) {
|
if (maximize) {
|
||||||
interactive_end(view);
|
interactive_end(view);
|
||||||
view->unmaximized_geometry.x = view->x;
|
if (!view->tiled) {
|
||||||
view->unmaximized_geometry.y = view->y;
|
view_store_natural_geometry(view);
|
||||||
view->unmaximized_geometry.width = view->w;
|
}
|
||||||
view->unmaximized_geometry.height = view->h;
|
|
||||||
|
|
||||||
view_apply_maximized_geometry(view);
|
view_apply_maximized_geometry(view);
|
||||||
view->maximized = true;
|
view->maximized = true;
|
||||||
} else {
|
} else {
|
||||||
/* unmaximize */
|
/* unmaximize */
|
||||||
view_apply_unmaximized_geometry(view);
|
if (view->tiled) {
|
||||||
|
view_apply_tiled_geometry(view, NULL);
|
||||||
|
} else {
|
||||||
|
view_apply_unmaximized_geometry(view);
|
||||||
|
}
|
||||||
view->maximized = false;
|
view->maximized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -322,6 +438,8 @@ view_toggle_decorations(struct view *view)
|
||||||
ssd_update_geometry(view);
|
ssd_update_geometry(view);
|
||||||
if (view->maximized) {
|
if (view->maximized) {
|
||||||
view_apply_maximized_geometry(view);
|
view_apply_maximized_geometry(view);
|
||||||
|
} else if (view->tiled) {
|
||||||
|
view_apply_tiled_geometry(view, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -353,6 +471,8 @@ view_set_decorations(struct view *view, bool decorations)
|
||||||
ssd_update_geometry(view);
|
ssd_update_geometry(view);
|
||||||
if (view->maximized) {
|
if (view->maximized) {
|
||||||
view_apply_maximized_geometry(view);
|
view_apply_maximized_geometry(view);
|
||||||
|
} else if (view->tiled) {
|
||||||
|
view_apply_tiled_geometry(view, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -381,11 +501,8 @@ view_set_fullscreen(struct view *view, bool fullscreen,
|
||||||
wlr_output = view_wlr_output(view);
|
wlr_output = view_wlr_output(view);
|
||||||
}
|
}
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
if (!view->maximized) {
|
if (!view->maximized && !view->tiled) {
|
||||||
view->unmaximized_geometry.x = view->x;
|
view_store_natural_geometry(view);
|
||||||
view->unmaximized_geometry.y = view->y;
|
|
||||||
view->unmaximized_geometry.width = view->w;
|
|
||||||
view->unmaximized_geometry.height = view->h;
|
|
||||||
}
|
}
|
||||||
view->fullscreen = wlr_output;
|
view->fullscreen = wlr_output;
|
||||||
view_apply_fullscreen_geometry(view, view->fullscreen);
|
view_apply_fullscreen_geometry(view, view->fullscreen);
|
||||||
|
|
@ -393,6 +510,8 @@ view_set_fullscreen(struct view *view, bool fullscreen,
|
||||||
/* restore to normal */
|
/* restore to normal */
|
||||||
if (view->maximized) {
|
if (view->maximized) {
|
||||||
view_apply_maximized_geometry(view);
|
view_apply_maximized_geometry(view);
|
||||||
|
} else if (view->tiled) {
|
||||||
|
view_apply_tiled_geometry(view, NULL);
|
||||||
} else {
|
} else {
|
||||||
view_apply_unmaximized_geometry(view);
|
view_apply_unmaximized_geometry(view);
|
||||||
}
|
}
|
||||||
|
|
@ -421,6 +540,9 @@ view_adjust_for_layout_change(struct view *view)
|
||||||
} else if (view->maximized) {
|
} else if (view->maximized) {
|
||||||
/* recompute maximized geometry */
|
/* recompute maximized geometry */
|
||||||
view_apply_maximized_geometry(view);
|
view_apply_maximized_geometry(view);
|
||||||
|
} else if (view->tiled) {
|
||||||
|
/* recompute tiled geometry */
|
||||||
|
view_apply_tiled_geometry(view, NULL);
|
||||||
} else {
|
} else {
|
||||||
/* reposition view if it's offscreen */
|
/* reposition view if it's offscreen */
|
||||||
struct wlr_box box = { view->x, view->y, view->w, view->h };
|
struct wlr_box box = { view->x, view->y, view->w, view->h };
|
||||||
|
|
@ -515,35 +637,6 @@ view_move_to_edge(struct view *view, const char *direction)
|
||||||
view_move(view, x, y);
|
view_move(view, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum view_edge {
|
|
||||||
VIEW_EDGE_INVALID,
|
|
||||||
|
|
||||||
VIEW_EDGE_LEFT,
|
|
||||||
VIEW_EDGE_RIGHT,
|
|
||||||
VIEW_EDGE_UP,
|
|
||||||
VIEW_EDGE_DOWN,
|
|
||||||
VIEW_EDGE_CENTER,
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum view_edge
|
|
||||||
view_edge_invert(enum view_edge edge)
|
|
||||||
{
|
|
||||||
switch (edge) {
|
|
||||||
case VIEW_EDGE_LEFT:
|
|
||||||
return VIEW_EDGE_RIGHT;
|
|
||||||
case VIEW_EDGE_RIGHT:
|
|
||||||
return VIEW_EDGE_LEFT;
|
|
||||||
case VIEW_EDGE_UP:
|
|
||||||
return VIEW_EDGE_DOWN;
|
|
||||||
case VIEW_EDGE_DOWN:
|
|
||||||
return VIEW_EDGE_UP;
|
|
||||||
case VIEW_EDGE_CENTER:
|
|
||||||
case VIEW_EDGE_INVALID:
|
|
||||||
default:
|
|
||||||
return VIEW_EDGE_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum view_edge
|
static enum view_edge
|
||||||
view_edge_parse(const char *direction)
|
view_edge_parse(const char *direction)
|
||||||
{
|
{
|
||||||
|
|
@ -565,53 +658,6 @@ view_edge_parse(const char *direction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wlr_box
|
|
||||||
view_get_edge_snap_box(struct view *view, struct output *output,
|
|
||||||
enum view_edge edge)
|
|
||||||
{
|
|
||||||
struct wlr_box usable = output_usable_area_in_layout_coords(output);
|
|
||||||
if (usable.height == output->wlr_output->height
|
|
||||||
&& output->wlr_output->scale != 1) {
|
|
||||||
usable.height /= output->wlr_output->scale;
|
|
||||||
}
|
|
||||||
if (usable.width == output->wlr_output->width
|
|
||||||
&& output->wlr_output->scale != 1) {
|
|
||||||
usable.width /= output->wlr_output->scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x_offset = edge == VIEW_EDGE_RIGHT
|
|
||||||
? (usable.width + rc.gap) / 2 : rc.gap;
|
|
||||||
int y_offset = edge == VIEW_EDGE_DOWN
|
|
||||||
? (usable.height + rc.gap) / 2 : rc.gap;
|
|
||||||
|
|
||||||
int base_width, base_height;
|
|
||||||
switch (edge) {
|
|
||||||
case VIEW_EDGE_LEFT:
|
|
||||||
case VIEW_EDGE_RIGHT:
|
|
||||||
base_width = (usable.width - 3 * rc.gap) / 2;
|
|
||||||
base_height = usable.height - 2 * rc.gap;
|
|
||||||
break;
|
|
||||||
case VIEW_EDGE_UP:
|
|
||||||
case VIEW_EDGE_DOWN:
|
|
||||||
base_width = usable.width - 2 * rc.gap;
|
|
||||||
base_height = (usable.height - 3 * rc.gap) / 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case VIEW_EDGE_CENTER:
|
|
||||||
base_width = usable.width - 2 * rc.gap;
|
|
||||||
base_height = usable.height - 2 * rc.gap;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
struct wlr_box dst = {
|
|
||||||
.x = x_offset + usable.x + view->margin.left,
|
|
||||||
.y = y_offset + usable.y + view->margin.top,
|
|
||||||
.width = base_width - view->margin.left - view->margin.right,
|
|
||||||
.height = base_height - view->margin.top - view->margin.bottom,
|
|
||||||
};
|
|
||||||
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
view_snap_to_edge(struct view *view, const char *direction)
|
view_snap_to_edge(struct view *view, const char *direction)
|
||||||
{
|
{
|
||||||
|
|
@ -619,6 +665,9 @@ view_snap_to_edge(struct view *view, const char *direction)
|
||||||
wlr_log(WLR_ERROR, "no view");
|
wlr_log(WLR_ERROR, "no view");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (view->fullscreen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
struct output *output = view_output(view);
|
struct output *output = view_output(view);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
wlr_log(WLR_ERROR, "no output");
|
wlr_log(WLR_ERROR, "no output");
|
||||||
|
|
@ -630,50 +679,50 @@ view_snap_to_edge(struct view *view, const char *direction)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_box dst = view_get_edge_snap_box(view, output, edge);
|
if (view->tiled == edge) {
|
||||||
|
/* We are already tiled for this edge and thus should switch outputs */
|
||||||
if (view->x == dst.x && view->y == dst.y && view->w == dst.width
|
struct wlr_output *new_output = NULL;
|
||||||
&& view->h == dst.height) {
|
struct wlr_output *current_output = output->wlr_output;
|
||||||
/* Move over to the next screen if this is already snapped. */
|
struct wlr_output_layout *layout = view->server->output_layout;
|
||||||
struct wlr_box usable =
|
|
||||||
output_usable_area_in_layout_coords(output);
|
|
||||||
switch (edge) {
|
switch (edge) {
|
||||||
case VIEW_EDGE_LEFT:
|
case VIEW_EDGE_LEFT:
|
||||||
dst.x -= (usable.width / 2) + 1;
|
new_output = wlr_output_layout_adjacent_output(
|
||||||
|
layout, WLR_DIRECTION_LEFT, current_output, 1, 0);
|
||||||
break;
|
break;
|
||||||
case VIEW_EDGE_RIGHT:
|
case VIEW_EDGE_RIGHT:
|
||||||
dst.x += (usable.width / 2) + 1;
|
new_output = wlr_output_layout_adjacent_output(
|
||||||
|
layout, WLR_DIRECTION_RIGHT, current_output, 1, 0);
|
||||||
break;
|
break;
|
||||||
case VIEW_EDGE_UP:
|
case VIEW_EDGE_UP:
|
||||||
dst.y -= (usable.height / 2) + 1;
|
new_output = wlr_output_layout_adjacent_output(
|
||||||
|
layout, WLR_DIRECTION_UP, current_output, 0, 1);
|
||||||
break;
|
break;
|
||||||
case VIEW_EDGE_DOWN:
|
case VIEW_EDGE_DOWN:
|
||||||
dst.y += (usable.height / 2) + 1;
|
new_output = wlr_output_layout_adjacent_output(
|
||||||
|
layout, WLR_DIRECTION_DOWN, current_output, 0, 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (new_output && new_output != current_output) {
|
||||||
struct wlr_output *new_wlr_output = wlr_output_layout_output_at(
|
/* Move to next output */
|
||||||
view->server->output_layout, dst.x, dst.y);
|
edge = view_edge_invert(edge);
|
||||||
struct output *new_output =
|
output = output_from_wlr_output(view->server, new_output);
|
||||||
output_from_wlr_output(view->server, new_wlr_output);
|
} else {
|
||||||
|
/* No more output to move to */
|
||||||
if (new_output == output || !new_output
|
|
||||||
|| edge == VIEW_EDGE_CENTER) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dst = view_get_edge_snap_box(view, new_output,
|
|
||||||
view_edge_invert(edge));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view->w == dst.width && view->h == dst.height) {
|
if (view->maximized) {
|
||||||
/* move horizontally/vertically without changing size */
|
/* Unmaximize + keep using existing natural_geometry */
|
||||||
view_move(view, dst.x, dst.y);
|
view_maximize(view, false);
|
||||||
} else {
|
} else if (!view->tiled) {
|
||||||
view_move_resize(view, dst);
|
/* store current geometry as new natural_geometry */
|
||||||
|
view_store_natural_geometry(view);
|
||||||
}
|
}
|
||||||
|
view->tiled = edge;
|
||||||
|
view_apply_tiled_geometry(view, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,6 @@ xdg_toplevel_view_map(struct view *view)
|
||||||
|
|
||||||
view->ssd.enabled = has_ssd(view);
|
view->ssd.enabled = has_ssd(view);
|
||||||
if (view->ssd.enabled) {
|
if (view->ssd.enabled) {
|
||||||
view->margin = ssd_thickness(view);
|
|
||||||
ssd_create(view);
|
ssd_create(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,7 +310,6 @@ xdg_toplevel_view_map(struct view *view)
|
||||||
}
|
}
|
||||||
|
|
||||||
view_discover_output(view);
|
view_discover_output(view);
|
||||||
|
|
||||||
view->been_mapped = true;
|
view->been_mapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ unmanaged_handle_commit(struct wl_listener *listener, void *data)
|
||||||
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
||||||
unmanaged->lx = xsurface->x;
|
unmanaged->lx = xsurface->x;
|
||||||
unmanaged->ly = xsurface->y;
|
unmanaged->ly = xsurface->y;
|
||||||
|
wlr_scene_node_set_position(unmanaged->node,
|
||||||
|
unmanaged->lx, unmanaged->ly);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -33,6 +35,8 @@ unmanaged_handle_set_geometry(struct wl_listener *listener, void *data)
|
||||||
wlr_log(WLR_DEBUG, "xwayland-unmanaged surface has moved");
|
wlr_log(WLR_DEBUG, "xwayland-unmanaged surface has moved");
|
||||||
unmanaged->lx = xsurface->x;
|
unmanaged->lx = xsurface->x;
|
||||||
unmanaged->ly = xsurface->y;
|
unmanaged->ly = xsurface->y;
|
||||||
|
wlr_scene_node_set_position(unmanaged->node,
|
||||||
|
unmanaged->lx, unmanaged->ly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,10 +63,11 @@ unmanaged_handle_map(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* node will be destroyed automatically once surface is destroyed */
|
/* node will be destroyed automatically once surface is destroyed */
|
||||||
struct wlr_scene_node *node = &wlr_scene_surface_create(
|
unmanaged->node = &wlr_scene_surface_create(
|
||||||
unmanaged->server->unmanaged_tree,
|
unmanaged->server->unmanaged_tree,
|
||||||
xsurface->surface)->buffer->node;
|
xsurface->surface)->buffer->node;
|
||||||
wlr_scene_node_set_position(node, unmanaged->lx, unmanaged->ly);
|
wlr_scene_node_set_position(unmanaged->node,
|
||||||
|
unmanaged->lx, unmanaged->ly);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,14 @@ handle_request_configure(struct wl_listener *listener, void *data)
|
||||||
int height = event->height;
|
int height = event->height;
|
||||||
view_adjust_size(view, &width, &height);
|
view_adjust_size(view, &width, &height);
|
||||||
|
|
||||||
|
view->pending_move_resize.update_x = event->x != view->x;
|
||||||
|
view->pending_move_resize.update_y = event->y != view->y;
|
||||||
|
view->pending_move_resize.x = event->x;
|
||||||
|
view->pending_move_resize.y = event->y;
|
||||||
|
view->pending_move_resize.width = width;
|
||||||
|
view->pending_move_resize.height = height;
|
||||||
|
|
||||||
|
wlr_scene_node_set_position(&view->scene_tree->node, event->x, event->y);
|
||||||
wlr_xwayland_surface_configure(view->xwayland_surface,
|
wlr_xwayland_surface_configure(view->xwayland_surface,
|
||||||
event->x, event->y, width, height);
|
event->x, event->y, width, height);
|
||||||
}
|
}
|
||||||
|
|
@ -216,6 +224,13 @@ move(struct view *view, double x, double y)
|
||||||
{
|
{
|
||||||
view->x = x;
|
view->x = x;
|
||||||
view->y = y;
|
view->y = y;
|
||||||
|
|
||||||
|
/* override any previous pending move */
|
||||||
|
view->pending_move_resize.update_x = false;
|
||||||
|
view->pending_move_resize.update_y = false;
|
||||||
|
view->pending_move_resize.x = x;
|
||||||
|
view->pending_move_resize.y = y;
|
||||||
|
|
||||||
struct wlr_xwayland_surface *s = view->xwayland_surface;
|
struct wlr_xwayland_surface *s = view->xwayland_surface;
|
||||||
wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y,
|
wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y,
|
||||||
(uint16_t)s->width, (uint16_t)s->height);
|
(uint16_t)s->width, (uint16_t)s->height);
|
||||||
|
|
@ -329,7 +344,7 @@ map(struct view *view)
|
||||||
if (!view->been_mapped) {
|
if (!view->been_mapped) {
|
||||||
view->ssd.enabled = want_deco(view);
|
view->ssd.enabled = want_deco(view);
|
||||||
if (view->ssd.enabled) {
|
if (view->ssd.enabled) {
|
||||||
view->margin = ssd_thickness(view);
|
ssd_create(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!view->maximized && !view->fullscreen) {
|
if (!view->maximized && !view->fullscreen) {
|
||||||
|
|
@ -341,11 +356,6 @@ map(struct view *view)
|
||||||
}
|
}
|
||||||
|
|
||||||
view_discover_output(view);
|
view_discover_output(view);
|
||||||
|
|
||||||
if (view->ssd.enabled) {
|
|
||||||
/* Create ssd after view_disover_output() had been called */
|
|
||||||
ssd_create(view);
|
|
||||||
}
|
|
||||||
view->been_mapped = true;
|
view->been_mapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue