nixos-dotfiles

nixos-dotfiles

https://git.tonybtw.com/nixos-dotfiles.git git://git.tonybtw.com/nixos-dotfiles.git
10,252 bytes raw
1
/*
2
 * Attempt to consolidate unavoidable suck into one file, away from dwl.c.  This
3
 * file is not meant to be pretty.  We use a .h file with static inline
4
 * functions instead of a separate .c module, or function pointers like sway, so
5
 * that they will simply compile out if the chosen #defines leave them unused.
6
 */
7
8
/* Leave these functions first; they're used in the others */
9
static inline int
10
client_is_x11(Client *c)
11
{
12
#ifdef XWAYLAND
13
	return c->type == X11;
14
#endif
15
	return 0;
16
}
17
18
static inline struct wlr_surface *
19
client_surface(Client *c)
20
{
21
#ifdef XWAYLAND
22
	if (client_is_x11(c))
23
		return c->surface.xwayland->surface;
24
#endif
25
	return c->surface.xdg->surface;
26
}
27
28
static inline int
29
toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
30
{
31
	struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
32
	struct wlr_surface *root_surface;
33
	struct wlr_layer_surface_v1 *layer_surface;
34
	Client *c = NULL;
35
	LayerSurface *l = NULL;
36
	int type = -1;
37
#ifdef XWAYLAND
38
	struct wlr_xwayland_surface *xsurface;
39
#endif
40
41
	if (!s)
42
		return -1;
43
	root_surface = wlr_surface_get_root_surface(s);
44
45
#ifdef XWAYLAND
46
	if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
47
		c = xsurface->data;
48
		type = c->type;
49
		goto end;
50
	}
51
#endif
52
53
	if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
54
		l = layer_surface->data;
55
		type = LayerShell;
56
		goto end;
57
	}
58
59
	xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
60
	while (xdg_surface) {
61
		tmp_xdg_surface = NULL;
62
		switch (xdg_surface->role) {
63
		case WLR_XDG_SURFACE_ROLE_POPUP:
64
			if (!xdg_surface->popup || !xdg_surface->popup->parent)
65
				return -1;
66
67
			tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
68
69
			if (!tmp_xdg_surface)
70
				return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
71
72
			xdg_surface = tmp_xdg_surface;
73
			break;
74
		case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
75
			c = xdg_surface->data;
76
			type = c->type;
77
			goto end;
78
		case WLR_XDG_SURFACE_ROLE_NONE:
79
			return -1;
80
		}
81
	}
82
83
end:
84
	if (pl)
85
		*pl = l;
86
	if (pc)
87
		*pc = c;
88
	return type;
89
}
90
91
/* The others */
92
static inline void
93
client_activate_surface(struct wlr_surface *s, int activated)
94
{
95
	struct wlr_xdg_toplevel *toplevel;
96
#ifdef XWAYLAND
97
	struct wlr_xwayland_surface *xsurface;
98
	if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
99
		wlr_xwayland_surface_activate(xsurface, activated);
100
		return;
101
	}
102
#endif
103
	if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
104
		wlr_xdg_toplevel_set_activated(toplevel, activated);
105
}
106
107
static inline uint32_t
108
client_set_bounds(Client *c, int32_t width, int32_t height)
109
{
110
#ifdef XWAYLAND
111
	if (client_is_x11(c))
112
		return 0;
113
#endif
114
	if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
115
			XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
116
			&& (c->bounds.width != width || c->bounds.height != height)) {
117
		c->bounds.width = width;
118
		c->bounds.height = height;
119
		return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
120
	}
121
	return 0;
122
}
123
124
static inline const char *
125
client_get_appid(Client *c)
126
{
127
#ifdef XWAYLAND
128
	if (client_is_x11(c))
129
		return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
130
#endif
131
	return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken";
132
}
133
134
static inline void
135
client_get_clip(Client *c, struct wlr_box *clip)
136
{
137
	*clip = (struct wlr_box){
138
		.x = 0,
139
		.y = 0,
140
		.width = c->geom.width - c->bw,
141
		.height = c->geom.height - c->bw,
142
	};
143
144
#ifdef XWAYLAND
145
	if (client_is_x11(c))
146
		return;
147
#endif
148
149
	clip->x = c->surface.xdg->geometry.x;
150
	clip->y = c->surface.xdg->geometry.y;
151
}
152
153
static inline void
154
client_get_geometry(Client *c, struct wlr_box *geom)
155
{
156
#ifdef XWAYLAND
157
	if (client_is_x11(c)) {
158
		geom->x = c->surface.xwayland->x;
159
		geom->y = c->surface.xwayland->y;
160
		geom->width = c->surface.xwayland->width;
161
		geom->height = c->surface.xwayland->height;
162
		return;
163
	}
164
#endif
165
	*geom = c->surface.xdg->geometry;
166
}
167
168
static inline Client *
169
client_get_parent(Client *c)
170
{
171
	Client *p = NULL;
172
#ifdef XWAYLAND
173
	if (client_is_x11(c)) {
174
		if (c->surface.xwayland->parent)
175
			toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
176
		return p;
177
	}
178
#endif
179
	if (c->surface.xdg->toplevel->parent)
180
		toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
181
	return p;
182
}
183
184
static inline int
185
client_has_children(Client *c)
186
{
187
#ifdef XWAYLAND
188
	if (client_is_x11(c))
189
		return !wl_list_empty(&c->surface.xwayland->children);
190
#endif
191
	/* surface.xdg->link is never empty because it always contains at least the
192
	 * surface itself. */
193
	return wl_list_length(&c->surface.xdg->link) > 1;
194
}
195
196
static inline const char *
197
client_get_title(Client *c)
198
{
199
#ifdef XWAYLAND
200
	if (client_is_x11(c))
201
		return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
202
#endif
203
	return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
204
}
205
206
static inline int
207
client_is_float_type(Client *c)
208
{
209
	struct wlr_xdg_toplevel *toplevel;
210
	struct wlr_xdg_toplevel_state state;
211
212
#ifdef XWAYLAND
213
	if (client_is_x11(c)) {
214
		struct wlr_xwayland_surface *surface = c->surface.xwayland;
215
		xcb_size_hints_t *size_hints = surface->size_hints;
216
		if (surface->modal)
217
			return 1;
218
219
		if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
220
				|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
221
				|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
222
				|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
223
			return 1;
224
		}
225
226
		return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
227
			&& (size_hints->max_width == size_hints->min_width
228
				|| size_hints->max_height == size_hints->min_height);
229
	}
230
#endif
231
232
	toplevel = c->surface.xdg->toplevel;
233
	state = toplevel->current;
234
	return toplevel->parent || (state.min_width != 0 && state.min_height != 0
235
		&& (state.min_width == state.max_width
236
			|| state.min_height == state.max_height));
237
}
238
239
static inline int
240
client_is_rendered_on_mon(Client *c, Monitor *m)
241
{
242
	/* This is needed for when you don't want to check formal assignment,
243
	 * but rather actual displaying of the pixels.
244
	 * Usually VISIBLEON suffices and is also faster. */
245
	struct wlr_surface_output *s;
246
	int unused_lx, unused_ly;
247
	if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
248
		return 0;
249
	wl_list_for_each(s, &client_surface(c)->current_outputs, link)
250
		if (s->output == m->wlr_output)
251
			return 1;
252
	return 0;
253
}
254
255
static inline int
256
client_is_stopped(Client *c)
257
{
258
	int pid;
259
	siginfo_t in = {0};
260
#ifdef XWAYLAND
261
	if (client_is_x11(c))
262
		return 0;
263
#endif
264
265
	wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
266
	if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
267
		/* This process is not our child process, while is very unlikely that
268
		 * it is stopped, in order to do not skip frames, assume that it is. */
269
		if (errno == ECHILD)
270
			return 1;
271
	} else if (in.si_pid) {
272
		if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
273
			return 1;
274
		if (in.si_code == CLD_CONTINUED)
275
			return 0;
276
	}
277
278
	return 0;
279
}
280
281
static inline int
282
client_is_unmanaged(Client *c)
283
{
284
#ifdef XWAYLAND
285
	if (client_is_x11(c))
286
		return c->surface.xwayland->override_redirect;
287
#endif
288
	return 0;
289
}
290
291
static inline void
292
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
293
{
294
	if (kb)
295
		wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
296
				kb->num_keycodes, &kb->modifiers);
297
	else
298
		wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
299
}
300
301
static inline void
302
client_send_close(Client *c)
303
{
304
#ifdef XWAYLAND
305
	if (client_is_x11(c)) {
306
		wlr_xwayland_surface_close(c->surface.xwayland);
307
		return;
308
	}
309
#endif
310
	wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
311
}
312
313
static inline void
314
client_set_border_color(Client *c, const float color[static 4])
315
{
316
	int i;
317
	for (i = 0; i < 4; i++)
318
		wlr_scene_rect_set_color(c->border[i], color);
319
}
320
321
static inline void
322
client_set_fullscreen(Client *c, int fullscreen)
323
{
324
#ifdef XWAYLAND
325
	if (client_is_x11(c)) {
326
		wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
327
		return;
328
	}
329
#endif
330
	wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
331
}
332
333
static inline void
334
client_set_scale(struct wlr_surface *s, float scale)
335
{
336
	wlr_fractional_scale_v1_notify_scale(s, scale);
337
	wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
338
}
339
340
static inline uint32_t
341
client_set_size(Client *c, uint32_t width, uint32_t height)
342
{
343
#ifdef XWAYLAND
344
	if (client_is_x11(c)) {
345
		wlr_xwayland_surface_configure(c->surface.xwayland,
346
				c->geom.x + c->bw, c->geom.y + c->bw, width, height);
347
		return 0;
348
	}
349
#endif
350
	if ((int32_t)width == c->surface.xdg->toplevel->current.width
351
			&& (int32_t)height == c->surface.xdg->toplevel->current.height)
352
		return 0;
353
	return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
354
}
355
356
static inline void
357
client_set_tiled(Client *c, uint32_t edges)
358
{
359
#ifdef XWAYLAND
360
	if (client_is_x11(c)) {
361
		wlr_xwayland_surface_set_maximized(c->surface.xwayland,
362
				edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
363
		return;
364
  }
365
#endif
366
	if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
367
			>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
368
		wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
369
	} else {
370
		wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
371
	}
372
}
373
374
static inline void
375
client_set_suspended(Client *c, int suspended)
376
{
377
#ifdef XWAYLAND
378
	if (client_is_x11(c))
379
		return;
380
#endif
381
382
	wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
383
}
384
385
static inline int
386
client_wants_focus(Client *c)
387
{
388
#ifdef XWAYLAND
389
	return client_is_unmanaged(c)
390
		&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
391
		&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
392
#endif
393
	return 0;
394
}
395
396
static inline int
397
client_wants_fullscreen(Client *c)
398
{
399
#ifdef XWAYLAND
400
	if (client_is_x11(c))
401
		return c->surface.xwayland->fullscreen;
402
#endif
403
	return c->surface.xdg->toplevel->requested.fullscreen;
404
}