Skip to content

[WIP] [X11] Port from libwnck to libxfce4windowing - #1585

Draft
Sunderland93 wants to merge 14 commits into
mate-desktop:masterfrom
Sunderland93:backend_refactor
Draft

Sunderland93 wants to merge 14 commits into
mate-desktop:masterfrom
Sunderland93:backend_refactor

Conversation

@Sunderland93

Copy link
Copy Markdown
Contributor

We already use libxfce4windowing for Wayland backend, but this library also supports X11, as it uses libwnck under the hood. So, instead of maintaining two codebases for two backends, we can maintain a single, unified one. This way, both backends will work identically, have a common structure, and a single source of bugs. All backend-agnostic code is moved into separate structures, making the codebase overall cleaner and easier to maintain, and significantly simplifying the addition of features like this #1535

Needs a lot of testing, so WIP for now

This also removes a disconnect call that was placed outside X11
guard and broke builds with X11 support disabled
Window selector backend already only talked to libxfce4windowing
and therefore works on X11 as well
workspace-switcher.h was only included inside HAVE_X11 block,
leaving workspace_switcherapplet_fill undeclared when building
without X11
@Sunderland93
Sunderland93 marked this pull request as draft October 2, 2026 17:30
@lukefromdc

Copy link
Copy Markdown
Member

Got this segfault after a few minutes runtime under wayland (current session):

** (mate-panel:103584): CRITICAL **: 16:56:36.868: IA__xfw_window_x11_get_xid: assertion 'XFW_IS_WINDOW_X11(window)' failed
Segmentation fault         mate-panel --replace

@lukefromdc

Copy link
Copy Markdown
Member

Got this backtrace from the segfault under wayland:


Reading symbols from mate-panel...
(gdb) run
Starting program: /usr/bin/mate-panel 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff59ff6c0 (LWP 104321) (id 2)]
[New Thread 0x7ffff51fe6c0 (LWP 104322) (id 3)]
[New Thread 0x7ffff49fd6c0 (LWP 104323) (id 4)]
[New Thread 0x7fffe7fff6c0 (LWP 104324) (id 5)]
[New Thread 0x7fffe77fe6c0 (LWP 104325) (id 6)]
[New Thread 0x7fffe6ffd6c0 (LWP 104326) (id 7)]
** Message: 16:57:43.003: Window<->Workspace association is not available on your compositor
[New Thread 0x7fffd5f516c0 (LWP 104349) (id 8)]
[New Thread 0x7fffd56de6c0 (LWP 104351) (id 9)]

** (mate-panel:104318): CRITICAL **: 16:57:45.069: IA__xfw_window_x11_get_xid: assertion 'XFW_IS_WINDOW_X11(window)' failed

Thread 1 "mate-panel" received signal SIGSEGV, Segmentation fault.
0x00007ffff6eff7ae in _XGetRequest ()
   from /usr/lib/x86_64-linux-gnu/libX11.so.6
(gdb) thread apply all bt full

Thread 9 (Thread 0x7fffd56de6c0 (LWP 104351) "cal-client-dbus"):
#0  __syscall_cancel_arch () at ../sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S:56
#1  0x00007ffff6d089d4 in __internal_syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:49
        result = <optimized out>
        pd = <optimized out>
        ch = <optimized out>
#2  0x00007ffff6d08a1d in __syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:75
        r = <optimized out>
#3  0x00007ffff6d7d45e in __GI_ppoll (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>, sigmask=<optimized out>) at ../sysdeps/unix/sysv/linux/ppoll.c:42
        tval = {tv_sec = 93824998683616, tv_nsec = 140737488345344}
#4  0x00007ffff7e8f47e in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff7e90047 in g_main_loop_run () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007fffe62559c7 in ??? () at /usr/lib/x86_64-linux-gnu/libecal-2.0.so.3
#7  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
--Type <RET> for more, q to quit, c to continue without paging--c
#8  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140736774137536, 1154556802855172029, 140737488345344, 140737488345590, 0, 140736765747200, -1154498684271888451, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#9  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 8 (Thread 0x7fffd5f516c0 (LWP 104349) "mate-panel"):
#0  __syscall_cancel_arch () at ../sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S:56
#1  0x00007ffff6d089d4 in __internal_syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:49
        result = <optimized out>
        pd = <optimized out>
        ch = <optimized out>
#2  0x00007ffff6d08a1d in __syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:75
        r = <optimized out>
#3  0x00007ffff6d7d45e in __GI_ppoll (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>, sigmask=<optimized out>) at ../sysdeps/unix/sysv/linux/ppoll.c:42
        tval = {tv_sec = 93824999047136, tv_nsec = 3069}
#4  0x00007ffff7e8f47e in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff7e90047 in g_main_loop_run () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007fffe615804e in ??? () at /usr/lib/x86_64-linux-gnu/libedataserver-1.2.so.27
#7  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#8  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140736782997184, 1154556802855172029, 140737488344928, 140737488345174, 11, 140736774606848, -1154499709158459459, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#9  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 7 (Thread 0x7fffe6ffd6c0 (LWP 104326) "[pango] fontcon"):
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ffff7ec4712 in g_cond_wait () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#2  0x00007ffff7e5005c in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#3  0x00007ffff7e50573 in g_async_queue_pop () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#4  0x00007ffff6805977 in ??? () at /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0
#5  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737068914368, 1154556802855172029, 140737488342640, 140737488342886, 0, 140737060524032, -1154607381841086531, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#7  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 6 (Thread 0x7fffe77fe6c0 (LWP 104325) "dconf worker"):
#0  __syscall_cancel_arch () at ../sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S:56
#1  0x00007ffff6d089d4 in __internal_syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:49
        result = <optimized out>
        pd = <optimized out>
        ch = <optimized out>
#2  0x00007ffff6d08a1d in __syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:75
        r = <optimized out>
#3  0x00007ffff6d7d45e in __GI_ppoll (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>, sigmask=<optimized out>) at ../sysdeps/unix/sysv/linux/ppoll.c:42
        tval = {tv_sec = 93824993237616, tv_nsec = 140737488346176}
#4  0x00007ffff7e8f47e in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff7e8fd20 in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007ffff7fb300d in ??? () at /usr/lib/x86_64-linux-gnu/gio/modules/libdconfsettings.so
#7  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#8  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737077307072, 1154556802855172029, 140737488346176, 140737488346422, 17, 140737068916736, -1154608480815843395, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#9  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 5 (Thread 0x7fffe7fff6c0 (LWP 104324) "gdbus"):
#0  __syscall_cancel_arch () at ../sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S:56
#1  0x00007ffff6d089d4 in __internal_syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:49
        result = <optimized out>
        pd = <optimized out>
        ch = <optimized out>
#2  0x00007ffff6d08a1d in __syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:75
        r = <optimized out>
#3  0x00007ffff6d7d45e in __GI_ppoll (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>, sigmask=<optimized out>) at ../sysdeps/unix/sysv/linux/ppoll.c:42
        tval = {tv_sec = 140737152834112, tv_nsec = 140737297499808}
#4  0x00007ffff7e8f47e in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff7e90047 in g_main_loop_run () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007ffff713dfba in ??? () at /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#7  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#8  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737085699776, 1154556802855172029, 140737297499808, 140737297500054, 11, 140737077309440, -1154609579790600259, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#9  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 4 (Thread 0x7ffff49fd6c0 (LWP 104323) "pool-0"):
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ffff7ec4bf1 in g_cond_wait_until () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#2  0x00007ffff7e5001d in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#3  0x00007ffff7e506e5 in g_async_queue_timeout_pop () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#4  0x00007ffff7ec5650 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737297503936, 1154556802855172029, 140737314285504, 140737314285750, 0, 140737289113600, -1154568074300393539, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#7  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 3 (Thread 0x7ffff51fe6c0 (LWP 104322) "gmain"):
#0  __syscall_cancel_arch () at ../sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S:56
#1  0x00007ffff6d089d4 in __internal_syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:49
        result = <optimized out>
        pd = <optimized out>
        ch = <optimized out>
#2  0x00007ffff6d08a1d in __syscall_cancel (a1=<optimized out>, a2=<optimized out>, a3=<optimized out>, a4=<optimized out>, a5=a5@entry=8, a6=a6@entry=0, nr=271) at ./nptl/cancellation.c:75
        r = <optimized out>
#3  0x00007ffff6d7d45e in __GI_ppoll (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>, sigmask=<optimized out>) at ../sysdeps/unix/sysv/linux/ppoll.c:42
        tval = {tv_sec = 93824993144256, tv_nsec = 140737488347056}
#4  0x00007ffff7e8f47e in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff7e8fd20 in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6  0x00007ffff7e8fd71 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#7  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#8  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737305896640, 1154556802855172029, 140737488347056, 140737488347302, 2, 140737297506304, -1154569173275150403, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#9  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 2 (Thread 0x7ffff59ff6c0 (LWP 104321) "pool-spawner"):
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ffff7ec4712 in g_cond_wait () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#2  0x00007ffff7e5005c in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#3  0x00007ffff7ec51c6 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#4  0x00007ffff7ec4ea0 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5  0x00007ffff6d0bdb8 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:454
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737314289344, 1154556802855172029, 140737488347264, 140737488347510, 2, 140737305899008, -1154570272249907267, -1154571961812944963}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
        prevstate = <optimized out>
#6  0x00007ffff6d89f58 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 1 (Thread 0x7ffff5f65b40 (LWP 104318) "mate-panel"):
#0  0x00007ffff6eff7ae in _XGetRequest () at /usr/lib/x86_64-linux-gnu/libX11.so.6
#1  0x00007ffff6ef2912 in XQueryTree () at /usr/lib/x86_64-linux-gnu/libX11.so.6
#2  0x00007fffe6437cea in preview_window_thumbnail (window_handle=0x55555568d190, tasklist=0x5555556a8d30, thumbnail_width=0x7fffffffda0c, thumbnail_height=0x7fffffffda08, thumbnail_scale=0x7fffffffda04) at ../applets/wncklet/window-list.c:221
        window = 0x7fffe6441e4f <wayland_window_is_on_active_workspace+24>
        display = 0x55555562c530
        xdpy = 0x55555562e610
        win = 0
        frame = 0
        parent = 93824996427120
        root = 140737488345456
        children = 0x1
        nchildren = 21845
        thumbnail = 0x555555e84800
        cr = 0x0
        ratio = 4.6355706293814819e-310
        width = 0
        height = 0
        scale = 0
        src_x = 0
        src_y = 0
        pixbuf = 0x0
#3  0x00007fffe643893a in applet_enter_notify_event (tl=0x555555789480, windows=0x555555c85de0 = {...}, tasklist=0x5555556a8d30) at ../applets/wncklet/window-list.c:532
        thumbnail = 0x7fffffffde00
        window = 0x55555568d190
        n_windows = 1
        thumbnail_width = 32767
        thumbnail_height = -136536784
        thumbnail_scale = 32767
#4  0x00007ffff7db022f in g_cclosure_marshal_VOID__POINTERv () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#5  0x00007ffff7dac529 in ??? () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#6  0x00007ffff7dc48e6 in ??? () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#7  0x00007ffff7dc9d08 in g_signal_emit_valist () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#8  0x00007ffff7dc9dc3 in g_signal_emit () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#9  0x00007fffe643546a in tasklist_emit_hover_notify (button=0x555555a3bd60, tasklist=0x555555a18d80, signal_id=313) at ../applets/wncklet/tasklist-core.c:1441
        group = 0x0
        task = 0x555555a3bb80
        windows = 0x555555c85de0 = {0x55555568d190}
#10 0x00007fffe64354aa in on_toplevel_button_enter_notify (button=0x555555a3bd60, event=0x555555cd36e0, tasklist=0x555555a18d80) at ../applets/wncklet/tasklist-core.c:1449
#11 0x00007ffff7499b7b in ??? () at /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#12 0x00007ffff7dac203 in g_closure_invoke () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#13 0x00007ffff7dc2c69 in ??? () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#14 0x00007ffff7dc4104 in ??? () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#15 0x00007ffff7dc9d08 in g_signal_emit_valist () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#16 0x00007ffff7dc9dc3 in g_signal_emit () at /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#17 0x00007ffff773ab7c in ??? () at /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#18 0x00007ffff75f9f86 in gtk_main_do_event () at /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#19 0x00007ffff7c52465 in ??? () at /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
#20 0x00007ffff7c86592 in ??? () at /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
#21 0x00007ffff7e8bcb7 in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#22 0x00007ffff7e8f42f in ??? () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#23 0x00007ffff7e90047 in g_main_loop_run () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#24 0x00007ffff75f9155 in gtk_main () at /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#25 0x0000555555579350 in main (argc=1, argv=0x7fffffffe818) at ../mate-panel/main.c:223
        desktopfile = 0x5555556224c0 "P"
        context = 0x5555556237d0
        error = 0x0
        display = 0x55555562c530
        screen = 0x55555562e610
        css = 0x5555558a3a20
        provider = 0x5555558a3a20
        resource = 0x5555555ed7a8 "/org/mate/panel/theme/mate-panel.css"
        priority = 1
(gdb) 

@Sunderland93

Copy link
Copy Markdown
Contributor Author

Fixed

@lukefromdc

lukefromdc commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

This now works fine in both x11 and wayland. Forgot to test previews while in the x11 session however.

Note that the handling of very large numbers of open windows is somewhat different that what people may have come to expect on x11 and is the same as on wayland here.

It is possible to get a rendering issue where the window list overflows onto other applets in some edge cases like changing window scaling with a crowded window list at certain numbers of open windows, or with certain applications that somehow seem to set a miniumum button width in the window list such as avidemux. This would be guaranteed to generate bug reports on x11 wheras new issues on wayland are more expected. libwnck never, ever does this but in the past few years has had nasty issues in some versions with narrow switcher rectangle rendering.

@Sunderland93

Copy link
Copy Markdown
Contributor Author

It is possible to get a rendering issue where the window list overflows onto other applets in some edge cases like changing window scaling with a crowded window list at certain numbers of open windows, or with certain applications that somehow seem to set a miniumum button width in the window list such as avidemux.

Latest commit should address this issue, but I didn't testing it yet

@lukefromdc

lukefromdc commented Oct 4, 2026 via email

Copy link
Copy Markdown
Member

@Sunderland93

Copy link
Copy Markdown
Contributor Author

I can't reproduce issue with avidemux (probably I did it wrong), but latest commit should allow tasklist to correctly resize buttons to the width actually allocated

@lukefromdc

lukefromdc commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

I still got the same issue with avidemux but was just able to prove the problem is avidemux forcing a giant oversize icon into the tasklist button. The application name doesn't even fully show, just a cut-off stripe of a giant icon. This causes GTK to force up the button size until the icon gets hidden.

Tasklist_w_Avidemux

With this or the immediately previous version the tasklist gets cut off on the right and thankfully no longer crowds other applets off the panel when avidemux is running.

The fix would be to force the icon size to the intended size

@lukefromdc

lukefromdc commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Getting there. The tasklist buttons now shrink to fit even when avidemux is open, but all icons are now oversize and slightly blurry.

Tasklist_10-6-2026

Note that this is in wayland with scaling at 2 in the compositor, so it may be a double scaling problem in wayland. If scaling is set to 1.0 they are the correct size. In both cases they are a bit blurry

@lukefromdc

Copy link
Copy Markdown
Member

Note that avidemux only ships a 128x128 icon, this is a QT app written possibly without testing the icon in GTK based panels

@lukefromdc

Copy link
Copy Markdown
Member

Turns out there is a much simpler way to do this, using gtk_image_set_pixel_size() to force the icon to render at the intended size. This can be done simply to force GTK_ICON_SIZE_MENU as in the diff below from the last commit, but we then need to detect the panel height and set the icon size both when we load and when we render the icon to the largest standard icon size that will fit in the panel.

Any time we are forcing GTK_ICON_SIZE_MENU the tasklist icons will stay at 16x16 no matter how wide the user sets the panel height(on a horizonal panel)

Anyway, this diff reverts the last commit and adds just 3 lines of code, only supporting GTK_ICON_SIZE_MENU for now. It does render all icons sharp and all the same size.


--- /home/luke/Desktop/tasklist-core.c	2026-10-06 03:08:21.554050872 -0400
+++ /home/luke/Desktop/Development/MATE_Development_Work/mate-panel_1.29.0+xfce-x11-20261002/applets/wncklet/tasklist-core.c	2026-10-06 03:17:21.826063142 -0400
@@ -373,59 +373,6 @@ adjust_buttons (TasklistManager *tasklis
 	return;
 }
 
-static void
-tasklist_set_image_icon (GtkImage *image, GIcon *icon, const gchar *fallback_name)
-{
-	GtkIconTheme *theme;
-	GtkIconInfo *info;
-	GdkPixbuf *pixbuf;
-	gint scale, want;
-
-	if (image == NULL)
-		return;
-
-	scale = gtk_widget_get_scale_factor (GTK_WIDGET (image));
-	if (scale < 1)
-		scale = 1;
-
-	want = icon_size * scale;
-	pixbuf = NULL;
-
-	if (icon != NULL)
-	{
-		theme = gtk_icon_theme_get_default ();
-		info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, icon_size,
-								scale,
-								GTK_ICON_LOOKUP_FORCE_SIZE);
-		if (info != NULL)
-		{
-			pixbuf = gtk_icon_info_load_icon (info, NULL);
-			g_object_unref (info);
-		}
-	}
-
-	/* Only shrink. Enlarging would just blur the icon, and it cannot make
-	 * the button any wider than the bounded size we hand over below. */
-	if (pixbuf != NULL
-	    && (gdk_pixbuf_get_width (pixbuf) > want || gdk_pixbuf_get_height (pixbuf) > want))
-	{
-		GdkPixbuf *scaled;
-
-		scaled = gdk_pixbuf_scale_simple (pixbuf, want, want, GDK_INTERP_BILINEAR);
-		if (scaled != NULL)
-		{
-			g_object_unref (pixbuf);
-			pixbuf = scaled;
-		}
-	}
-
-	if (pixbuf != NULL)
-		gtk_image_set_from_pixbuf (image, pixbuf);
-	else
-		gtk_image_set_from_icon_name (image, fallback_name, GTK_ICON_SIZE_MENU);
-
-	g_clear_object (&pixbuf);
-}
 
 static void
 update_task_icon (ToplevelTask *task)
@@ -433,6 +380,7 @@ update_task_icon (ToplevelTask *task)
 	const TasklistBackend *backend;
 	GIcon *icon = NULL;
 	gpointer app;
+	gint width;
 
 	if (!task || !task->window || !task->icon)
 		return;
@@ -445,8 +393,15 @@ update_task_icon (ToplevelTask *task)
 	if (icon == NULL)
 		icon = backend->get_window_gicon (task->window);
 
-	tasklist_set_image_icon (GTK_IMAGE (task->icon), icon,
-				 backend->get_fallback_icon_name ());
+	if (icon != NULL)
+		gtk_image_set_from_gicon (GTK_IMAGE (task->icon), icon, GTK_ICON_SIZE_MENU);
+	else
+		gtk_image_set_from_icon_name (GTK_IMAGE (task->icon),
+					      backend->get_fallback_icon_name (),
+					      GTK_ICON_SIZE_MENU);
+
+	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, NULL);
+	gtk_image_set_pixel_size (GTK_IMAGE (task->icon), width);
 }
 
 static GIcon *
@@ -537,9 +492,12 @@ group_task_update_icon (GroupTask *group
 		return;
 
 	icon = group->tasklist->backend->get_app_gicon (group->app);
-
-	tasklist_set_image_icon (GTK_IMAGE (group->icon), icon,
-				 group->tasklist->backend->get_fallback_icon_name ());
+	if (icon != NULL)
+		gtk_image_set_from_gicon (GTK_IMAGE (group->icon), icon, GTK_ICON_SIZE_MENU);
+	else
+		gtk_image_set_from_icon_name (GTK_IMAGE (group->icon),
+					      group->tasklist->backend->get_fallback_icon_name (),
+					      GTK_ICON_SIZE_MENU);
 }
 
 static gboolean
@@ -851,10 +809,13 @@ group_task_menu_show (GroupTask *group,
 		item = gtk_menu_item_new ();
 		box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
 		icon = gtk_image_new ();
-		gtk_widget_set_size_request (icon, icon_size, icon_size);
 		gicon = window_gicon (group->tasklist, task->window);
-		tasklist_set_image_icon (GTK_IMAGE (icon), gicon,
-					 backend->get_fallback_icon_name ());
+		if (gicon != NULL)
+			gtk_image_set_from_gicon (GTK_IMAGE (icon), gicon, GTK_ICON_SIZE_MENU);
+		else
+			gtk_image_set_from_icon_name (GTK_IMAGE (icon),
+						      backend->get_fallback_icon_name (),
+						      GTK_ICON_SIZE_MENU);
 
 		label = gtk_label_new (backend->get_window_name (task->window));
 		gtk_label_set_xalign (GTK_LABEL (label), 0.0);
@@ -935,8 +896,8 @@ group_task_new (TasklistManager *tasklis
 
 	group->button = gtk_button_new ();
 	group->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-	group->icon = gtk_image_new ();
-	gtk_widget_set_size_request (group->icon, icon_size, icon_size);
+	group->icon = gtk_image_new_from_icon_name (tasklist->backend->get_fallback_icon_name (),
+						    icon_size);
 	group->label = gtk_label_new ("");
 	group->counter_label = gtk_label_new ("");
 
@@ -1712,8 +1673,7 @@ toplevel_task_new (TasklistManager *task
 	task->button = gtk_button_new ();
 	g_signal_connect (task->button, "clicked", G_CALLBACK (toplevel_task_handle_clicked), task);
 
-	task->icon = gtk_image_new ();
-	gtk_widget_set_size_request (task->icon, icon_size, icon_size);
+	task->icon = gtk_image_new_from_icon_name (backend->get_fallback_icon_name (), icon_size);
 
 	task->label = gtk_label_new ("");
 	gtk_label_set_max_width_chars (GTK_LABEL (task->label), TASKLIST_TEXT_MAX_WIDTH);

@lukefromdc

Copy link
Copy Markdown
Member

From the PREVIOUS commit 7e1015a this diff is much easier to understand:

--- /home/luke/Desktop/tasklist-core-Previous_Commit.c	2026-10-06 03:27:25.478076850 -0400
+++ /home/luke/Desktop/Development/MATE_Development_Work/mate-panel_1.29.0+xfce-x11-20261002/applets/wncklet/tasklist-core.c	2026-10-06 03:17:21.826063142 -0400
@@ -380,6 +380,7 @@ update_task_icon (ToplevelTask *task)
	const TasklistBackend *backend;
	GIcon *icon = NULL;
	gpointer app;
+	gint width;

	if (!task || !task->window || !task->icon)
		return;
@@ -398,6 +399,9 @@ update_task_icon (ToplevelTask *task)
		gtk_image_set_from_icon_name (GTK_IMAGE (task->icon),
					      backend->get_fallback_icon_name (),
					      GTK_ICON_SIZE_MENU);
+
+	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, NULL);
+	gtk_image_set_pixel_size (GTK_IMAGE (task->icon), width);
}

static GIcon *

@lukefromdc

Copy link
Copy Markdown
Member

Got this result:
tasklist-latest

@lukefromdc

lukefromdc commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

I just did some comparison testing of my diff applied to the next to last commit to git master. Turns out in master we already have all of the original rendering issues (too large icons when only oversize icons shipped and these icons making the window list overflow onto other applets) with avidemux and its 128x128 icon.

I also tested again in x11, behavior same as in wayland and icon size was correct (for GTK_ICON_SIZE MENU anyway) both with 1x and 2x window scaling.

Thus this was never worse in wayland than the current git master but of course ported those issues over to the x11 panel. From what we have now with my diff we just need to get the space available in terms of panel height on a horizontal panel/width on a vertical panel, select the icon from the largest folder that fits right, both load and force that size, and this will be ready.

The only remaining difference from the x11 panel will be subtle differences in when exactly icons or labels get hidden, and duplicating the exact behavior of libwnck to avoid bug reports over that sort of thing is probably impractical.

f9a329f scaled the icon to a fixed pixel size itself and handed GtkImage
the resulting pixbuf. That bounded the button, but GtkImage reports a
pixbuf's own pixel width as its logical width, so at a 2x scale the icon
came out twice the size it should have been, and every icon was a little
soft from the resample we did rather than the theme's.

Pin the size on the GtkImage instead and leave the lookup to GTK. A pixel
size is authoritative over the icon size, and having one set also makes
the lookup pass GTK_ICON_LOOKUP_FORCE_SIZE, so the theme scales the icon
to exactly that size. The widget's size then comes from the pixel size
rather than from the surface the theme returned, which is what stops an
application that only ships a 128x128 icon dragging the button's minimum
width up with it and pushing the tasklist off the panel.

Apply the same to the group button and the group context menu, which were
still sizing themselves from whatever the icon theme handed back.

The two image constructors passed the pixel constant icon_size (16) as a
GtkIconSize, whose range is 0 to 6, so the value was out of range. Ask
for GTK_ICON_SIZE_MENU instead.
@lukefromdc

lukefromdc commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

This works and we get sharp icons that scale with the panel including from avidemux now. We are selecting them one size too large however, they do fit but often with zero padding. This is an issue mostly because it looks different and people would want the old smaller icons back. At those panel sizes where padding is zero this can get a bit ugly

Tasklist_24px-NoPadding

These larger icons also cause the panel to crowd earlier than expected.

We also have an issue not present in master even in wayland with handling a very crowded tasklist when not even elipsized text can be shown. Rather than trying to use as much of the panel space as possible as in master, as windows are added beyond the limit for showing even labels the button width drops in two steps to near-zero, then some are not rendered and others are shown with contents again, sometimes as few as ten of them.

Panel with 40 windows open as this PR now stands on my panel, yours may differ due to available space:

Tasklist_40-windows-open

Panel with 40 windows open on master:

Tasklist_40-windows-master

@lukefromdc

Copy link
Copy Markdown
Member

We also have several issues with window grouping that this will presumably bring to the x11 session given identical x11 and wayland behavior:

1: If window grouping is turned on on an uncrowded panel and the panel becomes crowded, sometimes part of the last button gets cut off

2: Not all buttons that should be in a group(being from the same app) get included in that group, some remain separate

3: If window grouping is turned on while the panel is crowded, the icon is only shown in the buttons for grouped windows and not for solo windows of other apps

@lukefromdc

lukefromdc commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

In tasklist-core.c in tasklist_icon_available_space()
Looks like reading the expected padding value with gtk_style_context_get_padding (context, state, &padding); is always returning zero, verified this in menta to ensure this wasn't a theme issue.

I added gtk_style_context_get_padding (context, state, &padding.top); for testing purposes to show that value when running the panel from terminal. Also note that it is not re-run when changing GTK themes

Catching this zero case with


/* Ensure that window list buttons never touch the panel edges*/
static const int min_button_padding = 2;

at the top of the file and using it with the code below in tasklist_icon_available_space()


if(padding.top >= 0)
	padding.top = min_button_padding;

	if(padding.bottom >= 0)
		padding.bottom = min_button_padding;

	if(padding.left >= 0)
		padding.left = min_button_padding;

	if(padding.right >= 0)
		padding.right = min_button_padding;

solved the problem, a theme that sets a padding of 1px or more overrides it if the padding value is readable. A minimum padding value of 1px leads to oversize icons again at some panel sizes, while a 2px minimum seems to give behavior very similar to master in x11 so far as icon size is concerned.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants