Add a command line switch to set the name part of WM_CLASS independently

This commit is contained in:
Kovid Goyal 2017-11-20 20:48:17 +05:30
parent 02884c5045
commit 32a6dd2aa1
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
8 changed files with 58 additions and 31 deletions

View File

@ -36,6 +36,9 @@ version 0.5.1 [2017-12-01]
- Add an option to control the audio bell volume on X11 systems
- Add a command line switch to set the name part of the WM_CLASS window
property independently.
version 0.5.0 [2017-11-19]
---------------------------

7
glfw/glfw3.h vendored
View File

@ -2343,7 +2343,12 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* @remark @x11 The name and class of the `WM_CLASS` window property will by
* default be set to the window title passed to this function. Set the @ref
* GLFW_X11_WM_CLASS_NAME and @ref GLFW_X11_WM_CLASS_CLASS init hints before
* initialization to override this.
* initialization to override this. You can also set the title int he following
* special format, which allows setting the two parts of the WM_CLASS property
* and the window title independently:
* <01> WM_CLASS name <30> WM_CLASS class <30> title
* Here <01> refers to the byte value 01 (ASCII start-of-header) and <30> refers
* to the byte value 30 (ASCII record separator).
*
* @remark @wayland The window frame is currently unimplemented, as if
* [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`.

29
glfw/x11_window.c vendored
View File

@ -703,9 +703,11 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
updateNormalHints(window, wndconfig->width, wndconfig->height);
// Set ICCCM WM_CLASS property
// Set ICCCM WM_CLASS property and window title
{
XClassHint* hint = XAllocClassHint();
char *wm_cclass = NULL, *wm_cname = NULL;
const char *real_title = wndconfig->title;
if (strlen(_glfw.hints.init.x11.className) &&
strlen(_glfw.hints.init.x11.classClass))
@ -713,10 +715,26 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
hint->res_name = (char*) _glfw.hints.init.x11.className;
hint->res_class = (char*) _glfw.hints.init.x11.classClass;
}
else if (strlen(wndconfig->title))
else if (strlen(real_title))
{
hint->res_name = (char*) wndconfig->title;
hint->res_class = (char*) wndconfig->title;
if (*real_title == 1) {
char *p = strchr(real_title, 30);
if (p && p > real_title + 1) {
wm_cname = calloc(p - real_title + 1, 1);
if (wm_cname) memcpy(wm_cname, real_title + 1, p - real_title - 1);
hint->res_name = wm_cname;
char *q = strchr(p + 1, 30);
if (q && q > p + 1) {
wm_cclass = calloc(q - p + 1, 1);
if (wm_cclass) memcpy(wm_cclass, p + 1, q - p - 1);
hint->res_class = wm_cclass;
real_title = q + 1;
}
}
} else {
hint->res_name = (char*) real_title;
hint->res_class = (char*) real_title;
}
}
else
{
@ -726,6 +744,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
XSetClassHint(_glfw.x11.display, window->x11.handle, hint);
XFree(hint);
free(wm_cclass); free(wm_cname);
_glfwPlatformSetWindowTitle(window, real_title);
}
// Announce support for Xdnd (drag and drop)
@ -736,7 +756,6 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
PropModeReplace, (unsigned char*) &version, 1);
}
_glfwPlatformSetWindowTitle(window, wndconfig->title);
if (_glfw.x11.im)
{

View File

@ -19,8 +19,9 @@ from .keys import get_key_map, get_shortcut
from .session import create_session
from .tabs import SpecialWindow, TabManager
from .utils import (
end_startup_notification, get_primary_selection, init_startup_notification,
open_url, safe_print, set_primary_selection, single_instance
encode_wm_class, end_startup_notification, get_primary_selection,
init_startup_notification, open_url, safe_print, set_primary_selection,
single_instance
)
@ -78,10 +79,10 @@ class Boss:
startup_session = create_session(opts, args)
self.add_os_window(startup_session, os_window_id=os_window_id)
def add_os_window(self, startup_session, os_window_id=None, wclass=None, size=None, visible=True):
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, size=None, visible=True):
if os_window_id is None:
w, h = initial_window_size(self.opts) if size is None else size
os_window_id = create_os_window(w, h, wclass or self.args.cls, visible)
os_window_id = create_os_window(w, h, encode_wm_class(wname or self.args.name, wclass or self.args.cls), visible)
tm = TabManager(os_window_id, self.opts, self.args, startup_session)
self.os_window_map[os_window_id] = tm
return os_window_id
@ -103,7 +104,7 @@ class Boss:
args = option_parser().parse_args(msg['args'][1:])
opts = create_opts(args)
session = create_session(opts, args)
os_window_id = self.add_os_window(session, wclass=args.cls, size=initial_window_size(opts))
os_window_id = self.add_os_window(session, wclass=args.cls, wname=args.name, size=initial_window_size(opts))
if startup_id:
ctx = init_startup_notification(os_window_id, startup_id)
end_startup_notification(ctx)

View File

@ -20,7 +20,13 @@ def option_parser():
'--class',
default=appname,
dest='cls',
help=_('Set the WM_CLASS property')
help=_('Set the class part of the WM_CLASS property')
)
a(
'--name',
default=None,
dest='name',
help=_('Set the name part of the WM_CLASS property (defaults to using the value from {})').format('--class')
)
a(
'--config',

View File

@ -402,15 +402,6 @@ glfw_window_hint(PyObject UNUSED *self, PyObject *args) {
Py_RETURN_NONE;
}
PyObject*
glfw_init_hint_string(PyObject UNUSED *self, PyObject *args) {
int hint_id;
char *hint;
if (!PyArg_ParseTuple(args, "is", &hint_id, &hint)) return NULL;
glfwInitHintString(hint_id, hint);
Py_RETURN_NONE;
}
// }}}
@ -694,7 +685,6 @@ static PyMethodDef module_methods[] = {
{"glfw_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""},
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""},
{"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""},
{"glfw_init_hint_string", (PyCFunction)glfw_init_hint_string, METH_VARARGS, ""},
{"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""},
{"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""},
{NULL, NULL, 0, NULL} /* Sentinel */

View File

@ -14,13 +14,13 @@ from .cli import create_opts, option_parser
from .config import initial_window_size, load_cached_values, save_cached_values
from .constants import isosx, iswayland, logo_data_file
from .fast_data_types import (
change_wcwidth, create_os_window, glfw_init, glfw_init_hint_string,
glfw_terminate, install_sigchld_handler, set_default_window_icon,
set_logical_dpi, set_options, GLFW_X11_WM_CLASS_NAME, GLFW_X11_WM_CLASS_CLASS
change_wcwidth, create_os_window, glfw_init, glfw_terminate,
install_sigchld_handler, set_default_window_icon, set_logical_dpi,
set_options
)
from .fonts.box_drawing import set_scale
from .utils import (
detach, end_startup_notification, get_logical_dpi,
detach, encode_wm_class, end_startup_notification, get_logical_dpi,
init_startup_notification, single_instance
)
from .window import load_shader_programs
@ -45,7 +45,7 @@ def run_app(opts, args):
set_options(opts, iswayland, args.debug_gl)
load_cached_values()
w, h = initial_window_size(opts)
window_id = create_os_window(w, h, args.cls, True, load_all_shaders)
window_id = create_os_window(w, h, encode_wm_class(args.name, args.cls), True, load_all_shaders)
startup_ctx = init_startup_notification(window_id)
if not iswayland and not isosx: # no window icons on wayland
with open(logo_data_file, 'rb') as f:
@ -137,10 +137,7 @@ def main():
return
opts = create_opts(args)
change_wcwidth(not opts.use_system_wcwidth)
glfw_module = init_graphics()
if glfw_module == 'x11':
glfw_init_hint_string(GLFW_X11_WM_CLASS_CLASS, args.cls)
glfw_init_hint_string(GLFW_X11_WM_CLASS_NAME, args.cls)
init_graphics()
try:
with setup_profiling(args):
# Avoid needing to launch threads to reap zombies

View File

@ -291,3 +291,9 @@ def single_instance(group_id=None):
s.set_inheritable(False)
atexit.register(remove_socket_file, s)
return True
def encode_wm_class(name, cls, title=appname):
if isosx:
return title
return '\x01' + (name or cls) + '\x1e' + cls + '\x1e' + title