1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-03-24 21:53:31 +01:00

4 Commits

Author SHA1 Message Date
David Maciejak
66bf19c1e0 wmaker: add new ModifierKeyShortLabels option
This patch is adding a new ModifierKeyShortLabels option to the
WindowMaker file to let the user specify the modifier key labels
used in the shortcuts like those appearing in the root menu.
For example, to overwrite the default labels, a user can set
the new option value to:

ModifierKeyShortLabels = (
  "\342\207\247",
  "\342\214\203",
  "\342\214\245",
  "\342\207\255",
  "\342\207\263",
  "\342\214\230",
  "\342\207\252",
  "\342\227\206",
  "\342\214\245"
);

Which is using the same symbols as defined in macos.
For example, instead of printing M4+, "\342\214\230"
will print the ⌘ (Command) symbol.
2026-02-25 07:54:55 +00:00
David Maciejak
073235ada4 wmaker: set proper group window class when hint is empty
This patch is setting a proper class hint internally
when the app is not setting any.
That issue can be reproduced with terminator 2.1.3,
where the window itself is setting a proper WM_CLASS

$ xprop|grep WM_CLASS
WM_CLASS(STRING) = "terminator", "Terminator

But the window id # of group leader: 0x1000001
is setting only the instance name not the class name.
$ xprop -id 0x1000001|grep CLASS
WM_CLASS(STRING) = "terminator", ""

The issue is that wmaker is using those 2 string values
for the dock apps and to identify linked launched apps.
Those strings are concatenated and used in WMWindowAttributes.
Without the patch, that entry below is created:

  terminator. = {
    Icon = terminator..xpm;
  };

If wmaker is warm restarted, a new entry appears in WMWindowAttributes:

  terminator. = {
    Icon = terminator..xpm;
  };

  terminator = {
    Icon = terminator..xpm;
  };

and the opened window is not linked anymore to the dock app as the
WM_CLASS is different.
So you can launch the app as many times as you want from the dock,
the dock icon will
always have the 3 dots on the bottom left corner showing no window
apps are linked to it.

In case if the group window is not defining a CLASS but the client window
has one, the patch is setting the group window CLASS to the value of the
client window CLASS, or as a fallback, as seen in PropGetWMClass function,
setting it to "default".

With the patch, in WMWindowAttributes, we have now:
  terminator.Terminator = {
    Icon = terminator.Terminator.xpm;
  };

and a warm restart is not creating another entry.
2026-02-22 09:23:40 +00:00
David Maciejak
1b8eb63376 wmaker: add check in getSize function to prevent X error
This patch is checking if the passed Drawable exists before calling
XGetGeometry on it, as seen when using Steam and trying to change
the attributes of the 'Friends & Chat' popup window, wmaker is
generating such error in the logs:
warning: internal X error: BadDrawable (invalid Pixmap or Window parameter)
	Request code: 14 X_GetGeometry
	Request minor code: 0
	Resource ID: 0x0
	Error serial: 32091
2026-02-22 09:23:40 +00:00
David Maciejak
75a8299d18 wmaker: set the color pixel for TrueColor display
As mentioned in commit 67e2f5e1ca,
for TrueColor display it's not necessary to allocate a color but
it is required to set the pixel property of the XColor.
2026-02-20 08:47:50 +00:00
6 changed files with 114 additions and 27 deletions

View File

@@ -393,6 +393,7 @@ extern struct WPreferences {
signed char workspace_name_display_position;
unsigned int modifier_mask; /* mask to use as kbd modifier */
char *modifier_labels[7]; /* Names of the modifiers */
char *modifier_short_labels[9]; /* Short names of the modifiers */
unsigned int supports_tiff; /* Use tiff files */

View File

@@ -151,6 +151,7 @@ static WDECallbackUpdate setSwPOptions;
static WDECallbackUpdate updateUsableArea;
static WDECallbackUpdate setModifierKeyLabels;
static WDECallbackUpdate setModifierShortKeyLabels;
static WDECallbackUpdate setHotCornerActions;
static WDECallbackConvert getCursor;
@@ -624,6 +625,8 @@ WDefaultEntry optionList[] = {
NULL, getPropList, setSwPOptions, NULL, NULL},
{"ModifierKeyLabels", "(\"Shift+\", \"Control+\", \"Mod1+\", \"Mod2+\", \"Mod3+\", \"Mod4+\", \"Mod5+\")", &wPreferences,
NULL, getPropList, setModifierKeyLabels, NULL, NULL},
{"ModifierKeyShortLabels", "(\"Sh+\", \"^\", \"M1+\", \"M2+\", \"M3+\", \"M4+\", \"M5+\", \"M+\", \"A+\")", &wPreferences,
NULL, getPropList, setModifierShortKeyLabels, NULL, NULL},
{"FrameBorderWidth", "1", NULL,
NULL, getInt, setFrameBorderWidth, NULL, NULL},
{"FrameBorderColor", "black", NULL,
@@ -3499,6 +3502,42 @@ static int setModifierKeyLabels(WScreen * scr, WDefaultEntry * entry, void *tdat
return 0;
}
static int setModifierShortKeyLabels(WScreen * scr, WDefaultEntry * entry, void *tdata, void *foo)
{
WMPropList *array = tdata;
int i;
struct WPreferences *prefs = foo;
if (!WMIsPLArray(array) || WMGetPropListItemCount(array) != 9) {
wwarning(_("Value for option \"%s\" must be an array of 9 strings"), entry->key);
WMReleasePropList(array);
return 0;
}
DestroyWindowMenu(scr);
for (i = 0; i < 9; i++) {
if (prefs->modifier_short_labels[i])
wfree(prefs->modifier_short_labels[i]);
if (WMIsPLString(WMGetFromPLArray(array, i))) {
prefs->modifier_short_labels[i] = wstrdup(WMGetFromPLString(WMGetFromPLArray(array, i)));
if (prefs->modifier_short_labels[i][0] == '\0') {
wwarning(_("Invalid argument for option \"%s\" item %d, cannot be empty"), entry->key, i);
wfree(prefs->modifier_short_labels[i]);
prefs->modifier_short_labels[i] = NULL;
}
} else {
wwarning(_("Invalid argument for option \"%s\" item %d"), entry->key, i);
prefs->modifier_short_labels[i] = NULL;
}
}
WMReleasePropList(array);
return 0;
}
static int setHotCornerActions(WScreen * scr, WDefaultEntry * entry, void *tdata, void *foo)
{
WMPropList *array = tdata;

View File

@@ -105,6 +105,16 @@ static void tileObserver(void *self, WMNotification *notif)
static int getSize(Drawable d, unsigned int *w, unsigned int *h, unsigned int *dep)
{
if (d == None) {
if (w)
*w = 0;
if (h)
*h = 0;
if (dep)
*dep = 0;
return 0;
}
Window rjunk;
int xjunk, yjunk;
unsigned int bjunk;
@@ -195,6 +205,7 @@ static WIcon *icon_create_core(WScreen *scr, int coord_x, int coord_y)
/* Icon image */
icon->file = NULL;
icon->file_image = NULL;
icon->icon_win = None;
return icon;
}
@@ -752,7 +763,10 @@ static void set_dockapp_in_icon(WIcon *icon)
/* We need the application size to center it
* and show in the correct position */
getSize(icon->icon_win, &w, &h, &d);
if (!getSize(icon->icon_win, &w, &h, &d)) {
wwarning("Drawable invalid, skip reparenting dock app to icon.");
return;
}
/* Set the background pixmap */
XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->icon_tile_pixmap);

View File

@@ -35,20 +35,41 @@
#include "resources.h"
#include "screen.h"
static unsigned long scale_color_component(unsigned short value, unsigned long mask)
{
unsigned long m = mask;
int shift = 0, bits = 0;
if (!m)
return 0;
while (!(m & 1)) {
shift++;
m >>= 1;
}
while (m) {
bits++;
m >>= 1;
}
return ((unsigned long)(value >> (16 - bits)) & ((1UL << bits) - 1)) << shift;
}
int wGetColorForColormap(WScreen *scr, Colormap colormap, const char *color_name, XColor *color)
{
if (scr->w_visual->class == TrueColor) {
XColor dummy_exact;
if (!XLookupColor(dpy, colormap, color_name, &dummy_exact, color)) {
wwarning(_("could not lookup color \"%s\""), color_name);
return False;
}
return True;
}
if (!XParseColor(dpy, colormap, color_name, color)) {
wwarning(_("could not parse color \"%s\""), color_name);
return False;
}
if (scr->w_visual->class == TrueColor) {
/* Compute pixel directly from RGB components using the visual's channel masks */
color->pixel = scale_color_component(color->red, scr->w_visual->red_mask)
| scale_color_component(color->green, scr->w_visual->green_mask)
| scale_color_component(color->blue, scr->w_visual->blue_mask);
return True;
}
if (!XAllocColor(dpy, colormap, color)) {
wwarning(_("could not allocate color \"%s\""), color_name);
return False;

View File

@@ -848,6 +848,12 @@ WWindow *wManageWindow(WScreen *scr, Window window)
/* // only enter here if PropGetWMClass() succeeds */
PropGetWMClass(wwin->main_window, &class, &instance);
if (!class || class[0] == '\0') {
if (wwin->wm_class && wwin->wm_class[0] != '\0')
class = strdup(wwin->wm_class);
else
class = strdup("default");
}
buffer = StrConcatDot(instance, class);
index = WMFindInArray(scr->fakeGroupLeaders, matchIdentifier, (void *)buffer);

View File

@@ -280,24 +280,30 @@ const char *wXModifierToShortcutLabel(int mask)
if (mask < 0)
return NULL;
if (mask == ShiftMask)
return "Sh+";
if (mask == ControlMask)
return "^";
if (mask == AltMask)
return "A+";
if (mask == Mod1Mask)
return "M1+";
if (mask == Mod2Mask)
return "M2+";
if (mask == Mod3Mask)
return "M3+";
if (mask == Mod4Mask)
return "M4+";
if (mask == Mod5Mask)
return "M5+";
if (mask == MetaMask)
return "M+";
struct map_entry {
int mask;
int label_index;
const char *def;
} maps[] = {
{ ShiftMask, 0, "Sh+"},
{ ControlMask, 1, "^" },
{ AltMask, 8, "A+" },
{ Mod1Mask, 2, "M1+"},
{ Mod2Mask, 3, "M2+"},
{ Mod3Mask, 4, "M3+"},
{ Mod4Mask, 5, "M4+"},
{ Mod5Mask, 6, "M5+"},
{ MetaMask, 7, "M+" }
};
for (size_t i = 0; i < sizeof(maps)/sizeof(maps[0]); i++) {
if (mask == maps[i].mask) {
int idx = maps[i].label_index;
if (idx >= 0 && idx < 9 && wPreferences.modifier_short_labels[idx])
return wPreferences.modifier_short_labels[idx];
return maps[i].def;
}
}
wwarning(_("Can't convert keymask 0x%04X to a shortcut label"), mask);
return NULL;