mirror of
https://github.com/gryf/wmaker.git
synced 2026-03-21 02:43:32 +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
|
m4_divert_pop([INIT_PREPARE])dnl
|
||||||
|
|
||||||
AS_IF([test "x$enable_modelock" = "xyes"],
|
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
|
dnl XDND Drag-nd-Drop support
|
||||||
|
|||||||
@@ -232,3 +232,35 @@ AC_DEFUN_ONCE([WM_XEXT_CHECK_XRANDR],
|
|||||||
[supported_xext], [LIBXRANDR], [], [-])dnl
|
[supported_xext], [LIBXRANDR], [], [-])dnl
|
||||||
AC_SUBST([LIBXRANDR])dnl
|
AC_SUBST([LIBXRANDR])dnl
|
||||||
]) dnl AC_DEFUN
|
]) 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@ \
|
@XLFLAGS@ \
|
||||||
@LIBXRANDR@ \
|
@LIBXRANDR@ \
|
||||||
@LIBXINERAMA@ \
|
@LIBXINERAMA@ \
|
||||||
|
@LIBXKBFILE@ \
|
||||||
@XLIBS@ \
|
@XLIBS@ \
|
||||||
@LIBM@ \
|
@LIBM@ \
|
||||||
@INTLIBS@
|
@INTLIBS@
|
||||||
|
|||||||
17
src/event.c
17
src/event.c
@@ -593,10 +593,12 @@ static void handleExtensions(XEvent * event)
|
|||||||
handleShapeNotify(event);
|
handleShapeNotify(event);
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
XkbEvent *xkbevent = (XkbEvent *) event;
|
||||||
|
int xkb_type = xkbevent->any.xkb_type;
|
||||||
|
|
||||||
if (xkbevent->any.xkb_type == XkbNewKeyboardNotify) {
|
if (xkb_type == XkbNewKeyboardNotify) {
|
||||||
int j;
|
int j;
|
||||||
WScreen *scr;
|
WScreen *scr;
|
||||||
|
|
||||||
@@ -607,8 +609,10 @@ static void handleExtensions(XEvent * event)
|
|||||||
}
|
}
|
||||||
#ifdef KEEP_XKB_LOCK_STATUS
|
#ifdef KEEP_XKB_LOCK_STATUS
|
||||||
else {
|
else {
|
||||||
if (wPreferences.modelock && (xkbevent->any.xkb_type == XkbIndicatorStateNotify)) {
|
/* Listen not only for IndicatorStateNotify but also for StateNotify
|
||||||
handleXkbIndicatorStateNotify((XkbEvent *) event);
|
* which is commonly emitted on group (layout) changes. */
|
||||||
|
if (wPreferences.modelock && (xkb_type == XkbIndicatorStateNotify || xkb_type == XkbStateNotify)) {
|
||||||
|
handleXkbIndicatorStateNotify(xkbevent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /*KEEP_XKB_LOCK_STATUS */
|
#endif /*KEEP_XKB_LOCK_STATUS */
|
||||||
@@ -1324,6 +1328,8 @@ static void handleXkbIndicatorStateNotify(XkbEvent *event)
|
|||||||
if (wwin->frame->languagemode != staterec.group) {
|
if (wwin->frame->languagemode != staterec.group) {
|
||||||
wwin->frame->last_languagemode = wwin->frame->languagemode;
|
wwin->frame->last_languagemode = wwin->frame->languagemode;
|
||||||
wwin->frame->languagemode = staterec.group;
|
wwin->frame->languagemode = staterec.group;
|
||||||
|
wWindowGetLanguageLabel(wwin->frame->languagemode, wwin->frame->language_label);
|
||||||
|
wFrameWindowUpdateLanguageButton(wwin->frame);
|
||||||
}
|
}
|
||||||
#ifdef XKB_BUTTON_HINT
|
#ifdef XKB_BUTTON_HINT
|
||||||
if (wwin->frame->titlebar) {
|
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->languagemode = wwin->frame->last_languagemode;
|
||||||
wwin->frame->last_languagemode = staterec.group;
|
wwin->frame->last_languagemode = staterec.group;
|
||||||
XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
|
XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
|
||||||
|
/* Update the language label text */
|
||||||
|
wWindowGetLanguageLabel(wwin->frame->languagemode, wwin->frame->language_label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
192
src/framewin.c
192
src/framewin.c
@@ -54,7 +54,7 @@ static void resizebarMouseDown(WObjDescriptor * desc, XEvent * event);
|
|||||||
static void checkTitleSize(WFrameWindow * fwin);
|
static void checkTitleSize(WFrameWindow * fwin);
|
||||||
|
|
||||||
static void paintButton(WCoreWindow * button, WTexture * texture,
|
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);
|
static void updateTitlebar(WFrameWindow * fwin);
|
||||||
|
|
||||||
@@ -98,6 +98,7 @@ WFrameWindow *wFrameWindowCreate(WScreen * scr, int wlevel, int x, int y,
|
|||||||
#ifdef KEEP_XKB_LOCK_STATUS
|
#ifdef KEEP_XKB_LOCK_STATUS
|
||||||
fwin->languagemode = XkbGroup1Index;
|
fwin->languagemode = XkbGroup1Index;
|
||||||
fwin->last_languagemode = XkbGroup2Index;
|
fwin->last_languagemode = XkbGroup2Index;
|
||||||
|
wWindowGetLanguageLabel(fwin->languagemode, fwin->language_label);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fwin->depth = depth;
|
fwin->depth = depth;
|
||||||
@@ -145,6 +146,7 @@ void wFrameWindowUpdateBorders(WFrameWindow * fwin, int flags)
|
|||||||
theight = *fwin->title_min_height;
|
theight = *fwin->title_min_height;
|
||||||
} else {
|
} else {
|
||||||
theight = 0;
|
theight = 0;
|
||||||
|
fwin->flags.titlebar = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wPreferences.new_style == TS_NEW) {
|
if (wPreferences.new_style == TS_NEW) {
|
||||||
@@ -536,6 +538,8 @@ static void updateTitlebar(WFrameWindow * fwin)
|
|||||||
#ifdef XKB_BUTTON_HINT
|
#ifdef XKB_BUTTON_HINT
|
||||||
else {
|
else {
|
||||||
int bsize = theight - 7;
|
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->flags.hide_left_button || !fwin->left_button || fwin->flags.lbutton_dont_fit) {
|
||||||
if (fwin->language_button)
|
if (fwin->language_button)
|
||||||
wCoreConfigure(fwin->language_button, 3, (theight - bsize) / 2,
|
wCoreConfigure(fwin->language_button, 3, (theight - bsize) / 2,
|
||||||
@@ -950,6 +954,10 @@ void wFrameWindowPaint(WFrameWindow * fwin)
|
|||||||
remakeTexture(fwin, i);
|
remakeTexture(fwin, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef XKB_BUTTON_HINT
|
||||||
|
if (wPreferences.modelock)
|
||||||
|
wFrameWindowUpdateLanguageButton(fwin);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwin->flags.need_texture_change) {
|
if (fwin->flags.need_texture_change) {
|
||||||
@@ -1023,7 +1031,8 @@ void wFrameWindowPaint(WFrameWindow * fwin)
|
|||||||
allButtons = 0;
|
allButtons = 0;
|
||||||
}
|
}
|
||||||
#ifdef XKB_BUTTON_HINT
|
#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
|
#endif
|
||||||
|
|
||||||
if (fwin->title) {
|
if (fwin->title) {
|
||||||
@@ -1228,10 +1237,145 @@ int wFrameWindowChangeTitle(WFrameWindow *fwin, const char *new_title)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XKB_BUTTON_HINT
|
#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)
|
void wFrameWindowUpdateLanguageButton(WFrameWindow * fwin)
|
||||||
{
|
{
|
||||||
paintButton(fwin->language_button, fwin->title_texture[fwin->flags.state],
|
WScreen *scr = fwin->screen_ptr;
|
||||||
WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->languagebutton_image, True);
|
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 */
|
#endif /* XKB_BUTTON_HINT */
|
||||||
|
|
||||||
@@ -1286,7 +1430,7 @@ static void checkTitleSize(WFrameWindow * fwin)
|
|||||||
fwin->flags.incomplete_title = 0;
|
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;
|
WScreen *scr = button->screen_ptr;
|
||||||
GC copy_gc = scr->copy_gc;
|
GC copy_gc = scr->copy_gc;
|
||||||
@@ -1364,8 +1508,12 @@ static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long
|
|||||||
} else {
|
} else {
|
||||||
if (wPreferences.new_style == TS_OLD) {
|
if (wPreferences.new_style == TS_OLD) {
|
||||||
XSetForeground(dpy, copy_gc, scr->dark_pixel);
|
XSetForeground(dpy, copy_gc, scr->dark_pixel);
|
||||||
|
if (from_xpm)
|
||||||
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
|
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
|
||||||
button->width, button->height);
|
button->width, button->height);
|
||||||
|
else
|
||||||
|
XCopyArea(dpy, image->image, button->window, copy_gc,
|
||||||
|
left, 0, width, image->height, x, y);
|
||||||
} else {
|
} else {
|
||||||
XSetForeground(dpy, copy_gc, scr->black_pixel);
|
XSetForeground(dpy, copy_gc, scr->black_pixel);
|
||||||
XCopyArea(dpy, image->image, button->window, copy_gc,
|
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);
|
XSetForeground(dpy, copy_gc, color);
|
||||||
XSetBackground(dpy, copy_gc, texture->any.color.pixel);
|
XSetBackground(dpy, copy_gc, texture->any.color.pixel);
|
||||||
}
|
}
|
||||||
|
if (from_xpm)
|
||||||
XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width, button->height);
|
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
|
#ifdef XKB_BUTTON_HINT
|
||||||
if (button == fwin->language_button) {
|
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],
|
paintButton(button, fwin->title_texture[fwin->flags.state],
|
||||||
WMColorPixel(fwin->title_color[fwin->flags.state]),
|
WMColorPixel(fwin->title_color[fwin->flags.state]),
|
||||||
fwin->languagebutton_image, False);
|
fwin->languagebutton_image[lb_index],
|
||||||
|
False, False);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (button == fwin->left_button)
|
if (button == fwin->left_button)
|
||||||
paintButton(button, fwin->title_texture[fwin->flags.state],
|
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
|
else
|
||||||
paintButton(button, fwin->title_texture[fwin->flags.state],
|
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)
|
static void titlebarMouseDown(WObjDescriptor * desc, XEvent * event)
|
||||||
@@ -1437,7 +1594,7 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
|||||||
WCoreWindow *button = desc->self;
|
WCoreWindow *button = desc->self;
|
||||||
WPixmap *image;
|
WPixmap *image;
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
int done = 0, execute = 1;
|
int done = 0, execute = 1, from_xpm = True;
|
||||||
WTexture *texture;
|
WTexture *texture;
|
||||||
unsigned long pixel;
|
unsigned long pixel;
|
||||||
int clickButton = event->xbutton.button;
|
int clickButton = event->xbutton.button;
|
||||||
@@ -1458,13 +1615,18 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
|||||||
if (button == fwin->language_button) {
|
if (button == fwin->language_button) {
|
||||||
if (!wPreferences.modelock)
|
if (!wPreferences.modelock)
|
||||||
return;
|
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
|
#endif
|
||||||
|
|
||||||
pixel = WMColorPixel(fwin->title_color[fwin->flags.state]);
|
pixel = WMColorPixel(fwin->title_color[fwin->flags.state]);
|
||||||
texture = fwin->title_texture[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) {
|
while (!done) {
|
||||||
WMMaskEvent(dpy, LeaveWindowMask | EnterWindowMask | ButtonReleaseMask
|
WMMaskEvent(dpy, LeaveWindowMask | EnterWindowMask | ButtonReleaseMask
|
||||||
@@ -1472,12 +1634,12 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
|||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
case LeaveNotify:
|
case LeaveNotify:
|
||||||
execute = 0;
|
execute = 0;
|
||||||
paintButton(button, texture, pixel, image, False);
|
paintButton(button, texture, pixel, image, False, from_xpm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EnterNotify:
|
case EnterNotify:
|
||||||
execute = 1;
|
execute = 1;
|
||||||
paintButton(button, texture, pixel, image, True);
|
paintButton(button, texture, pixel, image, True, from_xpm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
@@ -1492,7 +1654,7 @@ static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
|
|||||||
WMHandleEvent(&ev);
|
WMHandleEvent(&ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
paintButton(button, texture, pixel, image, False);
|
paintButton(button, texture, pixel, image, False, from_xpm);
|
||||||
|
|
||||||
if (execute) {
|
if (execute) {
|
||||||
if (button == fwin->left_button) {
|
if (button == fwin->left_button) {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ typedef struct WFrameWindow {
|
|||||||
WPixmap *lbutton_image;
|
WPixmap *lbutton_image;
|
||||||
WPixmap *rbutton_image;
|
WPixmap *rbutton_image;
|
||||||
#ifdef XKB_BUTTON_HINT
|
#ifdef XKB_BUTTON_HINT
|
||||||
WPixmap *languagebutton_image;
|
WPixmap *languagebutton_image[2]; /* focused, unfocused */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
union WTexture **title_texture;
|
union WTexture **title_texture;
|
||||||
@@ -93,6 +93,7 @@ typedef struct WFrameWindow {
|
|||||||
#ifdef KEEP_XKB_LOCK_STATUS
|
#ifdef KEEP_XKB_LOCK_STATUS
|
||||||
int languagemode;
|
int languagemode;
|
||||||
int last_languagemode;
|
int last_languagemode;
|
||||||
|
char language_label[3]; /* 2-letter language code */
|
||||||
#endif /* KEEP_XKB_LOCK_STATUS */
|
#endif /* KEEP_XKB_LOCK_STATUS */
|
||||||
|
|
||||||
/* thing that uses this frame. passed as data to callbacks */
|
/* 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);
|
XSelectInput(dpy, scr->root_win, event_mask);
|
||||||
|
|
||||||
#ifdef KEEP_XKB_LOCK_STATUS
|
#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)
|
if (w_global.xext.xkb.supported)
|
||||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask);
|
XkbSelectEvents(dpy, XkbUseCoreKbd,
|
||||||
|
XkbIndicatorStateNotifyMask | XkbStateNotifyMask | XkbNewKeyboardNotifyMask,
|
||||||
|
XkbIndicatorStateNotifyMask | XkbStateNotifyMask | XkbNewKeyboardNotifyMask);
|
||||||
#else
|
#else
|
||||||
if (w_global.xext.xkb.supported)
|
if (w_global.xext.xkb.supported)
|
||||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask, XkbNewKeyboardNotifyMask);
|
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask, XkbNewKeyboardNotifyMask);
|
||||||
|
|||||||
84
src/window.c
84
src/window.c
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
#ifdef USE_XSHAPE
|
#ifdef USE_XSHAPE
|
||||||
#include <X11/extensions/shape.h>
|
#include <X11/extensions/shape.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -38,6 +39,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.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 */
|
/* For getting mouse wheel mappings from WINGs */
|
||||||
#include <WINGs/WINGs.h>
|
#include <WINGs/WINGs.h>
|
||||||
@@ -2304,14 +2311,6 @@ void wWindowUpdateButtonImages(WWindow *wwin)
|
|||||||
fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
|
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 */
|
/* close button */
|
||||||
|
|
||||||
@@ -3145,6 +3144,37 @@ static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XKB_BUTTON_HINT
|
#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)
|
static void windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event)
|
||||||
{
|
{
|
||||||
WWindow *wwin = data;
|
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)
|
if (event->xbutton.button != Button1 && event->xbutton.button != Button3)
|
||||||
return;
|
return;
|
||||||
tl = wwin->frame->languagemode;
|
tl = wwin->frame->languagemode;
|
||||||
|
|
||||||
|
/* 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->languagemode = wwin->frame->last_languagemode;
|
||||||
wwin->frame->last_languagemode = tl;
|
wwin->frame->last_languagemode = tl;
|
||||||
|
XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
|
||||||
|
}
|
||||||
|
/* Update label */
|
||||||
|
wWindowGetLanguageLabel(wwin->frame->languagemode, wwin->frame->language_label);
|
||||||
|
|
||||||
wSetFocusTo(scr, wwin);
|
wSetFocusTo(scr, wwin);
|
||||||
wwin->frame->languagebutton_image =
|
|
||||||
wwin->frame->screen_ptr->b_pixmaps[WBUT_XKBGROUP1 + wwin->frame->languagemode];
|
|
||||||
wFrameWindowUpdateLanguageButton(wwin->frame);
|
wFrameWindowUpdateLanguageButton(wwin->frame);
|
||||||
if (event->xbutton.button == Button3)
|
if (event->xbutton.button == Button3)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -405,4 +405,9 @@ void wWindowDeleteSavedState(WMagicNumber id);
|
|||||||
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
|
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
|
||||||
|
|
||||||
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
|
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
|
||||||
|
|
||||||
|
#ifdef XKB_BUTTON_HINT
|
||||||
|
void wWindowGetLanguageLabel(int group_index, char *label);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user