Compare commits

..
Author SHA1 Message Date
trurl 4732296762 Port WINGs data.c (WMData) to Rust.
This is not tested super well, but I hope we can be rid of it soon enough. (Once
we have WMPropList migrated, WMData and other WINGs data structures should be
easier to prune.)
2025-10-04 12:31:54 -04:00
trurl 3846a5017c Correct oversight in how WMMapArray is supposed to work. 2025-10-03 22:55:52 -04:00
trurl d736af8321 Drop WMData's destructor field.
WMData always owns its data and allocates it with wmalloc, so we can always free
it with wfree (and don't need to call anything else).
2025-10-03 01:19:07 -04:00
trurl 506e14cd24 Eliminate the WINGs function WMCreateDataWithBytesNoCopy.
This constructor was only needed in one particular place. We can duplidate the
data instead of borrowing it. This ensures that WMData always owns its data
segment, which simplifies porting to Rust significantly.
2025-10-03 01:16:32 -04:00
trurl ee047b63df Eliminate the unused WINGs function WMGetSubdataWithRange. 2025-10-03 01:02:40 -04:00
trurl 0b5033a0e4 Eliminate the unused WINGs function WMCreatePLDataWithBytesNoCopy. 2025-10-03 01:01:15 -04:00
trurl f6c897de95 Forgot to add new array.rs impl. 2025-10-03 00:50:02 -04:00
trurl 249dee3874 Fix const qualifier on strings returned by wgethomedir. 2025-10-03 00:44:58 -04:00
trurl 0d6f5b6d57 Reimplement WINGs array.c in Rust.
This is another utility that should not be used in any new (Rust) code. (We
should prefer Vec or something similar.) This should be removed once dependents
are ported to Rust.
2025-10-03 00:43:56 -04:00
trurl e4c619bb14 Replace most WUtil functions in findfile.c with Rust impls.
This is not a bug-for-bug reimplementation, and it may need some shaking down to
ensure that everything still works. Once their dependents are ported, it would
be appropriate to dispose of them.
2025-10-02 14:26:37 -04:00
trurl adb601eaa9 Use free() on memory returned by FcNameUnparse and hand back wfree-managed pointers from our functions.
This is necessary because we now allocate memory through a special allocator of
our own on the Rust side. Passing raw malloc'd pointers to wfree will break
things.
2025-10-02 13:26:57 -04:00
trurl a07bdb747d Remember to AC_SUBST the Rust compiler environment variables so they're visible in Makefiles. 2025-10-02 13:24:51 -04:00
trurl d7bde34561 Port custom allocators (WINGs memory.c) to Rust.
This introduces the crate wutil-rs, which is intended to be the destination for
migrating the API of WINGs/WINGs/WUtil.h to Rust.
2025-09-21 15:31:47 -04:00
trurl ceeddfb9da Rip out Boehm GC support.
This is done to simplify memory management across the boundary between C and
Rust. While rewriting WINGs, we may want to be able to malloc/free with the libc
allocator on both sides of that divide.
2025-09-19 20:04:10 -04:00
162 changed files with 6885 additions and 9770 deletions
+1 -17
View File
@@ -83,20 +83,13 @@ WINGs/Tests/wtest
WPrefs.app/WPrefs
# These files are generated from make rules
wmlib/wmlib.pc
wrlib/wrlib.pc
WINGs/WINGs.pc
WINGs/WUtil.pc
doc/wmaker.1
doc/wmsetbg.1
wrlib/libwraster.map
WindowMaker/appearance.menu
WindowMaker/appearance.menu.fy
WindowMaker/appearance.menu.nl
WindowMaker/appearance.menu.sr
WindowMaker/menu
WindowMaker/menu.bg
WindowMaker/menu.fi
@@ -106,7 +99,6 @@ WindowMaker/menu.ko
WindowMaker/menu.nl
WindowMaker/menu.ro
WindowMaker/menu.sk
WindowMaker/menu.sr
WindowMaker/menu.zh_TW
WindowMaker/plmenu
WindowMaker/plmenu.bg
@@ -119,7 +111,6 @@ WindowMaker/plmenu.nl
WindowMaker/plmenu.pl
WindowMaker/plmenu.ro
WindowMaker/plmenu.sk
WindowMaker/plmenu.sr
WindowMaker/plmenu.zh_CN
WindowMaker/plmenu.zh_TW
WindowMaker/wmmacros
@@ -151,11 +142,4 @@ WPrefs.app/WPrefs.desktop
.pc
# Rust stuff.
/**/target/**
WINGs/wings-rs-tests/Cargo.lock
WINGs/wings-rs/Cargo.lock
WINGs/wings-rs/src/WINGsP.rs
wmaker-rs/Cargo.lock
wrlib-rs/src/ffi.rs
wrlib-rs/Cargo.lock
wutil-rs/Cargo.lock
/*/target/**
+1 -1
View File
@@ -39,7 +39,7 @@ ACLOCAL_AMFLAGS = -I m4
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-silent-rules LINGUAS='*'
SUBDIRS = wrlib wrlib-rs wutil-rs WINGs wmaker-rs src util po WindowMaker wmlib WPrefs.app doc
SUBDIRS = wrlib wutil-rs WINGs wmaker-rs src util po WindowMaker wmlib WPrefs.app doc
DIST_SUBDIRS = $(SUBDIRS) test
EXTRA_DIST = TODO BUGS BUGFORM FAQ INSTALL \
+15 -5
View File
@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS =
SUBDIRS = WINGs wings-rs wings-rs-tests . po Documentation Resources
SUBDIRS = WINGs . po Documentation Resources
DIST_SUBDIRS = $(SUBDIRS) Tests Examples Extras
libWINGs_la_LDFLAGS = -version-info @WINGS_VERSION@
@@ -10,15 +10,16 @@ libWUtil_la_LDFLAGS = -version-info @WUTIL_VERSION@
lib_LTLIBRARIES = libWUtil.la libWINGs.la
wutilrs = $(top_builddir)/wutil-rs/target/debug/libwutil_rs.a
wraster = $(top_builddir)/wrlib/libwraster.la
LDADD= libWUtil.la libWINGs.la $(wraster) @INTLIBS@
libWINGs_la_LIBADD = libWUtil.la $(wraster) @XLIBS@ @XFT_LIBS@ @FCLIBS@ @LIBM@ @PANGO_LIBS@
LDADD= libWUtil.la libWINGs.la $(wraster) $(wutilrs) @INTLIBS@
libWINGs_la_LIBADD = libWUtil.la $(wraster) $(wutilrs) @XLIBS@ @XFT_LIBS@ @FCLIBS@ @LIBM@ @PANGO_LIBS@
libWUtil_la_LIBADD = @LIBBSD@ $(wutilrs)
EXTRA_DIST = BUGS make-rgb Examples Extras Tests
# wbutton.c
libWINGs_la_SOURCES = \
configuration.c \
@@ -39,6 +40,8 @@ libWINGs_la_SOURCES = \
wevent.c \
wfilepanel.c \
wframe.c \
wfont.c \
wfontpanel.c \
widgets.c \
winputmethod.c \
wlabel.c \
@@ -61,19 +64,26 @@ libWINGs_la_SOURCES = \
wwindow.c
libWUtil_la_SOURCES = \
bagtree.c \
error.c \
error.h \
findfile.c \
handlers.c \
hashtable.c \
menuparser.c \
menuparser.h \
menuparser_macros.c \
misc.c \
notification.c \
proplist.c \
string.c \
tree.c \
userdefaults.c \
userdefaults.h \
usleep.c \
wapplication.c \
wconfig.h
wconfig.h \
wutil.c
AM_CFLAGS = @PANGO_CFLAGS@
+3 -6
View File
@@ -4,17 +4,14 @@ AUTOMAKE_OPTIONS =
noinst_PROGRAMS = wtest wmquery wmfile testmywidget
LDADD= $(top_builddir)/WINGs/libWINGs.la \
$(top_builddir)/wrlib/libwraster.la \
LDADD= $(top_builddir)/WINGs/libWINGs.la $(top_builddir)/wrlib/libwraster.la \
$(top_builddir)/WINGs/libWUtil.la \
$(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a \
@XFT_LIBS@ @INTLIBS@ @XLIBS@ @FCLIBS@ @PANGO_LIBS@
@XFT_LIBS@ @INTLIBS@ @XLIBS@
testmywidget_SOURCES = testmywidget.c mywidget.c mywidget.h
wtest_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la \
$(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a
wtest_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la
EXTRA_DIST = logo.xpm upbtn.xpm wm.html wm.png
+25 -14
View File
@@ -132,7 +132,7 @@ typedef enum {
} WMButtonType;
/* button behaviour masks */
typedef enum {
enum {
WBBSpringLoadedMask = (1 << 0),
WBBPushInMask = (1 << 1),
WBBPushChangeMask = (1 << 2),
@@ -140,7 +140,7 @@ typedef enum {
WBBStateLightMask = (1 << 5),
WBBStateChangeMask = (1 << 6),
WBBStatePushMask = (1 << 7)
} WMButtonBehaviorMask;
};
/* frame title positions */
@@ -233,7 +233,7 @@ typedef enum {
/* text movement types */
typedef enum {
enum {
WMIllegalTextMovement,
WMReturnTextMovement,
WMEscapeTextMovement,
@@ -243,13 +243,13 @@ typedef enum {
WMRightTextMovement,
WMUpTextMovement,
WMDownTextMovement
} WMTextMovementType;
};
/* text field special events */
typedef enum {
enum {
WMInsertTextEvent,
WMDeleteTextEvent
} WMTextFieldSpecialEventType;
};
enum {
@@ -533,11 +533,14 @@ typedef struct WMBrowserDelegate {
typedef struct WMTextFieldDelegate {
void *data;
void (*didBeginEditing)(struct WMTextFieldDelegate *self, WMTextMovementType reason);
void (*didBeginEditing)(struct WMTextFieldDelegate *self,
WMNotification *notif);
void (*didChange)(struct WMTextFieldDelegate *self, WMTextFieldSpecialEventType reason);
void (*didChange)(struct WMTextFieldDelegate *self,
WMNotification *notif);
void (*didEndEditing)(struct WMTextFieldDelegate *self, WMTextMovementType reason);
void (*didEndEditing)(struct WMTextFieldDelegate *self,
WMNotification *notif);
Bool (*shouldBeginEditing)(struct WMTextFieldDelegate *self,
WMTextField *tPtr);
@@ -778,8 +781,12 @@ void WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs);
/* ---[ WINGs/wfont.c ]--------------------------------------------------- */
Bool WMIsAntialiasingEnabled(WMScreen *scrPtr);
WMFont* WMCreateFont(WMScreen *scrPtr, const char *fontName);
WMFont* WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style);
WMFont* WMRetainFont(WMFont *font);
void WMReleaseFont(WMFont *font);
@@ -788,10 +795,12 @@ char* WMGetFontName(WMFont *font);
unsigned int WMFontHeight(WMFont *font);
unsigned int WMFontAscent(WMFont *font);
void WMGetScaleBaseFromSystemFont(WMScreen *scrPtr, int *alphabetWidth, int *fontHeight);
void WMSetWidgetDefaultFont(WMScreen *scr, WMFont *font);
void WMSetWidgetDefaultBoldFont(WMScreen *scr, WMFont *font);
WMFont* WMDefaultSystemFont(WMScreen *scrPtr);
WMFont* WMDefaultBoldSystemFont(WMScreen *scrPtr);
@@ -809,8 +818,6 @@ void WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color,
int WMWidthOfString(WMFont *font, const char *text, int length);
struct _XftFont *WMFontXftFont(WMFont *font);
/* ---[ WINGs/wpixmap.c ]------------------------------------------------- */
WMPixmap* WMRetainPixmap(WMPixmap *pixmap);
@@ -1039,7 +1046,11 @@ void WMCloseWindow(WMWindow *win);
void WMSetButtonAction(WMButton *bPtr, WMAction *action, void *clientData);
WMButton* WMCreateCommandButton(WMWidget *parent);
#define WMCreateCommandButton(parent) \
WMCreateCustomButton((parent), WBBSpringLoadedMask\
|WBBPushInMask\
|WBBPushLightMask\
|WBBPushChangeMask)
#define WMCreateRadioButton(parent) \
WMCreateButton((parent), WBTRadio)
+29 -11
View File
@@ -122,6 +122,8 @@ typedef struct W_Screen {
WMOpenPanel *sharedOpenPanel;
WMSavePanel *sharedSavePanel;
struct W_FontPanel *sharedFontPanel;
struct W_ColorPanel *sharedColorPanel;
Pixmap stipple;
@@ -150,11 +152,11 @@ typedef struct W_Screen {
GC drawImStringGC; /* for WMDrawImageString() */
WMFont *normalFont;
struct W_Font *normalFont;
WMFont *boldFont;
struct W_Font *boldFont;
void *fontCache; /* owned/maintainted by wings-rs/src/screen.rs */
WMHashTable *fontCache;
Bool antialiasedText;
@@ -367,12 +369,8 @@ Bool W_CheckIdleHandlers(void);
void W_CheckTimerHandlers(void);
/*
* Returns the duration in milliseconds until the next timer event should go off
* (saturating at INT_MAX). If there is no such timer event, returns a negative
* value.
*/
int W_DelayUntilNextTimerEvent_millis();
Bool W_HandleInputEvents(Bool waitForInput, int inputfd);
/* ---[ notification.c ]-------------------------------------------------- */
@@ -380,7 +378,9 @@ void W_InitNotificationCenter(void);
void W_ReleaseNotificationCenter(void);
void W_ClearNotificationCenter(void);
void W_FlushASAPNotificationQueue(void);
void W_FlushIdleNotificationQueue(void);
/* ---[ selection.c ]----------------------------------------------------- */
@@ -445,6 +445,24 @@ typedef struct W_EventHandler {
void W_CallDestroyHandlers(W_View *view);
/* ---[ wfont.c ]--------------------------------------------------------- */
typedef struct W_Font {
struct W_Screen *screen;
struct _XftFont *font;
short height;
short y;
short refCount;
char *name;
@USE_PANGO@ PangoLayout *layout;
} W_Font;
#define W_FONTID(f) (f)->font->fid
/* ---[ widgets.c ]------------------------------------------------------- */
#define WC_UserWidget 128
@@ -490,7 +508,7 @@ void W_DrawReliefWithGC(W_Screen *scr, Drawable d, int x, int y,
GC black, GC dark, GC light, GC white);
void W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor,
WMFont *font, WMReliefType relief, const char *text,
W_Font *font, WMReliefType relief, const char *text,
WMAlignment alignment, W_Pixmap *image,
WMImagePosition position, WMColor *backColor, int ofs);
+167 -29
View File
@@ -156,7 +156,12 @@ typedef struct {
typedef struct WMHashEnumerator WMHashEnumerator;
/* DO NOT ACCESS THE CONTENTS OF THIS STRUCT */
typedef struct {
void *table;
void *nextItem;
int index;
} WMHashEnumerator;
typedef struct {
@@ -164,11 +169,15 @@ typedef struct {
unsigned (*hash)(const void *);
/* NULL is pointer compare */
Bool (*keyIsEqual)(const void *, const void *);
/* NULL does nothing */
void* (*retainKey)(const void *);
/* NULL does nothing */
void (*releaseKey)(const void *);
} WMHashTableCallbacks;
typedef int WMArrayIterator;
typedef int WMBagIterator;
typedef void *WMBagIterator;
typedef void WMNotificationObserverAction(void *observerData,
@@ -240,9 +249,6 @@ char* wgethomedir(void);
/* ---[ WINGs/proplist.c ]------------------------------------------------ */
/*
* Creates the directory path and all its parents.
*/
int wmkdirhier(const char *path);
int wrmdirhier(const char *path);
@@ -266,9 +272,14 @@ char* wstrconcat(const char *str1, const char *str2);
* so always assign the returned address to avoid dangling pointers. */
char* wstrappend(char *dst, const char *src);
size_t wstrlcpy(char *, const char *, size_t);
size_t wstrlcat(char *, const char *, size_t);
void wtokensplit(char *command, char ***argv, int *argc);
char* wtokennext(char *word, char **next);
char* wtokenjoin(char **list, int count);
void wtokenfree(char **tokens, int count);
@@ -297,24 +308,37 @@ void wusleep(unsigned int usec);
/* Event handlers: timer, idle, input */
WMHandlerID WMAddTimerHandler(unsigned milliseconds, WMCallback *callback,
WMHandlerID WMAddTimerHandler(int milliseconds, WMCallback *callback,
void *cdata);
WMHandlerID WMAddPersistentTimerHandler(unsigned milliseconds, WMCallback *callback,
WMHandlerID WMAddPersistentTimerHandler(int milliseconds, WMCallback *callback,
void *cdata);
void WMDeleteTimerWithClientData(void *cdata);
void WMDeleteTimerHandler(WMHandlerID handlerID);
WMHandlerID WMAddIdleHandler(WMCallback *callback, void *cdata);
void WMDeleteIdleHandler(WMHandlerID handlerID);
WMHandlerID WMAddInputHandler(int fd, int condition, WMInputProc *proc,
void *clientData);
/* ---[ wutil-rs/src/hash_table.rs ]----------------------------------------------- */
void WMDeleteInputHandler(WMHandlerID handlerID);
WMHashTable* WMCreateIdentityHashTable();
WMHashTable* WMCreateStringHashTable();
/* This function is used _only_ if you create a non-GUI program.
* For GUI based programs use WMNextEvent()/WMHandleEvent() instead.
* This function will handle all input/timer/idle events, then return.
*/
void WHandleEvents(void);
/* ---[ WINGs/hashtable.c ]----------------------------------------------- */
WMHashTable* WMCreateHashTable(const WMHashTableCallbacks callbacks);
void WMFreeHashTable(WMHashTable *table);
@@ -342,7 +366,7 @@ void* WMHashInsert(WMHashTable *table, const void *key, const void *data);
void WMHashRemove(WMHashTable *table, const void *key);
/* warning: do not manipulate the table while using the enumerator functions */
WMHashEnumerator* WMEnumerateHashTable(WMHashTable *table);
WMHashEnumerator WMEnumerateHashTable(WMHashTable *table);
void* WMNextHashEnumeratorItem(WMHashEnumerator *enumerator);
@@ -357,13 +381,17 @@ Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator *enumerator,
void **item, void **key);
void WMFreeHashEnumerator(WMHashEnumerator *enumerator);
/* some predefined callback sets */
extern const WMHashTableCallbacks WMIntHashCallbacks;
/* sizeof(keys) are <= sizeof(void*) */
extern const WMHashTableCallbacks WMStringHashCallbacks;
/* keys are strings. Strings will be copied with wstrdup()
* and freed with wfree() */
extern const WMHashTableCallbacks WMStringPointerHashCallbacks;
/* keys are strings, but they are not copied */
@@ -460,7 +488,7 @@ void* WMArrayPrevious(WMArray *array, WMArrayIterator *iter);
for (var = WMArrayLast(array, &(i)); (i) != WANotFound; \
var = WMArrayPrevious(array, &(i)))
/* ---[ wutil-rs/src/bag.rs ]------------------------------------------------- */
/* ---[ WINGs/bagtree.c ]------------------------------------------------- */
/*
* Tree bags use a red-black tree for storage.
@@ -475,16 +503,58 @@ void* WMArrayPrevious(WMArray *array, WMArrayIterator *iter);
* Slow for storing small numbers of elements
*/
#define WMCreateBag(size) WMCreateTreeBag()
#define WMCreateBagWithDestructor(size, d) WMCreateTreeBagWithDestructor(d)
WMBag* WMCreateTreeBag(void);
WMBag* WMCreateTreeBagWithDestructor(WMFreeDataProc *destructor);
int WMGetBagItemCount(WMBag *bag);
void WMAppendBag(WMBag *bag, WMBag *other);
void WMPutInBag(WMBag *bag, void *item);
/* insert will increment the index of elements after it by 1 */
void WMInsertInBag(WMBag *bag, int index, void *item);
/* erase will remove the element from the bag,
* but will keep the index of the other elements unchanged */
int WMEraseFromBag(WMBag *bag, int index);
/* delete and remove will remove the elements and cause the elements
* after them to decrement their indexes by 1 */
int WMDeleteFromBag(WMBag *bag, int index);
int WMRemoveFromBag(WMBag *bag, void *item);
void* WMGetFromBag(WMBag *bag, int index);
void WMSetInBag(WMBag *bag, int index, void *item);
void* WMReplaceInBag(WMBag *bag, int index, void *item);
#define WMSetInBag(bag, index, item) WMReplaceInBag(bag, index, item)
/* comparer must return:
* < 0 if a < b
* > 0 if a > b
* = 0 if a = b
*/
void WMSortBag(WMBag *bag, WMCompareDataProc *comparer);
void WMEmptyBag(WMBag *bag);
void WMFreeBag(WMBag *bag);
void WMMapBag(WMBag *bag, void (*function)(void*, void*), void *data);
int WMGetFirstInBag(WMBag *bag, void *item);
int WMCountInBag(WMBag *bag, void *item);
int WMFindInBag(WMBag *bag, WMMatchDataProc *match, void *cdata);
void* WMBagFirst(WMBag *bag, WMBagIterator *ptr);
void* WMBagLast(WMBag *bag, WMBagIterator *ptr);
@@ -496,11 +566,16 @@ void* WMBagPrevious(WMBag *bag, WMBagIterator *ptr);
void* WMBagIteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr);
int WMBagIndexForIterator(WMBag *bag, WMBagIterator ptr);
/* The following macro assumes that the bag doesn't change in the for loop */
/* The following 2 macros assume that the bag doesn't change in the for loop */
#define WM_ITERATE_BAG(bag, var, i) \
for (var = WMBagFirst(bag, &(i)); (i) != NULL; \
var = WMBagNext(bag, &(i)))
#define WM_ETARETI_BAG(bag, var, i) \
for (var = WMBagLast(bag, &(i)); (i) >= 0; \
for (var = WMBagLast(bag, &(i)); (i) != NULL; \
var = WMBagPrevious(bag, &(i)))
@@ -549,12 +624,14 @@ void WMSetDataFormat(WMData *aData, unsigned format);
unsigned WMGetDataFormat(WMData *aData);
/* Storing data */
/* ---[ wutil-rs/src/tree.rs ]---------------------------------------------------- */
/* ---[ WINGs/tree.c ]---------------------------------------------------- */
/* Generic Tree and TreeNode */
WMTreeNode* WMCreateTreeNode(void *data);
WMTreeNode* WMCreateTreeNodeWithDestructor(void *data, WMFreeDataProc *destructor);
WMTreeNode* WMInsertItemInTree(WMTreeNode *parent, int index, void *item);
#define WMAddItemToTree(parent, item) WMInsertItemInTree(parent, -1, item)
@@ -563,23 +640,48 @@ WMTreeNode* WMInsertNodeInTree(WMTreeNode *parent, int index, WMTreeNode *aNode)
#define WMAddNodeToTree(parent, aNode) WMInsertNodeInTree(parent, -1, aNode)
void WMDestroyTreeNode(WMTreeNode *aNode);
void WMDeleteLeafForTreeNode(WMTreeNode *aNode, int index);
void WMRemoveLeafForTreeNode(WMTreeNode *aNode, void *leaf);
void* WMReplaceDataForTreeNode(WMTreeNode *aNode, void *newData);
void* WMGetDataForTreeNode(WMTreeNode *aNode);
int WMGetTreeNodeDepth(WMTreeNode *aNode);
WMTreeNode* WMGetParentForTreeNode(WMTreeNode *aNode);
/* Sort only the leaves of the passed node */
void WMSortLeavesForTreeNode(WMTreeNode *aNode, WMCompareDataProc *comparer);
/* Sort all tree recursively starting from the passed node */
void WMSortTree(WMTreeNode *aNode, int (*comparer)(const WMTreeNode *a, const WMTreeNode *b));
void WMSortTree(WMTreeNode *aNode, WMCompareDataProc *comparer);
/* Returns the first node which matches node's data with cdata by 'match' */
WMTreeNode* WMFindInTree(WMTreeNode *aTree, WMMatchDataProc *match, void *cdata);
/* Returns the first node where node's data matches cdata by 'match' and node is
* at most `limit' depths down from `aTree'. */
WMTreeNode *WMFindInTreeWithDepthLimit(WMTreeNode * aTree, int (*match)(const WMTreeNode *item, const void *cdata), void *cdata, int limit);
WMTreeNode *WMFindInTreeWithDepthLimit(WMTreeNode * aTree, WMMatchDataProc * match, void *cdata, int limit);
/* Returns first tree node that has data == cdata */
#define WMGetFirstInTree(aTree, cdata) WMFindInTree(aTree, NULL, cdata)
/* Walk every node of aNode with `walk' */
void WMTreeWalk(WMTreeNode *aNode, WMTreeWalkProc * walk, void *data);
void WMTreeWalk(WMTreeNode *aNode, WMTreeWalkProc * walk, void *data, Bool DepthFirst);
/* ---[ WINGs/notification.c ]---------------------------------------------------- */
/* ---[ WINGs/data.c ]---------------------------------------------------- */
WMNotification* WMCreateNotification(const char *name, void *object, void *clientData);
void WMReleaseNotification(WMNotification *notification);
WMNotification* WMRetainNotification(WMNotification *notification);
void* WMGetNotificationClientData(WMNotification *notification);
void* WMGetNotificationObject(WMNotification *notification);
@@ -590,27 +692,48 @@ const char* WMGetNotificationName(WMNotification *notification);
void WMAddNotificationObserver(WMNotificationObserverAction *observerAction,
void *observer, const char *name, void *object);
void WMPostNotification(WMNotification *notification);
void WMRemoveNotificationObserver(void *observer);
void WMRemoveNotificationObserverWithName(void *observer, const char *name,
void *object);
void WMPostNotificationName(const char *name, void *object, void *clientData);
/* Property Lists handling */
WMNotificationQueue* WMGetDefaultNotificationQueue(void);
WMNotificationQueue* WMCreateNotificationQueue(void);
void WMDequeueNotificationMatching(WMNotificationQueue *queue,
WMNotification *notification,
unsigned mask);
void WMEnqueueNotification(WMNotificationQueue *queue,
WMNotification *notification,
WMPostingStyle postingStyle);
void WMEnqueueCoalesceNotification(WMNotificationQueue *queue,
WMNotification *notification,
WMPostingStyle postingStyle,
unsigned coalesceMask);
/* ---[ WINGs/proplist.c ]------------------------------------------------ */
WMPropList* WMCreatePLArray(WMPropList *elem, ...);
/* Property Lists handling */
/* ---[ wutil-rs/src/prop_list.rs ]--------------------------------------- */
void WMPLSetCaseSensitive(Bool caseSensitive);
WMPropList* WMCreatePLString(const char *str);
WMPropList* WMCreatePLArrayFromSlice(WMPropList *elems, unsigned int length);
WMPropList* WMCreatePLData(WMData *data);
WMPropList* WMCreateEmptyPLArray();
WMPropList* WMCreatePLDataWithBytes(const unsigned char *bytes, unsigned int length);
WMPropList* WMCreatePLDictionary(WMPropList *key, WMPropList *value);
WMPropList* WMCreatePLArray(WMPropList *elem, ...);
WMPropList* WMCreateEmptyPLDictionary();
WMPropList* WMCreatePLDictionary(WMPropList *key, WMPropList *value, ...);
WMPropList* WMRetainPropList(WMPropList *plist);
@@ -648,6 +771,8 @@ int WMGetPropListItemCount(WMPropList *plist);
Bool WMIsPLString(WMPropList *plist);
Bool WMIsPLData(WMPropList *plist);
Bool WMIsPLArray(WMPropList *plist);
Bool WMIsPLDictionary(WMPropList *plist);
@@ -657,6 +782,14 @@ Bool WMIsPropListEqualTo(WMPropList *plist, WMPropList *other);
/* Returns a reference. Do not free it! */
char* WMGetFromPLString(WMPropList *plist);
/* Returns a reference. Do not free it! */
WMData* WMGetFromPLData(WMPropList *plist);
/* Returns a reference. Do not free it! */
const unsigned char* WMGetPLDataBytes(WMPropList *plist);
int WMGetPLDataLength(WMPropList *plist);
/* Returns a reference. */
WMPropList* WMGetFromPLArray(WMPropList *plist, int index);
@@ -664,9 +797,14 @@ WMPropList* WMGetFromPLArray(WMPropList *plist, int index);
WMPropList* WMGetFromPLDictionary(WMPropList *plist, WMPropList *key);
/* Returns a PropList array with all the dictionary keys. Release it when
* you're done. */
* you're done. Keys in array are retained from the original dictionary
* not copied and need NOT to be released individually. */
WMPropList* WMGetPLDictionaryKeys(WMPropList *plist);
/* Creates only the first level deep object. All the elements inside are
* retained from the original */
WMPropList* WMShallowCopyPropList(WMPropList *plist);
/* Makes a completely separate replica of the original proplist */
WMPropList* WMDeepCopyPropList(WMPropList *plist);
+745
View File
@@ -0,0 +1,745 @@
#include <stdlib.h>
#include <string.h>
#include "WUtil.h"
typedef struct W_Node {
struct W_Node *parent;
struct W_Node *left;
struct W_Node *right;
int color;
void *data;
int index;
} W_Node;
typedef struct W_Bag {
W_Node *root;
W_Node *nil; /* sentinel */
int count;
void (*destructor) (void *item);
} W_Bag;
#define IS_LEFT(node) (node == node->parent->left)
#define IS_RIGHT(node) (node == node->parent->right)
static void leftRotate(W_Bag * tree, W_Node * node)
{
W_Node *node2;
node2 = node->right;
node->right = node2->left;
node2->left->parent = node;
node2->parent = node->parent;
if (node->parent == tree->nil) {
tree->root = node2;
} else {
if (IS_LEFT(node)) {
node->parent->left = node2;
} else {
node->parent->right = node2;
}
}
node2->left = node;
node->parent = node2;
}
static void rightRotate(W_Bag * tree, W_Node * node)
{
W_Node *node2;
node2 = node->left;
node->left = node2->right;
node2->right->parent = node;
node2->parent = node->parent;
if (node->parent == tree->nil) {
tree->root = node2;
} else {
if (IS_LEFT(node)) {
node->parent->left = node2;
} else {
node->parent->right = node2;
}
}
node2->right = node;
node->parent = node2;
}
static void treeInsert(W_Bag * tree, W_Node * node)
{
W_Node *y = tree->nil;
W_Node *x = tree->root;
while (x != tree->nil) {
y = x;
if (node->index <= x->index)
x = x->left;
else
x = x->right;
}
node->parent = y;
if (y == tree->nil)
tree->root = node;
else if (node->index <= y->index)
y->left = node;
else
y->right = node;
}
static void rbTreeInsert(W_Bag * tree, W_Node * node)
{
W_Node *y;
treeInsert(tree, node);
node->color = 'R';
while (node != tree->root && node->parent->color == 'R') {
if (IS_LEFT(node->parent)) {
y = node->parent->parent->right;
if (y->color == 'R') {
node->parent->color = 'B';
y->color = 'B';
node->parent->parent->color = 'R';
node = node->parent->parent;
} else {
if (IS_RIGHT(node)) {
node = node->parent;
leftRotate(tree, node);
}
node->parent->color = 'B';
node->parent->parent->color = 'R';
rightRotate(tree, node->parent->parent);
}
} else {
y = node->parent->parent->left;
if (y->color == 'R') {
node->parent->color = 'B';
y->color = 'B';
node->parent->parent->color = 'R';
node = node->parent->parent;
} else {
if (IS_LEFT(node)) {
node = node->parent;
rightRotate(tree, node);
}
node->parent->color = 'B';
node->parent->parent->color = 'R';
leftRotate(tree, node->parent->parent);
}
}
}
tree->root->color = 'B';
}
static void rbDeleteFixup(W_Bag * tree, W_Node * node)
{
W_Node *w;
while (node != tree->root && node->color == 'B') {
if (IS_LEFT(node)) {
w = node->parent->right;
if (w->color == 'R') {
w->color = 'B';
node->parent->color = 'R';
leftRotate(tree, node->parent);
w = node->parent->right;
}
if (w->left->color == 'B' && w->right->color == 'B') {
w->color = 'R';
node = node->parent;
} else {
if (w->right->color == 'B') {
w->left->color = 'B';
w->color = 'R';
rightRotate(tree, w);
w = node->parent->right;
}
w->color = node->parent->color;
node->parent->color = 'B';
w->right->color = 'B';
leftRotate(tree, node->parent);
node = tree->root;
}
} else {
w = node->parent->left;
if (w->color == 'R') {
w->color = 'B';
node->parent->color = 'R';
rightRotate(tree, node->parent);
w = node->parent->left;
}
if (w->left->color == 'B' && w->right->color == 'B') {
w->color = 'R';
node = node->parent;
} else {
if (w->left->color == 'B') {
w->right->color = 'B';
w->color = 'R';
leftRotate(tree, w);
w = node->parent->left;
}
w->color = node->parent->color;
node->parent->color = 'B';
w->left->color = 'B';
rightRotate(tree, node->parent);
node = tree->root;
}
}
}
node->color = 'B';
}
static W_Node *treeMinimum(W_Node * node, W_Node * nil)
{
while (node->left != nil)
node = node->left;
return node;
}
static W_Node *treeMaximum(W_Node * node, W_Node * nil)
{
while (node->right != nil)
node = node->right;
return node;
}
static W_Node *treeSuccessor(W_Node * node, W_Node * nil)
{
W_Node *y;
if (node->right != nil) {
return treeMinimum(node->right, nil);
}
y = node->parent;
while (y != nil && node == y->right) {
node = y;
y = y->parent;
}
return y;
}
static W_Node *treePredecessor(W_Node * node, W_Node * nil)
{
W_Node *y;
if (node->left != nil) {
return treeMaximum(node->left, nil);
}
y = node->parent;
while (y != nil && node == y->left) {
node = y;
y = y->parent;
}
return y;
}
static W_Node *rbTreeDelete(W_Bag * tree, W_Node * node)
{
W_Node *nil = tree->nil;
W_Node *x, *y;
if (node->left == nil || node->right == nil) {
y = node;
} else {
y = treeSuccessor(node, nil);
}
if (y->left != nil) {
x = y->left;
} else {
x = y->right;
}
x->parent = y->parent;
if (y->parent == nil) {
tree->root = x;
} else {
if (IS_LEFT(y)) {
y->parent->left = x;
} else {
y->parent->right = x;
}
}
if (y != node) {
node->index = y->index;
node->data = y->data;
}
if (y->color == 'B') {
rbDeleteFixup(tree, x);
}
return y;
}
static W_Node *treeSearch(W_Node * root, W_Node * nil, int index)
{
if (root == nil || root->index == index) {
return root;
}
if (index < root->index) {
return treeSearch(root->left, nil, index);
} else {
return treeSearch(root->right, nil, index);
}
}
static W_Node *treeFind(W_Node * root, W_Node * nil, void *data)
{
W_Node *tmp;
if (root == nil || root->data == data)
return root;
tmp = treeFind(root->left, nil, data);
if (tmp != nil)
return tmp;
tmp = treeFind(root->right, nil, data);
return tmp;
}
#if 0
static char buf[512];
static void printNodes(W_Node * node, W_Node * nil, int depth)
{
if (node == nil) {
return;
}
printNodes(node->left, nil, depth + 1);
memset(buf, ' ', depth * 2);
buf[depth * 2] = 0;
if (IS_LEFT(node))
printf("%s/(%2i\n", buf, node->index);
else
printf("%s\\(%2i\n", buf, node->index);
printNodes(node->right, nil, depth + 1);
}
void PrintTree(WMBag * bag)
{
W_TreeBag *tree = (W_TreeBag *) bag->data;
printNodes(tree->root, tree->nil, 0);
}
#endif
WMBag *WMCreateTreeBag(void)
{
return WMCreateTreeBagWithDestructor(NULL);
}
WMBag *WMCreateTreeBagWithDestructor(WMFreeDataProc * destructor)
{
WMBag *bag;
bag = wmalloc(sizeof(WMBag));
bag->nil = wmalloc(sizeof(W_Node));
bag->nil->left = bag->nil->right = bag->nil->parent = bag->nil;
bag->nil->index = WBNotFound;
bag->root = bag->nil;
bag->destructor = destructor;
return bag;
}
int WMGetBagItemCount(WMBag * self)
{
return self->count;
}
void WMAppendBag(WMBag * self, WMBag * bag)
{
WMBagIterator ptr;
void *data;
for (data = WMBagFirst(bag, &ptr); data != NULL; data = WMBagNext(bag, &ptr)) {
WMPutInBag(self, data);
}
}
void WMPutInBag(WMBag * self, void *item)
{
W_Node *ptr;
ptr = wmalloc(sizeof(W_Node));
ptr->data = item;
ptr->index = self->count;
ptr->left = self->nil;
ptr->right = self->nil;
ptr->parent = self->nil;
rbTreeInsert(self, ptr);
self->count++;
}
void WMInsertInBag(WMBag * self, int index, void *item)
{
W_Node *ptr;
ptr = wmalloc(sizeof(W_Node));
ptr->data = item;
ptr->index = index;
ptr->left = self->nil;
ptr->right = self->nil;
ptr->parent = self->nil;
rbTreeInsert(self, ptr);
while ((ptr = treeSuccessor(ptr, self->nil)) != self->nil) {
ptr->index++;
}
self->count++;
}
static int treeDeleteNode(WMBag * self, W_Node *ptr)
{
if (ptr != self->nil) {
W_Node *tmp;
self->count--;
tmp = treeSuccessor(ptr, self->nil);
while (tmp != self->nil) {
tmp->index--;
tmp = treeSuccessor(tmp, self->nil);
}
ptr = rbTreeDelete(self, ptr);
if (self->destructor)
self->destructor(ptr->data);
wfree(ptr);
return 1;
}
return 0;
}
int WMRemoveFromBag(WMBag * self, void *item)
{
W_Node *ptr = treeFind(self->root, self->nil, item);
return treeDeleteNode(self, ptr);
}
int WMEraseFromBag(WMBag * self, int index)
{
W_Node *ptr = treeSearch(self->root, self->nil, index);
if (ptr != self->nil) {
self->count--;
ptr = rbTreeDelete(self, ptr);
if (self->destructor)
self->destructor(ptr->data);
wfree(ptr);
wassertrv(self->count == 0 || self->root->index >= 0, 1);
return 1;
} else {
return 0;
}
}
int WMDeleteFromBag(WMBag * self, int index)
{
W_Node *ptr = treeSearch(self->root, self->nil, index);
return treeDeleteNode(self, ptr);
}
void *WMGetFromBag(WMBag * self, int index)
{
W_Node *node;
node = treeSearch(self->root, self->nil, index);
if (node != self->nil)
return node->data;
else
return NULL;
}
int WMGetFirstInBag(WMBag * self, void *item)
{
W_Node *node;
node = treeFind(self->root, self->nil, item);
if (node != self->nil)
return node->index;
else
return WBNotFound;
}
static int treeCount(W_Node * root, W_Node * nil, void *item)
{
int count = 0;
if (root == nil)
return 0;
if (root->data == item)
count++;
if (root->left != nil)
count += treeCount(root->left, nil, item);
if (root->right != nil)
count += treeCount(root->right, nil, item);
return count;
}
int WMCountInBag(WMBag * self, void *item)
{
return treeCount(self->root, self->nil, item);
}
void *WMReplaceInBag(WMBag * self, int index, void *item)
{
W_Node *ptr = treeSearch(self->root, self->nil, index);
void *old = NULL;
if (item == NULL) {
self->count--;
ptr = rbTreeDelete(self, ptr);
if (self->destructor)
self->destructor(ptr->data);
wfree(ptr);
} else if (ptr != self->nil) {
old = ptr->data;
ptr->data = item;
} else {
W_Node *ptr;
ptr = wmalloc(sizeof(W_Node));
ptr->data = item;
ptr->index = index;
ptr->left = self->nil;
ptr->right = self->nil;
ptr->parent = self->nil;
rbTreeInsert(self, ptr);
self->count++;
}
return old;
}
void WMSortBag(WMBag * self, WMCompareDataProc * comparer)
{
void **items;
W_Node *tmp;
int i;
if (self->count == 0)
return;
items = wmalloc(sizeof(void *) * self->count);
i = 0;
tmp = treeMinimum(self->root, self->nil);
while (tmp != self->nil) {
items[i++] = tmp->data;
tmp = treeSuccessor(tmp, self->nil);
}
qsort(&items[0], self->count, sizeof(void *), comparer);
i = 0;
tmp = treeMinimum(self->root, self->nil);
while (tmp != self->nil) {
tmp->index = i;
tmp->data = items[i++];
tmp = treeSuccessor(tmp, self->nil);
}
wfree(items);
}
static void deleteTree(WMBag * self, W_Node * node)
{
if (node == self->nil)
return;
deleteTree(self, node->left);
if (self->destructor)
self->destructor(node->data);
deleteTree(self, node->right);
wfree(node);
}
void WMEmptyBag(WMBag * self)
{
deleteTree(self, self->root);
self->root = self->nil;
self->count = 0;
}
void WMFreeBag(WMBag * self)
{
WMEmptyBag(self);
wfree(self->nil);
wfree(self);
}
static void mapTree(W_Bag * tree, W_Node * node, void (*function) (void *, void *), void *data)
{
if (node == tree->nil)
return;
mapTree(tree, node->left, function, data);
(*function) (node->data, data);
mapTree(tree, node->right, function, data);
}
void WMMapBag(WMBag * self, void (*function) (void *, void *), void *data)
{
mapTree(self, self->root, function, data);
}
static int findInTree(W_Bag * tree, W_Node * node, WMMatchDataProc * function, void *cdata)
{
int index;
if (node == tree->nil)
return WBNotFound;
index = findInTree(tree, node->left, function, cdata);
if (index != WBNotFound)
return index;
if ((*function) (node->data, cdata)) {
return node->index;
}
return findInTree(tree, node->right, function, cdata);
}
int WMFindInBag(WMBag * self, WMMatchDataProc * match, void *cdata)
{
return findInTree(self, self->root, match, cdata);
}
void *WMBagFirst(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
node = treeMinimum(self->root, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagLast(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
node = treeMaximum(self->root, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagNext(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
if (*ptr == NULL)
return NULL;
node = treeSuccessor(*ptr, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagPrevious(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
if (*ptr == NULL)
return NULL;
node = treePredecessor(*ptr, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagIteratorAtIndex(WMBag * self, int index, WMBagIterator * ptr)
{
W_Node *node;
node = treeSearch(self->root, self->nil, index);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
int WMBagIndexForIterator(WMBag * bag, WMBagIterator ptr)
{
/* Parameter not used, but tell the compiler that it is ok */
(void) bag;
return ((W_Node *) ptr)->index;
}
+1 -1
View File
@@ -498,7 +498,7 @@ static void registerDescriptionList(WMScreen * scr, WMView * view, WMArray * ope
for (i = 0; i < count; i++) {
text = WMGetDragOperationItemText(WMGetFromArray(operationArray, i));
strlcpy(textListItem, text, size);
wstrlcpy(textListItem, text, size);
/* to next text offset */
textListItem = &(textListItem[strlen(textListItem) + 1]);
+2 -2
View File
@@ -76,8 +76,8 @@ char *wfindfileinarray(WMPropList *array, const char *file)
path = wmalloc(len + flen + 2);
path = memcpy(path, p, len);
path[len] = 0;
if (strlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
strlcat(path, file, len + flen + 2) >= len + flen + 2) {
if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
wfree(path);
return NULL;
}
+566
View File
@@ -0,0 +1,566 @@
/*
* WINGs internal handlers: timer, idle and input handlers
*/
#include "wconfig.h"
#include "WINGsP.h"
#include <sys/types.h>
#include <unistd.h>
#include <X11/Xos.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include <time.h>
#ifndef X_GETTIMEOFDAY
#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
#endif
typedef struct TimerHandler {
WMCallback *callback; /* procedure to call */
struct timeval when; /* when to call the callback */
void *clientData;
struct TimerHandler *next;
int nextDelay; /* 0 if it's one-shot */
} TimerHandler;
typedef struct IdleHandler {
WMCallback *callback;
void *clientData;
} IdleHandler;
typedef struct InputHandler {
WMInputProc *callback;
void *clientData;
int fd;
int mask;
} InputHandler;
/* queue of timer event handlers */
static TimerHandler *timerHandler = NULL;
static WMArray *idleHandler = NULL;
static WMArray *inputHandler = NULL;
#define timerPending() (timerHandler)
static void rightNow(struct timeval *tv)
{
X_GETTIMEOFDAY(tv);
}
/* is t1 after t2 ? */
#define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
(((t1).tv_sec == (t2).tv_sec) \
&& ((t1).tv_usec > (t2).tv_usec)))
#define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
#define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
static void addmillisecs(struct timeval *tv, int milliseconds)
{
tv->tv_usec += milliseconds * 1000;
tv->tv_sec += tv->tv_usec / 1000000;
tv->tv_usec = tv->tv_usec % 1000000;
}
static void enqueueTimerHandler(TimerHandler * handler)
{
TimerHandler *tmp;
/* insert callback in queue, sorted by time left */
if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
/* first in the queue */
handler->next = timerHandler;
timerHandler = handler;
} else {
tmp = timerHandler;
while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
tmp = tmp->next;
}
handler->next = tmp->next;
tmp->next = handler;
}
}
static void delayUntilNextTimerEvent(struct timeval *delay)
{
struct timeval now;
TimerHandler *handler;
handler = timerHandler;
while (handler && IS_ZERO(handler->when))
handler = handler->next;
if (!handler) {
/* The return value of this function is only valid if there _are_
timers active. */
delay->tv_sec = 0;
delay->tv_usec = 0;
return;
}
rightNow(&now);
if (IS_AFTER(now, handler->when)) {
delay->tv_sec = 0;
delay->tv_usec = 0;
} else {
delay->tv_sec = handler->when.tv_sec - now.tv_sec;
delay->tv_usec = handler->when.tv_usec - now.tv_usec;
if (delay->tv_usec < 0) {
delay->tv_usec += 1000000;
delay->tv_sec--;
}
}
}
WMHandlerID WMAddTimerHandler(int milliseconds, WMCallback * callback, void *cdata)
{
TimerHandler *handler;
handler = malloc(sizeof(TimerHandler));
if (!handler)
return NULL;
rightNow(&handler->when);
addmillisecs(&handler->when, milliseconds);
handler->callback = callback;
handler->clientData = cdata;
handler->nextDelay = 0;
enqueueTimerHandler(handler);
return handler;
}
WMHandlerID WMAddPersistentTimerHandler(int milliseconds, WMCallback * callback, void *cdata)
{
TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata);
if (handler != NULL)
handler->nextDelay = milliseconds;
return handler;
}
void WMDeleteTimerWithClientData(void *cdata)
{
TimerHandler *handler, *tmp;
if (!cdata || !timerHandler)
return;
tmp = timerHandler;
if (tmp->clientData == cdata) {
tmp->nextDelay = 0;
if (!IS_ZERO(tmp->when)) {
timerHandler = tmp->next;
wfree(tmp);
}
} else {
while (tmp->next) {
if (tmp->next->clientData == cdata) {
handler = tmp->next;
handler->nextDelay = 0;
if (IS_ZERO(handler->when))
break;
tmp->next = handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
void WMDeleteTimerHandler(WMHandlerID handlerID)
{
TimerHandler *tmp, *handler = (TimerHandler *) handlerID;
if (!handler || !timerHandler)
return;
tmp = timerHandler;
handler->nextDelay = 0;
if (IS_ZERO(handler->when))
return;
if (tmp == handler) {
timerHandler = handler->next;
wfree(handler);
} else {
while (tmp->next) {
if (tmp->next == handler) {
tmp->next = handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
WMHandlerID WMAddIdleHandler(WMCallback * callback, void *cdata)
{
IdleHandler *handler;
handler = malloc(sizeof(IdleHandler));
if (!handler)
return NULL;
handler->callback = callback;
handler->clientData = cdata;
/* add handler at end of queue */
if (!idleHandler) {
idleHandler = WMCreateArrayWithDestructor(16, wfree);
}
WMAddToArray(idleHandler, handler);
return handler;
}
void WMDeleteIdleHandler(WMHandlerID handlerID)
{
IdleHandler *handler = (IdleHandler *) handlerID;
if (!handler || !idleHandler)
return;
WMRemoveFromArray(idleHandler, handler);
}
WMHandlerID WMAddInputHandler(int fd, int condition, WMInputProc * proc, void *clientData)
{
InputHandler *handler;
handler = wmalloc(sizeof(InputHandler));
handler->fd = fd;
handler->mask = condition;
handler->callback = proc;
handler->clientData = clientData;
if (!inputHandler)
inputHandler = WMCreateArrayWithDestructor(16, wfree);
WMAddToArray(inputHandler, handler);
return handler;
}
void WMDeleteInputHandler(WMHandlerID handlerID)
{
InputHandler *handler = (InputHandler *) handlerID;
if (!handler || !inputHandler)
return;
WMRemoveFromArray(inputHandler, handler);
}
Bool W_CheckIdleHandlers(void)
{
IdleHandler *handler;
WMArray *handlerCopy;
WMArrayIterator iter;
if (!idleHandler || WMGetArrayItemCount(idleHandler) == 0) {
W_FlushIdleNotificationQueue();
/* make sure an observer in queue didn't added an idle handler */
return (idleHandler != NULL && WMGetArrayItemCount(idleHandler) > 0);
}
handlerCopy = WMCreateArrayWithArray(idleHandler);
WM_ITERATE_ARRAY(handlerCopy, handler, iter) {
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInArray(idleHandler, handler) == WANotFound)
continue;
(*handler->callback) (handler->clientData);
WMDeleteIdleHandler(handler);
}
WMFreeArray(handlerCopy);
W_FlushIdleNotificationQueue();
/* this is not necesarrily False, because one handler can re-add itself */
return (WMGetArrayItemCount(idleHandler) > 0);
}
void W_CheckTimerHandlers(void)
{
TimerHandler *handler;
struct timeval now;
if (!timerHandler) {
W_FlushASAPNotificationQueue();
return;
}
rightNow(&now);
handler = timerHandler;
while (handler && IS_AFTER(now, handler->when)) {
if (!IS_ZERO(handler->when)) {
SET_ZERO(handler->when);
(*handler->callback) (handler->clientData);
}
handler = handler->next;
}
while (timerHandler && IS_ZERO(timerHandler->when)) {
handler = timerHandler;
timerHandler = timerHandler->next;
if (handler->nextDelay > 0) {
handler->when = now;
addmillisecs(&handler->when, handler->nextDelay);
enqueueTimerHandler(handler);
} else {
wfree(handler);
}
}
W_FlushASAPNotificationQueue();
}
/*
* This functions will handle input events on all registered file descriptors.
* Input:
* - waitForInput - True if we want the function to wait until an event
* appears on a file descriptor we watch, False if we
* want the function to immediately return if there is
* no data available on the file descriptors we watch.
* - inputfd - Extra input file descriptor to watch for input.
* This is only used when called from wevent.c to watch
* on ConnectionNumber(dpy) to avoid blocking of X events
* if we wait for input from other file handlers.
* Output:
* if waitForInput is False, the function will return False if there are no
* input handlers registered, or if there is no data
* available on the registered ones, and will return True
* if there is at least one input handler that has data
* available.
* if waitForInput is True, the function will return False if there are no
* input handlers registered, else it will block until an
* event appears on one of the file descriptors it watches
* and then it will return True.
*
* If the retured value is True, the input handlers for the corresponding file
* descriptors are also called.
*
* Parametersshould be passed like this:
* - from wevent.c:
* waitForInput - apropriate value passed by the function who called us
* inputfd = ConnectionNumber(dpy)
* - from wutil.c:
* waitForInput - apropriate value passed by the function who called us
* inputfd = -1
*
*/
Bool W_HandleInputEvents(Bool waitForInput, int inputfd)
{
#if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
struct poll fd *fds;
InputHandler *handler;
int count, timeout, nfds, i, extrafd;
extrafd = (inputfd < 0) ? 0 : 1;
if (inputHandler)
nfds = WMGetArrayItemCount(inputHandler);
else
nfds = 0;
if (!extrafd && nfds == 0) {
W_FlushASAPNotificationQueue();
return False;
}
fds = wmalloc((nfds + extrafd) * sizeof(struct pollfd));
if (extrafd) {
/* put this to the end of array to avoid using ranges from 1 to nfds+1 */
fds[nfds].fd = inputfd;
fds[nfds].events = POLLIN;
}
/* use WM_ITERATE_ARRAY() here */
for (i = 0; i < nfds; i++) {
handler = WMGetFromArray(inputHandler, i);
fds[i].fd = handler->fd;
fds[i].events = 0;
if (handler->mask & WIReadMask)
fds[i].events |= POLLIN;
if (handler->mask & WIWriteMask)
fds[i].events |= POLLOUT;
#if 0 /* FIXME */
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
#endif
}
/*
* Setup the timeout to the estimated time until the
* next timer expires.
*/
if (!waitForInput) {
timeout = 0;
} else if (timerPending()) {
struct timeval tv;
delayUntilNextTimerEvent(&tv);
timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
} else {
timeout = -1;
}
count = poll(fds, nfds + extrafd, timeout);
if (count > 0 && nfds > 0) {
WMArray *handlerCopy = WMCreateArrayWithArray(inputHandler);
int mask;
/* use WM_ITERATE_ARRAY() here */
for (i = 0; i < nfds; i++) {
handler = WMGetFromArray(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInArray(inputHandler, handler) == WANotFound)
continue;
mask = 0;
if ((handler->mask & WIReadMask) &&
(fds[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) && (fds[i].revents & (POLLOUT | POLLWRBAND)))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) && (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
mask |= WIExceptMask;
if (mask != 0 && handler->callback) {
(*handler->callback) (handler->fd, mask, handler->clientData);
}
}
WMFreeArray(handlerCopy);
}
wfree(fds);
W_FlushASAPNotificationQueue();
return (count > 0);
#else
#ifdef HAVE_SELECT
struct timeval timeout;
struct timeval *timeoutPtr;
fd_set rset, wset, eset;
int maxfd, nfds, i;
int count;
InputHandler *handler;
if (inputHandler)
nfds = WMGetArrayItemCount(inputHandler);
else
nfds = 0;
if (inputfd < 0 && nfds == 0) {
W_FlushASAPNotificationQueue();
return False;
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
if (inputfd < 0) {
maxfd = 0;
} else {
FD_SET(inputfd, &rset);
maxfd = inputfd;
}
/* use WM_ITERATE_ARRAY() here */
for (i = 0; i < nfds; i++) {
handler = WMGetFromArray(inputHandler, i);
if (handler->mask & WIReadMask)
FD_SET(handler->fd, &rset);
if (handler->mask & WIWriteMask)
FD_SET(handler->fd, &wset);
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
if (maxfd < handler->fd)
maxfd = handler->fd;
}
/*
* Setup the timeout to the estimated time until the
* next timer expires.
*/
if (!waitForInput) {
SET_ZERO(timeout);
timeoutPtr = &timeout;
} else if (timerPending()) {
delayUntilNextTimerEvent(&timeout);
timeoutPtr = &timeout;
} else {
timeoutPtr = (struct timeval *)0;
}
count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
if (count > 0 && nfds > 0) {
WMArray *handlerCopy = WMCreateArrayWithArray(inputHandler);
int mask;
/* use WM_ITERATE_ARRAY() here */
for (i = 0; i < nfds; i++) {
handler = WMGetFromArray(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInArray(inputHandler, handler) == WANotFound)
continue;
mask = 0;
if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
mask |= WIExceptMask;
if (mask != 0 && handler->callback) {
(*handler->callback) (handler->fd, mask, handler->clientData);
}
}
WMFreeArray(handlerCopy);
}
W_FlushASAPNotificationQueue();
return (count > 0);
#else /* not HAVE_SELECT, not HAVE_POLL */
# error Neither select nor poll. You lose.
#endif /* HAVE_SELECT */
#endif /* HAVE_POLL */
}
+422
View File
@@ -0,0 +1,422 @@
#include <config.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "WUtil.h"
#define INITIAL_CAPACITY 23
typedef struct HashItem {
const void *key;
const void *data;
struct HashItem *next; /* collided item list */
} HashItem;
typedef struct W_HashTable {
WMHashTableCallbacks callbacks;
unsigned itemCount;
unsigned size; /* table size */
HashItem **table;
} HashTable;
#define HASH(table, key) (((table)->callbacks.hash ? \
(*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
#define DUPKEY(table, key) ((table)->callbacks.retainKey ? \
(*(table)->callbacks.retainKey)(key) : (key))
#define RELKEY(table, key) if ((table)->callbacks.releaseKey) \
(*(table)->callbacks.releaseKey)(key)
static inline unsigned hashString(const void *param)
{
const char *key = param;
unsigned ret = 0;
unsigned ctr = 0;
while (*key) {
ret ^= *key++ << ctr;
ctr = (ctr + 1) % sizeof(char *);
}
return ret;
}
static inline unsigned hashPtr(const void *key)
{
return ((size_t) key / sizeof(char *));
}
static void rellocateItem(WMHashTable * table, HashItem * item)
{
unsigned h;
h = HASH(table, item->key);
item->next = table->table[h];
table->table[h] = item;
}
static void rebuildTable(WMHashTable * table)
{
HashItem *next;
HashItem **oldArray;
int i;
int oldSize;
int newSize;
oldArray = table->table;
oldSize = table->size;
newSize = table->size * 2;
table->table = wmalloc(sizeof(char *) * newSize);
table->size = newSize;
for (i = 0; i < oldSize; i++) {
while (oldArray[i] != NULL) {
next = oldArray[i]->next;
rellocateItem(table, oldArray[i]);
oldArray[i] = next;
}
}
wfree(oldArray);
}
WMHashTable *WMCreateHashTable(const WMHashTableCallbacks callbacks)
{
HashTable *table;
table = wmalloc(sizeof(HashTable));
table->callbacks = callbacks;
table->size = INITIAL_CAPACITY;
table->table = wmalloc(sizeof(HashItem *) * table->size);
return table;
}
void WMResetHashTable(WMHashTable * table)
{
HashItem *item, *tmp;
int i;
for (i = 0; i < table->size; i++) {
item = table->table[i];
while (item) {
tmp = item->next;
RELKEY(table, item->key);
wfree(item);
item = tmp;
}
}
table->itemCount = 0;
if (table->size > INITIAL_CAPACITY) {
wfree(table->table);
table->size = INITIAL_CAPACITY;
table->table = wmalloc(sizeof(HashItem *) * table->size);
} else {
memset(table->table, 0, sizeof(HashItem *) * table->size);
}
}
void WMFreeHashTable(WMHashTable * table)
{
HashItem *item, *tmp;
int i;
for (i = 0; i < table->size; i++) {
item = table->table[i];
while (item) {
tmp = item->next;
RELKEY(table, item->key);
wfree(item);
item = tmp;
}
}
wfree(table->table);
wfree(table);
}
unsigned WMCountHashTable(WMHashTable * table)
{
return table->itemCount;
}
static HashItem *hashGetItem(WMHashTable *table, const void *key)
{
unsigned h;
HashItem *item;
h = HASH(table, key);
item = table->table[h];
if (table->callbacks.keyIsEqual) {
while (item) {
if ((*table->callbacks.keyIsEqual) (key, item->key)) {
break;
}
item = item->next;
}
} else {
while (item) {
if (key == item->key) {
break;
}
item = item->next;
}
}
return item;
}
void *WMHashGet(WMHashTable * table, const void *key)
{
HashItem *item;
item = hashGetItem(table, key);
if (!item)
return NULL;
return (void *)item->data;
}
Bool WMHashGetItemAndKey(WMHashTable * table, const void *key, void **retItem, void **retKey)
{
HashItem *item;
item = hashGetItem(table, key);
if (!item)
return False;
if (retKey)
*retKey = (void *)item->key;
if (retItem)
*retItem = (void *)item->data;
return True;
}
void *WMHashInsert(WMHashTable * table, const void *key, const void *data)
{
unsigned h;
HashItem *item;
int replacing = 0;
h = HASH(table, key);
/* look for the entry */
item = table->table[h];
if (table->callbacks.keyIsEqual) {
while (item) {
if ((*table->callbacks.keyIsEqual) (key, item->key)) {
replacing = 1;
break;
}
item = item->next;
}
} else {
while (item) {
if (key == item->key) {
replacing = 1;
break;
}
item = item->next;
}
}
if (replacing) {
const void *old;
old = item->data;
item->data = data;
RELKEY(table, item->key);
item->key = DUPKEY(table, key);
return (void *)old;
} else {
HashItem *nitem;
nitem = wmalloc(sizeof(HashItem));
nitem->key = DUPKEY(table, key);
nitem->data = data;
nitem->next = table->table[h];
table->table[h] = nitem;
table->itemCount++;
}
/* OPTIMIZE: put this in an idle handler. */
if (table->itemCount > table->size) {
#ifdef DEBUG0
printf("rebuilding hash table...\n");
#endif
rebuildTable(table);
#ifdef DEBUG0
printf("finished rebuild.\n");
#endif
}
return NULL;
}
static HashItem *deleteFromList(HashTable * table, HashItem * item, const void *key)
{
HashItem *next;
if (item == NULL)
return NULL;
if ((table->callbacks.keyIsEqual && (*table->callbacks.keyIsEqual) (key, item->key))
|| (!table->callbacks.keyIsEqual && key == item->key)) {
next = item->next;
RELKEY(table, item->key);
wfree(item);
table->itemCount--;
return next;
}
item->next = deleteFromList(table, item->next, key);
return item;
}
void WMHashRemove(WMHashTable * table, const void *key)
{
unsigned h;
h = HASH(table, key);
table->table[h] = deleteFromList(table, table->table[h], key);
}
WMHashEnumerator WMEnumerateHashTable(WMHashTable * table)
{
WMHashEnumerator enumerator;
enumerator.table = table;
enumerator.index = 0;
enumerator.nextItem = table->table[0];
return enumerator;
}
void *WMNextHashEnumeratorItem(WMHashEnumerator * enumerator)
{
const void *data = NULL;
/* this assumes the table doesn't change between
* WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
if (enumerator->nextItem == NULL) {
HashTable *table = enumerator->table;
while (++enumerator->index < table->size) {
if (table->table[enumerator->index] != NULL) {
enumerator->nextItem = table->table[enumerator->index];
break;
}
}
}
if (enumerator->nextItem) {
data = ((HashItem *) enumerator->nextItem)->data;
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
}
return (void *)data;
}
void *WMNextHashEnumeratorKey(WMHashEnumerator * enumerator)
{
const void *key = NULL;
/* this assumes the table doesn't change between
* WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
if (enumerator->nextItem == NULL) {
HashTable *table = enumerator->table;
while (++enumerator->index < table->size) {
if (table->table[enumerator->index] != NULL) {
enumerator->nextItem = table->table[enumerator->index];
break;
}
}
}
if (enumerator->nextItem) {
key = ((HashItem *) enumerator->nextItem)->key;
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
}
return (void *)key;
}
Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator * enumerator, void **item, void **key)
{
/* this assumes the table doesn't change between
* WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
if (enumerator->nextItem == NULL) {
HashTable *table = enumerator->table;
while (++enumerator->index < table->size) {
if (table->table[enumerator->index] != NULL) {
enumerator->nextItem = table->table[enumerator->index];
break;
}
}
}
if (enumerator->nextItem) {
if (item)
*item = (void *)((HashItem *) enumerator->nextItem)->data;
if (key)
*key = (void *)((HashItem *) enumerator->nextItem)->key;
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
return True;
}
return False;
}
static Bool compareStrings(const void *param1, const void *param2)
{
const char *key1 = param1;
const char *key2 = param2;
return strcmp(key1, key2) == 0;
}
typedef void *(*retainFunc) (const void *);
typedef void (*releaseFunc) (const void *);
const WMHashTableCallbacks WMIntHashCallbacks = {
NULL,
NULL,
NULL,
NULL
};
const WMHashTableCallbacks WMStringHashCallbacks = {
hashString,
compareStrings,
(retainFunc) wstrdup,
(releaseFunc) wfree
};
const WMHashTableCallbacks WMStringPointerHashCallbacks = {
hashString,
compareStrings,
NULL,
NULL
};
+2 -2
View File
@@ -652,7 +652,7 @@ static void mpm_get_hostname(WParserMacro *this, WMenuParser parser)
return;
}
}
strlcpy((char *) this->value, h, sizeof(this->value) );
wstrlcpy((char *) this->value, h, sizeof(this->value) );
}
/* Name of the current user */
@@ -677,7 +677,7 @@ static void mpm_get_user_name(WParserMacro *this, WMenuParser parser)
user = pw_user->pw_name;
if (user == NULL) goto error_no_username;
}
strlcpy((char *) this->value, user, sizeof(this->value) );
wstrlcpy((char *) this->value, user, sizeof(this->value) );
}
/* Number id of the user under which we are running */
+482
View File
@@ -0,0 +1,482 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "WUtil.h"
#include "WINGsP.h"
typedef struct W_Notification {
const char *name;
void *object;
void *clientData;
int refCount;
} Notification;
const char *WMGetNotificationName(WMNotification * notification)
{
return notification->name;
}
void *WMGetNotificationObject(WMNotification * notification)
{
return notification->object;
}
void *WMGetNotificationClientData(WMNotification * notification)
{
return notification->clientData;
}
WMNotification *WMCreateNotification(const char *name, void *object, void *clientData)
{
Notification *nPtr;
nPtr = wmalloc(sizeof(Notification));
nPtr->name = name;
nPtr->object = object;
nPtr->clientData = clientData;
nPtr->refCount = 1;
return nPtr;
}
void WMReleaseNotification(WMNotification * notification)
{
notification->refCount--;
if (notification->refCount < 1) {
wfree(notification);
}
}
WMNotification *WMRetainNotification(WMNotification * notification)
{
notification->refCount++;
return notification;
}
/***************** Notification Center *****************/
typedef struct NotificationObserver {
WMNotificationObserverAction *observerAction;
void *observer;
const char *name;
void *object;
struct NotificationObserver *prev; /* for tables */
struct NotificationObserver *next;
struct NotificationObserver *nextAction; /* for observerTable */
} NotificationObserver;
typedef struct W_NotificationCenter {
WMHashTable *nameTable; /* names -> observer lists */
WMHashTable *objectTable; /* object -> observer lists */
NotificationObserver *nilList; /* obervers that catch everything */
WMHashTable *observerTable; /* observer -> NotificationObserver */
} NotificationCenter;
/* default (and only) center */
static NotificationCenter *notificationCenter = NULL;
void W_InitNotificationCenter(void)
{
notificationCenter = wmalloc(sizeof(NotificationCenter));
notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks);
notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks);
notificationCenter->nilList = NULL;
notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks);
}
void W_ReleaseNotificationCenter(void)
{
if (notificationCenter) {
if (notificationCenter->nameTable)
WMFreeHashTable(notificationCenter->nameTable);
if (notificationCenter->objectTable)
WMFreeHashTable(notificationCenter->objectTable);
if (notificationCenter->observerTable)
WMFreeHashTable(notificationCenter->observerTable);
wfree(notificationCenter);
notificationCenter = NULL;
}
}
void
WMAddNotificationObserver(WMNotificationObserverAction * observerAction,
void *observer, const char *name, void *object)
{
NotificationObserver *oRec, *rec;
oRec = wmalloc(sizeof(NotificationObserver));
oRec->observerAction = observerAction;
oRec->observer = observer;
oRec->name = name;
oRec->object = object;
oRec->next = NULL;
oRec->prev = NULL;
/* put this action in the list of actions for this observer */
rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec);
if (rec) {
/* if this is not the first action for the observer */
oRec->nextAction = rec;
} else {
oRec->nextAction = NULL;
}
if (!name && !object) {
/* catch-all */
oRec->next = notificationCenter->nilList;
if (notificationCenter->nilList) {
notificationCenter->nilList->prev = oRec;
}
notificationCenter->nilList = oRec;
} else if (!name) {
/* any message coming from object */
rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec);
oRec->next = rec;
if (rec) {
rec->prev = oRec;
}
} else {
/* name && (object || !object) */
rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec);
oRec->next = rec;
if (rec) {
rec->prev = oRec;
}
}
}
void WMPostNotification(WMNotification * notification)
{
NotificationObserver *orec, *tmp;
WMRetainNotification(notification);
/* tell the observers that want to know about a particular message */
orec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, notification->name);
while (orec) {
tmp = orec->next;
if (!orec->object || !notification->object || orec->object == notification->object) {
/* tell the observer */
if (orec->observerAction) {
(*orec->observerAction) (orec->observer, notification);
}
}
orec = tmp;
}
/* tell the observers that want to know about an object */
orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object);
while (orec) {
tmp = orec->next;
/* tell the observer */
if (orec->observerAction) {
(*orec->observerAction) (orec->observer, notification);
}
orec = tmp;
}
/* tell the catch all observers */
orec = notificationCenter->nilList;
while (orec) {
tmp = orec->next;
/* tell the observer */
if (orec->observerAction) {
(*orec->observerAction) (orec->observer, notification);
}
orec = tmp;
}
WMReleaseNotification(notification);
}
void WMRemoveNotificationObserver(void *observer)
{
NotificationObserver *orec, *tmp, *rec;
/* get the list of actions the observer is doing */
orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
/*
* FOREACH orec IN actionlist for observer
* DO
* remove from respective lists/tables
* free
* END
*/
while (orec) {
tmp = orec->nextAction;
if (!orec->name && !orec->object) {
/* catch-all */
if (notificationCenter->nilList == orec)
notificationCenter->nilList = orec->next;
} else if (!orec->name) {
/* any message coming from object */
rec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, orec->object);
if (rec == orec) {
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->objectTable, orec->object, orec->next);
} else {
WMHashRemove(notificationCenter->objectTable, orec->object);
}
}
} else {
/* name && (object || !object) */
rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name);
if (rec == orec) {
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->nameTable, orec->name, orec->next);
} else {
WMHashRemove(notificationCenter->nameTable, orec->name);
}
}
}
if (orec->prev)
orec->prev->next = orec->next;
if (orec->next)
orec->next->prev = orec->prev;
wfree(orec);
orec = tmp;
}
WMHashRemove(notificationCenter->observerTable, observer);
}
void WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object)
{
NotificationObserver *orec, *tmp, *rec;
NotificationObserver *newList = NULL;
/* get the list of actions the observer is doing */
orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
WMHashRemove(notificationCenter->observerTable, observer);
/* rebuild the list of actions for the observer */
while (orec) {
tmp = orec->nextAction;
if (orec->name == name && orec->object == object) {
if (!name && !object) {
if (notificationCenter->nilList == orec)
notificationCenter->nilList = orec->next;
} else if (!name) {
rec =
(NotificationObserver *) WMHashGet(notificationCenter->objectTable,
orec->object);
if (rec == orec) {
assert(rec->prev == NULL);
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->objectTable,
orec->object, orec->next);
} else {
WMHashRemove(notificationCenter->objectTable, orec->object);
}
}
} else {
rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable,
orec->name);
if (rec == orec) {
assert(rec->prev == NULL);
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->nameTable,
orec->name, orec->next);
} else {
WMHashRemove(notificationCenter->nameTable, orec->name);
}
}
}
if (orec->prev)
orec->prev->next = orec->next;
if (orec->next)
orec->next->prev = orec->prev;
wfree(orec);
} else {
/* append this action in the new action list */
orec->nextAction = NULL;
if (!newList) {
newList = orec;
} else {
NotificationObserver *p;
p = newList;
while (p->nextAction) {
p = p->nextAction;
}
p->nextAction = orec;
}
}
orec = tmp;
}
/* reinsert the list to the table */
if (newList) {
WMHashInsert(notificationCenter->observerTable, observer, newList);
}
}
void WMPostNotificationName(const char *name, void *object, void *clientData)
{
WMNotification *notification;
notification = WMCreateNotification(name, object, clientData);
WMPostNotification(notification);
WMReleaseNotification(notification);
}
/**************** Notification Queues ****************/
typedef struct W_NotificationQueue {
WMArray *asapQueue;
WMArray *idleQueue;
struct W_NotificationQueue *next;
} NotificationQueue;
static WMNotificationQueue *notificationQueueList = NULL;
/* default queue */
static WMNotificationQueue *notificationQueue = NULL;
WMNotificationQueue *WMGetDefaultNotificationQueue(void)
{
if (!notificationQueue)
notificationQueue = WMCreateNotificationQueue();
return notificationQueue;
}
WMNotificationQueue *WMCreateNotificationQueue(void)
{
NotificationQueue *queue;
queue = wmalloc(sizeof(NotificationQueue));
queue->asapQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
queue->idleQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
queue->next = notificationQueueList;
notificationQueueList = queue;
return queue;
}
void WMEnqueueNotification(WMNotificationQueue * queue, WMNotification * notification, WMPostingStyle postingStyle)
{
WMEnqueueCoalesceNotification(queue, notification, postingStyle, WNCOnName | WNCOnSender);
}
#define NOTIF ((WMNotification*)cdata)
#define ITEM ((WMNotification*)item)
static int matchSenderAndName(const void *item, const void *cdata)
{
return (NOTIF->object == ITEM->object && strcmp(NOTIF->name, ITEM->name) == 0);
}
static int matchSender(const void *item, const void *cdata)
{
return (NOTIF->object == ITEM->object);
}
static int matchName(const void *item, const void *cdata)
{
return (strcmp(NOTIF->name, ITEM->name) == 0);
}
#undef NOTIF
#undef ITEM
void WMDequeueNotificationMatching(WMNotificationQueue * queue, WMNotification * notification, unsigned mask)
{
WMMatchDataProc *matchFunc;
if ((mask & WNCOnName) && (mask & WNCOnSender))
matchFunc = matchSenderAndName;
else if (mask & WNCOnName)
matchFunc = matchName;
else if (mask & WNCOnSender)
matchFunc = matchSender;
else
return;
WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
}
void
WMEnqueueCoalesceNotification(WMNotificationQueue * queue,
WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask)
{
if (coalesceMask != WNCNone)
WMDequeueNotificationMatching(queue, notification, coalesceMask);
switch (postingStyle) {
case WMPostNow:
WMPostNotification(notification);
WMReleaseNotification(notification);
break;
case WMPostASAP:
WMAddToArray(queue->asapQueue, notification);
break;
case WMPostWhenIdle:
WMAddToArray(queue->idleQueue, notification);
break;
}
}
void W_FlushASAPNotificationQueue(void)
{
WMNotificationQueue *queue = notificationQueueList;
while (queue) {
while (WMGetArrayItemCount(queue->asapQueue)) {
WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
WMDeleteFromArray(queue->asapQueue, 0);
}
queue = queue->next;
}
}
void W_FlushIdleNotificationQueue(void)
{
WMNotificationQueue *queue = notificationQueueList;
while (queue) {
while (WMGetArrayItemCount(queue->idleQueue)) {
WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
WMDeleteFromArray(queue->idleQueue, 0);
}
queue = queue->next;
}
}
+1828 -6
View File
File diff suppressed because it is too large Load Diff
+425
View File
@@ -0,0 +1,425 @@
/*
* Until FreeBSD gets their act together;
* http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
*/
#if defined( FREEBSD )
# undef _XOPEN_SOURCE
#endif
#include "wconfig.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#ifdef HAVE_BSD_STRING_H
#include <bsd/string.h>
#endif
#include "WUtil.h"
#define PRC_ALPHA 0
#define PRC_BLANK 1
#define PRC_ESCAPE 2
#define PRC_DQUOTE 3
#define PRC_EOS 4
#define PRC_SQUOTE 5
typedef struct {
short nstate;
short output;
} DFA;
static DFA mtable[9][6] = {
{{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
{{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
{{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
{{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
{{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
{{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
{{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
{{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
};
char *wtokennext(char *word, char **next)
{
char *ptr;
char *ret, *t;
int state, ctype;
t = ret = wmalloc(strlen(word) + 1);
ptr = word;
state = 0;
while (1) {
if (*ptr == 0)
ctype = PRC_EOS;
else if (*ptr == '\\')
ctype = PRC_ESCAPE;
else if (*ptr == '"')
ctype = PRC_DQUOTE;
else if (*ptr == '\'')
ctype = PRC_SQUOTE;
else if (*ptr == ' ' || *ptr == '\t')
ctype = PRC_BLANK;
else
ctype = PRC_ALPHA;
if (mtable[state][ctype].output) {
*t = *ptr;
t++;
*t = 0;
}
state = mtable[state][ctype].nstate;
ptr++;
if (mtable[state][0].output < 0) {
break;
}
}
if (*ret == 0) {
wfree(ret);
ret = NULL;
}
if (ctype == PRC_EOS)
*next = NULL;
else
*next = ptr;
return ret;
}
/* separate a string in tokens, taking " and ' into account */
void wtokensplit(char *command, char ***argv, int *argc)
{
char *token, *line;
int count;
count = 0;
line = command;
do {
token = wtokennext(line, &line);
if (token) {
if (count == 0)
*argv = wmalloc(sizeof(**argv));
else
*argv = wrealloc(*argv, (count + 1) * sizeof(**argv));
(*argv)[count++] = token;
}
} while (token != NULL && line != NULL);
*argc = count;
}
char *wtokenjoin(char **list, int count)
{
int i, j;
char *flat_string, *wspace;
j = 0;
for (i = 0; i < count; i++) {
if (list[i] != NULL && list[i][0] != 0) {
j += strlen(list[i]);
if (strpbrk(list[i], " \t"))
j += 2;
}
}
flat_string = wmalloc(j + count + 1);
for (i = 0; i < count; i++) {
if (list[i] != NULL && list[i][0] != 0) {
if (i > 0 &&
wstrlcat(flat_string, " ", j + count + 1) >= j + count + 1)
goto error;
wspace = strpbrk(list[i], " \t");
if (wspace &&
wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
goto error;
if (wstrlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
goto error;
if (wspace &&
wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
goto error;
}
}
return flat_string;
error:
wfree(flat_string);
return NULL;
}
void wtokenfree(char **tokens, int count)
{
while (count--)
wfree(tokens[count]);
wfree(tokens);
}
char *wtrimspace(const char *s)
{
const char *t;
if (s == NULL)
return NULL;
while (isspace(*s) && *s)
s++;
t = s + strlen(s) - 1;
while (t > s && isspace(*t))
t--;
return wstrndup(s, t - s + 1);
}
char *wstrdup(const char *str)
{
assert(str != NULL);
return strcpy(wmalloc(strlen(str) + 1), str);
}
char *wstrndup(const char *str, size_t len)
{
char *copy;
assert(str != NULL);
len = WMIN(len, strlen(str));
copy = strncpy(wmalloc(len + 1), str, len);
copy[len] = 0;
return copy;
}
char *wstrconcat(const char *str1, const char *str2)
{
char *str;
size_t slen, slen1;
if (!str1 && str2)
return wstrdup(str2);
else if (str1 && !str2)
return wstrdup(str1);
else if (!str1 && !str2)
return NULL;
slen1 = strlen(str1);
slen = slen1 + strlen(str2) + 1;
str = wmalloc(slen);
strcpy(str, str1);
strcpy(str + slen1, str2);
return str;
}
char *wstrappend(char *dst, const char *src)
{
size_t slen;
if (!src || *src == 0)
return dst;
else if (!dst)
return wstrdup(src);
slen = strlen(dst) + strlen(src) + 1;
dst = wrealloc(dst, slen);
strcat(dst, src);
return dst;
}
#ifdef HAVE_STRLCAT
size_t
wstrlcat(char *dst, const char *src, size_t siz)
{
return strlcat(dst, src, siz);
}
#else
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
wstrlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
#endif /* HAVE_STRLCAT */
#ifdef HAVE_STRLCPY
size_t
wstrlcpy(char *dst, const char *src, size_t siz)
{
return strlcpy(dst, src, siz);
}
#else
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
wstrlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif /* HAVE_STRLCPY */
/* transform `s' so that the result is safe to pass to the shell as an argument.
* returns a newly allocated string.
* with very heavy inspirations from NetBSD's shquote(3).
*/
char *wshellquote(const char *s)
{
char *p, *r, *last, *ret;
size_t slen;
int needs_quoting;
if (!s)
return NULL;
needs_quoting = !*s; /* the empty string does need quoting */
/* do not quote if consists only of the following characters */
for (p = (char *)s; *p && !needs_quoting; p++) {
needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
(*p == '.') || (*p == ',') || (*p == '-'));
}
if (!needs_quoting)
return wstrdup(s);
for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
ret = r = wmalloc(slen);
p = (char *)s;
last = p;
if (*p != '\'') /* if string doesn't already begin with "'" */
*r++ ='\''; /* start putting it in quotes */
while (*p) {
last = p;
if (*p == '\'') { /* turn each ' into ''\' */
if (p != s) /* except if it's the first ', in which case */
*r++ = '\''; /* only escape it */
*r++ = '\\';
*r++ = '\'';
while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
*r++ = '\\';
*r++ = '\'';
}
if (*p) /* if more input follows, terminate */
*r++ = '\''; /* what we have so far */
} else {
*r++ = *p++;
}
}
if (*last != '\'') /* if the last one isn't already a ' */
*r++ = '\''; /* terminate the whole shebang */
*r = '\0';
return ret; /* technically, we lose (but not leak) a couple of */
/* bytes (twice the number of consecutive 's in the */
/* input or so), but since these are relatively rare */
/* and short-lived strings, not sure if a trip to */
/* wstrdup+wfree worths the gain. */
}
+255
View File
@@ -0,0 +1,255 @@
#include <string.h>
#include "WUtil.h"
typedef struct W_TreeNode {
void *data;
/*unsigned int uflags:16; */
WMArray *leaves;
int depth;
struct W_TreeNode *parent;
WMFreeDataProc *destructor;
} W_TreeNode;
static void destroyNode(void *data)
{
WMTreeNode *aNode = (WMTreeNode *) data;
if (aNode->destructor) {
(*aNode->destructor) (aNode->data);
}
if (aNode->leaves) {
WMFreeArray(aNode->leaves);
}
wfree(aNode);
}
WMTreeNode *WMCreateTreeNode(void *data)
{
return WMCreateTreeNodeWithDestructor(data, NULL);
}
WMTreeNode *WMCreateTreeNodeWithDestructor(void *data, WMFreeDataProc * destructor)
{
WMTreeNode *aNode;
aNode = (WMTreeNode *) wmalloc(sizeof(W_TreeNode));
aNode->destructor = destructor;
aNode->data = data;
aNode->parent = NULL;
aNode->depth = 0;
aNode->leaves = NULL;
/*aNode->leaves = WMCreateArrayWithDestructor(1, destroyNode); */
return aNode;
}
WMTreeNode *WMInsertItemInTree(WMTreeNode * parent, int index, void *item)
{
WMTreeNode *aNode;
wassertrv(parent != NULL, NULL);
aNode = WMCreateTreeNodeWithDestructor(item, parent->destructor);
aNode->parent = parent;
aNode->depth = parent->depth + 1;
if (!parent->leaves) {
parent->leaves = WMCreateArrayWithDestructor(1, destroyNode);
}
if (index < 0) {
WMAddToArray(parent->leaves, aNode);
} else {
WMInsertInArray(parent->leaves, index, aNode);
}
return aNode;
}
static void updateNodeDepth(WMTreeNode * aNode, int depth)
{
int i;
aNode->depth = depth;
if (aNode->leaves) {
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
updateNodeDepth(WMGetFromArray(aNode->leaves, i), depth + 1);
}
}
}
WMTreeNode *WMInsertNodeInTree(WMTreeNode * parent, int index, WMTreeNode * aNode)
{
wassertrv(parent != NULL, NULL);
wassertrv(aNode != NULL, NULL);
aNode->parent = parent;
updateNodeDepth(aNode, parent->depth + 1);
if (!parent->leaves) {
parent->leaves = WMCreateArrayWithDestructor(1, destroyNode);
}
if (index < 0) {
WMAddToArray(parent->leaves, aNode);
} else {
WMInsertInArray(parent->leaves, index, aNode);
}
return aNode;
}
void WMDestroyTreeNode(WMTreeNode * aNode)
{
wassertr(aNode != NULL);
if (aNode->parent && aNode->parent->leaves) {
WMRemoveFromArray(aNode->parent->leaves, aNode);
} else {
destroyNode(aNode);
}
}
void WMDeleteLeafForTreeNode(WMTreeNode * aNode, int index)
{
wassertr(aNode != NULL);
wassertr(aNode->leaves != NULL);
WMDeleteFromArray(aNode->leaves, index);
}
static int sameData(const void *item, const void *data)
{
return (((WMTreeNode *) item)->data == data);
}
void WMRemoveLeafForTreeNode(WMTreeNode * aNode, void *leaf)
{
int index;
wassertr(aNode != NULL);
wassertr(aNode->leaves != NULL);
index = WMFindInArray(aNode->leaves, sameData, leaf);
if (index != WANotFound) {
WMDeleteFromArray(aNode->leaves, index);
}
}
void *WMReplaceDataForTreeNode(WMTreeNode * aNode, void *newData)
{
void *old;
wassertrv(aNode != NULL, NULL);
old = aNode->data;
aNode->data = newData;
return old;
}
void *WMGetDataForTreeNode(WMTreeNode * aNode)
{
return aNode->data;
}
int WMGetTreeNodeDepth(WMTreeNode * aNode)
{
return aNode->depth;
}
WMTreeNode *WMGetParentForTreeNode(WMTreeNode * aNode)
{
return aNode->parent;
}
void WMSortLeavesForTreeNode(WMTreeNode * aNode, WMCompareDataProc * comparer)
{
wassertr(aNode != NULL);
if (aNode->leaves) {
WMSortArray(aNode->leaves, comparer);
}
}
static void sortLeavesForNode(WMTreeNode * aNode, WMCompareDataProc * comparer)
{
int i;
if (!aNode->leaves)
return;
WMSortArray(aNode->leaves, comparer);
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
sortLeavesForNode(WMGetFromArray(aNode->leaves, i), comparer);
}
}
void WMSortTree(WMTreeNode * aNode, WMCompareDataProc * comparer)
{
wassertr(aNode != NULL);
sortLeavesForNode(aNode, comparer);
}
static WMTreeNode *findNodeInTree(WMTreeNode * aNode, WMMatchDataProc * match, void *cdata, int limit)
{
if (match == NULL && aNode->data == cdata)
return aNode;
else if (match && (*match) (aNode->data, cdata))
return aNode;
if (aNode->leaves && limit != 0) {
WMTreeNode *leaf;
int i;
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
leaf = findNodeInTree(WMGetFromArray(aNode->leaves, i),
match, cdata, limit > 0 ? limit - 1 : limit);
if (leaf)
return leaf;
}
}
return NULL;
}
WMTreeNode *WMFindInTree(WMTreeNode * aTree, WMMatchDataProc * match, void *cdata)
{
wassertrv(aTree != NULL, NULL);
return findNodeInTree(aTree, match, cdata, -1);
}
WMTreeNode *WMFindInTreeWithDepthLimit(WMTreeNode * aTree, WMMatchDataProc * match, void *cdata, int limit)
{
wassertrv(aTree != NULL, NULL);
wassertrv(limit >= 0, NULL);
return findNodeInTree(aTree, match, cdata, limit);
}
void WMTreeWalk(WMTreeNode * aNode, WMTreeWalkProc * walk, void *data, Bool DepthFirst)
{
int i;
WMTreeNode *leaf;
wassertr(aNode != NULL);
if (DepthFirst)
(*walk)(aNode, data);
if (aNode->leaves) {
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
leaf = (WMTreeNode *)WMGetFromArray(aNode->leaves, i);
WMTreeWalk(leaf, walk, data, DepthFirst);
}
}
if (!DepthFirst)
(*walk)(aNode, data);
}
+35 -2
View File
@@ -46,6 +46,39 @@ static void synchronizeUserDefaults(void *foo);
#define UD_SYNC_INTERVAL 2000
#endif
const char *wusergnusteppath(void)
{
static const char subdir[] = "/" GSUSER_SUBDIR;
static char *path = NULL;
char *gspath;
char *h;
int pathlen;
if (path)
/* Value have been already computed, re-use it */
return path;
gspath = GETENV("WMAKER_USER_ROOT");
if (gspath) {
gspath = wexpandpath(gspath);
if (gspath) {
path = gspath;
return path;
}
wwarning(_("variable WMAKER_USER_ROOT defined with invalid path, not used"));
}
h = wgethomedir();
pathlen = strlen(h);
path = wmalloc(pathlen + sizeof(subdir));
strcpy(path, h);
strcpy(path + pathlen, subdir);
wfree(h);
return path;
}
const char *wuserdatapath(void)
{
static char *path = NULL;
@@ -297,7 +330,7 @@ WMUserDefaults *WMGetStandardUserDefaults(void)
/* terminate list */
defaults->searchList[2] = NULL;
defaults->searchListArray = WMCreateEmptyPLArray();
defaults->searchListArray = WMCreatePLArray(NULL, NULL);
i = 0;
while (defaults->searchList[i]) {
@@ -370,7 +403,7 @@ WMUserDefaults *WMGetDefaultsFromPath(const char *path)
/* terminate list */
defaults->searchList[1] = NULL;
defaults->searchListArray = WMCreateEmptyPLArray();
defaults->searchListArray = WMCreatePLArray(NULL, NULL);
i = 0;
while (defaults->searchList[i]) {
+11 -8
View File
@@ -44,6 +44,9 @@ void WMInitializeApplication(const char *applicationName, int *argc, char **argv
WMApplication.argv[i] = wstrdup(argv[i]);
}
WMApplication.argv[i] = NULL;
/* initialize notification center */
W_InitNotificationCenter();
}
void WMReleaseApplication(void) {
@@ -57,7 +60,7 @@ void WMReleaseApplication(void) {
*/
w_save_defaults_changes();
W_ClearNotificationCenter();
W_ReleaseNotificationCenter();
if (WMApplication.applicationName) {
wfree(WMApplication.applicationName);
@@ -98,21 +101,21 @@ static char *checkFile(const char *path, const char *folder, const char *ext, co
slen = strlen(path) + strlen(resource) + 1 + extralen;
ret = wmalloc(slen);
if (strlcpy(ret, path, slen) >= slen)
if (wstrlcpy(ret, path, slen) >= slen)
goto error;
if (folder &&
(strlcat(ret, "/", slen) >= slen ||
strlcat(ret, folder, slen) >= slen))
(wstrlcat(ret, "/", slen) >= slen ||
wstrlcat(ret, folder, slen) >= slen))
goto error;
if (ext &&
(strlcat(ret, "/", slen) >= slen ||
strlcat(ret, ext, slen) >= slen))
(wstrlcat(ret, "/", slen) >= slen ||
wstrlcat(ret, ext, slen) >= slen))
goto error;
if (strlcat(ret, "/", slen) >= slen ||
strlcat(ret, resource, slen) >= slen)
if (wstrlcat(ret, "/", slen) >= slen ||
wstrlcat(ret, resource, slen) >= slen)
goto error;
if (access(ret, F_OK) != 0)
+3 -5
View File
@@ -65,7 +65,7 @@ struct W_Balloon *W_CreateBalloon(WMScreen * scr)
W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
bPtr->flags.alignment = DEFAULT_ALIGNMENT;
bPtr->table = WMCreateIdentityHashTable();
bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
bPtr->delay = DEFAULT_DELAY;
@@ -456,12 +456,12 @@ static void handleEvents(XEvent * event, void *data)
static void destroyBalloon(Balloon * bPtr)
{
WMHashEnumerator *e;
WMHashEnumerator e;
char *str;
e = WMEnumerateHashTable(bPtr->table);
while ((str = WMNextHashEnumeratorItem(e))) {
while ((str = WMNextHashEnumeratorItem(&e))) {
wfree(str);
}
WMFreeHashTable(bPtr->table);
@@ -472,7 +472,5 @@ static void destroyBalloon(Balloon * bPtr)
if (bPtr->font)
WMReleaseFont(bPtr->font);
WMFreeHashEnumerator(e);
wfree(bPtr);
}
+9 -9
View File
@@ -314,7 +314,7 @@ static void removeColumn(WMBrowser * bPtr, int column)
wfree(bPtr->titles[i]);
bPtr->titles[i] = NULL;
}
WMRemoveNotificationObserver(bPtr->columns[i]);
WMRemoveNotificationObserverWithName(bPtr, WMListSelectionDidChangeNotification, bPtr->columns[i]);
WMDestroyWidget(bPtr->columns[i]);
bPtr->columns[i] = NULL;
}
@@ -720,14 +720,14 @@ char *WMGetBrowserPathToColumn(WMBrowser * bPtr, int column)
path = wmalloc(slen);
/* ignore first `/' */
for (i = 0; i <= column; i++) {
if (strlcat(path, bPtr->pathSeparator, slen) >= slen)
if (wstrlcat(path, bPtr->pathSeparator, slen) >= slen)
goto error;
item = WMGetListSelectedItem(bPtr->columns[i]);
if (!item)
break;
if (strlcat(path, item->text, slen) >= slen)
if (wstrlcat(path, item->text, slen) >= slen)
goto error;
}
@@ -782,7 +782,7 @@ WMArray *WMGetBrowserPaths(WMBrowser * bPtr)
path = wmalloc(slen);
/* ignore first `/' */
for (i = 0; i <= column; i++) {
strlcat(path, bPtr->pathSeparator, slen);
wstrlcat(path, bPtr->pathSeparator, slen);
if (i == column) {
item = lastItem;
} else {
@@ -790,7 +790,7 @@ WMArray *WMGetBrowserPaths(WMBrowser * bPtr)
}
if (!item)
break;
strlcat(path, item->text, slen);
wstrlcat(path, item->text, slen);
}
WMAddToArray(paths, path);
}
@@ -1130,25 +1130,25 @@ static char *createTruncatedString(WMFont * font, const char *text, int *textLen
if (width >= 3 * dLen) {
int tmpTextLen = *textLen;
if (strlcpy(textBuf, text, slen) >= slen)
if (wstrlcpy(textBuf, text, slen) >= slen)
goto error;
while (tmpTextLen && (WMWidthOfString(font, textBuf, tmpTextLen) + 3 * dLen > width))
tmpTextLen--;
if (strlcpy(textBuf + tmpTextLen, "...", slen) >= slen)
if (wstrlcpy(textBuf + tmpTextLen, "...", slen) >= slen)
goto error;
*textLen = tmpTextLen + 3;
} else if (width >= 2 * dLen) {
if (strlcpy(textBuf, "..", slen) >= slen)
if (wstrlcpy(textBuf, "..", slen) >= slen)
goto error;
*textLen = 2;
} else if (width >= dLen) {
if (strlcpy(textBuf, ".", slen) >= slen)
if (wstrlcpy(textBuf, ".", slen) >= slen)
goto error;
*textLen = 1;
-8
View File
@@ -216,14 +216,6 @@ WMButton *WMCreateButton(WMWidget * parent, WMButtonType type)
return bPtr;
}
WMButton *WMCreateCommandButton(WMWidget *parent)
{
return WMCreateCustomButton(
parent,
WBBSpringLoadedMask|WBBPushInMask|WBBPushLightMask|WBBPushChangeMask
);
}
static void updateDisabledMask(WMButton * bPtr)
{
WMScreen *scr = WMWidgetScreen(bPtr);
+1 -24
View File
@@ -3,17 +3,8 @@
* This event handling stuff was inspired on Tk.
*/
#include "wconfig.h"
#include "WINGsP.h"
#if !HAVE_POLL
# error poll(2) is not present on this system
#endif
#if HAVE_POLL_H
# include <poll.h>
#endif
/* table to map event types to event masks */
static const unsigned long eventMasks[] = {
0,
@@ -358,9 +349,6 @@ int WMIsDoubleClick(XEvent * event)
*/
static Bool waitForEvent(Display * dpy, unsigned long xeventmask, Bool waitForInput)
{
struct pollfd pfd;
int timeout, inputfd;
XSync(dpy, False);
if (xeventmask == 0) {
if (XPending(dpy))
@@ -373,18 +361,7 @@ static Bool waitForEvent(Display * dpy, unsigned long xeventmask, Bool waitForIn
}
}
inputfd = ConnectionNumber(dpy);
if (inputfd < 0) {
return False;
}
pfd.fd = inputfd;
pfd.events = POLLIN;
timeout = waitForInput ? W_DelayUntilNextTimerEvent_millis() : 0;
return poll(&pfd, 1, timeout) > 0;
return W_HandleInputEvents(waitForInput, ConnectionNumber(dpy));
}
void WMNextEvent(Display * dpy, XEvent * event)
+6 -6
View File
@@ -513,12 +513,12 @@ static void listDirectoryOnColumn(WMFilePanel * panel, int column, const char *p
if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
continue;
if (strlcpy(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf))
if (wstrlcpy(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf))
goto out;
if (strcmp(path, "/") != 0 &&
strlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf))
wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf))
goto out;
if (strlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf))
if (wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf))
goto out;
if (stat(pbuf, &stat_buf) != 0) {
@@ -626,11 +626,11 @@ static void createDir(WMWidget *widget, void *p_panel)
file = wmalloc(slen);
if (directory &&
(strlcat(file, directory, slen) >= slen ||
strlcat(file, "/", slen) >= slen))
(wstrlcat(file, directory, slen) >= slen ||
wstrlcat(file, "/", slen) >= slen))
goto out;
if (strlcat(file, dirName, slen) >= slen)
if (wstrlcat(file, dirName, slen) >= slen)
goto out;
if (mkdir(file, 00777) != 0) {
+433
View File
@@ -0,0 +1,433 @@
#include <stdlib.h>
#include "wconfig.h"
#include "WINGsP.h"
#include <wraster.h>
#include <assert.h>
#include <X11/Xlocale.h>
#include <X11/Xft/Xft.h>
#include <fontconfig/fontconfig.h>
#ifdef USE_PANGO
#include <pango/pango.h>
#include <pango/pangofc-fontmap.h>
#include <pango/pangoxft.h>
#endif
#define DEFAULT_FONT "sans serif:pixelsize=12"
#define DEFAULT_SIZE WINGsConfiguration.defaultFontSize
static FcPattern *xlfdToFcPattern(const char *xlfd)
{
FcPattern *pattern;
char *fname, *ptr;
/* Just skip old font names that contain %d in them.
* We don't support that anymore. */
if (strchr(xlfd, '%') != NULL)
return FcNameParse((FcChar8 *) DEFAULT_FONT);
fname = wstrdup(xlfd);
if ((ptr = strchr(fname, ','))) {
*ptr = 0;
}
pattern = XftXlfdParse(fname, False, False);
wfree(fname);
if (!pattern) {
wwarning(_("invalid font: %s. Trying '%s'"), xlfd, DEFAULT_FONT);
pattern = FcNameParse((FcChar8 *) DEFAULT_FONT);
}
return pattern;
}
static char *xlfdToFcName(const char *xlfd)
{
FcPattern *pattern;
char *fname;
char *result;
pattern = xlfdToFcPattern(xlfd);
fname = (char *)FcNameUnparse(pattern);
result = wstrdup(fname);
free(fname);
FcPatternDestroy(pattern);
return result;
}
static Bool hasProperty(FcPattern * pattern, const char *property)
{
FcValue val;
if (FcPatternGet(pattern, property, 0, &val) == FcResultMatch) {
return True;
}
return False;
}
static Bool hasPropertyWithStringValue(FcPattern * pattern, const char *object, const char *value)
{
FcChar8 *str;
int id;
if (!value || value[0] == 0)
return True;
id = 0;
while (FcPatternGetString(pattern, object, id, &str) == FcResultMatch) {
if (strcasecmp(value, (char *)str) == 0) {
return True;
}
id++;
}
return False;
}
static char *makeFontOfSize(const char *font, int size, const char *fallback)
{
FcPattern *pattern;
char *name;
char *result;
if (font[0] == '-') {
pattern = xlfdToFcPattern(font);
} else {
pattern = FcNameParse((const FcChar8 *) font);
}
/*FcPatternPrint(pattern); */
if (size > 0) {
FcPatternDel(pattern, FC_PIXEL_SIZE);
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)size);
} else if (size == 0 && !hasProperty(pattern, "size") && !hasProperty(pattern, FC_PIXEL_SIZE)) {
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)DEFAULT_SIZE);
}
if (fallback && !hasPropertyWithStringValue(pattern, FC_FAMILY, fallback)) {
FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) fallback);
}
/*FcPatternPrint(pattern); */
name = (char *)FcNameUnparse(pattern);
result = wstrdup(name);
free(name);
FcPatternDestroy(pattern);
return result;
}
WMFont *WMCreateFont(WMScreen * scrPtr, const char *fontName)
{
Display *display = scrPtr->display;
WMFont *font;
char *fname;
#ifdef USE_PANGO
PangoFontMap *fontmap;
PangoContext *context;
PangoLayout *layout;
FcPattern *pattern;
PangoFontDescription *description;
double size;
#endif
if (fontName[0] == '-') {
fname = xlfdToFcName(fontName);
} else {
fname = wstrdup(fontName);
}
if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) {
fname = wstrappend(fname, ":antialias=false");
}
font = WMHashGet(scrPtr->fontCache, fname);
if (font) {
WMRetainFont(font);
wfree(fname);
return font;
}
font = wmalloc(sizeof(WMFont));
font->screen = scrPtr;
font->font = XftFontOpenName(display, scrPtr->screen, fname);
if (!font->font) {
wfree(font);
wfree(fname);
return NULL;
}
font->height = font->font->ascent + font->font->descent;
font->y = font->font->ascent;
font->refCount = 1;
font->name = fname;
#ifdef USE_PANGO
fontmap = pango_xft_get_font_map(scrPtr->display, scrPtr->screen);
context = pango_font_map_create_context(fontmap);
layout = pango_layout_new(context);
pattern = FcNameParse((FcChar8 *) font->name);
description = pango_fc_font_description_from_pattern(pattern, FALSE);
/* Pango examines FC_SIZE but not FC_PIXEL_SIZE of the patten, but
* font-name has only "pixelsize", so set the size manually here.
*/
if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
pango_font_description_set_absolute_size(description, size * PANGO_SCALE);
pango_layout_set_font_description(layout, description);
font->layout = layout;
#endif
assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL);
return font;
}
WMFont *WMRetainFont(WMFont * font)
{
wassertrv(font != NULL, NULL);
font->refCount++;
return font;
}
void WMReleaseFont(WMFont * font)
{
wassertr(font != NULL);
font->refCount--;
if (font->refCount < 1) {
XftFontClose(font->screen->display, font->font);
if (font->name) {
WMHashRemove(font->screen->fontCache, font->name);
wfree(font->name);
}
wfree(font);
}
}
Bool WMIsAntialiasingEnabled(WMScreen * scrPtr)
{
return scrPtr->antialiasedText;
}
unsigned int WMFontHeight(WMFont * font)
{
wassertrv(font != NULL, 0);
return font->height;
}
char *WMGetFontName(WMFont * font)
{
wassertrv(font != NULL, NULL);
return font->name;
}
void WMGetScaleBaseFromSystemFont(WMScreen *scrPtr, int *alphabetWidth, int *fontHeight)
{
WMFont *font;
font = WMDefaultSystemFont(scrPtr);
*alphabetWidth = WMWidthOfString(font, "abcdefghijklmnopqrstuvwxyz", 26);
*fontHeight = WMFontHeight(font);
WMReleaseFont(font);
}
WMFont *WMDefaultSystemFont(WMScreen * scrPtr)
{
return WMRetainFont(scrPtr->normalFont);
}
WMFont *WMDefaultBoldSystemFont(WMScreen * scrPtr)
{
return WMRetainFont(scrPtr->boldFont);
}
WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size)
{
WMFont *font;
char *fontSpec;
fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL);
font = WMCreateFont(scrPtr, fontSpec);
if (!font) {
wwarning(_("could not load font: %s."), fontSpec);
}
wfree(fontSpec);
return font;
}
WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
{
WMFont *font;
char *fontSpec;
fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL);
font = WMCreateFont(scrPtr, fontSpec);
if (!font) {
wwarning(_("could not load font: %s."), fontSpec);
}
wfree(fontSpec);
return font;
}
int WMWidthOfString(WMFont * font, const char *text, int length)
{
#ifdef USE_PANGO
const char *previous_text;
int width;
#else
XGlyphInfo extents;
#endif
wassertrv(font != NULL && text != NULL, 0);
#ifdef USE_PANGO
previous_text = pango_layout_get_text(font->layout);
if ((previous_text == NULL) || (strncmp(text, previous_text, length) != 0) || previous_text[length] != '\0')
pango_layout_set_text(font->layout, text, length);
pango_layout_get_pixel_size(font->layout, &width, NULL);
return width;
#else
XftTextExtentsUtf8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
return extents.xOff; /* don't ask :P */
#endif
}
void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, int x, int y, const char *text, int length)
{
XftColor xftcolor;
#ifdef USE_PANGO
const char *previous_text;
#endif
wassertr(font != NULL);
xftcolor.color.red = color->color.red;
xftcolor.color.green = color->color.green;
xftcolor.color.blue = color->color.blue;
xftcolor.color.alpha = color->alpha;;
xftcolor.pixel = W_PIXEL(color);
XftDrawChange(scr->xftdraw, d);
#ifdef USE_PANGO
previous_text = pango_layout_get_text(font->layout);
if ((previous_text == NULL) || (strcmp(text, previous_text) != 0))
pango_layout_set_text(font->layout, text, length);
pango_xft_render_layout(scr->xftdraw, &xftcolor, font->layout, x * PANGO_SCALE, y * PANGO_SCALE);
#else
XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
#endif
}
void
WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * background,
WMFont * font, int x, int y, const char *text, int length)
{
XftColor textColor;
XftColor bgColor;
#ifdef USE_PANGO
const char *previous_text;
#endif
wassertr(font != NULL);
textColor.color.red = color->color.red;
textColor.color.green = color->color.green;
textColor.color.blue = color->color.blue;
textColor.color.alpha = color->alpha;;
textColor.pixel = W_PIXEL(color);
bgColor.color.red = background->color.red;
bgColor.color.green = background->color.green;
bgColor.color.blue = background->color.blue;
bgColor.color.alpha = background->alpha;;
bgColor.pixel = W_PIXEL(background);
XftDrawChange(scr->xftdraw, d);
XftDrawRect(scr->xftdraw, &bgColor, x, y, WMWidthOfString(font, text, length), font->height);
#ifdef USE_PANGO
previous_text = pango_layout_get_text(font->layout);
if ((previous_text == NULL) || (strcmp(text, previous_text) != 0))
pango_layout_set_text(font->layout, text, length);
pango_xft_render_layout(scr->xftdraw, &textColor, font->layout, x * PANGO_SCALE, y * PANGO_SCALE);
#else
XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
#endif
}
WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style)
{
FcPattern *pattern;
WMFont *copy;
char *name;
if (!font)
return NULL;
/* It's enough to add italic to slant, even if the font has no italic
* variant, but only oblique. This is because fontconfig will actually
* return the closest match font to what we requested which is the
* oblique font. Same goes for using bold for weight.
*/
pattern = FcNameParse((FcChar8 *) WMGetFontName(font));
switch (style) {
case WFSNormal:
FcPatternDel(pattern, FC_WEIGHT);
FcPatternDel(pattern, FC_SLANT);
break;
case WFSBold:
FcPatternDel(pattern, FC_WEIGHT);
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
break;
case WFSItalic:
FcPatternDel(pattern, FC_SLANT);
FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
break;
case WFSBoldItalic:
FcPatternDel(pattern, FC_WEIGHT);
FcPatternDel(pattern, FC_SLANT);
FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
break;
}
name = (char *)FcNameUnparse(pattern);
copy = WMCreateFont(scrPtr, name);
FcPatternDestroy(pattern);
free(name);
return copy;
}
+825
View File
@@ -0,0 +1,825 @@
#include "WINGsP.h"
#include "WUtil.h"
#include "wconfig.h"
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdint.h>
#include <X11/Xft/Xft.h>
#include <fontconfig/fontconfig.h>
/* XXX TODO */
char *WMFontPanelFontChangedNotification = "WMFontPanelFontChangedNotification";
typedef struct W_FontPanel {
WMWindow *win;
WMFrame *upperF;
WMTextField *sampleT;
WMSplitView *split;
WMFrame *lowerF;
WMLabel *famL;
WMList *famLs;
WMLabel *typL;
WMList *typLs;
WMLabel *sizL;
WMTextField *sizT;
WMList *sizLs;
WMAction2 *action;
void *data;
WMButton *revertB;
WMButton *setB;
WMPropList *fdb;
} FontPanel;
#define MIN_UPPER_HEIGHT 20
#define MIN_LOWER_HEIGHT 140
#define BUTTON_SPACE_HEIGHT 40
#define MIN_WIDTH 250
#define MIN_HEIGHT (MIN_UPPER_HEIGHT+MIN_LOWER_HEIGHT+BUTTON_SPACE_HEIGHT)
#define DEF_UPPER_HEIGHT 60
#define DEF_LOWER_HEIGHT 310
#define DEF_WIDTH 320
#define DEF_HEIGHT (DEF_UPPER_HEIGHT+DEF_LOWER_HEIGHT)
static const int scalableFontSizes[] = {
8,
10,
11,
12,
14,
16,
18,
20,
24,
36,
48,
64
};
static void setFontPanelFontName(FontPanel * panel, const char *family, const char *style, double size);
static int isXLFD(const char *font, int *length_ret);
static void arrangeLowerFrame(FontPanel * panel);
static void familyClick(WMWidget *, void *);
static void typefaceClick(WMWidget *, void *);
static void sizeClick(WMWidget *, void *);
static void listFamilies(WMScreen * scr, WMFontPanel * panel);
static void splitViewConstrainCallback(WMSplitView * sPtr, int indView, int *min, int *max)
{
/* Parameter not used, but tell the compiler that it is ok */
(void) sPtr;
(void) max;
if (indView == 0)
*min = MIN_UPPER_HEIGHT;
else
*min = MIN_LOWER_HEIGHT;
}
static void notificationObserver(void *self, WMNotification * notif)
{
WMFontPanel *panel = (WMFontPanel *) self;
void *object = WMGetNotificationObject(notif);
if (WMGetNotificationName(notif) == WMViewSizeDidChangeNotification) {
if (object == WMWidgetView(panel->win)) {
int h = WMWidgetHeight(panel->win);
int w = WMWidgetWidth(panel->win);
WMResizeWidget(panel->split, w, h - BUTTON_SPACE_HEIGHT);
WMMoveWidget(panel->setB, w - 80, h - (BUTTON_SPACE_HEIGHT - 5));
WMMoveWidget(panel->revertB, w - 240, h - (BUTTON_SPACE_HEIGHT - 5));
} else if (object == WMWidgetView(panel->upperF)) {
if (WMWidgetHeight(panel->upperF) < MIN_UPPER_HEIGHT) {
WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), MIN_UPPER_HEIGHT);
} else {
WMResizeWidget(panel->sampleT, WMWidgetWidth(panel->upperF) - 20,
WMWidgetHeight(panel->upperF) - 10);
}
} else if (object == WMWidgetView(panel->lowerF)) {
if (WMWidgetHeight(panel->lowerF) < MIN_LOWER_HEIGHT) {
WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), MIN_UPPER_HEIGHT);
WMMoveWidget(panel->lowerF, 0, WMWidgetHeight(panel->upperF)
+ WMGetSplitViewDividerThickness(panel->split));
WMResizeWidget(panel->lowerF, WMWidgetWidth(panel->lowerF),
WMWidgetWidth(panel->split) - MIN_UPPER_HEIGHT
- WMGetSplitViewDividerThickness(panel->split));
} else {
arrangeLowerFrame(panel);
}
}
}
}
static void closeWindow(WMWidget * w, void *data)
{
FontPanel *panel = (FontPanel *) data;
/* Parameter not used, but tell the compiler that it is ok */
(void) w;
WMHideFontPanel(panel);
}
static void setClickedAction(WMWidget * w, void *data)
{
FontPanel *panel = (FontPanel *) data;
/* Parameter not used, but tell the compiler that it is ok */
(void) w;
if (panel->action)
(*panel->action) (panel, panel->data);
}
static void revertClickedAction(WMWidget * w, void *data)
{
/* Parameter not used, but tell the compiler that it is ok */
(void) w;
(void) data;
/*FontPanel *panel = (FontPanel*)data; */
/* XXX TODO */
}
WMFontPanel *WMGetFontPanel(WMScreen * scr)
{
FontPanel *panel;
WMColor *dark, *white;
WMFont *font;
int divThickness;
if (scr->sharedFontPanel)
return scr->sharedFontPanel;
panel = wmalloc(sizeof(FontPanel));
panel->win = WMCreateWindow(scr, "fontPanel");
/* WMSetWidgetBackgroundColor(panel->win, WMWhiteColor(scr)); */
WMSetWindowTitle(panel->win, _("Font Panel"));
WMResizeWidget(panel->win, DEF_WIDTH, DEF_HEIGHT);
WMSetWindowMinSize(panel->win, MIN_WIDTH, MIN_HEIGHT);
WMSetViewNotifySizeChanges(WMWidgetView(panel->win), True);
WMSetWindowCloseAction(panel->win, closeWindow, panel);
panel->split = WMCreateSplitView(panel->win);
WMResizeWidget(panel->split, DEF_WIDTH, DEF_HEIGHT - BUTTON_SPACE_HEIGHT);
WMSetSplitViewConstrainProc(panel->split, splitViewConstrainCallback);
divThickness = WMGetSplitViewDividerThickness(panel->split);
panel->upperF = WMCreateFrame(panel->win);
WMSetFrameRelief(panel->upperF, WRFlat);
WMSetViewNotifySizeChanges(WMWidgetView(panel->upperF), True);
panel->lowerF = WMCreateFrame(panel->win);
/* WMSetWidgetBackgroundColor(panel->lowerF, WMBlackColor(scr)); */
WMSetFrameRelief(panel->lowerF, WRFlat);
WMSetViewNotifySizeChanges(WMWidgetView(panel->lowerF), True);
WMAddSplitViewSubview(panel->split, W_VIEW(panel->upperF));
WMAddSplitViewSubview(panel->split, W_VIEW(panel->lowerF));
WMResizeWidget(panel->upperF, DEF_WIDTH, DEF_UPPER_HEIGHT);
WMResizeWidget(panel->lowerF, DEF_WIDTH, DEF_LOWER_HEIGHT);
WMMoveWidget(panel->lowerF, 0, 60 + divThickness);
white = WMWhiteColor(scr);
dark = WMDarkGrayColor(scr);
panel->sampleT = WMCreateTextField(panel->upperF);
WMResizeWidget(panel->sampleT, DEF_WIDTH - 20, 50);
WMMoveWidget(panel->sampleT, 10, 10);
WMSetTextFieldText(panel->sampleT, _("The quick brown fox jumps over the lazy dog"));
font = WMBoldSystemFontOfSize(scr, 12);
panel->famL = WMCreateLabel(panel->lowerF);
WMSetWidgetBackgroundColor(panel->famL, dark);
WMSetLabelText(panel->famL, _("Family"));
WMSetLabelFont(panel->famL, font);
WMSetLabelTextColor(panel->famL, white);
WMSetLabelRelief(panel->famL, WRSunken);
WMSetLabelTextAlignment(panel->famL, WACenter);
panel->famLs = WMCreateList(panel->lowerF);
WMSetListAction(panel->famLs, familyClick, panel);
panel->typL = WMCreateLabel(panel->lowerF);
WMSetWidgetBackgroundColor(panel->typL, dark);
WMSetLabelText(panel->typL, _("Typeface"));
WMSetLabelFont(panel->typL, font);
WMSetLabelTextColor(panel->typL, white);
WMSetLabelRelief(panel->typL, WRSunken);
WMSetLabelTextAlignment(panel->typL, WACenter);
panel->typLs = WMCreateList(panel->lowerF);
WMSetListAction(panel->typLs, typefaceClick, panel);
panel->sizL = WMCreateLabel(panel->lowerF);
WMSetWidgetBackgroundColor(panel->sizL, dark);
WMSetLabelText(panel->sizL, _("Size"));
WMSetLabelFont(panel->sizL, font);
WMSetLabelTextColor(panel->sizL, white);
WMSetLabelRelief(panel->sizL, WRSunken);
WMSetLabelTextAlignment(panel->sizL, WACenter);
panel->sizT = WMCreateTextField(panel->lowerF);
/* WMSetTextFieldAlignment(panel->sizT, WARight); */
panel->sizLs = WMCreateList(panel->lowerF);
WMSetListAction(panel->sizLs, sizeClick, panel);
WMReleaseFont(font);
WMReleaseColor(white);
WMReleaseColor(dark);
panel->setB = WMCreateCommandButton(panel->win);
WMResizeWidget(panel->setB, 70, 24);
WMMoveWidget(panel->setB, 240, DEF_HEIGHT - (BUTTON_SPACE_HEIGHT - 5));
WMSetButtonText(panel->setB, _("Set"));
WMSetButtonAction(panel->setB, setClickedAction, panel);
panel->revertB = WMCreateCommandButton(panel->win);
WMResizeWidget(panel->revertB, 70, 24);
WMMoveWidget(panel->revertB, 80, DEF_HEIGHT - (BUTTON_SPACE_HEIGHT - 5));
WMSetButtonText(panel->revertB, _("Revert"));
WMSetButtonAction(panel->revertB, revertClickedAction, panel);
WMRealizeWidget(panel->win);
WMMapSubwidgets(panel->upperF);
WMMapSubwidgets(panel->lowerF);
WMMapSubwidgets(panel->split);
WMMapSubwidgets(panel->win);
WMUnmapWidget(panel->revertB);
arrangeLowerFrame(panel);
scr->sharedFontPanel = panel;
/* register notification observers */
WMAddNotificationObserver(notificationObserver, panel,
WMViewSizeDidChangeNotification, WMWidgetView(panel->win));
WMAddNotificationObserver(notificationObserver, panel,
WMViewSizeDidChangeNotification, WMWidgetView(panel->upperF));
WMAddNotificationObserver(notificationObserver, panel,
WMViewSizeDidChangeNotification, WMWidgetView(panel->lowerF));
listFamilies(scr, panel);
return panel;
}
void WMFreeFontPanel(WMFontPanel * panel)
{
if (panel == WMWidgetScreen(panel->win)->sharedFontPanel) {
WMWidgetScreen(panel->win)->sharedFontPanel = NULL;
}
WMRemoveNotificationObserver(panel);
WMUnmapWidget(panel->win);
WMDestroyWidget(panel->win);
wfree(panel);
}
void WMShowFontPanel(WMFontPanel * panel)
{
WMMapWidget(panel->win);
}
void WMHideFontPanel(WMFontPanel * panel)
{
WMUnmapWidget(panel->win);
}
WMFont *WMGetFontPanelFont(WMFontPanel * panel)
{
return WMGetTextFieldFont(panel->sampleT);
}
void WMSetFontPanelFont(WMFontPanel * panel, const char *fontName)
{
int fname_len;
FcPattern *pattern;
FcChar8 *family, *style;
double size;
if (!isXLFD(fontName, &fname_len)) {
/* maybe its proper fontconfig and we can parse it */
pattern = FcNameParse((const FcChar8 *) fontName);
} else {
/* maybe its proper xlfd and we can convert it to an FcPattern */
pattern = XftXlfdParse(fontName, False, False);
/*//FcPatternPrint(pattern); */
}
if (!pattern)
return;
if (FcPatternGetString(pattern, FC_FAMILY, 0, &family) == FcResultMatch)
if (FcPatternGetString(pattern, FC_STYLE, 0, &style) == FcResultMatch)
if (FcPatternGetDouble(pattern, "pixelsize", 0, &size) == FcResultMatch)
setFontPanelFontName(panel, (char *)family, (char *)style, size);
FcPatternDestroy(pattern);
}
void WMSetFontPanelAction(WMFontPanel * panel, WMAction2 * action, void *data)
{
panel->action = action;
panel->data = data;
}
static void arrangeLowerFrame(FontPanel * panel)
{
int width = WMWidgetWidth(panel->lowerF) - 55 - 30;
int height = WMWidgetHeight(panel->split) - WMWidgetHeight(panel->upperF);
int fw, tw, sw;
#define LABEL_HEIGHT 20
height -= WMGetSplitViewDividerThickness(panel->split);
height -= LABEL_HEIGHT + 8;
fw = (125 * width) / 235;
tw = (110 * width) / 235;
sw = 55;
WMMoveWidget(panel->famL, 10, 0);
WMResizeWidget(panel->famL, fw, LABEL_HEIGHT);
WMMoveWidget(panel->famLs, 10, 23);
WMResizeWidget(panel->famLs, fw, height);
WMMoveWidget(panel->typL, 10 + fw + 3, 0);
WMResizeWidget(panel->typL, tw, LABEL_HEIGHT);
WMMoveWidget(panel->typLs, 10 + fw + 3, 23);
WMResizeWidget(panel->typLs, tw, height);
WMMoveWidget(panel->sizL, 10 + fw + 3 + tw + 3, 0);
WMResizeWidget(panel->sizL, sw + 4, LABEL_HEIGHT);
WMMoveWidget(panel->sizT, 10 + fw + 3 + tw + 3, 23);
WMResizeWidget(panel->sizT, sw + 4, 20);
WMMoveWidget(panel->sizLs, 10 + fw + 3 + tw + 3, 46);
WMResizeWidget(panel->sizLs, sw + 4, height - 23);
}
#define NUM_FIELDS 14
static int isXLFD(const char *font, int *length_ret)
{
int c = 0;
*length_ret = 0;
while (*font) {
(*length_ret)++;
if (*font++ == '-')
c++;
}
return c == NUM_FIELDS;
}
typedef struct {
char *typeface;
WMArray *sizes;
} Typeface;
typedef struct {
char *name; /* gotta love simplicity */
WMArray *typefaces;
} Family;
static int compare_int(const void *a, const void *b)
{
int i1 = *(int *)a;
int i2 = *(int *)b;
if (i1 < i2)
return -1;
else if (i1 > i2)
return 1;
else
return 0;
}
static void addSizeToTypeface(Typeface * face, int size)
{
if (size == 0) {
int j;
for (j = 0; j < wlengthof(scalableFontSizes); j++) {
size = scalableFontSizes[j];
if (!WMCountInArray(face->sizes, (void *)(uintptr_t) size)) {
WMAddToArray(face->sizes, (void *)(uintptr_t) size);
}
}
WMSortArray(face->sizes, compare_int);
} else {
if (!WMCountInArray(face->sizes, (void *)(uintptr_t) size)) {
WMAddToArray(face->sizes, (void *)(uintptr_t) size);
WMSortArray(face->sizes, compare_int);
}
}
}
static void addTypefaceToXftFamily(Family * fam, const char *style)
{
Typeface *face;
WMArrayIterator i;
if (fam->typefaces) {
WM_ITERATE_ARRAY(fam->typefaces, face, i) {
if (strcmp(face->typeface, style) != 0)
continue; /* go to next interation */
addSizeToTypeface(face, 0);
return;
}
} else {
fam->typefaces = WMCreateArray(4);
}
face = wmalloc(sizeof(Typeface));
face->typeface = wstrdup(style);
face->sizes = WMCreateArray(4);
addSizeToTypeface(face, 0);
WMAddToArray(fam->typefaces, face);
}
/*
* families (same family name) (Hashtable of family -> array)
* registries (same family but different registries)
*
*/
static void addFontToXftFamily(WMHashTable * families, const char *name, const char *style)
{
WMArrayIterator i;
WMArray *array;
Family *fam;
array = WMHashGet(families, name);
if (array) {
WM_ITERATE_ARRAY(array, fam, i) {
if (strcmp(fam->name, name) == 0)
addTypefaceToXftFamily(fam, style);
return;
}
}
array = WMCreateArray(8);
fam = wmalloc(sizeof(Family));
fam->name = wstrdup(name);
addTypefaceToXftFamily(fam, style);
WMAddToArray(array, fam);
WMHashInsert(families, fam->name, array);
}
static void listFamilies(WMScreen * scr, WMFontPanel * panel)
{
FcObjectSet *os = 0;
FcFontSet *fs;
FcPattern *pat;
WMHashTable *families;
WMHashEnumerator enumer;
WMArray *array;
int i;
pat = FcPatternCreate();
os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
fs = FcFontList(0, pat, os);
if (!fs) {
WMRunAlertPanel(scr, panel->win, _("Error"),
_("Could not init font config library\n"), _("OK"), NULL, NULL);
return;
}
if (pat)
FcPatternDestroy(pat);
families = WMCreateHashTable(WMStringPointerHashCallbacks);
if (fs) {
for (i = 0; i < fs->nfont; i++) {
FcChar8 *family;
FcChar8 *style;
if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch)
if (FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch)
addFontToXftFamily(families, (char *)family, (char *)style);
}
FcFontSetDestroy(fs);
}
enumer = WMEnumerateHashTable(families);
while ((array = WMNextHashEnumeratorItem(&enumer))) {
WMArrayIterator i;
Family *fam;
char buffer[256];
WMListItem *item;
WM_ITERATE_ARRAY(array, fam, i) {
wstrlcpy(buffer, fam->name, sizeof(buffer));
item = WMAddListItem(panel->famLs, buffer);
item->clientData = fam;
}
WMFreeArray(array);
}
WMSortListItems(panel->famLs);
WMFreeHashTable(families);
}
static void getSelectedFont(FontPanel * panel, char buffer[], int bufsize)
{
WMListItem *item;
Family *family;
Typeface *face;
char *size;
item = WMGetListSelectedItem(panel->famLs);
if (!item)
return;
family = (Family *) item->clientData;
item = WMGetListSelectedItem(panel->typLs);
if (!item)
return;
face = (Typeface *) item->clientData;
size = WMGetTextFieldText(panel->sizT);
snprintf(buffer, bufsize, "%s:style=%s:pixelsize=%s", family->name, face->typeface, size);
wfree(size);
}
static void preview(FontPanel * panel)
{
char buffer[512];
WMFont *font;
getSelectedFont(panel, buffer, sizeof(buffer));
font = WMCreateFont(WMWidgetScreen(panel->win), buffer);
if (font) {
WMSetTextFieldFont(panel->sampleT, font);
WMReleaseFont(font);
}
}
static void familyClick(WMWidget * w, void *data)
{
WMList *lPtr = (WMList *) w;
WMListItem *item;
Family *family;
Typeface *face;
FontPanel *panel = (FontPanel *) data;
WMArrayIterator i;
/* current typeface and size */
char *oface = NULL;
char *osize = NULL;
int facei = -1;
int sizei = -1;
/* must try to keep the same typeface and size for the new family */
item = WMGetListSelectedItem(panel->typLs);
if (item)
oface = wstrdup(item->text);
osize = WMGetTextFieldText(panel->sizT);
item = WMGetListSelectedItem(lPtr);
family = (Family *) item->clientData;
WMClearList(panel->typLs);
WM_ITERATE_ARRAY(family->typefaces, face, i) {
char buffer[256];
int top = 0;
WMListItem *fitem;
wstrlcpy(buffer, face->typeface, sizeof(buffer));
if (strcasecmp(face->typeface, "Roman") == 0)
top = 1;
if (strcasecmp(face->typeface, "Regular") == 0)
top = 1;
if (top)
fitem = WMInsertListItem(panel->typLs, 0, buffer);
else
fitem = WMAddListItem(panel->typLs, buffer);
fitem->clientData = face;
}
if (oface) {
facei = WMFindRowOfListItemWithTitle(panel->typLs, oface);
wfree(oface);
}
if (facei < 0) {
facei = 0;
}
WMSelectListItem(panel->typLs, facei);
typefaceClick(panel->typLs, panel);
if (osize) {
sizei = WMFindRowOfListItemWithTitle(panel->sizLs, osize);
}
if (sizei >= 0) {
WMSelectListItem(panel->sizLs, sizei);
sizeClick(panel->sizLs, panel);
}
if (osize)
wfree(osize);
preview(panel);
}
static void typefaceClick(WMWidget * w, void *data)
{
FontPanel *panel = (FontPanel *) data;
WMListItem *item;
Typeface *face;
WMArrayIterator i;
char buffer[32];
char *osize = NULL;
int sizei = -1;
void *size;
/* Parameter not used, but tell the compiler that it is ok */
(void) w;
osize = WMGetTextFieldText(panel->sizT);
item = WMGetListSelectedItem(panel->typLs);
face = (Typeface *) item->clientData;
WMClearList(panel->sizLs);
WM_ITERATE_ARRAY(face->sizes, size, i) {
if (size != NULL) {
int size_int = (intptr_t) size;
sprintf(buffer, "%i", size_int);
WMAddListItem(panel->sizLs, buffer);
}
}
if (osize) {
sizei = WMFindRowOfListItemWithTitle(panel->sizLs, osize);
}
if (sizei < 0) {
sizei = WMFindRowOfListItemWithTitle(panel->sizLs, "12");
}
if (sizei < 0) {
sizei = 0;
}
WMSelectListItem(panel->sizLs, sizei);
WMSetListPosition(panel->sizLs, sizei);
sizeClick(panel->sizLs, panel);
if (osize)
wfree(osize);
preview(panel);
}
static void sizeClick(WMWidget * w, void *data)
{
FontPanel *panel = (FontPanel *) data;
WMListItem *item;
/* Parameter not used, but tell the compiler that it is ok */
(void) w;
item = WMGetListSelectedItem(panel->sizLs);
WMSetTextFieldText(panel->sizT, item->text);
WMSelectTextFieldRange(panel->sizT, wmkrange(0, strlen(item->text)));
preview(panel);
}
static void setFontPanelFontName(FontPanel * panel, const char *family, const char *style, double size)
{
int famrow;
int stlrow;
int sz;
char asize[64];
void *vsize;
WMListItem *item;
Family *fam;
Typeface *face;
WMArrayIterator i;
famrow = WMFindRowOfListItemWithTitle(panel->famLs, family);
if (famrow < 0) {
famrow = 0;
return;
}
WMSelectListItem(panel->famLs, famrow);
WMSetListPosition(panel->famLs, famrow);
WMClearList(panel->typLs);
item = WMGetListSelectedItem(panel->famLs);
fam = (Family *) item->clientData;
WM_ITERATE_ARRAY(fam->typefaces, face, i) {
char buffer[256];
int top = 0;
WMListItem *fitem;
wstrlcpy(buffer, face->typeface, sizeof(buffer));
if (strcasecmp(face->typeface, "Roman") == 0)
top = 1;
if (top)
fitem = WMInsertListItem(panel->typLs, 0, buffer);
else
fitem = WMAddListItem(panel->typLs, buffer);
fitem->clientData = face;
}
stlrow = WMFindRowOfListItemWithTitle(panel->typLs, style);
if (stlrow < 0) {
stlrow = 0;
return;
}
WMSelectListItem(panel->typLs, stlrow);
item = WMGetListSelectedItem(panel->typLs);
face = (Typeface *) item->clientData;
WMClearList(panel->sizLs);
WM_ITERATE_ARRAY(face->sizes, vsize, i) {
char buffer[32];
if (vsize != NULL) {
int size_int = (intptr_t) vsize;
sprintf(buffer, "%i", size_int);
WMAddListItem(panel->sizLs, buffer);
}
}
snprintf(asize, sizeof(asize) - 1, "%d", (int)(size + 0.5));
sz = WMFindRowOfListItemWithTitle(panel->sizLs, asize);
if (sz < 0) {
return;
}
WMSelectListItem(panel->sizLs, sz);
sizeClick(panel->sizLs, panel);
return;
}
+15 -3
View File
@@ -610,9 +610,10 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c
assert(W_ApplicationInitialized());
}
scrPtr = wmalloc(sizeof(W_Screen));
scrPtr = malloc(sizeof(W_Screen));
if (!scrPtr)
return NULL;
memset(scrPtr, 0, sizeof(W_Screen));
scrPtr->aflags.hasAppIcon = 1;
@@ -629,8 +630,7 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c
scrPtr->rootWin = RootWindow(display, screen);
// Will be initialized lazily in wings-rs/src/screen.rs.
scrPtr->fontCache = NULL;
scrPtr->fontCache = WMCreateHashTable(WMStringPointerHashCallbacks);
scrPtr->xftdraw = XftDrawCreate(scrPtr->display, W_DRAWABLE(scrPtr), scrPtr->visual, scrPtr->colormap);
@@ -910,6 +910,18 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c
return scrPtr;
}
void WMSetWidgetDefaultFont(WMScreen * scr, WMFont * font)
{
WMReleaseFont(scr->normalFont);
scr->normalFont = WMRetainFont(font);
}
void WMSetWidgetDefaultBoldFont(WMScreen * scr, WMFont * font)
{
WMReleaseFont(scr->boldFont);
scr->boldFont = WMRetainFont(font);
}
void WMHangData(WMWidget * widget, void *data)
{
W_VIEW(widget)->hangedData = data;
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "wings-rs-tests"
version = "0.1.0"
edition = "2024"
[dependencies]
libc = "0.2"
insta = "1.47"
insta-image = { version = "1.0", features = ["png"] }
png = "0.18"
tempdir = "0.3.7"
wings-rs = { path = "../wings-rs" }
wutil-rs = { path = "../../wutil-rs" }
x11 = "2.21.0"
[profile.dev.package]
insta.opt-level = 3
similar.opt-level = 3
-43
View File
@@ -1,43 +0,0 @@
AUTOMAKE_OPTIONS =
RUST_SOURCES = \
examples/font_panel.rs \
src/headless/mod.rs \
src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap \
src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap.png \
src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__snowlamp_in_window.snap \
src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__snowlamp_in_window.snap.png \
src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap \
src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap.png \
src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap \
src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap.png \
src/headless/snowlamp.xwd \
src/headless/xvfb.rs \
src/headless/xwd.rs \
src/lib.rs \
tests/font_panel_tests.rs \
tests/snapshots/font_panel_tests__font_panel.snap \
tests/snapshots/font_panel_tests__font_panel.snap.png
RUST_EXTRA = \
Cargo.lock \
Cargo.toml
Cargo.lock:
cargo build
rustlib: $(RUST_SOURCES) $(RUST_EXTRA)
cargo build
check-local: rustlib
clean-local:
$(CARGO) clean
all: rustlib
# Tests run with cargo-nextest because it puts each application test in its own
# process, and WINGs currently assumes that it is running in a single-threaded
# environment.
test: rustlib
LD_LIBRARY_PATH=../.libs $(CARGO) nextest run
-19
View File
@@ -1,19 +0,0 @@
fn main() {
println!("cargo::rustc-link-search=../.libs");
println!("cargo::rustc-link-arg=-lX11");
println!("cargo::rustc-link-arg-tests=-lWUtil");
println!("cargo::rustc-link-arg-tests=-lWINGs");
println!("cargo::rustc-link-arg-tests=-lXft");
println!("cargo::rustc-link-arg-tests=-lpango-1.0");
println!("cargo::rustc-link-arg-tests=-lpangoxft-1.0");
println!("cargo::rustc-link-arg-tests=-lpangoft2-1.0");
println!("cargo::rustc-link-arg-examples=-lWUtil");
println!("cargo::rustc-link-arg-examples=-lWINGs");
println!("cargo::rustc-link-arg-examples=-lX11");
println!("cargo::rustc-link-arg-examples=-lXft");
println!("cargo::rustc-link-arg-examples=-lpango-1.0");
println!("cargo::rustc-link-arg-examples=-lpangoxft-1.0");
println!("cargo::rustc-link-arg-examples=-lpangoft2-1.0");
}
@@ -1,11 +0,0 @@
use wings_rs::{font_panel::FontPanel, WINGsP::WMScreenMainLoop};
use wings_rs_tests::LiveApplication;
fn main() {
let app = LiveApplication::new("WMFontPanel");
let mut font_panel = FontPanel::new(app.screen.as_ptr()).expect("could not create font panel");
font_panel.show();
unsafe {
WMScreenMainLoop(app.screen.as_ptr());
}
}
-133
View File
@@ -1,133 +0,0 @@
//! Provides utilites for integration tests that render to a headless X11 server.
//!
//! ## X11 `DISPLAY` value allocation
//!
//! When starting headless X servers, some care needs to be taken in selecting
//! display numbers. An X server needs to have a unique display number and will
//! not start if it is assigned a display number that is already in use.
//!
//! Local X servers usually leave a lockfile in `/tmp`, like `/tmp/.X0-lock` for
//! display 0. Avoiding the use of display numbers that have a corresponding
//! lockfile will get you part of the way towards avoiding collisions, but
//! further coordination is provided by the [`Lock`] and
//! [`DisplayNumberRegistry`] structs. These interfaces provide a mechanism for
//! claiming a display number in a way that coordinates across processes and
//! should be more efficient than simply scanning `/tmp` each time a new display
//! number is needed.
use std::{
fs,
io,
path::PathBuf,
sync::atomic::{self, AtomicU16},
};
pub mod xvfb;
pub mod xwd;
/// Represents a lock on a display number, which is released on drop.
pub struct Lock {
display: u16,
path: PathBuf,
}
/// Errors that may occur when trying to lock a display number.
pub enum LockError {
Io(io::Error),
Locked,
}
impl Lock {
pub(crate) fn new(display: u16, path: PathBuf) -> Self {
Lock {
display,
path
}
}
/// Returns the locked `DISPLAY` value.
pub fn display(&self) -> u16 {
self.display
}
}
impl Drop for Lock {
fn drop(&mut self) {
// `file` should be unlinked already, but we explicitly try to delete it
// and unwrap the result so that errors aren't dropped silently.
match fs::remove_file(&self.path) {
Ok(_) => (),
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
Err(e) => panic!("could not unlink lock file: {:?}", e),
}
}
}
// Shared across threads in this process to help keep us from repeatedly asking
// for the same DISPLAY value.
static NEXT_DISPLAY: AtomicU16 = AtomicU16::new(32);
/// Coordinates on the value of `DISPLAY` to use when creating new X11 servers.
///
/// Methods on `DisplayNumberRegistry` may be called across threads or in
/// different processes to ensure that X servers are created with unique
/// display numbers.
pub struct DisplayNumberRegistry;
impl DisplayNumberRegistry {
/// Returns a lock on the first local display number (the `N` in `:N` for
/// the X client `DISPLAY` environment variable) that is not currently in
/// use.
///
/// If no display numbers are available, returns `None`.
///
/// To avoid collisions with other processes, attempts are made to sniff out
/// which display numbers are already in use by looking for lock files
/// matching the pattern `/tmp/.X*-lock`. If such a file exists, its
/// display number will not be used.
///
/// When an available display number is found, an empty lockfile is
/// atomically created (and marking the display number as claimed to other
/// well-behaved processes). When `Xvfb` is run using that display number,
/// it silently overwrites the empty lockfile.
///
/// Any extant lockfile should be deleted by the `Drop` impl for [`Lock`],
/// although tests that panic may leave stale lockfiles behind.
pub fn next_unused_display() -> io::Result<Lock> {
loop {
let prev = NEXT_DISPLAY.fetch_add(1, atomic::Ordering::SeqCst);
if prev == u16::MAX {
return Err(io::Error::other("display numbers exhausted; check /tmp/.X{n}-lock"));
}
let next = prev + 1;
let path = PathBuf::from(format!("/tmp/.X{}-lock", next));
match fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&path) {
Ok(_) => return Ok(Lock::new(next, path)),
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
Err(e) => return Err(e),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn find_unused_display() {
assert!(DisplayNumberRegistry::next_unused_display().is_ok());
assert_ne!(
DisplayNumberRegistry::next_unused_display()
.unwrap()
.display,
DisplayNumberRegistry::next_unused_display()
.unwrap()
.display
);
}
}
@@ -1,7 +0,0 @@
---
source: src/headless/xvfb.rs
assertion_line: 387
expression: xwd.into_png().unwrap()
extension: png
snapshot_kind: binary
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,7 +0,0 @@
---
source: src/headless/xvfb.rs
assertion_line: 416
expression: compressed
extension: png
snapshot_kind: binary
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

@@ -1,7 +0,0 @@
---
source: src/headless/xvfb.rs
assertion_line: 402
expression: compressed
extension: png
snapshot_kind: binary
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

@@ -1,7 +0,0 @@
---
source: src/headless/xwd.rs
assertion_line: 321
expression: snowlamp_xwd.into_png().unwrap()
extension: png
snapshot_kind: binary
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.
-471
View File
@@ -1,471 +0,0 @@
//! Provides utilities for headlessly running and taking screenshots of X11
//! programs in unit and integration tests.
//!
//! This uses [Xvfb](https://x.org/releases/X11R7.7/doc/man/man1/Xvfb.1.xhtml).
//!
//! Tests of this module invoke `xeyes` and `xwud` subprocesses. For all tests
//! to pass, you may need to install these X11 utilities and make them available
//! on your `PATH`.
use std::{
ffi::CString,
fs, io,
process::{Child, Command, ExitStatus, Stdio},
thread,
time::{Duration, Instant},
};
use tempdir::TempDir;
use super::xwd;
use super::Lock;
/// Arguments for `Xvfb`. Use `XvfbArgs::default()` for default values.
#[derive(Clone, Copy, Debug)]
pub struct XvfbArgs {
/// Width of the X11 screen.
pub width: u32,
/// Height of the X11 screen.
pub height: u32,
/// Bit depth of the X11 screen.
///
/// This should probably be one of 8, 16, or 24. (And if you don't choose 24
/// bits, you should have a good reason why.)
pub depth: u8,
}
impl Default for XvfbArgs {
fn default() -> Self {
XvfbArgs {
width: 640,
height: 480,
depth: 24,
}
}
}
/// A captive `Xvfb` process, with affordances for running subprocesses that
/// connect to it and taking screenshots.
///
/// When dropped, child processes will be killed automatically.
pub struct XvfbProcess {
lock: Lock,
framebuffer_directory: TempDir,
process: Child,
subprocesses: Vec<(Child, SubprocessMonitor)>,
is_shutdown: bool,
}
impl XvfbProcess {
/// Attempts to start `Xvfb` with default options.
///
/// Returns `None` if an error occurs while starting the `Xvfb` process.
pub fn start_default(lock: Lock) -> SubprocessResult<Self> {
XvfbProcess::start(lock, XvfbArgs::default())
}
/// Starts an `Xvfb` process with options specified by `args`.
///
/// Returns `None` if an error occurs while starting the `Xvfb` process.
///
/// This function connects to the `Xvfb` server briefly to try to ensure
/// that Xvfb is ready for clients to connect to it.
pub fn start(lock: Lock, args: XvfbArgs) -> SubprocessResult<Self> {
let framebuffer_directory = TempDir::new("wings_rs_xvfb").map_err(|e| {
SubprocessError::new("Xvfb temp dir".into(), SubprocessErrorType::Spawn(e))
})?;
#[cfg(target_os = "linux")]
unsafe {
// Kill children if this parent process dies catastrophically (e.g.,
// a test raises SIGABRT).
libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL);
}
let process = Command::new("Xvfb")
.arg(format!(":{}", lock.display))
.arg("-screen")
.arg("0")
.arg(format!("{}x{}x{}", args.width, args.height, args.depth))
.arg("-fbdir")
.arg(format!("{}", framebuffer_directory.path().display()))
.stderr(Stdio::piped())
.spawn()
.map_err(|e| SubprocessError::new("Xvfb".into(), SubprocessErrorType::Spawn(e)))?;
let process = XvfbProcess {
lock,
framebuffer_directory,
process,
subprocesses: Vec::new(),
is_shutdown: false,
};
let now = Instant::now();
let display_name = CString::new(
format!(":{}", process.lock.display)
).expect("could not construct display name");
while now.elapsed() < Duration::from_secs(1) {
unsafe {
let display = x11::xlib::XOpenDisplay(display_name.as_ptr());
if !display.is_null() {
x11::xlib::XCloseDisplay(display);
break;
}
}
thread::sleep(Duration::from_millis(10));
}
return Ok(process);
}
/// Returns the number in the `DISPLAY` environment variable to connect to
/// this X11 server.
pub fn display(&self) -> u16 {
self.lock.display
}
/// Provides access to the `Xvfb` child process wrapped by `self`.
pub fn process(&mut self) -> &mut Child {
&mut self.process
}
/// Attempts to clean up all child processes. Returns any errors encountered, or `Ok` if none.
///
/// Child processes are cleaned up with the following escalating steps:
///
/// * Call [`SubprocessMonitor::on_xvfb_shutdown`] on each child's monitor.
/// * Kill each of them directly (with [`Child::kill`]).
/// * Kill the `Xvfb` process (which may cause any children still connected to that display server to exit).
pub fn shutdown(&mut self) -> Result<(), Vec<SubprocessError>> {
if self.is_shutdown {
return Ok(());
}
self.is_shutdown = true;
let mut errors = Vec::new();
for (child, monitor) in self.subprocesses.iter_mut() {
if let Err(e) = monitor.on_xvfb_shutdown(child) {
errors.push(e);
}
match child.try_wait() {
Ok(Some(status)) => {
if let Err(e) = monitor.check_subprocess_exit(status) {
errors.push(e);
}
}
Ok(None) => {
if let Err(e) = child.kill() {
errors.push(SubprocessError::new(
monitor.name.clone(),
SubprocessErrorType::Kill(e),
));
}
}
Err(e) => errors.push(SubprocessError::new(
monitor.name.clone(),
SubprocessErrorType::Status(e),
)),
}
}
if let Err(e) = self.process.kill() {
errors.push(SubprocessError::new(
"Xvfb".into(),
SubprocessErrorType::Kill(e),
));
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
/// Runs a simple command in this display server. No command line parsing is
/// done, so `run("ls -la")` will probably not do what you expect (because
/// there is no binary on your `PATH` called `ls -la`). Use [`XvfbProcess::run_args`]
/// to provide arguments to `command`.
pub fn run(&mut self, command: impl Into<String>) -> Result<(), SubprocessError> {
let name = command.into();
self.run_args(name.clone(), &name, |_c| {})
}
/// Runs a command that you can provide arguments to in this display
/// server.
///
/// The `f` parameter can be used to modify the `Command` before it is
/// run (e.g., by adding arguments). For example:
///
/// ```
/// # use wings_rs_tests::headless::DisplayNumberRegistry;
/// # use wings_rs_tests::headless::xvfb::XvfbProcess;
/// # fn main() {
/// # let mut xvfb = XvfbProcess::start_default(DisplayNumberRegistry::next_unused_display().unwrap()).unwrap();
/// xvfb.run_args(
/// "demo of xeyes, angel-style",
/// "/usr/bin/xeyes",
/// |cmd| { cmd.arg("-biblicallyAccurate"); },
/// ).unwrap();
/// # }
/// ```
pub fn run_args(
&mut self,
name: impl Into<String>,
command: impl AsRef<std::ffi::OsStr>,
f: impl FnOnce(&mut Command),
) -> Result<(), SubprocessError> {
let mut command = Command::new(command);
command.env("DISPLAY", format!(":{}", self.lock.display));
f(&mut command);
let mut monitor = SubprocessMonitor::new(name.into(), command);
monitor.with_subprocess_exit(SubprocessMonitor::require_clean_exit());
let child = monitor.start()?;
self.subprocesses.push((child, monitor));
Ok(())
}
/// Checks all subprocesses started with the [`XvfbProcess::run`] family of
/// methods and returns errors for any that have an error status, or `Ok` if
/// none do.
pub fn check(&mut self) -> Result<(), Vec<SubprocessError>> {
let errors: Vec<_> = self
.subprocesses
.iter_mut()
.filter_map(|(child, monitor)| match child.try_wait() {
Ok(Some(status)) => monitor.check_subprocess_exit(status).err(),
_ => None,
})
.collect();
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
/// Returns a screenshot of the current framebuffer contents in `xwd(1)`
/// format.
///
/// For the same in a more generally useful format, try [`XvfbProcess::png_screenshot`].
pub fn xwd_screenshot(&self) -> io::Result<xwd::XwdImage> {
let path = self.framebuffer_directory.path().join("Xvfb_screen0");
Ok(xwd::XwdImage::read(&mut fs::read(path)?.into_iter()))
}
/// Returns a screenshot of the current framebuffer contents in PNG format.
///
/// Panics on errors.
pub fn png_screenshot(&self) -> Vec<u8> {
self.xwd_screenshot().unwrap().into_png().unwrap()
}
}
impl Drop for XvfbProcess {
fn drop(&mut self) {
self.shutdown().unwrap();
}
}
pub type SubprocessResult<T> = Result<T, SubprocessError>;
/// Errors that may occur when a subprocess fails to run or exit cleanly.
#[derive(Debug)]
pub struct SubprocessError {
/// Meaningful name that can be used to determine what subprocess failed.
pub name: String,
pub err: SubprocessErrorType,
}
impl SubprocessError {
pub fn new(name: String, err: SubprocessErrorType) -> Self {
SubprocessError { name, err }
}
}
/// Error details for `SubprocessError`.
#[derive(Debug)]
pub enum SubprocessErrorType {
/// Subprocess exited with bad exit code.
BadExit(ExitStatus),
/// Could not spawn child process (with `io::Error` as the reason).
Spawn(io::Error),
/// Could not kill child process (with `io::Error` as the reason).
Kill(io::Error),
/// Could not query child process for exit status (with `io::Error` as the reason).
Status(io::Error),
}
/// Manages spawning a subprocess, monitoring it during execution, and killing it when `Xvfb` shuts down.
pub struct SubprocessMonitor {
name: String,
command: Command,
check_subprocess_exit: Option<Box<dyn FnMut(&str, ExitStatus) -> SubprocessResult<()>>>,
on_xvfb_shutdown: Option<Box<dyn FnMut(&mut Child) -> SubprocessResult<()>>>,
}
impl SubprocessMonitor {
/// Creates a new monitor but does not start any subprocess yet.
///
/// This monitor may be configured further by calling mutators like
/// [`SubprocessMonitor::with_subprocess_exit`]. Once configuration is
/// completely, start the subprocess with [`SubprocessMonitor::start`].
pub fn new(name: impl Into<String>, command: Command) -> Self {
SubprocessMonitor {
name: name.into(),
command,
check_subprocess_exit: None,
on_xvfb_shutdown: None,
}
}
/// Sets the callback to execute when [`SubprocessMonitor::check_subprocess_exit`] is called.
pub fn with_subprocess_exit(
&mut self,
f: Box<dyn FnMut(&str, ExitStatus) -> SubprocessResult<()>>,
) -> &mut Self {
self.check_subprocess_exit = Some(f);
self
}
/// Sets the callback to execute when
/// [`SubprocessMonitor::on_xvfb_shutdown`] is called. It may check process
/// status, clean up, etc.
pub fn with_xvfb_shutdown(
&mut self,
f: Box<dyn FnMut(&mut Child) -> SubprocessResult<()>>,
) -> &mut Self {
self.on_xvfb_shutdown = Some(f);
self
}
/// Attempts to spawn a child process from the `Command` provided to
/// [`SubprocessMonitor::new`].
pub fn start(&mut self) -> SubprocessResult<Child> {
self.command
.spawn()
.map_err(|e| SubprocessError::new(self.name.clone(), SubprocessErrorType::Spawn(e)))
}
/// Called when subprocess exit status is polled. This may be used to signal
/// an error because the exit status is bad.
pub fn check_subprocess_exit(&mut self, status: ExitStatus) -> SubprocessResult<()> {
if let Some(f) = &mut self.check_subprocess_exit {
(f)(&self.name, status)
} else {
Ok(())
}
}
/// Called immediately before the parent display server is being shut
/// down. This may be used to send `SIGINT` or otherwise clean up the child
/// before it is killed more forcibly.
pub fn on_xvfb_shutdown(&mut self, child: &mut Child) -> SubprocessResult<()> {
if let Some(f) = &mut self.on_xvfb_shutdown {
(f)(child)
} else {
Ok(())
}
}
/// Returns a callback suitable for passing to [`SubprocessMonitor::check_subprocess_exit`]
/// which requires that the process has exited cleanly.
pub fn require_clean_exit() -> Box<dyn FnMut(&str, ExitStatus) -> SubprocessResult<()>> {
Box::new(|name: &str, status: ExitStatus| {
if status.success() {
Ok(())
} else {
Err(SubprocessError::new(
String::from(name),
SubprocessErrorType::BadExit(status),
))
}
})
}
}
#[cfg(test)]
mod tests {
use crate::headless::DisplayNumberRegistry;
use super::XvfbProcess;
use insta_image::assert_png_snapshot;
use std::{
thread,
time::Duration,
};
/// Starts Xvfb and returns a managing object, or panics.
fn start_xvfb() -> XvfbProcess {
XvfbProcess::start_default(
DisplayNumberRegistry::next_unused_display().expect("cannot find a value for DISPLAY"),
)
.expect("cannot start Xvfb")
}
/// Reads a single frame of PNG data from the PNG image in `data`. Panics on
/// errors.
fn read_png_metadata(data: &[u8]) -> png::OutputInfo {
let mut reader = png::Decoder::new(std::io::Cursor::new(data))
.read_info()
.unwrap();
let mut buf = vec![0; reader.output_buffer_size().unwrap()];
reader.next_frame(&mut buf).unwrap()
}
/// Launches `xeyes(1)` with colors to make sure we're doing the right thing
/// with our color channels when encoding a screenshot tas PNG.
fn xeyes_color(xvfb: &mut XvfbProcess) {
xvfb.run_args("xeyes", "xeyes", |c| {
c.arg("-outline")
.arg("blue")
.arg("-center")
.arg("red")
.arg("-fg")
.arg("green");
})
.unwrap();
thread::sleep(Duration::from_millis(100));
}
#[test]
fn png_blank_screenshot() {
let xvfb = start_xvfb();
let xwd = xvfb.xwd_screenshot().unwrap();
assert_eq!(
xwd.visual_class(),
crate::headless::xwd::VisualClass::TrueColor
);
let args = crate::headless::xvfb::XvfbArgs::default();
assert_eq!(xwd.header.depth, args.depth as u32);
assert_eq!(xwd.header.width, args.width);
assert_eq!(xwd.header.height, args.height);
assert_png_snapshot!("blank_screen", xwd.into_png().unwrap());
}
#[test]
fn png_xeyes_screenshot() {
let mut xvfb = start_xvfb();
xeyes_color(&mut xvfb);
let compressed = xvfb.png_screenshot();
let image_data = read_png_metadata(&compressed);
let args = crate::headless::xvfb::XvfbArgs::default();
assert_eq!(image_data.width, args.width);
assert_eq!(image_data.height, args.height);
assert_png_snapshot!("xeyes", compressed);
}
#[test]
fn png_lamp_image() {
let mut xvfb = start_xvfb();
xvfb.run_args("xwud", "xwud", |c| {
c.arg("-in").arg("src/headless/snowlamp.xwd");
})
.unwrap();
thread::sleep(Duration::from_millis(100));
let compressed = xvfb.png_screenshot();
assert_png_snapshot!("snowlamp_in_window", compressed);
}
}
-325
View File
@@ -1,325 +0,0 @@
//! Provides basic support for rendering dumps of X11 windows made with [the `xwud` utility](https://gitlab.freedesktop.org/xorg/app/xwud/-/blob/master/xwud.c?ref_type=heads).
use std::{
ffi::CString,
io::Cursor,
mem,
};
const SUPPORTED_XWD_VERSION: u32 = 7;
/// Header for `xwd`-style dumps of X11 windows.
///
/// This is taken from `/usr/include/X11/XWDFile.h` on a Debian system.
#[derive(Clone)]
#[repr(C)]
pub struct XwdHeader {
/// Total header size (including null-terminated window name).
pub size: u32,
/// Version of `xwd` that this dump came from.
pub version: u32,
pub _format: u32,
/// Bit depth of the X11 server.
pub depth: u32,
/// Image width.
pub width: u32,
/// Image height.
pub height: u32,
pub _x_offset: u32,
pub _byte_order: u32,
pub _bitmap_unit: u32,
pub _bitmap_bit_order: u32,
pub _bitmap_pad: u32,
pub bits_per_pixel: u32,
pub _bytes_per_line: u32,
/// X11 visual class for this window. See [`XwdImage::visual_class`] for a
/// more human-interpretable value.
pub visual_class: u32,
/// Bitmask for the red channel in pixel data.
pub red_mask: u32,
/// Bitmask for the green channel in pixel data.
pub green_mask: u32,
/// Bitmask for the blue channel in pixel data.
pub blue_mask: u32,
/// Number of bits per RGB tuple in color data. (E.g., 24-bit color may
/// actually be padded to 4 bytes.)
pub bits_per_rgb: u32,
pub _colormap_entries: u32,
/// Number of colors in the colormap for the window that this dump came from.
///
/// Note that a colormap may exist but be unused (if the visual class is not
/// one that uses a colormap).
pub ncolors: u32,
pub _window_width: u32,
pub _window_height: u32,
pub _window_x: u32,
pub _window_y: u32,
pub _window_border_width: u32,
}
const HEADER_SIZE: u32 = mem::size_of::<XwdHeader>() as u32;
/// Color data for an entry in a colormap.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct XwdColor {
pixel: u32,
red: u16,
green: u16,
blue: u16,
flags: u8,
pad: u8,
}
fn next_u32(bytes: &mut impl Iterator<Item = u8>) -> u32 {
let bytes = [
bytes.next().unwrap(),
bytes.next().unwrap(),
bytes.next().unwrap(),
bytes.next().unwrap(),
];
u32::from_be_bytes(bytes)
}
fn next_u16(bytes: &mut impl Iterator<Item = u8>) -> u16 {
let bytes = [bytes.next().unwrap(), bytes.next().unwrap()];
u16::from_be_bytes(bytes)
}
/// Describes how pixel data is represented in an `xwd` dump.
///
/// See descriptions of visual classes at
/// <https://tronche.com/gui/x/xlib/window/visual-types.html> and [the official
/// documentation](https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#visual_information)
/// for more information.
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub enum VisualClass {
StaticGray,
GrayScale,
StaticColor,
PseudoColor,
TrueColor,
DirectColor,
}
impl XwdHeader {
/// Decodes an `XwdHeader` from `bytes`, panicking on failure.
///
/// Leaves `bytes` pointing to the start of the window name.
pub fn read(bytes: &mut impl Iterator<Item = u8>) -> XwdHeader {
// This layout might change in the future, but let's just go with it for now.
XwdHeader {
size: next_u32(bytes),
version: next_u32(bytes),
_format: next_u32(bytes),
depth: next_u32(bytes),
width: next_u32(bytes),
height: next_u32(bytes),
_x_offset: next_u32(bytes),
_byte_order: next_u32(bytes),
_bitmap_unit: next_u32(bytes),
_bitmap_bit_order: next_u32(bytes),
_bitmap_pad: next_u32(bytes),
bits_per_pixel: next_u32(bytes),
_bytes_per_line: next_u32(bytes),
visual_class: next_u32(bytes),
red_mask: next_u32(bytes),
green_mask: next_u32(bytes),
blue_mask: next_u32(bytes),
bits_per_rgb: next_u32(bytes),
_colormap_entries: next_u32(bytes),
ncolors: next_u32(bytes),
_window_width: next_u32(bytes),
_window_height: next_u32(bytes),
_window_x: next_u32(bytes),
_window_y: next_u32(bytes),
_window_border_width: next_u32(bytes),
}
}
}
impl XwdColor {
/// Reads an `XwdColor` from `bytes`, panicking on failure.
///
/// Leaves `bytes` pointing to the next byte after the end of the color
/// definition.
pub fn read(bytes: &mut impl Iterator<Item = u8>) -> XwdColor {
XwdColor {
pixel: next_u32(bytes),
red: next_u16(bytes),
green: next_u16(bytes),
blue: next_u16(bytes),
flags: bytes.next().unwrap(),
pad: bytes.next().unwrap(),
}
}
}
/// A decoded `xwd` dump.
pub struct XwdImage {
/// Header with image metadata.
pub header: XwdHeader,
/// Name of the X11 window that the image came from.
pub name: CString,
/// Colormap data for the X11 window that the image came from.
///
/// Note that this may be populated even if it is unused (because the
/// window's visual class is one that does not use a colormap).
pub colors: Vec<XwdColor>,
/// Pixel data for the image.
///
/// This may be indices pointing into `colors`, or it may be actual pixel
/// values.
pub pixels: Vec<u8>,
}
impl XwdImage {
/// Reads an `XwdImage` from `bytes`, panicking on failure.
pub fn read(bytes: &mut impl Iterator<Item = u8>) -> XwdImage {
let header = XwdHeader::read(bytes);
if header.version != SUPPORTED_XWD_VERSION {
panic!(
"header version {} is not supported. only version {} files are supported.",
header.version, SUPPORTED_XWD_VERSION
);
}
let name = Self::read_name(&header, bytes);
let colors = Self::read_colors(&header, bytes);
let pixels = bytes.collect();
XwdImage {
header,
name,
colors,
pixels,
}
}
/// Reads a colormap for the image described by `header` from `bytes`.
///
/// `bytes` must point at the start of the colormap data. Leaves `bytes`
/// pointing at the first byte of the next item in the data stream.
pub fn read_colors(header: &XwdHeader, bytes: &mut impl Iterator<Item = u8>) -> Vec<XwdColor> {
let mut colors = Vec::with_capacity(header.ncolors as usize);
for _ in 0..header.ncolors {
colors.push(XwdColor::read(bytes));
}
colors
}
/// Reads the X11 window name from `bytes`.
///
/// `bytes` must point at the start of the window name. Leaves `bytes`
/// pointing at the first byte of the next item in the data stream.
///
/// Note that the window name is a null-terminated string, but `header.size`
/// (which is supposed to be equal to the size of the header structure plus
/// the window name) may actually be longer than `strlen(name) +
/// sizeof(HeaderType)`. When that is the case, the extra padding after the
/// first null byte in the window name will be passed over silently.
pub fn read_name(header: &XwdHeader, bytes: &mut impl Iterator<Item = u8>) -> CString {
if header.size <= HEADER_SIZE {
panic!(
"Invalid header size {} (smaller than header struct size {})",
header.size, HEADER_SIZE
);
}
let mut buf = Vec::new();
let mut found_nul = false;
for _ in 0..header.size - HEADER_SIZE {
let b = bytes.next().unwrap();
if b == 0 {
if found_nul {
continue;
} else {
buf.push(b);
found_nul = true;
}
} else {
buf.push(b);
}
}
CString::from_vec_with_nul(buf).unwrap()
}
/// Returns the visual class for this window dump.
pub fn visual_class(&self) -> VisualClass {
match self.header.visual_class {
0 => VisualClass::StaticGray,
1 => VisualClass::GrayScale,
2 => VisualClass::StaticColor,
3 => VisualClass::PseudoColor,
4 => VisualClass::TrueColor,
5 => VisualClass::DirectColor,
_ => panic!(
"unrecognized X11 visual class: {}",
self.header.visual_class
),
}
}
/// Encodes this image as a PNG, consumes `self` in the process (because the
/// image data is reused during the encoding process).
///
/// Note that only [`VisualClass::TrueColor`] images with a specific pixel
/// format (24-bit color packed into 32-bit segments with BGR ordering) are
/// supported.
pub fn into_png(self) -> Result<Vec<u8>, png::EncodingError> {
match self.visual_class() {
VisualClass::TrueColor => into_png_true_color(self.header, self.pixels),
_ => todo!("X11 visual classes other than TrueColor are not yet supported"),
}
}
}
fn into_png_true_color(
header: XwdHeader,
mut pixels: Vec<u8>,
) -> Result<Vec<u8>, png::EncodingError> {
if header.depth != 24 {
todo!("pixmap color depths other than 24-bit are not yet supported");
}
if !(header.red_mask == 0xff0000
&& header.green_mask == 0x00ff00
&& header.blue_mask == 0x0000ff)
{
todo!("color orderings other than RGB are not yet supported");
}
if header.bits_per_rgb == 32 {
todo!("bits per rgb triplet other than 32 are not yet supported");
}
let mut out = Cursor::new(Vec::<u8>::new());
let mut encoder = png::Encoder::new(&mut out, header.width, header.height);
encoder.set_color(png::ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight);
encoder.set_compression(png::Compression::High);
for pixel in pixels.chunks_mut(4) {
let blue = pixel[0];
let green = pixel[1];
let red = pixel[2];
pixel[0] = red;
pixel[1] = green;
pixel[2] = blue;
pixel[3] = 0xFF;
}
let mut writer = encoder.write_header()?;
writer.write_image_data(&pixels)?;
writer.finish()?;
Ok(out.into_inner())
}
#[cfg(test)]
mod tests {
use super::XwdImage;
use insta_image::assert_png_snapshot;
#[test]
fn png_encode() {
let snowlamp_xwd = XwdImage::read(&mut include_bytes!("snowlamp.xwd").into_iter().copied());
assert_png_snapshot!("snowlamp_encoded", snowlamp_xwd.into_png().unwrap());
}
}
-185
View File
@@ -1,185 +0,0 @@
pub mod headless;
use headless::{xvfb::XvfbProcess, DisplayNumberRegistry};
use std::{
env,
ffi::{c_char, c_int, CStr, CString},
ptr::{self, NonNull},
sync::Mutex,
};
use wings_rs::WINGsP::{WMHandleEvent, WMInitializeApplication, WMReleaseApplication, WMScreen};
static APPLICATION_COUNT: Mutex<u32> = Mutex::new(0);
/// Stubbed wrapper for WMApplication.
pub struct HeadlessApplication {
/// The headless X server process.
pub xvfb: XvfbProcess,
/// An open client handle to the headless X server.
pub display: NonNull<x11::xlib::Display>,
/// A fully initialized `WMScreen` for an application running on the
/// headless X server.
pub screen: NonNull<WMScreen>,
}
impl HeadlessApplication {
/// Starts a headless X server and calls `WMInitializeApplication` if no
/// WINGs application is active.
pub fn new() -> Self {
static PROGNAME: &'static CStr = c"Test@eqweq_ewq$eqw";
let xvfb = XvfbProcess::start_default(
DisplayNumberRegistry::next_unused_display()
.expect("cannot allocate a value for DISPLAY"),
)
.expect("cannot start Xvfb");
{
let mut application_count = APPLICATION_COUNT.lock().unwrap();
if *application_count == 0 {
unsafe {
let mut argv: Vec<*mut c_char> =
vec![PROGNAME.as_ptr().cast::<c_char>() as *mut c_char];
let mut argc: c_int = 1;
WMInitializeApplication(
PROGNAME.as_ptr().cast::<c_char>(),
&mut argc as *mut _,
argv.as_mut_ptr(),
);
}
}
*application_count += 1;
}
let display_str = CString::new(format!(":{}", xvfb.display())).unwrap();
let display =
NonNull::new(unsafe { x11::xlib::XOpenDisplay(display_str.as_ptr()) }).unwrap();
let screen = WMScreen::new(&display).unwrap();
HeadlessApplication {
xvfb,
display,
screen,
}
}
/// Pumps the WUtil and X11 event queues, hackily.
///
/// Runs WUtil event handlers that should be run by `now`, pumps the X11
/// event queue, dispatches the next pending event (if any), and runs
/// WUtil idle handlers (if no X11 events are available).
///
/// Returns `true` if more events are pending. (This does not account for
/// WUtils timer events that might need to fire, since the future time when
/// `pump_event_queue` will next be called cannot be known.)
///
/// This is somewhat hacky (because it does not match the WINGs main loop
/// logic exactly), so it should only be used by tests.
pub fn pump_event_queue(&mut self, now: std::time::Instant) -> bool {
let display = self.display.as_ptr();
wutil_rs::handlers::with_global_handlers(|handlers| handlers.check_timer_handlers(now));
unsafe {
x11::xlib::XSync(display, 0);
if x11::xlib::XPending(display) > 0 {
let mut event = x11::xlib::XEvent { type_: 0 };
x11::xlib::XNextEvent(display, &mut event as *mut _);
WMHandleEvent(&mut event as *mut _);
} else {
wutil_rs::handlers::run_global_idle_handlers();
}
x11::xlib::XSync(display, 0);
if x11::xlib::XPending(display) > 0 {
return true;
}
wutil_rs::handlers::with_global_handlers(|handlers| handlers.has_idle_handlers())
}
}
}
impl Drop for HeadlessApplication {
fn drop(&mut self) {
unsafe {
x11::xlib::XCloseDisplay(self.display.as_ptr());
// Leak self.screen, since WINGs doesn't provide a cleanup function.
}
let mut application_count = APPLICATION_COUNT.lock().unwrap();
if *application_count <= 1 {
*application_count = 0;
unsafe {
WMReleaseApplication();
}
} else {
*application_count -= 1;
}
self.xvfb.shutdown().unwrap();
}
}
/// Simple wrapper for demo WINGs applications.
///
/// This handles calling `WMInitializeApplication`, which operates on a
/// singleton behind the scenes and wants to be passed command line arguments.
///
/// When the last instantiated `LiveApplication` is dropped,
/// `WMReleaseApplication` is called automatically.
pub struct LiveApplication {
/// Live X11 `Display` that the application is running on.
pub display: NonNull<x11::xlib::Display>,
/// Fully intialized `WMScreen` for the application.
///
/// This is leaked when the `LiveApplication` is dropped because WINGs does
/// not provide a deletion function.
pub screen: NonNull<WMScreen>,
}
impl LiveApplication {
/// Creates a new application wrapper and initializes the global
/// `WMApplication` if necessary.
pub fn new(name: &str) -> Self {
let mut application_count = APPLICATION_COUNT.lock().unwrap();
if *application_count > 0 {
panic!("application already started!");
}
let name = CString::new(name).expect("invalid program name");
unsafe {
let mut argv: Vec<CString> = vec![name];
let name_ptr = argv[0].as_ptr().cast::<c_char>();
for arg in env::args() {
argv.push(CString::new(arg).expect("invalid argument string"));
}
let mut argv_ptrs: Vec<*mut c_char> = argv
.iter_mut()
.map(|a| a.as_ptr().cast::<c_char>() as *mut c_char)
.collect();
let mut argc: c_int = argv_ptrs.len().try_into().expect("invalid argument count");
WMInitializeApplication(name_ptr, &mut argc as *mut _, argv_ptrs.as_mut_ptr());
}
*application_count = 1;
let display = NonNull::new(unsafe { x11::xlib::XOpenDisplay(ptr::null_mut()) })
.expect("could not connect to X11 display");
let screen = WMScreen::new(&display).unwrap();
LiveApplication { display, screen }
}
}
impl Drop for LiveApplication {
fn drop(&mut self) {
unsafe {
x11::xlib::XCloseDisplay(self.display.as_ptr());
// Leak self.screen, since WINGs doesn't provide a cleanup function.
}
let mut application_count = APPLICATION_COUNT.lock().unwrap();
if *application_count <= 1 {
*application_count = 0;
unsafe {
WMReleaseApplication();
}
} else {
*application_count -= 1;
}
}
}
@@ -1,14 +0,0 @@
use insta_image::assert_png_snapshot;
use std::time::Instant;
use wings_rs::font_panel::FontPanel;
use wings_rs_tests::HeadlessApplication;
#[test]
fn show_font_panel() {
let mut app = HeadlessApplication::new();
let mut font_panel =
FontPanel::new(app.screen.as_ptr()).expect("could not construct font panel");
font_panel.show();
while app.pump_event_queue(Instant::now()) {}
assert_png_snapshot!("font_panel", app.xvfb.png_screenshot());
}
@@ -1,7 +0,0 @@
---
source: tests/font_panel_tests.rs
assertion_line: 16
expression: app.xvfb.png_screenshot()
extension: png
snapshot_kind: binary
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

-15
View File
@@ -1,15 +0,0 @@
[package]
name = "wings-rs"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
libc = "0.2.177"
pango-sys = "0.21.2"
wrlib-rs = { path = "../../wrlib-rs" }
wutil-rs = { path = "../../wutil-rs" }
x11 = "2.21.0"
yeslogic-fontconfig-sys = "6.0"
-73
View File
@@ -1,73 +0,0 @@
AUTOMAKE_OPTIONS =
RUST_SOURCES = \
src/WINGsP.rs \
src/button.rs \
src/configuration.rs \
src/font.rs \
src/font_panel.rs \
src/lib.rs \
src/list.rs \
src/pango_extras.rs \
src/screen.rs \
src/widget.rs
RUST_EXTRA = \
Cargo.lock \
Cargo.toml
src/WINGsP.rs: ../WINGs/WINGsP.h ../../wrlib/wraster.h ../WINGs/WINGs.h ../WINGs/WUtil.h Makefile patch_WINGsP.sh
$(BINDGEN) ../WINGs/WINGsP.h \
--no-recursive-allowlist \
--allowlist-type "^W_.+|^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Color|Pixmap|FilePanel)|R(Context|ContextAttributes|Image|RenderingMode|ScalingFilter|StdColormapMode|ImageFormat|Color)|_WINGsConfiguration" \
--allowlist-type "^WM(FontPanel|Screen|Button)" \
--allowlist-function "^WMCreateScreen|^WM(Get|Show)FontPanel|^WMCreateCommandButton|^WM(Initialize|Release)Application|^WMScreenMainLoop|^WMHandleEvent" \
--allowlist-function "^WMWidgetScreen|^WM(Initialize|Release)Application|^WM(ScreenMainLoop|HandleEvent)|^WM(((Get|Set)TextFieldFont)|GetTextFieldText|SetTextFieldText|SelectTextFieldRange)" \
--allowlist-type "WMList" \
--allowlist-function "^WM(CreateList|SetListAction|GetListSelectedItem|InsertListItem|ClearList|FindRowOfListItemWithTitle|SelectListItem|SetListPosition|SortListItems)" \
--allowlist-type "^WM(Window|Action)" \
--allowlist-function "^WM(CreateWindow|SetWindowTitle|SetWindowMinSize|SetWindowCloseAction)" \
--allowlist-type "^WMWidget" \
--allowlist-function "^WM(Map|Destroy|Unmap|Resize|Realize|Move)Widget" \
--allowlist-function "^WMWidget(Width|Height)" \
--allowlist-function "^WM(SetWidgetBackgroundColor|SetWidgetBackgroundColor|MapSubwidgets)" \
--allowlist-type "^WM(SplitView|SplitViewConstrainProc)" \
--allowlist-function "^WM(SetViewNotifySizeChanges|CreateSplitView|SetSplitViewConstrainProc|GetSplitViewDividerThickness|AddSplitViewSubview)" \
--allowlist-type "^WMNotification" \
--allowlist-function "^WM(Add|Remove)NotificationObserver|^WMGetNotification(Object|Name)" \
--allowlist-item "^WMNotificationObserverAction" \
--allowlist-item "^WMViewSizeDidChangeNotification" \
--allowlist-type "^WMFrame" \
--allowlist-function "^WM(CreateFrame|SetFrameRelief)" \
--allowlist-function "^WM(White|DarkGray|Release)Color" \
--allowlist-type "^WMTextField" \
--allowlist-function "^WM(CreateTextField)" \
--allowlist-type "^WMLabel" \
--allowlist-function "^WM(CreateLabel|SetLabelText|SetLabelFont|SetLabelTextColor|SetLabelRelief|SetLabelTextAlignment)" \
--allowlist-type "^WM(Button|ButtonBehaviorMask)" \
--allowlist-function "^WM(CreateCustomButton|SetButtonText|SetButtonAction|SetButtonText)" \
--allowlist-function "wmkrange" \
--allowlist-type "^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Color|Pixmap|FilePanel|Screen|Range|List|ListItem)" \
--allowlist-type "^R(Context|ContextAttributes|Image|RenderingMode|ScalingFilter|StdColormapMode|ImageFormat|Color)" \
--allowlist-type "_WINGsConfiguration" \
--allowlist-item "^WMAlignment" \
--allowlist-item "^WMReliefType" \
-o src/WINGsP.rs -- \
@PANGO_CFLAGS@ \
-I../../wrlib \
-I.. && ./patch_WINGsP.sh src/WINGsP.rs
Cargo.lock:
$(CARGO) build
target/debug/libwings_rs.so: $(RUST_SOURCES) $(RUST_EXTRA)
$(CARGO) build
check-local:
$(CARGO) test
clean-local:
$(CARGO) clean
rm -f src/WINGsP.rs
all: target/debug/libwings_rs.so
-22
View File
@@ -1,22 +0,0 @@
#!/bin/sh
# This file provides ad-hoc fixups to the WINGsP provided by bindgen:
# - Import Xlib symbols so that everything compiles.
# - The opaque type names _XftDraw and _XftFont are replaced with void*.
# - Pango bindings aren't yet pulled into our Rust code, so PangoLayout is also demoted to void*.
set -e
if [ "x$1" = "x" ]; then
echo "Usage: $(basename $0) <file to patch>"
exit 1
fi
FILE="$1"
exec sed -i -r \
-e "1s/^/use x11::xlib::*;\nuse crate::font::ffi::WMFont;\n\n/" \
-e "s/_XftDraw/::std::ffi::c_void/g" \
-e "s/_XftFont/::std::ffi::c_void/g" \
-e "s/PangoLayout/::std::ffi::c_void/g" \
"$1"
-22
View File
@@ -1,22 +0,0 @@
#[allow(non_snake_case)]
pub mod ffi {
use crate::WINGsP::*;
/// Creates a button like an "Ok" button to dismiss a dialog.
///
/// ## Rust rewrite notes
///
/// This was originally a macro.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreateCommandButton(parent: *mut WMWidget) -> *mut WMButton {
unsafe {
WMCreateCustomButton(
parent,
(WMButtonBehaviorMask_WBBSpringLoadedMask
| WMButtonBehaviorMask_WBBPushInMask
| WMButtonBehaviorMask_WBBPushLightMask
| WMButtonBehaviorMask_WBBPushChangeMask) as i32,
)
}
}
}
-66
View File
@@ -1,66 +0,0 @@
//! Global WINGs configuration.
//!
//! Use [`Configuration::global`] to get a snapshot of current configuration
//! settings.
//!
//! ## Rust rewrite notes
//!
//! This accesses a global that is defined in C code. Once more of WINGs is
//! migrated to Rust, we should use a different approach that is more
//! Rust-friendly. Threading a configuration object down the stack is a likely
//! way to go.
use crate::WINGsP::_WINGsConfiguration;
use std::{ffi::CStr, ptr::NonNull};
unsafe extern "C" {
static WINGsConfiguration: _WINGsConfiguration;
}
#[derive(Clone, Copy, Debug)]
pub struct Configuration {
pub system_font: &'static CStr,
pub bold_system_font: &'static CStr,
pub default_font_size: u16,
pub antialiased_text: bool,
pub floppy_path: &'static CStr,
pub double_click_delay: u32,
pub mouse_wheel_up: u32,
pub mouse_wheel_down: u32,
}
impl Configuration {
/// Returns the current WINGs configuration. Returns `None` if the
/// configuration appears not to have been loaded.
///
/// This should only be called after `W_ReadConfigurations` is called
/// (presumably when initializing WINGs in C code), but it should be safe to
/// call it at any time. (It may just contain nonsense values.)
///
/// ## Rust rewrite notes
///
/// We should migrate away from a static global and thread a configuration
/// object in some other way.
pub fn global() -> Option<Self> {
let c = unsafe { &WINGsConfiguration };
let system_font = unsafe { CStr::from_ptr(NonNull::new(c.systemFont)?.as_ptr()) };
let bold_system_font = unsafe { CStr::from_ptr(NonNull::new(c.boldSystemFont)?.as_ptr()) };
let default_font_size = u16::try_from(c.defaultFontSize).ok()?;
let antialiased_text = c.antialiasedText != 0;
let floppy_path = unsafe { CStr::from_ptr(NonNull::new(c.floppyPath)?.as_ptr()) };
let double_click_delay = u32::try_from(c.doubleClickDelay).ok()?;
let mouse_wheel_up = u32::try_from(c.mouseWheelUp).ok()?;
let mouse_wheel_down = u32::try_from(c.mouseWheelDown).ok()?;
Some(Configuration {
system_font,
bold_system_font,
default_font_size,
antialiased_text,
floppy_path,
double_click_delay,
mouse_wheel_up,
mouse_wheel_down,
})
}
}
-586
View File
@@ -1,586 +0,0 @@
use crate::pango_extras;
use std::{
ffi::{CStr, CString, c_double, c_int, c_uint, c_void},
ptr::NonNull,
rc::Rc,
};
use crate::configuration::Configuration;
pub const DEFAULT_FONT: &'static str = "sans serif:pixelsize=12";
pub const DEFAULT_FONT_CSTR: &'static CStr = c"sans serif:pixelsize=12";
/// A loaded font, with support for basic drawing operations.
///
/// This owns Pango rendering state, and draw operations may mutate it. As a
/// result, this is not at all thread-safe.
///
/// ## Rust rewrite notes
///
/// Unlike the original C API, font caching is handled by methods on
/// [`W_Screen`].
pub struct Font {
name: FontName,
font: NonNull<x11::xft::XftFont>,
height: c_uint,
ascent: c_uint,
layout: NonNull<pango_sys::PangoLayout>,
}
/// Attempts to convert `xlfd` to a Fontconfig pattern. Returns `None` if this
/// cannot be accomplished (e.g., `xlfd` could not be parsed).
fn xlfd_to_fc_pattern(xlfd: &str) -> Option<NonNull<x11::xft::FcPattern>> {
if xlfd.contains('%') {
return NonNull::new(unsafe {
fontconfig_sys::FcNameParse(DEFAULT_FONT_CSTR.as_ptr()).cast::<x11::xft::FcPattern>()
});
}
let name = xlfd.split(',').next().unwrap();
let ignore_scalable = 0;
let complete = 0;
NonNull::new(unsafe {
x11::xft::XftXlfdParse(
name.as_ptr(),
ignore_scalable,
complete,
)
})
.or_else(|| {
// TODO: warn.
NonNull::new(unsafe {
x11::xft::XftXlfdParse(
DEFAULT_FONT_CSTR.as_ptr(),
ignore_scalable,
complete,
)
})
})
}
/// A font name, with support for X logical font descriptions (like
/// `-bitstream-charter-medium-r-normal--12-120-75-75-p-68-iso8859-1`, including
/// `*`-style wildcards but not old-style `%d` tokens) and Fontconfig
/// descriptions (like `sans serif:pixelsize=12`).
///
/// Data is held in a [`std::rc::Rc`], so copies are lightweight, and ownership
/// may be shared between multiple objects (e.g., keying a hashtable and
/// referenced by hashtable values).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct FontName(Rc<CStr>);
impl FontName {
/// Tries to interpret `name` as an XLFD or Fontconfig name. Returns an
/// instantiated `FontName` if this succeeds, or `None`.
pub fn new(name: &str) -> Option<Self> {
let name = if name.starts_with('-') {
let pattern = xlfd_to_fc_pattern(name)?;
let name = unsafe { fontconfig_sys::FcNameUnparse(pattern.as_ptr().cast::<c_void>()) };
let name = NonNull::new(name)?;
let result = unsafe { CStr::from_ptr(name.as_ptr()) }.to_str().ok()?;
unsafe {
libc::free(name.as_ptr().cast::<c_void>());
fontconfig_sys::FcPatternDestroy(pattern.as_ptr().cast::<c_void>());
}
result
} else {
name
};
if !Configuration::global()
.map(|c| c.antialiased_text)
.unwrap_or(false)
&& !name.contains(":antialias=")
{
let mut name = String::from(name);
name += ":antialias=false";
Some(FontName(Rc::from(CString::new(name).ok()?)))
} else {
Some(FontName(Rc::from(CString::new(name).ok()?)))
}
}
/// Returns a C-style string owned by this object that names the font in a
/// way that is suitable for `x11::xft::XftFontOpenName` and other Xft
/// functions.
pub fn as_xft_name(&self) -> *const u8 {
self.0.as_ptr()
}
/// Converts `self` into a shareable name.
pub fn into_name(self) -> Rc<CStr> {
self.0.into()
}
}
impl Font {
/// Tries to load the named font for `screen` on `display`. Returns `None`
/// if `name` can't be handled or font cannot be loaded.
pub fn load(display: &mut x11::xlib::Display, screen: c_int, name: &FontName) -> Option<Self> {
let font = NonNull::new(unsafe {
x11::xft::XftFontOpenName(display, screen, name.as_xft_name())
})?;
let f = unsafe { font.as_ref() };
let height = u32::try_from(f.ascent + f.descent).ok()?;
let fontmap = unsafe { pango_extras::pango_xft_get_font_map(display, screen) };
let context = unsafe { pango_sys::pango_font_map_create_context(fontmap) };
let layout = NonNull::new(unsafe { pango_sys::pango_layout_new(context) })?;
let pattern = unsafe { fontconfig_sys::FcNameParse(name.as_xft_name()) };
let description =
unsafe { pango_extras::pango_fc_font_description_from_pattern(pattern.cast(), 0) };
// Pango examines FC_SIZE but not FC_PIXEL_SIZE of the pattern, but
// font-name has only "pixelsize", so set the size manually here.
let mut size: c_double = 0.0;
unsafe {
if fontconfig_sys::FcPatternGetDouble(
pattern,
fontconfig_sys::constants::FC_PIXEL_SIZE.as_ptr(),
0,
&mut size,
) == fontconfig_sys::FcResultMatch
{
pango_sys::pango_font_description_set_absolute_size(
description,
size * (pango_sys::PANGO_SCALE as c_double),
);
}
pango_sys::pango_layout_set_font_description(layout.as_ptr(), description);
pango_sys::pango_font_description_free(description);
}
Some(Font {
font,
height,
ascent: u32::try_from(f.ascent).ok()?,
name: name.clone(),
layout,
})
}
/// Loads the font `name` at the size `size` (in pixels).
pub fn load_at_size(
display: &mut x11::xlib::Display,
screen: c_int,
name: &FontName,
size: u32,
) -> Option<Self> {
let pattern = unsafe { fontconfig_sys::FcNameParse(name.as_xft_name()) };
unsafe {
fontconfig_sys::FcPatternDel(
pattern,
fontconfig_sys::constants::FC_PIXEL_SIZE.as_ptr(),
);
fontconfig_sys::FcPatternAddDouble(
pattern,
fontconfig_sys::constants::FC_PIXEL_SIZE.as_ptr(),
size as f64,
);
}
let name = unsafe { fontconfig_sys::FcNameUnparse(pattern) };
unsafe {
fontconfig_sys::FcPatternDestroy(pattern);
}
let name = NonNull::new(name)?;
let font_name = FontName(Rc::from(unsafe { CStr::from_ptr(name.as_ptr()) }));
unsafe {
libc::free(name.as_ptr().cast::<c_void>());
}
Font::load(display, screen, &font_name)
}
pub fn name(&self) -> &FontName {
&self.name
}
}
impl Drop for Font {
fn drop(&mut self) {
unsafe {
libc::free(self.font.as_ptr().cast::<c_void>());
}
}
}
pub mod ffi {
use super::{Font, FontName};
use std::ffi::CStr;
use crate::{WINGsP, configuration::Configuration, pango_extras};
use std::{
ffi::{c_char, c_int, c_uint},
ptr,
rc::Rc,
};
pub type WMFont = Rc<Font>;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreateFont(
screen: *mut WINGsP::W_Screen,
font_name: *const c_char,
) -> *mut WMFont {
if screen.is_null() || font_name.is_null() {
return ptr::null_mut();
}
let screen = unsafe { &mut *screen };
if screen.display.is_null() {
return ptr::null_mut();
}
let font_name = unsafe { CStr::from_ptr(font_name) };
let Ok(font_name) = font_name.to_str() else {
return ptr::null_mut();
};
let Some(font_name) = FontName::new(font_name) else {
return ptr::null_mut();
};
let display = unsafe { &mut *screen.display };
let screen_n = screen.screen;
screen
.font_cache_get_or_else(font_name, |font_name| {
Font::load(display, screen_n, font_name)
})
.map(|font| Box::leak(Box::new(font)) as *mut WMFont)
.unwrap_or(ptr::null_mut())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMRetainFont(font: *mut WMFont) -> *mut WMFont {
if font.is_null() {
return ptr::null_mut();
}
let font = unsafe { (*font).clone() };
Box::leak(Box::new(font))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMReleaseFont(font: *mut WMFont) {
if font.is_null() {
return;
}
let _ = unsafe { Box::from_raw(font) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetFontName(font: *const WMFont) -> *const c_char {
if font.is_null() {
return ptr::null_mut();
}
unsafe { (**font).name.as_xft_name() }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMFontAscent(font: *mut WMFont) -> c_uint {
if font.is_null() {
return 0;
}
return unsafe { (**font).ascent };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMFontXftFont(font: *mut WMFont) -> *mut x11::xft::XftFont {
if font.is_null() {
return ptr::null_mut();
}
return unsafe { (**font).font.as_ptr() };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMFontHeight(font: *const WMFont) -> c_uint {
if font.is_null() {
return 0;
}
unsafe { (**font).height }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetScaleBaseFromSystemFont(
screen: *mut WINGsP::W_Screen,
alphabet_width: *mut c_int,
font_height: *mut c_int,
) {
let font = unsafe { WMDefaultSystemFont(screen) };
unsafe {
*alphabet_width = WMWidthOfString(font, c"abcdefghijklmnopqrstuvwxyz".as_ptr(), 26);
}
if let Ok(x) = unsafe { (**font).height.try_into() } {
unsafe {
*font_height = x;
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMDefaultSystemFont(screen: *mut WINGsP::W_Screen) -> *mut WMFont {
if screen.is_null() {
return ptr::null_mut();
}
unsafe { WMRetainFont((*screen).normalFont) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMDefaultBoldSystemFont(screen: *mut WINGsP::W_Screen) -> *mut WMFont {
if screen.is_null() {
return ptr::null_mut();
}
unsafe { WMRetainFont((*screen).boldFont) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMSystemFontOfSize(
screen: *mut WINGsP::W_Screen,
size: c_int,
) -> *mut WMFont {
if screen.is_null() {
return ptr::null_mut();
}
let screen = unsafe { &*screen };
if screen.display.is_null() {
return ptr::null_mut();
}
if screen.display.is_null() {
return ptr::null_mut();
}
let display = unsafe { &mut *screen.display };
let size = if size > 0 {
size as u32
} else {
match Configuration::global().map(|c| c.default_font_size as u32) {
Some(x) => x,
None => return ptr::null_mut(),
}
};
let Some(font_name) = Configuration::global()
.and_then(|c| c.system_font.to_str().ok())
.and_then(|name| FontName::new(name))
else {
return ptr::null_mut();
};
if let Some(font) = Font::load_at_size(display, screen.screen, &font_name, size) {
Box::leak(Box::new(Rc::new(font)))
} else {
// TODO: warn.
ptr::null_mut()
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMBoldSystemFontOfSize(
screen: *mut WINGsP::W_Screen,
size: c_int,
) -> *mut WMFont {
if screen.is_null() {
return ptr::null_mut();
}
let screen = unsafe { &*screen };
if screen.display.is_null() {
return ptr::null_mut();
}
if screen.display.is_null() {
return ptr::null_mut();
}
let display = unsafe { &mut *screen.display };
let size = if size > 0 {
size as u32
} else {
match Configuration::global().map(|c| c.default_font_size as u32) {
Some(x) => x,
None => return ptr::null_mut(),
}
};
let Some(font_name) = Configuration::global()
.and_then(|c| c.bold_system_font.to_str().ok())
.and_then(|name| FontName::new(name))
else {
return ptr::null_mut();
};
if let Some(font) = Font::load_at_size(display, screen.screen, &font_name, size) {
Box::leak(Box::new(Rc::new(font)))
} else {
// TODO: warn.
ptr::null_mut()
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMWidthOfString(
font: *mut WMFont,
text: *const c_char,
length: c_int,
) -> c_int {
if font.is_null() || text.is_null() || length <= 0 {
return 0;
}
let font = unsafe { &*font };
let layout = font.layout.as_ptr();
let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) };
if previous_text.is_null() {
unsafe {
pango_sys::pango_layout_set_text(layout, text, length);
}
} else {
let length = length as usize;
let previous_text = unsafe { CStr::from_ptr(previous_text).to_bytes() };
let text = unsafe { std::slice::from_raw_parts(text, length) };
if previous_text.len() < length || previous_text[0..length] != text[0..length] {
unsafe {
pango_sys::pango_layout_set_text(layout, text.as_ptr(), length as i32);
}
}
}
let mut width = 0;
unsafe {
pango_sys::pango_layout_get_pixel_size(layout, &mut width, ptr::null_mut());
}
width
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMDrawString(
screen: *mut WINGsP::W_Screen,
d: x11::xlib::Drawable,
color: *mut WINGsP::W_Color,
font: *mut WMFont,
x: c_int,
y: c_int,
text: *const c_char,
length: c_int,
) {
if screen.is_null() || color.is_null() || font.is_null() || text.is_null() {
return;
}
let screen = unsafe { &*screen };
let color = unsafe { &*color };
let layout = unsafe { &mut *(**font).layout.as_ptr() };
let mut xftcolor = x11::xft::XftColor {
color: x11::xrender::XRenderColor {
red: color.color.red,
green: color.color.green,
blue: color.color.blue,
alpha: color.alpha,
},
pixel: color.color.pixel,
};
let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) };
if previous_text.is_null() {
unsafe {
pango_sys::pango_layout_set_text(layout, text, length);
}
} else {
let text = unsafe { CStr::from_ptr(text) };
let previous_text = unsafe { CStr::from_ptr(previous_text) };
if previous_text != text {
unsafe {
pango_sys::pango_layout_set_text(layout, text.as_ptr(), length);
}
}
}
unsafe {
x11::xft::XftDrawChange(screen.xftdraw.cast(), d);
pango_extras::pango_xft_render_layout(
screen.xftdraw.cast(),
&mut xftcolor,
layout,
x * pango_sys::PANGO_SCALE,
y * pango_sys::PANGO_SCALE,
);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMDrawImageString(
screen: *mut WINGsP::W_Screen,
d: x11::xlib::Drawable,
color: *mut WINGsP::W_Color,
background: *mut WINGsP::W_Color,
font: *mut WMFont,
x: c_int,
y: c_int,
text: *const c_char,
length: c_int,
) {
if screen.is_null() || color.is_null() || font.is_null() || text.is_null() {
return;
}
let screen = unsafe { &*screen };
let color = unsafe { &*color };
let background = unsafe { &*background };
let layout = unsafe { &mut *(**font).layout.as_ptr() };
let mut text_color = x11::xft::XftColor {
color: x11::xrender::XRenderColor {
red: color.color.red,
green: color.color.green,
blue: color.color.blue,
alpha: color.alpha,
},
pixel: color.color.pixel,
};
let background = x11::xft::XftColor {
color: x11::xrender::XRenderColor {
red: background.color.red,
green: background.color.green,
blue: background.color.blue,
alpha: background.alpha,
},
pixel: color.color.pixel,
};
unsafe {
let Ok(width) = u32::try_from(WMWidthOfString(font, text, length)) else {
// TODO: complain.
return;
};
x11::xft::XftDrawChange(screen.xftdraw.cast(), d);
x11::xft::XftDrawRect(
screen.xftdraw.cast(),
&background,
x,
y,
width,
(**font).height,
);
}
let previous_text = unsafe { pango_sys::pango_layout_get_text(layout) };
if previous_text.is_null() {
unsafe {
pango_sys::pango_layout_set_text(layout, text, length);
}
} else {
let text = unsafe { CStr::from_ptr(text) };
let previous_text = unsafe { CStr::from_ptr(previous_text) };
if text != previous_text {
unsafe {
pango_sys::pango_layout_set_text(layout, text.as_ptr(), length);
}
}
}
unsafe {
pango_extras::pango_xft_render_layout(
screen.xftdraw.cast(),
&mut text_color,
layout,
x * pango_sys::PANGO_SCALE,
y * pango_sys::PANGO_SCALE,
);
}
}
}
File diff suppressed because it is too large Load Diff
-13
View File
@@ -1,13 +0,0 @@
#[allow(improper_ctypes)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod WINGsP;
pub mod button;
pub mod configuration;
pub mod font;
pub mod font_panel;
pub mod list;
pub(crate) mod pango_extras;
pub mod screen;
pub mod widget;
-15
View File
@@ -1,15 +0,0 @@
#[allow(non_snake_case)]
pub mod ffi {
use crate::WINGsP::*;
use std::ffi::c_char;
/// Appends an item with the label `text` to `list`.
///
/// ## Rust rewrite notes
///
/// This was originally a macro.
pub unsafe fn WMAddListItem(list: *mut WMList, text: *const c_char) -> *mut WMListItem {
unsafe { WMInsertListItem(list, -1, text) }
}
}
-21
View File
@@ -1,21 +0,0 @@
use std::ffi::c_int;
unsafe extern "C" {
pub fn pango_xft_get_font_map(
display: *mut x11::xlib::Display,
screen: c_int,
) -> *mut pango_sys::PangoFontMap;
pub fn pango_fc_font_description_from_pattern(
pattern: *mut x11::xft::FcPattern,
include_size: c_int,
) -> *mut pango_sys::PangoFontDescription;
pub fn pango_xft_render_layout(
draw: *mut x11::xft::XftDraw,
color: *mut x11::xft::XftColor,
layout: *mut pango_sys::PangoLayout,
x: c_int,
y: c_int,
);
}
-68
View File
@@ -1,68 +0,0 @@
use crate::{
WINGsP::{WMScreen, WMCreateScreen},
font::{Font, FontName},
};
use std::{
collections::{HashMap, hash_map::Entry},
ffi::c_void,
ptr::NonNull,
rc::Rc,
};
impl WMScreen {
pub fn new(display: &NonNull<x11::xlib::Display>) -> Option<NonNull<Self>> {
NonNull::new(unsafe { WMCreateScreen(display.as_ptr(), x11::xlib::XDefaultScreen(display.as_ptr())) })
}
fn font_cache_mut(&mut self) -> &mut HashMap<FontName, Rc<Font>> {
if self.fontCache.is_null() {
self.fontCache = (Box::leak(Box::new(HashMap::<FontName, Rc<Font>>::new()))
as *mut HashMap<_, _>)
.cast::<c_void>();
}
unsafe { &mut *self.fontCache.cast::<HashMap<FontName, Rc<Font>>>() }
}
pub fn font_cache_get_or_else(
&mut self,
name: FontName,
f: impl FnOnce(&FontName) -> Option<Font>,
) -> Option<Rc<Font>> {
match self.font_cache_mut().entry(name) {
Entry::Occupied(o) => Some(o.get().clone()),
Entry::Vacant(v) => {
if let Some(font) = f(v.key()) {
let font = Rc::new(font);
v.insert(font.clone());
Some(font)
} else {
None
}
}
}
}
/// Removes `font` from the font cache if it is not in use anywhere else
/// (i.e., the only live references are `font` and an entry in the cache).
pub fn font_cache_flush(&mut self, font: &Rc<Font>) {
if Rc::strong_count(font) > 2 {
return;
}
self.font_cache_mut().remove(&font.name());
}
}
#[cfg(test)]
mod test {
use crate::WINGsP::WMScreen;
use std::mem::MaybeUninit;
#[test]
fn font_cache_init() {
let mut screen: WMScreen = unsafe { MaybeUninit::zeroed().assume_init() };
let cache = screen.font_cache_mut();
assert!(cache.is_empty());
}
}
-57
View File
@@ -1,57 +0,0 @@
//! Common WINGs widget fields.
//!
//! WINGs widgets all have a [`WINGsP::WMView`] object that tracks common attributes
//! like size and location and a [`WINGsP::W_Class`] field that identifies the widget
//! type (button, list, etc.). This module provides access to these fields.
//!
//! ## Rust rewrite notes
//!
//! The original WINGs implementation uses casting and a common layout for
//! "primitive" widget structs, such that the first two fields are always a
//! `W_Class` and a `*mut WMView`. We rely on this convention when implementing
//! [`Widget`] for widgets that are defined in C.
use crate::WINGsP;
use std::{
ptr::NonNull,
};
/// Base WINGs widget type.
///
/// All primitive widgets (like buttons and lists) should implement this.
pub trait Widget {
fn class(&self) -> WINGsP::W_Class;
fn view(&self) -> NonNull<WINGsP::WMView>;
}
/// Common widget header fields. It should be safe to cast opaque WINGs widget
/// structs defined in C to this type to access these fields. Before writing
/// code that casts anything to this, double-check the widget definition!
#[repr(C)]
struct WidgetLike {
class: WINGsP::W_Class,
view: *mut WINGsP::WMView,
}
/// Casts `$widget` to [`WidgetLike`]. Provided for convenience.
///
/// ## Safety
///
/// The caller of this macro is responsible for ensuring that the layout of `$widget` is compatible
/// with `WidgetLike`.
macro_rules! impl_widget {
($widget:ty) => {
impl Widget for $widget {
fn class(&self) -> crate::WINGsP::W_Class {
unsafe { ::std::mem::transmute::<&$widget, &WidgetLike>(self).class }
}
fn view(&self) -> ::std::ptr::NonNull<WINGsP::WMView> {
let widget = unsafe { ::std::mem::transmute::<&$widget, &WidgetLike>(self) };
NonNull::new(widget.view).expect("WMView field of widget struct cannot be null")
}
}
};
}
impl_widget!(WINGsP::WMWindow);
impl_widget!(WINGsP::WMFrame);
+1 -1
View File
@@ -109,7 +109,7 @@ void W_CreateIC(WMView * view)
// this really needs to be changed, but I don't know how yet -Dan
// it used to be like this with fontsets, but no longer applies to xft
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot,
XNArea, &rect, XNFontInfo, WMFontXftFont(scr->normalFont), NULL);
XNArea, &rect, XNFontInfo, scr->normalFont->font, NULL);
}
view->xic = XCreateIC(scr->imctx->xim, XNInputStyle, scr->imctx->ximstyle,
+1 -1
View File
@@ -201,7 +201,7 @@ W_PaintText(W_View * view, Drawable d, WMFont * font, int x, int y,
}
void
W_PaintTextAndImage(W_View * view, int wrap, WMColor * textColor, WMFont * font,
W_PaintTextAndImage(W_View * view, int wrap, WMColor * textColor, W_Font * font,
WMReliefType relief, const char *text,
WMAlignment alignment, W_Pixmap * image,
WMImagePosition position, WMColor * backColor, int ofs)
+17 -7
View File
@@ -166,6 +166,16 @@ typedef struct W_Text {
WMArray *xdndDestinationTypes;
} Text;
/* not used */
#if 0
#define NOTIFY(T,C,N,A) {\
WMNotification *notif = WMCreateNotification(N,T,A);\
if ((T)->delegate && (T)->delegate->C)\
(*(T)->delegate->C)((T)->delegate,notif);\
WMPostNotification(notif);\
WMReleaseNotification(notif);}
#endif
#define TYPETEXT 0
#if 0
@@ -718,8 +728,8 @@ static void paintText(Text * tPtr)
if (!tPtr->flags.monoFont && tb->underlined) {
XDrawLine(dpy, tPtr->db, WMColorGC(color),
tb->sections[s].x - tPtr->hpos,
y + WMFontAscent(font) + 1,
tb->sections[s].x + tb->sections[s].w - tPtr->hpos, y + WMFontAscent(font) + 1);
y + font->y + 1,
tb->sections[s].x + tb->sections[s].w - tPtr->hpos, y + font->y + 1);
}
}
tb = (!done ? tb->next : NULL);
@@ -897,7 +907,7 @@ static void updateCursorPosition(Text * tPtr)
if (!(tb = tPtr->firstTextBlock)) {
WMFont *font = tPtr->dFont;
tPtr->tpos = 0;
tPtr->cursor.h = WMFontHeight(font) + abs(WMFontHeight(font) - WMFontAscent(font));
tPtr->cursor.h = font->height + abs(font->height - font->y);
tPtr->cursor.y = 2;
tPtr->cursor.x = 2;
@@ -979,7 +989,7 @@ static void cursorToTextPosition(Text * tPtr, int x, int y)
if (!(tb = tPtr->firstTextBlock)) {
WMFont *font = tPtr->dFont;
tPtr->tpos = 0;
tPtr->cursor.h = WMFontHeight(font) + abs(WMFontHeight(font) - WMFontAscent(font));
tPtr->cursor.h = font->height + abs(font->height - font->y);
tPtr->cursor.y = 2;
tPtr->cursor.x = 2;
return;
@@ -1378,9 +1388,9 @@ static int layOutLine(Text * tPtr, myLineItems * items, int nitems, int x, int y
} else {
font = (tPtr->flags.monoFont) ? tPtr->dFont : tb->d.font;
/*max_d = WMAX(max_d, abs(WMFontHeight(font)-WMFontAscent(font))); */
/*max_d = WMAX(max_d, abs(font->height-font->y)); */
max_d = 2;
line_height = WMAX(line_height, WMFontHeight(font) + max_d);
line_height = WMAX(line_height, font->height + max_d);
text = &(tb->text[items[i].begin]);
len = items[i].end - items[i].begin;
if (tPtr->flags.alignment != WALeft)
@@ -1430,7 +1440,7 @@ static int layOutLine(Text * tPtr, myLineItems * items, int nitems, int x, int y
len = items[i].end - items[i].begin;
text = &(tb->text[items[i].begin]);
tb->sections[n].y = y + line_height - WMFontAscent(font);
tb->sections[n].y = y + line_height - font->y;
tb->sections[n].w =
WMWidthOfString(font,
&(tb->text[tb->sections[n].begin]),
+32 -41
View File
@@ -68,6 +68,12 @@ typedef struct W_TextField {
} flags;
} TextField;
#define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
if ((T)->delegate && (T)->delegate->C)\
(*(T)->delegate->C)((T)->delegate,notif);\
WMPostNotification(notif);\
WMReleaseNotification(notif);}
#define MIN_TEXT_BUFFER 2
#define TEXT_BUFFER_INCR 8
@@ -398,7 +404,7 @@ void WMInsertTextFieldText(WMTextField * tPtr, const char *text, int position)
if (position < 0 || position >= tPtr->textLen) {
/* append the text at the end */
strlcat(tPtr->text, text, tPtr->bufferSize);
wstrlcat(tPtr->text, text, tPtr->bufferSize);
tPtr->textLen += len;
tPtr->cursorPosition += len;
incrToFit(tPtr);
@@ -467,7 +473,7 @@ void WMSetTextFieldText(WMTextField * tPtr, const char *text)
tPtr->bufferSize = tPtr->textLen + TEXT_BUFFER_INCR;
tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
}
strlcpy(tPtr->text, text, tPtr->bufferSize);
wstrlcpy(tPtr->text, text, tPtr->bufferSize);
}
tPtr->cursorPosition = tPtr->selection.position = tPtr->textLen;
@@ -900,10 +906,7 @@ static void handleEvents(XEvent * event, void *data)
paintTextField(tPtr);
if (tPtr->delegate && tPtr->delegate->didBeginEditing) {
(*tPtr->delegate->didBeginEditing)(tPtr->delegate, 0);
}
WMPostNotificationName(WMTextDidBeginEditingNotification, tPtr, NULL);
NOTIFY(tPtr, didBeginEditing, WMTextDidBeginEditingNotification, NULL);
tPtr->flags.notIllegalMovement = 0;
break;
@@ -918,10 +921,8 @@ static void handleEvents(XEvent * event, void *data)
paintTextField(tPtr);
if (!tPtr->flags.notIllegalMovement) {
if (tPtr->delegate && tPtr->delegate->didEndEditing) {
(*tPtr->delegate->didEndEditing)(tPtr->delegate, WMIllegalTextMovement);
}
WMPostNotificationName(WMTextDidEndEditingNotification, tPtr, (void *)WMIllegalTextMovement);
NOTIFY(tPtr, didEndEditing, WMTextDidEndEditingNotification,
(void *)WMIllegalTextMovement);
}
break;
@@ -942,8 +943,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
char buffer[64];
KeySym ksym;
const char *textEvent = NULL;
WMTextMovementType movement_type;
WMTextFieldSpecialEventType special_field_event_type;
void *data = NULL;
int count, refresh = 0;
int control_pressed = 0;
int cancelSelection = 1;
@@ -975,14 +975,14 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
tPtr->view->prevFocusChain);
tPtr->flags.notIllegalMovement = 1;
}
movement_type = WMBacktabTextMovement;
data = (void *)WMBacktabTextMovement;
} else {
if (tPtr->view->nextFocusChain) {
W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
tPtr->view->nextFocusChain);
tPtr->flags.notIllegalMovement = 1;
}
movement_type = WMTabTextMovement;
data = (void *)WMTabTextMovement;
}
textEvent = WMTextDidEndEditingNotification;
@@ -994,7 +994,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
case XK_Escape:
if (!modified) {
movement_type = WMEscapeTextMovement;
data = (void *)WMEscapeTextMovement;
textEvent = WMTextDidEndEditingNotification;
relay = False;
@@ -1008,7 +1008,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
/* FALLTHRU */
case XK_Return:
if (!modified) {
movement_type = WMReturnTextMovement;
data = (void *)WMReturnTextMovement;
textEvent = WMTextDidEndEditingNotification;
relay = False;
@@ -1165,7 +1165,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
if (!modified) {
if (tPtr->selection.count) {
WMDeleteTextFieldRange(tPtr, tPtr->selection);
special_field_event_type = WMDeleteTextEvent;
data = (void *)WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
} else if (tPtr->cursorPosition > 0) {
int i = oneUTF8CharBackward(&tPtr->text[tPtr->cursorPosition],
@@ -1174,7 +1174,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
range.position = tPtr->cursorPosition + i;
range.count = -i;
WMDeleteTextFieldRange(tPtr, range);
special_field_event_type = WMDeleteTextEvent;
data = (void *)WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
}
@@ -1197,7 +1197,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
if (!modified) {
if (tPtr->selection.count) {
WMDeleteTextFieldRange(tPtr, tPtr->selection);
special_field_event_type = WMDeleteTextEvent;
data = (void *)WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
} else if (tPtr->cursorPosition < tPtr->textLen) {
WMRange range;
@@ -1205,7 +1205,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
range.count = oneUTF8CharForward(&tPtr->text[tPtr->cursorPosition],
tPtr->textLen - tPtr->cursorPosition);
WMDeleteTextFieldRange(tPtr, range);
special_field_event_type = WMDeleteTextEvent;
data = (void *)WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
}
@@ -1220,7 +1220,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
if (tPtr->selection.count)
WMDeleteTextFieldRange(tPtr, tPtr->selection);
WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
special_field_event_type = WMInsertTextEvent;
data = (void *)WMInsertTextEvent;
textEvent = WMTextDidChangeNotification;
relay = False;
@@ -1255,22 +1255,21 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
/*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count); */
if (textEvent) {
WMNotification *notif = WMCreateNotification(textEvent, tPtr, data);
if (tPtr->delegate) {
if (textEvent == WMTextDidBeginEditingNotification && tPtr->delegate->didBeginEditing)
(*tPtr->delegate->didBeginEditing) (tPtr->delegate, movement_type);
(*tPtr->delegate->didBeginEditing) (tPtr->delegate, notif);
else if (textEvent == WMTextDidEndEditingNotification && tPtr->delegate->didEndEditing)
(*tPtr->delegate->didEndEditing) (tPtr->delegate, movement_type);
(*tPtr->delegate->didEndEditing) (tPtr->delegate, notif);
else if (textEvent == WMTextDidChangeNotification && tPtr->delegate->didChange)
(*tPtr->delegate->didChange) (tPtr->delegate, special_field_event_type);
(*tPtr->delegate->didChange) (tPtr->delegate, notif);
}
if (textEvent == WMTextDidBeginEditingNotification || textEvent == WMTextDidEndEditingNotification) {
WMPostNotificationName(textEvent, tPtr, (void *)movement_type);
} else if (textEvent == WMTextDidChangeNotification) {
WMPostNotificationName(textEvent, tPtr, (void *)special_field_event_type);
}
WMPostNotification(notif);
WMReleaseNotification(notif);
}
if (refresh)
@@ -1346,10 +1345,7 @@ static void pasteText(WMView * view, Atom selection, Atom target, Time timestamp
str = (char *)WMDataBytes(data);
WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
if (tPtr->delegate && tPtr->delegate->didChange) {
(*tPtr->delegate->didChange)(tPtr->delegate, WMInsertTextEvent);
}
WMPostNotificationName(WMTextDidChangeNotification, tPtr, (void *)WMInsertTextEvent);
NOTIFY(tPtr, didChange, WMTextDidChangeNotification, (void *)WMInsertTextEvent);
} else {
int n;
@@ -1359,10 +1355,7 @@ static void pasteText(WMView * view, Atom selection, Atom target, Time timestamp
str[n] = 0;
WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
XFree(str);
if (tPtr->delegate && tPtr->delegate->didChange) {
(*tPtr->delegate->didChange)(tPtr->delegate, WMInsertTextEvent);
}
WMPostNotificationName(WMTextDidChangeNotification, tPtr, (void *)WMInsertTextEvent);
NOTIFY(tPtr, didChange, WMTextDidChangeNotification, (void *)WMInsertTextEvent);
}
}
}
@@ -1484,10 +1477,8 @@ static void handleTextFieldActionEvents(XEvent * event, void *data)
text[n] = 0;
WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
XFree(text);
if (tPtr->delegate && tPtr->delegate->didChange) {
(*tPtr->delegate->didChange)(tPtr->delegate, WMInsertTextEvent);
}
WMPostNotificationName(WMTextDidChangeNotification, tPtr, (void *)WMInsertTextEvent);
NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
(void *)WMInsertTextEvent);
}
} else {
tPtr->flags.waitingSelection = 1;
+24
View File
@@ -0,0 +1,24 @@
/*
* Handle events for non-GUI based applications
*/
#include "WINGsP.h"
void WHandleEvents(void)
{
/* Check any expired timers */
W_CheckTimerHandlers();
/* Do idle and timer stuff while there are no input events */
/* Do not wait for input here. just peek to see if input is available */
while (!W_HandleInputEvents(False, -1) && W_CheckIdleHandlers()) {
/* dispatch timer events */
W_CheckTimerHandlers();
}
W_HandleInputEvents(True, -1);
/* Check any expired timers */
W_CheckTimerHandlers();
}
+2 -2
View File
@@ -2228,7 +2228,7 @@ static void prepareForClose(_Panel * panel)
WMUserDefaults *udb = WMGetStandardUserDefaults();
int i;
textureList = WMCreateEmptyPLArray();
textureList = WMCreatePLArray(NULL, NULL);
/* store list of textures */
for (i = 8; i < WMGetListNumberOfRows(panel->texLs); i++) {
@@ -2250,7 +2250,7 @@ static void prepareForClose(_Panel * panel)
WMReleasePropList(textureList);
/* store list of colors */
textureList = WMCreateEmptyPLArray();
textureList = WMCreatePLArray(NULL, NULL);
for (i = 0; i < wlengthof(sample_colors); i++) {
WMColor *color;
char *str;
+1 -1
View File
@@ -129,7 +129,7 @@ static void autoDelayChanged(void *observerData, WMNotification *notification)
}
char *value = WMGetTextFieldText(anAutoDelayT);
adjustButtonSelectionBasedOnValue(panel, row, value);
wfree(value);
free(value);
return;
}
}
+1 -1
View File
@@ -138,7 +138,7 @@ static void storeData(_Panel * panel)
if (sscanf(str, "%i", &i) != 1)
i = 0;
SetIntegerForKey(i, "RaiseDelay");
wfree(str);
free(str);
SetBoolForKey(WMGetButtonSelected(panel->ignB), "IgnoreFocusClick");
SetBoolForKey(WMGetButtonSelected(panel->newB), "AutoFocus");
+2 -2
View File
@@ -147,11 +147,11 @@ static void storeData(_Panel * panel)
if (sscanf(str, "%i", &i) != 1)
i = 0;
SetIntegerForKey(i, "HotCornerDelay");
wfree(str);
free(str);
SetIntegerForKey(WMGetSliderValue(panel->hceS), "HotCornerEdge");
list = WMCreateEmptyPLArray();
list = WMCreatePLArray(NULL, NULL);
for (i = 0; i < sizeof(panel->hcactionsT) / sizeof(WMTextField *); i++) {
str = WMGetTextFieldText(panel->hcactionsT[i]);
if (strlen(str) == 0)
+1 -1
View File
@@ -365,7 +365,7 @@ char *capture_shortcut(Display *dpy, Bool *capturing, Bool convert_case)
if ((numlock_mask != Mod5Mask) && (ev.xkey.state & Mod5Mask))
strcat(buffer, "Mod5+");
strlcat(buffer, key, sizeof(buffer));
wstrlcat(buffer, key, sizeof(buffer));
return wstrdup(buffer);
}
+1 -3
View File
@@ -66,12 +66,10 @@ AM_CPPFLAGS = -DRESOURCE_PATH=\"$(wpdatadir)\" -DWMAKER_RESOURCE_PATH=\"$(pkgdat
WPrefs_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la
WPrefs_LDADD = \
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.so\
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a\
$(top_builddir)/WINGs/libWINGs.la\
$(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.so\
$(top_builddir)/WINGs/libWUtil.la\
$(top_builddir)/wrlib/libwraster.la \
@PANGO_LIBS@ \
@XLFLAGS@ @XLIBS@ \
@LIBM@ \
@FCLIBS@ \
+2 -2
View File
@@ -203,7 +203,7 @@ static void storeData(_Panel * panel)
int i;
char *p;
list = WMCreateEmptyPLArray();
list = WMCreatePLArray(NULL, NULL);
for (i = 0; i < WMGetListNumberOfRows(panel->icoL); i++) {
p = WMGetListItem(panel->icoL, i)->text;
tmp = WMCreatePLString(p);
@@ -211,7 +211,7 @@ static void storeData(_Panel * panel)
}
SetObjectForKey(list, "IconPath");
list = WMCreateEmptyPLArray();
list = WMCreatePLArray(NULL, NULL);
for (i = 0; i < WMGetListNumberOfRows(panel->pixL); i++) {
p = WMGetListItem(panel->pixL, i)->text;
tmp = WMCreatePLString(p);
+2 -2
View File
@@ -705,10 +705,10 @@ static void loadConfigurations(WMScreen * scr, WMWindow * mainw)
}
if (!db) {
db = WMCreateEmptyPLDictionary();
db = WMCreatePLDictionary(NULL, NULL);
}
if (!gdb) {
gdb = WMCreateEmptyPLDictionary();
gdb = WMCreatePLDictionary(NULL, NULL);
}
GlobalDB = gdb;
+1 -1
View File
@@ -94,7 +94,7 @@ static void paintDoubleTest(_DoubleTest * dPtr)
if (dPtr->text) {
int y;
y = (dPtr->view->size.height - WMFontHeight(scr->normalFont)) / 2;
y = (dPtr->view->size.height - scr->normalFont->height) / 2;
W_PaintText(dPtr->view, dPtr->view->window, scr->normalFont,
dPtr->on, dPtr->on + y, dPtr->view->size.width, WACenter,
scr->black, False, dPtr->text, strlen(dPtr->text));
+4 -1
View File
@@ -824,15 +824,18 @@ static void stopEditItem(WEditMenu * menu, Bool apply)
menu->flags.isEditing = 0;
}
static void textEndedEditing(struct WMTextFieldDelegate *self, WMTextMovementType reason)
static void textEndedEditing(struct WMTextFieldDelegate *self, WMNotification * notif)
{
WEditMenu *menu = (WEditMenu *) self->data;
uintptr_t reason;
int i;
WEditMenuItem *item;
if (!menu->flags.isEditing)
return;
reason = (uintptr_t)WMGetNotificationClientData(notif);
switch (reason) {
case WMEscapeTextMovement:
stopEditItem(menu, False);
+9 -6
View File
@@ -47,6 +47,14 @@ struct {
static pid_t DeadChildren[MAX_DEATHS];
static int DeadChildrenCount = 0;
static noreturn void wAbort(Bool foo)
{
/* Parameter not used, but tell the compiler that it is ok */
(void) foo;
exit(1);
}
static void print_help(const char *progname)
{
printf(_("usage: %s [options]\n"), progname);
@@ -145,12 +153,7 @@ int main(int argc, char **argv)
exit(0);
}
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
Initialize(scr);
+37 -10
View File
@@ -60,11 +60,6 @@ AS_IF(test x$RUSTC = xno,
AC_MSG_ERROR([rustc is required. Please set the RUSTC environment variable or install the Rust toolchain from https://www.rust-lang.org/])
)
AC_SUBST(RUSTC, [rustc])
AC_CHECK_PROG(BINDGEN, [bindgen], [yes], [no])
AS_IF(test x$BINDGEN = xno,
AC_MSG_ERROR([bindgen is required. Please set the BINDGEN environment variable or install bindgen (maybe with `cargo install bindgen-cli`)])
)
AC_SUBST(BINDGEN, [bindgen])
dnl libtool library versioning
dnl ==========================
@@ -396,6 +391,39 @@ dnl the flag 'O_NOFOLLOW' for 'open' is used in WINGs
WM_FUNC_OPEN_NOFOLLOW
dnl Check for strlcat/strlcpy
dnl =========================
m4_divert_push([INIT_PREPARE])dnl
AC_ARG_WITH([libbsd],
[AS_HELP_STRING([--without-libbsd], [do not use libbsd for strlcat and strlcpy [default=check]])],
[AS_IF([test "x$with_libbsd" != "xno"],
[with_libbsd=bsd],
[with_libbsd=]
)],
[with_libbsd=bsd])
m4_divert_pop([INIT_PREPARE])dnl
tmp_libs=$LIBS
AC_SEARCH_LIBS([strlcat],[$with_libbsd],
[AC_DEFINE(HAVE_STRLCAT, 1, [Define if strlcat is available])],
[],
[]
)
AC_SEARCH_LIBS([strlcpy],[$with_libbsd],
[AC_DEFINE(HAVE_STRLCAT, 1, [Define if strlcpy is available])],
[],
[]
)
LIBS=$tmp_libs
LIBBSD=
AS_IF([test "x$ac_cv_search_strlcat" = "x-lbsd" -o "x$ac_cv_search_strlcpy" = "x-lbsd"],
[LIBBSD=-lbsd
AC_CHECK_HEADERS([bsd/string.h])]
)
AC_SUBST(LIBBSD)
dnl Check for OpenBSD kernel memory interface - kvm(3)
dnl ==================================================
AS_IF([test "x$WM_OSDEP" = "xbsd"],
@@ -928,15 +956,14 @@ AC_CONFIG_FILES(
dnl WRaster Library
wrlib/Makefile wrlib/po/Makefile
wrlib/tests/Makefile
wrlib-rs/Makefile
dnl Rust implementation of WINGs utilities
dnl Rust implementation of WINGs libraries
wutil-rs/Makefile
dnl WINGs toolkit
WINGs/Makefile WINGs/wings-rs/Makefile WINGs/WINGs/Makefile WINGs/wings-rs-tests/Makefile
WINGs/po/Makefile WINGs/Documentation/Makefile WINGs/Resources/Makefile
WINGs/Extras/Makefile WINGs/Examples/Makefile WINGs/Tests/Makefile
WINGs/Makefile WINGs/WINGs/Makefile WINGs/po/Makefile
WINGs/Documentation/Makefile WINGs/Resources/Makefile WINGs/Extras/Makefile
WINGs/Examples/Makefile WINGs/Tests/Makefile
dnl Rust implementation of Window Maker core
wmaker-rs/Makefile
+2 -10
View File
@@ -134,7 +134,7 @@ else
nodist_wmaker_SOURCES = misc.hack_nf.c \
xmodifier.hack_nf.c
CLEANFILES = $(nodist_wmaker_SOURCES)
CLEANFILES = $(nodist_wmaker_SOURCES) ../wmaker-rs/target
misc.hack_nf.c: misc.c $(top_srcdir)/script/nested-func-to-macro.sh
$(AM_V_GEN)$(top_srcdir)/script/nested-func-to-macro.sh \
@@ -155,20 +155,12 @@ AM_CPPFLAGS = $(DFLAGS) \
-I$(top_srcdir)/WINGs -I$(top_builddir)/WINGs \
@HEADER_SEARCH_PATH@
wmaker_LDFLAGS = \
-L$(top_builddir)/wutil-rs/target/debug \
-L$(top_builddir)/WINGs/wings-rs/target/debug \
-L$(top_builddir)/wmaker-rs/target/debug
wmaker_LDADD = \
$(top_builddir)/WINGs/libWINGs.la\
$(top_builddir)/WINGs/libWUtil.la\
$(top_builddir)/wrlib/libwraster.la\
-lwutil_rs\
-lwings_rs\
-lwmaker_rs\
@PANGO_LIBS@ \
@FCLIBS@ \
$(top_builddir)/wmaker-rs/target/debug/libwmaker_rs.a\
@XLFLAGS@ \
@LIBXRANDR@ \
@LIBXINERAMA@ \
+1 -1
View File
@@ -1360,7 +1360,7 @@ static void wApplicationSaveIconPathFor(const char *iconPath, const char *wm_ins
val = WMGetFromPLDictionary(adict, iconk);
} else {
/* no dictionary for app, so create one */
adict = WMCreateEmptyPLDictionary();
adict = WMCreatePLDictionary(NULL, NULL);
WMPutInPLDictionary(dict, key, adict);
WMReleasePropList(adict);
val = NULL;
+6 -6
View File
@@ -94,7 +94,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
wwarning(_("appmenu: bad menu entry \"%s\" in window %lx"), slist[*index], win);
return NULL;
}
if (strlcpy(title, &slist[*index][pos], sizeof(title)) >= sizeof(title)) {
if (wstrlcpy(title, &slist[*index][pos], sizeof(title)) >= sizeof(title)) {
wwarning(_("appmenu: menu command size exceeded in window %lx"), win);
return NULL;
}
@@ -127,7 +127,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
slist[*index], win);
return NULL;
}
strlcpy(title, &slist[*index][pos], sizeof(title));
wstrlcpy(title, &slist[*index][pos], sizeof(title));
rtext[0] = 0;
} else {
if (sscanf(slist[*index], "%i %i %i %i %s %n",
@@ -137,9 +137,9 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
slist[*index], win);
return NULL;
}
strlcpy(title, &slist[*index][pos], sizeof(title));
wstrlcpy(title, &slist[*index][pos], sizeof(title));
}
data = wmalloc(sizeof(WAppMenuData));
data = malloc(sizeof(WAppMenuData));
if (data == NULL) {
wwarning(_("appmenu: out of memory creating menu for window %lx"), win);
wMenuDestroy(menu, True);
@@ -152,7 +152,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
if (!entry) {
wMenuDestroy(menu, True);
wwarning(_("appmenu: out of memory creating menu for window %lx"), win);
wfree(data);
free(data);
return NULL;
}
if (rtext[0] != 0)
@@ -174,7 +174,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
return NULL;
}
strlcpy(title, &slist[*index][pos], sizeof(title));
wstrlcpy(title, &slist[*index][pos], sizeof(title));
*index += 1;
submenu = parseMenuCommand(scr, win, slist, count, index);
+2 -2
View File
@@ -307,7 +307,7 @@ void wClientCheckProperty(WWindow * wwin, XPropertyEvent * event)
wWindowUpdateName(wwin, tmp);
}
if (tmp)
wfree(tmp);
XFree(tmp);
}
break;
@@ -616,7 +616,7 @@ void wClientCheckProperty(WWindow * wwin, XPropertyEvent * event)
wWindowUpdateGNUstepAttr(wwin, attr);
wfree(attr);
XFree(attr);
} else {
wNETWMCheckClientHintChange(wwin, event);
}
+2 -7
View File
@@ -862,12 +862,7 @@ static void initDefaults(void)
unsigned int i;
WDefaultEntry *entry;
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
for (i = 0; i < wlengthof(optionList); i++) {
entry = &optionList[i];
@@ -2205,7 +2200,7 @@ static int getKeybind(WScreen * scr, WDefaultEntry * entry, WMPropList * value,
return True;
}
strlcpy(buf, val, MAX_SHORTCUT_LENGTH);
wstrlcpy(buf, val, MAX_SHORTCUT_LENGTH);
b = (char *)buf;
+34 -5
View File
@@ -39,6 +39,10 @@
#include <time.h>
#include <sys/utsname.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <signal.h>
#ifdef __FreeBSD__
#include <sys/signal.h>
@@ -246,7 +250,7 @@ static void SaveHistory(WMArray * history, const char *filename)
int i;
WMPropList *plhistory;
plhistory = WMCreateEmptyPLArray();
plhistory = WMCreatePLArray(NULL);
for (i = 0; i < WMGetArrayItemCount(history); ++i)
WMAddToPLArray(plhistory, WMCreatePLString(WMGetFromArray(history, i)));
@@ -605,9 +609,9 @@ static void listPixmaps(WScreen *scr, WMList *lPtr, const char *path)
if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
continue;
if (strlcpy(pbuf, apath, sizeof(pbuf)) >= sizeof(pbuf) ||
strlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf) ||
strlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf)) {
if (wstrlcpy(pbuf, apath, sizeof(pbuf)) >= sizeof(pbuf) ||
wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf) ||
wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf)) {
wwarning(_("full path for file \"%s\" in \"%s\" is longer than %d bytes, skipped"),
dentry->d_name, path, (int) (sizeof(pbuf) - 1) );
continue;
@@ -1357,7 +1361,7 @@ void wShowInfoPanel(WScreen *scr)
char *posn = getPrettyOSName();
if (posn) {
snprintf(buffer, sizeof(buffer), _("Running on: %s (%s)\n"), posn, uts.machine);
wfree(posn);
free(posn);
}
else
snprintf(buffer, sizeof(buffer), _("Running on: %s (%s)\n"), uts.sysname, uts.machine);
@@ -1389,6 +1393,31 @@ void wShowInfoPanel(WScreen *scr)
break;
}
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2)
{
struct mallinfo2 ma = mallinfo2();
snprintf(buffer, sizeof(buffer),
#ifdef DEBUG
_("Total memory allocated: %lu kB (in use: %lu kB, %lu free chunks)\n"),
#else
_("Total memory allocated: %lu kB (in use: %lu kB)\n"),
#endif
(ma.arena + ma.hblkhd) / 1024,
(ma.uordblks + ma.hblkhd) / 1024
#ifdef DEBUG
/*
* This information is representative of the memory
* fragmentation. In ideal case it should be 1, but
* that is never possible
*/
, ma.ordblks
#endif
);
strbuf = wstrappend(strbuf, buffer);
}
#endif
strbuf = wstrappend(strbuf, _("Image formats: "));
strl = RSupportedFileFormats();
separator = NULL;
+16 -16
View File
@@ -1603,13 +1603,11 @@ static WMPropList *make_icon_state(WAppIcon *btn)
snprintf(buffer, sizeof(buffer), "%hi,%hi", wAppIconGetXIndex(btn), wAppIconGetYIndex(btn));
position = WMCreatePLString(buffer);
node = WMCreatePLDictionary(dCommand, command);
WMPutInPLDictionary(node, dName, name);
WMPutInPLDictionary(node, dAutoLaunch, autolaunch);
WMPutInPLDictionary(node, dLock, lock);
WMPutInPLDictionary(node, dForced, forced);
WMPutInPLDictionary(node, dBuggyApplication, buggy);
WMPutInPLDictionary(node, dPosition, position);
node = WMCreatePLDictionary(dCommand, command,
dName, name,
dAutoLaunch, autolaunch,
dLock, lock,
dForced, forced, dBuggyApplication, buggy, dPosition, position, NULL);
WMReleasePropList(command);
WMReleasePropList(name);
WMReleasePropList(position);
@@ -1644,7 +1642,7 @@ static WMPropList *dockSaveState(WDock *dock)
WMPropList *value, *key;
char buffer[256];
list = WMCreateEmptyPLArray();
list = WMCreatePLArray(NULL);
for (i = (dock->type == WM_DOCK ? 0 : 1); i < dock->max_icons; i++) {
WAppIcon *btn = dock->icon_array[i];
@@ -1659,7 +1657,7 @@ static WMPropList *dockSaveState(WDock *dock)
}
}
dock_state = WMCreatePLDictionary(dApplications, list);
dock_state = WMCreatePLDictionary(dApplications, list, NULL);
if (dock->type == WM_DOCK) {
snprintf(buffer, sizeof(buffer), "Applications%i", dock->screen_ptr->scr_height);
@@ -3196,7 +3194,7 @@ static pid_t execCommand(WAppIcon *btn, const char *command, WSavedState *state)
setsid();
#endif
args = wmalloc(sizeof(char *) * (argc + 1));
args = malloc(sizeof(char *) * (argc + 1));
if (!args)
exit(111);
@@ -3340,8 +3338,8 @@ void wDockTrackWindowLaunch(WDock *dock, Window window)
char *command = NULL;
if (!PropGetWMClass(window, &wm_class, &wm_instance)) {
wfree(wm_class);
wfree(wm_instance);
free(wm_class);
free(wm_instance);
return;
}
@@ -3421,8 +3419,10 @@ void wDockTrackWindowLaunch(WDock *dock, Window window)
if (command)
wfree(command);
wfree(wm_class);
wfree(wm_instance);
if (wm_class)
free(wm_class);
if (wm_instance)
free(wm_instance);
}
void wClipUpdateForWorkspaceChange(WScreen *scr, int workspace)
@@ -5072,7 +5072,7 @@ static WMPropList *drawerSaveState(WDock *drawer)
ai = drawer->icon_array[0];
/* Store its name */
pstr = WMCreatePLString(wAppIconGetWmInstance(ai));
drawer_state = WMCreatePLDictionary(dName, pstr);
drawer_state = WMCreatePLDictionary(dName, pstr, NULL); /* we need this final NULL */
WMReleasePropList(pstr);
/* Store its position */
@@ -5114,7 +5114,7 @@ void wDrawersSaveState(WScreen *scr)
make_keys();
all_drawers = WMCreateEmptyPLArray();
all_drawers = WMCreatePLArray(NULL);
for (i=0, dc = scr->drawers;
i < scr->drawer_count;
i++, dc = dc->next) {
+3 -3
View File
@@ -141,7 +141,7 @@ WMagicNumber wAddDeathHandler(pid_t pid, WDeathHandler * callback, void *cdata)
{
DeathHandler *handler;
handler = wmalloc(sizeof(DeathHandler));
handler = malloc(sizeof(DeathHandler));
if (!handler)
return 0;
@@ -150,7 +150,7 @@ WMagicNumber wAddDeathHandler(pid_t pid, WDeathHandler * callback, void *cdata)
handler->client_data = cdata;
if (!deathHandlers)
deathHandlers = WMCreateArrayWithDestructor(8, wfree);
deathHandlers = WMCreateArrayWithDestructor(8, free);
WMAddToArray(deathHandlers, handler);
@@ -164,7 +164,7 @@ static void wdelete_death_handler(WMagicNumber id)
if (!handler || !deathHandlers)
return;
/* array destructor will call wfree(handler) */
/* array destructor will call free(handler) */
WMRemoveFromArray(deathHandlers, handler);
}
+1 -1
View File
@@ -40,7 +40,7 @@ WGeometryView *WCreateGeometryView(WMScreen * scr)
widgetClass = W_RegisterUserWidget();
}
gview = wmalloc(sizeof(WGeometryView));
gview = malloc(sizeof(WGeometryView));
if (!gview) {
return NULL;
}
+4 -4
View File
@@ -131,7 +131,7 @@ static void setWVisualID(int screen, int val)
/* no array at all, alloc space for screen + 1 entries
* and init with default value */
wVisualID_len = screen + 1;
wVisualID = (int *)wmalloc(wVisualID_len * sizeof(int));
wVisualID = (int *)malloc(wVisualID_len * sizeof(int));
for (i = 0; i < wVisualID_len; i++) {
wVisualID[i] = -1;
}
@@ -156,7 +156,7 @@ static void setWVisualID(int screen, int val)
*/
static int initWVisualID(const char *user_str)
{
char *mystr = wstrdup(user_str);
char *mystr = strdup(user_str);
int cur_in_pos = 0;
int cur_out_pos = 0;
int cur_screen = 0;
@@ -191,7 +191,7 @@ static int initWVisualID(const char *user_str)
cur_in_pos++;
}
wfree(mystr);
free(mystr);
if (cur_screen == 0||error_found != 0)
return 1;
@@ -383,7 +383,7 @@ Bool RelaunchWindow(WWindow *wwin)
setsid();
#endif
/* argv is not null-terminated */
char **a = (char **) wmalloc(argc + 1);
char **a = (char **) malloc(argc + 1);
if (! a) {
werror("out of memory trying to relaunch the application");
Exit(-1);
+4 -5
View File
@@ -1608,7 +1608,7 @@ void wMenuScroll(WMenu *menu)
XEvent ev;
if (omenu->jump_back)
WMDeleteTimerHandler(omenu->jump_back_timer);
WMDeleteTimerWithClientData(omenu->jump_back);
if (( /*omenu->flags.buttoned && */ !wPreferences.wrap_menus)
|| omenu->flags.app_menu) {
@@ -1709,7 +1709,7 @@ void wMenuScroll(WMenu *menu)
scr->flags.jump_back_pending = 1;
} else
delayer = omenu->jump_back;
omenu->jump_back_timer = WMAddTimerHandler(MENU_JUMP_BACK_DELAY, callback_leaving, delayer);
WMAddTimerHandler(MENU_JUMP_BACK_DELAY, callback_leaving, delayer);
}
}
@@ -2309,8 +2309,7 @@ static void saveMenuInfo(WMPropList * dict, WMenu * menu, WMPropList * key)
snprintf(buffer, sizeof(buffer), "%i,%i", menu->frame_x, menu->frame_y);
value = WMCreatePLString(buffer);
list = WMCreateEmptyPLArray();
WMAddToPLArray(list, value);
list = WMCreatePLArray(value, NULL);
if (menu->flags.lowered)
WMAddToPLArray(list, WMCreatePLString("lowered"));
WMPutInPLDictionary(dict, key, list);
@@ -2323,7 +2322,7 @@ void wMenuSaveState(WScreen * scr)
WMPropList *menus, *key;
int save_menus = 0;
menus = WMCreateEmptyPLDictionary();
menus = WMCreatePLDictionary(NULL, NULL);
if (scr->switch_menu && scr->switch_menu->flags.buttoned) {
key = WMCreatePLString("SwitchMenu");
-1
View File
@@ -91,7 +91,6 @@ typedef struct WMenu {
WMHandlerID timer; /* timer for the autoscroll */
void *jump_back; /* jump back data */
WMHandlerID jump_back_timer; /* set when jump_back is being used */
/* to be called when some entry is edited */
void (*on_edit)(struct WMenu *menu, struct WMenuEntry *entry);
+6 -6
View File
@@ -520,7 +520,7 @@ char *ExpandOptions(WScreen *scr, const char *cmdline)
len = strlen(cmdline);
olen = len + 1;
out = wmalloc(olen);
out = malloc(olen);
if (!out) {
wwarning(_("out of memory during expansion of \"%s\""), cmdline);
return NULL;
@@ -573,7 +573,7 @@ char *ExpandOptions(WScreen *scr, const char *cmdline)
(unsigned int)scr->focused_window->client_win);
slen = strlen(tmpbuf);
olen += slen;
nout = wrealloc(out, olen);
nout = realloc(out, olen);
if (!nout) {
wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%w", cmdline);
goto error;
@@ -590,7 +590,7 @@ char *ExpandOptions(WScreen *scr, const char *cmdline)
snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1);
slen = strlen(tmpbuf);
olen += slen;
nout = wrealloc(out, olen);
nout = realloc(out, olen);
if (!nout) {
wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%W", cmdline);
goto error;
@@ -607,7 +607,7 @@ char *ExpandOptions(WScreen *scr, const char *cmdline)
if (user_input) {
slen = strlen(user_input);
olen += slen;
nout = wrealloc(out, olen);
nout = realloc(out, olen);
if (!nout) {
wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%a", cmdline);
goto error;
@@ -630,7 +630,7 @@ char *ExpandOptions(WScreen *scr, const char *cmdline)
}
slen = strlen(scr->xdestring);
olen += slen;
nout = wrealloc(out, olen);
nout = realloc(out, olen);
if (!nout) {
wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%d", cmdline);
goto error;
@@ -651,7 +651,7 @@ char *ExpandOptions(WScreen *scr, const char *cmdline)
}
slen = strlen(selection);
olen += slen;
nout = wrealloc(out, olen);
nout = realloc(out, olen);
if (!nout) {
wwarning(_("out of memory during expansion of '%s' for command \"%s\""), "%s", cmdline);
goto error;
+6 -6
View File
@@ -54,13 +54,13 @@ int PropGetWMClass(Window window, char **wm_class, char **wm_instance)
class_hint = XAllocClassHint();
if (XGetClassHint(dpy, window, class_hint) == 0) {
*wm_class = wstrdup("default");
*wm_instance = wstrdup("default");
*wm_class = strdup("default");
*wm_instance = strdup("default");
XFree(class_hint);
return False;
}
*wm_instance = wstrdup(class_hint->res_name);
*wm_class = wstrdup(class_hint->res_class);
*wm_instance = strdup(class_hint->res_name);
*wm_class = strdup(class_hint->res_class);
XFree(class_hint->res_name);
XFree(class_hint->res_class);
@@ -133,7 +133,7 @@ int PropGetGNUstepWMAttr(Window window, GNUstepWMAttributes ** attr)
if (!data)
return False;
*attr = wmalloc(sizeof(GNUstepWMAttributes));
*attr = malloc(sizeof(GNUstepWMAttributes));
if (!*attr) {
XFree(data);
return False;
@@ -183,7 +183,7 @@ void PropSetIconTileHint(WScreen * scr, RImage * image)
imageAtom = XInternAtom(dpy, "_RGBA_IMAGE", False);
}
tmp = wmalloc(image->width * image->height * 4 + 4);
tmp = malloc(image->width * image->height * 4 + 4);
if (!tmp) {
wwarning("could not allocate memory to set _WINDOWMAKER_ICON_TILE hint");
return;
+5 -5
View File
@@ -406,7 +406,7 @@ static Bool addShortcut(const char *file, const char *shortcutDefinition, WMenu
ptr = wmalloc(sizeof(Shortcut));
strlcpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
wstrlcpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
b = (char *)buf;
/* get modifiers */
@@ -1243,7 +1243,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
if (dentry->d_name[0] == '.')
continue;
buffer = wmalloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
buffer = malloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
if (!buffer) {
werror(_("out of memory while constructing directory menu %s"), path[i]);
break;
@@ -1288,7 +1288,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
}
}
}
wfree(buffer);
free(buffer);
}
closedir(dir);
@@ -1315,7 +1315,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
length += 7;
if (command)
length += strlen(command) + 6;
buffer = wmalloc(length);
buffer = malloc(length);
if (!buffer) {
werror(_("out of memory while constructing directory menu %s"), path[data->index]);
break;
@@ -1353,7 +1353,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
if (command)
length += strlen(command);
buffer = wmalloc(length);
buffer = malloc(length);
if (!buffer) {
werror(_("out of memory while constructing directory menu %s"), path[data->index]);
break;
+3 -6
View File
@@ -968,6 +968,8 @@ void wScreenSaveState(WScreen * scr)
old_state = scr->session_state;
scr->session_state = WMCreatePLDictionary(NULL, NULL);
WMPLSetCaseSensitive(True);
/* save dock state to file */
if (!wPreferences.flags.nodock) {
wDockSaveState(scr, old_state);
@@ -1007,13 +1009,8 @@ void wScreenSaveState(WScreen * scr)
WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
}
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* clean up */
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
wMenuSaveState(scr);
+18 -25
View File
@@ -241,15 +241,14 @@ static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
snprintf(buffer, sizeof(buffer), "%u", mask);
shortcut = WMCreatePLString(buffer);
win_state = WMCreatePLDictionary(sName, name);
WMPutInPLDictionary(win_state, sCommand, cmd);
WMPutInPLDictionary(win_state, sWorkspace, workspace);
WMPutInPLDictionary(win_state, sShaded, shaded);
WMPutInPLDictionary(win_state, sMiniaturized, miniaturized);
WMPutInPLDictionary(win_state, sMaximized, maximized);
WMPutInPLDictionary(win_state, sHidden, hidden);
WMPutInPLDictionary(win_state, sShortcutMask, shortcut);
WMPutInPLDictionary(win_state, sGeometry, geometry);
win_state = WMCreatePLDictionary(sName, name,
sCommand, cmd,
sWorkspace, workspace,
sShaded, shaded,
sMiniaturized, miniaturized,
sMaximized, maximized,
sHidden, hidden,
sShortcutMask, shortcut, sGeometry, geometry, NULL);
WMReleasePropList(name);
WMReleasePropList(cmd);
@@ -290,9 +289,9 @@ static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
}
if (instance)
wfree(instance);
free(instance);
if (class)
wfree(class);
free(class);
if (command)
wfree(command);
@@ -314,7 +313,7 @@ void wSessionSaveState(WScreen * scr)
return;
}
list = WMCreateEmptyPLArray();
list = WMCreatePLArray(NULL);
wapp_list = WMCreateArray(16);
@@ -383,7 +382,7 @@ static pid_t execCommand(WScreen *scr, char *command)
SetupEnvironment(scr);
args = wmalloc(sizeof(char *) * (argc + 1));
args = malloc(sizeof(char *) * (argc + 1));
if (!args)
exit(111);
for (i = 0; i < argc; i++) {
@@ -488,6 +487,8 @@ void wSessionRestoreState(WScreen *scr)
if (!scr->session_state)
return;
WMPLSetCaseSensitive(True);
apps = WMGetFromPLDictionary(scr->session_state, sApplications);
if (!apps)
return;
@@ -578,13 +579,8 @@ void wSessionRestoreState(WScreen *scr)
if (class)
wfree(class);
}
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* clean up */
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
}
void wSessionRestoreLastWorkspace(WScreen * scr)
@@ -598,6 +594,8 @@ void wSessionRestoreLastWorkspace(WScreen * scr)
if (!scr->session_state)
return;
WMPLSetCaseSensitive(True);
wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
if (!wks || !WMIsPLString(wks))
return;
@@ -607,13 +605,8 @@ void wSessionRestoreLastWorkspace(WScreen * scr)
if (!value)
return;
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* clean up */
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
/* Get the workspace number for the workspace name */
w = wGetWorkspaceNumber(scr, value);
+5 -6
View File
@@ -109,16 +109,16 @@ void Shutdown(WShutdownMode mode)
}
}
static void restoreWindows(WMBag * bag, WMBagIterator *iter)
static void restoreWindows(WMBag * bag, WMBagIterator iter)
{
WCoreWindow *next;
WCoreWindow *core;
WWindow *wwin;
if (*iter < 0) {
core = WMBagFirst(bag, iter);
if (iter == NULL) {
core = WMBagFirst(bag, &iter);
} else {
core = WMBagNext(bag, iter);
core = WMBagNext(bag, &iter);
}
if (core == NULL)
@@ -168,8 +168,7 @@ void RestoreDesktop(WScreen * scr)
wDestroyInspectorPanels();
/* reparent windows back to the root window, keeping the stacking order */
WMBagIterator iter = -1;
restoreWindows(scr->stacking_list, &iter);
restoreWindows(scr->stacking_list, NULL);
XUngrabServer(dpy);
XSetInputFocus(dpy, PointerRoot, RevertToParent, CurrentTime);
+2 -2
View File
@@ -244,7 +244,7 @@ reinit:
wApplicationSetBouncing(data->wapp, 0);
WMDeleteTimerHandler(data->timer);
wApplicationDestroy(data->wapp);
wfree(data);
free(data);
}
static int bounceDirection(WAppIcon *aicon)
@@ -324,7 +324,7 @@ void wAppBounce(WApplication *wapp)
wApplicationIncrementRefcount(wapp);
wApplicationSetBouncing(wapp, 1);
AppBouncerData *data = (AppBouncerData *)wmalloc(sizeof(AppBouncerData));
AppBouncerData *data = (AppBouncerData *)malloc(sizeof(AppBouncerData));
data->wapp = wapp;
data->count = data->pow = 0;
data->dir = bounceDirection(wApplicationGetAppIcon(wapp));
+2 -1
View File
@@ -357,7 +357,8 @@ static void drawTitle(WSwitchPanel *panel, int idecks, const char *title)
WMSetLabelText(panel->label, ntitle);
}
wfree(ntitle);
if (ntitle)
free(ntitle);
}
static WMArray *makeWindowListArray(WScreen *scr, int include_unmapped, Bool class_only)
+17 -32
View File
@@ -174,18 +174,15 @@ static WMPropList *get_value_from_instanceclass(const char *value)
key = WMCreatePLString(value);
WMPLSetCaseSensitive(True);
if (w_global.domain.window_attr->dictionary)
val = key ? WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, key) : NULL;
if (key)
WMReleasePropList(key);
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
return val;
}
@@ -222,6 +219,8 @@ void wDefaultFillAttributes(const char *instance, const char *class,
dn = get_value_from_instanceclass(instance);
dc = get_value_from_instanceclass(class);
WMPLSetCaseSensitive(True);
if ((w_global.domain.window_attr->dictionary) && (useGlobalDefault))
da = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, AnyWindow);
@@ -312,13 +311,8 @@ void wDefaultFillAttributes(const char *instance, const char *class,
APPLY_VAL(value, no_language_button, ANoLanguageButton);
#endif
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* clean up */
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
}
static WMPropList *get_generic_value(const char *instance, const char *class,
@@ -328,6 +322,8 @@ static WMPropList *get_generic_value(const char *instance, const char *class,
value = NULL;
WMPLSetCaseSensitive(True);
/* Search the icon name using class and instance */
if (class && instance) {
char *buffer;
@@ -375,12 +371,7 @@ static WMPropList *get_generic_value(const char *instance, const char *class,
value = WMGetFromPLDictionary(dict, option);
}
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
return value;
}
@@ -554,13 +545,15 @@ void wDefaultChangeIcon(const char *instance, const char *class, const char *fil
int same = 0;
if (!dict) {
dict = WMCreateEmptyPLDictionary();
dict = WMCreatePLDictionary(NULL, NULL);
if (dict)
db->dictionary = dict;
else
return;
}
WMPLSetCaseSensitive(True);
if (instance && class) {
char *buffer;
@@ -577,7 +570,7 @@ void wDefaultChangeIcon(const char *instance, const char *class, const char *fil
if (file) {
value = WMCreatePLString(file);
icon_value = WMCreatePLDictionary(AIcon, value);
icon_value = WMCreatePLDictionary(AIcon, value, NULL);
WMReleasePropList(value);
def_win = WMGetFromPLDictionary(dict, AnyWindow);
@@ -607,12 +600,7 @@ void wDefaultChangeIcon(const char *instance, const char *class, const char *fil
if (icon_value)
WMReleasePropList(icon_value);
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
}
void wDefaultPurgeInfo(const char *instance, const char *class)
@@ -624,6 +612,8 @@ void wDefaultPurgeInfo(const char *instance, const char *class)
init_wdefaults();
}
WMPLSetCaseSensitive(True);
buffer = wmalloc(strlen(class) + strlen(instance) + 2);
sprintf(buffer, "%s.%s", instance, class);
key = WMCreatePLString(buffer);
@@ -641,12 +631,7 @@ void wDefaultPurgeInfo(const char *instance, const char *class)
wfree(buffer);
WMReleasePropList(key);
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
}
/* --------------------------- Local ----------------------- */
+11 -11
View File
@@ -283,10 +283,10 @@ void wWindowDestroy(WWindow *wwin)
XFree(wwin->wm_hints);
if (wwin->wm_instance)
wfree(wwin->wm_instance);
XFree(wwin->wm_instance);
if (wwin->wm_class)
wfree(wwin->wm_class);
XFree(wwin->wm_class);
if (wwin->wm_gnustep_attr)
wfree(wwin->wm_gnustep_attr);
@@ -950,10 +950,10 @@ WWindow *wManageWindow(WScreen *scr, Window window)
}
if (instance)
wfree(instance);
free(instance);
if (class)
wfree(class);
free(class);
#undef ADEQUATE
}
@@ -1413,7 +1413,7 @@ WWindow *wManageWindow(WScreen *scr, Window window)
/* Update name must come after WApplication stuff is done */
wWindowUpdateName(wwin, title);
if (title)
wfree(title);
XFree(title);
XUngrabServer(dpy);
@@ -1648,9 +1648,9 @@ void wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed)
wSelectWindow(wwin, False);
/* remove all pending events on window */
/* I think this only matters for autoraise. see event.c:1197. */
/* I think this only matters for autoraise */
if (wPreferences.raise_delay)
WMDeleteTimerHandler(wwin->frame->core->screen_ptr->autoRaiseTimer);
WMDeleteTimerWithClientData(wwin->frame->core);
XFlush(dpy);
@@ -2602,7 +2602,7 @@ void wWindowSetShape(WWindow * wwin)
if (!rects)
goto alt_code;
urec = wmalloc(sizeof(XRectangle) * (count + 2));
urec = malloc(sizeof(XRectangle) * (count + 2));
if (!urec) {
XFree(rects);
goto alt_code;
@@ -2779,7 +2779,7 @@ WMagicNumber wWindowAddSavedState(const char *instance, const char *class,
{
WWindowState *wstate;
wstate = wmalloc(sizeof(WWindowState));
wstate = malloc(sizeof(WWindowState));
if (!wstate)
return NULL;
@@ -2841,9 +2841,9 @@ WMagicNumber wWindowGetSavedState(Window win)
if (command)
wfree(command);
if (instance)
wfree(instance);
free(instance);
if (class)
wfree(class);
free(class);
return wstate;
}
+6 -9
View File
@@ -597,7 +597,7 @@ static void saveSettings(WMWidget *button, void *client_data)
dict = db->dictionary;
if (!dict) {
dict = WMCreateEmptyPLDictionary();
dict = WMCreatePLDictionary(NULL, NULL);
if (dict) {
db->dictionary = dict;
} else {
@@ -609,8 +609,10 @@ static void saveSettings(WMWidget *button, void *client_data)
if (showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD) < 0)
return;
winDic = WMCreateEmptyPLDictionary();
appDic = WMCreateEmptyPLDictionary();
WMPLSetCaseSensitive(True);
winDic = WMCreatePLDictionary(NULL, NULL);
appDic = WMCreatePLDictionary(NULL, NULL);
/* Save the icon info */
/* The flag "Ignore client suplied icon is not selected" */
@@ -707,13 +709,8 @@ static void saveSettings(WMWidget *button, void *client_data)
UpdateDomainFile(db);
/*
* Rust rewrite note: this API surface has been removed, but we leave in
* a record of where it was invoked to set a value other than the
* default, in case it helps to track down bugs in the future.
*/
/* clean up */
/* WMPLSetCaseSensitive(False); */
WMPLSetCaseSensitive(False);
}
static void applySettings(WMWidget *button, void *client_data)
+3 -3
View File
@@ -797,7 +797,7 @@ void wWorkspaceMenuUpdate(WScreen * scr, WMenu * menu)
i = scr->workspace_count - (menu->entry_no - MC_WORKSPACE1);
ws = menu->entry_no - MC_WORKSPACE1;
while (i > 0) {
strlcpy(title, scr->workspaces[ws]->name, MAX_WORKSPACENAME_WIDTH);
wstrlcpy(title, scr->workspaces[ws]->name, MAX_WORKSPACENAME_WIDTH);
entry = wMenuAddCallback(menu, title, switchWSCommand, (void *)ws);
entry->flags.indicator = 1;
@@ -852,10 +852,10 @@ void wWorkspaceSaveState(WScreen * scr, WMPropList * old_state)
make_keys();
old_wks_state = WMGetFromPLDictionary(old_state, dWorkspaces);
parr = WMCreateEmptyPLArray();
parr = WMCreatePLArray(NULL);
for (i = 0; i < scr->workspace_count; i++) {
pstr = WMCreatePLString(scr->workspaces[i]->name);
wks_state = WMCreatePLDictionary(dName, pstr);
wks_state = WMCreatePLDictionary(dName, pstr, NULL);
WMReleasePropList(pstr);
if (!wPreferences.flags.noclip) {
pstr = wClipSaveWorkspaceState(scr, i);

Some files were not shown because too many files have changed in this diff Show More