This is an automated email generated because a ref change occurred in the
git repository for project wmaker-crm.git.
The branch, master has been updated
via cc0a652ea87f24fea82875ea46270713ff70501c (commit)
via 80079cd343d02b11d8b7c78b454ea3635d85db66 (commit)
from 955c6793a6cf22b1b9fe33f8bf1198dd43bd1e18 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit cc0a652ea87f24fea82875ea46270713ff70501c
Author: David Maciejak <
david.m...@gmail.com>
Date: Mon, 16 Feb 2026 10:07:36 -0500
URL: <
https://repo.or.cz/wmaker-crm.git/cc0a652ea87f24fe>
WPrefs: add mouse wheel action to the expert panel
This patch is adding the mouse wheel action to be performed
on the expert text frame panel.
---
WINGs/WINGs/WINGs.h | 2 +
WPrefs.app/Expert.c | 130 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h
index f8bb53f10508..5ead0a8f5618 100644
--- a/WINGs/WINGs/WINGs.h
+++ b/WINGs/WINGs/WINGs.h
@@ -1533,6 +1533,8 @@ void WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type);
WMRect WMGetScrollViewVisibleRect(WMScrollView *sPtr);
+void WMScrollViewScrollPoint(WMScrollView * sPtr, WMPoint point);
+
WMScroller* WMGetScrollViewHorizontalScroller(WMScrollView *sPtr);
WMScroller* WMGetScrollViewVerticalScroller(WMScrollView *sPtr);
diff --git a/WPrefs.app/Expert.c b/WPrefs.app/Expert.c
index 6ef6307ddc8f..d2d330289116 100644
--- a/WPrefs.app/Expert.c
+++ b/WPrefs.app/Expert.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2014-2023 Window Maker Team
* Copyright (c) 1998-2003 Alfredo K. Kojima
- * Copyright (c) 2009-2023 Window Maker Team
+ * Copyright (c) 2009-2026 Window Maker Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -147,6 +147,8 @@ typedef struct _Panel {
WMButton *swi[wlengthof_nocheck(expert_options)];
WMTextField *textfield[wlengthof_nocheck(expert_options)];
+ WMScrollView *sv;
+ WMWidget *frame;
} _Panel;
@@ -167,6 +169,124 @@ static void changeIntTextfield(void *data, int delta)
WMSetTextFieldText(textfield, buffer);
}
+static void scrollViewWheelHandler(XEvent *event, void *data)
+{
+ _Panel *panel = (_Panel *) data;
+ int amount, viewH, contentH, newY, maxY;
+ WMRect rect;
+ WMPoint pt;
+
+ if (!panel || !panel->sv || !panel->frame)
+ return;
+
+ if (event->type != ButtonPress)
+ return;
+
+ if (event->xbutton.button != WINGsConfiguration.mouseWheelUp &&
+ event->xbutton.button != WINGsConfiguration.mouseWheelDown)
+ return;
+
+ rect = WMGetScrollViewVisibleRect(panel->sv);
+ viewH = rect.size.height;
+ contentH = WMWidgetHeight(panel->frame);
+
+ if (event->xbutton.state & ControlMask) {
+ amount = viewH; /* page */
+ } else if (event->xbutton.state & ShiftMask) {
+ amount = 1; /* line */
+ } else {
+ amount = viewH / 3; /* default */
+ if (amount == 0)
+ amount = 1;
+ }
+
+ if (event->xbutton.button == WINGsConfiguration.mouseWheelUp)
+ amount = -amount;
+
+ newY = rect.pos.y + amount;
+ maxY = contentH - viewH;
+ if (maxY < 0)
+ maxY = 0;
+ if (newY < 0)
+ newY = 0;
+ if (newY > maxY)
+ newY = maxY;
+
+ pt.x = rect.pos.x;
+ pt.y = newY;
+
+ WMScrollViewScrollPoint(panel->sv, pt);
+}
+
+static void scrollViewRealizeObserver(void *self, WMNotification *not)
+{
+ (void) not;
+ _Panel *panel = (_Panel *) self;
+ Display *dpy = NULL;
+ Window viewport_win = 0;
+ WMView *frameView;
+
+ if (!panel || !panel->frame)
+ return;
+
+ frameView = WMWidgetView(panel->frame);
+
+ if (frameView && frameView->parent) {
+ dpy = frameView->screen->display;
+ viewport_win = frameView->parent->window;
+ }
+
+ /* fallback: use the scrollview's view window if parent viewport not available */
+ if (!viewport_win && panel->sv) {
+ WMView *svView = WMWidgetView(panel->sv);
+ if (svView && svView->screen) {
+ dpy = svView->screen->display;
+ viewport_win = svView->window;
+ }
+ }
+
+ if (!dpy || viewport_win == 0)
+ return;
+
+ XGrabButton(dpy, WINGsConfiguration.mouseWheelUp, AnyModifier, viewport_win,
+ True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+ XGrabButton(dpy, WINGsConfiguration.mouseWheelDown, AnyModifier, viewport_win,
+ True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+}
+
+static void scrollViewPrepareForClose(Panel *p)
+{
+ _Panel *panel = (_Panel *) p;
+ Display *dpy = NULL;
+ Window viewport_win = 0;
+
+ if (!panel)
+ return;
+
+ if (panel->frame) {
+ WMView *frameView = WMWidgetView(panel->frame);
+ if (frameView && frameView->parent) {
+ dpy = frameView->screen->display;
+ viewport_win = frameView->parent->window;
+ }
+ }
+
+ if (!viewport_win && panel->sv) {
+ WMView *svView = WMWidgetView(panel->sv);
+ if (svView && svView->screen) {
+ dpy = svView->screen->display;
+ viewport_win = svView->window;
+ }
+ }
+
+ if (dpy && viewport_win != 0) {
+ XUngrabButton(dpy, WINGsConfiguration.mouseWheelUp, AnyModifier, viewport_win);
+ XUngrabButton(dpy, WINGsConfiguration.mouseWheelDown, AnyModifier, viewport_win);
+ }
+
+ WMRemoveNotificationObserver(panel);
+}
+
static void downButtonCallback(WMWidget *self, void *data)
{
(void) self;
@@ -290,7 +410,7 @@ static void createPanel(Panel *p)
default:
#ifdef DEBUG
- wwarning("export_options[%d].class = %d, this should not happen\n",
+ wwarning("expert_options[%d].class = %d, this should not happen\n",
i, expert_options[i].class);
#endif
state = expert_options[i].def_state;
@@ -302,6 +422,11 @@ static void createPanel(Panel *p)
WMMapSubwidgets(panel->box);
WMSetScrollViewContentView(sv, WMWidgetView(f));
+ /* keep references for the wheel handler and register it */
+ panel->sv = sv;
+ panel->frame = f;
+ WMCreateEventHandler(WMWidgetView(sv), ButtonPressMask, scrollViewWheelHandler, panel);
+ WMAddNotificationObserver(scrollViewRealizeObserver, panel, WMViewRealizedNotification, WMWidgetView(sv));
WMRealizeWidget(panel->box);
}
@@ -362,6 +487,7 @@ Panel *InitExpert(WMWidget *parent)
panel->callbacks.createWidgets = createPanel;
panel->callbacks.updateDomain = storeDefaults;
+ panel->callbacks.prepareForClose = scrollViewPrepareForClose;
AddSection(panel, ICON_FILE);
commit 80079cd343d02b11d8b7c78b454ea3635d85db66
Author: David Maciejak <
david.m...@gmail.com>
Date: Mon, 16 Feb 2026 10:52:16 -0500
URL: <
https://repo.or.cz/wmaker-crm.git/80079cd343d02b11>
WINGs: improve wlist widget
This patch is adding keyboard control to the wlist widget
(up/down/pgup/pgdw/home/end) and typeahead list search.
That component is for example used in the wmaker icon chooser,
and WPrefs keyboard shortcut, font conf panels.
---
WINGs/wlist.c | 488 +++++++++++++++++++++++++++++++++++++++++++++++++-
src/dialog.c | 1 +
2 files changed, 488 insertions(+), 1 deletion(-)
diff --git a/WINGs/wlist.c b/WINGs/wlist.c
index 8350095b3f16..4e6591cf3a02 100644
--- a/WINGs/wlist.c
+++ b/WINGs/wlist.c
@@ -1,5 +1,7 @@
#include "WINGsP.h"
+#include <ctype.h>
+#include <strings.h>
const char *WMListDidScrollNotification = "WMListDidScrollNotification";
const char *WMListSelectionDidChangeNotification = "WMListSelectionDidChangeNotification";
@@ -27,11 +29,15 @@ typedef struct W_List {
WMHandlerID *idleID; /* for updating the scroller after adding elements */
WMHandlerID *selectID; /* for selecting items in list while scrolling */
+ WMHandlerID *typeaheadID; /* for clearing typeahead buffer */
WMScroller *vScroller;
Pixmap doubleBuffer;
+ char *typeahead;
+ int typeaheadLen;
+
struct {
unsigned int allowMultipleSelection:1;
unsigned int allowEmptySelection:1;
@@ -48,6 +54,7 @@ typedef struct W_List {
#define DEFAULT_HEIGHT 150
#define SCROLL_DELAY 100
+#define TYPEAHEAD_CLEAR_DELAY 700
static void destroyList(List * lPtr);
static void paintList(List * lPtr);
@@ -62,6 +69,8 @@ static void scrollBackwardSelecting(void *data);
static void vScrollCallBack(WMWidget * scroller, void *self);
static void toggleItemSelection(WMList * lPtr, int index);
+static void jumpToFirstItemWithPrefix(WMList * lPtr, const char *prefix, int prefixLen);
+static void typeaheadTimeout(void *data);
static void updateGeometry(WMList * lPtr);
static void didResizeList(W_ViewDelegate * self, WMView * view);
@@ -113,6 +122,9 @@ WMList *WMCreateList(WMWidget * parent)
W_Screen *scrPtr = W_VIEW(parent)->screen;
lPtr = wmalloc(sizeof(List));
+ lPtr->typeahead = NULL;
+ lPtr->typeaheadLen = 0;
+ lPtr->typeaheadID = NULL;
lPtr->widgetClass = WC_List;
@@ -129,7 +141,8 @@ WMList *WMCreateList(WMWidget * parent)
| ClientMessageMask, handleEvents, lPtr);
WMCreateEventHandler(lPtr->view, ButtonPressMask | ButtonReleaseMask
- | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, lPtr);
+ | EnterWindowMask | LeaveWindowMask | ButtonMotionMask
+ | KeyPressMask, handleActionEvents, lPtr);
lPtr->itemHeight = WMFontHeight(scrPtr->normalFont) + 1;
@@ -288,6 +301,14 @@ void WMClearList(WMList * lPtr)
WMDeleteTimerHandler(lPtr->selectID);
lPtr->selectID = NULL;
}
+ if (lPtr->typeaheadID) {
+ WMDeleteTimerHandler(lPtr->typeaheadID);
+ lPtr->typeaheadID = NULL;
+ }
+ if (lPtr->typeahead) {
+ lPtr->typeahead[0] = '\0';
+ lPtr->typeaheadLen = 0;
+ }
if (lPtr->view->flags.realized) {
updateScroller(lPtr);
}
@@ -923,6 +944,85 @@ static void toggleItemSelection(WMList * lPtr, int index)
}
}
+static int findItemWithPrefix(List * lPtr, const char *prefix, int prefixLen)
+{
+ if (prefixLen <= 0)
+ return -1;
+
+ int i, itemCount;
+
+ itemCount = WMGetArrayItemCount(lPtr->items);
+ for (i = 0; i < itemCount; i++) {
+ WMListItem *item = WMGetFromArray(lPtr->items, i);
+
+ if (!item || !item->text || item->text[0] == '\0')
+ continue;
+ if (strncasecmp(item->text, prefix, prefixLen) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static void jumpToFirstItemWithPrefix(WMList * lPtr, const char *prefix, int prefixLen)
+{
+ int index, oldTop, visibleCount;
+
+ index = findItemWithPrefix(lPtr, prefix, prefixLen);
+ if (index < 0)
+ return;
+
+ if (lPtr->flags.allowMultipleSelection) {
+ WMRange range;
+
+ range.position = index;
+ range.count = 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMSelectListItem(lPtr, index);
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+
+ visibleCount = lPtr->fullFitLines + lPtr->flags.dontFitAll;
+ if (visibleCount < 1)
+ visibleCount = 1;
+
+ oldTop = lPtr->topItem;
+ if (index < lPtr->topItem) {
+ lPtr->topItem = index;
+ } else {
+ if (lPtr->flags.dontFitAll) {
+ if (lPtr->fullFitLines <= 0) {
+ lPtr->topItem = index;
+ } else {
+ int lastFullyVisible = lPtr->topItem + lPtr->fullFitLines - 1;
+ if (index > lastFullyVisible)
+ lPtr->topItem = index - lPtr->fullFitLines + 1;
+ }
+ } else if (index >= lPtr->topItem + visibleCount) {
+ lPtr->topItem = index - visibleCount + 1;
+ }
+ }
+ if (lPtr->topItem < 0)
+ lPtr->topItem = 0;
+
+ if (lPtr->view->flags.realized && lPtr->topItem != oldTop)
+ updateScroller(lPtr);
+}
+
+static void typeaheadTimeout(void *data)
+{
+ List *lPtr = (List *) data;
+
+ lPtr->typeaheadID = NULL;
+ if (lPtr->typeahead) {
+ lPtr->typeahead[0] = '\0';
+ lPtr->typeaheadLen = 0;
+ }
+}
+
static void handleActionEvents(XEvent * event, void *data)
{
List *lPtr = (List *) data;
@@ -962,6 +1062,7 @@ static void handleActionEvents(XEvent * event, void *data)
WMDeleteTimerHandler(lPtr->selectID);
lPtr->selectID = NULL;
}
+ WMSetFocusToWidget(lPtr);
break;
case LeaveNotify:
@@ -973,6 +1074,9 @@ static void handleActionEvents(XEvent * event, void *data)
lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollBackwardSelecting, lPtr);
}
}
+ WMWidget *parentWidget = WMWidgetOfView(lPtr->view->parent);
+ if (parentWidget)
+ WMSetFocusToWidget(parentWidget);
break;
case ButtonPress:
@@ -1079,6 +1183,381 @@ static void handleActionEvents(XEvent * event, void *data)
prevItem = tmp;
}
break;
+
+ case KeyPress:
+ char buffer[16];
+ KeySym ksym;
+ Status status;
+ int len;
+ WMScreen *scr = lPtr->view->screen;
+ XWindowAttributes wattr;
+
+ if (event->xkey.state & (ControlMask | Mod1Mask))
+ break;
+
+ if (!(XGetWindowAttributes(scr->display, lPtr->view->window, &wattr) && wattr.map_state == IsViewable))
+ break;
+
+ len = W_LookupString(lPtr->view, &event->xkey, buffer, (int)sizeof(buffer) - 1, &ksym, &status);
+ if (len < 0)
+ break;
+ if (len > 0)
+ buffer[len] = '\0';
+
+ /* Handle navigation keys */
+ switch (ksym) {
+ case XK_Up: {
+ int newRow;
+ int itemCount = WMGetArrayItemCount(lPtr->items);
+ int cur = WMGetListSelectedItemRow(lPtr);
+
+ if (lPtr->flags.allowMultipleSelection && WMGetArrayItemCount(lPtr->selectedItems) > 0) {
+ WMListItem *lastSel = WMGetFromArray(lPtr->selectedItems, WMGetArrayItemCount(lPtr->selectedItems) - 1);
+ if (lastSel)
+ cur = WMGetFirstInArray(lPtr->items, lastSel);
+ }
+
+ if (cur == WLNotFound)
+ cur = lPtr->topItem;
+ newRow = cur - 1;
+ if (newRow < 0)
+ newRow = 0;
+
+ if (newRow != cur && itemCount > 0) {
+ if (lPtr->flags.allowMultipleSelection) {
+ if (event->xkey.state & ShiftMask) {
+ WMRange range;
+ int anchor = WMGetListSelectedItemRow(lPtr);
+ if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+ anchor = cur;
+ }
+
+ range.position = anchor;
+ if (newRow >= anchor)
+ range.count = newRow - anchor + 1;
+ else
+ range.count = newRow - anchor - 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMRange range = { .position = newRow, .count = 1 };
+ WMSetListSelectionToRange(lPtr, range);
+ lastClicked = newRow;
+ }
+ } else {
+ WMSelectListItem(lPtr, newRow);
+ lastClicked = newRow;
+ }
+
+ /* Ensure visibility */
+ if (newRow < lPtr->topItem) {
+ lPtr->topItem = newRow;
+ if (lPtr->view->flags.realized)
+ updateScroller(lPtr);
+ }
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+ break;
+ }
+ case XK_Down: {
+ int newRow;
+ int itemCount = WMGetArrayItemCount(lPtr->items);
+ int cur = WMGetListSelectedItemRow(lPtr);
+
+ if (lPtr->flags.allowMultipleSelection && WMGetArrayItemCount(lPtr->selectedItems) > 0) {
+ WMListItem *lastSel = WMGetFromArray(lPtr->selectedItems, WMGetArrayItemCount(lPtr->selectedItems) - 1);
+ if (lastSel)
+ cur = WMGetFirstInArray(lPtr->items, lastSel);
+ }
+
+ if (cur == WLNotFound)
+ cur = lPtr->topItem;
+ newRow = cur + 1;
+ if (newRow >= itemCount)
+ newRow = itemCount - 1;
+
+ if (newRow != cur && itemCount > 0) {
+ if (lPtr->flags.allowMultipleSelection) {
+ if (event->xkey.state & ShiftMask) {
+ WMRange range;
+ int anchor = WMGetListSelectedItemRow(lPtr);
+ if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+ anchor = cur;
+ }
+
+ range.position = anchor;
+ if (newRow >= anchor)
+ range.count = newRow - anchor + 1;
+ else
+ range.count = newRow - anchor - 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMRange range = { .position = newRow, .count = 1 };
+ WMSetListSelectionToRange(lPtr, range);
+ lastClicked = newRow;
+ }
+ } else {
+ WMSelectListItem(lPtr, newRow);
+ lastClicked = newRow;
+ }
+
+ /* Ensure visibility */
+ if (newRow > (lPtr->topItem + lPtr->fullFitLines - 1)) {
+ lPtr->topItem = newRow - lPtr->fullFitLines + 1;
+ if (lPtr->topItem < 0)
+ lPtr->topItem = 0;
+ /* Ensure we don't scroll past the end */
+ if (lPtr->topItem + lPtr->fullFitLines > itemCount)
+ lPtr->topItem = itemCount - lPtr->fullFitLines;
+ if (lPtr->topItem < 0)
+ lPtr->topItem = 0;
+ if (lPtr->view->flags.realized)
+ updateScroller(lPtr);
+ }
+
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+ break;
+ }
+ case XK_Page_Up: {
+ int newRow;
+ int page = lPtr->fullFitLines > 0 ? lPtr->fullFitLines : 1;
+ int cur = WMGetListSelectedItemRow(lPtr);
+
+ if (cur == WLNotFound)
+ cur = lPtr->topItem;
+ newRow = cur - page;
+ if (newRow < 0)
+ newRow = 0;
+
+ if (newRow != cur) {
+ if (lPtr->flags.allowMultipleSelection) {
+ if (event->xkey.state & ShiftMask) {
+ WMRange range;
+ int anchor = WMGetListSelectedItemRow(lPtr);
+ if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+ anchor = cur;
+ }
+
+ range.position = anchor;
+ if (newRow >= anchor)
+ range.count = newRow - anchor + 1;
+ else
+ range.count = newRow - anchor - 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMRange range = { .position = newRow, .count = 1 };
+ WMSetListSelectionToRange(lPtr, range);
+ lastClicked = newRow;
+ }
+ } else {
+ WMSelectListItem(lPtr, newRow);
+ lastClicked = newRow;
+ }
+ if (newRow < lPtr->topItem) {
+ lPtr->topItem = newRow;
+ if (lPtr->view->flags.realized)
+ updateScroller(lPtr);
+ }
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+ break;
+ }
+ case XK_Page_Down: {
+ int newRow;
+ int page = lPtr->fullFitLines > 0 ? lPtr->fullFitLines : 1;
+ int itemCount = WMGetArrayItemCount(lPtr->items);
+ int cur = WMGetListSelectedItemRow(lPtr);
+
+ if (cur == WLNotFound)
+ cur = lPtr->topItem;
+ newRow = cur + page;
+ if (newRow >= itemCount)
+ newRow = itemCount - 1;
+
+ if (newRow != cur && itemCount > 0) {
+ if (lPtr->flags.allowMultipleSelection) {
+ if (event->xkey.state & ShiftMask) {
+ WMRange range;
+ int anchor = WMGetListSelectedItemRow(lPtr);
+ if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+ anchor = cur;
+ }
+
+ range.position = anchor;
+ if (newRow >= anchor)
+ range.count = newRow - anchor + 1;
+ else
+ range.count = newRow - anchor - 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMRange range = { .position = newRow, .count = 1 };
+ WMSetListSelectionToRange(lPtr, range);
+ lastClicked = newRow;
+ }
+ } else {
+ WMSelectListItem(lPtr, newRow);
+ lastClicked = newRow;
+ }
+
+ /* Ensure visibility */
+ if (newRow > (lPtr->topItem + lPtr->fullFitLines - 1)) {
+ lPtr->topItem = newRow - lPtr->fullFitLines + 1;
+ if (lPtr->topItem < 0)
+ lPtr->topItem = 0;
+ /* Ensure we don't scroll past the end */
+ if (lPtr->topItem + lPtr->fullFitLines > itemCount)
+ lPtr->topItem = itemCount - lPtr->fullFitLines;
+ if (lPtr->topItem < 0)
+ lPtr->topItem = 0;
+ if (lPtr->view->flags.realized)
+ updateScroller(lPtr);
+ }
+
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+ break;
+ }
+ case XK_Home: {
+ int itemCount = WMGetArrayItemCount(lPtr->items);
+ if (itemCount > 0) {
+ int newRow = 0;
+ if (lPtr->flags.allowMultipleSelection) {
+ if (event->xkey.state & ShiftMask) {
+ WMRange range;
+ int anchor = WMGetListSelectedItemRow(lPtr);
+ if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+ anchor = lPtr->topItem;
+ }
+
+ range.position = anchor;
+ if (newRow >= anchor)
+ range.count = newRow - anchor + 1;
+ else
+ range.count = newRow - anchor - 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMRange range = { .position = newRow, .count = 1 };
+ WMSetListSelectionToRange(lPtr, range);
+ lastClicked = newRow;
+ }
+ } else {
+ WMSelectListItem(lPtr, newRow);
+ lastClicked = newRow;
+ }
+ if (newRow < lPtr->topItem) {
+ lPtr->topItem = newRow;
+ if (lPtr->view->flags.realized)
+ updateScroller(lPtr);
+ }
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+ break;
+ }
+ case XK_End: {
+ int itemCount = WMGetArrayItemCount(lPtr->items);
+ if (itemCount > 0) {
+ int newRow = itemCount - 1;
+ if (lPtr->flags.allowMultipleSelection) {
+ if (event->xkey.state & ShiftMask) {
+ WMRange range;
+ int anchor = WMGetListSelectedItemRow(lPtr);
+ if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+ anchor = lPtr->topItem;
+ }
+
+ range.position = anchor;
+ if (newRow >= anchor)
+ range.count = newRow - anchor + 1;
+ else
+ range.count = newRow - anchor - 1;
+ WMSetListSelectionToRange(lPtr, range);
+ } else {
+ WMRange range = { .position = newRow, .count = 1 };
+ WMSetListSelectionToRange(lPtr, range);
+ lastClicked = newRow;
+ }
+ } else {
+ WMSelectListItem(lPtr, newRow);
+ lastClicked = newRow;
+ }
+
+ /* Ensure the last item is fully visible */
+ lPtr->topItem = itemCount - lPtr->fullFitLines;
+ if (lPtr->topItem < 0)
+ lPtr->topItem = 0;
+ if (lPtr->view->flags.realized)
+ updateScroller(lPtr);
+
+ /* Trigger action callback */
+ if (lPtr->action)
+ (*lPtr->action) (lPtr, lPtr->clientData);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* If we handled a navigation keysym, avoid falling through to typeahead logic */
+ if (ksym == XK_Up || ksym == XK_Down || ksym == XK_Page_Up || ksym == XK_Page_Down || ksym == XK_Home || ksym == XK_End)
+ break;
+
+ if (len <= 0)
+ break;
+
+ buffer[len] = '\0';
+
+ if (ksym == XK_Escape) {
+ if (lPtr->typeaheadID) {
+ WMDeleteTimerHandler(lPtr->typeaheadID);
+ lPtr->typeaheadID = NULL;
+ }
+ if (lPtr->typeahead) {
+ lPtr->typeahead[0] = '\0';
+ lPtr->typeaheadLen = 0;
+ }
+ break;
+ }
+
+ if (ksym == XK_BackSpace) {
+ if (lPtr->typeaheadLen > 0 && lPtr->typeahead) {
+ lPtr->typeaheadLen--;
+ lPtr->typeahead[lPtr->typeaheadLen] = '\0';
+ }
+ } else if (len == 1 && isalnum((unsigned char)buffer[0])) {
+ if (!lPtr->typeahead) {
+ lPtr->typeahead = wmalloc(2);
+ lPtr->typeaheadLen = 0;
+ }
+ lPtr->typeahead = wrealloc(lPtr->typeahead, lPtr->typeaheadLen + 2);
+ lPtr->typeahead[lPtr->typeaheadLen] = buffer[0];
+ lPtr->typeaheadLen++;
+ lPtr->typeahead[lPtr->typeaheadLen] = '\0';
+ } else {
+ break;
+ }
+
+ if (lPtr->typeaheadLen > 0)
+ jumpToFirstItemWithPrefix(lPtr, lPtr->typeahead, lPtr->typeaheadLen);
+
+ if (lPtr->typeaheadID) {
+ WMDeleteTimerHandler(lPtr->typeaheadID);
+ lPtr->typeaheadID = NULL;
+ }
+ if (lPtr->typeaheadLen > 0)
+ lPtr->typeaheadID = WMAddTimerHandler(TYPEAHEAD_CLEAR_DELAY, typeaheadTimeout, lPtr);
+ break;
+
}
if (lPtr->topItem != topItem)
WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
@@ -1126,6 +1605,10 @@ static void destroyList(List * lPtr)
WMDeleteTimerHandler(lPtr->selectID);
lPtr->selectID = NULL;
+ if (lPtr->typeaheadID)
+ WMDeleteTimerHandler(lPtr->typeaheadID);
+ lPtr->typeaheadID = NULL;
+
if (lPtr->selectedItems)
WMFreeArray(lPtr->selectedItems);
@@ -1135,6 +1618,9 @@ static void destroyList(List * lPtr)
if (lPtr->doubleBuffer)
XFreePixmap(lPtr->view->screen->display, lPtr->doubleBuffer);
+ if (lPtr->typeahead)
+ wfree(lPtr->typeahead);
+
WMRemoveNotificationObserver(lPtr);
wfree(lPtr);
diff --git a/src/dialog.c b/src/dialog.c
index 98e0b5154252..82c20965bd65 100644
--- a/src/dialog.c
+++ b/src/dialog.c
@@ -1083,6 +1083,7 @@ Bool wIconChooserDialog(WScreen *scr, char **file, const char *instance, const c
WMMapWidget(panel->win);
wWindowMap(wwin);
+ wSetFocusTo(scr, wwin);
while (!panel->done) {
XEvent event;
-----------------------------------------------------------------------
Summary of changes:
WINGs/WINGs/WINGs.h | 2 +
WINGs/wlist.c | 488 +++++++++++++++++++++++++++++++++++++++++++-
WPrefs.app/Expert.c | 130 +++++++++++-
src/dialog.c | 1 +
4 files changed, 618 insertions(+), 3 deletions(-)
repo.or.cz automatic notification. Contact project admin
crm...@gmail.com
if you want to unsubscribe, or site admin
ad...@repo.or.cz if you receive
no reply.
--
wmaker-crm.git ("The Window Maker window manager")