+13
-107
src/video/wayland/SDL_waylandvideo.c
+13
-107
src/video/wayland/SDL_waylandvideo.c
···
49
49
#include "frog-color-management-v1-client-protocol.h"
50
50
#include "idle-inhibit-unstable-v1-client-protocol.h"
51
51
#include "input-timestamps-unstable-v1-client-protocol.h"
52
-
#include "kde-output-order-v1-client-protocol.h"
53
52
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
54
53
#include "pointer-constraints-unstable-v1-client-protocol.h"
55
54
#include "primary-selection-unstable-v1-client-protocol.h"
···
203
202
return false;
204
203
}
205
204
206
-
static void Wayland_FlushOutputOrder(SDL_VideoData *vid)
207
-
{
208
-
SDL_WaylandConnectorName *c, *tmp;
209
-
wl_list_for_each_safe (c, tmp, &vid->output_order, link) {
210
-
WAYLAND_wl_list_remove(&c->link);
211
-
SDL_free(c);
212
-
}
213
-
214
-
vid->output_order_finalized = false;
215
-
}
216
-
217
-
/* The order of wl_output displays exposed by KDE doesn't correspond to any priority, but KDE does provide a protocol
218
-
* that tells clients the preferred order or all connected displays via an ordered list of connector name strings.
219
-
*/
220
-
static void handle_kde_output_order_output(void *data, struct kde_output_order_v1 *kde_output_order_v1, const char *output_name)
221
-
{
222
-
SDL_VideoData *vid = (SDL_VideoData *)data;
223
-
224
-
// Starting a new list, flush the old.
225
-
if (vid->output_order_finalized) {
226
-
Wayland_FlushOutputOrder(vid);
227
-
}
228
-
229
-
const int len = SDL_strlen(output_name) + 1;
230
-
SDL_WaylandConnectorName *node = SDL_malloc(sizeof(SDL_WaylandConnectorName) + len);
231
-
SDL_strlcpy(node->wl_output_name, output_name, len);
232
-
233
-
WAYLAND_wl_list_insert(vid->output_order.prev, &node->link);
234
-
}
235
-
236
-
static void handle_kde_output_order_done(void *data, struct kde_output_order_v1 *kde_output_order_v1)
237
-
{
238
-
SDL_VideoData *vid = (SDL_VideoData *)data;
239
-
vid->output_order_finalized = true;
240
-
}
241
-
242
-
static const struct kde_output_order_v1_listener kde_output_order_listener = {
243
-
handle_kde_output_order_output,
244
-
handle_kde_output_order_done
245
-
};
246
-
247
205
// Sort the list of displays into a deterministic order
248
206
static int SDLCALL Wayland_DisplayPositionCompare(const void *a, const void *b)
249
207
{
···
350
308
return best_index;
351
309
}
352
310
353
-
static bool Wayland_SortOutputsByPriorityHint(SDL_VideoData *vid)
311
+
static void Wayland_SortOutputsByPriorityHint(SDL_VideoData *vid)
354
312
{
355
313
const char *name_hint = SDL_GetHint(SDL_HINT_VIDEO_DISPLAY_PRIORITY);
356
314
···
358
316
char *saveptr;
359
317
char *str = SDL_strdup(name_hint);
360
318
SDL_DisplayData **sorted_list = SDL_malloc(sizeof(SDL_DisplayData *) * vid->output_count);
361
-
int sorted_index = 0;
362
319
363
320
if (str && sorted_list) {
321
+
int sorted_index = 0;
322
+
364
323
// Sort the requested displays to the front of the list.
365
324
const char *token = SDL_strtok_r(str, ",", &saveptr);
366
325
while (token) {
···
389
348
390
349
SDL_free(str);
391
350
SDL_free(sorted_list);
392
-
393
-
return true;
394
351
}
395
-
396
-
return false;
397
352
}
398
353
399
354
static void Wayland_SortOutputs(SDL_VideoData *vid)
400
355
{
401
-
bool have_primary = false;
402
-
403
-
/* KDE provides the kde-output-order-v1 protocol, which gives us the full preferred display
404
-
* ordering in the form of a list of wl_output.name strings.
405
-
*/
406
-
if (!WAYLAND_wl_list_empty(&vid->output_order)) {
407
-
SDL_WaylandConnectorName *c;
408
-
SDL_DisplayData **sorted_list = SDL_malloc(sizeof(SDL_DisplayData *) * vid->output_count);
409
-
int sorted_index = 0;
410
-
411
-
if (sorted_list) {
412
-
// Sort the outputs by connector name.
413
-
wl_list_for_each (c, &vid->output_order, link) {
414
-
for (int i = 0; i < vid->output_count; ++i) {
415
-
SDL_DisplayData *d = vid->output_list[i];
416
-
if (d && d->wl_output_name && SDL_strcmp(c->wl_output_name, d->wl_output_name) == 0) {
417
-
sorted_list[sorted_index++] = d;
418
-
vid->output_list[i] = NULL;
419
-
break;
420
-
}
421
-
}
422
-
}
423
-
424
-
/* If any displays were omitted during the sort, append them to the new list.
425
-
* This shouldn't happen, but better safe than sorry.
426
-
*/
427
-
for (int i = 0; i < vid->output_count; ++i) {
428
-
if (vid->output_list[i]) {
429
-
sorted_list[sorted_index++] = vid->output_list[i];
430
-
}
431
-
}
432
-
433
-
// Copy the sorted list to the output list.
434
-
SDL_memcpy(vid->output_list, sorted_list, sizeof(SDL_DisplayData *) * vid->output_count);
435
-
SDL_free(sorted_list);
356
+
// Sort by position or connector name, so the order of outputs is deterministic.
357
+
SDL_qsort(vid->output_list, vid->output_count, sizeof(SDL_DisplayData *), Wayland_DisplayPositionCompare);
436
358
437
-
have_primary = true;
438
-
}
439
-
} else {
440
-
// Sort by position or connector name, so the order of outputs is deterministic.
441
-
SDL_qsort(vid->output_list, vid->output_count, sizeof(SDL_DisplayData *), Wayland_DisplayPositionCompare);
359
+
// Find a suitable primary display and move it to the front of the list.
360
+
const int primary_index = Wayland_GetPrimaryDisplay(vid);
361
+
if (primary_index) {
362
+
SDL_DisplayData *primary = vid->output_list[primary_index];
363
+
SDL_memmove(&vid->output_list[1], &vid->output_list[0], sizeof(SDL_DisplayData *) * primary_index);
364
+
vid->output_list[0] = primary;
442
365
}
443
366
444
-
// Apply the ordering hint if specified, otherwise, try to find the primary display, if no preferred order is known.
445
-
if (!Wayland_SortOutputsByPriorityHint(vid) && !have_primary) {
446
-
const int primary_index = Wayland_GetPrimaryDisplay(vid);
447
-
if (primary_index) {
448
-
SDL_DisplayData *primary = vid->output_list[primary_index];
449
-
SDL_memmove(&vid->output_list[1], &vid->output_list[0], sizeof(SDL_DisplayData *) * primary_index);
450
-
vid->output_list[0] = primary;
451
-
}
452
-
}
367
+
// Apply the ordering hint, if specified.
368
+
Wayland_SortOutputsByPriorityHint(vid);
453
369
}
454
370
455
371
static void display_handle_done(void *data, struct wl_output *output);
···
643
559
data->input = input;
644
560
data->display_externally_owned = display_is_external;
645
561
data->scale_to_display_enabled = SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY, false);
646
-
WAYLAND_wl_list_init(&data->output_order);
647
562
WAYLAND_wl_list_init(&external_window_list);
648
563
649
564
// Initialize all variables that we clean on shutdown
···
1353
1268
d->wp_alpha_modifier_v1 = wl_registry_bind(d->registry, id, &wp_alpha_modifier_v1_interface, 1);
1354
1269
} else if (SDL_strcmp(interface, "xdg_toplevel_icon_manager_v1") == 0) {
1355
1270
d->xdg_toplevel_icon_manager_v1 = wl_registry_bind(d->registry, id, &xdg_toplevel_icon_manager_v1_interface, 1);
1356
-
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
1357
-
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
1358
-
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
1359
1271
} else if (SDL_strcmp(interface, "frog_color_management_factory_v1") == 0) {
1360
1272
d->frog_color_management_factory_v1 = wl_registry_bind(d->registry, id, &frog_color_management_factory_v1_interface, 1);
1361
1273
}
···
1632
1544
if (data->xdg_toplevel_icon_manager_v1) {
1633
1545
xdg_toplevel_icon_manager_v1_destroy(data->xdg_toplevel_icon_manager_v1);
1634
1546
data->xdg_toplevel_icon_manager_v1 = NULL;
1635
-
}
1636
-
1637
-
if (data->kde_output_order) {
1638
-
Wayland_FlushOutputOrder(data);
1639
-
kde_output_order_v1_destroy(data->kde_output_order);
1640
-
data->kde_output_order = NULL;
1641
1547
}
1642
1548
1643
1549
if (data->frog_color_management_factory_v1) {
-3
src/video/wayland/SDL_waylandvideo.h
-3
src/video/wayland/SDL_waylandvideo.h
-33
wayland-protocols/kde-output-order-v1.xml
-33
wayland-protocols/kde-output-order-v1.xml
···
1
-
<?xml version="1.0" encoding="UTF-8"?>
2
-
<protocol name="kde_output_order_v1">
3
-
<copyright><![CDATA[
4
-
SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
5
-
6
-
SPDX-License-Identifier: MIT-CMU
7
-
]]></copyright>
8
-
9
-
<interface name="kde_output_order_v1" version="1">
10
-
<description summary="announce order of outputs">
11
-
Announce the order in which desktop environment components should be placed on outputs.
12
-
The compositor will send the list of outputs when the global is bound and whenever there is a change.
13
-
</description>
14
-
15
-
<event name="output">
16
-
<description summary="output name">
17
-
Specifies the output identified by their wl_output.name.
18
-
</description>
19
-
<arg name="output_name" type="string" summary="the name of the output"/>
20
-
</event>
21
-
22
-
<event name="done">
23
-
<description summary="done">
24
-
Specifies that the output list is complete. On the next output event, a new list begins.
25
-
</description>
26
-
</event>
27
-
28
-
<request name="destroy" type="destructor">
29
-
<description summary="Destroy the output order notifier."/>
30
-
</request>
31
-
</interface>
32
-
33
-
</protocol>