mirror of
https://github.com/gryf/wmaker.git
synced 2026-03-21 19:03:31 +01:00
wmaker: revamp titlebar language button
This patch is replacing the modelock legacy hardcoded language dropdown icons with a compact titlebar button based on the current locale. (it adds also a detection to xkbfile library which is required to get the short name of the locale). Now supports up to 4 layouts, clicking on the language button will cycle through them (XKB officially supports up to four groups).
This commit is contained in:
committed by
Carlos R. Mafra
parent
29177f94ed
commit
ec115fedf7
@@ -555,7 +555,9 @@ AC_ARG_ENABLE([modelock],
|
||||
m4_divert_pop([INIT_PREPARE])dnl
|
||||
|
||||
AS_IF([test "x$enable_modelock" = "xyes"],
|
||||
[AC_DEFINE([XKB_MODELOCK], [1], [whether XKB language MODELOCK should be enabled]) ])
|
||||
[WM_XEXT_CHECK_XKBFILE
|
||||
AS_IF([test "x$enable_modelock" = "xyes"],
|
||||
[AC_DEFINE([XKB_MODELOCK], [1], [whether XKB language MODELOCK should be enabled])])])
|
||||
|
||||
|
||||
dnl XDND Drag-nd-Drop support
|
||||
|
||||
@@ -232,3 +232,35 @@ AC_DEFUN_ONCE([WM_XEXT_CHECK_XRANDR],
|
||||
[supported_xext], [LIBXRANDR], [], [-])dnl
|
||||
AC_SUBST([LIBXRANDR])dnl
|
||||
]) dnl AC_DEFUN
|
||||
|
||||
|
||||
# WM_XEXT_CHECK_XKBFILE
|
||||
# ---------------------
|
||||
#
|
||||
# Check for the XKB File extension library (libxkbfile)
|
||||
# The check depends on variable 'enable_modelock' being either:
|
||||
# yes - detect, fail if not found
|
||||
# no - do not detect, disable support
|
||||
#
|
||||
# When found, append appropriate stuff in LIBXKBFILE, and append info to
|
||||
# the variable 'supported_xext'
|
||||
# When not found, generate an error because it's required for modelock
|
||||
AC_DEFUN_ONCE([WM_XEXT_CHECK_XKBFILE],
|
||||
[WM_LIB_CHECK([XKBFile], [-lxkbfile], [XkbRF_GetNamesProp], [$XLIBS],
|
||||
[wm_save_CFLAGS="$CFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([dnl
|
||||
@%:@include <stdio.h>
|
||||
@%:@include <X11/Xlib.h>
|
||||
@%:@include <X11/XKBlib.h>
|
||||
@%:@include <X11/extensions/XKBfile.h>
|
||||
@%:@include <X11/extensions/XKBrules.h>
|
||||
], [dnl
|
||||
Display *dpy = NULL;
|
||||
XkbRF_VarDefsRec vd;
|
||||
XkbRF_GetNamesProp(dpy, NULL, &vd);])],
|
||||
[],
|
||||
[AC_MSG_ERROR([found $CACHEVAR but cannot compile using XKBfile header])])
|
||||
CFLAGS="$wm_save_CFLAGS"],
|
||||
[supported_xext], [LIBXKBFILE], [enable_modelock], [-])dnl
|
||||
AC_SUBST([LIBXKBFILE])dnl
|
||||
]) dnl AC_DEFUN
|
||||
|
||||
@@ -165,6 +165,7 @@ wmaker_LDADD = \
|
||||
@XLFLAGS@ \
|
||||
@LIBXRANDR@ \
|
||||
@LIBXINERAMA@ \
|
||||
@LIBXKBFILE@ \
|
||||
@XLIBS@ \
|
||||
@LIBM@ \
|
||||
@INTLIBS@
|
||||
|
||||
17
src/event.c
17
src/event.c
@@ -593,10 +593,12 @@ static void handleExtensions(XEvent * event)
|
||||
handleShapeNotify(event);
|
||||
}
|
||||
#endif
|
||||
if (w_global.xext.xkb.supported && event->type == w_global.xext.xkb.event_base) {
|
||||
if (w_global.xext.xkb.supported && event->type >= w_global.xext.xkb.event_base
|
||||
&& event->type <= w_global.xext.xkb.event_base + 255) {
|
||||
XkbEvent *xkbevent = (XkbEvent *) event;
|
||||
int xkb_type = xkbevent->any.xkb_type;
|
||||
|
||||
if (xkbevent->any.xkb_type == XkbNewKeyboardNotify) {
|
||||
if (xkb_type == XkbNewKeyboardNotify) {
|
||||
int j;
|
||||
WScreen *scr;
|
||||
|
||||
@@ -607,8 +609,10 @@ static void handleExtensions(XEvent * event)
|
||||
}
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
else {
|
||||
if (wPreferences.modelock && (xkbevent->any.xkb_type == XkbIndicatorStateNotify)) {
|
||||
handleXkbIndicatorStateNotify((XkbEvent *) event);
|
||||
/* Listen not only for IndicatorStateNotify but also for StateNotify
|
||||
* which is commonly emitted on group (layout) changes. */
|
||||
if (wPreferences.modelock && (xkb_type == XkbIndicatorStateNotify || xkb_type == XkbStateNotify)) {
|
||||
handleXkbIndicatorStateNotify(xkbevent);
|
||||
}
|
||||
}
|
||||
#endif /*KEEP_XKB_LOCK_STATUS */
|
||||
@@ -1324,6 +1328,8 @@ static void handleXkbIndicatorStateNotify(XkbEvent *event)
|
||||
if (wwin->frame->languagemode != staterec.group) {
|
||||
wwin->frame->last_languagemode = wwin->frame->languagemode;
|
||||
wwin->frame->languagemode = staterec.group;
|
||||
wWindowGetLanguageLabel(wwin->frame->languagemode, wwin->frame->language_label);
|
||||
wFrameWindowUpdateLanguageButton(wwin->frame);
|
||||
}
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (wwin->frame->titlebar) {
|
||||
@@ -1967,7 +1973,8 @@ static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent
|
||||
wwin->frame->languagemode = wwin->frame->last_languagemode;
|
||||
wwin->frame->last_languagemode = staterec.group;
|
||||
XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
|
||||
|
||||
/* Update the language label text */
|
||||
wWindowGetLanguageLabel(wwin->frame->languagemode, wwin->frame->language_label);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
198
src/framewin.c
198
src/framewin.c
@@ -54,7 +54,7 @@ static void resizebarMouseDown(WObjDescriptor * desc, XEvent * event);
|
||||
static void checkTitleSize(WFrameWindow * fwin);
|
||||
|
||||
static void paintButton(WCoreWindow * button, WTexture * texture,
|
||||
unsigned long color, WPixmap * image, int pushed);
|
||||
unsigned long color, WPixmap * image, int pushed, int from_xpm);
|
||||
|
||||
static void updateTitlebar(WFrameWindow * fwin);
|
||||
|
||||
@@ -98,6 +98,7 @@ WFrameWindow *wFrameWindowCreate(WScreen * scr, int wlevel, int x, int y,
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
fwin->languagemode = XkbGroup1Index;
|
||||
fwin->last_languagemode = XkbGroup2Index;
|
||||
wWindowGetLanguageLabel(fwin->languagemode, fwin->language_label);
|
||||
#endif
|
||||
|
||||
fwin->depth = depth;
|
||||
@@ -145,6 +146,7 @@ void wFrameWindowUpdateBorders(WFrameWindow * fwin, int flags)
|
||||
theight = *fwin->title_min_height;
|
||||
} else {
|
||||
theight = 0;
|
||||
fwin->flags.titlebar = 0;
|
||||
}
|
||||
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
@@ -536,6 +538,8 @@ static void updateTitlebar(WFrameWindow * fwin)
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
else {
|
||||
int bsize = theight - 7;
|
||||
if (wPreferences.new_style == TS_NEXT)
|
||||
bsize -= 1;
|
||||
if (fwin->flags.hide_left_button || !fwin->left_button || fwin->flags.lbutton_dont_fit) {
|
||||
if (fwin->language_button)
|
||||
wCoreConfigure(fwin->language_button, 3, (theight - bsize) / 2,
|
||||
@@ -950,6 +954,10 @@ void wFrameWindowPaint(WFrameWindow * fwin)
|
||||
remakeTexture(fwin, i);
|
||||
}
|
||||
}
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (wPreferences.modelock)
|
||||
wFrameWindowUpdateLanguageButton(fwin);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fwin->flags.need_texture_change) {
|
||||
@@ -1023,7 +1031,8 @@ void wFrameWindowPaint(WFrameWindow * fwin)
|
||||
allButtons = 0;
|
||||
}
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
fwin->languagebutton_image = scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
|
||||
if (fwin->flags.language_button && !fwin->languagebutton_image[0])
|
||||
wFrameWindowUpdateLanguageButton(fwin);
|
||||
#endif
|
||||
|
||||
if (fwin->title) {
|
||||
@@ -1228,10 +1237,145 @@ int wFrameWindowChangeTitle(WFrameWindow *fwin, const char *new_title)
|
||||
}
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
|
||||
static int wFrameWindowSetLanguageButtonImages(WFrameWindow *fwin, Pixmap *pixmaps, int count)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
WPixmap *wp = wPixmapCreate(pixmaps[i], None);
|
||||
if (!wp) {
|
||||
int j;
|
||||
XFreePixmap(dpy, pixmaps[i]);
|
||||
for (j = i + 1; j < count; j++)
|
||||
XFreePixmap(dpy, pixmaps[j]);
|
||||
return 0;
|
||||
}
|
||||
wp->client_owned = 0;
|
||||
wp->client_owned_mask = 0;
|
||||
if (fwin->languagebutton_image[i] && !fwin->languagebutton_image[i]->shared)
|
||||
wPixmapDestroy(fwin->languagebutton_image[i]);
|
||||
fwin->languagebutton_image[i] = wp;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void wFrameWindowUpdateLanguageButton(WFrameWindow * fwin)
|
||||
{
|
||||
paintButton(fwin->language_button, fwin->title_texture[fwin->flags.state],
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->languagebutton_image, True);
|
||||
WScreen *scr = fwin->screen_ptr;
|
||||
WCoreWindow *button = fwin->language_button;
|
||||
GC gc = scr->copy_gc;
|
||||
int i, text_width, text_height;
|
||||
int border_thickness = 3;
|
||||
int key_width, key_height;
|
||||
int group_index;
|
||||
Pixmap tmp[2]; /* focused, unfocused */
|
||||
|
||||
if (!fwin->flags.titlebar || fwin->core->descriptor.parent_type != WCLASS_WINDOW)
|
||||
return;
|
||||
|
||||
if (!button || fwin->language_label[0] == '\0')
|
||||
return;
|
||||
|
||||
group_index = fwin->languagemode;
|
||||
if (group_index < 0 || group_index >= 4)
|
||||
return;
|
||||
|
||||
/* Calculate text dimensions */
|
||||
int small_px = WMFontHeight(*fwin->font) * 55 / 100;
|
||||
WMFont *small = WMBoldSystemFontOfSize(scr->wmscreen, small_px);
|
||||
text_width = WMWidthOfString(small, fwin->language_label, strlen(fwin->language_label));
|
||||
text_height = WMFontHeight(small);
|
||||
|
||||
key_width = button->width - border_thickness;
|
||||
key_height = button->height - border_thickness;
|
||||
|
||||
/* Ensure dimensions are valid */
|
||||
if (key_width < 1 || key_height < 1) {
|
||||
WMReleaseFont(small);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create temporary pixmaps for immediate drawing */
|
||||
tmp[0] = XCreatePixmap(dpy, button->window, 2*key_width, key_height, scr->w_depth);
|
||||
if (tmp[0] == None) {
|
||||
WMReleaseFont(small);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp[1] = None;
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
tmp[1] = XCreatePixmap(dpy, button->window, 2*key_width, key_height, scr->w_depth);
|
||||
if (tmp[1] == None) {
|
||||
XFreePixmap(dpy, tmp[0]);
|
||||
WMReleaseFont(small);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset GC to ensure clean state for drawing */
|
||||
XSetClipMask(dpy, gc, None);
|
||||
|
||||
/* Draw the language label centered in the button */
|
||||
int text_x = (key_width - text_width) / 2;
|
||||
int text_y = (key_height - text_height) / 2;
|
||||
|
||||
/* Fill the color pixmap depending on the style */
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (fwin->title_texture[i]->any.type != WTEX_SOLID && fwin->title_back[i] != None) {
|
||||
XCopyArea(dpy, fwin->languagebutton_back[i], tmp[i], scr->copy_gc,
|
||||
0, 0, button->width, button->height, -1, -1);
|
||||
} else {
|
||||
unsigned long bg_pixel = fwin->title_texture[i]->solid.normal.pixel;
|
||||
XSetForeground(dpy, gc, bg_pixel);
|
||||
XFillRectangle(dpy, tmp[i], gc, 0, 0, key_width, key_height);
|
||||
}
|
||||
WMDrawString(scr->wmscreen, tmp[i], fwin->title_color[i],
|
||||
small, text_x, text_y, fwin->language_label, strlen(fwin->language_label));
|
||||
}
|
||||
} else if (wPreferences.new_style == TS_OLD) {
|
||||
unsigned long bg_pixel = scr->widget_texture->normal.pixel;
|
||||
XSetForeground(dpy, gc, bg_pixel);
|
||||
XFillRectangle(dpy, tmp[0], gc, 0, 0, key_width, key_height);
|
||||
WMDrawString(scr->wmscreen, tmp[0], WMBlackColor(scr->wmscreen),
|
||||
small, text_x, text_y, fwin->language_label, strlen(fwin->language_label));
|
||||
} else {
|
||||
unsigned long bg_pixel = scr->widget_texture->dark.pixel;
|
||||
XSetForeground(dpy, gc, bg_pixel);
|
||||
XFillRectangle(dpy, tmp[0], gc, 0, 0, key_width, key_height);
|
||||
WMColor *silver = WMCreateRGBColor(scr->wmscreen, 0xc0c0, 0xc0c0, 0xc0c0, True);
|
||||
WMDrawString(scr->wmscreen, tmp[0], silver,
|
||||
small, text_x, text_y, fwin->language_label, strlen(fwin->language_label));
|
||||
WMReleaseColor(silver);
|
||||
}
|
||||
|
||||
/* pushed button next to normal for easy access when painting */
|
||||
text_x = key_width + (key_width - text_width) / 2;
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
XSetForeground(dpy, gc, scr->white_pixel);
|
||||
for (i = 0; i < 2; i++) {
|
||||
XFillRectangle(dpy, tmp[i], gc, key_width, 0, key_width, key_height);
|
||||
WMDrawString(scr->wmscreen, tmp[i], WMBlackColor(scr->wmscreen),
|
||||
small, text_x, text_y, fwin->language_label, strlen(fwin->language_label));
|
||||
}
|
||||
} else if (wPreferences.new_style == TS_OLD) {
|
||||
XSetForeground(dpy, gc, scr->white_pixel);
|
||||
XFillRectangle(dpy, tmp[0], gc, key_width, 0, key_width, key_height);
|
||||
WMDrawString(scr->wmscreen, tmp[0], WMDarkGrayColor(scr->wmscreen),
|
||||
small, text_x, text_y, fwin->language_label, strlen(fwin->language_label));
|
||||
} else {
|
||||
unsigned long bg_pixel = scr->widget_texture->dark.pixel;
|
||||
WMColor *silver = WMCreateRGBColor(scr->wmscreen, 0xc0c0, 0xc0c0, 0xc0c0, True);
|
||||
XSetForeground(dpy, gc, bg_pixel);
|
||||
XFillRectangle(dpy, tmp[0], gc, key_width, 0, key_width, key_height);
|
||||
WMDrawString(scr->wmscreen, tmp[0], silver,
|
||||
small, text_x, text_y, fwin->language_label, strlen(fwin->language_label));
|
||||
WMReleaseColor(silver);
|
||||
}
|
||||
|
||||
WMReleaseFont(small);
|
||||
|
||||
wFrameWindowSetLanguageButtonImages(fwin, tmp, (wPreferences.new_style == TS_NEW) ? 2 : 1);
|
||||
}
|
||||
#endif /* XKB_BUTTON_HINT */
|
||||
|
||||
@@ -1286,7 +1430,7 @@ static void checkTitleSize(WFrameWindow * fwin)
|
||||
fwin->flags.incomplete_title = 0;
|
||||
}
|
||||
|
||||
static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long color, WPixmap * image, int pushed)
|
||||
static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long color, WPixmap * image, int pushed, int from_xpm)
|
||||
{
|
||||
WScreen *scr = button->screen_ptr;
|
||||
GC copy_gc = scr->copy_gc;
|
||||
@@ -1364,8 +1508,12 @@ static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long
|
||||
} else {
|
||||
if (wPreferences.new_style == TS_OLD) {
|
||||
XSetForeground(dpy, copy_gc, scr->dark_pixel);
|
||||
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
|
||||
button->width, button->height);
|
||||
if (from_xpm)
|
||||
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
|
||||
button->width, button->height);
|
||||
else
|
||||
XCopyArea(dpy, image->image, button->window, copy_gc,
|
||||
left, 0, width, image->height, x, y);
|
||||
} else {
|
||||
XSetForeground(dpy, copy_gc, scr->black_pixel);
|
||||
XCopyArea(dpy, image->image, button->window, copy_gc,
|
||||
@@ -1379,7 +1527,11 @@ static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long
|
||||
XSetForeground(dpy, copy_gc, color);
|
||||
XSetBackground(dpy, copy_gc, texture->any.color.pixel);
|
||||
}
|
||||
XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width, button->height);
|
||||
if (from_xpm)
|
||||
XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width, button->height);
|
||||
else
|
||||
XCopyArea(dpy, image->image, button->window, copy_gc,
|
||||
left, 0, width, image->height, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1394,18 +1546,23 @@ static void handleButtonExpose(WObjDescriptor * desc, XEvent * event)
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (button == fwin->language_button) {
|
||||
if (!fwin->flags.hide_language_button)
|
||||
if (!fwin->flags.hide_language_button) {
|
||||
/* map focused and pfocused states to focus language button image */
|
||||
int lb_index = wPreferences.new_style == TS_NEW && (fwin->flags.state == 1) ? 1 : 0;
|
||||
|
||||
paintButton(button, fwin->title_texture[fwin->flags.state],
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]),
|
||||
fwin->languagebutton_image, False);
|
||||
fwin->languagebutton_image[lb_index],
|
||||
False, False);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (button == fwin->left_button)
|
||||
paintButton(button, fwin->title_texture[fwin->flags.state],
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->lbutton_image, False);
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->lbutton_image, False, True);
|
||||
else
|
||||
paintButton(button, fwin->title_texture[fwin->flags.state],
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->rbutton_image, False);
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->rbutton_image, False, True);
|
||||
}
|
||||
|
||||
static void titlebarMouseDown(WObjDescriptor * desc, XEvent * event)
|
||||
@@ -1437,7 +1594,7 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
||||
WCoreWindow *button = desc->self;
|
||||
WPixmap *image;
|
||||
XEvent ev;
|
||||
int done = 0, execute = 1;
|
||||
int done = 0, execute = 1, from_xpm = True;
|
||||
WTexture *texture;
|
||||
unsigned long pixel;
|
||||
int clickButton = event->xbutton.button;
|
||||
@@ -1458,13 +1615,18 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
||||
if (button == fwin->language_button) {
|
||||
if (!wPreferences.modelock)
|
||||
return;
|
||||
image = fwin->languagebutton_image;
|
||||
|
||||
/* map focused and pfocused states to focus language button image */
|
||||
int lb_index = wPreferences.new_style == TS_NEW && (fwin->flags.state == 1) ? 1 : 0;
|
||||
|
||||
image = fwin->languagebutton_image[lb_index];
|
||||
from_xpm = False;
|
||||
}
|
||||
#endif
|
||||
|
||||
pixel = WMColorPixel(fwin->title_color[fwin->flags.state]);
|
||||
texture = fwin->title_texture[fwin->flags.state];
|
||||
paintButton(button, texture, pixel, image, True);
|
||||
paintButton(button, texture, pixel, image, True, from_xpm);
|
||||
|
||||
while (!done) {
|
||||
WMMaskEvent(dpy, LeaveWindowMask | EnterWindowMask | ButtonReleaseMask
|
||||
@@ -1472,12 +1634,12 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
||||
switch (ev.type) {
|
||||
case LeaveNotify:
|
||||
execute = 0;
|
||||
paintButton(button, texture, pixel, image, False);
|
||||
paintButton(button, texture, pixel, image, False, from_xpm);
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
execute = 1;
|
||||
paintButton(button, texture, pixel, image, True);
|
||||
paintButton(button, texture, pixel, image, True, from_xpm);
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
@@ -1492,7 +1654,7 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
||||
WMHandleEvent(&ev);
|
||||
}
|
||||
}
|
||||
paintButton(button, texture, pixel, image, False);
|
||||
paintButton(button, texture, pixel, image, False, from_xpm);
|
||||
|
||||
if (execute) {
|
||||
if (button == fwin->left_button) {
|
||||
|
||||
@@ -80,7 +80,7 @@ typedef struct WFrameWindow {
|
||||
WPixmap *lbutton_image;
|
||||
WPixmap *rbutton_image;
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
WPixmap *languagebutton_image;
|
||||
WPixmap *languagebutton_image[2]; /* focused, unfocused */
|
||||
#endif
|
||||
|
||||
union WTexture **title_texture;
|
||||
@@ -93,6 +93,7 @@ typedef struct WFrameWindow {
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
int languagemode;
|
||||
int last_languagemode;
|
||||
char language_label[3]; /* 2-letter language code */
|
||||
#endif /* KEEP_XKB_LOCK_STATUS */
|
||||
|
||||
/* thing that uses this frame. passed as data to callbacks */
|
||||
|
||||
@@ -658,11 +658,10 @@ WScreen *wScreenInit(int screen_number)
|
||||
XSelectInput(dpy, scr->root_win, event_mask);
|
||||
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
/* Only GroupLock doesn't work correctly in my system since right-alt
|
||||
* can change mode while holding it too - ]d
|
||||
*/
|
||||
if (w_global.xext.xkb.supported)
|
||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask);
|
||||
XkbSelectEvents(dpy, XkbUseCoreKbd,
|
||||
XkbIndicatorStateNotifyMask | XkbStateNotifyMask | XkbNewKeyboardNotifyMask,
|
||||
XkbIndicatorStateNotifyMask | XkbStateNotifyMask | XkbNewKeyboardNotifyMask);
|
||||
#else
|
||||
if (w_global.xext.xkb.supported)
|
||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask, XkbNewKeyboardNotifyMask);
|
||||
|
||||
88
src/window.c
88
src/window.c
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#ifdef USE_XSHAPE
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
@@ -38,6 +39,12 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
#include <X11/extensions/XKBfile.h> // Required for XkbRF_VarDefsRec
|
||||
#include <X11/extensions/XKBrules.h> // Required for XkbRF_GetNamesProp
|
||||
#endif
|
||||
|
||||
/* For getting mouse wheel mappings from WINGs */
|
||||
#include <WINGs/WINGs.h>
|
||||
@@ -2304,14 +2311,6 @@ void wWindowUpdateButtonImages(WWindow *wwin)
|
||||
fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
|
||||
}
|
||||
}
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (!WFLAGP(wwin, no_language_button)) {
|
||||
if (fwin->languagebutton_image && !fwin->languagebutton_image->shared)
|
||||
wPixmapDestroy(fwin->languagebutton_image);
|
||||
|
||||
fwin->languagebutton_image = scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* close button */
|
||||
|
||||
@@ -3145,6 +3144,37 @@ static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
|
||||
}
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
/* Helper function to extract the 2-letter language code for a given XKB group index */
|
||||
void wWindowGetLanguageLabel(int group_index, char *label)
|
||||
{
|
||||
XkbRF_VarDefsRec vd;
|
||||
/* Default to empty - will fallback to pixmap if we can't get the label */
|
||||
label[0] = '\0';
|
||||
|
||||
if (XkbRF_GetNamesProp(dpy, NULL, &vd) && vd.layout) {
|
||||
int i;
|
||||
char *layout_list = strdup(vd.layout);
|
||||
char *tok = strtok(layout_list, ",");
|
||||
|
||||
/* Iterate to the requested group index */
|
||||
for (i = 0; i < group_index && tok != NULL; i++) {
|
||||
tok = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
if (tok) {
|
||||
/* Copy exactly the first two bytes, then format: first uppercase, second lowercase */
|
||||
strncpy(label, tok, 2);
|
||||
label[2] = '\0';
|
||||
if (label[0])
|
||||
label[0] = (char) toupper((unsigned char) label[0]);
|
||||
if (label[1])
|
||||
label[1] = (char) tolower((unsigned char) label[1]);
|
||||
}
|
||||
|
||||
free(layout_list);
|
||||
}
|
||||
}
|
||||
|
||||
static void windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event)
|
||||
{
|
||||
WWindow *wwin = data;
|
||||
@@ -3158,11 +3188,45 @@ static void windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event)
|
||||
if (event->xbutton.button != Button1 && event->xbutton.button != Button3)
|
||||
return;
|
||||
tl = wwin->frame->languagemode;
|
||||
wwin->frame->languagemode = wwin->frame->last_languagemode;
|
||||
wwin->frame->last_languagemode = tl;
|
||||
|
||||
/* Try to advance to the next available XKB group */
|
||||
XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
|
||||
int newgroup = -1;
|
||||
if (desc && desc->names) {
|
||||
int i;
|
||||
const int MAX_GROUPS = 4; /* typical XKB max groups */
|
||||
for (i = 1; i <= MAX_GROUPS; i++) {
|
||||
int cand = (tl + i) % MAX_GROUPS;
|
||||
Atom a = desc->names->groups[cand];
|
||||
if (a != None) {
|
||||
/* Use XGetAtomName to ensure the atom actually has a name */
|
||||
char *nm = XGetAtomName(dpy, a);
|
||||
if (nm && nm[0] != '\0') {
|
||||
newgroup = cand;
|
||||
XFree(nm);
|
||||
break;
|
||||
}
|
||||
if (nm)
|
||||
XFree(nm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newgroup >= 0) {
|
||||
wwin->frame->last_languagemode = tl;
|
||||
wwin->frame->languagemode = newgroup;
|
||||
XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
|
||||
} else {
|
||||
/* fallback to previous toggle behaviour for setups with only two
|
||||
* groups or when group info is not available */
|
||||
wwin->frame->languagemode = wwin->frame->last_languagemode;
|
||||
wwin->frame->last_languagemode = tl;
|
||||
XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
|
||||
}
|
||||
/* Update label */
|
||||
wWindowGetLanguageLabel(wwin->frame->languagemode, wwin->frame->language_label);
|
||||
|
||||
wSetFocusTo(scr, wwin);
|
||||
wwin->frame->languagebutton_image =
|
||||
wwin->frame->screen_ptr->b_pixmaps[WBUT_XKBGROUP1 + wwin->frame->languagemode];
|
||||
wFrameWindowUpdateLanguageButton(wwin->frame);
|
||||
if (event->xbutton.button == Button3)
|
||||
return;
|
||||
|
||||
@@ -405,4 +405,9 @@ void wWindowDeleteSavedState(WMagicNumber id);
|
||||
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
|
||||
|
||||
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
void wWindowGetLanguageLabel(int group_index, char *label);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user