mirror of
https://github.com/gryf/wmaker.git
synced 2026-07-07 11:16:38 +02:00
Compare commits
53 Commits
da676c9e9e
...
cc0a652ea8
| Author | SHA1 | Date | |
|---|---|---|---|
| cc0a652ea8 | |||
| 80079cd343 | |||
| 955c6793a6 | |||
| 189679b49c | |||
| e45a3bc07d | |||
| bc16a03722 | |||
| 260415eb42 | |||
| c8174a4b2e | |||
| 2901b418ad | |||
| ae6b03e50f | |||
| 128ba2ddc7 | |||
| 7ca96b9ed6 | |||
| 839061a25a | |||
| 1e63c590b6 | |||
| 92e1e9fb0b | |||
| ddf0b20367 | |||
| d303317a31 | |||
| c620b354b5 | |||
| ebac2bbcd8 | |||
| 3281349f8d | |||
| 3f5280987e | |||
| 6d0953bc22 | |||
| ef1a504898 | |||
| 474b23344a | |||
| 77db6dc649 | |||
| b09ac30233 | |||
| 6e14b6142b | |||
| 7778df2fc5 | |||
| 156841f80e | |||
| c82e6dad5c | |||
| 95c68fe26d | |||
| 77c3b95fd5 | |||
| b662d0827c | |||
| a542934e67 | |||
| d2b2c3238b | |||
| d37a3162e0 | |||
| 9ddacfc29b | |||
| 7e21785710 | |||
| 7cfdf6bd68 | |||
| 72942267aa | |||
| ac19c4bc07 | |||
| 14bd13b1be | |||
| afe13d3e72 | |||
| e356ef8c05 | |||
| 3d993a7323 | |||
| a4a6e65ca9 | |||
| 4392fdc291 | |||
| 67e2f5e1ca | |||
| 3579c85af1 | |||
| 896bbce2e5 | |||
| 8f1ee27595 | |||
| 541947e9ef | |||
| 7bb7d0f4d6 |
@@ -15,7 +15,7 @@ Summary of Contents:
|
||||
1.2 Where can I get Window Maker?
|
||||
1.3 Where are the mailing list archives?
|
||||
1.4 Where is more documentation on configuring Window Maker?
|
||||
1.5 What is an App Icon?
|
||||
1.5 What is an appicon?
|
||||
1.6 How can I get a question added to the FAQ?
|
||||
1.7 How do I report bugs?
|
||||
1.8 Is there an anonymous cvs server?
|
||||
@@ -134,7 +134,7 @@ Introduction:
|
||||
|
||||
1.1 What is Window Maker?
|
||||
----------------------------------
|
||||
Window Maker is an elegant X11 window manger that emulates the
|
||||
Window Maker is an elegant X11 window manager that emulates the
|
||||
OpenStep desktop with some noticeable enhancements. Look at
|
||||
http://wm.current.nu/themes/my-themes.html and
|
||||
http://wm.current.nu/themes/screenshots.html
|
||||
@@ -507,7 +507,7 @@ exec wmaker
|
||||
Things to try if it doesn't work: (somewhat fuzzy and random)
|
||||
|
||||
This should do it although I did have problems sometimes initially which I
|
||||
fixed by randomly trying absolute pathes for wmaker in .xsession/.xinitrc and/or
|
||||
fixed by randomly trying absolute paths for wmaker in .xsession/.xinitrc and/or
|
||||
making the dtprofile/.xinitrc/etc executable. It helps logging in on the console
|
||||
(select from CDE login screen) and start X manually using 'X'.
|
||||
If it works that way it should work when logging into the CDE environment.
|
||||
@@ -628,7 +628,7 @@ the last app started by .xinitrc is closed.
|
||||
the X server will be closed, and your session will end.
|
||||
|
||||
|
||||
3.3 How do I "dock" AppIcons on the Clip?
|
||||
3.3 How do I "dock" appicons on the Clip?
|
||||
-----------------------------------------
|
||||
Just drag icons near it like you would for the dock. Note that if you place
|
||||
the clip near the dock, you may have problems docking appicons in either.
|
||||
@@ -674,7 +674,7 @@ David Reviejo <dreviejo@arrakis.es> best summed up this answer:
|
||||
|
||||
|
||||
|
||||
3.7 How do I "undock" AppIcons?
|
||||
3.7 How do I "undock" appicons?
|
||||
----------------------------------
|
||||
If the program is not running, just drag the icon to the middle of your
|
||||
desktop (away from the dock and clip) and watch it disappear.
|
||||
@@ -731,7 +731,7 @@ These directories will be listed under the "Search Path" section of WPrefs.
|
||||
3.11 When I run GNOME application they have no title bar.
|
||||
----------------------------------
|
||||
|
||||
The GNOME toolkit decided to behave his own way, so it draws its own title bar
|
||||
The GNOME toolkit decided to behave in its own way, so it draws its own title bar
|
||||
with buttons, and asks Window Maker to not draw anything (title bar, resize bar,
|
||||
close and miniaturise button, ...).
|
||||
|
||||
@@ -838,7 +838,7 @@ AlwaysUserIcon=Yes;
|
||||
};
|
||||
|
||||
|
||||
4.6 How do I get a Tile background for my AppIcons (those things in
|
||||
4.6 How do I get a Tile background for my appicons (those things in
|
||||
the dock)?
|
||||
----------------------------------
|
||||
You need to change 1 line to your ~/GNUstep/Defaults/WindowMaker file.
|
||||
@@ -868,9 +868,9 @@ Application Icon'' Option then Save, Apply and close the dialog.
|
||||
|
||||
This should allow you do dock the program normally.
|
||||
|
||||
Emulate Appicon does exactly the same thing as dockit, a small app
|
||||
Emulate AppIcon does exactly the same thing as dockit, a small app
|
||||
distributed with ancient versions of Window Maker before the Attribute
|
||||
Editor existed (now deprecated for the obvious reason). If Emulate Appicon
|
||||
Editor existed (now deprecated for the obvious reason). If Emulate AppIcon
|
||||
does not work, dockit will not work either. Such applications violate the
|
||||
ICCCM (Inter-Client Communication Conventions Manual) and are considered
|
||||
badly coded for not setting the instance.class hints.
|
||||
@@ -898,7 +898,7 @@ NoAppIcon=Yes;
|
||||
|
||||
4.9 How do I set a pixmap background?
|
||||
----------------------------------
|
||||
Here is the in depth explanation straight from the NEWS file:
|
||||
Here is the in-depth explanation straight from the NEWS file:
|
||||
|
||||
wmsetbg now accepts the following options:
|
||||
usage: wmsetbg [-options] image
|
||||
@@ -1476,7 +1476,7 @@ Themes:
|
||||
8.1 What exactly are themes?
|
||||
----------------------------------
|
||||
Themes are a great aspect of Window Maker allowing a user to simply
|
||||
save the entire 'look' of their desktop in a Archive to distribute freely among
|
||||
save the entire 'look' of their desktop in an archive to distribute freely among
|
||||
friends, fellow users and/or the whole net in general. :)
|
||||
|
||||
See the theme-HOWTO at http://wm.current.nu/themes/theme-HOWTO.html
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
#include <WINGs/WINGs.h>
|
||||
#include <WINGs/WUtil.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
void wAbort()
|
||||
noreturn void wAbort(void)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
@@ -40,7 +41,7 @@ void show(WMWidget * self, void *data)
|
||||
WMSetLabelText(l, buf);
|
||||
}
|
||||
|
||||
void quit(WMWidget * self, void *data)
|
||||
noreturn void quit(WMWidget * self, void *data)
|
||||
{
|
||||
(void) self;
|
||||
(void) data;
|
||||
|
||||
+6
-1
@@ -521,7 +521,7 @@ void testSlider(WMScreen * scr)
|
||||
void testTextField(WMScreen * scr)
|
||||
{
|
||||
WMWindow *win;
|
||||
WMTextField *field, *field2;
|
||||
WMTextField *field, *field2, *field3;
|
||||
|
||||
windowCount++;
|
||||
|
||||
@@ -540,6 +540,11 @@ void testTextField(WMScreen * scr)
|
||||
WMMoveWidget(field2, 20, 50);
|
||||
WMSetTextFieldAlignment(field2, WARight);
|
||||
|
||||
field3 = WMCreateTextField(win);
|
||||
WMResizeWidget(field3, 200, 20);
|
||||
WMMoveWidget(field3, 20, 80);
|
||||
WMSetTextFieldAlignment(field3, WACenter);
|
||||
|
||||
WMRealizeWidget(win);
|
||||
WMMapSubwidgets(win);
|
||||
WMMapWidget(win);
|
||||
|
||||
@@ -1462,6 +1462,10 @@ void WMSetPopUpButtonEnabled(WMPopUpButton *bPtr, Bool flag);
|
||||
|
||||
Bool WMGetPopUpButtonEnabled(WMPopUpButton *bPtr);
|
||||
|
||||
int WMSelectPopUpButtonPreviousItem(WMPopUpButton *bPtr);
|
||||
|
||||
int WMSelectPopUpButtonNextItem(WMPopUpButton *bPtr);
|
||||
|
||||
/* ---[ WINGs/wprogressindicator.c ]------------------------------------- */
|
||||
|
||||
WMProgressIndicator* WMCreateProgressIndicator(WMWidget *parent);
|
||||
@@ -1529,6 +1533,8 @@ void WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type);
|
||||
|
||||
WMRect WMGetScrollViewVisibleRect(WMScrollView *sPtr);
|
||||
|
||||
void WMScrollViewScrollPoint(WMScrollView * sPtr, WMPoint point);
|
||||
|
||||
WMScroller* WMGetScrollViewHorizontalScroller(WMScrollView *sPtr);
|
||||
|
||||
WMScroller* WMGetScrollViewVerticalScroller(WMScrollView *sPtr);
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ sk.po Slovak Jan 'judas' Tomka <judas@linux.sk>
|
||||
bg.po Bulgarian Anton Zinoviev <zinoviev@debian.org>
|
||||
nl.po Dutch Alwin <translations@ziggo.nl>
|
||||
fy.po Frisian Alwin <translations@ziggo.nl>
|
||||
sr.po Serbian Strahinya Radich <contact@strahinja.org>
|
||||
sr.po Serbian Strahinya Radich <sr@strahinja.org>
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
# 1998-2006 Dan Pascu
|
||||
# 2013-2020 Window Maker Developers Team
|
||||
# This file is distributed under the same license as the Window Maker package.
|
||||
# Strahinya Radich (Страхиња Радић) <contact@strahinja.org>, 2023.
|
||||
# Strahinya Radich (Страхиња Радић) <sr@strahinja.org>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -11,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: wmaker-dev@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2023-11-02 19:36+0100\n"
|
||||
"PO-Revision-Date: 2023-11-02 19:48+0100\n"
|
||||
"Last-Translator: Страхиња Радић <contact@strahinja.org>\n"
|
||||
"Last-Translator: Страхиња Радић <sr@strahinja.org>\n"
|
||||
"Language-Team: Serbian <sr@li.org>\n"
|
||||
"Language: sr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+37
-33
@@ -70,37 +70,30 @@ static Bool hasProperty(FcPattern * pattern, const char *property)
|
||||
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;
|
||||
FcPattern *pattern = NULL;
|
||||
char *result;
|
||||
|
||||
if (font[0] == '-') {
|
||||
if (font && font[0] == '-') {
|
||||
pattern = xlfdToFcPattern(font);
|
||||
} else {
|
||||
pattern = FcNameParse((const FcChar8 *) font);
|
||||
}
|
||||
|
||||
/*FcPatternPrint(pattern); */
|
||||
if (!pattern) {
|
||||
wwarning(_("could not load font spec: %s."), font);
|
||||
if (!fallback)
|
||||
return NULL;
|
||||
pattern = FcPatternCreate();
|
||||
if (!pattern)
|
||||
return NULL;
|
||||
if (!FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) fallback)) {
|
||||
wfatal(_("could not load default font spec: %s."), fallback);
|
||||
FcPatternDestroy(pattern);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
FcPatternDel(pattern, FC_PIXEL_SIZE);
|
||||
@@ -109,12 +102,6 @@ static char *makeFontOfSize(const char *font, int size, const char *fallback)
|
||||
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)DEFAULT_SIZE);
|
||||
}
|
||||
|
||||
if (fallback && !hasPropertyWithStringValue(pattern, FC_FAMILY, fallback)) {
|
||||
FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) fallback);
|
||||
}
|
||||
|
||||
/*FcPatternPrint(pattern); */
|
||||
|
||||
result = (char *)FcNameUnparse(pattern);
|
||||
FcPatternDestroy(pattern);
|
||||
|
||||
@@ -135,7 +122,7 @@ WMFont *WMCreateFont(WMScreen * scrPtr, const char *fontName)
|
||||
double size;
|
||||
#endif
|
||||
|
||||
if (fontName[0] == '-') {
|
||||
if (fontName && fontName[0] == '-') {
|
||||
fname = xlfdToFcName(fontName);
|
||||
} else {
|
||||
fname = wstrdup(fontName);
|
||||
@@ -187,6 +174,10 @@ WMFont *WMCreateFont(WMScreen * scrPtr, const char *fontName)
|
||||
pango_layout_set_font_description(layout, description);
|
||||
|
||||
font->layout = layout;
|
||||
|
||||
pango_font_description_free(description);
|
||||
g_object_unref(context);
|
||||
FcPatternDestroy(pattern);
|
||||
#endif
|
||||
|
||||
assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL);
|
||||
@@ -210,6 +201,11 @@ void WMReleaseFont(WMFont * font)
|
||||
font->refCount--;
|
||||
if (font->refCount < 1) {
|
||||
XftFontClose(font->screen->display, font->font);
|
||||
#ifdef USE_PANGO
|
||||
if (font->layout) {
|
||||
g_object_unref(font->layout);
|
||||
}
|
||||
#endif
|
||||
if (font->name) {
|
||||
WMHashRemove(font->screen->fontCache, font->name);
|
||||
wfree(font->name);
|
||||
@@ -262,7 +258,11 @@ WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size)
|
||||
WMFont *font;
|
||||
char *fontSpec;
|
||||
|
||||
fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL);
|
||||
fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, DEFAULT_FONT);
|
||||
|
||||
if (!fontSpec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
font = WMCreateFont(scrPtr, fontSpec);
|
||||
|
||||
@@ -280,7 +280,11 @@ WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
|
||||
WMFont *font;
|
||||
char *fontSpec;
|
||||
|
||||
fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL);
|
||||
fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, DEFAULT_FONT);
|
||||
|
||||
if (!fontSpec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
font = WMCreateFont(scrPtr, fontSpec);
|
||||
|
||||
@@ -336,7 +340,7 @@ void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, in
|
||||
|
||||
#ifdef USE_PANGO
|
||||
previous_text = pango_layout_get_text(font->layout);
|
||||
if ((previous_text == NULL) || (strcmp(text, previous_text) != 0))
|
||||
if ((previous_text == NULL) || (strncmp(text, previous_text, length) != 0) || previous_text[length] != '\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
|
||||
@@ -374,7 +378,7 @@ WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * backgro
|
||||
|
||||
#ifdef USE_PANGO
|
||||
previous_text = pango_layout_get_text(font->layout);
|
||||
if ((previous_text == NULL) || (strcmp(text, previous_text) != 0))
|
||||
if ((previous_text == NULL) || (strncmp(text, previous_text, length) != 0) || previous_text[length] != '\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
|
||||
|
||||
+498
-9
@@ -1,5 +1,7 @@
|
||||
|
||||
#include "WINGsP.h"
|
||||
#include <ctype.h>
|
||||
#include <strings.h>
|
||||
|
||||
const char *WMListDidScrollNotification = "WMListDidScrollNotification";
|
||||
const char *WMListSelectionDidChangeNotification = "WMListSelectionDidChangeNotification";
|
||||
@@ -27,11 +29,15 @@ typedef struct W_List {
|
||||
WMHandlerID *idleID; /* for updating the scroller after adding elements */
|
||||
|
||||
WMHandlerID *selectID; /* for selecting items in list while scrolling */
|
||||
WMHandlerID *typeaheadID; /* for clearing typeahead buffer */
|
||||
|
||||
WMScroller *vScroller;
|
||||
|
||||
Pixmap doubleBuffer;
|
||||
|
||||
char *typeahead;
|
||||
int typeaheadLen;
|
||||
|
||||
struct {
|
||||
unsigned int allowMultipleSelection:1;
|
||||
unsigned int allowEmptySelection:1;
|
||||
@@ -48,6 +54,7 @@ typedef struct W_List {
|
||||
#define DEFAULT_HEIGHT 150
|
||||
|
||||
#define SCROLL_DELAY 100
|
||||
#define TYPEAHEAD_CLEAR_DELAY 700
|
||||
|
||||
static void destroyList(List * lPtr);
|
||||
static void paintList(List * lPtr);
|
||||
@@ -62,6 +69,8 @@ static void scrollBackwardSelecting(void *data);
|
||||
static void vScrollCallBack(WMWidget * scroller, void *self);
|
||||
|
||||
static void toggleItemSelection(WMList * lPtr, int index);
|
||||
static void jumpToFirstItemWithPrefix(WMList * lPtr, const char *prefix, int prefixLen);
|
||||
static void typeaheadTimeout(void *data);
|
||||
|
||||
static void updateGeometry(WMList * lPtr);
|
||||
static void didResizeList(W_ViewDelegate * self, WMView * view);
|
||||
@@ -113,6 +122,9 @@ WMList *WMCreateList(WMWidget * parent)
|
||||
W_Screen *scrPtr = W_VIEW(parent)->screen;
|
||||
|
||||
lPtr = wmalloc(sizeof(List));
|
||||
lPtr->typeahead = NULL;
|
||||
lPtr->typeaheadLen = 0;
|
||||
lPtr->typeaheadID = NULL;
|
||||
|
||||
lPtr->widgetClass = WC_List;
|
||||
|
||||
@@ -129,7 +141,8 @@ WMList *WMCreateList(WMWidget * parent)
|
||||
| ClientMessageMask, handleEvents, lPtr);
|
||||
|
||||
WMCreateEventHandler(lPtr->view, ButtonPressMask | ButtonReleaseMask
|
||||
| EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, lPtr);
|
||||
| EnterWindowMask | LeaveWindowMask | ButtonMotionMask
|
||||
| KeyPressMask, handleActionEvents, lPtr);
|
||||
|
||||
lPtr->itemHeight = WMFontHeight(scrPtr->normalFont) + 1;
|
||||
|
||||
@@ -288,6 +301,14 @@ void WMClearList(WMList * lPtr)
|
||||
WMDeleteTimerHandler(lPtr->selectID);
|
||||
lPtr->selectID = NULL;
|
||||
}
|
||||
if (lPtr->typeaheadID) {
|
||||
WMDeleteTimerHandler(lPtr->typeaheadID);
|
||||
lPtr->typeaheadID = NULL;
|
||||
}
|
||||
if (lPtr->typeahead) {
|
||||
lPtr->typeahead[0] = '\0';
|
||||
lPtr->typeaheadLen = 0;
|
||||
}
|
||||
if (lPtr->view->flags.realized) {
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
@@ -495,15 +516,16 @@ static void paintItem(List * lPtr, int index)
|
||||
static void paintList(List * lPtr)
|
||||
{
|
||||
W_Screen *scrPtr = lPtr->view->screen;
|
||||
int i, lim;
|
||||
int i, lim, itemCount;
|
||||
|
||||
if (!lPtr->view->flags.mapped)
|
||||
return;
|
||||
|
||||
if (WMGetArrayItemCount(lPtr->items) > 0) {
|
||||
if (lPtr->topItem + lPtr->fullFitLines + lPtr->flags.dontFitAll > WMGetArrayItemCount(lPtr->items)) {
|
||||
itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
if (itemCount > 0) {
|
||||
if (lPtr->topItem + lPtr->fullFitLines + lPtr->flags.dontFitAll > itemCount) {
|
||||
|
||||
lim = WMGetArrayItemCount(lPtr->items) - lPtr->topItem;
|
||||
lim = itemCount - lPtr->topItem;
|
||||
XClearArea(scrPtr->display, lPtr->view->window, 19,
|
||||
2 + lim * lPtr->itemHeight, lPtr->view->size.width - 21,
|
||||
lPtr->view->size.height - lim * lPtr->itemHeight - 3, False);
|
||||
@@ -820,7 +842,7 @@ void WMSetListSelectionToRange(WMList * lPtr, WMRange range)
|
||||
|
||||
void WMSelectAllListItems(WMList * lPtr)
|
||||
{
|
||||
int i;
|
||||
int i, itemCount;
|
||||
WMListItem *item;
|
||||
|
||||
if (!lPtr->flags.allowMultipleSelection)
|
||||
@@ -833,7 +855,8 @@ void WMSelectAllListItems(WMList * lPtr)
|
||||
WMFreeArray(lPtr->selectedItems);
|
||||
lPtr->selectedItems = WMCreateArrayWithArray(lPtr->items);
|
||||
|
||||
for (i = 0; i < WMGetArrayItemCount(lPtr->items); i++) {
|
||||
itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
for (i = 0; i < itemCount; i++) {
|
||||
item = WMGetFromArray(lPtr->items, i);
|
||||
if (!item->selected) {
|
||||
item->selected = 1;
|
||||
@@ -859,10 +882,11 @@ void WMSelectAllListItems(WMList * lPtr)
|
||||
*/
|
||||
static void unselectAllListItems(WMList * lPtr, WMListItem * exceptThis)
|
||||
{
|
||||
int i;
|
||||
int i, itemCount;
|
||||
WMListItem *item;
|
||||
|
||||
for (i = 0; i < WMGetArrayItemCount(lPtr->items); i++) {
|
||||
itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
for (i = 0; i < itemCount; i++) {
|
||||
item = WMGetFromArray(lPtr->items, i);
|
||||
if (item != exceptThis && item->selected) {
|
||||
item->selected = 0;
|
||||
@@ -920,6 +944,85 @@ static void toggleItemSelection(WMList * lPtr, int index)
|
||||
}
|
||||
}
|
||||
|
||||
static int findItemWithPrefix(List * lPtr, const char *prefix, int prefixLen)
|
||||
{
|
||||
if (prefixLen <= 0)
|
||||
return -1;
|
||||
|
||||
int i, itemCount;
|
||||
|
||||
itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
for (i = 0; i < itemCount; i++) {
|
||||
WMListItem *item = WMGetFromArray(lPtr->items, i);
|
||||
|
||||
if (!item || !item->text || item->text[0] == '\0')
|
||||
continue;
|
||||
if (strncasecmp(item->text, prefix, prefixLen) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void jumpToFirstItemWithPrefix(WMList * lPtr, const char *prefix, int prefixLen)
|
||||
{
|
||||
int index, oldTop, visibleCount;
|
||||
|
||||
index = findItemWithPrefix(lPtr, prefix, prefixLen);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
WMRange range;
|
||||
|
||||
range.position = index;
|
||||
range.count = 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMSelectListItem(lPtr, index);
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
|
||||
visibleCount = lPtr->fullFitLines + lPtr->flags.dontFitAll;
|
||||
if (visibleCount < 1)
|
||||
visibleCount = 1;
|
||||
|
||||
oldTop = lPtr->topItem;
|
||||
if (index < lPtr->topItem) {
|
||||
lPtr->topItem = index;
|
||||
} else {
|
||||
if (lPtr->flags.dontFitAll) {
|
||||
if (lPtr->fullFitLines <= 0) {
|
||||
lPtr->topItem = index;
|
||||
} else {
|
||||
int lastFullyVisible = lPtr->topItem + lPtr->fullFitLines - 1;
|
||||
if (index > lastFullyVisible)
|
||||
lPtr->topItem = index - lPtr->fullFitLines + 1;
|
||||
}
|
||||
} else if (index >= lPtr->topItem + visibleCount) {
|
||||
lPtr->topItem = index - visibleCount + 1;
|
||||
}
|
||||
}
|
||||
if (lPtr->topItem < 0)
|
||||
lPtr->topItem = 0;
|
||||
|
||||
if (lPtr->view->flags.realized && lPtr->topItem != oldTop)
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
|
||||
static void typeaheadTimeout(void *data)
|
||||
{
|
||||
List *lPtr = (List *) data;
|
||||
|
||||
lPtr->typeaheadID = NULL;
|
||||
if (lPtr->typeahead) {
|
||||
lPtr->typeahead[0] = '\0';
|
||||
lPtr->typeaheadLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleActionEvents(XEvent * event, void *data)
|
||||
{
|
||||
List *lPtr = (List *) data;
|
||||
@@ -959,6 +1062,7 @@ static void handleActionEvents(XEvent * event, void *data)
|
||||
WMDeleteTimerHandler(lPtr->selectID);
|
||||
lPtr->selectID = NULL;
|
||||
}
|
||||
WMSetFocusToWidget(lPtr);
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
@@ -970,6 +1074,9 @@ static void handleActionEvents(XEvent * event, void *data)
|
||||
lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollBackwardSelecting, lPtr);
|
||||
}
|
||||
}
|
||||
WMWidget *parentWidget = WMWidgetOfView(lPtr->view->parent);
|
||||
if (parentWidget)
|
||||
WMSetFocusToWidget(parentWidget);
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
@@ -1076,6 +1183,381 @@ static void handleActionEvents(XEvent * event, void *data)
|
||||
prevItem = tmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case KeyPress:
|
||||
char buffer[16];
|
||||
KeySym ksym;
|
||||
Status status;
|
||||
int len;
|
||||
WMScreen *scr = lPtr->view->screen;
|
||||
XWindowAttributes wattr;
|
||||
|
||||
if (event->xkey.state & (ControlMask | Mod1Mask))
|
||||
break;
|
||||
|
||||
if (!(XGetWindowAttributes(scr->display, lPtr->view->window, &wattr) && wattr.map_state == IsViewable))
|
||||
break;
|
||||
|
||||
len = W_LookupString(lPtr->view, &event->xkey, buffer, (int)sizeof(buffer) - 1, &ksym, &status);
|
||||
if (len < 0)
|
||||
break;
|
||||
if (len > 0)
|
||||
buffer[len] = '\0';
|
||||
|
||||
/* Handle navigation keys */
|
||||
switch (ksym) {
|
||||
case XK_Up: {
|
||||
int newRow;
|
||||
int itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
int cur = WMGetListSelectedItemRow(lPtr);
|
||||
|
||||
if (lPtr->flags.allowMultipleSelection && WMGetArrayItemCount(lPtr->selectedItems) > 0) {
|
||||
WMListItem *lastSel = WMGetFromArray(lPtr->selectedItems, WMGetArrayItemCount(lPtr->selectedItems) - 1);
|
||||
if (lastSel)
|
||||
cur = WMGetFirstInArray(lPtr->items, lastSel);
|
||||
}
|
||||
|
||||
if (cur == WLNotFound)
|
||||
cur = lPtr->topItem;
|
||||
newRow = cur - 1;
|
||||
if (newRow < 0)
|
||||
newRow = 0;
|
||||
|
||||
if (newRow != cur && itemCount > 0) {
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
if (event->xkey.state & ShiftMask) {
|
||||
WMRange range;
|
||||
int anchor = WMGetListSelectedItemRow(lPtr);
|
||||
if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
|
||||
anchor = cur;
|
||||
}
|
||||
|
||||
range.position = anchor;
|
||||
if (newRow >= anchor)
|
||||
range.count = newRow - anchor + 1;
|
||||
else
|
||||
range.count = newRow - anchor - 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMRange range = { .position = newRow, .count = 1 };
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
} else {
|
||||
WMSelectListItem(lPtr, newRow);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
|
||||
/* Ensure visibility */
|
||||
if (newRow < lPtr->topItem) {
|
||||
lPtr->topItem = newRow;
|
||||
if (lPtr->view->flags.realized)
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XK_Down: {
|
||||
int newRow;
|
||||
int itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
int cur = WMGetListSelectedItemRow(lPtr);
|
||||
|
||||
if (lPtr->flags.allowMultipleSelection && WMGetArrayItemCount(lPtr->selectedItems) > 0) {
|
||||
WMListItem *lastSel = WMGetFromArray(lPtr->selectedItems, WMGetArrayItemCount(lPtr->selectedItems) - 1);
|
||||
if (lastSel)
|
||||
cur = WMGetFirstInArray(lPtr->items, lastSel);
|
||||
}
|
||||
|
||||
if (cur == WLNotFound)
|
||||
cur = lPtr->topItem;
|
||||
newRow = cur + 1;
|
||||
if (newRow >= itemCount)
|
||||
newRow = itemCount - 1;
|
||||
|
||||
if (newRow != cur && itemCount > 0) {
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
if (event->xkey.state & ShiftMask) {
|
||||
WMRange range;
|
||||
int anchor = WMGetListSelectedItemRow(lPtr);
|
||||
if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
|
||||
anchor = cur;
|
||||
}
|
||||
|
||||
range.position = anchor;
|
||||
if (newRow >= anchor)
|
||||
range.count = newRow - anchor + 1;
|
||||
else
|
||||
range.count = newRow - anchor - 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMRange range = { .position = newRow, .count = 1 };
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
} else {
|
||||
WMSelectListItem(lPtr, newRow);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
|
||||
/* Ensure visibility */
|
||||
if (newRow > (lPtr->topItem + lPtr->fullFitLines - 1)) {
|
||||
lPtr->topItem = newRow - lPtr->fullFitLines + 1;
|
||||
if (lPtr->topItem < 0)
|
||||
lPtr->topItem = 0;
|
||||
/* Ensure we don't scroll past the end */
|
||||
if (lPtr->topItem + lPtr->fullFitLines > itemCount)
|
||||
lPtr->topItem = itemCount - lPtr->fullFitLines;
|
||||
if (lPtr->topItem < 0)
|
||||
lPtr->topItem = 0;
|
||||
if (lPtr->view->flags.realized)
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XK_Page_Up: {
|
||||
int newRow;
|
||||
int page = lPtr->fullFitLines > 0 ? lPtr->fullFitLines : 1;
|
||||
int cur = WMGetListSelectedItemRow(lPtr);
|
||||
|
||||
if (cur == WLNotFound)
|
||||
cur = lPtr->topItem;
|
||||
newRow = cur - page;
|
||||
if (newRow < 0)
|
||||
newRow = 0;
|
||||
|
||||
if (newRow != cur) {
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
if (event->xkey.state & ShiftMask) {
|
||||
WMRange range;
|
||||
int anchor = WMGetListSelectedItemRow(lPtr);
|
||||
if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
|
||||
anchor = cur;
|
||||
}
|
||||
|
||||
range.position = anchor;
|
||||
if (newRow >= anchor)
|
||||
range.count = newRow - anchor + 1;
|
||||
else
|
||||
range.count = newRow - anchor - 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMRange range = { .position = newRow, .count = 1 };
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
} else {
|
||||
WMSelectListItem(lPtr, newRow);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
if (newRow < lPtr->topItem) {
|
||||
lPtr->topItem = newRow;
|
||||
if (lPtr->view->flags.realized)
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XK_Page_Down: {
|
||||
int newRow;
|
||||
int page = lPtr->fullFitLines > 0 ? lPtr->fullFitLines : 1;
|
||||
int itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
int cur = WMGetListSelectedItemRow(lPtr);
|
||||
|
||||
if (cur == WLNotFound)
|
||||
cur = lPtr->topItem;
|
||||
newRow = cur + page;
|
||||
if (newRow >= itemCount)
|
||||
newRow = itemCount - 1;
|
||||
|
||||
if (newRow != cur && itemCount > 0) {
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
if (event->xkey.state & ShiftMask) {
|
||||
WMRange range;
|
||||
int anchor = WMGetListSelectedItemRow(lPtr);
|
||||
if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
|
||||
anchor = cur;
|
||||
}
|
||||
|
||||
range.position = anchor;
|
||||
if (newRow >= anchor)
|
||||
range.count = newRow - anchor + 1;
|
||||
else
|
||||
range.count = newRow - anchor - 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMRange range = { .position = newRow, .count = 1 };
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
} else {
|
||||
WMSelectListItem(lPtr, newRow);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
|
||||
/* Ensure visibility */
|
||||
if (newRow > (lPtr->topItem + lPtr->fullFitLines - 1)) {
|
||||
lPtr->topItem = newRow - lPtr->fullFitLines + 1;
|
||||
if (lPtr->topItem < 0)
|
||||
lPtr->topItem = 0;
|
||||
/* Ensure we don't scroll past the end */
|
||||
if (lPtr->topItem + lPtr->fullFitLines > itemCount)
|
||||
lPtr->topItem = itemCount - lPtr->fullFitLines;
|
||||
if (lPtr->topItem < 0)
|
||||
lPtr->topItem = 0;
|
||||
if (lPtr->view->flags.realized)
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XK_Home: {
|
||||
int itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
if (itemCount > 0) {
|
||||
int newRow = 0;
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
if (event->xkey.state & ShiftMask) {
|
||||
WMRange range;
|
||||
int anchor = WMGetListSelectedItemRow(lPtr);
|
||||
if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
|
||||
anchor = lPtr->topItem;
|
||||
}
|
||||
|
||||
range.position = anchor;
|
||||
if (newRow >= anchor)
|
||||
range.count = newRow - anchor + 1;
|
||||
else
|
||||
range.count = newRow - anchor - 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMRange range = { .position = newRow, .count = 1 };
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
} else {
|
||||
WMSelectListItem(lPtr, newRow);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
if (newRow < lPtr->topItem) {
|
||||
lPtr->topItem = newRow;
|
||||
if (lPtr->view->flags.realized)
|
||||
updateScroller(lPtr);
|
||||
}
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XK_End: {
|
||||
int itemCount = WMGetArrayItemCount(lPtr->items);
|
||||
if (itemCount > 0) {
|
||||
int newRow = itemCount - 1;
|
||||
if (lPtr->flags.allowMultipleSelection) {
|
||||
if (event->xkey.state & ShiftMask) {
|
||||
WMRange range;
|
||||
int anchor = WMGetListSelectedItemRow(lPtr);
|
||||
if (anchor == WLNotFound || WMGetArrayItemCount(lPtr->selectedItems) == 0) {
|
||||
anchor = lPtr->topItem;
|
||||
}
|
||||
|
||||
range.position = anchor;
|
||||
if (newRow >= anchor)
|
||||
range.count = newRow - anchor + 1;
|
||||
else
|
||||
range.count = newRow - anchor - 1;
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
} else {
|
||||
WMRange range = { .position = newRow, .count = 1 };
|
||||
WMSetListSelectionToRange(lPtr, range);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
} else {
|
||||
WMSelectListItem(lPtr, newRow);
|
||||
lastClicked = newRow;
|
||||
}
|
||||
|
||||
/* Ensure the last item is fully visible */
|
||||
lPtr->topItem = itemCount - lPtr->fullFitLines;
|
||||
if (lPtr->topItem < 0)
|
||||
lPtr->topItem = 0;
|
||||
if (lPtr->view->flags.realized)
|
||||
updateScroller(lPtr);
|
||||
|
||||
/* Trigger action callback */
|
||||
if (lPtr->action)
|
||||
(*lPtr->action) (lPtr, lPtr->clientData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we handled a navigation keysym, avoid falling through to typeahead logic */
|
||||
if (ksym == XK_Up || ksym == XK_Down || ksym == XK_Page_Up || ksym == XK_Page_Down || ksym == XK_Home || ksym == XK_End)
|
||||
break;
|
||||
|
||||
if (len <= 0)
|
||||
break;
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
if (ksym == XK_Escape) {
|
||||
if (lPtr->typeaheadID) {
|
||||
WMDeleteTimerHandler(lPtr->typeaheadID);
|
||||
lPtr->typeaheadID = NULL;
|
||||
}
|
||||
if (lPtr->typeahead) {
|
||||
lPtr->typeahead[0] = '\0';
|
||||
lPtr->typeaheadLen = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ksym == XK_BackSpace) {
|
||||
if (lPtr->typeaheadLen > 0 && lPtr->typeahead) {
|
||||
lPtr->typeaheadLen--;
|
||||
lPtr->typeahead[lPtr->typeaheadLen] = '\0';
|
||||
}
|
||||
} else if (len == 1 && isalnum((unsigned char)buffer[0])) {
|
||||
if (!lPtr->typeahead) {
|
||||
lPtr->typeahead = wmalloc(2);
|
||||
lPtr->typeaheadLen = 0;
|
||||
}
|
||||
lPtr->typeahead = wrealloc(lPtr->typeahead, lPtr->typeaheadLen + 2);
|
||||
lPtr->typeahead[lPtr->typeaheadLen] = buffer[0];
|
||||
lPtr->typeaheadLen++;
|
||||
lPtr->typeahead[lPtr->typeaheadLen] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (lPtr->typeaheadLen > 0)
|
||||
jumpToFirstItemWithPrefix(lPtr, lPtr->typeahead, lPtr->typeaheadLen);
|
||||
|
||||
if (lPtr->typeaheadID) {
|
||||
WMDeleteTimerHandler(lPtr->typeaheadID);
|
||||
lPtr->typeaheadID = NULL;
|
||||
}
|
||||
if (lPtr->typeaheadLen > 0)
|
||||
lPtr->typeaheadID = WMAddTimerHandler(TYPEAHEAD_CLEAR_DELAY, typeaheadTimeout, lPtr);
|
||||
break;
|
||||
|
||||
}
|
||||
if (lPtr->topItem != topItem)
|
||||
WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
|
||||
@@ -1123,6 +1605,10 @@ static void destroyList(List * lPtr)
|
||||
WMDeleteTimerHandler(lPtr->selectID);
|
||||
lPtr->selectID = NULL;
|
||||
|
||||
if (lPtr->typeaheadID)
|
||||
WMDeleteTimerHandler(lPtr->typeaheadID);
|
||||
lPtr->typeaheadID = NULL;
|
||||
|
||||
if (lPtr->selectedItems)
|
||||
WMFreeArray(lPtr->selectedItems);
|
||||
|
||||
@@ -1132,6 +1618,9 @@ static void destroyList(List * lPtr)
|
||||
if (lPtr->doubleBuffer)
|
||||
XFreePixmap(lPtr->view->screen->display, lPtr->doubleBuffer);
|
||||
|
||||
if (lPtr->typeahead)
|
||||
wfree(lPtr->typeahead);
|
||||
|
||||
WMRemoveNotificationObserver(lPtr);
|
||||
|
||||
wfree(lPtr);
|
||||
|
||||
@@ -252,6 +252,56 @@ WMMenuItem *WMGetPopUpButtonMenuItem(WMPopUpButton * bPtr, int index)
|
||||
return WMGetFromArray(bPtr->items, index);
|
||||
}
|
||||
|
||||
int WMSelectPopUpButtonPreviousItem(WMPopUpButton * bPtr)
|
||||
{
|
||||
int testIndex;
|
||||
|
||||
CHECK_CLASS(bPtr, WC_PopUpButton);
|
||||
|
||||
if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0)
|
||||
return -1;
|
||||
|
||||
testIndex = bPtr->selectedItemIndex - 1;
|
||||
|
||||
while (testIndex >= 0 && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
|
||||
testIndex--;
|
||||
|
||||
if (testIndex != -1) {
|
||||
WMSetPopUpButtonSelectedItem(bPtr, testIndex);
|
||||
if (bPtr->action)
|
||||
(*bPtr->action) (bPtr, bPtr->clientData);
|
||||
return testIndex;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WMSelectPopUpButtonNextItem(WMPopUpButton * bPtr)
|
||||
{
|
||||
int itemCount;
|
||||
int testIndex;
|
||||
|
||||
CHECK_CLASS(bPtr, WC_PopUpButton);
|
||||
|
||||
if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0)
|
||||
return -1;
|
||||
|
||||
itemCount = WMGetArrayItemCount(bPtr->items);
|
||||
testIndex = bPtr->selectedItemIndex + 1;
|
||||
|
||||
while (testIndex < itemCount && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
|
||||
testIndex++;
|
||||
|
||||
if (testIndex != itemCount) {
|
||||
WMSetPopUpButtonSelectedItem(bPtr, testIndex);
|
||||
if (bPtr->action)
|
||||
(*bPtr->action) (bPtr, bPtr->clientData);
|
||||
return testIndex;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void paintPopUpButton(PopUpButton * bPtr)
|
||||
{
|
||||
W_Screen *scr = bPtr->view->screen;
|
||||
|
||||
+16
-16
@@ -219,9 +219,9 @@ static char *default_bullet[] = {
|
||||
};
|
||||
|
||||
/* These id are used when sharing the selected text between applications */
|
||||
static Atom XA_Targets = None;
|
||||
static Atom XA_Format_Text = None;
|
||||
static Atom XA_Format_Compound_Text = None;
|
||||
static Atom XA_TARGETS = None;
|
||||
static Atom XA_TEXT = None;
|
||||
static Atom XA_COMPOUND_TEXT = None;
|
||||
|
||||
static void handleEvents(XEvent * event, void *data);
|
||||
static void layOutDocument(Text * tPtr);
|
||||
@@ -2050,7 +2050,7 @@ static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *
|
||||
(void) selection;
|
||||
(void) cdata;
|
||||
|
||||
if (target == XA_STRING || target == XA_Format_Text || target == XA_Format_Compound_Text) {
|
||||
if (target == XA_STRING || target == XA_TEXT || target == XA_COMPOUND_TEXT) {
|
||||
char *text = WMGetTextSelectedStream(tPtr);
|
||||
|
||||
if (text) {
|
||||
@@ -2063,18 +2063,18 @@ static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *
|
||||
} else
|
||||
printf("didn't get it\n");
|
||||
|
||||
if (target == XA_Targets) {
|
||||
Atom array[4];
|
||||
if (target == XA_TARGETS) {
|
||||
Atom supported_type[4];
|
||||
|
||||
array[0] = XA_Targets;
|
||||
array[1] = XA_STRING;
|
||||
array[2] = XA_Format_Text;
|
||||
array[3] = XA_Format_Compound_Text;
|
||||
supported_type[0] = XA_TARGETS;
|
||||
supported_type[1] = XA_STRING;
|
||||
supported_type[2] = XA_TEXT;
|
||||
supported_type[3] = XA_COMPOUND_TEXT;
|
||||
|
||||
data = WMCreateDataWithBytes(&array, sizeof(array));
|
||||
data = WMCreateDataWithBytes(supported_type, sizeof(supported_type));
|
||||
WMSetDataFormat(data, 32);
|
||||
|
||||
*type = target;
|
||||
*type = XA_ATOM;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -2977,15 +2977,15 @@ WMText *WMCreateTextForDocumentType(WMWidget * parent, WMAction * parser, WMActi
|
||||
dpy = tPtr->view->screen->display;
|
||||
scr = tPtr->view->screen;
|
||||
|
||||
if (XA_Targets == None) {
|
||||
if (XA_TARGETS == None) {
|
||||
/*
|
||||
* Because the X protocol guaranties that the value will never change in
|
||||
* the lifespan of the server, we query the values only the first time a
|
||||
* widget is created
|
||||
*/
|
||||
XA_Targets = XInternAtom(dpy, "TARGETS", False);
|
||||
XA_Format_Text = XInternAtom(dpy, "TEXT", False);
|
||||
XA_Format_Compound_Text = XInternAtom(dpy, "COMPOUND_TEXT", False);
|
||||
XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
|
||||
XA_TEXT = XInternAtom(dpy, "TEXT", False);
|
||||
XA_COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
|
||||
}
|
||||
|
||||
tPtr->view->self = tPtr;
|
||||
|
||||
+89
-59
@@ -239,9 +239,9 @@ static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *
|
||||
TextField *tPtr = view->self;
|
||||
int count;
|
||||
Display *dpy = tPtr->view->screen->display;
|
||||
Atom _TARGETS;
|
||||
Atom TEXT = XInternAtom(dpy, "TEXT", False);
|
||||
Atom COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
|
||||
Atom XA_TARGETS;
|
||||
Atom XA_TEXT = XInternAtom(dpy, "TEXT", False);
|
||||
Atom XA_COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
|
||||
WMData *data;
|
||||
|
||||
/* Parameter not used, but tell the compiler that it is ok */
|
||||
@@ -251,7 +251,7 @@ static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *
|
||||
count = tPtr->selection.count < 0
|
||||
? tPtr->selection.position + tPtr->selection.count : tPtr->selection.position;
|
||||
|
||||
if (target == XA_STRING || target == TEXT || target == COMPOUND_TEXT) {
|
||||
if (target == XA_STRING || target == XA_TEXT || target == XA_COMPOUND_TEXT) {
|
||||
|
||||
data = WMCreateDataWithBytes(&(tPtr->text[count]), abs(tPtr->selection.count));
|
||||
WMSetDataFormat(data, 8);
|
||||
@@ -260,19 +260,19 @@ static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *
|
||||
return data;
|
||||
}
|
||||
|
||||
_TARGETS = XInternAtom(dpy, "TARGETS", False);
|
||||
if (target == _TARGETS) {
|
||||
XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
|
||||
if (target == XA_TARGETS) {
|
||||
Atom supported_type[4];
|
||||
|
||||
supported_type[0] = _TARGETS;
|
||||
supported_type[0] = XA_TARGETS;
|
||||
supported_type[1] = XA_STRING;
|
||||
supported_type[2] = TEXT;
|
||||
supported_type[3] = COMPOUND_TEXT;
|
||||
supported_type[2] = XA_TEXT;
|
||||
supported_type[3] = XA_COMPOUND_TEXT;
|
||||
|
||||
data = WMCreateDataWithBytes(supported_type, sizeof(supported_type));
|
||||
WMSetDataFormat(data, 32);
|
||||
|
||||
*type = target;
|
||||
*type = XA_ATOM;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -446,6 +446,13 @@ void WMDeleteTextFieldRange(WMTextField * tPtr, WMRange range)
|
||||
|
||||
decrToFit(tPtr);
|
||||
|
||||
/* Ensure cursor is visible after deletion */
|
||||
if (tPtr->cursorPosition < tPtr->viewPosition) {
|
||||
tPtr->viewPosition = tPtr->cursorPosition;
|
||||
} else {
|
||||
incrToFit2(tPtr);
|
||||
}
|
||||
|
||||
paintTextField(tPtr);
|
||||
}
|
||||
|
||||
@@ -490,11 +497,6 @@ void WMSetTextFieldAlignment(WMTextField * tPtr, WMAlignment alignment)
|
||||
|
||||
tPtr->flags.alignment = alignment;
|
||||
|
||||
if (alignment != WALeft) {
|
||||
wwarning(_("only left alignment is supported in textfields"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tPtr->view->flags.realized) {
|
||||
paintTextField(tPtr);
|
||||
}
|
||||
@@ -846,8 +848,8 @@ static void paintTextField(TextField * tPtr)
|
||||
count = tPtr->viewPosition;
|
||||
}
|
||||
|
||||
rx = tPtr->offsetWidth + 1 + WMWidthOfString(tPtr->font, text, count)
|
||||
- WMWidthOfString(tPtr->font, text, tPtr->viewPosition);
|
||||
rx = tx + WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]),
|
||||
count - tPtr->viewPosition);
|
||||
|
||||
WMDrawImageString(screen, drawbuffer, color, screen->gray,
|
||||
tPtr->font, rx, ty, &(text[count]), count2);
|
||||
@@ -1029,7 +1031,6 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
|
||||
case XK_Left:
|
||||
if (tPtr->cursorPosition > 0) {
|
||||
int i;
|
||||
paintCursor(tPtr);
|
||||
|
||||
i = tPtr->cursorPosition;
|
||||
i += oneUTF8CharBackward(&tPtr->text[i], i);
|
||||
@@ -1045,9 +1046,8 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
|
||||
|
||||
if (tPtr->cursorPosition < tPtr->viewPosition) {
|
||||
tPtr->viewPosition = tPtr->cursorPosition;
|
||||
refresh = 1;
|
||||
} else
|
||||
paintCursor(tPtr);
|
||||
}
|
||||
refresh = 1;
|
||||
}
|
||||
if (shifted)
|
||||
cancelSelection = 0;
|
||||
@@ -1070,7 +1070,6 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
|
||||
case XK_Right:
|
||||
if (tPtr->cursorPosition < tPtr->textLen) {
|
||||
int i;
|
||||
paintCursor(tPtr);
|
||||
|
||||
i = tPtr->cursorPosition;
|
||||
if (controled) {
|
||||
@@ -1083,10 +1082,8 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
|
||||
}
|
||||
tPtr->cursorPosition = i;
|
||||
|
||||
refresh = incrToFit2(tPtr);
|
||||
|
||||
if (!refresh)
|
||||
paintCursor(tPtr);
|
||||
incrToFit2(tPtr);
|
||||
refresh = 1;
|
||||
}
|
||||
if (shifted)
|
||||
cancelSelection = 0;
|
||||
@@ -1109,13 +1106,11 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
|
||||
case XK_Home:
|
||||
if (!controled) {
|
||||
if (tPtr->cursorPosition > 0) {
|
||||
paintCursor(tPtr);
|
||||
tPtr->cursorPosition = 0;
|
||||
if (tPtr->viewPosition > 0) {
|
||||
tPtr->viewPosition = 0;
|
||||
refresh = 1;
|
||||
} else
|
||||
paintCursor(tPtr);
|
||||
}
|
||||
refresh = 1;
|
||||
}
|
||||
if (shifted)
|
||||
cancelSelection = 0;
|
||||
@@ -1138,14 +1133,11 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
|
||||
case XK_End:
|
||||
if (!controled) {
|
||||
if (tPtr->cursorPosition < tPtr->textLen) {
|
||||
paintCursor(tPtr);
|
||||
tPtr->cursorPosition = tPtr->textLen;
|
||||
tPtr->viewPosition = 0;
|
||||
|
||||
refresh = incrToFit(tPtr);
|
||||
|
||||
if (!refresh)
|
||||
paintCursor(tPtr);
|
||||
incrToFit(tPtr);
|
||||
refresh = 1;
|
||||
}
|
||||
if (shifted)
|
||||
cancelSelection = 0;
|
||||
@@ -1408,7 +1400,25 @@ static void handleTextFieldActionEvents(XEvent * event, void *data)
|
||||
tPtr->viewPosition);
|
||||
}
|
||||
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xmotion.x);
|
||||
if (tPtr->flags.alignment == WARight) {
|
||||
int textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
|
||||
if (textWidth < tPtr->usableWidth) {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr,
|
||||
event->xmotion.x - tPtr->usableWidth + textWidth);
|
||||
} else {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xmotion.x);
|
||||
}
|
||||
} else if (tPtr->flags.alignment == WACenter) {
|
||||
int textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
|
||||
if (textWidth < tPtr->usableWidth) {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr,
|
||||
event->xmotion.x - (tPtr->usableWidth - textWidth) / 2);
|
||||
} else {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xmotion.x);
|
||||
}
|
||||
} else {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xmotion.x);
|
||||
}
|
||||
|
||||
/* Do not allow text selection in secure textfields */
|
||||
if (tPtr->flags.secure) {
|
||||
@@ -1441,17 +1451,35 @@ static void handleTextFieldActionEvents(XEvent * event, void *data)
|
||||
if (tPtr->flags.enabled && !tPtr->flags.focused) {
|
||||
WMSetFocusToWidget(tPtr);
|
||||
}
|
||||
if (textWidth < tPtr->usableWidth) {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr,
|
||||
event->xbutton.x - tPtr->usableWidth
|
||||
+ textWidth);
|
||||
} else
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x);
|
||||
|
||||
if (tPtr->flags.focused) {
|
||||
tPtr->selection.position = tPtr->cursorPosition;
|
||||
tPtr->selection.count = 0;
|
||||
}
|
||||
paintTextField(tPtr);
|
||||
break;
|
||||
|
||||
case WACenter:
|
||||
textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
|
||||
if (tPtr->flags.enabled && !tPtr->flags.focused) {
|
||||
WMSetFocusToWidget(tPtr);
|
||||
}
|
||||
if (textWidth < tPtr->usableWidth) {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr,
|
||||
event->xbutton.x - tPtr->usableWidth
|
||||
+ textWidth);
|
||||
} else
|
||||
event->xbutton.x - (tPtr->usableWidth - textWidth) / 2);
|
||||
} else {
|
||||
tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x);
|
||||
|
||||
}
|
||||
if (tPtr->flags.focused) {
|
||||
tPtr->selection.position = tPtr->cursorPosition;
|
||||
tPtr->selection.count = 0;
|
||||
}
|
||||
paintTextField(tPtr);
|
||||
break;
|
||||
|
||||
@@ -1465,29 +1493,31 @@ static void handleTextFieldActionEvents(XEvent * event, void *data)
|
||||
tPtr->selection.count = 0;
|
||||
paintTextField(tPtr);
|
||||
}
|
||||
if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
|
||||
char *text;
|
||||
int n;
|
||||
|
||||
if (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING,
|
||||
event->xbutton.time, pasteText, NULL)) {
|
||||
text = XFetchBuffer(tPtr->view->screen->display, &n, 0);
|
||||
|
||||
if (text) {
|
||||
text[n] = 0;
|
||||
WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
|
||||
XFree(text);
|
||||
NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
|
||||
(void *)WMInsertTextEvent);
|
||||
}
|
||||
} else {
|
||||
tPtr->flags.waitingSelection = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
|
||||
char *text;
|
||||
int n;
|
||||
|
||||
if (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING,
|
||||
event->xbutton.time, pasteText, NULL)) {
|
||||
text = XFetchBuffer(tPtr->view->screen->display, &n, 0);
|
||||
|
||||
if (text) {
|
||||
text[n] = 0;
|
||||
WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
|
||||
XFree(text);
|
||||
NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
|
||||
(void *)WMInsertTextEvent);
|
||||
}
|
||||
} else {
|
||||
tPtr->flags.waitingSelection = 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
|
||||
+134
-2
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (c) 2014-2023 Window Maker Team
|
||||
* Copyright (c) 1998-2003 Alfredo K. Kojima
|
||||
* Copyright (c) 2009-2023 Window Maker Team
|
||||
* Copyright (c) 2009-2026 Window Maker Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -72,9 +72,15 @@ static struct expert_option {
|
||||
{ N_("Cycle windows only on the active head."),
|
||||
/* default: */ False, OPTION_WMAKER, "CycleActiveHeadOnly" },
|
||||
|
||||
{ N_("Cycle all windows from all workspaces."),
|
||||
/* default: */ False, OPTION_WMAKER, "CycleAllWorkspaces" },
|
||||
|
||||
{ N_("Ignore minimized windows when cycling."),
|
||||
/* default: */ False, OPTION_WMAKER, "CycleIgnoreMinimized" },
|
||||
|
||||
{ N_("Show app icons in window list."),
|
||||
/* default: */ False, OPTION_WMAKER, "WindowListAppIcons" },
|
||||
|
||||
{ N_("Show switch panel when cycling windows."),
|
||||
/* default: */ True, OPTION_WMAKER_ARRAY, "SwitchPanelImages" },
|
||||
|
||||
@@ -141,6 +147,8 @@ typedef struct _Panel {
|
||||
WMButton *swi[wlengthof_nocheck(expert_options)];
|
||||
|
||||
WMTextField *textfield[wlengthof_nocheck(expert_options)];
|
||||
WMScrollView *sv;
|
||||
WMWidget *frame;
|
||||
|
||||
} _Panel;
|
||||
|
||||
@@ -161,6 +169,124 @@ static void changeIntTextfield(void *data, int delta)
|
||||
WMSetTextFieldText(textfield, buffer);
|
||||
}
|
||||
|
||||
static void scrollViewWheelHandler(XEvent *event, void *data)
|
||||
{
|
||||
_Panel *panel = (_Panel *) data;
|
||||
int amount, viewH, contentH, newY, maxY;
|
||||
WMRect rect;
|
||||
WMPoint pt;
|
||||
|
||||
if (!panel || !panel->sv || !panel->frame)
|
||||
return;
|
||||
|
||||
if (event->type != ButtonPress)
|
||||
return;
|
||||
|
||||
if (event->xbutton.button != WINGsConfiguration.mouseWheelUp &&
|
||||
event->xbutton.button != WINGsConfiguration.mouseWheelDown)
|
||||
return;
|
||||
|
||||
rect = WMGetScrollViewVisibleRect(panel->sv);
|
||||
viewH = rect.size.height;
|
||||
contentH = WMWidgetHeight(panel->frame);
|
||||
|
||||
if (event->xbutton.state & ControlMask) {
|
||||
amount = viewH; /* page */
|
||||
} else if (event->xbutton.state & ShiftMask) {
|
||||
amount = 1; /* line */
|
||||
} else {
|
||||
amount = viewH / 3; /* default */
|
||||
if (amount == 0)
|
||||
amount = 1;
|
||||
}
|
||||
|
||||
if (event->xbutton.button == WINGsConfiguration.mouseWheelUp)
|
||||
amount = -amount;
|
||||
|
||||
newY = rect.pos.y + amount;
|
||||
maxY = contentH - viewH;
|
||||
if (maxY < 0)
|
||||
maxY = 0;
|
||||
if (newY < 0)
|
||||
newY = 0;
|
||||
if (newY > maxY)
|
||||
newY = maxY;
|
||||
|
||||
pt.x = rect.pos.x;
|
||||
pt.y = newY;
|
||||
|
||||
WMScrollViewScrollPoint(panel->sv, pt);
|
||||
}
|
||||
|
||||
static void scrollViewRealizeObserver(void *self, WMNotification *not)
|
||||
{
|
||||
(void) not;
|
||||
_Panel *panel = (_Panel *) self;
|
||||
Display *dpy = NULL;
|
||||
Window viewport_win = 0;
|
||||
WMView *frameView;
|
||||
|
||||
if (!panel || !panel->frame)
|
||||
return;
|
||||
|
||||
frameView = WMWidgetView(panel->frame);
|
||||
|
||||
if (frameView && frameView->parent) {
|
||||
dpy = frameView->screen->display;
|
||||
viewport_win = frameView->parent->window;
|
||||
}
|
||||
|
||||
/* fallback: use the scrollview's view window if parent viewport not available */
|
||||
if (!viewport_win && panel->sv) {
|
||||
WMView *svView = WMWidgetView(panel->sv);
|
||||
if (svView && svView->screen) {
|
||||
dpy = svView->screen->display;
|
||||
viewport_win = svView->window;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dpy || viewport_win == 0)
|
||||
return;
|
||||
|
||||
XGrabButton(dpy, WINGsConfiguration.mouseWheelUp, AnyModifier, viewport_win,
|
||||
True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
|
||||
XGrabButton(dpy, WINGsConfiguration.mouseWheelDown, AnyModifier, viewport_win,
|
||||
True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
|
||||
}
|
||||
|
||||
static void scrollViewPrepareForClose(Panel *p)
|
||||
{
|
||||
_Panel *panel = (_Panel *) p;
|
||||
Display *dpy = NULL;
|
||||
Window viewport_win = 0;
|
||||
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
if (panel->frame) {
|
||||
WMView *frameView = WMWidgetView(panel->frame);
|
||||
if (frameView && frameView->parent) {
|
||||
dpy = frameView->screen->display;
|
||||
viewport_win = frameView->parent->window;
|
||||
}
|
||||
}
|
||||
|
||||
if (!viewport_win && panel->sv) {
|
||||
WMView *svView = WMWidgetView(panel->sv);
|
||||
if (svView && svView->screen) {
|
||||
dpy = svView->screen->display;
|
||||
viewport_win = svView->window;
|
||||
}
|
||||
}
|
||||
|
||||
if (dpy && viewport_win != 0) {
|
||||
XUngrabButton(dpy, WINGsConfiguration.mouseWheelUp, AnyModifier, viewport_win);
|
||||
XUngrabButton(dpy, WINGsConfiguration.mouseWheelDown, AnyModifier, viewport_win);
|
||||
}
|
||||
|
||||
WMRemoveNotificationObserver(panel);
|
||||
}
|
||||
|
||||
static void downButtonCallback(WMWidget *self, void *data)
|
||||
{
|
||||
(void) self;
|
||||
@@ -284,7 +410,7 @@ static void createPanel(Panel *p)
|
||||
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
wwarning("export_options[%d].class = %d, this should not happen\n",
|
||||
wwarning("expert_options[%d].class = %d, this should not happen\n",
|
||||
i, expert_options[i].class);
|
||||
#endif
|
||||
state = expert_options[i].def_state;
|
||||
@@ -296,6 +422,11 @@ static void createPanel(Panel *p)
|
||||
|
||||
WMMapSubwidgets(panel->box);
|
||||
WMSetScrollViewContentView(sv, WMWidgetView(f));
|
||||
/* keep references for the wheel handler and register it */
|
||||
panel->sv = sv;
|
||||
panel->frame = f;
|
||||
WMCreateEventHandler(WMWidgetView(sv), ButtonPressMask, scrollViewWheelHandler, panel);
|
||||
WMAddNotificationObserver(scrollViewRealizeObserver, panel, WMViewRealizedNotification, WMWidgetView(sv));
|
||||
WMRealizeWidget(panel->box);
|
||||
}
|
||||
|
||||
@@ -356,6 +487,7 @@ Panel *InitExpert(WMWidget *parent)
|
||||
|
||||
panel->callbacks.createWidgets = createPanel;
|
||||
panel->callbacks.updateDomain = storeDefaults;
|
||||
panel->callbacks.prepareForClose = scrollViewPrepareForClose;
|
||||
|
||||
AddSection(panel, ICON_FILE);
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ static void createPanel(Panel * p)
|
||||
WMMoveWidget(panel->hcdescF, 15, 130);
|
||||
|
||||
panel->hcdescL = WMCreateLabel(panel->hcdescF);
|
||||
WMResizeWidget(panel->hcdescL, 200, 60);
|
||||
WMResizeWidget(panel->hcdescL, 200, 70);
|
||||
WMMoveWidget(panel->hcdescL, 15, 10);
|
||||
WMSetLabelText(panel->hcdescL,
|
||||
_("Instructions:\n\n"
|
||||
|
||||
@@ -284,14 +284,14 @@ static void createPanel(Panel * p)
|
||||
|
||||
/***************** Options ****************/
|
||||
panel->optF = WMCreateFrame(panel->box);
|
||||
WMResizeWidget(panel->optF, 255, 94);
|
||||
WMResizeWidget(panel->optF, 255, 96);
|
||||
WMMoveWidget(panel->optF, 15, 125);
|
||||
WMSetFrameTitle(panel->optF, _("AppIcon bouncing"));
|
||||
|
||||
for (i = 0; i < wlengthof(appicon_bouncing); i++) {
|
||||
panel->bounceB[i] = WMCreateSwitchButton(panel->optF);
|
||||
WMResizeWidget(panel->bounceB[i], 237, 26);
|
||||
WMMoveWidget(panel->bounceB[i], 9, 14 + i * 25);
|
||||
WMMoveWidget(panel->bounceB[i], 9, 16 + i * 26);
|
||||
WMSetButtonText(panel->bounceB[i], _(appicon_bouncing[i].label));
|
||||
|
||||
if (appicon_bouncing[i].default_value)
|
||||
@@ -306,7 +306,7 @@ static void createPanel(Panel * p)
|
||||
|
||||
/***************** Workspace border ****************/
|
||||
panel->borderF = WMCreateFrame(panel->box);
|
||||
WMResizeWidget(panel->borderF, 220, 75);
|
||||
WMResizeWidget(panel->borderF, 220, 77);
|
||||
WMMoveWidget(panel->borderF, 285, 144);
|
||||
WMSetFrameTitle(panel->borderF, _("Workspace border"));
|
||||
|
||||
|
||||
@@ -26,4 +26,4 @@ et.po Estonian Ivar Smolin <okul@linux.ee>
|
||||
ca.po Catalan Ernest Adrogué <eadrogue@gmx.net>
|
||||
nl.po Dutch Alwin <translations@ziggo.nl>
|
||||
fy.po Frisian Alwin <translations@ziggo.nl>
|
||||
sr.po Serbian Strahinya Radich <contact@strahinja.org>
|
||||
sr.po Serbian Strahinya Radich <sr@strahinja.org>
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
# 1998-2006 Dan Pascu
|
||||
# 2013-2020 Window Maker Developers Team
|
||||
# This file is distributed under the same license as the Window Maker package.
|
||||
# Strahinya Radich (Страхиња Радић) <contact@strahinja.org>, 2023.
|
||||
# Strahinya Radich (Страхиња Радић) <sr@strahinja.org>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -11,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: wmaker-dev@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2023-11-02 19:25+0100\n"
|
||||
"PO-Revision-Date: 2023-11-02 19:48+0100\n"
|
||||
"Last-Translator: Страхиња Радић <contact@strahinja.org>\n"
|
||||
"Last-Translator: Страхиња Радић <sr@strahinja.org>\n"
|
||||
"Language-Team: Serbian <sr@li.org>\n"
|
||||
"Language: sr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
@@ -233,7 +233,7 @@
|
||||
ScreenSwitchKey = None;
|
||||
RunKey = None;
|
||||
ExitKey = None;
|
||||
ScreenCaptureKey = Print;
|
||||
ScreenCaptureKey = None;
|
||||
WindowCaptureKey = None;
|
||||
PartialCaptureKey = None;
|
||||
NormalCursor = (builtin, left_ptr);
|
||||
@@ -252,5 +252,7 @@
|
||||
SelectCursor = (builtin, cross);
|
||||
DialogHistoryLines = 500;
|
||||
CycleActiveHeadOnly = NO;
|
||||
CycleAllWorkspaces = NO;
|
||||
CycleIgnoreMinimized = NO;
|
||||
WindowListAppIcons = NO;
|
||||
}
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ menu.bg Bulgarian Slavei Karadjov <slaff@exco.net>
|
||||
menu.sk Slovak judas@hell <tomka@oalevice.sk>
|
||||
menu.nl Dutch Alwin <translations@ziggo.nl>
|
||||
menu.fy Frisian Alwin <translations@ziggo.nl>
|
||||
menu.sr Serbian Strahinya Radich <contact@strahinja.org>
|
||||
menu.sr Serbian Strahinya Radich <sr@strahinja.org>
|
||||
|
||||
|
||||
|
||||
@@ -81,5 +81,5 @@ plmenu.sk Slovak judas@hell <tomka@oalevice.sk>
|
||||
plmenu.ja Japanese Seiichi SATO <sato@cvs-net.co.jp>
|
||||
plmenu.nl Dutch Alwin <translations@ziggo.nl>
|
||||
plmenu.fy Frisian Alwin <translations@ziggo.nl>
|
||||
plmenu.sr Serbian Strahinya Radich <contact@strahinja.org>
|
||||
plmenu.sr Serbian Strahinya Radich <sr@strahinja.org>
|
||||
|
||||
|
||||
@@ -4,4 +4,3 @@ Comment=This session logs you into Window Maker
|
||||
Exec=wmaker
|
||||
TryExec=wmaker
|
||||
DesktopNames=WindowMaker
|
||||
X-GDM-SessionRegisters=true
|
||||
|
||||
+50
-4
@@ -71,16 +71,16 @@ dnl 6. If any interfaces have been removed or changed since the last
|
||||
dnl public release, then set age to 0.
|
||||
dnl
|
||||
dnl libwraster
|
||||
WRASTER_CURRENT=7
|
||||
WRASTER_CURRENT=8
|
||||
WRASTER_REVISION=0
|
||||
WRASTER_AGE=1
|
||||
WRASTER_AGE=2
|
||||
WRASTER_VERSION=$WRASTER_CURRENT:$WRASTER_REVISION:$WRASTER_AGE
|
||||
AC_SUBST(WRASTER_VERSION)
|
||||
dnl
|
||||
dnl libWINGs
|
||||
WINGS_CURRENT=5
|
||||
WINGS_CURRENT=6
|
||||
WINGS_REVISION=0
|
||||
WINGS_AGE=2
|
||||
WINGS_AGE=3
|
||||
WINGS_VERSION=$WINGS_CURRENT:$WINGS_REVISION:$WINGS_AGE
|
||||
AC_SUBST(WINGS_VERSION)
|
||||
dnl
|
||||
@@ -130,6 +130,20 @@ AS_IF([test "x$debug" = "xyes"],
|
||||
])
|
||||
|
||||
|
||||
dnl Native CPU Optimizations Option
|
||||
dnl =================
|
||||
m4_divert_push([INIT_PREPARE])dnl
|
||||
AC_ARG_ENABLE([native],
|
||||
[AS_HELP_STRING([--enable-native], [enable native option, @<:@default=no@:>@])],
|
||||
[AS_CASE(["$enableval"],
|
||||
[yes], [native=yes],
|
||||
[no], [native=no],
|
||||
[AC_MSG_ERROR([bad value $enableval for --enable-native])] )],
|
||||
[native=no])
|
||||
m4_divert_pop([INIT_PREPARE])dnl
|
||||
AS_IF([test "x$native" = "xyes"],
|
||||
[AX_CFLAGS_GCC_OPTION([-march=native])])
|
||||
|
||||
AX_CFLAGS_GCC_OPTION([-Wall])
|
||||
AX_CFLAGS_GCC_OPTION([-Wextra -Wno-sign-compare])
|
||||
dnl
|
||||
@@ -766,6 +780,19 @@ m4_divert_pop([INIT_PREPARE])dnl
|
||||
WM_IMGFMT_CHECK_JPEG
|
||||
|
||||
|
||||
dnl JXL Support
|
||||
dnl ============
|
||||
m4_divert_push([INIT_PREPARE])dnl
|
||||
AC_ARG_ENABLE([jxl],
|
||||
[AS_HELP_STRING([--disable-jxl], [disable JXL support through libjxl])],
|
||||
[AS_CASE(["$enableval"],
|
||||
[yes|no], [],
|
||||
[AC_MSG_ERROR([bad value $enableval for --enable-jxl])] )],
|
||||
[enable_jxl=auto])
|
||||
m4_divert_pop([INIT_PREPARE])dnl
|
||||
WM_IMGFMT_CHECK_JXL
|
||||
|
||||
|
||||
dnl GIF Support
|
||||
dnl ============
|
||||
m4_divert_push([INIT_PREPARE])dnl
|
||||
@@ -844,6 +871,22 @@ AM_CONDITIONAL([ICON_EXT_XPM], [test "x$ICONEXT" = "xxpm"])
|
||||
AM_CONDITIONAL([ICON_EXT_TIFF], [test "x$ICONEXT" = "xtiff"])
|
||||
|
||||
|
||||
dnl Archive Support for wmiv
|
||||
dnl =================================
|
||||
dnl Check for libarchive (comprehensive archive support)
|
||||
AC_CHECK_LIB([archive], [archive_read_new], [
|
||||
AC_CHECK_HEADER([archive.h], [
|
||||
AC_DEFINE([HAVE_LIBARCHIVE], [1], [Define if libarchive is available])
|
||||
LIBARCHIVE_LIBS="-larchive"
|
||||
], [
|
||||
AC_MSG_WARN([libarchive header not found, archive support disabled])
|
||||
])
|
||||
], [
|
||||
AC_MSG_WARN([libarchive not found, archive support disabled])
|
||||
])
|
||||
AC_SUBST([LIBARCHIVE_LIBS])
|
||||
|
||||
|
||||
dnl ==============================================
|
||||
dnl End of Graphic Format Libraries
|
||||
dnl ==============================================
|
||||
@@ -1008,6 +1051,9 @@ echo "Supported graphic format libraries :$supported_gfx"
|
||||
echo "Unsupported features :$unsupported"
|
||||
echo "Pango text layout support in WINGs : $pango"
|
||||
echo "Translated languages to support :$supported_locales"
|
||||
AS_IF([test "x$native" = "xyes"],
|
||||
[AS_ECHO(["Target architecture : native"]) ],
|
||||
[AS_ECHO(["Target architecture : generic"]) ])
|
||||
AS_IF([test "x$WEB_REPO_ROOT" != "x"],
|
||||
[AS_ECHO(["Git repository for WMaker's Website : $WEB_REPO_ROOT"]) ])
|
||||
AS_IF([test "x$debug" = "xyes"],
|
||||
|
||||
Vendored
+12
@@ -204,6 +204,11 @@ Note that if you don't have it, @command{configure} will issue a big warning in
|
||||
this is because JPEG images are often used in themes and for background images
|
||||
so you probably want this format supported.
|
||||
|
||||
@item @emph{libjxl} 0.7.0 or newer
|
||||
|
||||
For @emph{JXL} image support,
|
||||
@uref{https://github.com/libjxl/libjxl}
|
||||
|
||||
@item @emph{libgif} 2.2 or @emph{libungif}
|
||||
|
||||
For @emph{GIF} image support,
|
||||
@@ -477,6 +482,9 @@ Disable GIF support in @emph{WRaster} library; when enabled use @file{libgif} or
|
||||
@item --disable-jpeg
|
||||
Disable JPEG support in @emph{WRaster} library; when enabled use @file{libjpeg}.
|
||||
|
||||
@item --disable-jxl
|
||||
Disable JPEG-XL support in @emph{WRaster} library; when enabled use @file{libjxl}.
|
||||
|
||||
@item --without-libbsd
|
||||
Refuse use of the @file{libbsd} compatibility library in @emph{WINGs} utility library,
|
||||
even if your system provides it.
|
||||
@@ -643,6 +651,10 @@ appropriate requirements and works with this.
|
||||
Despite all this, if you think there's a use for it and feel in the mood to help, do not hesitate to
|
||||
discuss on the mailing list @value{emailsupport} to get it working.
|
||||
|
||||
@item --enable-native
|
||||
Enable native CPU optimizations by adding @option{-march=native} to the compiler flags, tuning the
|
||||
generated code for the build machine at the expense of portability.
|
||||
|
||||
@item --with-web-repo=@i{PATH}
|
||||
Enable generation of HTML documentation to be uploaded to @sc{Window Maker}'s website.
|
||||
The @file{@i{PATH}} is the directory where you have cloned the homepage's repository.
|
||||
|
||||
+8
-8
@@ -12,7 +12,7 @@ necessary.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
.BI \-display " host:display.screen"
|
||||
specify display to use.
|
||||
specify the display to use.
|
||||
On multiheaded machines, Window Maker will automatically manage all screens.
|
||||
If you want Window Maker to manage only a specific screen, you must supply
|
||||
the screen number you want to have managed with the
|
||||
@@ -24,13 +24,13 @@ wmaker -display :0.1
|
||||
.EE
|
||||
.TP
|
||||
.B \-\-dont\-restore
|
||||
do not restore saved session
|
||||
do not restore the saved session
|
||||
.TP
|
||||
.B \-\-global_defaults_path
|
||||
print the path where the files for the default configuration are installed and exit
|
||||
.TP
|
||||
.B \-\-help
|
||||
print the list of command line options supported, one per line, and exit
|
||||
print the list of supported command line options, one per line, and exit
|
||||
.TP
|
||||
.BI \-\-locale " locale"
|
||||
specify the locale (i18n language) to use; Window Maker will also set the variable
|
||||
@@ -38,7 +38,7 @@ specify the locale (i18n language) to use; Window Maker will also set the variab
|
||||
which will be inherited by all applications started from Window Maker
|
||||
.TP
|
||||
.B \-\-no\-autolaunch
|
||||
do not launch at start-up the applications that were marked in the configuration as autolanched
|
||||
do not launch at start-up the applications that were marked in the configuration as autolaunched
|
||||
.TP
|
||||
.B \-\-no\-clip
|
||||
do not show the workspace Clip
|
||||
@@ -53,7 +53,7 @@ disable the Drawers in the Dock
|
||||
@!HAVE_INOTIFY@disable the periodic check on the configuration file to reload it automatically
|
||||
@USE_ICCCM_WMREPLACE@.TP
|
||||
@USE_ICCCM_WMREPLACE@.B \-\-replace
|
||||
@USE_ICCCM_WMREPLACE@ask the currently running window manager to let Window Maker take his place
|
||||
@USE_ICCCM_WMREPLACE@ask the currently running window manager to let Window Maker take its place
|
||||
.TP
|
||||
.B \-\-static
|
||||
do not update or save automatically the configuration
|
||||
@@ -88,7 +88,7 @@ few options not available using the Attributes Editor.
|
||||
.B @pkgconfdir@/
|
||||
All the above-mentioned files are READ from here if not found except
|
||||
for WMState, which is COPIED from here. No matter where they are read
|
||||
from, if it's necessary to write configuration changes back into this
|
||||
from, if it's necessary to write configuration changes back into these
|
||||
files, user's files will be written to.
|
||||
.TP
|
||||
.B ~/GNUstep/Library/WindowMaker/autostart
|
||||
@@ -108,7 +108,7 @@ might be shut down before the script is executed.
|
||||
The menu file indicated in WMRootMenu is looked for here...
|
||||
.TP
|
||||
.B @pkgdatadir@/
|
||||
and here, in that order. Unless, the indicated path is an absolute path.
|
||||
and here, in that order. Unless the indicated path is an absolute path.
|
||||
.TP
|
||||
.B ~/GNUstep/Library/WindowMaker/Pixmaps/
|
||||
Window Maker looks for \fBpixmaps\fP here
|
||||
@@ -131,7 +131,7 @@ Window Maker looks for theme files here (ibid)
|
||||
System-wide (Window Maker-specific) pixmaps are located here
|
||||
.TP
|
||||
.B @pkgdatadir@/Styles/
|
||||
System wide styles are here
|
||||
System-wide styles are here
|
||||
.TP
|
||||
.B @pkgdatadir@/Themes/
|
||||
Guess... ;-)
|
||||
|
||||
+26
-17
@@ -3,11 +3,14 @@
|
||||
wmiv \- quick image viewer using wrlib
|
||||
.SH SYNOPSIS
|
||||
.B wmiv
|
||||
.RI [ \,image(s)\/ | \,directory\/ ]
|
||||
.RI [ \,image(s)\/ | \,directory\/ | \,archive\/]
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-\-help
|
||||
print help text
|
||||
display this help
|
||||
.TP
|
||||
.B \-\-ignore-unknown
|
||||
ignore unknown image format
|
||||
.TP
|
||||
.B \-\-version
|
||||
print version
|
||||
@@ -19,21 +22,6 @@ zoom in
|
||||
[\-]
|
||||
zoom out
|
||||
.TP
|
||||
[Esc]
|
||||
actual size
|
||||
.TP
|
||||
[D]
|
||||
launch diaporama mode
|
||||
.TP
|
||||
[L]
|
||||
rotate image on the left
|
||||
.TP
|
||||
[Q]
|
||||
quit
|
||||
.TP
|
||||
[R]
|
||||
rotate image on the right
|
||||
.TP
|
||||
[â–¸]
|
||||
next image
|
||||
.TP
|
||||
@@ -45,6 +33,27 @@ first image
|
||||
.TP
|
||||
[â–ľ]
|
||||
last image
|
||||
.TP
|
||||
[Ctrl+C]
|
||||
copy image to clipboard
|
||||
.TP
|
||||
[D]
|
||||
start slideshow
|
||||
.TP
|
||||
[Esc]
|
||||
actual size
|
||||
.TP
|
||||
[F]
|
||||
toggle full-screen mode
|
||||
.TP
|
||||
[L]
|
||||
rotate image on the left
|
||||
.TP
|
||||
[Q]
|
||||
quit
|
||||
.TP
|
||||
[R]
|
||||
rotate image on the right
|
||||
.SH AUTHOR
|
||||
.B wmiv
|
||||
is a part of Window Maker. It was written by David Maciejak.
|
||||
|
||||
+6
-6
@@ -37,7 +37,7 @@ AC_DEFUN_ONCE([WM_I18N_LANGUAGES],
|
||||
[AC_ARG_VAR([LINGUAS],
|
||||
[list of language translations to support (I18N), use 'list' to get the list of supported languages, default: none])dnl
|
||||
AC_DEFUN([WM_ALL_LANGUAGES],
|
||||
[m4_esyscmd([( ls wrlib/po/ ; ls WINGs/po/ ; ls po/ ; ls WPrefs.app/po/ ; ls util/po/ ) | sed -n -e '/po$/{s,\.po,,;p}' | sort -u | tr '\n' ' '])])dnl
|
||||
[m4_esyscmd([( ls wrlib/po/ ; ls WINGs/po/ ; ls po/ ; ls WPrefs.app/po/ ; ls util/po/ ) | sed -n -e '/po$/{s,\.po,,;p;}' | sort -u | tr '\n' ' '])])dnl
|
||||
dnl We 'divert' the macro to have it executed as soon as the option list have
|
||||
dnl been processed, so the list of locales will be printed after the configure
|
||||
dnl options have been parsed, but before any test have been run
|
||||
@@ -66,11 +66,11 @@ AS_IF([test "x$LINGUAS" != "x"],
|
||||
supported_locales=""
|
||||
|
||||
# This is the list of locales that our archive currently supports
|
||||
wraster_locales=" m4_esyscmd([ls wrlib/po/ | sed -n '/po$/{s,.po,,;p}' | tr '\n' ' '])"
|
||||
wings_locales=" m4_esyscmd([ls WINGs/po/ | sed -n '/po$/{s,.po,,;p}' | tr '\n' ' '])"
|
||||
wmaker_locales=" m4_esyscmd([ls po/ | sed -n '/po$/{s,.po,,;p}' | tr '\n' ' '])"
|
||||
wprefs_locales=" m4_esyscmd([ls WPrefs.app/po/ | sed -n '/po$/{s,.po,,;p}' | tr '\n' ' '])"
|
||||
util_locales=" m4_esyscmd([ls util/po/ | sed -n '/po$/{s,.po,,;p}' | tr '\n' ' '])"
|
||||
wraster_locales=" m4_esyscmd([ls wrlib/po/ | sed -n '/po$/{s,.po,,;p;}' | tr '\n' ' '])"
|
||||
wings_locales=" m4_esyscmd([ls WINGs/po/ | sed -n '/po$/{s,.po,,;p;}' | tr '\n' ' '])"
|
||||
wmaker_locales=" m4_esyscmd([ls po/ | sed -n '/po$/{s,.po,,;p;}' | tr '\n' ' '])"
|
||||
wprefs_locales=" m4_esyscmd([ls WPrefs.app/po/ | sed -n '/po$/{s,.po,,;p;}' | tr '\n' ' '])"
|
||||
util_locales=" m4_esyscmd([ls util/po/ | sed -n '/po$/{s,.po,,;p;}' | tr '\n' ' '])"
|
||||
man_locales=" m4_esyscmd([ls doc/ | grep '^[a-z][a-z]\(_[A-Z][A-Z]\)*$' | tr '\n' ' '])"
|
||||
|
||||
# If the LINGUAS is specified as a simple '*', then we enable all the languages
|
||||
|
||||
@@ -113,6 +113,37 @@ AC_DEFUN_ONCE([WM_IMGFMT_CHECK_JPEG],
|
||||
]) dnl AC_DEFUN
|
||||
|
||||
|
||||
# WM_IMGFMT_CHECK_JXL
|
||||
# -------------------
|
||||
#
|
||||
# Check for JXL (JPEG XL) file support through 'libjxl'
|
||||
# The check depends on variable 'enable_jxl' being either:
|
||||
# yes - detect, fail if not found
|
||||
# no - do not detect, disable support
|
||||
# auto - detect, disable if not found
|
||||
#
|
||||
# When found, append appropriate stuff in GFXLIBS, and append info to
|
||||
# the variable 'supported_gfx'
|
||||
# When not found, append info to variable 'unsupported'
|
||||
AC_DEFUN_ONCE([WM_IMGFMT_CHECK_JXL],
|
||||
[WM_LIB_CHECK([JXL], [-ljxl], [JxlDecoderCreate], [$XLFLAGS $XLIBS],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[@%:@include <stdlib.h>
|
||||
@%:@include <jxl/decode.h>],
|
||||
[ JxlDecoder* dec = JxlDecoderCreate(NULL);
|
||||
JxlDecoderDestroy(dec);])],
|
||||
[],
|
||||
[AS_ECHO([failed])
|
||||
AS_ECHO(["$as_me: error: found $CACHEVAR but cannot compile header"])
|
||||
AS_ECHO(["$as_me: error: - does header 'jxl/decode.h' exists? (is package 'libjxl-dev' missing?)"])
|
||||
AS_ECHO(["$as_me: error: - version of header is not supported? (report to dev team)"])
|
||||
AC_MSG_ERROR([JXL library is not usable, cannot continue])])
|
||||
],
|
||||
[supported_gfx], [GFXLIBS])dnl
|
||||
]) dnl AC_DEFUN
|
||||
|
||||
|
||||
# WM_IMGFMT_CHECK_PNG
|
||||
# -------------------
|
||||
#
|
||||
|
||||
@@ -45,7 +45,7 @@ bs.po Bosnian Ahmet Mulalic <am@lugzdk.ba>
|
||||
hy.po Armenian Norayr Chilignaryan <chnorik@gmail.com>
|
||||
nl.po Dutch Alwin <translations@ziggo.nl>
|
||||
fy.po Frisian Alwin <translations@ziggo.nl>
|
||||
sr.po Serbian Strahinya Radich <contact@strahinja.org>
|
||||
sr.po Serbian Strahinya Radich <sr@strahinja.org>
|
||||
|
||||
|
||||
Some translations are based on previous translations by other people.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# 1998-2006 Dan Pascu
|
||||
# 2013-2020 Window Maker Developers Team
|
||||
# This file is distributed under the same license as the Window Maker package.
|
||||
# Strahinya Radich (Страхиња Радић) <contact@strahinja.org>, 2023.
|
||||
# Strahinya Radich (Страхиња Радић) <sr@strahinja.org>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -11,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: wmaker-dev@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2023-11-02 19:22+0100\n"
|
||||
"PO-Revision-Date: 2023-11-02 19:51+0100\n"
|
||||
"Last-Translator: Страхиња Радић <contact@strahinja.org>\n"
|
||||
"Last-Translator: Страхиња Радић <sr@strahinja.org>\n"
|
||||
"Language-Team: Serbian <sr@li.org>\n"
|
||||
"Language: sr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+2
-2
@@ -454,6 +454,7 @@ extern struct WPreferences {
|
||||
char single_click; /* single click to lauch applications */
|
||||
int history_lines; /* history of "Run..." dialog */
|
||||
char cycle_active_head_only; /* Cycle only windows on the active head */
|
||||
char cycle_all_workspaces; /* Cycle all windows from all workspaces */
|
||||
char cycle_ignore_minimized; /* Ignore minimized windows when cycling */
|
||||
char double_click_fullscreen; /* Double click on titlebar maximize a window to full screen*/
|
||||
char close_rootmenu_left_right_click;/* Close application menu when mouse (left or right) is clicked outside focus */
|
||||
@@ -478,6 +479,7 @@ extern struct WPreferences {
|
||||
int hot_corner_delay; /* Delay after which the hot corner is triggered */
|
||||
int hot_corner_edge; /* Hot corner edge size */
|
||||
char *hot_corner_actions[4]; /* Action of each corner */
|
||||
char window_list_app_icons; /* Show app icons in window list */
|
||||
|
||||
struct {
|
||||
#ifdef USE_ICCCM_WMREPLACE
|
||||
@@ -618,12 +620,10 @@ extern struct wmaker_global_variables {
|
||||
} shape;
|
||||
#endif
|
||||
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
struct {
|
||||
Bool supported;
|
||||
int event_base;
|
||||
} xkb;
|
||||
#endif
|
||||
|
||||
#ifdef USE_RANDR
|
||||
struct {
|
||||
|
||||
+9
-6
@@ -1186,14 +1186,17 @@ static void create_appicon_from_dock(WWindow *wwin, WApplication *wapp, Window m
|
||||
|
||||
wapp->app_icon->running = 1;
|
||||
wapp->app_icon->icon->owner = mainw;
|
||||
if (mainw->wm_hints && (mainw->wm_hints->flags & IconWindowHint))
|
||||
wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
|
||||
|
||||
/* Update the icon images */
|
||||
wIconUpdate(wapp->app_icon->icon);
|
||||
if (!WFLAGP(wwin, always_user_icon)) {
|
||||
if (mainw->wm_hints && (mainw->wm_hints->flags & IconWindowHint))
|
||||
wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
|
||||
|
||||
/* Paint it */
|
||||
wAppIconPaint(wapp->app_icon);
|
||||
/* Update the icon images */
|
||||
wIconUpdate(wapp->app_icon->icon);
|
||||
|
||||
/* Paint it */
|
||||
wAppIconPaint(wapp->app_icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-8
@@ -245,6 +245,20 @@ void wClientConfigure(WWindow * wwin, XConfigureRequestEvent * xcre)
|
||||
wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS | MAX_CENTRAL);
|
||||
|
||||
wWindowConstrainSize(wwin, (unsigned int *)&nwidth, (unsigned int *)&nheight);
|
||||
|
||||
/* Ignore tiny position adjustments from client ConfigureRequests to prevent
|
||||
* window jitters (e.g., VirtualBox sending incremental 1-2px corrections). */
|
||||
if (wwin->flags.mapped && !wwin->moveresize.active && (xcre->value_mask & (CWX | CWY))) {
|
||||
int dx = abs(nx - wwin->frame_x);
|
||||
int dy = abs(ny - wwin->frame_y);
|
||||
|
||||
if (dx < 3 && dy < 3) {
|
||||
/* Keep current position */
|
||||
nx = wwin->frame_x;
|
||||
ny = wwin->frame_y;
|
||||
}
|
||||
}
|
||||
|
||||
wWindowConfigure(wwin, nx, ny, nwidth, nheight);
|
||||
wwin->old_geometry.x = nx;
|
||||
wwin->old_geometry.y = ny;
|
||||
@@ -454,15 +468,16 @@ void wClientCheckProperty(WWindow * wwin, XPropertyEvent * event)
|
||||
/* update icon */
|
||||
if ((wwin->wm_hints->flags & IconPixmapHint)
|
||||
|| (wwin->wm_hints->flags & IconWindowHint)) {
|
||||
WApplication *wapp;
|
||||
if (!WFLAGP(wwin, always_user_icon)) {
|
||||
WApplication *wapp;
|
||||
if (wwin->flags.miniaturized && wwin->icon)
|
||||
wIconUpdate(wwin->icon);
|
||||
|
||||
if (wwin->flags.miniaturized && wwin->icon)
|
||||
wIconUpdate(wwin->icon);
|
||||
|
||||
wapp = wApplicationOf(wwin->main_window);
|
||||
if (wapp && wapp->app_icon) {
|
||||
wIconUpdate(wapp->app_icon->icon);
|
||||
wAppIconPaint(wapp->app_icon);
|
||||
wapp = wApplicationOf(wwin->main_window);
|
||||
if (wapp && wapp->app_icon) {
|
||||
wIconUpdate(wapp->app_icon->icon);
|
||||
wAppIconPaint(wapp->app_icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,6 +534,8 @@ WDefaultEntry optionList[] = {
|
||||
&wPreferences.hot_corner_edge, getInt, NULL, NULL, NULL},
|
||||
{"HotCornerActions", "(\"None\", \"None\", \"None\", \"None\")", &wPreferences,
|
||||
NULL, getPropList, setHotCornerActions, NULL, NULL},
|
||||
{"WindowListAppIcons", "NO", NULL,
|
||||
&wPreferences.window_list_app_icons, getBool, NULL, NULL, NULL},
|
||||
|
||||
/* style options */
|
||||
|
||||
@@ -849,6 +851,8 @@ WDefaultEntry optionList[] = {
|
||||
&wPreferences.history_lines, getInt, NULL, NULL, NULL},
|
||||
{"CycleActiveHeadOnly", "NO", NULL,
|
||||
&wPreferences.cycle_active_head_only, getBool, NULL, NULL, NULL},
|
||||
{"CycleAllWorkspaces", "NO", NULL,
|
||||
&wPreferences.cycle_all_workspaces, getBool, NULL, NULL, NULL},
|
||||
{"CycleIgnoreMinimized", "NO", NULL,
|
||||
&wPreferences.cycle_ignore_minimized, getBool, NULL, NULL, NULL},
|
||||
{"DbClickFullScreen", "NO", NULL,
|
||||
@@ -1301,6 +1305,29 @@ void wReadDefaults(WScreen * scr, WMPropList * new_dict)
|
||||
}
|
||||
}
|
||||
|
||||
void wReadKeybindings(WScreen *scr, WMPropList *dict)
|
||||
{
|
||||
WDefaultEntry *entry;
|
||||
unsigned int i;
|
||||
void *tdata;
|
||||
|
||||
for (i = 0; i < wlengthof(optionList); i++) {
|
||||
entry = &optionList[i];
|
||||
if (entry->convert == getKeybind) {
|
||||
WMPropList *plvalue = NULL;
|
||||
if (dict)
|
||||
plvalue = WMGetFromPLDictionary(dict, entry->plkey);
|
||||
if (!plvalue)
|
||||
plvalue = entry->plvalue;
|
||||
if (plvalue) {
|
||||
int ok = (*entry->convert)(scr, entry, plvalue, entry->addr, &tdata);
|
||||
if (ok && entry->update)
|
||||
(*entry->update)(scr, entry, tdata, entry->extra_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wDefaultUpdateIcons(WScreen *scr)
|
||||
{
|
||||
WAppIcon *aicon = scr->app_icon_list;
|
||||
|
||||
@@ -33,6 +33,7 @@ WDDomain * wDefaultsInitDomain(const char *domain, Bool requireDictionary);
|
||||
void wDefaultsMergeGlobalMenus(WDDomain *menuDomain);
|
||||
|
||||
void wReadDefaults(WScreen *scr, WMPropList *new_dict);
|
||||
void wReadKeybindings(WScreen *scr, WMPropList *dict);
|
||||
void wDefaultUpdateIcons(WScreen *scr);
|
||||
void wReadStaticDefaults(WMPropList *dict);
|
||||
void wDefaultsCheckDomains(void *arg);
|
||||
|
||||
+22
-6
@@ -1083,6 +1083,7 @@ Bool wIconChooserDialog(WScreen *scr, char **file, const char *instance, const c
|
||||
WMMapWidget(panel->win);
|
||||
|
||||
wWindowMap(wwin);
|
||||
wSetFocusTo(scr, wwin);
|
||||
|
||||
while (!panel->done) {
|
||||
XEvent event;
|
||||
@@ -1276,9 +1277,9 @@ void wShowInfoPanel(WScreen *scr)
|
||||
panel->win = WMCreateWindow(scr->wmscreen, "info");
|
||||
WMGetScaleBaseFromSystemFont(scr->wmscreen, &wmScaleWidth, &wmScaleHeight);
|
||||
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2) && defined(DEBUG)
|
||||
pwidth = WMScaleX(412);
|
||||
pwidth = WMScaleX(432);
|
||||
#else
|
||||
pwidth = WMScaleX(382);
|
||||
pwidth = WMScaleX(392);
|
||||
#endif
|
||||
pheight = WMScaleY(270);
|
||||
WMResizeWidget(panel->win, pwidth, pheight);
|
||||
@@ -1344,7 +1345,7 @@ void wShowInfoPanel(WScreen *scr)
|
||||
|
||||
panel->copyrL = WMCreateLabel(panel->win);
|
||||
WMResizeWidget(panel->copyrL, WMScaleX(360), WMScaleY(60));
|
||||
WMMoveWidget(panel->copyrL, WMScaleX(15), WMScaleY(210));
|
||||
WMMoveWidget(panel->copyrL, WMScaleX(15), WMScaleY(215));
|
||||
WMSetLabelTextAlignment(panel->copyrL, WALeft);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), COPYRIGHT_TEXT, current_year);
|
||||
@@ -1455,7 +1456,7 @@ void wShowInfoPanel(WScreen *scr)
|
||||
strbuf = wstrappend(strbuf, _("Xinerama: "));
|
||||
{
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof(tmp) - 1, _("%d head(s) found"), scr->xine_info.count);
|
||||
snprintf(tmp, sizeof(tmp) - 1, scr->xine_info.count > 1 ? _("%d head(s) found") : _("%d head found"), scr->xine_info.count);
|
||||
strbuf = wstrappend(strbuf, tmp);
|
||||
}
|
||||
#endif
|
||||
@@ -1471,9 +1472,9 @@ void wShowInfoPanel(WScreen *scr)
|
||||
|
||||
panel->infoL = WMCreateLabel(panel->win);
|
||||
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2) && defined(DEBUG)
|
||||
WMResizeWidget(panel->infoL, WMScaleX(380), WMScaleY(100));
|
||||
WMResizeWidget(panel->infoL, WMScaleX(430), WMScaleY(105));
|
||||
#else
|
||||
WMResizeWidget(panel->infoL, WMScaleX(350), WMScaleY(100));
|
||||
WMResizeWidget(panel->infoL, WMScaleX(370), WMScaleY(105));
|
||||
#endif
|
||||
WMMoveWidget(panel->infoL, WMScaleX(15), WMScaleY(115));
|
||||
WMSetLabelText(panel->infoL, strbuf);
|
||||
@@ -1641,6 +1642,8 @@ typedef struct _CrashPanel {
|
||||
int action; /* what to do after */
|
||||
|
||||
KeyCode retKey;
|
||||
KeyCode upKey;
|
||||
KeyCode downKey;
|
||||
|
||||
} CrashPanel;
|
||||
|
||||
@@ -1650,6 +1653,17 @@ static void handleKeyPress(XEvent * event, void *clientData)
|
||||
|
||||
if (event->xkey.keycode == panel->retKey) {
|
||||
WMPerformButtonClick(panel->okB);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->xkey.keycode == panel->upKey) {
|
||||
WMSelectPopUpButtonPreviousItem(panel->whatP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->xkey.keycode == panel->downKey) {
|
||||
WMSelectPopUpButtonNextItem(panel->whatP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1721,6 +1735,8 @@ int wShowCrashingDialogPanel(int whatSig)
|
||||
panel = wmalloc(sizeof(CrashPanel));
|
||||
|
||||
panel->retKey = XKeysymToKeycode(dpy, XK_Return);
|
||||
panel->upKey = XKeysymToKeycode(dpy, XK_Up);
|
||||
panel->downKey = XKeysymToKeycode(dpy, XK_Down);
|
||||
|
||||
panel->win = WMCreateWindow(scr, "crashingDialog");
|
||||
WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
|
||||
|
||||
+41
-10
@@ -49,9 +49,7 @@
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
#include <X11/XKBlib.h>
|
||||
#endif /* KEEP_XKB_LOCK_STATUS */
|
||||
|
||||
#include "WindowMaker.h"
|
||||
#include "window.h"
|
||||
@@ -103,7 +101,9 @@ static void handleKeyPress(XEvent *event);
|
||||
static void handleFocusIn(XEvent *event);
|
||||
static void handleMotionNotify(XEvent *event);
|
||||
static void handleVisibilityNotify(XEvent *event);
|
||||
#ifdef HAVE_INOTIFY
|
||||
static void handle_inotify_events(void);
|
||||
#endif
|
||||
static void handle_selection_request(XSelectionRequestEvent *event);
|
||||
static void handle_selection_clear(XSelectionClearEvent *event);
|
||||
static void wdelete_death_handler(WMagicNumber id);
|
||||
@@ -569,11 +569,26 @@ static void handleExtensions(XEvent * event)
|
||||
handleShapeNotify(event);
|
||||
}
|
||||
#endif
|
||||
if (w_global.xext.xkb.supported && event->type == w_global.xext.xkb.event_base) {
|
||||
XkbEvent *xkbevent = (XkbEvent *) event;
|
||||
|
||||
if (xkbevent->any.xkb_type == XkbNewKeyboardNotify) {
|
||||
int j;
|
||||
WScreen *scr;
|
||||
|
||||
for (j = 0; j < w_global.screen_count; j++) {
|
||||
scr = wScreenWithNumber(j);
|
||||
wReadKeybindings(scr, w_global.domain.wmaker->dictionary);
|
||||
}
|
||||
}
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
if (wPreferences.modelock && (event->type == w_global.xext.xkb.event_base)) {
|
||||
handleXkbIndicatorStateNotify((XkbEvent *) event);
|
||||
else {
|
||||
if (wPreferences.modelock && (xkbevent->any.xkb_type == XkbIndicatorStateNotify)) {
|
||||
handleXkbIndicatorStateNotify((XkbEvent *) event);
|
||||
}
|
||||
}
|
||||
#endif /*KEEP_XKB_LOCK_STATUS */
|
||||
}
|
||||
#endif /*KEEP_XKB_LOCK_STATUS */
|
||||
#ifdef USE_RANDR
|
||||
if (w_global.xext.randr.supported && event->type == (w_global.xext.randr.event_base + RRScreenChangeNotify)) {
|
||||
/* From xrandr man page: "Clients must call back into Xlib using
|
||||
@@ -1275,6 +1290,7 @@ static void handleXkbIndicatorStateNotify(XkbEvent *event)
|
||||
WScreen *scr;
|
||||
XkbStateRec staterec;
|
||||
int i;
|
||||
(void) event;
|
||||
|
||||
for (i = 0; i < w_global.screen_count; i++) {
|
||||
scr = wScreenWithNumber(i);
|
||||
@@ -1942,16 +1958,31 @@ static void handleKeyPress(XEvent * event)
|
||||
#define CORNER_BOTTOMLEFT 3
|
||||
#define CORNER_BOTTOMRIGHT 4
|
||||
|
||||
static int get_corner(WMRect rect, WMPoint p)
|
||||
static inline int get_corner(WMRect rect, WMPoint p)
|
||||
{
|
||||
if (p.x <= (rect.pos.x + wPreferences.hot_corner_edge) && p.y <= (rect.pos.y + wPreferences.hot_corner_edge))
|
||||
const int edge = wPreferences.hot_corner_edge;
|
||||
const int left_edge = rect.pos.x + edge;
|
||||
const int right_edge = rect.pos.x + rect.size.width - edge;
|
||||
const int top_edge = rect.pos.y + edge;
|
||||
const int bottom_edge = rect.pos.y + rect.size.height - edge;
|
||||
|
||||
int in_left = (p.x <= left_edge);
|
||||
int in_right = (p.x >= right_edge);
|
||||
int in_top = (p.y <= top_edge);
|
||||
int in_bottom = (p.y >= bottom_edge);
|
||||
|
||||
if (!(in_left || in_right) || !(in_top || in_bottom))
|
||||
return CORNER_NONE;
|
||||
|
||||
if (in_left && in_top)
|
||||
return CORNER_TOPLEFT;
|
||||
if (p.x >= (rect.pos.x + rect.size.width - wPreferences.hot_corner_edge) && p.y <= (rect.pos.y + wPreferences.hot_corner_edge))
|
||||
if (in_right && in_top)
|
||||
return CORNER_TOPRIGHT;
|
||||
if (p.x <= (rect.pos.x + wPreferences.hot_corner_edge) && p.y >= (rect.pos.y + rect.size.height - wPreferences.hot_corner_edge))
|
||||
if (in_left && in_bottom)
|
||||
return CORNER_BOTTOMLEFT;
|
||||
if (p.x >= (rect.pos.x + rect.size.width - wPreferences.hot_corner_edge) && p.y >= (rect.pos.y + rect.size.height - wPreferences.hot_corner_edge))
|
||||
if (in_right && in_bottom)
|
||||
return CORNER_BOTTOMRIGHT;
|
||||
|
||||
return CORNER_NONE;
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -58,14 +58,14 @@ static void paintButton(WCoreWindow * button, WTexture * texture,
|
||||
|
||||
static void updateTitlebar(WFrameWindow * fwin);
|
||||
|
||||
static void allocFrameBorderPixel(Colormap colormap, const char *color_name, unsigned long **pixel);
|
||||
static void allocFrameBorderPixel(WFrameWindow *fwin, const char *color_name, unsigned long **pixel);
|
||||
|
||||
static void allocFrameBorderPixel(Colormap colormap, const char *color_name, unsigned long **pixel) {
|
||||
static void allocFrameBorderPixel(WFrameWindow *fwin, const char *color_name, unsigned long **pixel) {
|
||||
XColor xcol;
|
||||
|
||||
*pixel = NULL;
|
||||
|
||||
if (! wGetColorForColormap(colormap, color_name, &xcol))
|
||||
if (! wGetColorForColormap(fwin->screen_ptr, fwin->colormap, color_name, &xcol))
|
||||
return;
|
||||
|
||||
*pixel = wmalloc(sizeof(unsigned long));
|
||||
@@ -412,9 +412,9 @@ void wFrameWindowUpdateBorders(WFrameWindow * fwin, int flags)
|
||||
|
||||
checkTitleSize(fwin);
|
||||
|
||||
allocFrameBorderPixel(fwin->colormap, WMGetColorRGBDescription(scr->frame_border_color), &fwin->border_pixel);
|
||||
allocFrameBorderPixel(fwin->colormap, WMGetColorRGBDescription(scr->frame_focused_border_color), &fwin->focused_border_pixel);
|
||||
allocFrameBorderPixel(fwin->colormap, WMGetColorRGBDescription(scr->frame_selected_border_color), &fwin->selected_border_pixel);
|
||||
allocFrameBorderPixel(fwin, WMGetColorRGBDescription(scr->frame_border_color), &fwin->border_pixel);
|
||||
allocFrameBorderPixel(fwin, WMGetColorRGBDescription(scr->frame_focused_border_color), &fwin->focused_border_pixel);
|
||||
allocFrameBorderPixel(fwin, WMGetColorRGBDescription(scr->frame_selected_border_color), &fwin->selected_border_pixel);
|
||||
|
||||
if (flags & WFF_SELECTED) {
|
||||
if (fwin->selected_border_pixel)
|
||||
@@ -1394,7 +1394,7 @@ static void handleButtonExpose(WObjDescriptor * desc, XEvent * event)
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (button == fwin->language_button) {
|
||||
if (wPreferences.modelock)
|
||||
if (!fwin->flags.hide_language_button)
|
||||
paintButton(button, fwin->title_texture[fwin->flags.state],
|
||||
WMColorPixel(fwin->title_color[fwin->flags.state]),
|
||||
fwin->languagebutton_image, False);
|
||||
|
||||
@@ -331,6 +331,14 @@ void wIconChangeTitle(WIcon *icon, WWindow *wwin)
|
||||
/* Set the new one, using two methods to identify
|
||||
the icon name or switch back to window name */
|
||||
icon->icon_name = wNETWMGetIconName(wwin->client_win);
|
||||
if (icon->icon_name) {
|
||||
/* treat empty string as unset */
|
||||
if (icon->icon_name[0] == '\0') {
|
||||
XFree(icon->icon_name);
|
||||
icon->icon_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!icon->icon_name)
|
||||
if (!wGetIconName(dpy, wwin->client_win, &icon->icon_name))
|
||||
icon->icon_name = wNETWMGetWindowName(wwin->client_win);
|
||||
|
||||
+6
-4
@@ -326,7 +326,8 @@ void ExecuteShellCommand(WScreen *scr, const char *command)
|
||||
#endif
|
||||
execl(shell, shell, "-c", command, NULL);
|
||||
werror("could not execute %s -c %s", shell, command);
|
||||
Exit(-1);
|
||||
/* exec failed in child -- exit immediately without running parent cleanup */
|
||||
_exit(127);
|
||||
} else if (pid < 0) {
|
||||
werror("cannot fork a new process");
|
||||
} else {
|
||||
@@ -377,10 +378,10 @@ Bool RelaunchWindow(WWindow *wwin)
|
||||
setsid();
|
||||
#endif
|
||||
/* argv is not null-terminated */
|
||||
char **a = (char **) malloc(argc + 1);
|
||||
char **a = malloc((argc + 1) * sizeof(char *));
|
||||
if (! a) {
|
||||
werror("out of memory trying to relaunch the application");
|
||||
Exit(-1);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
int i;
|
||||
@@ -389,7 +390,8 @@ Bool RelaunchWindow(WWindow *wwin)
|
||||
a[i] = NULL;
|
||||
|
||||
execvp(a[0], a);
|
||||
Exit(-1);
|
||||
/* exec failed in child -- exit immediately */
|
||||
_exit(127);
|
||||
} else if (pid < 0) {
|
||||
werror("cannot fork a new process");
|
||||
|
||||
|
||||
+31
@@ -267,6 +267,7 @@ WMenuEntry *wMenuInsertCallback(WMenu *menu, int index, const char *text,
|
||||
entry = wmalloc(sizeof(WMenuEntry));
|
||||
entry->flags.enabled = 1;
|
||||
entry->text = wstrdup(text);
|
||||
entry->icon = NULL;
|
||||
entry->cascade = -1;
|
||||
entry->clientdata = clientdata;
|
||||
entry->callback = callback;
|
||||
@@ -369,6 +370,9 @@ void wMenuRemoveItem(WMenu * menu, int index)
|
||||
if (menu->entries[index]->text)
|
||||
wfree(menu->entries[index]->text);
|
||||
|
||||
if (menu->entries[index]->icon)
|
||||
wPixmapDestroy(menu->entries[index]->icon);
|
||||
|
||||
if (menu->entries[index]->rtext)
|
||||
wfree(menu->entries[index]->rtext);
|
||||
|
||||
@@ -499,6 +503,10 @@ void wMenuRealize(WMenu * menu)
|
||||
text = menu->entries[i]->text;
|
||||
width = WMWidthOfString(scr->menu_entry_font, text, strlen(text)) + 10;
|
||||
|
||||
if (wPreferences.window_list_app_icons && menu->entries[i]->icon) {
|
||||
width += menu->entries[i]->icon->width + 4;
|
||||
}
|
||||
|
||||
if (menu->entries[i]->flags.indicator) {
|
||||
width += MENU_INDICATOR_SPACE;
|
||||
}
|
||||
@@ -562,6 +570,9 @@ void wMenuDestroy(WMenu * menu, int recurse)
|
||||
|
||||
wfree(menu->entries[i]->text);
|
||||
|
||||
if (menu->entries[i]->icon)
|
||||
wPixmapDestroy(menu->entries[i]->icon);
|
||||
|
||||
if (menu->entries[i]->rtext)
|
||||
wfree(menu->entries[i]->rtext);
|
||||
#ifdef USER_MENU
|
||||
@@ -711,6 +722,26 @@ static void paintEntry(WMenu * menu, int index, int selected)
|
||||
if (entry->flags.indicator)
|
||||
x += MENU_INDICATOR_SPACE + 2;
|
||||
|
||||
if (wPreferences.window_list_app_icons && entry->icon && entry->icon->image != None) {
|
||||
int ix = x;
|
||||
int iy = y + (h - entry->icon->height) / 2;
|
||||
|
||||
if (entry->icon->mask != None) {
|
||||
XSetClipMask(dpy, scr->copy_gc, entry->icon->mask);
|
||||
XSetClipOrigin(dpy, scr->copy_gc, ix, iy);
|
||||
} else {
|
||||
XSetClipMask(dpy, scr->copy_gc, None);
|
||||
XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
|
||||
}
|
||||
|
||||
XCopyArea(dpy, entry->icon->image, win, scr->copy_gc,
|
||||
0, 0, entry->icon->width, entry->icon->height, ix, iy);
|
||||
XSetClipMask(dpy, scr->copy_gc, None);
|
||||
XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
|
||||
|
||||
x += entry->icon->width + 4;
|
||||
}
|
||||
|
||||
WMDrawString(scr->wmscreen, win, color, scr->menu_entry_font,
|
||||
x, 3 + y + wPreferences.menu_text_clearance, entry->text, strlen(entry->text));
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ typedef struct WMenuEntry {
|
||||
int order;
|
||||
char *text; /* entry text */
|
||||
char *rtext; /* text to show in the right part */
|
||||
struct WPixmap *icon; /* optional icon displayed before the text */
|
||||
void (*callback)(struct WMenu *menu, struct WMenuEntry *entry);
|
||||
void (*free_cdata)(void *data); /* proc to be used to free clientdata */
|
||||
void *clientdata; /* data to pass to callback */
|
||||
|
||||
+71
-8
@@ -124,6 +124,44 @@ Bool wGetIconName(Display *dpy, Window win, char **iconname)
|
||||
return False;
|
||||
}
|
||||
|
||||
int WMStrEqual(const char *x, const char *y)
|
||||
{
|
||||
if ((x == NULL) && (y == NULL))
|
||||
return 1;
|
||||
|
||||
if ((x == NULL) || (y == NULL))
|
||||
return 0;
|
||||
|
||||
return (strcmp(x, y) == 0);
|
||||
}
|
||||
|
||||
int WMPLGetBool(WMPropList *value)
|
||||
{
|
||||
char *val;
|
||||
|
||||
if (!WMIsPLString(value))
|
||||
return 0;
|
||||
|
||||
val = WMGetFromPLString(value);
|
||||
if (val == NULL)
|
||||
return 0;
|
||||
|
||||
if ((val[1] == '\0' &&
|
||||
(val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' ||
|
||||
val[0] == 't' || val[0] == '1')) ||
|
||||
(strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
|
||||
return 1;
|
||||
} else if ((val[1] == '\0' &&
|
||||
(val[0] == 'n' || val[0] == 'N' || val[0] == 'F' ||
|
||||
val[0] == 'f' || val[0] == '0')) ||
|
||||
(strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
wwarning(_("can't convert \"%s\" to boolean"), val);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void eatExpose(void)
|
||||
{
|
||||
XEvent event, foo;
|
||||
@@ -259,13 +297,22 @@ void slide_windows(Window wins[], int n, int from_x, int from_y, int to_x, int t
|
||||
eatExpose();
|
||||
}
|
||||
|
||||
/* find the start of a UTF-8 character at or before the given position */
|
||||
static int utf8_find_char_start(const char *string, int pos)
|
||||
{
|
||||
while (pos > 0 && (string[pos] & 0xC0) == 0x80) {
|
||||
pos--;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
char *ShrinkString(WMFont *font, const char *string, int width)
|
||||
{
|
||||
int w, w1 = 0;
|
||||
int p;
|
||||
char *pos;
|
||||
char *text;
|
||||
int p1, p2, t;
|
||||
int p1, p2, t, utf8_safe_pos;
|
||||
|
||||
p = strlen(string);
|
||||
w = WMWidthOfString(font, string, p);
|
||||
@@ -302,18 +349,34 @@ char *ShrinkString(WMFont *font, const char *string, int width)
|
||||
p1 = 0;
|
||||
p2 = p;
|
||||
t = (p2 - p1) / 2;
|
||||
while (p2 > p1 && p1 != t) {
|
||||
w = WMWidthOfString(font, &string[p - t], t);
|
||||
while (p2 > p1) {
|
||||
int old_t = t;
|
||||
/* ensure we cut at UTF-8 character boundary */
|
||||
utf8_safe_pos = utf8_find_char_start(string, p - t);
|
||||
t = p - utf8_safe_pos;
|
||||
|
||||
w = WMWidthOfString(font, &string[utf8_safe_pos], t);
|
||||
if (w > width) {
|
||||
p2 = t;
|
||||
t = p1 + (p2 - p1) / 2;
|
||||
} else if (w < width) {
|
||||
p1 = t;
|
||||
t = p1 + (p2 - p1) / 2;
|
||||
} else
|
||||
p2 = p1 = t;
|
||||
} else {
|
||||
p1 = t;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculate new t for next iteration */
|
||||
t = p1 + (p2 - p1) / 2;
|
||||
|
||||
/* Prevent infinite loop if we're not making progress */
|
||||
if (t == old_t || (p2 - p1) <= 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
strcat(text, &string[p - p1]);
|
||||
|
||||
/* ensure final cut is at UTF-8 character boundary */
|
||||
utf8_safe_pos = utf8_find_char_start(string, p - p1);
|
||||
strcat(text, &string[utf8_safe_pos]);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -54,4 +54,6 @@ char *GetShortcutKey(WShortKey key);
|
||||
char *EscapeWM_CLASS(const char *name, const char *class);
|
||||
char *StrConcatDot(const char *a, const char *b);
|
||||
char *GetCommandForWindow(Window win);
|
||||
int WMStrEqual(const char *x, const char *y);
|
||||
int WMPLGetBool(WMPropList *value);
|
||||
#endif
|
||||
|
||||
+42
-4
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "wconfig.h"
|
||||
#include "wmspec.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
@@ -1916,7 +1917,7 @@ int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
if (event.xbutton.button != ev->xbutton.button)
|
||||
if (!wwin->moveresize.active && (event.xbutton.button != ev->xbutton.button))
|
||||
break;
|
||||
|
||||
if (started) {
|
||||
@@ -1964,6 +1965,10 @@ int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
|
||||
WMUnmapWidget(scr->gview);
|
||||
}
|
||||
}
|
||||
if (wwin->moveresize.active) {
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
wwin->moveresize.active = 0;
|
||||
}
|
||||
done = True;
|
||||
break;
|
||||
|
||||
@@ -2101,8 +2106,13 @@ void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
|
||||
wwarning("internal error: tryein");
|
||||
return;
|
||||
}
|
||||
orig_x = ev->xbutton.x_root;
|
||||
orig_y = ev->xbutton.y_root;
|
||||
if (ev->type == MotionNotify) {
|
||||
orig_x = ev->xmotion.x_root;
|
||||
orig_y = ev->xmotion.y_root;
|
||||
} else {
|
||||
orig_x = ev->xbutton.x_root;
|
||||
orig_y = ev->xbutton.y_root;
|
||||
}
|
||||
|
||||
started = 0;
|
||||
wUnselectWindows(scr);
|
||||
@@ -2113,6 +2123,29 @@ void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
|
||||
shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
|
||||
shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
|
||||
|
||||
if (wwin->moveresize.active) {
|
||||
int direction = wwin->moveresize.resize_edge;
|
||||
|
||||
res = 0;
|
||||
is_resizebar = 0;
|
||||
if (direction == _NET_WM_MOVERESIZE_SIZE_TOP)
|
||||
res |= UP;
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_BOTTOM)
|
||||
res |= DOWN;
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_LEFT)
|
||||
res |= LEFT;
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_RIGHT)
|
||||
res |= RIGHT;
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_TOPLEFT)
|
||||
res |= (UP | LEFT);
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_TOPRIGHT)
|
||||
res |= (UP | RIGHT);
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)
|
||||
res |= (DOWN | LEFT);
|
||||
else if (direction == _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT)
|
||||
res |= (DOWN | RIGHT);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
|
||||
| ButtonReleaseMask | PointerMotionHintMask | ButtonPressMask | ExposureMask, &event);
|
||||
@@ -2269,7 +2302,7 @@ void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
if (event.xbutton.button != ev->xbutton.button)
|
||||
if (!wwin->moveresize.active && (event.xbutton.button != ev->xbutton.button))
|
||||
break;
|
||||
|
||||
if (started) {
|
||||
@@ -2291,6 +2324,11 @@ void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
|
||||
wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
|
||||
wWindowSynthConfigureNotify(wwin);
|
||||
}
|
||||
if (wwin->moveresize.active) {
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
wwin->moveresize.active = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
|
||||
+2
-2
@@ -197,8 +197,8 @@ void PropSetIconTileHint(WScreen * scr, RImage * image)
|
||||
if (image->format == RRGBAFormat) {
|
||||
memcpy(&tmp[4], image->data, image->width * image->height * 4);
|
||||
} else {
|
||||
char *ptr = (char *)(tmp + 4);
|
||||
char *src = (char *)image->data;
|
||||
unsigned char *ptr = tmp + 4;
|
||||
unsigned char *src = (unsigned char *)image->data;
|
||||
|
||||
for (y = 0; y < image->height; y++) {
|
||||
for (x = 0; x < image->width; x++) {
|
||||
|
||||
+13
-2
@@ -35,8 +35,16 @@
|
||||
#include "resources.h"
|
||||
#include "screen.h"
|
||||
|
||||
int wGetColorForColormap(Colormap colormap, const char *color_name, XColor *color)
|
||||
int wGetColorForColormap(WScreen *scr, Colormap colormap, const char *color_name, XColor *color)
|
||||
{
|
||||
if (scr->w_visual->class == TrueColor) {
|
||||
XColor dummy_exact;
|
||||
if (!XLookupColor(dpy, colormap, color_name, &dummy_exact, color)) {
|
||||
wwarning(_("could not lookup color \"%s\""), color_name);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
if (!XParseColor(dpy, colormap, color_name, color)) {
|
||||
wwarning(_("could not parse color \"%s\""), color_name);
|
||||
return False;
|
||||
@@ -50,11 +58,14 @@ int wGetColorForColormap(Colormap colormap, const char *color_name, XColor *colo
|
||||
|
||||
int wGetColor(WScreen *scr, const char *color_name, XColor *color)
|
||||
{
|
||||
return wGetColorForColormap(scr->w_colormap, color_name, color);
|
||||
return wGetColorForColormap(scr, scr->w_colormap, color_name, color);
|
||||
}
|
||||
|
||||
void wFreeColor(WScreen * scr, unsigned long pixel)
|
||||
{
|
||||
if (scr->w_visual->class == TrueColor)
|
||||
return;
|
||||
|
||||
if (pixel != scr->white_pixel && pixel != scr->black_pixel) {
|
||||
unsigned long colors[1];
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#ifndef WMRESOURCES_H_
|
||||
#define WMRESOURCES_H_
|
||||
|
||||
int wGetColorForColormap(Colormap colormap, const char *color_name, XColor *color);
|
||||
int wGetColorForColormap(WScreen *scr, Colormap colormap, const char *color_name, XColor *color);
|
||||
int wGetColor(WScreen *scr, const char *color_name, XColor *color);
|
||||
void wFreeColor(WScreen *scr, unsigned long pixel);
|
||||
|
||||
|
||||
+5
-9
@@ -32,9 +32,7 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
#include <X11/XKBlib.h>
|
||||
#endif /* KEEP_XKB_LOCK_STATUS */
|
||||
#ifdef USE_RANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
@@ -663,9 +661,11 @@ WScreen *wScreenInit(int screen_number)
|
||||
/* Only GroupLock doesn't work correctly in my system since right-alt
|
||||
* can change mode while holding it too - ]d
|
||||
*/
|
||||
if (w_global.xext.xkb.supported) {
|
||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
|
||||
}
|
||||
if (w_global.xext.xkb.supported)
|
||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask);
|
||||
#else
|
||||
if (w_global.xext.xkb.supported)
|
||||
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask, XkbNewKeyboardNotifyMask);
|
||||
#endif /* KEEP_XKB_LOCK_STATUS */
|
||||
|
||||
#ifdef USE_RANDR
|
||||
@@ -1348,11 +1348,7 @@ void ScreenCapture(WScreen *scr, int mode)
|
||||
}
|
||||
|
||||
if (img) {
|
||||
#ifdef USE_PNG
|
||||
if (RSaveTitledImage(img, filepath, (char *)(filetype + 1), "Screenshot from Window Maker")) {
|
||||
#else
|
||||
if (RSaveTitledImage(img, filepath, (char *)(filetype + 1), "Screenshot from Window Maker")) {
|
||||
#endif
|
||||
scale_img = RSmoothScaleImage(img, scr->scr_width / 10, scr->scr_height / 10);
|
||||
showMiniScreenshot(scr, scale_img);
|
||||
RReleaseImage(scale_img);
|
||||
|
||||
+6
-49
@@ -123,35 +123,6 @@ static void make_keys(void)
|
||||
sNo = WMCreatePLString("No");
|
||||
}
|
||||
|
||||
static int getBool(WMPropList * value)
|
||||
{
|
||||
char *val;
|
||||
|
||||
if (!WMIsPLString(value)) {
|
||||
return 0;
|
||||
}
|
||||
val = WMGetFromPLString(value);
|
||||
if (val == NULL)
|
||||
return 0;
|
||||
|
||||
if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
|
||||
|| strcasecmp(val, "YES") == 0) {
|
||||
|
||||
return 1;
|
||||
} else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
|
||||
|| strcasecmp(val, "NO") == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
int i;
|
||||
if (sscanf(val, "%i", &i) == 1) {
|
||||
return (i != 0);
|
||||
} else {
|
||||
wwarning(_("can't convert \"%s\" to boolean"), val);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned getInt(WMPropList * value)
|
||||
{
|
||||
char *val;
|
||||
@@ -423,11 +394,11 @@ static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
|
||||
|
||||
value = WMGetFromPLDictionary(win_state, sShaded);
|
||||
if (value != NULL)
|
||||
state->shaded = getBool(value);
|
||||
state->shaded = WMPLGetBool(value);
|
||||
|
||||
value = WMGetFromPLDictionary(win_state, sMiniaturized);
|
||||
if (value != NULL)
|
||||
state->miniaturized = getBool(value);
|
||||
state->miniaturized = WMPLGetBool(value);
|
||||
|
||||
value = WMGetFromPLDictionary(win_state, sMaximized);
|
||||
if (value != NULL) {
|
||||
@@ -436,7 +407,7 @@ static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
|
||||
|
||||
value = WMGetFromPLDictionary(win_state, sHidden);
|
||||
if (value != NULL)
|
||||
state->hidden = getBool(value);
|
||||
state->hidden = WMPLGetBool(value);
|
||||
|
||||
value = WMGetFromPLDictionary(win_state, sShortcutMask);
|
||||
if (value != NULL) {
|
||||
@@ -456,20 +427,6 @@ static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
|
||||
return state;
|
||||
}
|
||||
|
||||
static inline int is_same(const char *x, const char *y)
|
||||
{
|
||||
if ((x == NULL) && (y == NULL))
|
||||
return 1;
|
||||
|
||||
if ((x == NULL) || (y == NULL))
|
||||
return 0;
|
||||
|
||||
if (strcmp(x, y) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wSessionRestoreState(WScreen *scr)
|
||||
{
|
||||
WSavedState *state;
|
||||
@@ -556,9 +513,9 @@ void wSessionRestoreState(WScreen *scr)
|
||||
if (dock != NULL) {
|
||||
for (j = 0; j < dock->max_icons; j++) {
|
||||
btn = dock->icon_array[j];
|
||||
if (btn && is_same(instance, btn->wm_instance) &&
|
||||
is_same(class, btn->wm_class) &&
|
||||
is_same(command, btn->command) &&
|
||||
if (btn && WMStrEqual(instance, btn->wm_instance) &&
|
||||
WMStrEqual(class, btn->wm_class) &&
|
||||
WMStrEqual(command, btn->command) &&
|
||||
!btn->launching) {
|
||||
found = 1;
|
||||
break;
|
||||
|
||||
+4
-3
@@ -41,9 +41,7 @@
|
||||
#ifdef USE_XSHAPE
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
#ifdef USE_RANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
@@ -601,12 +599,15 @@ void StartUp(Bool defaultScreenOnly)
|
||||
w_global.xext.randr.supported = XRRQueryExtension(dpy, &w_global.xext.randr.event_base, &j);
|
||||
#endif
|
||||
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
w_global.xext.xkb.supported = XkbQueryExtension(dpy, NULL, &w_global.xext.xkb.event_base, NULL, NULL, NULL);
|
||||
#ifdef KEEP_XKB_LOCK_STATUS
|
||||
if (wPreferences.modelock && !w_global.xext.xkb.supported) {
|
||||
wwarning(_("XKB is not supported. KbdModeLock is automatically disabled."));
|
||||
wPreferences.modelock = 0;
|
||||
}
|
||||
#else
|
||||
if (!w_global.xext.xkb.supported)
|
||||
wwarning(_("XKB is not supported."));
|
||||
#endif
|
||||
|
||||
if (defaultScreenOnly)
|
||||
|
||||
@@ -48,6 +48,50 @@ static int initialized = 0;
|
||||
static void observer(void *self, WMNotification * notif);
|
||||
static void wsobserver(void *self, WMNotification * notif);
|
||||
|
||||
static WPixmap *switchMenuIconForWindow(WScreen *scr, WWindow *wwin)
|
||||
{
|
||||
RImage *image = NULL;
|
||||
WPixmap *pix;
|
||||
WApplication *wapp;
|
||||
int max_size;
|
||||
|
||||
if (!scr || !wwin)
|
||||
return NULL;
|
||||
|
||||
max_size = WMFontHeight(scr->menu_entry_font) + 2;
|
||||
if (max_size < 12)
|
||||
max_size = 12;
|
||||
|
||||
/* Prefer the actual appicon image when available */
|
||||
wapp = wApplicationOf(wwin->main_window);
|
||||
if (wapp && wapp->app_icon && wapp->app_icon->icon && wapp->app_icon->icon->file_image) {
|
||||
image = RRetainImage(wapp->app_icon->icon->file_image);
|
||||
}
|
||||
|
||||
/* Fall back to _NET_WM_ICON, then the default icon */
|
||||
if (!image && !WFLAGP(wwin, always_user_icon) && wwin->net_icon_image)
|
||||
image = RRetainImage(wwin->net_icon_image);
|
||||
if (!image)
|
||||
image = get_icon_image(scr, wwin->wm_instance, wwin->wm_class, max_size);
|
||||
|
||||
if (!image)
|
||||
return NULL;
|
||||
|
||||
image = wIconValidateIconSize(image, max_size);
|
||||
if (!image)
|
||||
return NULL;
|
||||
|
||||
pix = wmalloc(sizeof(WPixmap));
|
||||
memset(pix, 0, sizeof(WPixmap));
|
||||
RConvertImageMask(scr->rcontext, image, &pix->image, &pix->mask, 128);
|
||||
pix->width = image->width;
|
||||
pix->height = image->height;
|
||||
pix->depth = scr->w_depth;
|
||||
|
||||
RReleaseImage(image);
|
||||
return pix;
|
||||
}
|
||||
|
||||
/*
|
||||
* FocusWindow
|
||||
*
|
||||
@@ -216,6 +260,8 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
|
||||
entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
|
||||
wfree(t);
|
||||
|
||||
entry->icon = switchMenuIconForWindow(scr, wwin);
|
||||
|
||||
entry->flags.indicator = 1;
|
||||
entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
|
||||
if (IS_OMNIPRESENT(wwin))
|
||||
@@ -273,6 +319,7 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
|
||||
if (entry->rtext) {
|
||||
int idx = -1;
|
||||
char *t, *rt;
|
||||
WPixmap *ipix;
|
||||
int it, ion;
|
||||
|
||||
if (IS_OMNIPRESENT(wwin)) {
|
||||
@@ -285,6 +332,8 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
|
||||
|
||||
rt = entry->rtext;
|
||||
entry->rtext = NULL;
|
||||
ipix = entry->icon;
|
||||
entry->icon = NULL;
|
||||
t = entry->text;
|
||||
entry->text = NULL;
|
||||
|
||||
@@ -300,6 +349,7 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
|
||||
entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
|
||||
wfree(t);
|
||||
entry->rtext = rt;
|
||||
entry->icon = ipix;
|
||||
entry->flags.indicator = 1;
|
||||
entry->flags.indicator_type = it;
|
||||
entry->flags.indicator_on = ion;
|
||||
|
||||
+9
-3
@@ -79,7 +79,7 @@ static short int label_height;
|
||||
|
||||
static int canReceiveFocus(WWindow *wwin)
|
||||
{
|
||||
if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
|
||||
if (!wPreferences.cycle_all_workspaces && wwin->frame->workspace != wwin->screen_ptr->current_workspace)
|
||||
return 0;
|
||||
|
||||
if (wPreferences.cycle_active_head_only &&
|
||||
@@ -90,7 +90,7 @@ static int canReceiveFocus(WWindow *wwin)
|
||||
return 0;
|
||||
|
||||
if (!wwin->flags.mapped) {
|
||||
if (!wwin->flags.shaded && !wwin->flags.miniaturized && !wwin->flags.hidden)
|
||||
if (!wwin->flags.shaded && !wwin->flags.miniaturized && !wwin->flags.hidden && !wPreferences.cycle_all_workspaces)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
@@ -186,12 +186,18 @@ static void addIconForWindow(WSwitchPanel *panel, WMWidget *parent, WWindow *wwi
|
||||
{
|
||||
WMFrame *icon = WMCreateFrame(parent);
|
||||
RImage *image = NULL;
|
||||
WApplication *wapp;
|
||||
|
||||
WMSetFrameRelief(icon, WRFlat);
|
||||
WMResizeWidget(icon, icon_tile_size, icon_tile_size);
|
||||
WMMoveWidget(icon, x, y);
|
||||
|
||||
if (!WFLAGP(wwin, always_user_icon) && wwin->net_icon_image)
|
||||
wapp = wApplicationOf(wwin->main_window);
|
||||
if (wapp && wapp->app_icon && wapp->app_icon->icon && wapp->app_icon->icon->file_image) {
|
||||
image = RRetainImage(wapp->app_icon->icon->file_image);
|
||||
}
|
||||
|
||||
if (!image && !WFLAGP(wwin, always_user_icon) && wwin->net_icon_image)
|
||||
image = RRetainImage(wwin->net_icon_image);
|
||||
|
||||
/* get_icon_image() includes the default icon image */
|
||||
|
||||
+3
-36
@@ -43,14 +43,13 @@
|
||||
#include "icon.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define APPLY_VAL(value, flag, attrib) \
|
||||
if (value) {attr->flag = getBool(attrib, value); \
|
||||
if (mask) mask->flag = 1;}
|
||||
#define APPLY_VAL(value, flag, attrib) \
|
||||
if (value) {attr->flag = WMPLGetBool(value); \
|
||||
if (mask) mask->flag = 1;}
|
||||
|
||||
/* Local stuff */
|
||||
|
||||
/* type converters */
|
||||
static int getBool(WMPropList *, WMPropList *);
|
||||
static char *getString(WMPropList *, WMPropList *);
|
||||
static WMPropList *ANoTitlebar = NULL;
|
||||
static WMPropList *ANoResizebar;
|
||||
@@ -634,38 +633,6 @@ void wDefaultPurgeInfo(const char *instance, const char *class)
|
||||
WMPLSetCaseSensitive(False);
|
||||
}
|
||||
|
||||
/* --------------------------- Local ----------------------- */
|
||||
|
||||
static int getBool(WMPropList * key, WMPropList * value)
|
||||
{
|
||||
char *val;
|
||||
|
||||
if (!WMIsPLString(value)) {
|
||||
wwarning(_("Wrong option format for key \"%s\". Should be %s."),
|
||||
WMGetFromPLString(key), "Boolean");
|
||||
return 0;
|
||||
}
|
||||
val = WMGetFromPLString(value);
|
||||
|
||||
if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' || val[0] == 't' || val[0] == '1'))
|
||||
|| (strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
|
||||
|
||||
return 1;
|
||||
} else if ((val[1] == '\0'
|
||||
&& (val[0] == 'n' || val[0] == 'N' || val[0] == 'F' || val[0] == 'f' || val[0] == '0'))
|
||||
|| (strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
wwarning(_("can't convert \"%s\" to boolean"), val);
|
||||
/* We return False if we can't convert to BOOLEAN.
|
||||
* This is because all options defaults to False.
|
||||
* -1 is not checked and thus is interpreted as True,
|
||||
* which is not good.*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* WARNING: Do not free the value returned by this function!! */
|
||||
static char *getString(WMPropList * key, WMPropList * value)
|
||||
{
|
||||
|
||||
+15
-19
@@ -681,6 +681,15 @@ WWindow *wManageWindow(WScreen *scr, Window window)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Some applications create placeholder windows with 1x1 size
|
||||
* (e.g. VirtualBox internal windows). Don't manage those initial
|
||||
* 1x1 windows — wait for a proper ConfigureNotify/MapRequest with
|
||||
* a real size. */
|
||||
if (wattribs.width <= 1 && wattribs.height <= 1) {
|
||||
XUngrabServer(dpy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wm_state = PropGetWindowState(window);
|
||||
|
||||
/* if it's startup and the window is unmapped, don't manage it */
|
||||
@@ -1428,7 +1437,8 @@ WWindow *wManageInternalWindow(WScreen *scr, Window window, Window owner,
|
||||
foo = WFF_RIGHT_BUTTON | WFF_BORDER;
|
||||
foo |= WFF_TITLEBAR;
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
foo |= WFF_LANGUAGE_BUTTON;
|
||||
if (wPreferences.modelock)
|
||||
foo |= WFF_LANGUAGE_BUTTON;
|
||||
#endif
|
||||
|
||||
wwin->frame = wFrameWindowCreate(scr, WMFloatingLevel,
|
||||
@@ -2726,20 +2736,6 @@ WMagicNumber wWindowAddSavedState(const char *instance, const char *class,
|
||||
return wstate;
|
||||
}
|
||||
|
||||
static inline int is_same(const char *x, const char *y)
|
||||
{
|
||||
if ((x == NULL) && (y == NULL))
|
||||
return 1;
|
||||
|
||||
if ((x == NULL) || (y == NULL))
|
||||
return 0;
|
||||
|
||||
if (strcmp(x, y) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
WMagicNumber wWindowGetSavedState(Window win)
|
||||
{
|
||||
char *instance, *class, *command = NULL;
|
||||
@@ -2754,9 +2750,9 @@ WMagicNumber wWindowGetSavedState(Window win)
|
||||
|
||||
if (PropGetWMClass(win, &class, &instance)) {
|
||||
while (wstate) {
|
||||
if (is_same(instance, wstate->instance) &&
|
||||
is_same(class, wstate->class) &&
|
||||
is_same(command, wstate->command)) {
|
||||
if (WMStrEqual(instance, wstate->instance) &&
|
||||
WMStrEqual(class, wstate->class) &&
|
||||
WMStrEqual(command, wstate->command)) {
|
||||
break;
|
||||
}
|
||||
wstate = wstate->next;
|
||||
@@ -2982,7 +2978,7 @@ static void frameMouseDown(WObjDescriptor *desc, XEvent *event)
|
||||
|
||||
CloseWindowMenu(wwin->screen_ptr);
|
||||
|
||||
if (!(event->xbutton.state & ControlMask) && !WFLAGP(wwin, no_focusable))
|
||||
if (event->xbutton.button != Button4 && event->xbutton.button != Button5 && !(event->xbutton.state & ControlMask) && !WFLAGP(wwin, no_focusable))
|
||||
wSetFocusTo(wwin->screen_ptr, wwin);
|
||||
|
||||
if (event->xbutton.button == Button1)
|
||||
|
||||
@@ -237,6 +237,12 @@ typedef struct WWindow {
|
||||
int cmap_window_no;
|
||||
Window *cmap_windows;
|
||||
|
||||
/* move/resize state for _NET_WM_MOVERESIZE support */
|
||||
struct {
|
||||
int active; /* 1 if move/resize is in progress */
|
||||
int resize_edge; /* which edge for resize (0-7) */
|
||||
} moveresize;
|
||||
|
||||
/* protocols */
|
||||
WProtocols protocols; /* accepted WM_PROTOCOLS */
|
||||
|
||||
|
||||
+9
-28
@@ -55,7 +55,11 @@
|
||||
#define UPDATE_TEXT_FIELD 2
|
||||
#define REVERT_TO_DEFAULT 4
|
||||
#define PWIDTH 290
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
#define PHEIGHT 380
|
||||
#else
|
||||
#define PHEIGHT 360
|
||||
#endif
|
||||
#define UNDEFINED_POS 0xffffff
|
||||
#define UPDATE_DEFAULTS 1
|
||||
#define IS_BOOLEAN 2
|
||||
@@ -504,33 +508,6 @@ static int showIconFor(WMScreen *scrPtr, InspectorPanel *panel, const char *wm_i
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getBool(WMPropList *value)
|
||||
{
|
||||
char *val;
|
||||
|
||||
if (!WMIsPLString(value))
|
||||
return 0;
|
||||
|
||||
val = WMGetFromPLString(value);
|
||||
if (val == NULL)
|
||||
return 0;
|
||||
|
||||
if ((val[1] == '\0' &&
|
||||
(val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' ||
|
||||
val[0] == 't' || val[0] == '1')) ||
|
||||
(strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
|
||||
return 1;
|
||||
} else if ((val[1] == '\0' &&
|
||||
(val[0] == 'n' || val[0] == 'N' || val[0] == 'F' ||
|
||||
val[0] == 'f' || val[0] == '0')) ||
|
||||
(strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
wwarning(_("can't convert \"%s\" to boolean"), val);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Will insert the attribute = value; pair in window's list,
|
||||
* if it's different from the defaults.
|
||||
* Defaults means either defaults database, or attributes saved
|
||||
@@ -554,7 +531,7 @@ insertAttribute(WMPropList *dict, WMPropList *window, WMPropList *attr, WMPropLi
|
||||
def_value = ((flags & IS_BOOLEAN) != 0) ? No : EmptyString;
|
||||
|
||||
if (flags & IS_BOOLEAN)
|
||||
update = (getBool(value) != getBool(def_value));
|
||||
update = (WMPLGetBool(value) != WMPLGetBool(def_value));
|
||||
else
|
||||
update = !WMIsPropListEqualTo(value, def_value);
|
||||
|
||||
@@ -1342,7 +1319,11 @@ static void create_tab_window_advanced(WWindow *wwin, InspectorPanel *panel, int
|
||||
panel->moreFrm = WMCreateFrame(panel->win);
|
||||
WMSetFrameTitle(panel->moreFrm, _("Advanced"));
|
||||
WMMoveWidget(panel->moreFrm, 15, 45);
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
WMResizeWidget(panel->moreFrm, frame_width, 285);
|
||||
#else
|
||||
WMResizeWidget(panel->moreFrm, frame_width, 265);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < wlengthof(advanced_option); i++) {
|
||||
int is_userdef, flag;
|
||||
|
||||
+104
-33
@@ -32,7 +32,9 @@
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <WINGs/WUtil.h>
|
||||
#include "WindowMaker.h"
|
||||
@@ -69,7 +71,7 @@ static Atom net_showing_desktop;
|
||||
/* Other Root Window Messages */
|
||||
static Atom net_close_window;
|
||||
static Atom net_moveresize_window; /* TODO */
|
||||
static Atom net_wm_moveresize; /* TODO */
|
||||
static Atom net_wm_moveresize;
|
||||
|
||||
/* Application Window Properties */
|
||||
static Atom net_wm_name;
|
||||
@@ -123,7 +125,7 @@ static Atom net_wm_strut;
|
||||
static Atom net_wm_strut_partial; /* TODO: doesn't really fit into the current strut scheme */
|
||||
static Atom net_wm_icon_geometry; /* FIXME: should work together with net_wm_handled_icons, gnome-panel-2.2.0.1 doesn't use _NET_WM_HANDLED_ICONS, thus present situation. */
|
||||
static Atom net_wm_icon;
|
||||
static Atom net_wm_pid; /* TODO */
|
||||
static Atom net_wm_pid;
|
||||
static Atom net_wm_handled_icons; /* FIXME: see net_wm_icon_geometry */
|
||||
static Atom net_wm_window_opacity;
|
||||
|
||||
@@ -224,35 +226,6 @@ static atomitem_t atomNames[] = {
|
||||
#define _NET_WM_STATE_ADD 1
|
||||
#define _NET_WM_STATE_TOGGLE 2
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* These constant provide information on the kind of window move/resize when
|
||||
* it is initiated by the application instead of by WindowMaker. They are
|
||||
* parameter for the client message _NET_WM_MOVERESIZE, as defined by the
|
||||
* FreeDesktop wm-spec standard:
|
||||
* http://standards.freedesktop.org/wm-spec/1.5/ar01s04.html
|
||||
*
|
||||
* Today, WindowMaker does not support this at all (the corresponding Atom
|
||||
* is not added to the list in setSupportedHints), probably because there is
|
||||
* nothing it needs to do about it, the application is assumed to know what
|
||||
* it is doing, and WindowMaker won't get in the way.
|
||||
*
|
||||
* The definition of the constants (taken from the standard) are disabled to
|
||||
* avoid a spurious warning (-Wunused-macros).
|
||||
*/
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
|
||||
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
|
||||
#endif
|
||||
|
||||
static void observer(void *self, WMNotification *notif);
|
||||
static void wsobserver(void *self, WMNotification *notif);
|
||||
|
||||
@@ -274,6 +247,9 @@ static void setSupportedHints(WScreen *scr)
|
||||
{
|
||||
Atom atom[wlengthof(atomNames)];
|
||||
int i = 0;
|
||||
long pid = 0;
|
||||
char wm_name[64] = "";
|
||||
XClassHint *class_hint;
|
||||
|
||||
/* set supported hints list */
|
||||
/* XXX: extend this !!! */
|
||||
@@ -289,9 +265,7 @@ static void setSupportedHints(WScreen *scr)
|
||||
atom[i++] = net_workarea;
|
||||
atom[i++] = net_supporting_wm_check;
|
||||
atom[i++] = net_showing_desktop;
|
||||
#if 0
|
||||
atom[i++] = net_wm_moveresize;
|
||||
#endif
|
||||
atom[i++] = net_wm_desktop;
|
||||
#ifdef USE_XINERAMA
|
||||
atom[i++] = net_wm_fullscreen_monitors;
|
||||
@@ -357,6 +331,25 @@ static void setSupportedHints(WScreen *scr)
|
||||
|
||||
XChangeProperty(dpy, scr->info_window, net_supporting_wm_check, XA_WINDOW,
|
||||
32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
|
||||
|
||||
/* set _NET_WM_NAME on supporting window */
|
||||
snprintf(wm_name, sizeof(wm_name), "WindowMaker %s", VERSION);
|
||||
XChangeProperty(dpy, scr->info_window, net_wm_name, utf8_string, 8,
|
||||
PropModeReplace, (unsigned char *)wm_name, strlen(wm_name));
|
||||
|
||||
/* set _NET_WM_PID on supporting window */
|
||||
pid = getpid();
|
||||
XChangeProperty(dpy, scr->info_window, net_wm_pid, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char *)&pid, 1);
|
||||
|
||||
/* set WM_CLASS on supporting window */
|
||||
class_hint = XAllocClassHint();
|
||||
if (class_hint) {
|
||||
class_hint->res_name = "wmaker";
|
||||
class_hint->res_class = "WindowMaker";
|
||||
XSetClassHint(dpy, scr->info_window, class_hint);
|
||||
XFree(class_hint);
|
||||
}
|
||||
}
|
||||
|
||||
void wNETWMUpdateDesktop(WScreen *scr)
|
||||
@@ -1790,6 +1783,84 @@ Bool wNETWMProcessClientMessage(XClientMessageEvent *event)
|
||||
}
|
||||
return True;
|
||||
|
||||
} else if (event->message_type == net_wm_moveresize) {
|
||||
XEvent fake_event;
|
||||
int direction = event->data.l[2];
|
||||
int x_root = event->data.l[0];
|
||||
int y_root = event->data.l[1];
|
||||
int button = event->data.l[3];
|
||||
int junk;
|
||||
Window junkw;
|
||||
unsigned int mask;
|
||||
|
||||
if (direction == _NET_WM_MOVERESIZE_CANCEL) {
|
||||
if (wwin->moveresize.active) {
|
||||
memset(&fake_event, 0, sizeof(XEvent));
|
||||
fake_event.type = ButtonRelease;
|
||||
fake_event.xbutton.window = wwin->frame->core->window;
|
||||
fake_event.xbutton.x_root = x_root;
|
||||
fake_event.xbutton.y_root = y_root;
|
||||
fake_event.xbutton.button = event->data.l[3];
|
||||
XSendEvent(dpy, wwin->frame->core->window, False, ButtonReleaseMask, &fake_event);
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Check if already in progress */
|
||||
if (wwin->moveresize.active)
|
||||
return True;
|
||||
|
||||
/* Check if the initiating button is actually pressed */
|
||||
if (!XQueryPointer(dpy, wwin->screen_ptr->root_win, &junkw, &junkw,
|
||||
&junk, &junk, &junk, &junk, &mask))
|
||||
return True;
|
||||
|
||||
if (button > 0) {
|
||||
unsigned int expected =
|
||||
button == 1 ? Button1Mask :
|
||||
button == 2 ? Button2Mask :
|
||||
button == 3 ? Button3Mask :
|
||||
0;
|
||||
|
||||
if (expected && !(mask & expected))
|
||||
/* Race: button already released */
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Check if operation is allowed */
|
||||
if (direction == _NET_WM_MOVERESIZE_MOVE) {
|
||||
if (WFLAGP(wwin, no_movable))
|
||||
return True;
|
||||
} else if (direction <= _NET_WM_MOVERESIZE_SIZE_LEFT) {
|
||||
if (WFLAGP(wwin, no_resizable))
|
||||
return True;
|
||||
} else {
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Grab the pointer for the operation */
|
||||
if (XGrabPointer(dpy, wwin->frame->core->window, False,
|
||||
ButtonReleaseMask | PointerMotionMask | ButtonPressMask,
|
||||
GrabModeAsync, GrabModeAsync,
|
||||
None, None, CurrentTime) != GrabSuccess)
|
||||
return True;
|
||||
|
||||
/* Set up the move/resize state */
|
||||
wwin->moveresize.active = 1;
|
||||
wwin->moveresize.resize_edge = direction;
|
||||
|
||||
memset(&fake_event, 0, sizeof(XEvent));
|
||||
fake_event.type = MotionNotify;
|
||||
fake_event.xmotion.x_root = x_root;
|
||||
fake_event.xmotion.y_root = y_root;
|
||||
fake_event.xmotion.window = wwin->frame->core->window;
|
||||
if (direction == _NET_WM_MOVERESIZE_MOVE)
|
||||
wMouseMoveWindow(wwin, &fake_event);
|
||||
else
|
||||
wMouseResizeWindow(wwin, &fake_event);
|
||||
|
||||
return True;
|
||||
|
||||
#ifdef USE_XINERAMA
|
||||
} else if (event->message_type == net_wm_fullscreen_monitors) {
|
||||
unsigned long top, bottom, left, right, src_indication;
|
||||
|
||||
@@ -28,6 +28,26 @@
|
||||
#include "window.h"
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
/*
|
||||
* These constant provide information on the kind of window move/resize when
|
||||
* it is initiated by the application instead of by WindowMaker. They are
|
||||
* parameter for the client message _NET_WM_MOVERESIZE, as defined by the
|
||||
* FreeDesktop wm-spec standard:
|
||||
* http://standards.freedesktop.org/wm-spec/1.5/ar01s04.html
|
||||
*/
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
|
||||
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
|
||||
|
||||
void wNETWMInitStuff(WScreen *scr);
|
||||
void wNETWMCleanup(WScreen *scr);
|
||||
void wNETWMUpdateWorkarea(WScreen *scr);
|
||||
|
||||
+3
-2
@@ -76,9 +76,10 @@ wmiv_LDADD = \
|
||||
$(top_builddir)/wrlib/libwraster.la \
|
||||
$(top_builddir)/WINGs/libWINGs.la \
|
||||
@XLFLAGS@ @XLIBS@ @GFXLIBS@ \
|
||||
@PANGO_LIBS@ @PTHREAD_LIBS@ @LIBEXIF@
|
||||
@PANGO_LIBS@ @PTHREAD_LIBS@ @LIBEXIF@ \
|
||||
@LIBARCHIVE_LIBS@ @LIBM@ @LIBXRANDR@
|
||||
|
||||
wmiv_SOURCES = wmiv.c wmiv.h
|
||||
wmiv_SOURCES = wmiv.c wmiv.hi xdnd.c xdnd.h
|
||||
|
||||
CLEANFILES = wmaker.inst
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ File Language Note Current Maintainer
|
||||
------------------------------------------------------------------------------
|
||||
nl.po Dutch Alwin <translations@ziggo.nl>
|
||||
fy.po Frisian Alwin <translations@ziggo.nl>
|
||||
sr.po Serbian Strahinya Radich <contact@strahinja.org>
|
||||
sr.po Serbian Strahinya Radich <sr@strahinja.org>
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
# 1998-2006 Dan Pascu
|
||||
# 2013-2020 Window Maker Developers Team
|
||||
# This file is distributed under the same license as the Window Maker package.
|
||||
# Strahinya Radich (Страхиња Радић) <contact@strahinja.org>, 2023.
|
||||
# Strahinya Radich (Страхиња Радић) <sr@strahinja.org>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -11,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: wmaker-dev@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2023-11-02 19:43+0100\n"
|
||||
"PO-Revision-Date: 2023-11-02 19:48+0100\n"
|
||||
"Last-Translator: Страхиња Радић <contact@strahinja.org>\n"
|
||||
"Last-Translator: Страхиња Радић <sr@strahinja.org>\n"
|
||||
"Language-Team: Serbian <sr@li.org>\n"
|
||||
"Language: sr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1494
-229
File diff suppressed because it is too large
Load Diff
+1596
File diff suppressed because it is too large
Load Diff
+219
@@ -0,0 +1,219 @@
|
||||
/* xdnd.c, xdnd.h - C program library for handling the Xdnd protocol
|
||||
Copyright (C) 1996-2000 Paul Sheer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _X_DND_H
|
||||
#define _X_DND_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* you can set this to either 2 (which support 0 and 1 as well) or 3 */
|
||||
/* #define XDND_VERSION 2 */
|
||||
|
||||
#define XDND_VERSION 3
|
||||
|
||||
/* XdndEnter */
|
||||
#define XDND_THREE 3
|
||||
#define XDND_ENTER_SOURCE_WIN(e) ((e)->xclient.data.l[0])
|
||||
#define XDND_ENTER_THREE_TYPES(e) (((e)->xclient.data.l[1] & 0x1UL) == 0)
|
||||
#define XDND_ENTER_THREE_TYPES_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
|
||||
#define XDND_ENTER_VERSION(e) ((e)->xclient.data.l[1] >> 24)
|
||||
#define XDND_ENTER_VERSION_SET(e,v) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24)
|
||||
#define XDND_ENTER_TYPE(e,i) ((e)->xclient.data.l[2 + i]) /* i => (0, 1, 2) */
|
||||
|
||||
/* XdndPosition */
|
||||
#define XDND_POSITION_SOURCE_WIN(e) ((e)->xclient.data.l[0])
|
||||
#define XDND_POSITION_ROOT_X(e) ((e)->xclient.data.l[2] >> 16)
|
||||
#define XDND_POSITION_ROOT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFUL)
|
||||
#define XDND_POSITION_ROOT_SET(e,x,y) (e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL)
|
||||
#define XDND_POSITION_TIME(e) ((e)->xclient.data.l[3])
|
||||
#define XDND_POSITION_ACTION(e) ((e)->xclient.data.l[4])
|
||||
|
||||
/* XdndStatus */
|
||||
#define XDND_STATUS_TARGET_WIN(e) ((e)->xclient.data.l[0])
|
||||
#define XDND_STATUS_WILL_ACCEPT(e) ((e)->xclient.data.l[1] & 0x1L)
|
||||
#define XDND_STATUS_WILL_ACCEPT_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
|
||||
#define XDND_STATUS_WANT_POSITION(e) ((e)->xclient.data.l[1] & 0x2UL)
|
||||
#define XDND_STATUS_WANT_POSITION_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x2UL) | (((b) == 0) ? 0 : 0x2UL)
|
||||
#define XDND_STATUS_RECT_X(e) ((e)->xclient.data.l[2] >> 16)
|
||||
#define XDND_STATUS_RECT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFL)
|
||||
#define XDND_STATUS_RECT_WIDTH(e) ((e)->xclient.data.l[3] >> 16)
|
||||
#define XDND_STATUS_RECT_HEIGHT(e) ((e)->xclient.data.l[3] & 0xFFFFL)
|
||||
#define XDND_STATUS_RECT_SET(e,x,y,w,h) {(e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL); (e)->xclient.data.l[3] = ((w) << 16) | ((h) & 0xFFFFUL); }
|
||||
#define XDND_STATUS_ACTION(e) ((e)->xclient.data.l[4])
|
||||
|
||||
/* XdndLeave */
|
||||
#define XDND_LEAVE_SOURCE_WIN(e) ((e)->xclient.data.l[0])
|
||||
|
||||
/* XdndDrop */
|
||||
#define XDND_DROP_SOURCE_WIN(e) ((e)->xclient.data.l[0])
|
||||
#define XDND_DROP_TIME(e) ((e)->xclient.data.l[2])
|
||||
|
||||
/* XdndFinished */
|
||||
#define XDND_FINISHED_TARGET_WIN(e) ((e)->xclient.data.l[0])
|
||||
|
||||
struct _DndCursor {
|
||||
int width, height;
|
||||
int x, y;
|
||||
unsigned char *image_data, *mask_data;
|
||||
char *_action;
|
||||
Pixmap image_pixmap, mask_pixmap;
|
||||
Cursor cursor;
|
||||
Atom action;
|
||||
};
|
||||
|
||||
typedef struct _DndCursor DndCursor;
|
||||
typedef struct _DndClass DndClass;
|
||||
|
||||
struct _DndClass {
|
||||
/* insert chars sequentionally into the target widget, type will be the same as `desired_type'
|
||||
returned from widget_apply_position. This may be called several times in succession
|
||||
with sequention blocks of data. Must return non-zero on failure */
|
||||
int (*widget_insert_drop) (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type);
|
||||
|
||||
/* In response to DELETE requests : FIXME - not yet used */
|
||||
int (*widget_delete_selection) (DndClass * dnd, Window window, Window from);
|
||||
|
||||
/* returns 1 if widget exists, zero otherwise. If this method is not
|
||||
set then the code assumes that no widgets have support for recieving drops.
|
||||
In this case none of the widget methods need be set. */
|
||||
int (*widget_exists) (DndClass * dnd, Window window);
|
||||
|
||||
/* must update the widgets border to its default appearance */
|
||||
void (*widget_apply_leave) (DndClass * dnd, Window widgets_window);
|
||||
|
||||
/* must update the widgets border to give the appearance of being able to recieve a drop,
|
||||
plus return all data to pointers. As per the protocol, if the widget cannot
|
||||
perform the action specified by `action' then it should return either XdndActionPrivate
|
||||
or XdndActionCopy into supported_action (leaving 0 supported_action unchanged is equivalent
|
||||
to XdndActionCopy). Returns 1 if ready to ok drop */
|
||||
int (*widget_apply_position) (DndClass * dnd, Window widgets_window, Window from,
|
||||
Atom action, int x, int y, Time t, Atom * typelist,
|
||||
int *want_position, Atom * supported_action, Atom * desired_type,
|
||||
XRectangle * rectangle);
|
||||
|
||||
/* returns drag data of the specified type. This will be one of `typelist' given to xdnd_drag */
|
||||
void (*widget_get_data) (DndClass * dnd, Window window, unsigned char **data, int *length, Atom type);
|
||||
|
||||
/* this is called from with the main event loop if an expose event is recieved and is optional */
|
||||
void (*handle_expose_events) (DndClass * dnd, XEvent * xevent);
|
||||
|
||||
/* creates a chooser dialog if the action is XdndActionAsk. Returns non-zero on cancel */
|
||||
int (*action_choose_dialog) (DndClass * dnd, char **descriptions, Atom * actions, Atom * result);
|
||||
|
||||
#if 0 /* implemented internally */
|
||||
/* returns a widget that is dnd aware within a parent widget that lies under the point x, y */
|
||||
Window (*widget_get_child_widget) (DndClass * dnd, Window parent, int x, int y);
|
||||
#endif
|
||||
|
||||
void *pad1[8];
|
||||
|
||||
DndCursor *cursors;
|
||||
|
||||
Display *display;
|
||||
|
||||
Atom XdndAware;
|
||||
Atom XdndSelection;
|
||||
Atom XdndEnter;
|
||||
Atom XdndLeave;
|
||||
Atom XdndPosition;
|
||||
Atom XdndDrop;
|
||||
Atom XdndFinished;
|
||||
Atom XdndStatus;
|
||||
Atom XdndActionCopy;
|
||||
Atom XdndActionMove;
|
||||
Atom XdndActionLink;
|
||||
Atom XdndActionAsk;
|
||||
Atom XdndActionPrivate;
|
||||
Atom XdndTypeList;
|
||||
Atom XdndActionList;
|
||||
Atom XdndActionDescription;
|
||||
|
||||
Atom Xdnd_NON_PROTOCOL_ATOM;
|
||||
Atom version;
|
||||
|
||||
Atom pad2[16];
|
||||
|
||||
Window root_window;
|
||||
|
||||
#define XDND_DROP_STAGE_IDLE 0
|
||||
#define XDND_DRAG_STAGE_DRAGGING 1
|
||||
#define XDND_DRAG_STAGE_ENTERED 2
|
||||
#define XDND_DROP_STAGE_CONVERTING 3
|
||||
#define XDND_DROP_STAGE_ENTERED 4
|
||||
int stage;
|
||||
int dragging_version;
|
||||
int internal_drag;
|
||||
int want_position;
|
||||
int ready_to_drop;
|
||||
int will_accept;
|
||||
XRectangle rectangle;
|
||||
Window dropper_window, dragger_window;
|
||||
Atom *dragger_typelist;
|
||||
Atom desired_type;
|
||||
Atom supported_action;
|
||||
Time time;
|
||||
/* drop position from last XdndPosition */
|
||||
int x, y;
|
||||
int pad3[16];
|
||||
|
||||
/* move euclidian pixels before considering this to be an actual drag */
|
||||
float drag_threshold;
|
||||
|
||||
/* block for only this many seconds on not receiving a XdndFinished from target, default : 10 */
|
||||
int time_out;
|
||||
|
||||
#define XDND_OPTION_NO_HYSTERESIS (1<<0)
|
||||
int options;
|
||||
|
||||
/* user hooks */
|
||||
void *user_hook1;
|
||||
void *user_hook2;
|
||||
void *user_hook3;
|
||||
Window dropper_toplevel;
|
||||
void *pad4[15];
|
||||
};
|
||||
|
||||
|
||||
void xdnd_init (DndClass * dnd, Display * display);
|
||||
void xdnd_shut (DndClass * dnd);
|
||||
/* for nested widgets where parent and child receive drops of different
|
||||
types; then always pass typelist as null */
|
||||
void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist);
|
||||
int xdnd_is_dnd_aware (DndClass * dnd, Window window, int *version, Atom * typelist);
|
||||
void xdnd_set_type_list (DndClass * dnd, Window window, Atom * typelist);
|
||||
void xdnd_set_actions (DndClass * dnd, Window window, Atom * actions, char **descriptions);
|
||||
int xdnd_get_actions (DndClass * dnd, Window window, Atom ** actions, char ***descriptions);
|
||||
int xdnd_choose_action_dialog (DndClass * dnd, Atom * actions, char **descriptions, Atom * result);
|
||||
Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist);
|
||||
|
||||
/* Returns 1 if event is handled, This must be placed in the widget
|
||||
libraries main event loop and be called if the event type is
|
||||
ClientMessage or SelectionNotify */
|
||||
int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent);
|
||||
Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
|
||||
unsigned char **data, int *length, Atom * type, int *x, int *y);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_X_DND_H */
|
||||
@@ -1,3 +1,5 @@
|
||||
- added RSaveRawImage()
|
||||
|
||||
- added RSaveTitledImage()
|
||||
|
||||
- removed obsoleted RDestroyImage()
|
||||
|
||||
@@ -58,6 +58,10 @@ libwraster_la_SOURCES += load_jpeg.c
|
||||
libwraster_la_SOURCES += save_jpeg.c
|
||||
endif
|
||||
|
||||
if USE_JXL
|
||||
libwraster_la_SOURCES += load_jxl.c
|
||||
endif
|
||||
|
||||
if USE_PNG
|
||||
libwraster_la_SOURCES += load_png.c
|
||||
libwraster_la_SOURCES += save_png.c
|
||||
|
||||
+38
-38
@@ -25,47 +25,47 @@
|
||||
|
||||
|
||||
void RCombineAlpha(unsigned char *d, unsigned char *s, int s_has_alpha,
|
||||
int width, int height, int dwi, int swi, int opacity) {
|
||||
int x, y;
|
||||
int t, sa;
|
||||
int alpha;
|
||||
float ratio, cratio;
|
||||
int width, int height, int dwi, int swi, int opacity) {
|
||||
int x, y;
|
||||
unsigned char *dst = d;
|
||||
unsigned char *src = s;
|
||||
|
||||
for (y=0; y<height; y++) {
|
||||
for (x=0; x<width; x++) {
|
||||
sa=s_has_alpha?*(s+3):255;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
int sa = s_has_alpha ? src[3] : 255;
|
||||
int t, alpha;
|
||||
|
||||
if (opacity!=255) {
|
||||
t = sa * opacity + 0x80;
|
||||
sa = ((t>>8)+t)>>8;
|
||||
}
|
||||
if (opacity != 255) {
|
||||
t = sa * opacity + 0x80;
|
||||
sa = ((t >> 8) + t) >> 8;
|
||||
}
|
||||
|
||||
t = *(d+3) * (255-sa) + 0x80;
|
||||
alpha = sa + (((t>>8)+t)>>8);
|
||||
t = dst[3] * (255 - sa) + 0x80;
|
||||
alpha = sa + (((t >> 8) + t) >> 8);
|
||||
|
||||
if (sa==0 || alpha==0) {
|
||||
ratio = 0;
|
||||
cratio = 1.0;
|
||||
} else if(sa == alpha) {
|
||||
ratio = 1.0;
|
||||
cratio = 0;
|
||||
} else {
|
||||
ratio = (float)sa / alpha;
|
||||
cratio = 1.0F - ratio;
|
||||
}
|
||||
if (alpha == 0) {
|
||||
dst[3] = 0;
|
||||
} else if (sa == alpha) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = alpha;
|
||||
} else if (sa == 0) {
|
||||
dst[3] = alpha;
|
||||
} else {
|
||||
int ratio = (sa << 8) / alpha;
|
||||
int inv_ratio = 256 - ratio;
|
||||
|
||||
*d = (int)*d * cratio + (int)*s * ratio;
|
||||
s++; d++;
|
||||
*d = (int)*d * cratio + (int)*s * ratio;
|
||||
s++; d++;
|
||||
*d = (int)*d * cratio + (int)*s * ratio;
|
||||
s++; d++;
|
||||
*d = alpha;
|
||||
d++;
|
||||
dst[0] = (dst[0] * inv_ratio + src[0] * ratio) >> 8;
|
||||
dst[1] = (dst[1] * inv_ratio + src[1] * ratio) >> 8;
|
||||
dst[2] = (dst[2] * inv_ratio + src[2] * ratio) >> 8;
|
||||
dst[3] = alpha;
|
||||
}
|
||||
|
||||
if (s_has_alpha) s++;
|
||||
}
|
||||
d+=dwi;
|
||||
s+=swi;
|
||||
}
|
||||
}
|
||||
dst += 4;
|
||||
src += s_has_alpha ? 4 : 3;
|
||||
}
|
||||
dst += dwi;
|
||||
src += swi;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -554,7 +554,7 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu
|
||||
|
||||
if (!(context->attribs->flags & RC_ScalingFilter)) {
|
||||
context->attribs->flags |= RC_ScalingFilter;
|
||||
context->attribs->scaling_filter = RMitchellFilter;
|
||||
context->attribs->scaling_filter = RCatmullRomFilter;
|
||||
}
|
||||
|
||||
/* get configuration from environment variables */
|
||||
|
||||
+9
-2
@@ -38,12 +38,13 @@ typedef enum {
|
||||
IM_PPM = 4,
|
||||
IM_JPEG = 5,
|
||||
IM_GIF = 6,
|
||||
IM_WEBP = 7
|
||||
IM_WEBP = 7,
|
||||
IM_JXL = 8
|
||||
} WRImgFormat;
|
||||
|
||||
/* How many image types we have. */
|
||||
/* Increase this when adding new image types! */
|
||||
#define IM_TYPES 7
|
||||
#define IM_TYPES 8
|
||||
|
||||
/*
|
||||
* Function for Loading in a specific format
|
||||
@@ -64,6 +65,10 @@ RImage *RLoadPNG(RContext *context, const char *file);
|
||||
RImage *RLoadJPEG(const char *file);
|
||||
#endif
|
||||
|
||||
#ifdef USE_JXL
|
||||
RImage *RLoadJXL(const char *file);
|
||||
#endif
|
||||
|
||||
#ifdef USE_GIF
|
||||
RImage *RLoadGIF(const char *file, int index);
|
||||
#endif
|
||||
@@ -85,10 +90,12 @@ Bool RSaveXPM(RImage *image, const char *filename);
|
||||
|
||||
#ifdef USE_PNG
|
||||
Bool RSavePNG(RImage *image, const char *filename, char *title);
|
||||
Bool RSaveRawPNG(RImage *image, char *title, unsigned char **out_buf, size_t *out_size);
|
||||
#endif
|
||||
|
||||
#ifdef USE_JPEG
|
||||
Bool RSaveJPEG(RImage *image, const char *filename, char *title);
|
||||
Bool RSaveRawJPEG(RImage *image, char *title, unsigned char **out_buf, size_t *out_size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+27
-1
@@ -3,7 +3,7 @@
|
||||
* Raster graphics library
|
||||
*
|
||||
* Copyright (c) 1997-2003 Alfredo K. Kojima
|
||||
* Copyright (c) 2014-2021 Window Maker Team
|
||||
* Copyright (c) 2014-2025 Window Maker Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
@@ -93,6 +93,9 @@ char **RSupportedFileFormats(void)
|
||||
#ifdef USE_JPEG
|
||||
tmp[i++] = "JPEG";
|
||||
#endif
|
||||
#ifdef USE_JXL
|
||||
tmp[i++] = "JXL";
|
||||
#endif
|
||||
#ifdef USE_GIF
|
||||
tmp[i++] = "GIF";
|
||||
#endif
|
||||
@@ -159,6 +162,11 @@ RImage *RLoadImage(RContext *context, const char *file, int index)
|
||||
|
||||
assert(file != NULL);
|
||||
|
||||
/* just to suppress the compilation warning as index is only used with TIFF and GIF */
|
||||
#if !defined(USE_TIFF) && !defined(USE_GIF)
|
||||
(void)index;
|
||||
#endif
|
||||
|
||||
if (RImageCacheSize < 0)
|
||||
init_cache();
|
||||
|
||||
@@ -219,6 +227,12 @@ RImage *RLoadImage(RContext *context, const char *file, int index)
|
||||
break;
|
||||
#endif /* USE_JPEG */
|
||||
|
||||
#ifdef USE_JXL
|
||||
case IM_JXL:
|
||||
image = RLoadJXL(file);
|
||||
break;
|
||||
#endif /* USE_JXL */
|
||||
|
||||
#ifdef USE_GIF
|
||||
case IM_GIF:
|
||||
image = RLoadGIF(file, index);
|
||||
@@ -305,6 +319,11 @@ char *RGetImageFileFormat(const char *file)
|
||||
return "JPEG";
|
||||
#endif /* USE_JPEG */
|
||||
|
||||
#ifdef USE_JXL
|
||||
case IM_JXL:
|
||||
return "JXL";
|
||||
#endif /* USE_JXL */
|
||||
|
||||
#ifdef USE_GIF
|
||||
case IM_GIF:
|
||||
return "GIF";
|
||||
@@ -377,6 +396,13 @@ static WRImgFormat identFile(const char *path)
|
||||
if (buffer[0] == 0xff && buffer[1] == 0xd8)
|
||||
return IM_JPEG;
|
||||
|
||||
/* check for JXL */
|
||||
if ((buffer[0] == 0xff && buffer[1] == 0x0a) || /* naked codestream */
|
||||
(buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x00 && buffer[3] == 0x0c && /* container format */
|
||||
buffer[4] == 0x4a && buffer[5] == 0x58 && buffer[6] == 0x4c && buffer[7] == 0x20 &&
|
||||
buffer[8] == 0x0d && buffer[9] == 0x0a && buffer[10] == 0x87 && buffer[11] == 0x0a))
|
||||
return IM_JXL;
|
||||
|
||||
/* check for GIF */
|
||||
if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F' && buffer[3] == '8' &&
|
||||
(buffer[4] == '7' || buffer[4] == '9') && buffer[5] == 'a')
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/* load_jxl.c - load JXL (JPEG XL) image from file
|
||||
*
|
||||
* Raster graphics library
|
||||
*
|
||||
* Copyright (c) 2025 Window Maker Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef USE_JXL
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <jxl/decode.h>
|
||||
|
||||
#include "wraster.h"
|
||||
#include "imgformat.h"
|
||||
#include "wr_i18n.h"
|
||||
|
||||
static unsigned char *do_read_file(const char *filename, size_t *size)
|
||||
{
|
||||
FILE *file;
|
||||
struct stat st;
|
||||
unsigned char *data;
|
||||
|
||||
if (stat(filename, &st) != 0) {
|
||||
RErrorCode = RERR_OPEN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
RErrorCode = RERR_OPEN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size = st.st_size;
|
||||
data = malloc(*size);
|
||||
if (!data) {
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fread(data, 1, *size, file) != *size) {
|
||||
RErrorCode = RERR_READ;
|
||||
free(data);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return data;
|
||||
}
|
||||
|
||||
RImage *RLoadJXL(const char *file)
|
||||
{
|
||||
RImage *image = NULL;
|
||||
unsigned char *data = NULL, *pixels = NULL;
|
||||
size_t size;
|
||||
JxlDecoder *dec = NULL;
|
||||
JxlDecoderStatus status;
|
||||
JxlBasicInfo info;
|
||||
JxlPixelFormat format;
|
||||
size_t buffer_size;
|
||||
int width = 0, height = 0;
|
||||
int has_alpha = 0;
|
||||
|
||||
/* Load file data */
|
||||
data = do_read_file(file, &size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
/* Create decoder */
|
||||
dec = JxlDecoderCreate(NULL);
|
||||
if (!dec) {
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Subscribe to basic info and full image */
|
||||
if (JxlDecoderSubscribeEvents(dec, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set input data */
|
||||
if (JxlDecoderSetInput(dec, data, size) != JXL_DEC_SUCCESS) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Process events */
|
||||
for (;;) {
|
||||
status = JxlDecoderProcessInput(dec);
|
||||
|
||||
if (status == JXL_DEC_ERROR) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (status == JXL_DEC_NEED_MORE_INPUT) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (status == JXL_DEC_BASIC_INFO) {
|
||||
if (JxlDecoderGetBasicInfo(dec, &info) != JXL_DEC_SUCCESS) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
width = info.xsize;
|
||||
height = info.ysize;
|
||||
|
||||
if (width < 1 || height < 1) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check if image has alpha channel */
|
||||
has_alpha = (info.alpha_bits > 0);
|
||||
|
||||
/* Set pixel format based on alpha channel presence */
|
||||
if (has_alpha) {
|
||||
format.num_channels = 4; /* RGBA */
|
||||
} else {
|
||||
format.num_channels = 3; /* RGB */
|
||||
}
|
||||
format.data_type = JXL_TYPE_UINT8;
|
||||
format.endianness = JXL_NATIVE_ENDIAN;
|
||||
format.align = 0;
|
||||
|
||||
} else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
||||
/* Allocate image with or without alpha */
|
||||
image = RCreateImage(width, height, has_alpha ? True : False);
|
||||
if (!image) {
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Determine buffer size */
|
||||
if (JxlDecoderImageOutBufferSize(dec, &format, &buffer_size) != JXL_DEC_SUCCESS) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
pixels = malloc(buffer_size);
|
||||
if (!pixels) {
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set output buffer */
|
||||
if (JxlDecoderSetImageOutBuffer(dec, &format, pixels, buffer_size) != JXL_DEC_SUCCESS) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
goto error;
|
||||
}
|
||||
} else if (status == JXL_DEC_FULL_IMAGE) {
|
||||
/* Image is ready, copy data directly for RGB or RGBA */
|
||||
if (has_alpha) {
|
||||
/* RGBA format - copy directly */
|
||||
memcpy(image->data, pixels, width * height * 4);
|
||||
} else {
|
||||
/* RGB format - copy directly */
|
||||
memcpy(image->data, pixels, width * height * 3);
|
||||
}
|
||||
break;
|
||||
} else if (status == JXL_DEC_SUCCESS) {
|
||||
/* All done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(data);
|
||||
free(pixels);
|
||||
JxlDecoderDestroy(dec);
|
||||
return image;
|
||||
|
||||
error:
|
||||
if (data)
|
||||
free(data);
|
||||
if (pixels)
|
||||
free(pixels);
|
||||
if (image)
|
||||
RReleaseImage(image);
|
||||
if (dec)
|
||||
JxlDecoderDestroy(dec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* USE_JXL */
|
||||
@@ -29,6 +29,7 @@ POTFILES = \
|
||||
$(top_srcdir)/wrlib/load_ppm.c \
|
||||
$(top_srcdir)/wrlib/load_gif.c \
|
||||
$(top_srcdir)/wrlib/load_jpeg.c \
|
||||
$(top_srcdir)/wrlib/load_jxl.c \
|
||||
$(top_srcdir)/wrlib/load_png.c \
|
||||
$(top_srcdir)/wrlib/load_tiff.c \
|
||||
$(top_srcdir)/wrlib/load_xpm.c \
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
# 1998-2006 Dan Pascu
|
||||
# 2013-2020 Window Maker Developers Team
|
||||
# This file is distributed under the same license as the Window Maker package.
|
||||
# Strahinya Radich (Страхиња Радић) <contact@strahinja.org>, 2023.
|
||||
# Strahinya Radich (Страхиња Радић) <sr@strahinja.org>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -11,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: wmaker-dev@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2023-11-02 19:43+0100\n"
|
||||
"PO-Revision-Date: 2023-11-02 19:48+0100\n"
|
||||
"Last-Translator: Страхиња Радић <contact@strahinja.org>\n"
|
||||
"Last-Translator: Страхиња Радић <sr@strahinja.org>\n"
|
||||
"Language-Team: Serbian <sr@li.org>\n"
|
||||
"Language: sr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+20
-1
@@ -3,7 +3,7 @@
|
||||
* Raster graphics library
|
||||
*
|
||||
* Copyright (c) 1998-2003 Alfredo K. Kojima
|
||||
* Copyright (c) 2013-2023 Window Maker Team
|
||||
* Copyright (c) 2013-2025 Window Maker Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
@@ -40,6 +40,25 @@ Bool RSaveImage(RImage *image, const char *filename, const char *format)
|
||||
return RSaveTitledImage(image, filename, format, NULL);
|
||||
}
|
||||
|
||||
Bool RSaveRawImage(RImage *image, const char *format, unsigned char **out_buf, size_t *out_size)
|
||||
{
|
||||
#ifdef USE_PNG
|
||||
if (strcasecmp(format, "PNG") == 0)
|
||||
return RSaveRawPNG(image, NULL, out_buf, out_size);
|
||||
#endif
|
||||
|
||||
#ifdef USE_JPEG
|
||||
if (strcasecmp(format, "JPG") == 0)
|
||||
return RSaveRawJPEG(image, NULL, out_buf, out_size);
|
||||
|
||||
if (strcasecmp(format, "JPEG") == 0)
|
||||
return RSaveRawJPEG(image, NULL, out_buf, out_size);
|
||||
#endif
|
||||
|
||||
RErrorCode = RERR_BADFORMAT;
|
||||
return False;
|
||||
}
|
||||
|
||||
Bool RSaveTitledImage(RImage *image, const char *filename, const char *format, char *title)
|
||||
{
|
||||
#ifdef USE_PNG
|
||||
|
||||
+120
-21
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Raster graphics library
|
||||
*
|
||||
* Copyright (c) 2023 Window Maker Team
|
||||
* Copyright (c) 2023-2025 Window Maker Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
@@ -33,39 +33,92 @@
|
||||
#include "imgformat.h"
|
||||
#include "wr_i18n.h"
|
||||
|
||||
/* Structure for JPEG memory destination */
|
||||
struct jpeg_mem_data {
|
||||
unsigned char **out_buf;
|
||||
size_t *out_size;
|
||||
unsigned char *buffer;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
/* JPEG memory destination methods */
|
||||
static void jpeg_init_mem_destination(j_compress_ptr cinfo)
|
||||
{
|
||||
struct jpeg_mem_data *dest = (struct jpeg_mem_data *)cinfo->client_data;
|
||||
dest->buffer_size = 32768; /* Initial buffer size */
|
||||
dest->buffer = malloc(dest->buffer_size);
|
||||
if (!dest->buffer) {
|
||||
/* Memory allocation failed - will be caught by caller */
|
||||
dest->buffer_size = 0;
|
||||
return;
|
||||
}
|
||||
cinfo->dest->next_output_byte = dest->buffer;
|
||||
cinfo->dest->free_in_buffer = dest->buffer_size;
|
||||
}
|
||||
|
||||
static boolean jpeg_empty_mem_output_buffer(j_compress_ptr cinfo)
|
||||
{
|
||||
struct jpeg_mem_data *dest = (struct jpeg_mem_data *)cinfo->client_data;
|
||||
size_t old_size = dest->buffer_size;
|
||||
dest->buffer_size *= 2;
|
||||
dest->buffer = realloc(dest->buffer, dest->buffer_size);
|
||||
if (!dest->buffer) {
|
||||
/* Memory allocation failed - signal error */
|
||||
dest->buffer_size = 0;
|
||||
return FALSE;
|
||||
}
|
||||
cinfo->dest->next_output_byte = dest->buffer + old_size;
|
||||
cinfo->dest->free_in_buffer = dest->buffer_size - old_size;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void jpeg_term_mem_destination(j_compress_ptr cinfo)
|
||||
{
|
||||
struct jpeg_mem_data *dest = (struct jpeg_mem_data *)cinfo->client_data;
|
||||
*dest->out_size = dest->buffer_size - cinfo->dest->free_in_buffer;
|
||||
*dest->out_buf = dest->buffer;
|
||||
/* Don't free dest->buffer here - caller will free it */
|
||||
}
|
||||
|
||||
/*
|
||||
* Save RImage to JPEG image
|
||||
* Save RImage to JPEG data in memory
|
||||
*/
|
||||
|
||||
Bool RSaveJPEG(RImage *img, const char *filename, char *title)
|
||||
Bool RSaveRawJPEG(RImage *img, char *title, unsigned char **out_buf, size_t *out_size)
|
||||
{
|
||||
FILE *file;
|
||||
int x, y, img_depth;
|
||||
int x, y;
|
||||
char *buffer;
|
||||
RColor pixel;
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
struct jpeg_destination_mgr jpeg_dest;
|
||||
struct jpeg_mem_data mem_data;
|
||||
JSAMPROW row_pointer;
|
||||
|
||||
file = fopen(filename, "wb");
|
||||
if (!file) {
|
||||
RErrorCode = RERR_OPEN;
|
||||
return False;
|
||||
}
|
||||
|
||||
if (img->format == RRGBAFormat)
|
||||
img_depth = 4;
|
||||
else
|
||||
img_depth = 3;
|
||||
*out_buf = NULL;
|
||||
*out_size = 0;
|
||||
|
||||
/* collect separate RGB values to a buffer */
|
||||
buffer = malloc(sizeof(char) * 3 * img->width * img->height);
|
||||
if (!buffer) {
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
|
||||
for (y = 0; y < img->height; y++) {
|
||||
for (x = 0; x < img->width; x++) {
|
||||
RGetPixel(img, x, y, &pixel);
|
||||
buffer[y*img->width*3+x*3+0] = (char)(pixel.red);
|
||||
buffer[y*img->width*3+x*3+1] = (char)(pixel.green);
|
||||
buffer[y*img->width*3+x*3+2] = (char)(pixel.blue);
|
||||
/* Handle transparent pixels by converting them to white
|
||||
* since JPEG doesn't support transparency */
|
||||
if (pixel.alpha == 0) {
|
||||
buffer[y*img->width*3+x*3+0] = (char)255; /* white red */
|
||||
buffer[y*img->width*3+x*3+1] = (char)255; /* white green */
|
||||
buffer[y*img->width*3+x*3+2] = (char)255; /* white blue */
|
||||
} else {
|
||||
buffer[y*img->width*3+x*3+0] = (char)(pixel.red);
|
||||
buffer[y*img->width*3+x*3+1] = (char)(pixel.green);
|
||||
buffer[y*img->width*3+x*3+2] = (char)(pixel.blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +127,17 @@ Bool RSaveJPEG(RImage *img, const char *filename, char *title)
|
||||
|
||||
/* Initialize cinfo structure */
|
||||
jpeg_create_compress(&cinfo);
|
||||
jpeg_stdio_dest(&cinfo, file);
|
||||
|
||||
/* Set up custom memory destination */
|
||||
mem_data.out_buf = out_buf;
|
||||
mem_data.out_size = out_size;
|
||||
jpeg_dest.init_destination = jpeg_init_mem_destination;
|
||||
jpeg_dest.empty_output_buffer = jpeg_empty_mem_output_buffer;
|
||||
jpeg_dest.term_destination = jpeg_term_mem_destination;
|
||||
cinfo.dest = &jpeg_dest;
|
||||
cinfo.dest->next_output_byte = NULL;
|
||||
cinfo.dest->free_in_buffer = 0;
|
||||
cinfo.client_data = &mem_data;
|
||||
|
||||
cinfo.image_width = img->width;
|
||||
cinfo.image_height = img->height;
|
||||
@@ -90,15 +153,51 @@ Bool RSaveJPEG(RImage *img, const char *filename, char *title)
|
||||
jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET*)title, strlen(title));
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
row_pointer = (JSAMPROW) &buffer[cinfo.next_scanline * img_depth * img->width];
|
||||
row_pointer = (JSAMPROW) &buffer[cinfo.next_scanline * 3 * img->width];
|
||||
jpeg_write_scanlines(&cinfo, &row_pointer, 1);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
/* Clean */
|
||||
free(buffer);
|
||||
fclose(file);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save RImage to JPEG file
|
||||
*/
|
||||
|
||||
Bool RSaveJPEG(RImage *img, const char *filename, char *title)
|
||||
{
|
||||
FILE *file;
|
||||
unsigned char *jpeg_data;
|
||||
size_t jpeg_size;
|
||||
size_t written;
|
||||
|
||||
/* Generate JPEG data in memory */
|
||||
if (!RSaveRawJPEG(img, title, &jpeg_data, &jpeg_size)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Write to file */
|
||||
file = fopen(filename, "wb");
|
||||
if (!file) {
|
||||
free(jpeg_data);
|
||||
RErrorCode = RERR_OPEN;
|
||||
return False;
|
||||
}
|
||||
|
||||
written = fwrite(jpeg_data, 1, jpeg_size, file);
|
||||
fclose(file);
|
||||
free(jpeg_data);
|
||||
|
||||
if (written != jpeg_size) {
|
||||
RErrorCode = RERR_WRITE;
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
+112
-18
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Raster graphics library
|
||||
*
|
||||
* Copyright (c) 2023 Window Maker Team
|
||||
* Copyright (c) 2023-2025 Window Maker Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
@@ -33,12 +33,51 @@
|
||||
#include "imgformat.h"
|
||||
#include "wr_i18n.h"
|
||||
|
||||
/*
|
||||
* Save RImage to PNG image
|
||||
*/
|
||||
Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
/* Structure to hold PNG data in memory */
|
||||
struct png_mem_data {
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
/* Callback function to write PNG data to memory buffer */
|
||||
static void png_write_to_memory(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
struct png_mem_data *p = (struct png_mem_data *)png_get_io_ptr(png_ptr);
|
||||
size_t new_size = p->size + length;
|
||||
|
||||
/* Expand buffer if necessary */
|
||||
if (new_size > p->capacity) {
|
||||
size_t new_capacity = p->capacity ? p->capacity * 2 : 8192;
|
||||
while (new_capacity < new_size)
|
||||
new_capacity *= 2;
|
||||
|
||||
unsigned char *new_buffer = realloc(p->buffer, new_capacity);
|
||||
if (!new_buffer) {
|
||||
png_error(png_ptr, "Out of memory");
|
||||
return;
|
||||
}
|
||||
p->buffer = new_buffer;
|
||||
p->capacity = new_capacity;
|
||||
}
|
||||
|
||||
/* Copy data to buffer */
|
||||
memcpy(p->buffer + p->size, data, length);
|
||||
p->size += length;
|
||||
}
|
||||
|
||||
/* Dummy flush function for memory I/O */
|
||||
static void png_flush_memory(png_structp png_ptr)
|
||||
{
|
||||
/* No-op for memory I/O */
|
||||
(void)png_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save RImage to PNG data in memory
|
||||
*/
|
||||
Bool RSaveRawPNG(RImage *img, char *title, unsigned char **out_buf, size_t *out_size)
|
||||
{
|
||||
FILE *file;
|
||||
png_structp png_ptr;
|
||||
png_infop png_info_ptr;
|
||||
png_bytep png_row;
|
||||
@@ -46,17 +85,14 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
int x, y;
|
||||
int width = img->width;
|
||||
int height = img->height;
|
||||
struct png_mem_data png_data = {NULL, 0, 0};
|
||||
|
||||
file = fopen(filename, "wb");
|
||||
if (file == NULL) {
|
||||
RErrorCode = RERR_OPEN;
|
||||
return False;
|
||||
}
|
||||
*out_buf = NULL;
|
||||
*out_size = 0;
|
||||
|
||||
/* Initialize write structure */
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (png_ptr == NULL) {
|
||||
fclose(file);
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
@@ -64,19 +100,22 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
/* Initialize info structure */
|
||||
png_info_ptr = png_create_info_struct(png_ptr);
|
||||
if (png_info_ptr == NULL) {
|
||||
fclose(file);
|
||||
png_destroy_write_struct(&png_ptr, NULL);
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Setup Exception handling */
|
||||
if (setjmp(png_jmpbuf (png_ptr))) {
|
||||
fclose(file);
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
if (png_data.buffer)
|
||||
free(png_data.buffer);
|
||||
png_destroy_write_struct(&png_ptr, &png_info_ptr);
|
||||
RErrorCode = RERR_INTERNAL;
|
||||
return False;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, file);
|
||||
/* Set up memory I/O */
|
||||
png_set_write_fn(png_ptr, &png_data, png_write_to_memory, png_flush_memory);
|
||||
|
||||
/* Write header (8 bit colour depth) */
|
||||
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
|
||||
@@ -96,6 +135,13 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
|
||||
/* Allocate memory for one row (3 bytes per pixel - RGB) */
|
||||
png_row = (png_bytep) malloc(3 * width * sizeof(png_byte));
|
||||
if (!png_row) {
|
||||
if (png_data.buffer)
|
||||
free(png_data.buffer);
|
||||
png_destroy_write_struct(&png_ptr, &png_info_ptr);
|
||||
RErrorCode = RERR_NOMEMORY;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Write image data */
|
||||
for (y = 0; y < height; y++) {
|
||||
@@ -114,8 +160,7 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
/* End write */
|
||||
png_write_end(png_ptr, NULL);
|
||||
|
||||
/* Clean */
|
||||
fclose(file);
|
||||
/* Clean up structures */
|
||||
if (png_info_ptr != NULL)
|
||||
png_free_data(png_ptr, png_info_ptr, PNG_FREE_ALL, -1);
|
||||
if (png_ptr != NULL)
|
||||
@@ -123,5 +168,54 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
if (png_row != NULL)
|
||||
free(png_row);
|
||||
|
||||
/* Return the buffer */
|
||||
*out_buf = png_data.buffer;
|
||||
*out_size = png_data.size;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save RImage to PNG image
|
||||
*/
|
||||
Bool RSavePNG(RImage *img, const char *filename, char *title)
|
||||
{
|
||||
FILE *file;
|
||||
unsigned char *png_data = NULL;
|
||||
size_t png_size = 0;
|
||||
size_t written;
|
||||
|
||||
if (!img || !filename) {
|
||||
RErrorCode = RERR_BADIMAGEFILE;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Use RSaveRawPNG to generate PNG data in memory */
|
||||
if (!RSaveRawPNG(img, title, &png_data, &png_size)) {
|
||||
/* Error code already set by RSaveRawPNG */
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Open file for writing */
|
||||
file = fopen(filename, "wb");
|
||||
if (file == NULL) {
|
||||
free(png_data);
|
||||
RErrorCode = RERR_OPEN;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Write PNG data to file */
|
||||
written = fwrite(png_data, 1, png_size, file);
|
||||
fclose(file);
|
||||
|
||||
/* Check if all data was written */
|
||||
if (written != png_size) {
|
||||
free(png_data);
|
||||
RErrorCode = RERR_WRITE;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
free(png_data);
|
||||
return True;
|
||||
}
|
||||
|
||||
+24
-3
@@ -244,8 +244,25 @@ static double Mitchell_filter(double t)
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
static double (*filterf)(double) = Mitchell_filter;
|
||||
static double fwidth = Mitchell_support;
|
||||
#define CatmullRom_support (2.0)
|
||||
|
||||
static double CatmullRom_filter(double t)
|
||||
{
|
||||
double tt;
|
||||
|
||||
tt = t * t;
|
||||
if (t < 0)
|
||||
t = -t;
|
||||
if (t < 1.0) {
|
||||
return ((1.5 * t * tt) - (2.5 * tt) + 1.0);
|
||||
} else if (t < 2.0) {
|
||||
return ((-0.5 * t * tt) + (2.5 * tt) - (4.0 * t) + 2.0);
|
||||
}
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
static double (*filterf)(double) = CatmullRom_filter;
|
||||
static double fwidth = CatmullRom_support;
|
||||
|
||||
void wraster_change_filter(RScalingFilter type)
|
||||
{
|
||||
@@ -270,11 +287,15 @@ void wraster_change_filter(RScalingFilter type)
|
||||
filterf = Lanczos3_filter;
|
||||
fwidth = Lanczos3_support;
|
||||
break;
|
||||
default:
|
||||
case RMitchellFilter:
|
||||
filterf = Mitchell_filter;
|
||||
fwidth = Mitchell_support;
|
||||
break;
|
||||
default:
|
||||
case RCatmullRomFilter:
|
||||
filterf = CatmullRom_filter;
|
||||
fwidth = CatmullRom_support;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -143,7 +143,8 @@ typedef enum {
|
||||
RBellFilter,
|
||||
RBSplineFilter,
|
||||
RLanczos3Filter,
|
||||
RMitchellFilter
|
||||
RMitchellFilter,
|
||||
RCatmullRomFilter
|
||||
} RScalingFilter;
|
||||
|
||||
|
||||
@@ -391,6 +392,9 @@ RImage *RGetImageFromXPMData(RContext *context, char **xpmData)
|
||||
Bool RSaveImage(RImage *image, const char *filename, const char *format)
|
||||
__wrlib_nonnull(1, 2, 3);
|
||||
|
||||
Bool RSaveRawImage(RImage *image, const char *format, unsigned char **out_buf, size_t *out_size)
|
||||
__wrlib_nonnull(1, 2, 3, 4);
|
||||
|
||||
Bool RSaveTitledImage(RImage *image, const char *filename, const char *format, char *title)
|
||||
__wrlib_nonnull(1, 2, 3);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user