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 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] 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 * @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 * 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 * 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 * @remark @wayland The window frame is currently unimplemented, as if
* [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`. * [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); updateNormalHints(window, wndconfig->width, wndconfig->height);
// Set ICCCM WM_CLASS property // Set ICCCM WM_CLASS property and window title
{ {
XClassHint* hint = XAllocClassHint(); XClassHint* hint = XAllocClassHint();
char *wm_cclass = NULL, *wm_cname = NULL;
const char *real_title = wndconfig->title;
if (strlen(_glfw.hints.init.x11.className) && if (strlen(_glfw.hints.init.x11.className) &&
strlen(_glfw.hints.init.x11.classClass)) 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_name = (char*) _glfw.hints.init.x11.className;
hint->res_class = (char*) _glfw.hints.init.x11.classClass; 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; if (*real_title == 1) {
hint->res_class = (char*) wndconfig->title; 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 else
{ {
@ -726,6 +744,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
XSetClassHint(_glfw.x11.display, window->x11.handle, hint); XSetClassHint(_glfw.x11.display, window->x11.handle, hint);
XFree(hint); XFree(hint);
free(wm_cclass); free(wm_cname);
_glfwPlatformSetWindowTitle(window, real_title);
} }
// Announce support for Xdnd (drag and drop) // Announce support for Xdnd (drag and drop)
@ -736,7 +756,6 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
PropModeReplace, (unsigned char*) &version, 1); PropModeReplace, (unsigned char*) &version, 1);
} }
_glfwPlatformSetWindowTitle(window, wndconfig->title);
if (_glfw.x11.im) if (_glfw.x11.im)
{ {

View File

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

View File

@ -20,7 +20,13 @@ def option_parser():
'--class', '--class',
default=appname, default=appname,
dest='cls', 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( a(
'--config', '--config',

View File

@ -402,15 +402,6 @@ glfw_window_hint(PyObject UNUSED *self, PyObject *args) {
Py_RETURN_NONE; 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_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""},
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, 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_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_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""},
{"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""}, {"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""},
{NULL, NULL, 0, NULL} /* Sentinel */ {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 .config import initial_window_size, load_cached_values, save_cached_values
from .constants import isosx, iswayland, logo_data_file from .constants import isosx, iswayland, logo_data_file
from .fast_data_types import ( from .fast_data_types import (
change_wcwidth, create_os_window, glfw_init, glfw_init_hint_string, change_wcwidth, create_os_window, glfw_init, glfw_terminate,
glfw_terminate, install_sigchld_handler, set_default_window_icon, install_sigchld_handler, set_default_window_icon, set_logical_dpi,
set_logical_dpi, set_options, GLFW_X11_WM_CLASS_NAME, GLFW_X11_WM_CLASS_CLASS set_options
) )
from .fonts.box_drawing import set_scale from .fonts.box_drawing import set_scale
from .utils import ( 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 init_startup_notification, single_instance
) )
from .window import load_shader_programs from .window import load_shader_programs
@ -45,7 +45,7 @@ def run_app(opts, args):
set_options(opts, iswayland, args.debug_gl) set_options(opts, iswayland, args.debug_gl)
load_cached_values() load_cached_values()
w, h = initial_window_size(opts) 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) startup_ctx = init_startup_notification(window_id)
if not iswayland and not isosx: # no window icons on wayland if not iswayland and not isosx: # no window icons on wayland
with open(logo_data_file, 'rb') as f: with open(logo_data_file, 'rb') as f:
@ -137,10 +137,7 @@ def main():
return return
opts = create_opts(args) opts = create_opts(args)
change_wcwidth(not opts.use_system_wcwidth) change_wcwidth(not opts.use_system_wcwidth)
glfw_module = init_graphics() 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)
try: try:
with setup_profiling(args): with setup_profiling(args):
# Avoid needing to launch threads to reap zombies # Avoid needing to launch threads to reap zombies

View File

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