Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window with em-dash in title causes missing focus_changed hook (xconnection.cpp: 347: Can not create text list) #1534

Open
The-Compiler opened this issue Nov 25, 2022 · 2 comments

Comments

@The-Compiler
Copy link
Member

On v0.9.5 (or current git master, 5cc2914), with a reproducer such as:

from PyQt5.QtWidgets import QApplication, QWidget
app = QApplication([])
w = QWidget()
w.setWindowTitle("—x")
w.show()
app.exec()

When focusing the window, no focus_changed hook is shown with hc --idle. After a hc watch clients.focus.title and hc watch clients.focus.winid, the winid one is reported, but the title one is also missing for that window.

Running hlwm with --verbose shows:

../../src/xconnection.cpp: 347: Can not create text list

from here:

int status = Xutf8TextListToTextProperty(
m_display, (char**) value_c_str.data(), value_c_str.size(),
XUTF8StringStyle, &text_prop);
if (status != Success) {
// maybe no locale support.
status = XmbTextListToTextProperty(
m_display, (char**) value_c_str.data(), value_c_str.size(),
XStdICCTextStyle, &text_prop);
}
if (status != Success) {
HSDebug("Can not create text list\n");
return;
}

I've tried stepping into Xutf8TextListToTextProperty to understand what's going on, but I have no idea what I'm seeing exactly.

The input data looks as it should:

(gdb) p value
$1 = std::vector of length 3, capacity 3 = {"focus_changed", "0x400006", "—x"}
(gdb) p value_c_str
$2 = std::vector of length 3, capacity 3 = {0x55555589f140 "focus_changed", 0x55555589f160 "0x400006", 0x55555589f180 "—x"}

Also note that when using only (no x), the hook is emitted fine, just without any arguments. Similarly, with things like hc echo "x—x", the dash is just dropped (it echos xx instead).

But when coming from a window title, and being >1 character, it looks like Xutf8TextListToTextProperty returns 1, because the underlying _XTextListToTextProperty gets 1 as unconv_num.

Stack:

#0  _XTextListToTextProperty (lcd=0x555555743180, dpy=0x55555575b260, from_type=from_type@entry=0x7ffff7e19b43 "utf8String", list=0x55555589b7e0 "\220ˋUUU", count=3, style=XUTF8StringStyle, text_prop=0x7fffffffc070) at xlibi18n/lcTxtPr.c:182
#1  0x00007ffff7db535f in _Xutf8TextListToTextProperty (lcd=<optimized out>, dpy=<optimized out>, list=<optimized out>, count=<optimized out>, style=<optimized out>, text_prop=<optimized out>) at xlibi18n/lcTxtPr.c:252
#2  0x00005555556ba337 in XConnection::setPropertyString (this=this@entry=0x555555757920, w=2097155, property=293, value=std::vector of length 3, capacity 3 = {...}) at ../../src/xconnection.cpp:337
#3  0x0000555555613605 in IpcServer::emitHook (this=this@entry=0x55555576f260, args=std::vector of length 3, capacity 3 = {...}) at ../../src/ipc-server.cpp:104
#4  0x00005555556124eb in hook_emit (args=std::vector of length 3, capacity 3 = {...}) at ../../src/hook.cpp:15
#5  0x00005555555b1512 in ClientManager::focusedClientChanges (this=<optimized out>, newFocus=0x555555893be0) at ../../src/clientmanager.cpp:548
#6  0x00005555555b265d in std::__invoke_impl<void, void (ClientManager::*&)(Client*), ClientManager*&, Client*> (__t=<optimized out>, __f=<optimized out>) at /usr/include/c++/12.2.0/bits/invoke.h:74
#7  std::__invoke<void (ClientManager::*&)(Client*), ClientManager*&, Client*> (__fn=<optimized out>) at /usr/include/c++/12.2.0/bits/invoke.h:96
#8  std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)>::__call<void, Client*&&, 0ul, 1ul>(std::tuple<Client*&&>&&, std::_Index_tuple<0ul, 1ul>) (__args=..., this=<optimized out>) at /usr/include/c++/12.2.0/functional:484
#9  std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)>::operator()<Client*, void>(Client*&&) (this=<optimized out>) at /usr/include/c++/12.2.0/functional:567
#10 std::__invoke_impl<void, std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)>&, Client*>(std::__invoke_other, std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)>&, Client*&&) (__f=...) at /usr/include/c++/12.2.0/bits/invoke.h:61
#11 std::__invoke_r<void, std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)>&, Client*>(std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)>&, Client*&&) (__fn=...) at /usr/include/c++/12.2.0/bits/invoke.h:154
#12 std::_Function_handler<void (Client*), std::_Bind<void (ClientManager::*(ClientManager*, std::_Placeholder<1>))(Client*)> >::_M_invoke(std::_Any_data const&, Client*&&) (__functor=..., __args#0=<optimized out>) at /usr/include/c++/12.2.0/bits/std_function.h:290
#13 0x000055555563aace in std::function<void (Client*)>::operator()(Client*) const (__args#0=<optimized out>, this=0x55555586a880) at /usr/include/c++/12.2.0/bits/std_function.h:591
#14 Signal_<Client*>::emit (data=<synthetic pointer>: 0x555555893be0, this=<optimized out>) at ../../src/signal.h:68
#15 Link_<Client>::operator= (new_value=0x555555893be0, this=<optimized out>) at ../../src/link.h:30
#16 Monitor::applyLayout (this=0x555555893250) at ../../src/monitor.cpp:275
#17 0x0000555555641c9c in MonitorManager::lock_number_changed (this=<optimized out>) at ../../src/monitormanager.cpp:494
#18 0x0000555555673eb4 in operator() (__closure=<optimized out>) at ../../src/settings.cpp:440
#19 std::__invoke_impl<void, Settings::injectDependencies(Root*)::<lambda(bool)>&, long unsigned int> (__f=...) at /usr/include/c++/12.2.0/bits/invoke.h:61
#20 std::__invoke_r<void, Settings::injectDependencies(Root*)::<lambda(bool)>&, long unsigned int> (__fn=...) at /usr/include/c++/12.2.0/bits/invoke.h:154
#21 std::_Function_handler<void(long unsigned int), Settings::injectDependencies(Root*)::<lambda(bool)> >::_M_invoke(const std::_Any_data &, unsigned long &&) (__functor=..., __args#0=<optimized out>) at /usr/include/c++/12.2.0/bits/std_function.h:290
#22 0x0000555555641c31 in std::function<void (unsigned long)>::operator()(unsigned long) const (__args#0=<optimized out>, this=0x5555558730e0) at /usr/include/c++/12.2.0/bits/std_function.h:591
#23 Signal_<unsigned long>::emit (data=<optimized out>, this=<optimized out>) at ../../src/signal.h:68
#24 Attribute_<unsigned long>::operator= (payload=<optimized out>, this=<optimized out>) at ../../src/attribute_.h:141
#25 MonitorManager::unlock (this=<optimized out>) at ../../src/monitormanager.cpp:485
#26 0x000055555561b361 in focus_client (client=client@entry=0x555555893be0, switch_tag=switch_tag@entry=false, switch_monitor=switch_monitor@entry=true, raise=<optimized out>) at ../../src/layout.cpp:860
#27 0x00005555556bf4ad in XMainLoop::buttonpress (this=0x7fffffffc770, be=0x7fffffffc530) at ../../src/xmainloop.cpp:294
#28 0x00005555556be9c4 in XMainLoop::run (this=this@entry=0x7fffffffc770) at ../../src/xmainloop.cpp:209
#29 0x000055555557c69e in main (argc=<optimized out>, argv=0x7fffffffcb68) at ../../src/main.cpp:449

The manpage for that function says:

If the supplied text is not fully convertible to the specified encoding, the functions
return the number of unconvertible characters. Each unconvertible character is converted
to an implementation-defined and encoding-specific default string. Otherwise, the
functions return Success. Note that full convertibility to all styles except XStringStyle
is guaranteed.

So maybe the check for Success is actually a bit too strict there? Not sure if there is a more proper solution, though.

@Wasja7
Copy link

Wasja7 commented Nov 29, 2022

For anybody who looks for a workaround until this issue is solved: xprop -root -spy "_NET_ACTIVE_WINDOW" does essentially the same as herbstclient -i focus_changed

@The-Compiler
Copy link
Member Author

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

No branches or pull requests

2 participants