Download raw body.
fvwm(1): replace GPL-licensed code, fix bugs and add improvements
Hello everyone,
I have attached a patch to this email that focuses on three major areas:
First, FvwmRearrange has been completely rewritten to provide clearer
behavior, and the documentation has been updated. It now cleanly
separates tile and cascade modes, tightens argument semantics, and
behaves predictably with multiple monitors and large virtual desktops.
Second, the core and modules have transitioned to a safer
infrastructure. The legacy temp-file IPC has been replaced with pipes
and waitpid(). The key/placement logic is more robust, and the
widespread string/memory handling has been tightened (snprintf/strlcpy
and better bounds/NULL checks). Along the way, long-standing correctness
issues have been fixed, such as maximizing across virtual pages,
destroying live menus, and occasional PipeRead hangs.
Third, licensing is clarified across the tree. The COPYRIGHT file has
been updated, and GPL-licensed remnants have been replaced with
components under the ISC/OpenBSD license, including the new rearrange
code and color utilities. This aligns the codebase with the project's
stated copyright policy.
These changes aim to preserve backward compatibility with existing
configurations. I tested it on amd64, but not thoroughly. Further
testing, as well as compiling and testing on other platforms, is needed.
Best regards,
David.
Index: app/fvwm/COPYING
===================================================================
RCS file: /cvs/xenocara/app/fvwm/COPYING,v
diff -u -p -u -r1.1.1.1 COPYING
--- app/fvwm/COPYING 26 Nov 2006 10:53:04 -0000 1.1.1.1
+++ app/fvwm/COPYING 25 Oct 2025 19:27:18 -0000
@@ -1,3 +1,8 @@
+FVWM Licensing Terms and Conditions
+===================================
+
+General Terms
+-------------
Permission is granted to distribute all software within this
distribution freely as long as the individual copyrights,
copyright notices and associated disclaimers remain intact
@@ -11,29 +16,9 @@ THIS PACKAGE IS PROVIDED "AS IS" AND WIT
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------
-
-In addition - with the exception of the following directories
-and all files within:
-
- modules/FvwmRearrange
- extras/FvwmPipe
- modules/FvwmAnimate
- modules/FvwmAudio
- modules/FvwmEvents
-
-- permission is granted to use this software for any purpose, as
-long as the individual copyrights, copyright notices and
-associated disclaimers remain intact in the sources and the
-supporting documentation. The following pieces of software are
-exempt from this statement.
-
-The modules modules/FvwmAnimate, modules/FvwmAudio and modules/FvwmEvents
-are subject to the GNU public license (see below).
-
-----------------------------------------------------------------------
-
-The copyrights of the fvwm main module are:
+FVWM Main Module
+----------------
+The FVWM main module is distributed under the following license:
fvwm is copyright 1988 by Evans and Sutherland Computer
Corporation, Salt Lake City, Utah, and 1989 by the Massachusetts
@@ -58,314 +43,25 @@ USE, DATA OR PROFITS, WHETHER IN AN ACTI
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
--------------------------------------------------------------------------
+Additional Component Licenses
+-----------------------------
+The following pieces of software are distributed under the ISC License:
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ libs/ColorUtils.c
+ modules/FvwmRearrange
+ modules/FvwmBacker/root_bits.c
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- 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
+ISC License
+-----------
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Index: app/fvwm/docs/BUGS
===================================================================
RCS file: /cvs/xenocara/app/fvwm/docs/BUGS,v
diff -u -p -u -r1.1.1.1 BUGS
--- app/fvwm/docs/BUGS 26 Nov 2006 10:53:06 -0000 1.1.1.1
+++ app/fvwm/docs/BUGS 25 Oct 2025 19:27:19 -0000
@@ -9,7 +9,6 @@ from our home page.
======================================================================
======================================================================
- - No geometry can be specified for FvwmButtons panels.
- Running fvwm2 on an XNest X server does not work well.
- FvwmSave and FvwmSaveDesk are not up to date.
- The fvwm_convert script is not up to date.
@@ -18,14 +17,6 @@ from our home page.
server.
- AutoHide in FvwmTaskBar does not work well. See 'EdgeThickness' command in
the manpage.
- - DestroyMenu/DestroyFunc causes a coredump if a function/menu destroys
- itself.
- - Maximize does not work well when applied to a window that is not on
- the current page.
- - A piperead command may hang if used in .fvwm2rc (if the pipe is never
- closed).
- - StartsOnPage does not work as expected? Please read the manpage carefully.
-
======================================================================
======================================================================
Index: app/fvwm/fvwm/bindings.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/bindings.c,v
diff -u -p -u -r1.1.1.1 bindings.c
--- app/fvwm/fvwm/bindings.c 26 Nov 2006 10:53:23 -0000 1.1.1.1
+++ app/fvwm/fvwm/bindings.c 25 Oct 2025 19:27:19 -0000
@@ -119,7 +119,6 @@ void ParseBindEntry(XEvent *eventp,Windo
int button,i,min,max;
int n1=0,n2=0,n3=0;
KeySym keysym;
- KeySym tkeysym;
int contexts;
int mods;
int maxmods;
@@ -248,13 +247,38 @@ void ParseBindEntry(XEvent *eventp,Windo
max = button;
maxmods = 0;
}
- for (i=min; i<=max; i++)
+ for (i = min; i <= max; i++)
{
- /* If this is a mouse binding we'll fall through the for loop (maxmods is
- * zero) and the if condition is always true (fKey is zero). Since min ==
- * max == button there is no loop at all is case of a mouse binding. */
- for (m = 0, tkeysym = XK_Left; m <= maxmods && tkeysym != NoSymbol; m++)
- if (!fKey || (tkeysym = XKeycodeToKeysym(dpy, i, m)) == keysym)
+ KeySym *mapping = NULL;
+ int mapping_width = 0;
+ int column_limit = maxmods;
+
+ if (fKey)
+ {
+ mapping = XGetKeyboardMapping(dpy, i, 1, &mapping_width);
+ if (mapping == NULL || mapping_width <= 0)
+ {
+ if (mapping)
+ XFree(mapping);
+ continue;
+ }
+ column_limit = mapping_width - 1;
+ if (column_limit > maxmods)
+ column_limit = maxmods;
+ }
+
+ for (m = 0; m <= column_limit; m++)
+ {
+ KeySym current = NoSymbol;
+
+ if (fKey)
+ {
+ current = mapping[m];
+ if (current == NoSymbol)
+ break;
+ }
+
+ if (!fKey || current == keysym)
{
temp = Scr.AllBindings;
Scr.AllBindings = (Binding *)safemalloc(sizeof(Binding));
@@ -266,6 +290,10 @@ void ParseBindEntry(XEvent *eventp,Windo
Scr.AllBindings->Action = stripcpy(action);
Scr.AllBindings->NextBinding = temp;
}
+ }
+
+ if (mapping)
+ XFree(mapping);
}
return;
}
Index: app/fvwm/fvwm/builtins.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/builtins.c,v
diff -u -p -u -r1.2 builtins.c
--- app/fvwm/fvwm/builtins.c 24 Jan 2021 09:47:56 -0000 1.2
+++ app/fvwm/fvwm/builtins.c 25 Oct 2025 19:27:19 -0000
@@ -314,6 +314,22 @@ void WarpOn(FvwmWindow *t,int warp_x, in
* (Un)Maximize a window.
*
***********************************************************************/
+static int
+virtual_page_origin(int coordinate, int span)
+{
+ int base;
+
+ if (span <= 0)
+ return 0;
+ if (coordinate >= 0)
+ return (coordinate / span) * span;
+
+ base = -((-coordinate) / span) * span;
+ if ((-coordinate) % span != 0)
+ base -= span;
+ return base;
+}
+
void Maximize(XEvent *eventp,Window w,FvwmWindow *tmp_win,
unsigned long context, char *action, int *Module)
{
@@ -357,20 +373,31 @@ void Maximize(XEvent *eventp,Window w,Fv
new_height = tmp_win->frame_height;
new_x = tmp_win->frame_x;
new_y = tmp_win->frame_y;
+#ifndef NON_VIRTUAL
+ {
+ const int page_x = virtual_page_origin(tmp_win->frame_x,
+ Scr.MyDisplayWidth);
+ const int page_y = virtual_page_origin(tmp_win->frame_y,
+ Scr.MyDisplayHeight);
+#else
+ {
+ const int page_x = 0;
+ const int page_y = 0;
+#endif
if(val1 >0)
{
new_width = val1*val1_unit/100-2;
- new_x = 0;
+ new_x = page_x;
}
if(val2 >0)
{
new_height = val2*val2_unit/100-2;
- new_y = 0;
+ new_y = page_y;
}
if((val1==0)&&(val2==0))
{
- new_x = 0;
- new_y = 0;
+ new_x = page_x;
+ new_y = page_y;
new_height = Scr.MyDisplayHeight-2;
new_width = Scr.MyDisplayWidth-2;
}
@@ -378,6 +405,7 @@ void Maximize(XEvent *eventp,Window w,Fv
ConstrainSize (tmp_win, &new_width, &new_height, False, 0, 0);
SetupFrame(tmp_win,new_x,new_y,new_width,new_height,TRUE);
SetBorder(tmp_win,Scr.Hilite == tmp_win,True,True,None);
+ }
}
}
@@ -560,6 +588,8 @@ void destroy_menu(XEvent *eventp,Window
free(token);
while (mr)
{
+ if (mr == last_menu)
+ last_menu = NULL;
mrContinuation = mr->continuation; /* save continuation before destroy */
DestroyMenu(mr);
mr = mrContinuation;
Index: app/fvwm/fvwm/events.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/events.c,v
diff -u -p -u -r1.2 events.c
--- app/fvwm/fvwm/events.c 24 Jan 2021 09:50:25 -0000 1.2
+++ app/fvwm/fvwm/events.c 25 Oct 2025 19:27:19 -0000
@@ -382,11 +382,23 @@ void HandleKeyPress()
Context = GetContext(Tmp_win,&Event, &PressedW);
PressedW = None;
- /* Here's a real hack - some systems have two keys with the
- * same keysym and different keycodes. This converts all
- * the cases to one keycode. */
- Event.xkey.keycode =
- XKeysymToKeycode(dpy,XKeycodeToKeysym(dpy,Event.xkey.keycode,0));
+ /* Normalize keycodes that map to the same keysym. */
+ {
+ KeySym *mapping;
+ int width;
+
+ mapping = XGetKeyboardMapping(dpy, Event.xkey.keycode, 1, &width);
+ if (mapping != NULL && width > 0)
+ {
+ KeySym primary = mapping[0];
+ KeyCode canonical = XKeysymToKeycode(dpy, primary);
+
+ if (canonical != 0)
+ Event.xkey.keycode = canonical;
+ }
+ if (mapping != NULL)
+ XFree(mapping);
+ }
for (key = Scr.AllBindings; key != NULL; key = key->NextBinding)
{
Index: app/fvwm/fvwm/fvwm.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/fvwm.c,v
diff -u -p -u -r1.3 fvwm.c
--- app/fvwm/fvwm/fvwm.c 15 Apr 2017 17:18:01 -0000 1.3
+++ app/fvwm/fvwm/fvwm.c 25 Oct 2025 19:27:19 -0000
@@ -1399,10 +1399,10 @@ void InitVariables(void)
Scr.StipledTitles = False;
/* RBW - 11/02/1998 */
- Scr.go.ModifyUSP = True;
- Scr.go.CaptureHonorsStartsOnPage = True;
- Scr.go.RecaptureHonorsStartsOnPage = False;
- Scr.go.ActivePlacementHonorsStartsOnPage = False;
+ Scr.go.ModifyUSP = 1U;
+ Scr.go.CaptureHonorsStartsOnPage = 1U;
+ Scr.go.RecaptureHonorsStartsOnPage = 0U;
+ Scr.go.ActivePlacementHonorsStartsOnPage = 0U;
Scr.gs.EmulateMWM = False;
Scr.gs.EmulateWIN = False;
Index: app/fvwm/fvwm/fvwm2.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/fvwm2.1,v
diff -u -p -u -r1.2 fvwm2.1
--- app/fvwm/fvwm/fvwm2.1 19 Oct 2019 16:39:49 -0000 1.2
+++ app/fvwm/fvwm/fvwm2.1 25 Oct 2025 19:27:19 -0000
@@ -2883,17 +2883,12 @@ rate of bug discovery we should expect t
4.27e+27 years. I guess I better plan on passing this thing on to my
children....
-Known bugs can be found in the BUGS file in the distribution, in
-the fvwm bug tracking system (accessible from the fvwm home page) and
-in the TO-DO list.
-
-Bug reports can be sent to the FVWM workers' mailing list (see the FAQ).
+Known bugs can be found in the BUGS file and TO-DO list in the
+distribution.
.SH AUTHOR
Robert Nation with help from many people, based on \fItwm\fP code,
-which was written by Tom LaStrange. After Robert Nation came Charles Hines,
-followed by Brady Montz. Currently fvwm is maintained by a number of people
-on the fvwm-workers mailing list (Dan Espen, Steve Robbins, Paul Smith,
-Jason Tibbitts, Dominik Vogt, Bob Woodside and others).
-
-The official FVWM homepage is http://www.fvwm.org/.
+which was written by Tom LaStrange. After Robert Nation came Charles
+Hines, followed by Brady Montz. Currently fvwm is maintained by a long
+list of people (Dan Espen, Steve Robbins, Paul Smith, Jason Tibbitts,
+Dominik Vogt, Bob Woodside and others).
Index: app/fvwm/fvwm/icons.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/icons.c,v
diff -u -p -u -r1.1.1.1 icons.c
--- app/fvwm/fvwm/icons.c 26 Nov 2006 10:53:30 -0000 1.1.1.1
+++ app/fvwm/fvwm/icons.c 25 Oct 2025 19:27:19 -0000
@@ -338,7 +338,7 @@ void RedoIconName(FvwmWindow *Tmp_win)
if(Tmp_win->flags & SUPPRESSICON)
return;
- if (Tmp_win->icon_w == (int)NULL)
+ if (Tmp_win->icon_w == None)
return;
Tmp_win->icon_t_width = XTextWidth(Scr.IconFont.font,Tmp_win->icon_name,
Index: app/fvwm/fvwm/menus.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/menus.c,v
diff -u -p -u -r1.2 menus.c
--- app/fvwm/fvwm/menus.c 18 Jan 2011 19:28:33 -0000 1.2
+++ app/fvwm/fvwm/menus.c 25 Oct 2025 19:27:19 -0000
@@ -2179,6 +2179,17 @@ void DestroyMenu(MenuRoot *mr)
if(mr == NULL)
return;
+ if (mr->in_use)
+ {
+ PopDownMenu(mr);
+ mr->in_use = 0;
+ if (mr->mrDynamicPrev && mr->mrDynamicPrev->selected &&
+ MrPopupForMi(mr->mrDynamicPrev->selected) == mr)
+ {
+ mr->mrDynamicPrev->selected = NULL;
+ }
+ }
+
tmp = Scr.menus.all;
prev = NULL;
while((tmp != NULL)&&(tmp != mr))
Index: app/fvwm/fvwm/misc.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/misc.c,v
diff -u -p -u -r1.1.1.1 misc.c
--- app/fvwm/fvwm/misc.c 26 Nov 2006 10:53:32 -0000 1.1.1.1
+++ app/fvwm/fvwm/misc.c 25 Oct 2025 19:27:19 -0000
@@ -1110,7 +1110,7 @@ void HandleHardFocus(FvwmWindow *t)
** type -> DBG == Debug, ERR == Error, INFO == Information, WARN == Warning
** id -> name of function, or other identifier
*/
-void fvwm_msg(int type,char *id,char *msg,...)
+void fvwm_msg(int type, const char *id, const char *msg, ...)
{
char *typestr;
va_list args1, args2;
Index: app/fvwm/fvwm/misc.h
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/misc.h,v
diff -u -p -u -r1.1.1.1 misc.h
--- app/fvwm/fvwm/misc.h 26 Nov 2006 10:53:32 -0000 1.1.1.1
+++ app/fvwm/fvwm/misc.h 25 Oct 2025 19:27:19 -0000
@@ -482,7 +482,7 @@ void CoerceEnterNotifyOnCurrentWindow();
#define INFO 0
#define WARN 1
#define ERR 2
-void fvwm_msg(int type,char *id,char *msg,...);
+void fvwm_msg(int type, const char *id, const char *msg, ...);
#endif /* MISC_H */
Index: app/fvwm/fvwm/placement.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/placement.c,v
diff -u -p -u -r1.1.1.1 placement.c
--- app/fvwm/fvwm/placement.c 26 Nov 2006 10:53:33 -0000 1.1.1.1
+++ app/fvwm/fvwm/placement.c 25 Oct 2025 19:27:19 -0000
@@ -471,7 +471,7 @@ Bool PlaceWindow(FvwmWindow *tmp_win, un
/*
we have a USPosition, and overriding it is disallowed...
*/
- if (!PPosOverride && (USPosition && !Scr.go.ModifyUSP))
+ if (!PPosOverride && ((USPosition != 0) && !Scr.go.ModifyUSP))
{
HonorStartsOnPage = False;
}
@@ -550,26 +550,33 @@ Bool PlaceWindow(FvwmWindow *tmp_win, un
*/
if (!(tflag & STICKY_FLAG) && (tflag & STARTSONDESK_FLAG))
{
- if (PageX && PageY)
+ if (PageX || PageY)
{
- px = PageX - 1;
- py = PageY -1 ;
- px *= Scr.MyDisplayWidth;
- py *= Scr.MyDisplayHeight;
- if ( (!PPosOverride) && (!(tmp_win->flags & SHOW_ON_MAP)) )
+ int current_px = (Scr.MyDisplayWidth != 0)
+ ? Scr.Vx / Scr.MyDisplayWidth : 0;
+ int current_py = (Scr.MyDisplayHeight != 0)
+ ? Scr.Vy / Scr.MyDisplayHeight : 0;
+
+ px = (PageX != 0)
+ ? ((PageX > 0) ? PageX - 1 : PageX)
+ : current_px;
+ py = (PageY != 0)
+ ? ((PageY > 0) ? PageY - 1 : PageY)
+ : current_py;
+
+ px *= Scr.MyDisplayWidth;
+ py *= Scr.MyDisplayHeight;
+
+ if ((!PPosOverride) && (!(tmp_win->flags & SHOW_ON_MAP)))
{
MoveViewport(px,py,True);
}
- else
+ else if (HonorStartsOnPage)
{
- if (HonorStartsOnPage)
- {
- /* Save the delta from current page */
- pdeltax = Scr.Vx - px;
- pdeltay = Scr.Vy - py;
- PageRight -= pdeltax;
- PageBottom -= pdeltay;
- }
+ pdeltax = Scr.Vx - px;
+ pdeltay = Scr.Vy - py;
+ PageRight -= pdeltax;
+ PageBottom -= pdeltay;
}
}
}
Index: app/fvwm/fvwm/read.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/read.c,v
diff -u -p -u -r1.1.1.1 read.c
--- app/fvwm/fvwm/read.c 26 Nov 2006 10:53:33 -0000 1.1.1.1
+++ app/fvwm/fvwm/read.c 25 Oct 2025 19:27:19 -0000
@@ -19,6 +19,11 @@
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/wait.h>
#include "fvwm.h"
#include "menus.h"
@@ -37,6 +42,118 @@ static int last_read_failed=0;
static const char *read_system_rc_cmd="Read system"FVWMRC;
+typedef struct
+{
+ FILE *stream;
+ pid_t pid;
+ int fd;
+} PipeChild;
+
+#define PIPE_READ_INTERVAL_SEC 1
+#define PIPE_READ_MAX_IDLE_LOOPS 10
+#define PIPE_REAP_WAIT_USEC 100000
+#define PIPE_REAP_ATTEMPTS 20
+
+static int
+start_pipe_process(const char *command, PipeChild *child)
+{
+ int pipe_fd[2];
+ pid_t pid;
+
+ if (pipe(pipe_fd) < 0)
+ return -1;
+
+ pid = fork();
+ if (pid < 0)
+ {
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return -1;
+ }
+
+ if (pid == 0)
+ {
+ close(pipe_fd[0]);
+ if (dup2(pipe_fd[1], STDOUT_FILENO) == -1)
+ _exit(127);
+ close(pipe_fd[1]);
+ execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+ _exit(127);
+ }
+
+ close(pipe_fd[1]);
+ child->fd = pipe_fd[0];
+ child->stream = fdopen(child->fd, "r");
+ if (child->stream == NULL)
+ {
+ close(child->fd);
+ kill(pid, SIGTERM);
+ (void)waitpid(pid, NULL, 0);
+ child->fd = -1;
+ return -1;
+ }
+ fcntl(child->fd, F_SETFD, 1);
+ child->pid = pid;
+ return 0;
+}
+
+static void
+stop_pipe_process(PipeChild *child, int timed_out,
+ const char *cmdname, const char *command)
+{
+ int status;
+ int attempt;
+ pid_t waited = -1;
+
+ if (child->stream)
+ {
+ fclose(child->stream);
+ child->stream = NULL;
+ }
+
+ if (child->fd >= 0)
+ child->fd = -1;
+
+ if (child->pid <= 0)
+ return;
+
+ if (timed_out)
+ {
+ fvwm_msg(WARN, cmdname,
+ "command '%s' did not close pipe, terminating it", command);
+ kill(child->pid, SIGTERM);
+ }
+
+ for (attempt = 0; attempt < PIPE_REAP_ATTEMPTS; ++attempt)
+ {
+ waited = waitpid(child->pid, &status, timed_out ? WNOHANG : 0);
+ if (waited == child->pid)
+ break;
+ if (waited == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ if (errno != ECHILD)
+ fvwm_msg(ERR, cmdname,
+ "waitpid failed for '%s': %s",
+ command, strerror(errno));
+ break;
+ }
+ if (waited == 0)
+ usleep(PIPE_REAP_WAIT_USEC);
+ }
+
+ if (timed_out && waited != child->pid)
+ {
+ kill(child->pid, SIGKILL);
+ while ((waited = waitpid(child->pid, &status, 0)) == -1 &&
+ errno == EINTR)
+ ;
+ }
+
+ child->pid = -1;
+}
+
extern void StartupStuff(void);
@@ -52,11 +169,14 @@ static void ReadSubFunc(XEvent *eventp,W
char *filename= NULL,*Home, *home_file, *ofilename = NULL;
char *option; /* optional arg to read */
char *rest,*tline,line[1024];
- FILE *fd;
+ FILE *stream = NULL;
+ PipeChild child = { NULL, -1, -1 };
int thisfileno;
char missing_quiet; /* missing file msg control */
char *cmdname;
size_t len;
+ int timed_out = 0;
+ int idle_loops = 0;
/* domivogt (30-Dec-1998: I tried using conditional evaluation instead
* of the cmdname variable ( piperead?"PipeRead":"Read" ), but gcc seems
@@ -89,93 +209,141 @@ static void ReadSubFunc(XEvent *eventp,W
free(option); /* arg not needed after this */
} /* end there is a second arg */
- filename = ofilename;
-/* fvwm_msg(INFO, cmdname,"trying '%s'",filename); */
-
if (piperead)
- fd = popen(filename,"r");
- else if (ofilename[0] != '/')
- {
- /* find the home directory to look in */
- Home = getenv("HOME");
- if (Home != NULL)
- {
- len = strlen(Home) + strlen(ofilename) + 3;
- home_file = safemalloc(len);
- strlcpy(home_file,Home,len);
- strlcat(home_file,"/",len);
- strlcat(home_file,ofilename,len);
- filename = home_file;
- fd = fopen(filename,"r");
- }
- else
- {
- fd = 0;
- }
- if (fd == 0)
- {
- if((filename != NULL)&&(filename!= ofilename))
- free(filename);
- /* find the home directory to look in */
- Home = FVWM_CONFIGDIR;
- len = strlen(Home) + strlen(ofilename) + 3;
- home_file = safemalloc(len);
- strlcpy(home_file,Home,len);
- strlcat(home_file,"/",len);
- strlcat(home_file,ofilename,len);
- filename = home_file;
- fd = fopen(filename,"r");
+ {
+ child.pid = -1;
+ child.fd = -1;
+ child.stream = NULL;
+ if (start_pipe_process(ofilename, &child) == 0)
+ stream = child.stream;
}
- }
else
- {
- /* open file with absolute path */
- fd = fopen(filename,"r");
- }
+ {
+ filename = ofilename;
+ if (ofilename[0] != '/')
+ {
+ Home = getenv("HOME");
+ if (Home != NULL)
+ {
+ len = strlen(Home) + strlen(ofilename) + 3;
+ home_file = safemalloc(len);
+ strlcpy(home_file,Home,len);
+ strlcat(home_file,"/",len);
+ strlcat(home_file,ofilename,len);
+ filename = home_file;
+ stream = fopen(filename,"r");
+ }
+ else
+ {
+ stream = NULL;
+ }
+ if (stream == NULL)
+ {
+ if((filename != NULL)&&(filename!= ofilename))
+ free(filename);
+ Home = FVWM_CONFIGDIR;
+ len = strlen(Home) + strlen(ofilename) + 3;
+ home_file = safemalloc(len);
+ strlcpy(home_file,Home,len);
+ strlcat(home_file,"/",len);
+ strlcat(home_file,ofilename,len);
+ filename = home_file;
+ stream = fopen(filename,"r");
+ }
+ }
+ else
+ {
+ stream = fopen(filename,"r");
+ }
+ }
- if(fd == NULL)
+ if(stream == NULL)
{
- if (missing_quiet == 'n') { /* if quiet option not on */
+ if (missing_quiet == 'n')
+ {
if (piperead)
- fvwm_msg(ERR, cmdname, "command '%s' not run", ofilename);
+ fvwm_msg(ERR, cmdname, "command '%s' not run", ofilename);
else
- fvwm_msg(ERR, cmdname,
- "file '%s' not found in $HOME or "FVWM_CONFIGDIR, ofilename);
- } /* end quiet option not on */
- if((ofilename != filename)&&(filename != NULL))
- {
- free(filename);
+ fvwm_msg(ERR, cmdname,
+ "file '%s' not found in $HOME or "FVWM_CONFIGDIR, ofilename);
}
- if(ofilename != NULL)
- {
+ if (!piperead && filename && filename != ofilename)
+ free(filename);
+ if (piperead && child.pid > 0)
+ stop_pipe_process(&child, 1, cmdname, ofilename);
+ if (piperead || (filename != ofilename))
free(ofilename);
- }
last_read_failed = 1;
return;
}
- if((ofilename != NULL)&&(filename!= ofilename))
- free(ofilename);
- fcntl(fileno(fd), F_SETFD, 1);
+
if (!piperead)
{
+ if (filename != ofilename && ofilename != NULL)
+ {
+ free(ofilename);
+ ofilename = NULL;
+ }
+ fcntl(fileno(stream), F_SETFD, 1);
if(fvwm_file != NULL)
free(fvwm_file);
fvwm_file = filename;
}
- else
- {
- if (filename)
- free(filename);
- }
- tline = fgets(line,(sizeof line)-1,fd);
- while(tline)
+ while(stream && !timed_out)
{
- int l;
- while(tline && (l = strlen(line)) < sizeof(line) && l >= 2 &&
- line[l-2]=='\\' && line[l-1]=='\n')
+ if (piperead)
+ {
+ fd_set readfds;
+ struct timeval tv;
+ int ready;
+
+ FD_ZERO(&readfds);
+ FD_SET(child.fd, &readfds);
+ tv.tv_sec = PIPE_READ_INTERVAL_SEC;
+ tv.tv_usec = 0;
+
+ ready = select(child.fd + 1, &readfds, NULL, NULL, &tv);
+ if (ready < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ timed_out = 1;
+ break;
+ }
+ if (ready == 0)
+ {
+ if (++idle_loops >= PIPE_READ_MAX_IDLE_LOOPS)
+ {
+ timed_out = 1;
+ break;
+ }
+ continue;
+ }
+ idle_loops = 0;
+ }
+
+ tline = fgets(line,(sizeof line)-1,stream);
+ if(tline == NULL)
{
- tline = fgets(line+l-2,sizeof(line)-l+1,fd);
+ if (!piperead || feof(stream))
+ break;
+ if (ferror(stream))
+ {
+ clearerr(stream);
+ continue;
+ }
+ break;
+ }
+ {
+ int l;
+ while((l = strlen(line)) < sizeof(line) && l >= 2 &&
+ line[l-2]=='\\' && line[l-1]=='\n')
+ {
+ char *cont = fgets(line+l-2,sizeof(line)-l+1,stream);
+ if (cont == NULL)
+ break;
+ }
}
tline=line;
while(isspace(*tline))
@@ -185,14 +353,15 @@ static void ReadSubFunc(XEvent *eventp,W
fvwm_msg(DBG,"ReadSubFunc","about to exec: '%s'",tline);
}
ExecuteFunction(tline,tmp_win,eventp,context,*Module);
- tline = fgets(line,(sizeof line)-1,fd);
}
if (piperead)
- pclose(fd);
+ stop_pipe_process(&child, timed_out, cmdname, ofilename);
else
- fclose(fd);
- last_read_failed = 0;
+ fclose(stream);
+ if (piperead && ofilename)
+ free(ofilename);
+ last_read_failed = timed_out;
}
void ReadFile(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
Index: app/fvwm/fvwm/screen.h
===================================================================
RCS file: /cvs/xenocara/app/fvwm/fvwm/screen.h,v
diff -u -p -u -r1.2 screen.h
--- app/fvwm/fvwm/screen.h 18 Jan 2011 19:28:33 -0000 1.2
+++ app/fvwm/fvwm/screen.h 25 Oct 2025 19:27:19 -0000
@@ -322,18 +322,18 @@ typedef struct ScreenInfo
int ClickToFocusRaises;
int MouseFocusClickRaises;
int StipledTitles;
- struct
- {
- Bool ModifyUSP : 1; /* - RBW - 11/02/1998 */
- Bool CaptureHonorsStartsOnPage : 1; /* - RBW - 11/02/1998 */
- Bool RecaptureHonorsStartsOnPage : 1; /* - RBW - 11/02/1998 */
- Bool ActivePlacementHonorsStartsOnPage : 1; /* - RBW - 11/02/1998 */
- } go; /* global options */
- struct
- {
- Bool EmulateMWM : 1;
- Bool EmulateWIN : 1;
- } gs; /* global style structure */
+ struct
+ {
+ unsigned int ModifyUSP : 1; /* - RBW - 11/02/1998 */
+ unsigned int CaptureHonorsStartsOnPage : 1; /* - RBW - 11/02/1998 */
+ unsigned int RecaptureHonorsStartsOnPage : 1; /* - RBW - 11/02/1998 */
+ unsigned int ActivePlacementHonorsStartsOnPage : 1; /* - RBW - 11/02/1998 */
+ } go; /* global options */
+ struct
+ {
+ unsigned int EmulateMWM : 1;
+ unsigned int EmulateWIN : 1;
+ } gs; /* global style structure */
Bool hasIconFont;
Bool hasWindowFont;
} ScreenInfo;
Index: app/fvwm/libs/ColorUtils.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/libs/ColorUtils.c,v
diff -u -p -u -r1.1.1.1 ColorUtils.c
--- app/fvwm/libs/ColorUtils.c 26 Nov 2006 10:53:40 -0000 1.1.1.1
+++ app/fvwm/libs/ColorUtils.c 25 Oct 2025 19:27:20 -0000
@@ -1,261 +1,134 @@
/*
- * The following GPL code from scwm implements a good, fast 3D-shadowing
- * algorithm. It converts the color from RGB to HLS space, then
- * multiplies both the luminosity and the saturation by a specified
- * factor (clipping at the extremes). Then it converts back to RGB and
- * creates a color. The guts of it, i.e. the `color_mult' routine, looks
- * a bit longish, but this is only because there are 6-way conditionals
- * at the begining and end; it actually runs quite fast. The algorithm is
- * the same as Gtk's, but the implemenation is independent and more
- * streamlined.
- *
- * Calling `adjust_pixel_brightness' with a `factor' of 1.3 for hilights
- * and 0.7 for shadows exactly emulates Gtk's shadowing, which is, IMO
- * the most visually pleasing shadowing of any widget set; using 1.2 and
- * 0.5 respectively gives something closer to the "classic" fvwm effect
- * with deeper shadows and more subtle hilights, but still (IMO) smoother
- * and more attractive than fvwm.
- *
- * The only color these routines do not usefully handle is black; black
- * will be returned even for a factor greater than 1.0, when optimally
- * one would like to see a very dark gray. This could possibly be
- * addressed by adding a small additive factor when brightening
- * colors. If anyone adds that feature, please feed it upstream to me.
- *
- * Feel free to use this code in fvwm2, of course.
- *
- * - Maciej Stachowiak
- *
- * And, of course, history shows, we took him up on the offer.
- * Integrated into fvwm2 by Dan Espen, 11/13/98.
- */
-
-
-/*
- * Copyright (C) 1997, 1998, Maciej Stachowiak and Greg J. Badros
- *
- * 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, 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 software; see the file COPYING.GPL. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
+ * Copyright (c) 2025 David Uhden Collado <david@uhden.dev>
*
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "config.h" /* must be first */
+#include "config.h"
#include <stdio.h>
-#include <X11/Xproto.h> /* for X functions in general */
-#include "fvwmlib.h" /* prototype GetShadow GetHilit */
+#include <X11/Xproto.h>
+#include "fvwmlib.h"
#define SCALE 65535.0
-#define HALF_SCALE (SCALE / 2)
-typedef enum {
- R_MAX_G_MIN, R_MAX_B_MIN,
- G_MAX_B_MIN, G_MAX_R_MIN,
- B_MAX_R_MIN, B_MAX_G_MIN
-} MinMaxState;
-
-
-/* Multiply the HLS-space lightness and saturation of the color by the
- given multiple, k - based on the way gtk does shading, but independently
- coded. Should give better relief colors for many cases than the old
- fvwm algorithm. */
-
-/* FIXMS: This can probably be optimized more, examine later. */
-
-static void
-color_mult (unsigned short *red,
- unsigned short *green,
- unsigned short *blue, double k)
+#define HALF_SCALE (SCALE * 0.5)
+
+enum ColorChannel {
+ CHANNEL_RED = 0,
+ CHANNEL_GREEN = 1,
+ CHANNEL_BLUE = 2
+};
+
+static void
+color_mult(unsigned short *red, unsigned short *green,
+ unsigned short *blue, double factor)
{
- if (*red == *green && *red == *blue) {
- double temp;
- /* A shade of gray */
- temp = k * (double) (*red);
- if (temp > SCALE) {
- temp = SCALE;
+ double components[3];
+ components[CHANNEL_RED] = (double)*red;
+ components[CHANNEL_GREEN] = (double)*green;
+ components[CHANNEL_BLUE] = (double)*blue;
+
+ if (components[CHANNEL_RED] == components[CHANNEL_GREEN] &&
+ components[CHANNEL_RED] == components[CHANNEL_BLUE]) {
+ double level = components[CHANNEL_RED] * factor;
+ if (level > SCALE) {
+ level = SCALE;
}
- *red = (unsigned short)(temp);
+ *red = (unsigned short)level;
*green = *red;
*blue = *red;
- } else {
- /* Non-zero saturation */
- double r, g, b;
- double min, max;
- double a, l, s;
- double delta;
- double middle;
- MinMaxState min_max_state;
-
- r = (double) *red;
- g = (double) *green;
- b = (double) *blue;
-
- if (r > g) {
- if (r > b) {
- max = r;
- if (g < b) {
- min = g;
- min_max_state = R_MAX_G_MIN;
- a = b - g;
- } else {
- min = b;
- min_max_state = R_MAX_B_MIN;
- a = g - b;
- }
- } else {
- max = b;
- min = g;
- min_max_state = B_MAX_G_MIN;
- a = r - g;
- }
- } else {
- if (g > b) {
- max = g;
- if (b < r) {
- min = b;
- min_max_state = G_MAX_B_MIN;
- a = r - b;
- } else {
- min = r;
- min_max_state = G_MAX_R_MIN;
- a = b - r;
- }
- } else {
- max = b;
- min = r;
- min_max_state = B_MAX_R_MIN;
- a = g - r;
- }
- }
-
- delta = max - min;
- a = a / delta;
-
- l = (max + min) / 2;
- if (l <= HALF_SCALE) {
- s = max + min;
- } else {
- s = 2.0 * SCALE - (max + min);
- }
- s = delta/s;
-
- l *= k;
- if (l > SCALE) {
- l = SCALE;
- }
- s *= k;
- if (s > 1.0) {
- s = 1.0;
- }
+ return;
+ }
- if (l <= HALF_SCALE) {
- max = l * (1 + s);
- } else {
- max = s * SCALE + l - s * l;
+ int max_index = CHANNEL_RED;
+ int min_index = CHANNEL_RED;
+ for (int idx = CHANNEL_GREEN; idx <= CHANNEL_BLUE; ++idx) {
+ if (components[idx] > components[max_index]) {
+ max_index = idx;
}
-
- min = 2 * l - max;
- delta = max - min;
- middle = min + delta * a;
-
- switch (min_max_state) {
- case R_MAX_G_MIN:
- r = max;
- g = min;
- b = middle;
- break;
- case R_MAX_B_MIN:
- r = max;
- g = middle;
- b = min;
- break;
- case G_MAX_B_MIN:
- r = middle;
- g = max;
- b = min;
- break;
- case G_MAX_R_MIN:
- r = min;
- g = max;
- b = middle;
- break;
- case B_MAX_G_MIN:
- r = middle;
- g = min;
- b = max;
- break;
- case B_MAX_R_MIN:
- r = min;
- g = middle;
- b = max;
- break;
+ if (components[idx] < components[min_index]) {
+ min_index = idx;
}
+ }
+
+ int mid_index = CHANNEL_RED + CHANNEL_GREEN + CHANNEL_BLUE - max_index - min_index;
+ double max_value = components[max_index];
+ double min_value = components[min_index];
+ double span = max_value - min_value;
+ double ratio = (components[mid_index] - min_value) / span;
+
+ double lightness = 0.5 * (max_value + min_value);
+ double extrema_sum = max_value + min_value;
+ double saturation_denominator = (lightness <= HALF_SCALE)
+ ? extrema_sum
+ : (2.0 * SCALE - extrema_sum);
+ double saturation = span / saturation_denominator;
+
+ lightness *= factor;
+ if (lightness > SCALE) {
+ lightness = SCALE;
+ }
+ saturation *= factor;
+ if (saturation > 1.0) {
+ saturation = 1.0;
+ }
- *red = (unsigned short) r;
- *green = (unsigned short) g;
- *blue = (unsigned short) b;
+ double new_max;
+ if (lightness <= HALF_SCALE) {
+ new_max = lightness * (1.0 + saturation);
+ } else {
+ new_max = saturation * SCALE + lightness - saturation * lightness;
}
+
+ double new_min = 2.0 * lightness - new_max;
+ double new_span = new_max - new_min;
+ double new_mid = new_min + new_span * ratio;
+
+ double updated[3];
+ updated[max_index] = new_max;
+ updated[min_index] = new_min;
+ updated[mid_index] = new_mid;
+
+ *red = (unsigned short)updated[CHANNEL_RED];
+ *green = (unsigned short)updated[CHANNEL_GREEN];
+ *blue = (unsigned short)updated[CHANNEL_BLUE];
}
-/*
- * This routine uses PictureSaveDisplay and PictureCMap which must be
- * created by InitPictureCMAP in Picture.c.
- *
- * If you attempt to use GetShadow and GetHilit, make sure your module
- * calls InitPictureCMAP first.
- */
static Pixel
adjust_pixel_brightness(Pixel pixel, double factor)
{
extern Colormap PictureCMap;
extern Display *PictureSaveDisplay;
- XColor c;
- c.pixel = pixel;
- XQueryColor (PictureSaveDisplay, PictureCMap, &c);
- color_mult(&c.red, &c.green, &c.blue, factor);
- XAllocColor (PictureSaveDisplay, PictureCMap, &c);
+ XColor color_spec;
+
+ color_spec.pixel = pixel;
+ XQueryColor(PictureSaveDisplay, PictureCMap, &color_spec);
+ color_mult(&color_spec.red, &color_spec.green, &color_spec.blue, factor);
+ XAllocColor(PictureSaveDisplay, PictureCMap, &color_spec);
- return c.pixel;
+ return color_spec.pixel;
}
-/*
- * These are the original fvwm2 APIs, one for highlights and one for
- * shadows. Together, if used in a frame around a rectangle, they
- * produce a 3d appearance.
- *
- * The input pixel, is normally the background color used in the
- * rectangle. One would hope, when the user selects to color something
- * with a multi-color pixmap, they will have the insight to also assign a
- * background color to the pixmaped area that approximates the average
- * color of the pixmap.
- *
- * Currently callers handle monochrome before calling this routine. The
- * next logical enhancement is for that logic to be moved here. Probably
- * a new API that deals with foreground/background/hilite/shadow
- * allocation all in 1 call is the next logical extenstion.
- *
- * Color allocation is also a good candidate for becoming a library
- * routine. The color allocation logic in FvwmButtons using the XPM
- * library closeness stuff may be the ideal model.
- * (dje 11/15/98)
- */
#define DARKNESS_FACTOR 0.5
-Pixel GetShadow(Pixel background) {
+Pixel
+GetShadow(Pixel background)
+{
return adjust_pixel_brightness(background, DARKNESS_FACTOR);
}
#define BRIGHTNESS_FACTOR 1.4
-Pixel GetHilite(Pixel background) {
+Pixel
+GetHilite(Pixel background)
+{
return adjust_pixel_brightness(background, BRIGHTNESS_FACTOR);
}
Index: app/fvwm/libs/ModParse.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/libs/ModParse.c,v
diff -u -p -u -r1.1.1.1 ModParse.c
--- app/fvwm/libs/ModParse.c 26 Nov 2006 10:53:41 -0000 1.1.1.1
+++ app/fvwm/libs/ModParse.c 25 Oct 2025 19:27:20 -0000
@@ -25,7 +25,7 @@
*/
-char *DoPeekArgument(const char *pstr, char **pret)
+char *DoPeekArgument(const char *pstr, const char **pret)
{
char *tok=NULL;
const char *p;
@@ -84,8 +84,10 @@ char *DoPeekArgument(const char *pstr, c
}
}
- if (!isspace(*p)) p++;
- if (pret) *pret = p;
+ if (*p && !isspace((unsigned char)*p))
+ p++;
+ if (pret)
+ *pret = p;
return tok;
}
@@ -101,15 +103,17 @@ char *PeekArgument(const char *pstr)
char *GetArgument(char **pstr)
{
char *tok ;
+ const char *next = NULL;
- if (!pstr || !*pstr || !(tok=DoPeekArgument(*pstr, pstr)))
+ if (!pstr || !*pstr || !(tok=DoPeekArgument(*pstr, &next)))
return NULL; /* *pstr=NULL; ???? */
+ *pstr = (char *)next;
/* skip tok and following whitespace/separators in pstr & DON'T realloc */
EatWS(*pstr);
- if (!**pstr)
- *pstr=NULL; /* change \0 to NULL */
+ if (*pstr && !**pstr)
+ *pstr=NULL; /* change \0 to NULL */
return tok;
}
@@ -291,26 +295,28 @@ const char *MatchToken(register const ch
*/
-int XCmpToken(char *s, char **t)
+int XCmpToken(const void *vs, const void *vt)
{
- register char *w=*t;
+ const char *s = (const char *)vs;
+ const char *w = *(const char * const *)vt;
if (w==NULL) return 1; /* non existant word */
if (s==NULL) return -1; /* non existant string */
while (*w && (*s==*w ||
#ifdef WORD_IS_UPPERCASE
- isupper(*s) && _toupper(*s)==*w
+ (isupper((unsigned char)*s) &&
+ _toupper((unsigned char)*s)==*w)
#else
- toupper(*s)==toupper(*w)
+ toupper((unsigned char)*s)==toupper((unsigned char)*w)
#endif
))
s++,w++;
- if ((*s=='\0' && (ispunct(*w) || isspace(*w)))||
- (*w=='\0' && (ispunct(*s) || isspace(*s))) )
+ if ((*s=='\0' && (ispunct((unsigned char)*w) || isspace((unsigned char)*w)))||
+ (*w=='\0' && (ispunct((unsigned char)*s) || isspace((unsigned char)*s)) ) )
return 0; /* 1st word equal */
else
- return toupper(*s)-toupper(*w); /* smaller/greater */
+ return toupper((unsigned char)*s)-toupper((unsigned char)*w); /* smaller/greater */
}
Index: app/fvwm/libs/ModParse.h
===================================================================
RCS file: /cvs/xenocara/app/fvwm/libs/ModParse.h,v
diff -u -p -u -r1.1.1.1 ModParse.h
--- app/fvwm/libs/ModParse.h 26 Nov 2006 10:53:41 -0000 1.1.1.1
+++ app/fvwm/libs/ModParse.h 25 Oct 2025 19:27:20 -0000
@@ -40,7 +40,7 @@ int MatchArgument(const char *pstr,char
sizeof(struct_entry), \
XCmpToken)
-int XCmpToken(); /* (char *s, char **t); but avoid compiler warning */
+int XCmpToken(const void *s, const void *t);
/* needed by (L)FindToken */
#if 0
Index: app/fvwm/modules/FvwmBacker/FvwmBacker.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmBacker/FvwmBacker.c,v
diff -u -p -u -r1.1.1.1 FvwmBacker.c
--- app/fvwm/modules/FvwmBacker/FvwmBacker.c 26 Nov 2006 10:53:43 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmBacker/FvwmBacker.c 25 Oct 2025 19:27:20 -0000
@@ -306,7 +306,7 @@ void ParseConfig()
char line2[40];
char *tline;
- sprintf(line2,"*%sDesk",Module);
+ snprintf(line2, sizeof(line2), "*%sDesk", Module);
GetConfigLine(Fvwm_fd,&tline);
@@ -379,8 +379,9 @@ int num;
fflush(logFile);
#endif
commands[num].type = 0;
- commands[num].cmdStr = (char *)safemalloc(strlen(temp)+1);
- strcpy(commands[num].cmdStr,temp);
+ size_t cmd_len = strlen(temp);
+ commands[num].cmdStr = (char *)safemalloc(cmd_len + 1);
+ strlcpy(commands[num].cmdStr, temp, cmd_len + 1);
}
}
Index: app/fvwm/modules/FvwmBacker/Mallocs.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmBacker/Mallocs.c,v
diff -u -p -u -r1.1.1.1 Mallocs.c
--- app/fvwm/modules/FvwmBacker/Mallocs.c 26 Nov 2006 10:53:43 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmBacker/Mallocs.c 25 Oct 2025 19:27:20 -0000
@@ -45,11 +45,16 @@ char *newptr;
return ptr;
}
-void UpdateString(char **string,char *value)
+void UpdateString(char **string, char *value)
{
- if (value==NULL) return;
- if (*string==NULL) *string=safemalloc(strlen(value)+1);
- else *string=(char *)realloc(*string,strlen(value)+1);
- strcpy(*string,value);
+ if (value == NULL)
+ return;
+
+ size_t value_len = strlen(value);
+ if (*string == NULL)
+ *string = safemalloc(value_len + 1);
+ else
+ *string = saferealloc(*string, value_len + 1);
+ strlcpy(*string, value, value_len + 1);
}
Index: app/fvwm/modules/FvwmBacker/root_bits.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmBacker/root_bits.c,v
diff -u -p -u -r1.2 root_bits.c
--- app/fvwm/modules/FvwmBacker/root_bits.c 24 Jan 2021 09:13:15 -0000 1.2
+++ app/fvwm/modules/FvwmBacker/root_bits.c 25 Oct 2025 19:27:20 -0000
@@ -1,19 +1,17 @@
-/* Rewrite of this file by Dominik Vogt on Nov-1-1998 to remove the
- * Xconsortium copyright.
+/*
+ * Copyright (c) 2025 David Uhden Collado <david@uhden.dev>
*
- * 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.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <X11/Xlib.h>
@@ -24,22 +22,22 @@ extern Display *dpy;
extern int screen;
extern char *Module;
-unsigned long GetColor(char *name)
+unsigned long
+GetColor(char *name)
{
- XColor color;
+ Colormap cmap = DefaultColormap(dpy, screen);
+ XColor spec = {0};
+
+ if (!XParseColor(dpy, cmap, name, &spec)) {
+ fprintf(stderr, "%s: unknown color \"%s\"\n", Module, name);
+ exit(1);
+ }
- color.pixel = 0;
- if (!XParseColor (dpy, DefaultColormap(dpy,screen), name, &color))
- {
- fprintf(stderr,"%s: unknown color \"%s\"\n",Module,name);
- exit(1);
- }
- else if(!XAllocColor (dpy, DefaultColormap(dpy,screen), &color))
- {
- fprintf(stderr, "%s: unable to allocate color for \"%s\"\n",
- Module, name);
- exit(1);
- }
+ if (!XAllocColor(dpy, cmap, &spec)) {
+ fprintf(stderr, "%s: unable to allocate color for \"%s\"\n",
+ Module, name);
+ exit(1);
+ }
- return color.pixel;
+ return spec.pixel;
}
Index: app/fvwm/modules/FvwmBanner/FvwmBanner.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmBanner/FvwmBanner.c,v
diff -u -p -u -r1.1.1.1 FvwmBanner.c
--- app/fvwm/modules/FvwmBanner/FvwmBanner.c 26 Nov 2006 10:53:43 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmBanner/FvwmBanner.c 25 Oct 2025 19:27:20 -0000
@@ -99,10 +99,14 @@ int main(int argc, char **argv)
/* Save our program name - for error messages */
string = strrchr (argv[0], '/');
- if (string != (char *) 0) string++;
+ if (string != (char *) 0)
+ string++;
+ else
+ string = argv[0];
- myName = safemalloc (strlen (string) + 1);
- strcpy (myName, string);
+ size_t name_len = strlen(string);
+ myName = safemalloc(name_len + 1);
+ strlcpy(myName, string, name_len + 1);
if(argc>=3)
{
@@ -125,8 +129,9 @@ int main(int argc, char **argv)
}
if (argc > 6) {
- pixmapName = safemalloc (strlen (argv[6]) + 1);
- strcpy (pixmapName, argv[6]);
+ size_t pixmap_len = strlen(argv[6]);
+ pixmapName = safemalloc(pixmap_len + 1);
+ strlcpy(pixmapName, argv[6], pixmap_len + 1);
}
/* Open the display */
Index: app/fvwm/modules/FvwmButtons/FvwmButtons.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmButtons/FvwmButtons.1,v
diff -u -p -u -r1.1.1.1 FvwmButtons.1
--- app/fvwm/modules/FvwmButtons/FvwmButtons.1 26 Nov 2006 10:53:44 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmButtons/FvwmButtons.1 25 Oct 2025 19:27:20 -0000
@@ -567,11 +567,6 @@ XCOMM big items
-geometry 100x50+0-0 -font 5x7`)
.sp
.fi
-
-.SH BUGS
-
-The action part of the Swallow option must be quoted if it contains
-any whitespace character.
.SH COPYRIGHTS
The FvwmButtons program, and the concept for interfacing this module to
Index: app/fvwm/modules/FvwmButtons/FvwmButtons.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmButtons/FvwmButtons.c,v
diff -u -p -u -r1.3 FvwmButtons.c
--- app/fvwm/modules/FvwmButtons/FvwmButtons.c 24 Jan 2021 09:02:54 -0000 1.3
+++ app/fvwm/modules/FvwmButtons/FvwmButtons.c 25 Oct 2025 19:27:20 -0000
@@ -103,6 +103,7 @@ void DebugEvents(XEvent*);
panel_info *seekpanel(button_info *);
void Slide(panel_info *, button_info *);
+static int IOErrorHandler(Display *dpy);
/* -------------------------------- globals ---------------------------------*/
@@ -170,7 +171,6 @@ Bool DestroyedWindow(Display *d,XEvent *
int IsThereADestroyEvent(button_info *b)
{
XEvent event;
- Bool DestroyedWindow();
return XCheckIfEvent(Dpy,&event,DestroyedWindow,(char*)b->IconWin);
}
@@ -466,6 +466,13 @@ int myErrorHandler(Display *dpy, XErrorE
return 0;
}
+static int IOErrorHandler(Display *dpy)
+{
+ (void)dpy;
+ DeadPipe(0);
+ return 0;
+}
+
/* ---------------------------------- main ----------------------------------*/
/**
@@ -483,8 +490,11 @@ int main(int argc, char **argv)
temp=argv[0];
s=strrchr(argv[0],'/');
if(s) temp=s+1;
- MyName=mymalloc(strlen(temp)+1);
- strcpy(MyName,temp);
+ {
+ size_t name_len = strlen(temp) + 1;
+ MyName = mymalloc((int)name_len);
+ strlcpy(MyName, temp, name_len);
+ }
#ifdef HAVE_SIGACTION
{
@@ -539,6 +549,7 @@ int main(int argc, char **argv)
XDisplayName(display_name));
exit (1);
}
+ XSetIOErrorHandler(IOErrorHandler);
x_fd=XConnectionNumber(Dpy);
fd_width=GetFdWidth();
@@ -561,6 +572,8 @@ int main(int argc, char **argv)
UberButton->BHeight=1;
UberButton->font = NULL;
UberButton->font_string = NULL;
+ UberButton->x = -30000;
+ UberButton->y = -30000;
MakeContainer(UberButton);
dpw = DisplayWidth(Dpy,screen);
@@ -572,8 +585,11 @@ int main(int argc, char **argv)
CurrentPanel = MainPanel
= (panel_info *) mymalloc(sizeof(panel_info));
+ memset(MainPanel, 0, sizeof(panel_info));
MainPanel->next = NULL;
MainPanel->uber = UberButton;
+ MainPanel->geom_w = -1;
+ MainPanel->geom_h = -1;
UberButton->title = MyName;
UberButton->swallow = 1; /* the panel is shown */
@@ -874,13 +890,16 @@ void Loop(void)
else
i2=i;
- tmp=mymalloc(strlen(act)+1);
- strcpy(tmp,"Exec ");
+ {
+ size_t tmp_len = strlen(act) + 1;
+ tmp = mymalloc((int)tmp_len);
+ strlcpy(tmp, "Exec ", tmp_len);
while(act[i2]!=0 && isspace(act[i2]))
i2++;
- strcat(tmp,&act[i2]);
+ strlcat(tmp, &act[i2], tmp_len);
MySendText(fd,tmp,0);
free(tmp);
+ }
}
else if(strncasecmp(act,"DumpButtons",11)==0)
DumpButtons(UberButton);
@@ -1219,11 +1238,22 @@ void CreateWindow(button_info *ub,int ma
XGCValues gcv;
unsigned long gcm;
XClassHint myclasshints;
+ int req_w = -1;
+ int req_h = -1;
x = CurrentPanel->uber->x; /* Geometry x where to put the panel */
y = CurrentPanel->uber->y; /* Geometry y where to put the panel */
xneg = CurrentPanel->uber->w;
yneg = CurrentPanel->uber->h;
+ gravity = NorthWestGravity;
+
+ if (CurrentPanel)
+ {
+ req_w = CurrentPanel->geom_w;
+ req_h = CurrentPanel->geom_h;
+ }
+ w = (req_w > -1) ? req_w : -1;
+ h = (req_h > -1) ? req_h : -1;
if(maxx<16)
maxx=16;
@@ -1263,16 +1293,33 @@ void CreateWindow(button_info *ub,int ma
mysizehints.base_height+=ub->c->num_rows*2;
mysizehints.base_width+=ub->c->num_columns*2;
- if(w>-1) /* from geometry */
+ if(req_w > -1 || req_h > -1) /* from geometry */
{
# ifdef DEBUG_INIT
- fprintf(stderr,"constraining (w=%i)...",w);
+ fprintf(stderr,"constraining (w=%i,h=%i)...",req_w,req_h);
# endif
- ConstrainSize(&mysizehints,&w,&h);
- mysizehints.width = w;
- mysizehints.height = h;
+ {
+ int tmp_w = (req_w > -1) ? req_w : mysizehints.width;
+ int tmp_h = (req_h > -1) ? req_h : mysizehints.height;
+ ConstrainSize(&mysizehints,&tmp_w,&tmp_h);
+ if (req_w > -1)
+ w = tmp_w;
+ else
+ w = -1;
+ if (req_h > -1)
+ h = tmp_h;
+ else
+ h = -1;
+ mysizehints.width = tmp_w;
+ mysizehints.height = tmp_h;
+ }
mysizehints.flags |= USSize;
}
+ else
+ {
+ w = -1;
+ h = -1;
+ }
# ifdef DEBUG_INIT
fprintf(stderr,"gravity...");
@@ -1353,9 +1400,10 @@ void CreateWindow(button_info *ub,int ma
}
else
{
- myclasshints.res_name=(char *)malloc(strlen(MyName)+6);
- strcpy(myclasshints.res_name,MyName);
- strcat(myclasshints.res_name,"Panel");
+ size_t total_len = strlen(MyName) + sizeof("Panel");
+ myclasshints.res_name=(char *)safemalloc(total_len);
+ strlcpy(myclasshints.res_name,MyName,total_len);
+ strlcat(myclasshints.res_name,"Panel",total_len);
}
#endif
myclasshints.res_class=strdup((CurrentPanel == MainPanel)
@@ -1415,7 +1463,7 @@ int PleaseAllocColor(XColor *color)
XImage *dummy1=None,*dummy2=None;
static char buf[20];
- sprintf(buf,"x c #%04x%04x%04x",color->red,color->green,color->blue);
+ snprintf(buf,sizeof(buf),"x c #%04x%04x%04x",color->red,color->green,color->blue);
xpm[1]=buf;
attr.valuemask=XpmCloseness;
attr.closeness=40000; /* value used by fvwm and fvwmlib */
Index: app/fvwm/modules/FvwmButtons/FvwmButtons.h
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmButtons/FvwmButtons.h,v
diff -u -p -u -r1.2 FvwmButtons.h
--- app/fvwm/modules/FvwmButtons/FvwmButtons.h 18 Jan 2011 19:28:33 -0000 1.2
+++ app/fvwm/modules/FvwmButtons/FvwmButtons.h 25 Oct 2025 19:27:20 -0000
@@ -153,8 +153,11 @@ struct button_info_struct
};
struct panel_info_struct
-{ button_info *uber; /* panel */
+{
+ button_info *uber; /* panel */
panel_info *next;
+ int geom_w; /* requested width, -1 if unset */
+ int geom_h; /* requested height, -1 if unset */
};
#include "button.h"
Index: app/fvwm/modules/FvwmButtons/parse.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmButtons/parse.c,v
diff -u -p -u -r1.1.1.1 parse.c
--- app/fvwm/modules/FvwmButtons/parse.c 26 Nov 2006 10:53:46 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmButtons/parse.c 25 Oct 2025 19:27:21 -0000
@@ -65,6 +65,36 @@ char *seekright(char **s)
return token;
}
+static char *seekright_command(char **s)
+{
+ char *command = seekright(s);
+
+ if (command == NULL)
+ return NULL;
+
+ while (terminator != '\0' && terminator != ')' && terminator != ',')
+ {
+ char *next = seekright(s);
+
+ if (next == NULL)
+ break;
+
+ size_t len_command = strlen(command);
+ size_t len_next = strlen(next);
+ char *combined = mymalloc(len_command + len_next + 2);
+
+ memcpy(combined, command, len_command);
+ combined[len_command] = ' ';
+ memcpy(combined + len_command + 1, next, len_next + 1);
+
+ free(command);
+ free(next);
+ command = combined;
+ }
+
+ return command;
+}
+
/**
*** ParseBack()
*** Parses the options possible to Back
@@ -588,7 +618,7 @@ void match_string(button_info **uberb,ch
if(*s=='(' && s++)
ParseSwallow(&s,&b->swallow,&b->swallow_mask);
t=seekright(&s);
- o=seekright(&s);
+ o=seekright_command(&s);
if(t)
{
if (b->hangon)
@@ -848,12 +878,24 @@ void ParseConfigLine(button_info **ubb,c
if(i==1)
{
flags=XParseGeometry(geom,&g_x,&g_y,&width,&height);
+ w = -1;
+ h = -1;
+ CurrentPanel->geom_w = -1;
+ CurrentPanel->geom_h = -1;
UberButton->w = 0;
UberButton->h = 0;
+ UberButton->x = -30000;
+ UberButton->y = -30000;
if(flags&WidthValue)
- w=width;
+ {
+ w = (int)width;
+ CurrentPanel->geom_w = (int)width;
+ }
if(flags&HeightValue)
- h=height;
+ {
+ h = (int)height;
+ CurrentPanel->geom_h = (int)height;
+ }
if(flags&XValue)
UberButton->x = g_x;
if(flags&YValue)
@@ -898,31 +940,35 @@ void ParseConfigLine(button_info **ubb,c
config_file=seekright(&s);
break;
case 9:/* Pixmap */
- s = trimleft(s);
- if (strncasecmp(s,"none",4)==0)
- ub->c->flags|=b_TransBack;
- else
- CopyString(&(ub->c->back_file),s);
- ub->c->flags|=b_IconBack;
- break;
+ s = trimleft(s);
+ if (strncasecmp(s,"none",4)==0)
+ ub->c->flags|=b_TransBack;
+ else
+ CopyString(&(ub->c->back_file),s);
+ ub->c->flags|=b_IconBack;
+ break;
case 10:/* Panel */
- s = trimleft(s);
- CurrentPanel->next = (panel_info *) mymalloc(sizeof(panel_info));
- CurrentPanel = CurrentPanel->next;
- CurrentPanel->next = NULL;
- CurrentPanel->uber = UberButton
- = (button_info *) mymalloc(sizeof(button_info));
- if (UberButton->title)
- free(UberButton->title);
- UberButton->title = seekright(&s);
- UberButton->flags = 0;
- UberButton->parent = NULL;
- UberButton->BWidth = 1;
- UberButton->BHeight = 1;
- UberButton->swallow = 0; /* subpanel is hidden initially */
- MakeContainer(UberButton);
- ub = *ubb = UberButton;
- break;
+ s = trimleft(s);
+ CurrentPanel->next = (panel_info *)mymalloc(sizeof(panel_info));
+ CurrentPanel = CurrentPanel->next;
+ memset(CurrentPanel, 0, sizeof(panel_info));
+ CurrentPanel->geom_w = -1;
+ CurrentPanel->geom_h = -1;
+ CurrentPanel->next = NULL;
+ CurrentPanel->uber = UberButton
+ = (button_info *)mymalloc(sizeof(button_info));
+ memset(UberButton, 0, sizeof(button_info));
+ UberButton->title = seekright(&s);
+ UberButton->flags = 0;
+ UberButton->parent = NULL;
+ UberButton->BWidth = 1;
+ UberButton->BHeight = 1;
+ UberButton->swallow = 0; /* subpanel is hidden initially */
+ UberButton->x = -30000;
+ UberButton->y = -30000;
+ MakeContainer(UberButton);
+ ub = *ubb = UberButton;
+ break;
case 11: /* BoxSize */
ParseBoxSize(&s, &ub->c->flags);
break;
@@ -984,8 +1030,9 @@ void ParseOptions(button_info *ub)
char *s;
char *items[]={"iconpath","pixmappath","colorlimit",NULL,NULL};
- items[3]=mymalloc(strlen(MyName)+2);
- sprintf(items[3],"*%s",MyName);
+ size_t name_len = strlen(MyName);
+ items[3] = mymalloc(name_len + 2);
+ snprintf(items[3], name_len + 2, "*%s", MyName);
GetConfigLine(fd,&s);
while(s && s[0])
Index: app/fvwm/modules/FvwmCpp/FvwmCpp.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmCpp/FvwmCpp.1,v
diff -u -p -u -r1.1.1.1 FvwmCpp.1
--- app/fvwm/modules/FvwmCpp/FvwmCpp.1 26 Nov 2006 10:53:46 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmCpp/FvwmCpp.1 25 Oct 2025 19:27:21 -0000
@@ -134,9 +134,6 @@ determined at compile time.
.EE
.SH BUGS
-Module configurations do not become active until fvwm2 has restarted
-if you use FvwmCpp on startup. FvwmCpp creates a temporary file
-and passes this to fvwm2, so you would have to edit this file too.
There are some problems with comments in your .fvwmrc file.
The comment sign # is misinterpreted by the preprocessor.
This has usually no impact on functionality but generates
@@ -164,4 +161,4 @@ and not
.SH AUTHOR
FvwmCpp is the result of a random bit mutation on a hard disk,
-presumably a result of a cosmic-ray or some such thing.
+presumably a result of a cosmic-ray or some such thing.
Index: app/fvwm/modules/FvwmCpp/FvwmCpp.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmCpp/FvwmCpp.c,v
diff -u -p -u -r1.1.1.1 FvwmCpp.c
--- app/fvwm/modules/FvwmCpp/FvwmCpp.c 26 Nov 2006 10:53:46 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmCpp/FvwmCpp.c 25 Oct 2025 19:27:21 -0000
@@ -52,9 +52,12 @@ int ScreenWidth, ScreenHeight;
int Mscreen;
long Vx, Vy;
-static char *MkDef(char *name, char *def);
-static char *MkNum(char *name,int def);
-static char *cpp_defs(Display *display, const char *host, char *m4_options, char *config_file);
+static char *MkDef(const char *name, const char *def);
+static char *MkNum(const char *name,int def);
+static int cpp_process(Display *display, const char *host, char *options,
+ const char *config_file, int keep_output);
+static int is_cpp_linemarker(const char *line);
+static void *xrealloc(void *ptr, size_t size);
#define MAXHOSTNAME 255
#define EXTRA 20
@@ -76,10 +79,9 @@ int main(int argc, char **argv)
char *temp, *s;
char *display_name = NULL;
char *filename = NULL;
- char *tmp_file, read_string[80],delete_string[80];
- int i,cpp_debug = 0;
+ int i, cpp_debug = 0;
- strcpy(cpp_options,"");
+ cpp_options[0] = '\0';
/* Record the program name for error messages */
temp = argv[0];
@@ -88,9 +90,10 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ size_t name_len = strlen(temp);
+ MyName = safemalloc(name_len + 2);
+ strlcpy(MyName, "*", name_len + 2);
+ strlcat(MyName, temp, name_len + 2);
if(argc < 6)
{
@@ -161,202 +164,364 @@ int main(int argc, char **argv)
filename[i] = 0;
}
- if (!(dpy = XOpenDisplay(display_name)))
+ if (filename == NULL)
{
- fprintf(stderr,"%s: can't open display %s",
- MyName, XDisplayName(display_name));
- exit (1);
+ fprintf(stderr, "%s: no configuration file specified\n", MyName);
+ exit(1);
}
- tmp_file = cpp_defs(dpy, display_name,cpp_options, filename);
-
- snprintf(read_string,sizeof(read_string),"read %s\n",tmp_file);
- SendInfo(fd,read_string,0);
+ if (cpp_process(dpy, display_name, cpp_options, filename, cpp_debug) != 0)
+ exit(1);
- /* For a debugging version, we may wish to omit this part. */
- /* I'll let some cpp advocates clean this up */
- if(!cpp_debug)
- {
- snprintf(delete_string,sizeof(delete_string),"exec rm %s\n",tmp_file);
- SendInfo(fd,delete_string,0);
- }
return 0;
}
-static char *cpp_defs(Display *display, const char *host, char *cpp_options, char *config_file)
+static int
+cpp_process(Display *display, const char *host, char *cpp_opts,
+ const char *config_file, int keep_output)
{
Screen *screen;
Visual *visual;
char client[MAXHOSTNAME], server[MAXHOSTNAME], *colon;
char ostype[BUFSIZ];
- char options[BUFSIZ];
- static char tmp_name[BUFSIZ];
+ char feature_opts[BUFSIZ];
struct hostent *hostname;
- char *vc; /* Visual Class */
- FILE *tmpf;
+ char *vc;
struct passwd *pwent;
- int fd;
- /* Generate a temporary filename. Honor the TMPDIR environment variable,
- if set. Hope nobody deletes this file! */
-
- if (strlen(cpp_outfile) == 0) {
- if ((vc=getenv("TMPDIR"))) {
- strlcpy(tmp_name, vc, sizeof(tmp_name));
- } else {
- strlcpy(tmp_name, "/tmp", sizeof(tmp_name));
+ FILE *cpp_in = NULL;
+ FILE *cpp_out = NULL;
+ FILE *mirror = NULL;
+ int to_child[2];
+ int from_child[2];
+ pid_t pid;
+ int status;
+ char command[2 * BUFSIZ];
+ char tmp_name[BUFSIZ];
+ int created_temp = 0;
+ char kept_path[BUFSIZ];
+ size_t line_cap = 1024;
+ char *linebuf = NULL;
+ size_t line_len = 0;
+ unsigned char chunk[BUFSIZ];
+ size_t nread;
+ int appended_newline = 0;
+
+ kept_path[0] = '\0';
+
+ if (cpp_outfile[0] != '\0') {
+ mirror = fopen(cpp_outfile, "w");
+ if (mirror == NULL)
+ fprintf(stderr, "%s: unable to open %s for writing\n", MyName,
+ cpp_outfile);
+ } else if (keep_output) {
+ const char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = "/tmp";
+ strlcpy(tmp_name, tmpdir, sizeof(tmp_name));
+ strlcat(tmp_name, "/fvwmcppXXXXXXXXXX", sizeof(tmp_name));
+ {
+ int fd_tmp = mkstemp(tmp_name);
+ if (fd_tmp >= 0) {
+ mirror = fdopen(fd_tmp, "w");
+ if (mirror != NULL) {
+ strlcpy(kept_path, tmp_name, sizeof(kept_path));
+ created_temp = 1;
+ } else {
+ close(fd_tmp);
+ }
+ } else {
+ perror("mkstemp failed in cpp_process");
+ }
}
- strlcat(tmp_name, "/fvwmrcXXXXXXXXXX", sizeof(tmp_name));
- mktemp(tmp_name);
- } else {
- strlcpy(tmp_name,cpp_outfile, sizeof(tmp_name));
}
- if (*tmp_name == '\0')
- {
- perror("mktemp failed in cpp_defs");
- exit(0377);
- }
+ if (pipe(to_child) == -1 || pipe(from_child) == -1) {
+ perror("pipe in cpp_process");
+ if (mirror)
+ fclose(mirror);
+ return -1;
+ }
- /*
- ** check to make sure it doesn't exist already, to prevent security hole
- */
- if ((fd = open(tmp_name, O_WRONLY|O_EXCL|O_CREAT, 0600)) < 0)
- {
- perror("exclusive open for output file failed in cpp_defs");
- exit(0377);
+ snprintf(command, sizeof(command), "%s %s", cpp_prog,
+ (cpp_opts != NULL) ? cpp_opts : "");
+
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork in cpp_process");
+ close(to_child[0]);
+ close(to_child[1]);
+ close(from_child[0]);
+ close(from_child[1]);
+ if (mirror)
+ fclose(mirror);
+ return -1;
}
- close(fd);
- /*
- * Create the appropriate command line to run cpp, and
- * open a pipe to the command.
- */
+ if (pid == 0) {
+ dup2(to_child[0], STDIN_FILENO);
+ dup2(from_child[1], STDOUT_FILENO);
+ close(to_child[0]);
+ close(to_child[1]);
+ close(from_child[0]);
+ close(from_child[1]);
+ execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+ _exit(127);
+ }
- strlcpy(options, cpp_prog, sizeof(options));
- strlcat(options, " ", sizeof(options));
- strlcat(options, cpp_options, sizeof(options));
- strlcat(options, " >", sizeof(options));
- strlcat(options, tmp_name, sizeof(options));
+ close(to_child[0]);
+ close(from_child[1]);
- tmpf = popen(options, "w");
- if (tmpf == NULL) {
- perror("Cannot open pipe to cpp");
- exit(0377);
+ cpp_in = fdopen(to_child[1], "w");
+ cpp_out = fdopen(from_child[0], "r");
+ if (cpp_in == NULL || cpp_out == NULL) {
+ perror("fdopen in cpp_process");
+ if (cpp_in)
+ fclose(cpp_in);
+ else
+ close(to_child[1]);
+ if (cpp_out)
+ fclose(cpp_out);
+ else
+ close(from_child[0]);
+ if (mirror)
+ fclose(mirror);
+ waitpid(pid, NULL, 0);
+ return -1;
}
- gethostname(client,MAXHOSTNAME);
+#define WRITE_DEF(name, value) \
+ do { \
+ char *tmp__ = MkDef((name), (value)); \
+ fputs(tmp__, cpp_in); \
+ free(tmp__); \
+ } while (0)
+#define WRITE_NUM(name, value) \
+ do { \
+ char *tmp__ = MkNum((name), (value)); \
+ fputs(tmp__, cpp_in); \
+ free(tmp__); \
+ } while (0)
- getostype (ostype, sizeof ostype);
+ gethostname(client, MAXHOSTNAME);
+ getostype(ostype, sizeof ostype);
hostname = gethostbyname(client);
strlcpy(server, XDisplayName(host), sizeof(server));
colon = strchr(server, ':');
- if (colon != NULL) *colon = '\0';
+ if (colon != NULL)
+ *colon = '\0';
if ((server[0] == '\0') || (!strcmp(server, "unix")))
- strlcpy(server, client, sizeof(server)); /* must be connected to :0 or unix:0 */
-
- /* TWM_TYPE is fvwm, for completeness */
+ strlcpy(server, client, sizeof(server));
- fputs(MkDef("TWM_TYPE", "fvwm"), tmpf);
-
- /* The machine running the X server */
- fputs(MkDef("SERVERHOST", server), tmpf);
- /* The machine running the window manager process */
- fputs(MkDef("CLIENTHOST", client), tmpf);
+ WRITE_DEF("TWM_TYPE", "fvwm");
+ WRITE_DEF("SERVERHOST", server);
+ WRITE_DEF("CLIENTHOST", client);
if (hostname)
- fputs(MkDef("HOSTNAME", (char *)hostname->h_name), tmpf);
+ WRITE_DEF("HOSTNAME", (char *)hostname->h_name);
else
- fputs(MkDef("HOSTNAME", (char *)client), tmpf);
+ WRITE_DEF("HOSTNAME", client);
+ WRITE_DEF("OSTYPE", ostype);
- fputs(MkDef("OSTYPE", ostype), tmpf);
+ pwent = getpwuid(geteuid());
+ if (pwent && pwent->pw_name)
+ WRITE_DEF("USER", pwent->pw_name);
+ else
+ WRITE_DEF("USER", "");
- pwent=getpwuid(geteuid());
- fputs(MkDef("USER", pwent->pw_name), tmpf);
+ {
+ const char *home = getenv("HOME");
+ WRITE_DEF("HOME", (home != NULL) ? home : "");
+ }
+
+ WRITE_NUM("VERSION", ProtocolVersion(display));
+ WRITE_NUM("REVISION", ProtocolRevision(display));
+ WRITE_DEF("VENDOR", ServerVendor(display));
+ WRITE_NUM("RELEASE", VendorRelease(display));
- fputs(MkDef("HOME", getenv("HOME")), tmpf);
- fputs(MkNum("VERSION", ProtocolVersion(display)), tmpf);
- fputs(MkNum("REVISION", ProtocolRevision(display)), tmpf);
- fputs(MkDef("VENDOR", ServerVendor(display)), tmpf);
- fputs(MkNum("RELEASE", VendorRelease(display)), tmpf);
screen = ScreenOfDisplay(display, Mscreen);
visual = DefaultVisualOfScreen(screen);
- fputs(MkNum("WIDTH", DisplayWidth(display,Mscreen)), tmpf);
- fputs(MkNum("HEIGHT", DisplayHeight(display,Mscreen)), tmpf);
-
- fputs(MkNum("X_RESOLUTION",Resolution(screen->width,screen->mwidth)),tmpf);
- fputs(MkNum("Y_RESOLUTION",Resolution(screen->height,screen->mheight)),tmpf);
- fputs(MkNum("PLANES",DisplayPlanes(display, Mscreen)), tmpf);
+ WRITE_NUM("WIDTH", DisplayWidth(display, Mscreen));
+ WRITE_NUM("HEIGHT", DisplayHeight(display, Mscreen));
+ WRITE_NUM("X_RESOLUTION", Resolution(screen->width, screen->mwidth));
+ WRITE_NUM("Y_RESOLUTION", Resolution(screen->height, screen->mheight));
+ WRITE_NUM("PLANES", DisplayPlanes(display, Mscreen));
+ WRITE_NUM("BITS_PER_RGB", visual->bits_per_rgb);
+ WRITE_NUM("SCREEN", Mscreen);
+
+ switch (visual->class) {
+ case StaticGray:
+ vc = "StaticGray";
+ break;
+ case GrayScale:
+ vc = "GrayScale";
+ break;
+ case StaticColor:
+ vc = "StaticColor";
+ break;
+ case PseudoColor:
+ vc = "PseudoColor";
+ break;
+ case TrueColor:
+ vc = "TrueColor";
+ break;
+ case DirectColor:
+ vc = "DirectColor";
+ break;
+ default:
+ vc = "NonStandard";
+ break;
+ }
- fputs(MkNum("BITS_PER_RGB", visual->bits_per_rgb), tmpf);
- fputs(MkNum("SCREEN", Mscreen), tmpf);
+ WRITE_DEF("CLASS", vc);
+ if (visual->class != StaticGray && visual->class != GrayScale)
+ WRITE_DEF("COLOR", "Yes");
+ else
+ WRITE_DEF("COLOR", "No");
+ WRITE_DEF("FVWM_VERSION", VERSION);
- switch(visual->class)
- {
- case(StaticGray):
- vc = "StaticGray";
- break;
- case(GrayScale):
- vc = "GrayScale";
- break;
- case(StaticColor):
- vc = "StaticColor";
- break;
- case(PseudoColor):
- vc = "PseudoColor";
- break;
- case(TrueColor):
- vc = "TrueColor";
- break;
- case(DirectColor):
- vc = "DirectColor";
- break;
- default:
- vc = "NonStandard";
- break;
+ feature_opts[0] = '\0';
+#ifdef SHAPE
+ strlcat(feature_opts, "SHAPE ", sizeof(feature_opts));
+#endif
+#ifdef XPM
+ strlcat(feature_opts, "XPM ", sizeof(feature_opts));
+#endif
+ strlcat(feature_opts, "Cpp ", sizeof(feature_opts));
+#ifdef NO_SAVEUNDERS
+ strlcat(feature_opts, "NO_SAVEUNDERS ", sizeof(feature_opts));
+#endif
+ WRITE_DEF("OPTIONS", feature_opts);
+ WRITE_DEF("FVWM_MODULEDIR", FVWM_MODULEDIR);
+ WRITE_DEF("FVWM_CONFIGDIR", FVWM_CONFIGDIR);
+
+ fprintf(cpp_in, "#include \"%s\"\n", config_file);
+ fflush(cpp_in);
+ fclose(cpp_in);
+
+#undef WRITE_DEF
+#undef WRITE_NUM
+
+ linebuf = safemalloc(line_cap);
+ while ((nread = fread(chunk, 1, sizeof(chunk), cpp_out)) > 0) {
+ if (mirror)
+ fwrite(chunk, 1, nread, mirror);
+ for (size_t i = 0; i < nread; i++) {
+ if (line_len + 1 >= line_cap) {
+ line_cap *= 2;
+ linebuf = xrealloc(linebuf, line_cap);
+ }
+ linebuf[line_len++] = chunk[i];
+ if (chunk[i] == '\n') {
+ if (line_len >= 2 && linebuf[line_len - 2] == '\\') {
+ /* Preserve fvwm's "\" line continuation semantics. */
+ line_len -= 2;
+ continue;
+ }
+ linebuf[line_len] = '\0';
+ if (!is_cpp_linemarker(linebuf))
+ SendInfo(fd, linebuf, 0);
+ line_len = 0;
}
+ }
+ }
- fputs(MkDef("CLASS", vc), tmpf);
- if (visual->class != StaticGray && visual->class != GrayScale)
- fputs(MkDef("COLOR", "Yes"), tmpf);
- else
- fputs(MkDef("COLOR", "No"), tmpf);
- fputs(MkDef("FVWM_VERSION", VERSION), tmpf);
+ if (ferror(cpp_out))
+ perror("cpp output read");
- /* Add options together */
- *options = '\0';
-#ifdef SHAPE
- strcat(options, "SHAPE ");
-#endif
-#ifdef XPM
- strcat(options, "XPM ");
-#endif
+ if (line_len > 0) {
+ if (line_len + 2 >= line_cap) {
+ line_cap *= 2;
+ linebuf = xrealloc(linebuf, line_cap);
+ }
+ if (linebuf[line_len - 1] != '\n') {
+ linebuf[line_len++] = '\n';
+ appended_newline = 1;
+ }
+ linebuf[line_len] = '\0';
+ if (mirror && appended_newline)
+ fputc('\n', mirror);
+ if (!is_cpp_linemarker(linebuf))
+ SendInfo(fd, linebuf, 0);
+ }
- strcat(options, "Cpp ");
+ free(linebuf);
+ fclose(cpp_out);
-#ifdef NO_SAVEUNDERS
- strcat(options, "NO_SAVEUNDERS ");
-#endif
+ if (mirror)
+ fclose(mirror);
+
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("waitpid for cpp");
+ status = 1;
+ }
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "%s: cpp exited with status %d\n", MyName,
+ WEXITSTATUS(status));
+ return -1;
+ }
- fputs(MkDef("OPTIONS", options), tmpf);
+ if (created_temp && kept_path[0] != '\0') {
+ char msg[BUFSIZ];
+ snprintf(msg, sizeof(msg), "Echo %s: preprocessor output kept in %s\n",
+ MyName, kept_path);
+ SendInfo(fd, msg, 0);
+ }
+
+ return 0;
+}
- fputs(MkDef("FVWM_MODULEDIR", FVWM_MODULEDIR), tmpf);
- fputs(MkDef("FVWM_CONFIGDIR", FVWM_CONFIGDIR), tmpf);
- /*
- * At this point, we've sent the definitions to cpp. Just include
- * the fvwmrc file now.
- */
- fprintf(tmpf, "#include \"%s\"\n", config_file);
- pclose(tmpf);
- return(tmp_name);
+
+
+static int
+is_cpp_linemarker(const char *line)
+{
+ const unsigned char *p;
+
+ if (line == NULL)
+ return 0;
+
+ p = (const unsigned char *)line;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p != '#')
+ return 0;
+ p++;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '\0' || *p == '\n')
+ return 1;
+ if (isdigit(*p)) {
+ while (isdigit(*p))
+ p++;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '\0' || *p == '\n' || *p == '"')
+ return 1;
+ }
+ if (strncmp((const char *)p, "line", 4) == 0)
+ return 1;
+ return 0;
}
+static void *
+xrealloc(void *ptr, size_t size)
+{
+ void *tmp = realloc(ptr, size);
+ if (tmp == NULL) {
+ fprintf(stderr, "%s: unable to allocate %zu bytes\n", MyName, size);
+ exit(1);
+ }
+ return tmp;
+}
/***********************************************************************
@@ -370,7 +535,7 @@ void DeadPipe(int nonsense)
exit(0);
}
-static char *MkDef(char *name, char *def)
+static char *MkDef(const char *name, const char *def)
{
char *cp = NULL;
int n;
@@ -380,16 +545,16 @@ static char *MkDef(char *name, char *def
n = EXTRA + strlen(name) + strlen(def);
cp = safemalloc(n);
- sprintf(cp, "#define %s %s\n",name,def);
+ snprintf(cp, n, "#define %s %s\n", name, def);
return(cp);
}
-static char *MkNum(char *name,int def)
+static char *MkNum(const char *name,int def)
{
char num[20];
- sprintf(num, "%d", def);
+ snprintf(num, sizeof(num), "%d", def);
return(MkDef(name, num));
}
Index: app/fvwm/modules/FvwmForm/FvwmForm.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmForm/FvwmForm.1,v
diff -u -p -u -r1.2 FvwmForm.1
--- app/fvwm/modules/FvwmForm/FvwmForm.1 20 Mar 2010 20:13:27 -0000 1.2
+++ app/fvwm/modules/FvwmForm/FvwmForm.1 25 Oct 2025 19:27:21 -0000
@@ -380,10 +380,6 @@ This example provides a front-end to xwd
.br
*CaptureButton quit "Quit"
-.SH BUGS AND LIMITATIONS
-There is a hard-coded limit on the number of items.
-
-Report bugs to ztfeng@math.princeton.edu.
.SH COPYRIGHT
FvwmForm is original work of Thomas Zuwei Feng.
Index: app/fvwm/modules/FvwmForm/FvwmForm.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmForm/FvwmForm.c,v
diff -u -p -u -r1.3 FvwmForm.c
--- app/fvwm/modules/FvwmForm/FvwmForm.c 25 Oct 2021 11:12:09 -0000 1.3
+++ app/fvwm/modules/FvwmForm/FvwmForm.c 25 Oct 2025 19:27:21 -0000
@@ -10,6 +10,8 @@
#include "../../libs/fvwmlib.h"
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include <sys/types.h>
@@ -42,11 +44,11 @@ void dummy (FILE *f, const char *fmt, ..
#define ITEM_HSPC 10
#define ITEM_VSPC 5
-/* tba: use dynamic buffer expanding */
-#define MAX_LINES 50
-#define MAX_ITEMS 100
-#define ITEMS_PER_LINE 64
-#define CHOICES_PER_SEL 64
+/* initial allocation sizes, structures grow dynamically as needed */
+#define INITIAL_LINE_CAPACITY 8
+#define INITIAL_LINE_ITEMS_CAPACITY 8
+#define INITIAL_ITEMS_CAPACITY 128
+#define INITIAL_CHOICES_CAPACITY 8
#define I_TEXT 1
#define I_INPUT 2
@@ -91,6 +93,7 @@ typedef union _item {
int key; /* one of IS_MULTIPLE, IS_SINGLE */
int n; /* number of choices */
union _item **choices; /* list of choices */
+ int choices_cap;
} select;
struct { /* I_CHOICE */
struct _head head;
@@ -110,6 +113,7 @@ typedef union _item {
int keypress; /* short cut */
/* Fvwm command to execute */
char **commands;
+ int commands_cap;
} button;
} Item;
@@ -123,23 +127,20 @@ typedef struct _line {
int n; /* number of items on the line */
int justify; /* justification */
int size_x, size_y; /* size of bounding rectangle */
- Item **items; /* list of items */
+ Item **items; /* list of items */
+ int items_cap; /* capacity of items array */
} Line;
-
-
-/* global variables */
-char *prog_name; /* program name, e.g. FvwmForm */
-
+
int fd_in; /* fd for Fvwm->Module packets */
int fd_out; /* fd for Module->Fvwm packets */
-int fd[2]; /* pipe pair */
-int fd_err;
FILE *fp_err;
-Line lines[MAX_LINES];
+Line *lines = NULL;
int n_lines;
-Item items[MAX_ITEMS];
+int lines_capacity = 0;
+Item *items = NULL;
int n_items;
+int items_capacity = 0;
Item def_button;
int grab_server = 0, server_grabbed = 0;
@@ -148,6 +149,9 @@ int warp_pointer = 0;
Display *dpy;
int fd_x; /* fd for X connection */
+char *prog_name;
+int fd[2];
+int fd_err;
Window root, frame, ref;
Colormap d_cmap;
@@ -182,6 +186,69 @@ int rel_cursor;
static char *buf;
static int N = 8;
+static void
+ensure_line_capacity(int count)
+{
+ if (lines_capacity >= count) {
+ return;
+ }
+ int new_cap = lines_capacity ? lines_capacity : INITIAL_LINE_CAPACITY;
+ while (new_cap < count) {
+ new_cap *= 2;
+ }
+ lines = (Line *)realloc(lines, sizeof(Line) * new_cap);
+ for (int i = lines_capacity; i < new_cap; ++i) {
+ lines[i].n = 0;
+ lines[i].justify = L_CENTER;
+ lines[i].size_x = 0;
+ lines[i].size_y = 0;
+ lines[i].items = NULL;
+ lines[i].items_cap = 0;
+ }
+ lines_capacity = new_cap;
+}
+
+static void
+ensure_line_item_capacity(Line *line, int count)
+{
+ if (line->items_cap >= count) {
+ return;
+ }
+ int new_cap = line->items_cap ? line->items_cap : INITIAL_LINE_ITEMS_CAPACITY;
+ while (new_cap < count) {
+ new_cap *= 2;
+ }
+ line->items = (Item **)realloc(line->items, sizeof(Item *) * new_cap);
+ line->items_cap = new_cap;
+}
+
+static Line *
+add_line(int justify)
+{
+ ensure_line_capacity(n_lines + 1);
+ Line *line = &lines[n_lines++];
+ line->n = 0;
+ line->justify = justify;
+ line->size_x = 0;
+ line->size_y = 0;
+ if (!line->items) {
+ line->items_cap = 0;
+ }
+ ensure_line_item_capacity(line, 1);
+ return line;
+}
+
+static void
+append_item_to_line(Line *line, Item *item)
+{
+ ensure_line_item_capacity(line, line->n + 1);
+ line->items[line->n++] = item;
+ line->size_x += item->header.size_x;
+ if (line->size_y < item->header.size_y) {
+ line->size_y = item->header.size_y;
+ }
+}
+
/* copy a string until '\0', or up to n chars, and delete trailing spaces */
char *CopyNString (char *cp, int n)
{
@@ -252,30 +319,34 @@ int FontWidth (XFontStruct *xfs)
/* read the configuration file */
void ReadConfig ()
{
- FILE *fopen();
int prog_name_len, i, j, l, extra;
char *line_buf;
char *cp;
Line *cur_line, *line;
Item *item, *cur_sel, *cur_button;
-#define AddToLine(item) { cur_line->items[cur_line->n++] = item; cur_line->size_x += item->header.size_x; if (cur_line->size_y < item->header.size_y) cur_line->size_y = item->header.size_y; }
+ /* ensure items array capacity (dynamic) */
+ if (!items) {
+ items_capacity = INITIAL_ITEMS_CAPACITY;
+ items = (Item *)malloc(sizeof(Item) * items_capacity);
+ }
n_items = 0;
- n_lines = 0;
/* default line in case the first *FFLine is missing */
- lines[0].n = 0;
- lines[0].justify = L_CENTER;
- lines[0].size_x = lines[0].size_y = 0;
- lines[0].items = (Item **)malloc(sizeof(Item *) * ITEMS_PER_LINE);
- cur_line = lines;
+ ensure_line_capacity(1);
+ n_lines = 0;
+ cur_line = add_line(L_CENTER);
/* default button is for initial functions */
cur_button = &def_button;
def_button.button.n = 0;
- def_button.button.commands = (char **)malloc(sizeof(char *) * MAX_ITEMS);
+ if (!def_button.button.commands) {
+ def_button.button.commands = (char **)malloc(sizeof(char *) * 8);
+ def_button.button.commands_cap = 8;
+ }
def_button.button.key = IB_CONTINUE;
+ cur_sel = NULL;
/* default fonts in case the *FFFont's are missing */
xfs[f_text] = xfs[f_input] = xfs[f_button] =
@@ -359,7 +430,16 @@ void ReadConfig ()
continue;
} else if (strncmp(cp, "Line", 4) == 0) {
cp += 4;
- cur_line = lines + n_lines++;
+ if (n_lines == 0) {
+ cur_line = add_line(L_CENTER);
+ } else if (n_lines == 1 && lines[0].n == 0) {
+ cur_line = &lines[0];
+ cur_line->n = 0;
+ cur_line->size_x = 0;
+ cur_line->size_y = 0;
+ } else {
+ cur_line = add_line(L_CENTER);
+ }
while (isspace(*cp)) cp++;
if (strncmp(cp, "left", 4) == 0)
cur_line->justify = L_LEFT;
@@ -370,12 +450,16 @@ void ReadConfig ()
else
cur_line->justify = L_LEFTRIGHT;
cur_line->n = 0;
- cur_line->items = (Item **)malloc(sizeof(Item *) * ITEMS_PER_LINE);
+ cur_line->size_x = cur_line->size_y = 0;
continue;
} else if (strncmp(cp, "Text", 4) == 0) {
/* syntax: *FFText "<text>" */
cp += 4;
- item = items + n_items++;
+ if (n_items + 1 > items_capacity) {
+ items_capacity = items_capacity ? items_capacity * 2 : INITIAL_ITEMS_CAPACITY;
+ items = (Item *)realloc(items, sizeof(Item) * items_capacity);
+ }
+ item = &items[n_items++];
item->type = I_TEXT;
item->header.name = "";
while (isspace(*cp)) cp++;
@@ -389,13 +473,17 @@ void ReadConfig ()
item->header.size_y = FontHeight(xfs[f_text]) + 2 * TEXT_SPC;
fprintf(fp_err, "Text \"%s\" [%d, %d]\n", item->text.value,
item->header.size_x, item->header.size_y);
- AddToLine(item);
+ append_item_to_line(cur_line, item);
continue;
}
else if (strncmp(cp, "Input", 5) == 0) {
/* syntax: *FFInput <name> <size> "<init_value>" */
cp += 5;
- item = items + n_items++;
+ if (n_items + 1 > items_capacity) {
+ items_capacity = items_capacity ? items_capacity * 2 : INITIAL_ITEMS_CAPACITY;
+ items = (Item *)realloc(items, sizeof(Item) * items_capacity);
+ }
+ item = &items[n_items++];
item->type = I_INPUT;
while (isspace(*cp)) cp++;
item->header.name = CopySolidString(cp);
@@ -419,61 +507,92 @@ void ReadConfig ()
+ 2 * BOX_SPC;
fprintf(fp_err, "Input, %s, [%d], \"%s\"\n", item->header.name,
item->input.size, item->input.init_value);
- AddToLine(item);
+ append_item_to_line(cur_line, item);
}
else if (strncmp(cp, "Selection", 9) == 0) {
/* syntax: *FFSelection <name> single | multiple */
cp += 9;
- cur_sel = items + n_items++;
+ if (n_items + 1 > items_capacity) {
+ items_capacity = items_capacity ? items_capacity * 2 : INITIAL_ITEMS_CAPACITY;
+ items = (Item *)realloc(items, sizeof(Item) * items_capacity);
+ }
+ cur_sel = &items[n_items++];
cur_sel->type = I_SELECT;
while (isspace(*cp)) cp++;
cur_sel->header.name = CopySolidString(cp);
cp += strlen(cur_sel->header.name);
while (isspace(*cp)) cp++;
if (strncmp(cp, "multiple", 8) == 0)
- cur_sel->select.key = IS_MULTIPLE;
+ cur_sel->select.key = IS_MULTIPLE;
else
- cur_sel->select.key = IS_SINGLE;
+ cur_sel->select.key = IS_SINGLE;
cur_sel->select.n = 0;
- cur_sel->select.choices =
- (Item **)malloc(sizeof(Item *) * CHOICES_PER_SEL);
+ cur_sel->select.choices_cap = INITIAL_CHOICES_CAPACITY;
+ cur_sel->select.choices = (Item **)malloc(sizeof(Item *) * cur_sel->select.choices_cap);
+ cur_sel->header.size_x = 0;
+ cur_sel->header.size_y = 0;
+ fprintf(fp_err, "Selection %s (%s)\n", cur_sel->header.name,
+ (cur_sel->select.key == IS_MULTIPLE) ? "multiple" : "single");
continue;
- } else if (strncmp(cp, "Choice", 6) == 0) {
-/* syntax: *FFChoice <name> <value> [on | _off_] ["<text>"] */
+ }
+ else if (strncmp(cp, "Choice", 6) == 0) {
+/* syntax: *FFChoice <name> <value> on|off "<text>" */
cp += 6;
- item = items + n_items++;
- item->type = I_CHOICE;
while (isspace(*cp)) cp++;
+ if (cur_sel == NULL) {
+ fprintf(fp_err, "Choice specified before Selection, skipping\n");
+ continue;
+ }
+ if (cur_sel->select.n + 1 > cur_sel->select.choices_cap) {
+ cur_sel->select.choices_cap *= 2;
+ cur_sel->select.choices = (Item **)realloc(cur_sel->select.choices,
+ sizeof(Item *) * cur_sel->select.choices_cap);
+ }
+ if (n_items + 1 > items_capacity) {
+ items_capacity = items_capacity ? items_capacity * 2 : INITIAL_ITEMS_CAPACITY;
+ items = (Item *)realloc(items, sizeof(Item) * items_capacity);
+ }
+ item = &items[n_items++];
+ item->type = I_CHOICE;
+ item->choice.sel = cur_sel;
item->header.name = CopySolidString(cp);
cp += strlen(item->header.name);
while (isspace(*cp)) cp++;
item->choice.value = CopySolidString(cp);
cp += strlen(item->choice.value);
while (isspace(*cp)) cp++;
- if (strncmp(cp, "on", 2) == 0)
- item->choice.init_on = 1;
- else
- item->choice.init_on = 0;
- while (!isspace(*cp)) cp++;
+ if (strncmp(cp, "on", 2) == 0) {
+ item->choice.on = 1;
+ item->choice.init_on = 1;
+ } else {
+ item->choice.on = 0;
+ item->choice.init_on = 0;
+ }
+ while (!isspace(*cp) && *cp != '\0')
+ cp++;
while (isspace(*cp)) cp++;
- if (*cp == '\"')
- item->choice.text = CopyQuotedString(++cp);
+ if (*cp == '"')
+ item->choice.text = CopyQuotedString(++cp);
else
- item->choice.text = "";
+ item->choice.text = "";
item->choice.n = strlen(item->choice.text);
- item->choice.sel = cur_sel;
cur_sel->select.choices[cur_sel->select.n++] = item;
item->header.size_y = FontHeight(xfs[f_text]) + 2 * TEXT_SPC;
item->header.size_x = FontHeight(xfs[f_text]) + 4 * TEXT_SPC +
XTextWidth(xfs[f_text], item->choice.text, item->choice.n);
fprintf(fp_err, "Choice %s, \"%s\", [%d, %d]\n", item->header.name,
item->choice.text, item->header.size_x, item->header.size_y);
- AddToLine(item);
+ append_item_to_line(cur_line, item);
continue;
- } else if (strncmp(cp, "Button", 6) == 0) {
+ }
+ else if (strncmp(cp, "Button", 6) == 0) {
/* syntax: *FFButton continue | restart | quit "<text>" */
cp += 6;
- item = items + n_items++;
+ if (n_items + 1 > items_capacity) {
+ items_capacity = items_capacity ? items_capacity * 2 : INITIAL_ITEMS_CAPACITY;
+ items = (Item *)realloc(items, sizeof(Item) * items_capacity);
+ }
+ item = &items[n_items++];
item->type = I_BUTTON;
item->header.name = "";
while (isspace(*cp)) cp++;
@@ -497,22 +616,28 @@ void ReadConfig ()
item->button.keypress = 256 + atoi(++cp);
else
item->button.keypress = -1;
- item->button.len = strlen(item->button.text);
- item->button.n = 0;
- item->button.commands = (char **)malloc(sizeof(char *) * MAX_ITEMS);
- item->header.size_y = FontHeight(xfs[f_button]) + 2 * TEXT_SPC
+ item->button.len = strlen(item->button.text);
+ item->button.n = 0;
+ item->button.commands = (char **)malloc(sizeof(char *) * 8);
+ item->button.commands_cap = 8;
+ item->header.size_y = FontHeight(xfs[f_button]) + 2 * TEXT_SPC
+ 2 * BOX_SPC;
- item->header.size_x = 2 * TEXT_SPC + 2 * BOX_SPC
+ item->header.size_x = 2 * TEXT_SPC + 2 * BOX_SPC
+ XTextWidth(xfs[f_button], item->button.text, item->button.len);
- AddToLine(item);
+ append_item_to_line(cur_line, item);
cur_button = item;
continue;
} else if (strncmp(cp, "Command", 7) == 0) {
/* syntax: *FFCommand <command> */
cp += 7;
while (isspace(*cp)) cp++;
+ if (cur_button->button.n + 1 > cur_button->button.commands_cap) {
+ cur_button->button.commands_cap *= 2;
+ cur_button->button.commands = (char **)realloc(cur_button->button.commands,
+ sizeof(char *) * cur_button->button.commands_cap);
+ }
cur_button->button.commands[cur_button->button.n++] =
- CopyNString(cp, 0);
+ CopyNString(cp, 0);
}
} /* end of switch() */
/* get the geometry right */
@@ -696,8 +821,9 @@ void Restart ()
case I_INPUT:
if (!cur_text)
cur_text = item;
- item->input.n = strlen(item->input.init_value);
- strcpy(item->input.value, item->input.init_value);
+ size_t init_len = strlen(item->input.init_value);
+ item->input.n = init_len;
+ strlcpy(item->input.value, item->input.init_value, item->input.buf);
item->input.left = 0;
item->input.o_cursor = 0;
break;
@@ -1503,7 +1629,6 @@ void MainLoop ()
/* main procedure */
int main (int argc, char **argv)
{
- FILE *fdopen();
int i;
buf = (char *)malloc(N); /* some kludge */
Index: app/fvwm/modules/FvwmIconBox/FvwmIconBox.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIconBox/FvwmIconBox.c,v
diff -u -p -u -r1.1.1.1 FvwmIconBox.c
--- app/fvwm/modules/FvwmIconBox/FvwmIconBox.c 26 Nov 2006 10:53:48 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmIconBox/FvwmIconBox.c 25 Oct 2025 19:27:21 -0000
@@ -180,8 +180,11 @@ int main(int argc, char **argv)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+1);
- strcpy(MyName, temp);
+ {
+ size_t name_len = strlen(temp) + 1;
+ MyName = safemalloc(name_len);
+ strlcpy(MyName, temp, name_len);
+ }
signal (SIGPIPE, DeadPipe);
@@ -644,9 +647,9 @@ void RedrawIcon(struct icon_info *item,
h = max_icon_height + icon_relief;
if (item->flags & ICONIFIED){
- sprintf(label, "(%s)", item->name);
+ snprintf(label, sizeof(label), "(%s)", item->name);
}else
- strcpy(label, item->name);
+ strlcpy(label, item->name, sizeof(label));
len = strlen(label);
tw = XTextWidth(font, label, len);
@@ -1734,16 +1737,41 @@ void parsekey(char *tline)
}
XDisplayKeycodes(dpy, &kmin, &kmax);
- for (i=kmin; i<=kmax; i++)
- if (XKeycodeToKeysym(dpy, i, 0) == keysym)
+ {
+ Bool matched = False;
+
+ for (i = kmin; i <= kmax; i++)
+ {
+ KeySym *mapping;
+ int width;
+
+ mapping = XGetKeyboardMapping(dpy, i, 1, &width);
+ if (mapping == NULL)
+ continue;
+
+ for (int col = 0; col < width; col++)
{
+ if (mapping[col] == keysym)
+ {
k = (struct keyfunc *)safemalloc(sizeof(struct keyfunc));
k->name = nptr;
- k->keycode = i;
+ k->keycode = i;
k->action = aptr;
k->next = KeyActions;
KeyActions = k;
+ matched = True;
+ break;
+ }
}
+ XFree(mapping);
+ }
+
+ if (!matched)
+ {
+ free(nptr);
+ free(aptr);
+ }
+ }
}
/***********************************************************************
@@ -1959,8 +1987,8 @@ void process_message(unsigned long type,
RedrawIcon(tmp, 2);
break;
case M_DEFAULTICON:
- str = (char *)safemalloc(strlen((char *)&body[3])+1);
- strcpy(str, (char *)&body[3]);
+ str = (char *)safemalloc(strlen((char *)&body[3])+1);
+ strlcpy(str, (char *)&body[3], strlen((char *)&body[3]) + 1);
FvwmDefaultIcon = str;
break;
case M_ICONIFY:
@@ -2211,8 +2239,9 @@ struct icon_info *UpdateItem(unsigned lo
tmp = Head;
while (tmp != NULL){
if (tmp->id == id){
- str = (char *)safemalloc(strlen(item)+1);
- strcpy(str, item);
+ size_t item_len = strlen(item) + 1;
+ str = (char *)safemalloc(item_len);
+ strlcpy(str, item, item_len);
switch (type){
case M_ICON_NAME:
@@ -2540,8 +2569,22 @@ void ExecuteKey(XEvent event)
return;
tmp = KeyActions;
- event.xkey.keycode =
- XKeysymToKeycode(dpy,XKeycodeToKeysym(dpy,event.xkey.keycode,0));
+ {
+ KeySym *mapping;
+ int width;
+
+ mapping = XGetKeyboardMapping(dpy, event.xkey.keycode, 1, &width);
+ if (mapping != NULL)
+ {
+ KeySym primary = width > 0 ? mapping[0] : NoSymbol;
+ KeyCode canonical = (primary != NoSymbol)
+ ? XKeysymToKeycode(dpy, primary)
+ : 0;
+ if (canonical != 0)
+ event.xkey.keycode = canonical;
+ XFree(mapping);
+ }
+ }
while (tmp != NULL){
if (tmp->keycode == event.xkey.keycode){
SendFvwmPipe(fd, tmp->action, item->id);
Index: app/fvwm/modules/FvwmIconMan/FvwmIconMan.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIconMan/FvwmIconMan.c,v
diff -u -p -u -r1.1.1.1 FvwmIconMan.c
--- app/fvwm/modules/FvwmIconMan/FvwmIconMan.c 26 Nov 2006 10:53:49 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmIconMan/FvwmIconMan.c 25 Oct 2025 19:27:21 -0000
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
+#include <string.h>
#include "FvwmIconMan.h"
#include "readconfig.h"
#include "x.h"
@@ -36,7 +37,7 @@ char *copy_string (char **target, char *
ConsoleDebug (CORE, "copy_string: 2\n");
*target = (char *)safemalloc ((len + 1) * sizeof (char));
- strcpy (*target, src);
+ strlcpy(*target, src, len + 1);
ConsoleDebug (CORE, "copy_string: 3\n");
return *target;
}
Index: app/fvwm/modules/FvwmIconMan/FvwmIconMan.h
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIconMan/FvwmIconMan.h,v
diff -u -p -u -r1.2 FvwmIconMan.h
--- app/fvwm/modules/FvwmIconMan/FvwmIconMan.h 18 Jan 2011 19:28:33 -0000 1.2
+++ app/fvwm/modules/FvwmIconMan/FvwmIconMan.h 25 Oct 2025 19:27:21 -0000
@@ -195,8 +195,8 @@ typedef struct win_data {
char *iconname;
struct win_data *win_prev, *win_next;
struct win_manager *manager;
- int app_id_set : 1;
- int geometry_set : 1;
+ unsigned int app_id_set : 1;
+ unsigned int geometry_set : 1;
Uchar complete;
} WinData;
Index: app/fvwm/modules/FvwmIconMan/readconfig.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIconMan/readconfig.c,v
diff -u -p -u -r1.1.1.1 readconfig.c
--- app/fvwm/modules/FvwmIconMan/readconfig.c 26 Nov 2006 10:53:50 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmIconMan/readconfig.c 25 Oct 2025 19:27:21 -0000
@@ -759,33 +759,57 @@ static Binding *ParseKeyEntry (char *tli
XDisplayKeycodes(theDisplay, &min, &max);
- for (i=min; i<=max; i++) {
- if (XKeycodeToKeysym(theDisplay, i, 0) == keysym) {
- if (!func) {
- func = parse_function_list (action);
- if (!func) {
- ConsoleMessage ("Bad action: %s\n", action);
- return NULL;
- }
- actionstring = stripcpy(action);
- keystring = stripcpy(key);
- }
- temp = new;
- new = (Binding *)safemalloc(sizeof(Binding));
- new->IsMouse = 0;
- new->Button_Key = i;
- new->key_name = keystring;
- new->Modifier = mods;
- new->Action = actionstring;
- new->Function = func;
- new->NextBinding = temp;
- if (!last) {
- last = new;
+ {
+ Bool matched = False;
+
+ for (i = min; i <= max; i++) {
+ KeySym *mapping;
+ int width;
+
+ mapping = XGetKeyboardMapping(theDisplay, i, 1, &width);
+ if (mapping == NULL)
+ continue;
+
+ for (int col = 0; col < width; col++) {
+ if (mapping[col] == keysym) {
+ if (!func) {
+ func = parse_function_list(action);
+ if (!func) {
+ XFree(mapping);
+ ConsoleMessage("Bad action: %s\n", action);
+ return NULL;
+ }
+ actionstring = stripcpy(action);
+ keystring = stripcpy(key);
+ }
+ temp = new;
+ new = (Binding *)safemalloc(sizeof(Binding));
+ new->IsMouse = 0;
+ new->Button_Key = i;
+ new->key_name = keystring;
+ new->Modifier = mods;
+ new->Action = actionstring;
+ new->Function = func;
+ new->NextBinding = temp;
+ if (!last) {
+ last = new;
+ }
+ new->LastBinding = last;
+
+ ConsoleDebug(CONFIG, "Key: %d %s %d %s\n", i, new->key_name,
+ mods, new->Action);
+ matched = True;
+ break;
+ }
}
- new->LastBinding = last;
+ XFree(mapping);
+ }
- ConsoleDebug (CONFIG, "Key: %d %s %d %s\n", i, new->key_name,
- mods, new->Action);
+ if (!matched && func) {
+ Free(actionstring);
+ Free(keystring);
+ free_function_list(func);
+ func = NULL;
}
}
return new;
Index: app/fvwm/modules/FvwmIconMan/winlist.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIconMan/winlist.c,v
diff -u -p -u -r1.1.1.1 winlist.c
--- app/fvwm/modules/FvwmIconMan/winlist.c 26 Nov 2006 10:53:50 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmIconMan/winlist.c 25 Oct 2025 19:27:21 -0000
@@ -1,8 +1,9 @@
#include <limits.h>
+#include <string.h>
#include "FvwmIconMan.h"
static char const rcsid[] =
"$Id$";
#define HASHTAB_SIZE 257
@@ -77,10 +78,11 @@ void add_to_stringlist (StringList *list
type == ALL_NAME ? "all" : s, pat);
new = (StringEl *)safemalloc (sizeof (StringEl));
- new->string = (char *)safemalloc ((strlen (pat) + 1) * sizeof (char));
+ size_t pat_len = strlen(pat);
+ new->string = (char *)safemalloc((pat_len + 1) * sizeof(char));
new->type = type;
- strcpy (new->string, pat);
+ strlcpy(new->string, pat, pat_len + 1);
new->next = list->list;
if (list->list)
list->mask |= type;
Index: app/fvwm/modules/FvwmIconMan/x.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIconMan/x.c,v
diff -u -p -u -r1.1.1.1 x.c
--- app/fvwm/modules/FvwmIconMan/x.c 26 Nov 2006 10:53:50 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmIconMan/x.c 25 Oct 2025 19:27:21 -0000
@@ -205,10 +205,21 @@ void xevent_loop (void)
/* Here's a real hack - some systems have two keys with the
* same keysym and different keycodes. This converts all
* the cases to one keycode. */
- theEvent.xkey.keycode =
- XKeysymToKeycode (theDisplay,
- XKeycodeToKeysym(theDisplay,
- theEvent.xkey.keycode,0));
+ {
+ KeySym *mapping;
+ int width;
+
+ mapping = XGetKeyboardMapping(theDisplay, theEvent.xkey.keycode, 1,
+ &width);
+ if (mapping != NULL) {
+ KeySym primary = (width > 0) ? mapping[0] : NoSymbol;
+ KeyCode canonical =
+ (primary != NoSymbol) ? XKeysymToKeycode(theDisplay, primary) : 0;
+ if (canonical != 0)
+ theEvent.xkey.keycode = canonical;
+ XFree(mapping);
+ }
+ }
modifier = (theEvent.xkey.state & MODS_USED);
ConsoleDebug (X11, "\tKeyPress: %d\n", theEvent.xkey.keycode);
Index: app/fvwm/modules/FvwmIdent/FvwmIdent.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmIdent/FvwmIdent.c,v
diff -u -p -u -r1.1.1.1 FvwmIdent.c
--- app/fvwm/modules/FvwmIdent/FvwmIdent.c 26 Nov 2006 10:53:52 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmIdent/FvwmIdent.c 25 Oct 2025 19:27:22 -0000
@@ -96,9 +96,10 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ size_t name_len = strlen(temp);
+ MyName = safemalloc(name_len + 2);
+ strlcpy(MyName, "*", name_len + 2);
+ strlcat(MyName, temp, name_len + 2);
Clength = strlen(MyName);
if((argc != 6)&&(argc != 7))
@@ -590,13 +591,13 @@ void MakeList(void)
width = target.frame_w - bw;
height = target.frame_h - target.title_h - bw;
- sprintf(desktop, "%ld", target.desktop);
- sprintf(id, "0x%x", (unsigned int)target.id);
- sprintf(swidth, "%d", width);
- sprintf(sheight, "%d", height);
- sprintf(borderw, "%ld", target.border_w);
- sprintf(xstr, "%ld", target.frame_x);
- sprintf(ystr, "%ld", target.frame_y);
+ snprintf(desktop, sizeof(desktop), "%ld", target.desktop);
+ snprintf(id, sizeof(id), "0x%x", (unsigned int)target.id);
+ snprintf(swidth, sizeof(swidth), "%d", width);
+ snprintf(sheight, sizeof(sheight), "%d", height);
+ snprintf(borderw, sizeof(borderw), "%ld", target.border_w);
+ snprintf(xstr, sizeof(xstr), "%ld", target.frame_x);
+ snprintf(ystr, sizeof(ystr), "%ld", target.frame_y);
AddToList("Name:", target.name);
AddToList("Icon Name:", target.icon_name);
@@ -669,37 +670,37 @@ void MakeList(void)
width = (width - target.base_w)/target.width_inc;
height = (height - target.base_h)/target.height_inc;
- sprintf(loc,"%dx%d",width,height);
- strcpy(geometry, loc);
+ snprintf(loc, sizeof(loc), "%dx%d", width, height);
+ strlcpy(geometry, loc, sizeof(geometry));
if ((target.gravity == EastGravity) ||(target.gravity == NorthEastGravity)||
(target.gravity == SouthEastGravity))
- sprintf(loc,"-%d",x2);
+ snprintf(loc, sizeof(loc), "-%d", x2);
else
- sprintf(loc,"+%d",x1);
- strcat(geometry, loc);
+ snprintf(loc, sizeof(loc), "+%d", x1);
+ strlcat(geometry, loc, sizeof(geometry));
if((target.gravity == SouthGravity)||(target.gravity == SouthEastGravity)||
(target.gravity == SouthWestGravity))
- sprintf(loc,"-%d",y2);
+ snprintf(loc, sizeof(loc), "-%d", y2);
else
- sprintf(loc,"+%d",y1);
- strcat(geometry, loc);
+ snprintf(loc, sizeof(loc), "+%d", y1);
+ strlcat(geometry, loc, sizeof(geometry));
AddToList("Geometry:", geometry);
#if 0
{
char tmp[20], *foo;
- sprintf(tmp,"%d", target.base_w);
+ snprintf(tmp, sizeof(tmp), "%d", target.base_w);
foo = strdup(tmp);
AddToList(" - base_w:", foo);
- sprintf(tmp,"%d", target.width_inc);
+ snprintf(tmp, sizeof(tmp), "%d", target.width_inc);
foo = strdup(tmp);
AddToList(" - width_inc:", foo);
- sprintf(tmp,"%d", target.base_h);
+ snprintf(tmp, sizeof(tmp), "%d", target.base_h);
foo = strdup(tmp);
AddToList(" - base_h:", foo);
- sprintf(tmp,"%d", target.height_inc);
+ snprintf(tmp, sizeof(tmp), "%d", target.height_inc);
foo = strdup(tmp);
AddToList(" - height_inc:", foo);
}
@@ -771,10 +772,10 @@ void MakeList(void)
&supplied_return,
XA_WM_ZOOM_HINTS))) {
if (supplied_return & PAspect) { /* if window has a aspect ratio */
- sprintf(mymin_aspect, "%d/%d", size_hints->min_aspect.x,
+ snprintf(mymin_aspect, sizeof(mymin_aspect), "%d/%d", size_hints->min_aspect.x,
size_hints->min_aspect.y);
AddToList("Minimum aspect ratio:",mymin_aspect);
- sprintf(max_aspect, "%d/%d", size_hints->max_aspect.x,
+ snprintf(max_aspect, sizeof(max_aspect), "%d/%d", size_hints->max_aspect.x,
size_hints->max_aspect.y);
AddToList("Maximum aspect ratio:",max_aspect);
} /* end aspect ratio */
Index: app/fvwm/modules/FvwmM4/FvwmM4.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmM4/FvwmM4.c,v
diff -u -p -u -r1.1.1.1 FvwmM4.c
--- app/fvwm/modules/FvwmM4/FvwmM4.c 26 Nov 2006 10:53:52 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmM4/FvwmM4.c 25 Oct 2025 19:27:22 -0000
@@ -49,8 +49,8 @@ int ScreenWidth, ScreenHeight;
int Mscreen;
long Vx, Vy;
-static char *MkDef(char *name, char *def);
-static char *MkNum(char *name,int def);
+static char *MkDef(const char *name, const char *def);
+static char *MkNum(const char *name,int def);
static char *m4_defs(Display *display, const char *host, char *m4_options, char *config_file);
#define MAXHOSTNAME 255
#define EXTRA 50
@@ -82,7 +82,7 @@ int main(int argc, char **argv)
m4_enable = TRUE;
m4_prefix = FALSE;
- strcpy(m4_options,"");
+ m4_options[0] = '\0';
m4_default_quotes = 1;
/* Record the program name for error messages */
@@ -92,9 +92,12 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ {
+ size_t name_len = strlen(temp) + 2;
+ MyName = safemalloc(name_len);
+ strlcpy(MyName, "*", name_len);
+ strlcat(MyName, temp, name_len);
+ }
if(argc < 6)
{
@@ -168,11 +171,13 @@ int main(int argc, char **argv)
filename = argv[i];
}
- for(i=0;i<strlen(filename);i++)
- if((filename[i] == '\n')||(filename[i] == '\r'))
+ if (filename != NULL) {
+ for (i = 0; filename[i] != '\0'; i++)
+ if ((filename[i] == '\n') || (filename[i] == '\r'))
{
filename[i] = 0;
}
+ }
if (!(dpy = XOpenDisplay(display_name)))
{
@@ -215,47 +220,43 @@ static char *m4_defs(Display *display, c
/* Generate a temporary filename. Honor the TMPDIR environment variable,
if set. Hope nobody deletes this file! */
- if (strlen(m4_outfile) == 0) {
- if ((vc=getenv("TMPDIR"))) {
- strlcpy(tmp_name, vc, sizeof(tmp_name));
+ if (m4_outfile[0] == '\0') {
+ const char *tmpdir = getenv("TMPDIR");
+ if (tmpdir != NULL) {
+ strlcpy(tmp_name, tmpdir, sizeof(tmp_name));
} else {
- strlcpy(tmp_name, "/tmp",sizeof(tmp_name));
+ strlcpy(tmp_name, "/tmp", sizeof(tmp_name));
+ }
+ strlcat(tmp_name, "/fvwmrcXXXXXXXXXX", sizeof(tmp_name));
+ fd = mkstemp(tmp_name);
+ if (fd < 0) {
+ perror("mkstemp failed in m4_defs");
+ exit(0377);
}
- strlcat(tmp_name, "/fvwmrcXXXXXXXXXX",sizeof(tmp_name));
- mktemp(tmp_name);
+ close(fd);
} else {
- strlcpy(tmp_name,m4_outfile,sizeof(tmp_name));
- }
-
- if (*tmp_name == '\0')
- {
- perror("mktemp failed in m4_defs");
- exit(0377);
- }
-
- /*
- ** check to make sure it doesn't exist already, to prevent security hole
- */
- if ((fd = open(tmp_name, O_WRONLY|O_EXCL|O_CREAT, 0600)) < 0)
- {
- perror("exclusive open for output file failed in m4_defs");
- exit(0377);
+ strlcpy(tmp_name, m4_outfile, sizeof(tmp_name));
+ fd = open(tmp_name, O_WRONLY | O_EXCL | O_CREAT, 0600);
+ if (fd < 0) {
+ perror("exclusive open for output file failed in m4_defs");
+ exit(0377);
+ }
+ close(fd);
}
- close(fd);
/*
* Create the appropriate command line to run m4, and
* open a pipe to the command.
*/
- if(m4_prefix)
- sprintf(options, "%s --prefix-builtins %s > %s\n",
- m4_prog,
- m4_options, tmp_name);
+ if (m4_prefix)
+ snprintf(options, sizeof(options), "%s --prefix-builtins %s > %s\n",
+ m4_prog,
+ m4_options, tmp_name);
else
- sprintf(options, "%s %s > %s\n",
- m4_prog,
- m4_options, tmp_name);
+ snprintf(options, sizeof(options), "%s %s > %s\n",
+ m4_prog,
+ m4_options, tmp_name);
tmpf = popen(options, "w");
if (tmpf == NULL) {
perror("Cannot open pipe to m4");
@@ -351,18 +352,18 @@ static char *m4_defs(Display *display, c
fputs(MkDef("FVWM_VERSION", VERSION), tmpf);
/* Add options together */
- *options = '\0';
+ options[0] = '\0';
#ifdef SHAPE
- strcat(options, "SHAPE ");
+ strlcat(options, "SHAPE ", sizeof(options));
#endif
#ifdef XPM
- strcat(options, "XPM ");
+ strlcat(options, "XPM ", sizeof(options));
#endif
- strcat(options, "M4 ");
+ strlcat(options, "M4 ", sizeof(options));
#ifdef NO_SAVEUNDERS
- strcat(options, "NO_SAVEUNDERS ");
+ strlcat(options, "NO_SAVEUNDERS ", sizeof(options));
#endif
fputs(MkDef("OPTIONS", options), tmpf);
@@ -402,70 +403,59 @@ void DeadPipe(int nonsense)
-static char *MkDef(char *name, char *def)
+static char *MkDef(const char *name, const char *def)
{
- static char *cp = NULL;
- static int maxsize = 0;
- int n;
-
- /* The char * storage only lasts for 1 call... */
-
- /* Get space to hold everything, if needed */
-
- n = EXTRA + strlen(name) + strlen(def);
- if (n > maxsize) {
- maxsize = n;
- if (cp == NULL) {
- cp = malloc(n);
- } else {
- cp = realloc(cp, n);
- }
- }
-
- if (cp == NULL) {
- perror("MkDef can't allocate enough space for a macro definition");
- exit(0377);
+ static char *cp = NULL;
+ static int maxsize = 0;
+ int needed;
+ const char *prefix = m4_prefix ? "m4_define" : "define";
+ const char *suffix = m4_prefix ? "m4_" : "";
+
+ needed = snprintf(NULL, 0, "%s(%s,%s%s%s%s%s)%sdnl\n",
+ prefix,
+ name,
+ m4_startquote,
+ m4_startquote,
+ def,
+ m4_endquote,
+ m4_endquote,
+ suffix);
+ if (needed < 0) {
+ perror("MkDef failed to calculate length");
+ exit(0377);
+ }
+ needed += 1; /* account for terminating null */
+ if (needed > maxsize) {
+ char *tmp = realloc(cp, needed);
+ if (tmp == NULL) {
+ perror("MkDef can't allocate enough space for a macro definition");
+ free(cp);
+ exit(0377);
}
+ cp = tmp;
+ maxsize = needed;
+ }
- /* Create the macro definition, using the appropriate prefix, if any */
-
- if (m4_prefix)
- {
- strcpy(cp, "m4_define(");
- }
- else
- strcpy(cp, "define(");
-
- strcat(cp, name);
-
- /* Tack on "," and 2 sets of starting quotes */
- strcat(cp, ",");
- strcat(cp, m4_startquote);
- strcat(cp, m4_startquote);
-
- /* The definition itself */
- strcat(cp, def);
-
- /* Add 2 sets of closing quotes */
- strcat(cp, m4_endquote);
- strcat(cp, m4_endquote);
-
- /* End the definition, appropriately */
- strcat(cp, ")");
- if (m4_prefix)
- {
- strcat(cp, "m4_");
- }
-
- strcat(cp, "dnl\n");
+ if (snprintf(cp, maxsize, "%s(%s,%s%s%s%s%s)%sdnl\n",
+ prefix,
+ name,
+ m4_startquote,
+ m4_startquote,
+ def,
+ m4_endquote,
+ m4_endquote,
+ suffix) < 0) {
+ perror("MkDef failed to build macro definition");
+ exit(0377);
+ }
- return(cp);
+ return(cp);
}
-static char *MkNum(char *name,int def)
+static char *MkNum(const char *name,int def)
{
char num[20];
- sprintf(num, "%d", def);
+ snprintf(num, sizeof(num), "%d", def);
return(MkDef(name, num));
}
Index: app/fvwm/modules/FvwmPager/FvwmPager.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmPager/FvwmPager.c,v
diff -u -p -u -r1.2 FvwmPager.c
--- app/fvwm/modules/FvwmPager/FvwmPager.c 18 Nov 2015 17:41:42 -0000 1.2
+++ app/fvwm/modules/FvwmPager/FvwmPager.c 25 Oct 2025 19:27:22 -0000
@@ -122,8 +122,11 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName, temp);
+ {
+ size_t name_len = strlen(temp) + 1;
+ MyName = safemalloc(name_len);
+ strlcpy(MyName, temp, name_len);
+ }
if(argc < 6)
{
@@ -199,7 +202,7 @@ int main(int argc, char **argv)
Desks = (DeskInfo *)safemalloc(ndesks*sizeof(DeskInfo));
for(i=0;i<ndesks;i++)
{
- sprintf(line,"Desk %d",i+desk1);
+ snprintf(line, sizeof(line), "Desk %d", i + desk1);
CopyString(&Desks[i].label,line);
CopyString(&Desks[i].Dcolor,PagerBack);
#ifdef DEBUG
@@ -637,14 +640,14 @@ void list_new_desk(unsigned long *body)
Desks[0].label = NULL;
}
if (item->next != NULL && item->next->label != NULL)
- {
- CopyString(&Desks[0].label, item->next->label);
- }
+ {
+ CopyString(&Desks[0].label, item->next->label);
+ }
else
- {
- sprintf(line, "Desk %d", desk1);
- CopyString(&Desks[0].label, line);
- }
+ {
+ snprintf(line, sizeof(line), "Desk %d", desk1);
+ CopyString(&Desks[0].label, line);
+ }
XStoreName(dpy, Scr.Pager_w, Desks[0].label);
XSetIconName(dpy, Scr.Pager_w, Desks[0].label);
if (Desks[0].Dcolor != NULL)
Index: app/fvwm/modules/FvwmPager/x_pager.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmPager/x_pager.c,v
diff -u -p -u -r1.1.1.1 x_pager.c
--- app/fvwm/modules/FvwmPager/x_pager.c 26 Nov 2006 10:53:53 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmPager/x_pager.c 25 Oct 2025 19:27:22 -0000
@@ -797,12 +797,12 @@ void MovePage(void)
icon_desk_shown = Scr.CurrentDesk;
if((Scr.CurrentDesk >= desk1)&&(Scr.CurrentDesk <=desk2))
- sptr = Desks[Scr.CurrentDesk -desk1].label;
+ sptr = Desks[Scr.CurrentDesk -desk1].label;
else
- {
- sprintf(str,"Desk %d",Scr.CurrentDesk);
- sptr = &str[0];
- }
+ {
+ snprintf(str, sizeof(str), "Desk %d", Scr.CurrentDesk);
+ sptr = &str[0];
+ }
if (XStringListToTextProperty(&sptr,1,&name) == 0)
{
fprintf(stderr,"%s: cannot allocate window name",MyName);
@@ -913,7 +913,7 @@ void DrawGrid(int i, int erase)
w=XTextWidth(font,ptr,strlen(ptr));
if( w > desk_w)
{
- sprintf(str,"%d",d);
+ snprintf(str, sizeof(str), "%d", d);
ptr = str;
w=XTextWidth(font,ptr,strlen(ptr));
}
@@ -979,7 +979,7 @@ void SwitchToDesk(int Desk)
{
char command[256];
- sprintf(command,"Desk 0 %d\n",Desk+desk1);
+ snprintf(command, sizeof(command), "Desk 0 %d\n", Desk + desk1);
SendInfo(fd,command,0);
}
@@ -1001,15 +1001,15 @@ void SwitchToDeskAndPage(int Desk, XEven
(desk_h*Scr.MyDisplayHeight);
Scr.Vx = vx * Scr.MyDisplayWidth;
Scr.Vy = vy * Scr.MyDisplayHeight;
- sprintf(command,"GotoPage %d %d\n", vx, vy);
+ snprintf(command, sizeof(command), "GotoPage %d %d\n", vx, vy);
SendInfo(fd,command,0);
- sprintf(command,"Desk 0 %d\n",Desk+desk1);
+ snprintf(command, sizeof(command), "Desk 0 %d\n", Desk + desk1);
SendInfo(fd,command,0);
}
else
{
- sprintf(command,"GotoPage %d %d\n",
+ snprintf(command, sizeof(command), "GotoPage %d %d\n",
Event->xbutton.x*(Scr.VxMax+Scr.MyDisplayWidth)/
(desk_w*Scr.MyDisplayWidth),
Event->xbutton.y*(Scr.VyMax+Scr.MyDisplayHeight)/
@@ -1025,7 +1025,7 @@ void IconSwitchPage(XEvent *Event)
#ifndef NON_VIRTUAL
char command[256];
- sprintf(command,"GotoPage %d %d\n",
+ snprintf(command, sizeof(command), "GotoPage %d %d\n",
Event->xbutton.x*(Scr.VxMax+Scr.MyDisplayWidth)/
(icon_w*Scr.MyDisplayWidth),
Event->xbutton.y*(Scr.VyMax+Scr.MyDisplayHeight)/
@@ -1344,7 +1344,7 @@ void Scroll(int window_w, int window_h,
if(sx == 0 && x == 0 && Scr.Vx != 0) sx = -1;
if(sy == 0 && y == 0 && Scr.Vy != 0) sy = -1;
- sprintf(command,"Scroll %d %d\n",sx,sy);
+ snprintf(command, sizeof(command), "Scroll %d %d\n", sx, sy);
SendInfo(fd,command,0);
Wait = 1;
}
@@ -1453,7 +1453,7 @@ void MoveWindow(XEvent *Event)
XMoveWindow(dpy,t->w,Scr.MyDisplayWidth+Scr.VxMax,
Scr.MyDisplayHeight+Scr.VyMax);
XSync(dpy,0);
- sprintf(command,"MoveToDesk 0 %d", NewDesk);
+ snprintf(command, sizeof(command), "MoveToDesk 0 %d", NewDesk);
SendInfo(fd,command,t->w);
t->desk = NewDesk;
}
@@ -1468,7 +1468,7 @@ void MoveWindow(XEvent *Event)
x, y, &x1, &y1, &dumwin);
XUngrabPointer(dpy,CurrentTime);
XSync(dpy,0);
- sprintf(command, "Move %dp %dp", x, y);
+ snprintf(command, sizeof(command), "Move %dp %dp", x, y);
SendInfo(fd,command,t->w);
SendInfo(fd,"Raise",t->w);
SendInfo(fd,"Move",t->w);
@@ -1527,7 +1527,7 @@ void MoveWindow(XEvent *Event)
}
else
{
- sprintf(command,"MoveToDesk 0 %d", NewDesk + desk1);
+ snprintf(command, sizeof(command), "MoveToDesk 0 %d", NewDesk + desk1);
SendInfo(fd,command,t->w);
t->desk = NewDesk + desk1;
}
@@ -1852,7 +1852,7 @@ void IconMoveWindow(XEvent *Event,PagerW
x, y, &x1, &y1, &dumwin);
XUngrabPointer(dpy,CurrentTime);
XSync(dpy,0);
- sprintf(command, "Move %dp %dp", x, y);
+ snprintf(command, sizeof(command), "Move %dp %dp", x, y);
SendInfo(fd,command,t->w);
SendInfo(fd,"Raise",t->w);
SendInfo(fd,"Move",t->w);
Index: app/fvwm/modules/FvwmRearrange/FvwmRearrange.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmRearrange/FvwmRearrange.1,v
diff -u -p -u -r1.1.1.1 FvwmRearrange.1
--- app/fvwm/modules/FvwmRearrange/FvwmRearrange.1 26 Nov 2006 10:53:53 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmRearrange/FvwmRearrange.1 25 Oct 2025 19:27:22 -0000
@@ -1,7 +1,7 @@
-.\" $OpenBSD$
-.\" t
-.\" @(#)FvwmRearrange.1 11/9/98
-.de EX \"Begin example
+." $OpenBSD: FvwmRearrange.1,v 2.0 2025/10/18 10:00:00 random Exp $
+." t
+." @(#)FvwmRearrange.1 18/10/25
+.de EX "Begin example
.ne 5
.if n .sp 1
.if t .sp .5
@@ -14,128 +14,121 @@
.if n .sp 1
.if t .sp .5
..
-.TH FvwmRearrange 1 "November 9, 1998" "FvwmRearrange 1.0" "FvwmRearrange 1.0"
+.TH FvwmRearrange 1 "October 18, 2025" "FvwmRearrange 2.0" "FvwmRearrange 2.0"
.UC
.SH NAME
-FvwmRearrange \- rearrange FVWM windows
+FvwmRearrange \- reorganise FVWM clients
.SH SYNOPSIS
-FvwmRearrange is spawned by fvwm, so no command line invocation will work.
+FvwmRearrange is launched internally by fvwm; invoking it directly from a shell
+is not supported.
.SH DESCRIPTION
-This module can be called to tile or cascade windows.
-
-When tiling the module attempts to tile windows on the current screen
-subject to certain constraints. Horizontal or vertical tiling is performed
-so that each window does not overlap another, and by default each window
-is resized to its nearest resize increment (note sometimes some space
-might appear between tiled windows -- this is why).
-
-When cascading the module attempts to cascade windows on the current screen
-subject to certain constraints. Layering is performed so consecutive
-windows will have their window titles visible underneath the previous.
+FvwmRearrange arranges windows either in a tiled grid or in a cascading stack.
+Tiling fills the current screen with non-overlapping frames. Rows or columns
+may be generated automatically so every client finds a slot. When tiling is in
+effect, windows are resized to match their assigned cell unless stretching has
+been disabled, which can leave gaps between tiles.
+
+In cascade mode the module positions successive windows so that the title of
+each client remains visible beneath the one before it. Windows can optionally
+be constrained to a maximum width and height while still honouring the resize
+increment rules.
.SH INVOCATION
-FvwmRearrange is best invoked from a menu, popup or button. There are a
-number of command line options which can be used to constrain the
-layering, these are described below. As an example case, one could
-call FvwmRearrange with the following arguments:
+FvwmRearrange is normally bound to menus, buttons, or key bindings. The module
+accepts a variety of switches that tailor how windows are selected and laid
+out. The following samples show typical usage:
.EX
FvwmRearrange -tile -h 10 10 90 90
.EE
-or
.EX
-FvwmRearrange -cascade \-resize 10 2 80 70
+FvwmRearrange -cascade -resize 10 2 80 70
.EE
-The first invocation will horizontally tile windows with a bounding box
-which starts at 10 by 10 percent into and down the screen and ends at
-90 by 90 percent into and down the screen.
-
-The second invocation will cascade windows starting 10 by 2 percent into and
-down the screen. Windows will be constrained to 80 by 70 percent of
-the screen dimensions. Since the \fIresize\fP is also specified,
-windows will be resized to the given constrained width and height.
-
-FvwmRearrange can be called as FvwmTile or FvwmCascade. This is equivalent
-to providing the -tile or -cascade option. This form is obsolete and
-supplied for backwards compatibility only.
+The first command tiles across the screen horizontally, beginning 10 percent
+from the left and top edges and finishing at the point 90 percent across and
+down. The second command cascades windows starting 10 percent across and
+2 percent down, resizing each client to 80 by 70 percent of the screen when
+possible.
+
+For backward compatibility the module can also be invoked as FvwmTile or
+FvwmCascade, which internally pass \-tile or \-cascade.
-Command-line arguments passed to FvwmRearrange are described here.
+.SH OPTIONS
+The options recognised by FvwmRearrange are described below.
.IP \-a
-Causes \fIall\fP window styles to be affected, even ones with the
-WindowListSkip style.
+Process every window, including those marked with the WindowListSkip style. As
+part of this shortcut, untitled, transient, and maximised clients are also
+selected.
.IP \-cascade
-Cascade windows. This argument must be the first on the command line.
-This is the default.
+Choose cascade mode. If neither \-cascade nor \-tile is supplied, cascade is
+the default behaviour.
.IP \-desk
-Causes all windows on the desk to be cascaded/tiled instead of the
-current screen only.
+Operate on all windows on the current desk rather than limiting the action to
+those that intersect the visible screen.
.IP \-flatx
-Inhibits border width increment. Only used when cascading.
+When cascading, suppress the automatic horizontal offset that would normally be
+added for each step.
.IP \-flaty
-Inhibits border height increment. Only used when cascading.
+When cascading, suppress the automatic vertical offset that would normally be
+added for each step.
.IP \-h
-Tiles horizontally (default is to tile vertically). Used for tiling only.
-.IP "\-incx \fIarg\fP"
-Specifies a horizontal increment which is successively added to
-cascaded windows. \fIarg\fP is a percentage of screen width, or pixel
-value if a \fIp\fP is suffixed. Default is zero. Used only for cascading.
-.IP "\-incy \fIarg\fP"
-Specifies a vertical increment which is successively added to cascaded
-windows. \fIarg\fP is a percentage of screen height, or pixel value
-if a \fIp\fP is suffixed. Default is zero. Used only for cascading.
-
+Tile across the screen first, and then downward. Without this option the module
+tiles vertically.
+.IP "\-incx \fIvalue\fP"
+Add \fIvalue\fP to the horizontal offset between cascaded windows. The value
+is taken as a percentage of the screen width unless suffixed with \fIp\fP, in
+which case it is a pixel amount.
+.IP "\-incy \fIvalue\fP"
+Add \fIvalue\fP to the vertical offset between cascaded windows. Percentages
+are relative to the screen height; appending \fIp\fP forces interpretation as
+pixels.
.IP \-m
-Causes maximized windows to also be affected (implied by \-all).
-.IP "\-mn \fIarg\fP"
-Tiles up to \fIarg\fP windows in tile direction. If more windows
-exist, a new direction row or column is created (in effect, a matrix
-is created). Used only when tiling windows.
+Include maximised windows in the operation (this is implied by \-a).
+.IP "\-mn \fIcount\fP"
+Limit each tile row or column to \fIcount\fP windows before starting another
+row or column. Only meaningful when tiling.
.IP \-noraise
-Inhibits window raising, leaving the depth ordering intact.
+Do not alter the stacking order of affected clients.
.IP \-noresize
-Inhibits window resizing, leaving window sizes intact. This is the default
-when cascading windows.
+Preserve existing window sizes. This is the implicit default when cascading.
.IP \-nostretch
-If tiling: inhibits window growth to fit tile. Windows are shrunk to fit the
-tile but not expanded.
-
-If cascading: inhibits window expansion when using the \-resize option. Windows
-will only shrink to fit the maximal width and height (if given).
+While tiling, only shrink windows to fit their cells; never enlarge them. While
+cascading, do not expand windows beyond the specified maximum size when
+\-resize is active.
.IP \-r
-Reverses the window sequence.
+Reverse the sequence in which windows are processed.
.IP \-resize
-Forces all windows to resize to the constrained width and height (if
-given). This is the default when tiling windows.
+Force clients to adopt the requested tiling or cascade dimensions. This is the
+default when tiling.
.IP \-s
-Causes sticky windows to also be affected (implied by \-all).
+Consider sticky windows along with normal clients (also implied by \-a).
.IP \-t
-Causes transient windows to also be affected (implied by \-all).
+Include transient windows (implied by \-a).
.IP \-tile
-Tile windows. This argument must be the first on the command line.
+Tile windows. If supplied it must appear before other options.
.IP \-u
-Causes untitled windows to also be affected (implied by \-all).
+Include untitled windows (implied by \-a).
+
+You may supply up to four additional numeric arguments. The first two numbers
+specify the initial X and Y offsets, in percentages of the screen size unless
+they end with \fIp\fP to denote pixels. The interpretation of the third and
+fourth numbers varies with the chosen mode:
+.RS
+.TP
+Tiling
+The third and fourth parameters represent the lower-right corner of the tiling
+bounding box.
+.TP
+Cascading
+The third value caps the window width and the fourth value caps the height. A
+window that exceeds either limit is resized down to the limit.
+.RE
-Up to four numbers can be placed on the command line that are not
-switches. The first pair specify an x and y offset to start the first
-window (default is 0, 0).
-The meaning of the second pair depends on operation mode:
-
-When tiling windows it specifies an absolute coordinate reference
-denoting the lower right bounding box for tiling.
-
-When cascading it specifies a maximal width and height for the layered
-windows. If an affected window exceeds either this width or height, it
-is resized to the maximal width or height.
-
-If any number is suffixed with the letter p, then it is taken to be a
-pixel value, otherwise it is interpreted as a screen percentage.
-Specifying zero for any parameter is equivalent to not specifying it.
-
-.SH BUGS
-It is probably not a good idea to delete windows while windows are
-being rearranged.
+Supplying zero for any numeric parameter leaves the corresponding default in
+place.
.SH AUTHORS
Andrew Veliath (original FvwmTile and FvwmCascade modules)
-Dominik Vogt (merged FvwmTile and FvwmCascade to FvwmRearrange)
+Dominik Vogt (merged FvwmTile and FvwmCascade into FvwmRearrange)
+David Uhden Collado (Complete rewrite and modernization)
Index: app/fvwm/modules/FvwmRearrange/FvwmRearrange.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmRearrange/FvwmRearrange.c,v
diff -u -p -u -r1.2 FvwmRearrange.c
--- app/fvwm/modules/FvwmRearrange/FvwmRearrange.c 8 Nov 2015 13:47:41 -0000 1.2
+++ app/fvwm/modules/FvwmRearrange/FvwmRearrange.c 25 Oct 2025 19:27:22 -0000
@@ -1,27 +1,21 @@
/*
- * FvwmRearrange.c -- fvwm module to arrange windows
+ * FvwmRearrange: fvwm module to tile or cascade windows in a region.
*
- * Copyright (C) 1996, 1997, 1998, 1999 Andrew T. Veliath
+ * Copyright (c) 2025 David Uhden Collado <david@uhden.dev>
*
- * Version 1.0
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 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
- *
- * Combined FvwmTile and FvwmCascade to FvwmRearrange module.
- * 9-Nov-1998 Dominik Vogt
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+
#include "config.h"
#include <stdio.h>
@@ -47,583 +41,773 @@
#include "../../fvwm/module.h"
#include "../../fvwm/fvwm.h"
-typedef struct window_item {
- Window frame;
- int th, bw;
- unsigned long width, height;
- struct window_item *prev, *next;
-} window_item, *window_list;
-
-/* vars */
-Display *dpy;
-int dwidth, dheight;
-char *argv0;
-int fd[2], fd_width;
-window_list wins = NULL, wins_tail = NULL;
-int wins_count = 0;
-FILE *console;
-
-/* switches */
-int ofsx = 0, ofsy = 0;
-int maxw = 0, maxh = 0;
-int maxx, maxy;
-int untitled = 0, transients = 0;
-int maximized = 0;
-int all = 0;
-int desk = 0;
-int reversed = 0, raise_window = 1;
-int resize = 0;
-int nostretch = 0;
-int sticky = 0;
-int flatx = 0, flaty = 0;
-int incx = 0, incy = 0;
-int horizontal = 0;
-int maxnum = 0;
-
-char FvwmTile;
-char FvwmCascade;
-
-void insert_window_list(window_list *wl, window_item *i)
-{
- if (*wl) {
- if ((i->prev = (*wl)->prev))
- i->prev->next = i;
- i->next = *wl;
- (*wl)->prev = i;
- } else
- i->next = i->prev = NULL;
- *wl = i;
-}
-
-void free_window_list(window_list *wl)
-{
- window_item *q;
- while (*wl) {
- q = *wl;
- *wl = (*wl)->next;
- free(q);
- }
+void DeadPipe(int sig);
+
+typedef struct ClientNode {
+ Window frame;
+ int title_height;
+ int border_width;
+ unsigned long width;
+ unsigned long height;
+ struct ClientNode *prev;
+ struct ClientNode *next;
+} ClientNode;
+
+typedef struct ModuleState {
+ Display *display;
+ int screen_width;
+ int screen_height;
+ char *program_name;
+ int pipe_fd[2];
+ int fd_width;
+ ClientNode *head;
+ ClientNode *tail;
+ int client_count;
+ FILE *log;
+ int offset_x;
+ int offset_y;
+ int limit_width;
+ int limit_height;
+ int bound_x;
+ int bound_y;
+ int include_untitled;
+ int include_transients;
+ int include_maximized;
+ int include_sticky;
+ int include_all;
+ int entire_desk;
+ int reverse_order;
+ int raise_clients;
+ int resize_clients;
+ int avoid_stretch;
+ int flat_x;
+ int flat_y;
+ int step_x;
+ int step_y;
+ int tile_horizontal;
+ int tile_limit;
+ char run_tile;
+ char run_cascade;
+} ModuleState;
+
+static ModuleState g_state = {
+ .raise_clients = 1
+};
+
+static void
+prepend_client(ModuleState *state, ClientNode *node)
+{
+ node->prev = NULL;
+ node->next = state->head;
+ if (state->head) {
+ state->head->prev = node;
+ } else {
+ state->tail = node;
+ }
+ state->head = node;
+ ++state->client_count;
}
-int is_suitable_window(unsigned long *body)
+static void
+release_clients(ModuleState *state)
{
- XWindowAttributes xwa;
- unsigned long flags = body[8];
+ ClientNode *cursor = state->head;
+ while (cursor) {
+ ClientNode *next = cursor->next;
+ free(cursor);
+ cursor = next;
+ }
+ state->head = NULL;
+ state->tail = NULL;
+ state->client_count = 0;
+}
- if ((flags&WINDOWLISTSKIP) && !all)
- return 0;
+static ClientNode *
+find_client(ModuleState *state, Window frame)
+{
+ for (ClientNode *cursor = state->head; cursor; cursor = cursor->next) {
+ if (cursor->frame == frame) {
+ return cursor;
+ }
+ }
+ return NULL;
+}
- if ((flags&MAXIMIZED) && !maximized)
- return 0;
-
- if ((flags&STICKY) && !sticky)
- return 0;
-
- if (!XGetWindowAttributes(dpy, (Window)body[1], &xwa))
- return 0;
-
- if (xwa.map_state != IsViewable)
- return 0;
+static void
+detach_client(ModuleState *state, ClientNode *node)
+{
+ if (!node) {
+ return;
+ }
+ if (node->prev) {
+ node->prev->next = node->next;
+ } else {
+ state->head = node->next;
+ }
+ if (node->next) {
+ node->next->prev = node->prev;
+ } else {
+ state->tail = node->prev;
+ }
+ free(node);
+ --state->client_count;
+}
- if (!(flags&MAPPED))
- return 0;
+static int
+window_matches(ModuleState *state, unsigned long *body)
+{
+ unsigned long flags = body[8];
+ XWindowAttributes xwa;
- if (flags&ICONIFIED)
- return 0;
+ if ((flags & WINDOWLISTSKIP) && !state->include_all) {
+ return 0;
+ }
+ if ((flags & MAXIMIZED) && !state->include_maximized) {
+ return 0;
+ }
+ if ((flags & STICKY) && !state->include_sticky) {
+ return 0;
+ }
+ if (!XGetWindowAttributes(state->display, (Window)body[1], &xwa)) {
+ return 0;
+ }
+ if (xwa.map_state != IsViewable) {
+ return 0;
+ }
+ if (!(flags & MAPPED)) {
+ return 0;
+ }
+ if (flags & ICONIFIED) {
+ return 0;
+ }
+ if (!state->entire_desk) {
+ int x = (int)body[3];
+ int y = (int)body[4];
+ int w = (int)body[5];
+ int h = (int)body[6];
+ if (!((x < state->screen_width) && (y < state->screen_height) &&
+ (x + w > 0) && (y + h > 0))) {
+ return 0;
+ }
+ }
+ if (!(flags & TITLE) && !state->include_untitled) {
+ return 0;
+ }
+ if ((flags & TRANSIENT) && !state->include_transients) {
+ return 0;
+ }
+ return 1;
+}
- if (!desk) {
- int x = (int)body[3], y = (int)body[4];
- int w = (int)body[5], h = (int)body[6];
- if (!((x < dwidth) && (y < dheight)
- && (x + w > 0) && (y + h > 0)))
- return 0;
- }
-
- if (!(flags&TITLE) && !untitled)
- return 0;
+static int
+collect_client(ModuleState *state)
+{
+ unsigned long header[HEADER_SIZE];
+ unsigned long *body;
+ fd_set infds;
+ int keep_running = 1;
+
+ FD_ZERO(&infds);
+ FD_SET(state->pipe_fd[1], &infds);
+ select(state->fd_width, &infds, NULL, NULL, NULL);
+
+ if (ReadFvwmPacket(state->pipe_fd[1], header, &body) > 0) {
+ switch (header[1]) {
+ case M_CONFIGURE_WINDOW:
+ if (window_matches(state, body)) {
+ ClientNode *node = (ClientNode *)safemalloc(sizeof(ClientNode));
+ node->frame = (Window)body[1];
+ node->title_height = (int)body[9];
+ node->border_width = (int)body[10];
+ node->width = body[5];
+ node->height = body[6];
+ prepend_client(state, node);
+ }
+ break;
+ case M_DESTROY_WINDOW:
+ if (body) {
+ ClientNode *node = find_client(state, (Window)body[1]);
+ if (node) {
+ detach_client(state, node);
+ }
+ }
+ break;
+ case M_END_WINDOWLIST:
+ keep_running = 0;
+ break;
+ default:
+ fprintf(state->log,
+ "%s: internal inconsistency: unknown message\n",
+ state->program_name);
+ break;
+ }
+ free(body);
+ } else {
+ keep_running = 0;
+ }
- if ((flags&TRANSIENT) && !transients)
- return 0;
+ return keep_running;
+}
- return 1;
+static int
+await_configure(ModuleState *state, ClientNode *node)
+{
+ for (;;) {
+ unsigned long header[HEADER_SIZE];
+ unsigned long *body;
+ fd_set infds;
+
+ FD_ZERO(&infds);
+ FD_SET(state->pipe_fd[1], &infds);
+ select(state->fd_width, &infds, NULL, NULL, NULL);
+
+ if (ReadFvwmPacket(state->pipe_fd[1], header, &body) > 0) {
+ switch (header[1]) {
+ case M_CONFIGURE_WINDOW:
+ if (body && (Window)body[1] == node->frame) {
+ free(body);
+ return 1;
+ }
+ break;
+ case M_DESTROY_WINDOW:
+ if (body) {
+ Window frame = (Window)body[1];
+ if (frame == node->frame) {
+ free(body);
+ return 0;
+ }
+ ClientNode *other = find_client(state, frame);
+ if (other) {
+ detach_client(state, other);
+ }
+ }
+ break;
+ case M_END_WINDOWLIST:
+ break;
+ default:
+ break;
+ }
+ free(body);
+ } else {
+ return 0;
+ }
+ }
}
-int get_window(void)
+static int
+parse_metric(const char *token, unsigned long reference)
{
- unsigned long header[HEADER_SIZE], *body;
- int count, last = 0;
- fd_set infds;
- FD_ZERO(&infds);
- FD_SET(fd[1], &infds);
- select(fd_width,&infds, 0, 0, NULL);
- if ((count = ReadFvwmPacket(fd[1],header,&body)) > 0) {
- switch (header[1])
- {
- case M_CONFIGURE_WINDOW:
- if (is_suitable_window(body)) {
- window_item *wi =
- (window_item*)safemalloc(sizeof( window_item ));
- wi->frame = (Window)body[1];
- wi->th = (int)body[9];
- wi->bw = (int)body[10];
- wi->width = body[5];
- wi->height = body[6];
- if (!wins_tail) wins_tail = wi;
- insert_window_list(&wins, wi);
- ++wins_count;
- }
- last = 1;
- break;
-
- case M_END_WINDOWLIST:
- break;
-
- default:
- fprintf(console,
- "%s: internal inconsistency: unknown message\n",
- argv0);
- break;
- }
- free(body);
- }
- return last;
-}
-
-void wait_configure(window_item *wi)
-{
- int found = 0;
- unsigned long header[HEADER_SIZE], *body;
- int count;
- fd_set infds;
- FD_ZERO(&infds);
- FD_SET(fd[1], &infds);
- select(fd_width,&infds, 0, 0, NULL);
- while (!found)
- if ((count = ReadFvwmPacket(fd[1],header,&body)) > 0) {
- if ((header[1] == M_CONFIGURE_WINDOW)
- && (Window)body[1] == wi->frame)
- found = 1;
- free(body);
- }
-}
-
-int atopixel(char *s, unsigned long f)
-{
- int l = strlen(s);
- if (l < 1) return 0;
- if (isalpha(s[l - 1])) {
- char s2[24];
- strcpy(s2,s);
- s2[strlen(s2) - 1] = 0;
- return atoi(s2);
- }
- return (atoi(s) * f) / 100;
-}
-
-void tile_windows(void)
-{
- char msg[128];
- int cur_x = ofsx, cur_y = ofsy;
- int wdiv, hdiv, i, j, count = 1;
- window_item *w = reversed ? wins_tail : wins;
-
- if (horizontal) {
- if ((maxnum > 0) && (maxnum < wins_count)) {
- count = wins_count / maxnum;
- if (wins_count % maxnum) ++count;
- hdiv = (maxy - ofsy + 1) / maxnum;
- } else {
- maxnum = wins_count;
- hdiv = (maxy - ofsy + 1) / wins_count;
+ char *endptr;
+ long value;
+
+ if (!token || !*token) {
+ return 0;
}
- wdiv = (maxx - ofsx + 1) / count;
- for (i = 0; w && (i < count); ++i) {
- for (j = 0; w && (j < maxnum); ++j) {
- int nw = wdiv - w->bw * 2;
- int nh = hdiv - w->bw * 2 - w->th;
-
- if (resize) {
- if (nostretch) {
- if (nw > w->width)
- nw = w->width;
- if (nh > w->height)
- nh = w->height;
- }
- sprintf(msg, "Resize %lup %lup",
- (nw > 0) ? nw : w->width,
- (nh > 0) ? nh : w->height);
- SendInfo(fd,msg,w->frame);
- }
- sprintf(msg, "Move %up %up", cur_x, cur_y);
- SendInfo(fd,msg,w->frame);
- if (raise_window)
- SendInfo(fd,"Raise",w->frame);
- cur_y += hdiv;
- wait_configure(w);
- w = reversed ? w->prev : w->next;
- }
- cur_x += wdiv;
- cur_y = ofsy;
- }
- } else {
- if ((maxnum > 0) && (maxnum < wins_count)) {
- count = wins_count / maxnum;
- if (wins_count % maxnum) ++count;
- wdiv = (maxx - ofsx + 1) / maxnum;
+ value = strtol(token, &endptr, 10);
+ if (endptr && *endptr && isalpha((unsigned char)*endptr)) {
+ return (int)value;
+ }
+ return (int)((value * (long)reference) / 100);
+}
+
+static void
+send_resize(ModuleState *state, const ClientNode *node,
+ unsigned long width, unsigned long height)
+{
+ char command[128];
+
+ snprintf(command, sizeof(command), "Resize %lup %lup",
+ width, height);
+ SendInfo(state->pipe_fd, command, node->frame);
+}
+
+static void
+send_move(ModuleState *state, const ClientNode *node, int x, int y)
+{
+ char command[128];
+
+ snprintf(command, sizeof(command), "Move %up %up", x, y);
+ SendInfo(state->pipe_fd, command, node->frame);
+}
+
+static void
+tile_clients(ModuleState *state)
+{
+ ClientNode *cursor = state->reverse_order ? state->tail : state->head;
+ int stripes = 1;
+ int slots_per_stripe;
+ int wdiv;
+ int hdiv;
+ int current_x = state->offset_x;
+ int current_y = state->offset_y;
+ int limit = state->tile_limit;
+
+ if (state->tile_horizontal) {
+ if ((limit > 0) && (limit < state->client_count)) {
+ stripes = state->client_count / limit;
+ if (state->client_count % limit) {
+ ++stripes;
+ }
+ hdiv = (state->bound_y - state->offset_y + 1) / limit;
+ } else {
+ limit = state->client_count;
+ state->tile_limit = limit;
+ hdiv = (state->bound_y - state->offset_y + 1) / state->client_count;
+ }
+ slots_per_stripe = limit;
+ wdiv = (state->bound_x - state->offset_x + 1) / stripes;
+
+ for (int s = 0; cursor && (s < stripes); ++s) {
+ for (int slot = 0; cursor && (slot < slots_per_stripe); ++slot) {
+ int new_width = wdiv - cursor->border_width * 2;
+ int new_height = hdiv - cursor->border_width * 2 - cursor->title_height;
+
+ if (state->resize_clients) {
+ if (state->avoid_stretch) {
+ if (new_width > (int)cursor->width) {
+ new_width = (int)cursor->width;
+ }
+ if (new_height > (int)cursor->height) {
+ new_height = (int)cursor->height;
+ }
+ }
+ send_resize(state, cursor,
+ (new_width > 0) ? (unsigned long)new_width : cursor->width,
+ (new_height > 0) ? (unsigned long)new_height : cursor->height);
+ }
+
+ send_move(state, cursor, current_x, current_y);
+ if (state->raise_clients) {
+ SendInfo(state->pipe_fd, "Raise", cursor->frame);
+ }
+
+ current_y += hdiv;
+ {
+ int alive = await_configure(state, cursor);
+ ClientNode *next = state->reverse_order ? cursor->prev : cursor->next;
+ if (!alive) {
+ detach_client(state, cursor);
+ }
+ cursor = next;
+ }
+ }
+ current_x += wdiv;
+ current_y = state->offset_y;
+ }
} else {
- maxnum = wins_count;
- wdiv = (maxx - ofsx + 1) / wins_count;
+ if ((limit > 0) && (limit < state->client_count)) {
+ stripes = state->client_count / limit;
+ if (state->client_count % limit) {
+ ++stripes;
+ }
+ wdiv = (state->bound_x - state->offset_x + 1) / limit;
+ } else {
+ limit = state->client_count;
+ state->tile_limit = limit;
+ wdiv = (state->bound_x - state->offset_x + 1) / state->client_count;
+ }
+ slots_per_stripe = limit;
+ hdiv = (state->bound_y - state->offset_y + 1) / stripes;
+
+ for (int s = 0; cursor && (s < stripes); ++s) {
+ for (int slot = 0; cursor && (slot < slots_per_stripe); ++slot) {
+ int new_width = wdiv - cursor->border_width * 2;
+ int new_height = hdiv - cursor->border_width * 2 - cursor->title_height;
+
+ if (state->resize_clients) {
+ if (state->avoid_stretch) {
+ if (new_width > (int)cursor->width) {
+ new_width = (int)cursor->width;
+ }
+ if (new_height > (int)cursor->height) {
+ new_height = (int)cursor->height;
+ }
+ }
+ send_resize(state, cursor,
+ (new_width > 0) ? (unsigned long)new_width : cursor->width,
+ (new_height > 0) ? (unsigned long)new_height : cursor->height);
+ }
+
+ send_move(state, cursor, current_x, current_y);
+ if (state->raise_clients) {
+ SendInfo(state->pipe_fd, "Raise", cursor->frame);
+ }
+
+ current_x += wdiv;
+ {
+ int alive = await_configure(state, cursor);
+ ClientNode *next = state->reverse_order ? cursor->prev : cursor->next;
+ if (!alive) {
+ detach_client(state, cursor);
+ }
+ cursor = next;
+ }
+ }
+ current_x = state->offset_x;
+ current_y += hdiv;
+ }
}
- hdiv = (maxy - ofsy + 1) / count;
+}
+
+static void
+cascade_clients(ModuleState *state)
+{
+ ClientNode *cursor = state->reverse_order ? state->tail : state->head;
+ int current_x = state->offset_x;
+ int current_y = state->offset_y;
+
+ while (cursor) {
+ unsigned long target_width = 0;
+ unsigned long target_height = 0;
+ int advance_x = state->step_x;
+ int advance_y = state->step_y;
+
+ if (state->raise_clients) {
+ SendInfo(state->pipe_fd, "Raise", cursor->frame);
+ }
+
+ send_move(state, cursor, current_x, current_y);
- for (i = 0; w && (i < count); ++i) {
- for (j = 0; w && (j < maxnum); ++j) {
- int nw = wdiv - w->bw * 2;
- int nh = hdiv - w->bw * 2 - w->th;
-
- if (resize) {
- if (nostretch) {
- if (nw > w->width)
- nw = w->width;
- if (nh > w->height)
- nh = w->height;
- }
- sprintf(msg, "Resize %lup %lup",
- (nw > 0) ? nw : w->width,
- (nh > 0) ? nh : w->height);
- SendInfo(fd,msg,w->frame);
- }
- sprintf(msg, "Move %up %up", cur_x, cur_y);
- SendInfo(fd,msg,w->frame);
- if (raise_window)
- SendInfo(fd,"Raise",w->frame);
- cur_x += wdiv;
- wait_configure(w);
- w = reversed ? w->prev : w->next;
- }
- cur_x = ofsx;
- cur_y += hdiv;
- }
- }
-}
-
-void cascade_windows(void)
-{
- char msg[128];
- int cur_x = ofsx, cur_y = ofsy;
- window_item *w = reversed ? wins_tail : wins;
- while (w)
- {
- unsigned long nw = 0, nh = 0;
- if (raise_window)
- SendInfo(fd,"Raise",w->frame);
- sprintf(msg, "Move %up %up", cur_x, cur_y);
- SendInfo(fd,msg,w->frame);
- if (resize) {
- if (nostretch) {
- if (maxw
- && (w->width > maxw))
- nw = maxw;
- if (maxh
- && (w->height > maxh))
- nh = maxh;
- } else {
- nw = maxw;
- nh = maxh;
- }
- if (nw || nh) {
- sprintf(msg, "Resize %lup %lup",
- nw ? nw : w->width,
- nh ? nh : w->height);
- SendInfo(fd,msg,w->frame);
- }
- }
- wait_configure(w);
- if (!flatx)
- cur_x += w->bw;
- cur_x += incx;
- if (!flaty)
- cur_y += w->bw + w->th;
- cur_y += incy;
- w = reversed ? w->prev : w->next;
- }
-}
-
-void parse_args(char *s, int argc, char *argv[], int argi)
-{
- int nsargc = 0;
- /* parse args */
- for (; argi < argc; ++argi)
- {
- if (!strcmp(argv[argi],"-tile") || !strcmp(argv[argi],"-cascade")) {
- /* ignore */
- }
- else if (!strcmp(argv[argi],"-u")) {
- untitled = 1;
- }
- else if (!strcmp(argv[argi],"-t")) {
- transients = 1;
- }
- else if (!strcmp(argv[argi], "-a")) {
- all = untitled = transients = maximized = 1;
- if (FvwmCascade)
- sticky = 1;
- }
- else if (!strcmp(argv[argi], "-r")) {
- reversed = 1;
- }
- else if (!strcmp(argv[argi], "-noraise")) {
- raise_window = 0;
- }
- else if (!strcmp(argv[argi], "-noresize")) {
- resize = 0;
- }
- else if (!strcmp(argv[argi], "-nostretch")) {
- nostretch = 1;
- }
- else if (!strcmp(argv[argi], "-desk")) {
- desk = 1;
- }
- else if (!strcmp(argv[argi], "-flatx")) {
- flatx = 1;
- }
- else if (!strcmp(argv[argi], "-flaty")) {
- flaty = 1;
- }
- else if (!strcmp(argv[argi], "-r")) {
- reversed = 1;
- }
- else if (!strcmp(argv[argi], "-h")) {
- horizontal = 1;
- }
- else if (!strcmp(argv[argi], "-m")) {
- maximized = 1;
- }
- else if (!strcmp(argv[argi], "-s")) {
- sticky = 1;
- }
- else if (!strcmp(argv[argi], "-mn") && ((argi + 1) < argc)) {
- maxnum = atoi(argv[++argi]);
- }
- else if (!strcmp(argv[argi], "-resize")) {
- resize = 1;
- }
- else if (!strcmp(argv[argi], "-nostretch")) {
- nostretch = 1;
- }
- else if (!strcmp(argv[argi], "-incx") && ((argi + 1) < argc)) {
- incx = atopixel(argv[++argi], dwidth);
- }
- else if (!strcmp(argv[argi], "-incy") && ((argi + 1) < argc)) {
- incy = atopixel(argv[++argi], dheight);
- }
- else {
- if (++nsargc > 4) {
- fprintf(console,
- "%s: %s: ignoring unknown arg %s\n",
- argv0, s, argv[argi]);
- continue;
- }
- if (nsargc == 1) {
- ofsx = atopixel(argv[argi], dwidth);
- } else if (nsargc == 2) {
- ofsy = atopixel(argv[argi], dheight);
- } else if (nsargc == 3) {
- if (FvwmCascade)
- maxw = atopixel(argv[argi], dwidth);
- else /* FvwmTile */
- maxx = atopixel(argv[argi], dwidth);
- } else if (nsargc == 4) {
- if (FvwmCascade)
- maxh = atopixel(argv[argi], dheight);
- else /* FvwmTile */
- maxy = atopixel(argv[argi], dheight);
- }
+ if (state->resize_clients) {
+ if (state->avoid_stretch) {
+ if (state->limit_width && cursor->width > (unsigned long)state->limit_width) {
+ target_width = (unsigned long)state->limit_width;
+ }
+ if (state->limit_height && cursor->height > (unsigned long)state->limit_height) {
+ target_height = (unsigned long)state->limit_height;
+ }
+ } else {
+ target_width = state->limit_width;
+ target_height = state->limit_height;
+ }
+
+ if (target_width || target_height) {
+ send_resize(state, cursor,
+ target_width ? target_width : cursor->width,
+ target_height ? target_height : cursor->height);
+ }
+ }
+
+ if (!state->flat_x) {
+ advance_x += cursor->border_width;
+ }
+ if (!state->flat_y) {
+ advance_y += cursor->border_width + cursor->title_height;
+ }
+
+ {
+ int alive = await_configure(state, cursor);
+ ClientNode *next = state->reverse_order ? cursor->prev : cursor->next;
+ if (!alive) {
+ detach_client(state, cursor);
+ }
+ cursor = next;
+ }
+
+ current_x += advance_x;
+ current_y += advance_y;
+ }
+}
+
+static void
+parse_arguments(ModuleState *state, const char *source, int argc,
+ char *argv[], int start_index)
+{
+ int positional = 0;
+
+ for (int i = start_index; i < argc; ++i) {
+ const char *arg = argv[i];
+
+ if (!strcmp(arg, "-tile") || !strcmp(arg, "-cascade")) {
+ continue;
+ } else if (!strcmp(arg, "-u")) {
+ state->include_untitled = 1;
+ } else if (!strcmp(arg, "-t")) {
+ state->include_transients = 1;
+ } else if (!strcmp(arg, "-a")) {
+ state->include_all = 1;
+ state->include_untitled = 1;
+ state->include_transients = 1;
+ state->include_maximized = 1;
+ if (state->run_cascade) {
+ state->include_sticky = 1;
+ }
+ } else if (!strcmp(arg, "-r")) {
+ state->reverse_order = 1;
+ } else if (!strcmp(arg, "-noraise")) {
+ state->raise_clients = 0;
+ } else if (!strcmp(arg, "-noresize")) {
+ state->resize_clients = 0;
+ } else if (!strcmp(arg, "-nostretch")) {
+ state->avoid_stretch = 1;
+ } else if (!strcmp(arg, "-desk")) {
+ state->entire_desk = 1;
+ } else if (!strcmp(arg, "-flatx")) {
+ state->flat_x = 1;
+ } else if (!strcmp(arg, "-flaty")) {
+ state->flat_y = 1;
+ } else if (!strcmp(arg, "-h")) {
+ state->tile_horizontal = 1;
+ } else if (!strcmp(arg, "-m")) {
+ state->include_maximized = 1;
+ } else if (!strcmp(arg, "-s")) {
+ state->include_sticky = 1;
+ } else if (!strcmp(arg, "-mn") && ((i + 1) < argc)) {
+ state->tile_limit = atoi(argv[++i]);
+ } else if (!strcmp(arg, "-resize")) {
+ state->resize_clients = 1;
+ } else if (!strcmp(arg, "-incx") && ((i + 1) < argc)) {
+ state->step_x = parse_metric(argv[++i], state->screen_width);
+ } else if (!strcmp(arg, "-incy") && ((i + 1) < argc)) {
+ state->step_y = parse_metric(argv[++i], state->screen_height);
+ } else {
+ ++positional;
+ if (positional > 4) {
+ fprintf(state->log,
+ "%s: %s: ignoring unknown arg %s\n",
+ state->program_name, source, arg);
+ continue;
+ }
+
+ if (positional == 1) {
+ state->offset_x = parse_metric(arg, state->screen_width);
+ } else if (positional == 2) {
+ state->offset_y = parse_metric(arg, state->screen_height);
+ } else if (positional == 3) {
+ if (state->run_cascade) {
+ state->limit_width = parse_metric(arg, state->screen_width);
+ } else {
+ state->bound_x = parse_metric(arg, state->screen_width);
+ }
+ } else if (positional == 4) {
+ if (state->run_cascade) {
+ state->limit_height = parse_metric(arg, state->screen_height);
+ } else {
+ state->bound_y = parse_metric(arg, state->screen_height);
+ }
+ }
+ }
}
- }
}
#ifdef USERC
-int parse_line(char *s, char ***args)
+static int
+tokenise_config(char *line, char ***argv_out)
{
- int count = 0, i = 0;
- char *arg_save[48];
- strtok(s, " ");
- while ((s = strtok(NULL, " ")))
- arg_save[count++] = s;
- *args = (char **)safemalloc(sizeof( char * ) * count);
- for (; i < count; ++i)
- (*args)[i] = arg_save[i];
- return count;
+ char *tokens[48];
+ int count = 0;
+ char *cursor = strtok(line, " \t");
+
+ while (cursor && count < 48) {
+ cursor = strtok(NULL, " \t");
+ if (!cursor) {
+ break;
+ }
+ tokens[count++] = cursor;
+ }
+
+ if (count > 0) {
+ *argv_out = (char **)safemalloc(sizeof(char *) * count);
+ for (int i = 0; i < count; ++i) {
+ (*argv_out)[i] = tokens[i];
+ }
+ } else {
+ *argv_out = NULL;
+ }
+
+ return count;
}
#ifdef FVWM1
-char *GetConfigLine(char *filename, char *match)
+static char *
+LoadConfigLine(const char *filename, const char *match)
{
- FILE *f = fopen(filename, "r");
- if (f) {
- int l = strlen(match), found = 0;
- char line[256], *s = line;
- line[0] = 0;
- s = fgets(line, 256, f);
- while (s && !found) {
- if (strncmp(line, match, l) == 0) {
- found = 1;
- break;
- }
- s = fgets(line, 256, f);
- }
- fclose(f);
- if (found) {
- char *ret;
- int l2 = strlen(line);
- ret = (char *)safemalloc(sizeof(char) * l2);
- strcpy(ret, line);
- if (ret[l2 - 1] == '\n')
- ret[l2 - 1] = 0;
- return ret;
- } else
- return NULL;
- } else
+ FILE *f = fopen(filename, "r");
+ if (f) {
+ char line[256];
+ size_t match_len = strlen(match);
+
+ while (fgets(line, sizeof(line), f)) {
+ if (strncmp(line, match, match_len) == 0) {
+ size_t len = strlen(line);
+ char *copy = (char *)safemalloc(len + 1);
+
+ strcpy(copy, line);
+ if (len && copy[len - 1] == '\n') {
+ copy[len - 1] = '\0';
+ }
+ fclose(f);
+ return copy;
+ }
+ }
+ fclose(f);
+ }
return NULL;
}
#endif /* FVWM1 */
#endif /* USERC */
-void DeadPipe(int sig) { exit(0); }
+static void
+handle_sigpipe(int sig)
+{
+ (void)sig;
+ exit(0);
+}
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
{
+ ModuleState *state = &g_state;
+
#ifdef USERC
- char match[128];
- int config_line_count, len;
- char *config_line;
+ char match[128];
+ char *config_line;
#endif
- console = fopen("/dev/console","w");
- if (!console) console = stderr;
+ state->log = fopen("/dev/console", "w");
+ if (!state->log) {
+ state->log = stderr;
+ }
- if (!(argv0 = strrchr(argv[0],'/')))
- argv0 = argv[0];
- else
- ++argv0;
+ state->program_name = strrchr(argv[0], '/');
+ state->program_name = state->program_name ? state->program_name + 1 : argv[0];
- if (argc < 6) {
- fprintf(stderr,
+ if (argc < 6) {
#ifdef FVWM1
- "%s: module should be executed by fvwm only\n",
+ fprintf(stderr, "%s: module should be executed by fvwm only\n",
+ state->program_name);
#else
- "%s: module should be executed by fvwm2 only\n",
+ fprintf(stderr, "%s: module should be executed by fvwm2 only\n",
+ state->program_name);
#endif
- argv0);
- exit(-1);
- }
-
- fd[0] = atoi(argv[1]);
- fd[1] = atoi(argv[2]);
-
- if (!(dpy = XOpenDisplay(NULL))) {
- fprintf(console, "%s: couldn't open display %s\n",
- argv0,
- XDisplayName(NULL));
- exit(-1);
- }
- signal (SIGPIPE, DeadPipe);
-
- {
- int s = DefaultScreen(dpy);
- dwidth = DisplayWidth(dpy, s);
- dheight = DisplayHeight(dpy, s);
- }
+ exit(-1);
+ }
+
+ state->pipe_fd[0] = atoi(argv[1]);
+ state->pipe_fd[1] = atoi(argv[2]);
+
+ state->display = XOpenDisplay(NULL);
+ if (!state->display) {
+ fprintf(state->log, "%s: couldn't open display %s\n",
+ state->program_name, XDisplayName(NULL));
+ exit(-1);
+ }
+
+ signal(SIGPIPE, handle_sigpipe);
+
+ {
+ int screen = DefaultScreen(state->display);
+ state->screen_width = DisplayWidth(state->display, screen);
+ state->screen_height = DisplayHeight(state->display, screen);
+ }
+
+ state->fd_width = GetFdWidth();
- fd_width = GetFdWidth();
-
#ifdef USERC
- strcpy(match, "*");
- strcat(match, argv0);
- len = strlen(match);
+ strcpy(match, "*");
+ strcat(match, state->program_name);
+
#ifdef FVWM1
- if ((config_line = GetConfigLine(argv[3], match))) {
- char **args = NULL;
- config_line_count = parse_line(config_line, &args);
- parse_args("config args",
- config_line_count, args, 0);
- free(config_line);
- free(args);
- }
+ config_line = LoadConfigLine(argv[3], match);
+ if (config_line) {
+ char **args = NULL;
+ int arg_count = tokenise_config(config_line, &args);
+
+ parse_arguments(state, "config args", arg_count, args, 0);
+ free(args);
+ free(config_line);
+ }
#else
- GetConfigLine(fd, &config_line);
- while (config_line != NULL) {
- if (strncmp(match,config_line,len)==0) {
- char **args = NULL;
- int cllen = strlen(config_line);
- if (config_line[cllen - 1] == '\n')
- config_line[cllen - 1] = 0;
- config_line_count = parse_line(config_line, &args);
- parse_args("config args",
- config_line_count, args, 0);
- free(args);
+ GetConfigLine(state->pipe_fd, &config_line);
+ while (config_line) {
+ if (strncmp(match, config_line, strlen(match)) == 0) {
+ char **args = NULL;
+ int len = strlen(config_line);
+ if (len && config_line[len - 1] == '\n') {
+ config_line[len - 1] = '\0';
+ }
+ {
+ int arg_count = tokenise_config(config_line, &args);
+ parse_arguments(state, "config args", arg_count, args, 0);
+ free(args);
+ }
+ }
+ GetConfigLine(state->pipe_fd, &config_line);
}
- GetConfigLine(fd, &config_line);
- }
#endif /* FVWM1 */
#endif /* USERC */
- if (strcmp(argv0, "FvwmCascade") && (!strcmp(argv0, "FvwmTile") ||
- (argc >= 7 && !strcmp(argv[6], "-tile"))))
- {
- FvwmTile = 1;
- FvwmCascade = 0;
- resize = 1;
- }
- else
- {
- FvwmCascade = 1;
- FvwmTile = 0;
- resize = 0;
- }
- parse_args("module args", argc, argv, 6);
+ if (strcmp(state->program_name, "FvwmCascade") &&
+ (!strcmp(state->program_name, "FvwmTile") ||
+ (argc >= 7 && !strcmp(argv[6], "-tile")))) {
+ state->run_tile = 1;
+ state->run_cascade = 0;
+ state->resize_clients = 1;
+ } else {
+ state->run_cascade = 1;
+ state->run_tile = 0;
+ state->resize_clients = 0;
+ }
+
+ parse_arguments(state, "module args", argc, argv, 6);
#ifdef FVWM1
- {
- char msg[256];
- sprintf(msg, "SET_MASK %lu\n",(unsigned long)(
- M_CONFIGURE_WINDOW|
- M_END_WINDOWLIST
- ));
- SendInfo(fd,msg,0);
-
+ {
+ char msg[256];
+ snprintf(msg, sizeof(msg), "SET_MASK %lu\n",
+ (unsigned long)(M_CONFIGURE_WINDOW | M_DESTROY_WINDOW |
+ M_END_WINDOWLIST));
+ SendInfo(state->pipe_fd, msg, 0);
+
#ifdef FVWM1_MOVENULL
- /* avoid interactive placement in fvwm version 1 */
- if (!ofsx) ++ofsx;
- if (!ofsy) ++ofsy;
+ if (!state->offset_x) {
+ ++state->offset_x;
+ }
+ if (!state->offset_y) {
+ ++state->offset_y;
+ }
#endif
- }
+ }
#else
- SetMessageMask(fd,
- M_CONFIGURE_WINDOW
- | M_END_WINDOWLIST
- );
+ SetMessageMask(state->pipe_fd,
+ M_CONFIGURE_WINDOW | M_DESTROY_WINDOW | M_END_WINDOWLIST);
#endif
- if (FvwmTile)
- {
- if (!maxx) maxx = dwidth;
- if (!maxy) maxy = dheight;
- }
-
- SendInfo(fd,"Send_WindowList",0);
- while (get_window());
- if (wins_count)
- {
- if (FvwmCascade)
- cascade_windows();
- else /* FvwmTile */
- tile_windows();
- }
- free_window_list(&wins);
- if (console != stderr)
- fclose(console);
- return 0;
+ if (state->run_tile) {
+ if (!state->bound_x) {
+ state->bound_x = state->screen_width;
+ }
+ if (!state->bound_y) {
+ state->bound_y = state->screen_height;
+ }
+ }
+
+ SendInfo(state->pipe_fd, "Send_WindowList", 0);
+ while (collect_client(state)) {
+ /* keep reading until the end marker arrives */
+ }
+
+ if (state->client_count) {
+ if (state->run_cascade) {
+ cascade_clients(state);
+ } else {
+ tile_clients(state);
+ }
+ }
+
+ release_clients(state);
+
+ if (state->log != stderr) {
+ fclose(state->log);
+ }
+
+ return 0;
+}
+
+void
+DeadPipe(int sig)
+{
+ (void)sig;
+ exit(0);
}
Index: app/fvwm/modules/FvwmSave/FvwmSave.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmSave/FvwmSave.c,v
diff -u -p -u -r1.1.1.1 FvwmSave.c
--- app/fvwm/modules/FvwmSave/FvwmSave.c 26 Nov 2006 10:53:54 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmSave/FvwmSave.c 25 Oct 2025 19:27:22 -0000
@@ -58,9 +58,10 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ size_t name_len = strlen(temp);
+ MyName = safemalloc(name_len + 2);
+ strlcpy(MyName, "*", name_len + 2);
+ strlcat(MyName, temp, name_len + 2);
if((argc != 6)&&(argc != 7))
{
@@ -287,7 +288,7 @@ void do_save(void)
int x1,x2,y1,y2,i,command_count;
long tVx, tVy;
- sprintf(tname, "%s/new.xinitrc", getenv( "HOME" ) );
+ snprintf(tname, sizeof(tname), "%s/new.xinitrc", getenv("HOME"));
out = fopen( tname, "w+" );
for (t = list_root; t != NULL; t = t->next)
{
@@ -318,22 +319,22 @@ void do_save(void)
tVx = Vx;
tVy = Vy;
}
- sprintf(tname,"%dx%d",dwidth,dheight);
+ snprintf(tname, sizeof(tname), "%dx%d", dwidth, dheight);
if ((t->gravity == EastGravity) ||
(t->gravity == NorthEastGravity) ||
(t->gravity == SouthEastGravity))
- sprintf(loc,"-%d",x2);
+ snprintf(loc, sizeof(loc), "-%d", x2);
else
- sprintf(loc,"+%d",x1+(int)tVx);
- strcat(tname, loc);
+ snprintf(loc, sizeof(loc), "+%d", x1 + (int)tVx);
+ strlcat(tname, loc, sizeof(tname));
if((t->gravity == SouthGravity)||
(t->gravity == SouthEastGravity)||
(t->gravity == SouthWestGravity))
- sprintf(loc,"-%d",y2);
+ snprintf(loc, sizeof(loc), "-%d", y2);
else
- sprintf(loc,"+%d",y1+(int)tVy);
- strcat(tname, loc);
+ snprintf(loc, sizeof(loc), "+%d", y1 + (int)tVy);
+ strlcat(tname, loc, sizeof(tname));
if ( XGetCommand( dpy, t->id, &command_list, &command_count ) )
{
Index: app/fvwm/modules/FvwmSaveDesk/FvwmSaveDesk.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmSaveDesk/FvwmSaveDesk.c,v
diff -u -p -u -r1.1.1.1 FvwmSaveDesk.c
--- app/fvwm/modules/FvwmSaveDesk/FvwmSaveDesk.c 26 Nov 2006 10:53:54 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmSaveDesk/FvwmSaveDesk.c 25 Oct 2025 19:27:22 -0000
@@ -74,9 +74,10 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ size_t name_len = strlen(temp);
+ MyName = safemalloc(name_len + 2);
+ strlcpy(MyName, "*", name_len + 2);
+ strlcat(MyName, temp, name_len + 2);
if((argc != 6)&&(argc != 7))
{
@@ -155,8 +156,9 @@ void process_message(unsigned long type,
{
struct list *l;
if ((l = find_window(body[0])) != 0) {
- l->name = (char *)safemalloc(strlen((char *)&body[3])+1);
- strcpy(l->name,(char *)&body[3]);
+ size_t name_len = strlen((char *)&body[3]);
+ l->name = (char *)safemalloc(name_len + 1);
+ strlcpy(l->name, (char *)&body[3], name_len + 1);
}
}
break;
@@ -300,7 +302,7 @@ void write_string(FILE *out, char *line)
void do_save_command(FILE *out, struct list *t, int *curdesk,
int emit_wait, int *isfirstline)
{
- char tname[200],loc[30];
+ char tname[200],loc[30];
char **command_list;
int dwidth,dheight,xtermline = 0;
int x1,x2,y1,y2,i,command_count;
@@ -333,22 +335,22 @@ void do_save_command(FILE *out, struct l
tVx = Vx;
tVy = Vy;
}
- sprintf(tname,"%dx%d",dwidth,dheight);
+ snprintf(tname, sizeof(tname), "%dx%d", dwidth, dheight);
if ((t->gravity == EastGravity) ||
(t->gravity == NorthEastGravity) ||
(t->gravity == SouthEastGravity))
- sprintf(loc,"-%d",x2);
+ snprintf(loc, sizeof(loc), "-%d", x2);
else
- sprintf(loc,"+%d",x1+(int)tVx);
- strcat(tname, loc);
+ snprintf(loc, sizeof(loc), "+%d", x1 + (int)tVx);
+ strlcat(tname, loc, sizeof(tname));
if((t->gravity == SouthGravity)||
(t->gravity == SouthEastGravity)||
(t->gravity == SouthWestGravity))
- sprintf(loc,"-%d",y2);
+ snprintf(loc, sizeof(loc), "-%d", y2);
else
- sprintf(loc,"+%d",y1+(int)tVy);
- strcat(tname, loc);
+ snprintf(loc, sizeof(loc), "+%d", y1 + (int)tVy);
+ strlcat(tname, loc, sizeof(tname));
if ( XGetCommand( dpy, t->id, &command_list, &command_count ) )
{
@@ -434,7 +436,7 @@ void do_save(void)
if (t->desk > maxdesk)
maxdesk = t->desk;
- sprintf(fnbuf, "%s/.fvwm2desk", getenv( "HOME" ) );
+ snprintf(fnbuf, sizeof(fnbuf), "%s/.fvwm2desk", getenv("HOME"));
out = fopen( fnbuf, "w" );
fprintf( out, "AddToFunc InitFunction");
Index: app/fvwm/modules/FvwmScroll/FvwmScroll.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmScroll/FvwmScroll.1,v
diff -u -p -u -r1.1.1.1 FvwmScroll.1
--- app/fvwm/modules/FvwmScroll/FvwmScroll.1 26 Nov 2006 10:53:54 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmScroll/FvwmScroll.1 25 Oct 2025 19:27:22 -0000
@@ -66,11 +66,6 @@ themselves.
.IP "*FvwmScrollBack \fIcolor\fP"
Tells the module to use \fIcolor\fP instead of black for the window
background.
-
-.SH BUGS
-When the scroll bars are removed by clicking on the button in the
-lower right corner, the window does not restore its location
-correctly.
.SH AUTHOR
Robert Nation
Index: app/fvwm/modules/FvwmScroll/FvwmScroll.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmScroll/FvwmScroll.c,v
diff -u -p -u -r1.1.1.1 FvwmScroll.c
--- app/fvwm/modules/FvwmScroll/FvwmScroll.c 26 Nov 2006 10:53:54 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmScroll/FvwmScroll.c 25 Oct 2025 19:27:22 -0000
@@ -74,9 +74,10 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ size_t name_len = strlen(temp);
+ MyName = safemalloc(name_len + 2);
+ strlcpy(MyName, "*", name_len + 2);
+ strlcat(MyName, temp, name_len + 2);
Clength = strlen(MyName);
if(argc < 6)
Index: app/fvwm/modules/FvwmScroll/GrabWindow.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmScroll/GrabWindow.c,v
diff -u -p -u -r1.2 GrabWindow.c
--- app/fvwm/modules/FvwmScroll/GrabWindow.c 24 Jan 2021 09:02:54 -0000 1.2
+++ app/fvwm/modules/FvwmScroll/GrabWindow.c 25 Oct 2025 19:27:22 -0000
@@ -353,7 +353,16 @@ void Loop(Window target)
(motion==QUIT))
{
XUnmapWindow(dpy,main_win);
- XReparentWindow(dpy,target,Root,x,y);
+ {
+ int root_x, root_y;
+ Window dummy;
+ if (XTranslateCoordinates(dpy, main_win, Root, 0, 0,
+ &root_x, &root_y, &dummy)) {
+ XReparentWindow(dpy,target,Root,root_x,root_y);
+ } else {
+ XReparentWindow(dpy,target,Root,x,y);
+ }
+ }
XSync(dpy,0);
exit(0);
}
Index: app/fvwm/modules/FvwmTalk/FvwmTalk.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmTalk/FvwmTalk.c,v
diff -u -p -u -r1.1.1.1 FvwmTalk.c
--- app/fvwm/modules/FvwmTalk/FvwmTalk.c 26 Nov 2006 10:53:55 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmTalk/FvwmTalk.c 25 Oct 2025 19:27:22 -0000
@@ -111,9 +111,10 @@ int main(int argc, char **argv)
if (s != NULL)
temp = s + 1;
- MyName = safemalloc(strlen(temp)+2);
- strcpy(MyName,"*");
- strcat(MyName, temp);
+ size_t name_len = strlen(temp);
+ MyName = safemalloc(name_len + 2);
+ strlcpy(MyName, "*", name_len + 2);
+ strlcat(MyName, temp, name_len + 2);
if((argc != 6)&&(argc != 7))
{
@@ -259,11 +260,11 @@ void Loop(int *fd)
}
else
{
- if(pos + count < 255)
- {
- strcat(Text,kbuf);
- pos += count;
- }
+ if(pos + count < 255)
+ {
+ strlcat(Text, kbuf, sizeof(Text));
+ pos += count;
+ }
else
XBell(dpy,0);
}
Index: app/fvwm/modules/FvwmWinList/ButtonArray.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmWinList/ButtonArray.c,v
diff -u -p -u -r1.3 ButtonArray.c
--- app/fvwm/modules/FvwmWinList/ButtonArray.c 24 Jan 2021 09:26:52 -0000 1.3
+++ app/fvwm/modules/FvwmWinList/ButtonArray.c 25 Oct 2025 19:27:22 -0000
@@ -51,8 +51,9 @@ Button *ButtonNew(char *title, FvwmPictu
Button *new;
new = (Button *)safemalloc(sizeof(Button));
- new->title = safemalloc(strlen(title)+1);
- strcpy(new->title, title);
+ size_t title_len = strlen(title);
+ new->title = safemalloc(title_len + 1);
+ strlcpy(new->title, title, title_len + 1);
if (p != NULL)
{
new->p.picture = p->picture;
@@ -142,8 +143,9 @@ int UpdateButton(ButtonArray *array, int
{
if (title!=NULL)
{
- temp->title=(char *)saferealloc(temp->title,strlen(title)+1);
- strcpy(temp->title,title);
+ size_t title_len = strlen(title);
+ temp->title = (char *)saferealloc(temp->title, title_len + 1);
+ strlcpy(temp->title, title, title_len + 1);
temp->tw=XTextWidth(ButtonFont,title,strlen(title));
temp->truncatewidth = 0;
}
Index: app/fvwm/modules/FvwmWinList/FvwmWinList.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmWinList/FvwmWinList.c,v
diff -u -p -u -r1.2 FvwmWinList.c
--- app/fvwm/modules/FvwmWinList/FvwmWinList.c 18 Jan 2011 19:28:33 -0000 1.2
+++ app/fvwm/modules/FvwmWinList/FvwmWinList.c 25 Oct 2025 19:27:22 -0000
@@ -154,9 +154,10 @@ int main(int argc, char **argv)
temp = s + 1;
/* Setup my name */
- Module = safemalloc(strlen(temp)+2);
- strcpy(Module,"*");
- strcat(Module, temp);
+ size_t name_len = strlen(temp);
+ Module = safemalloc(name_len + 2);
+ strlcpy(Module, "*", name_len + 2);
+ strlcat(Module, temp, name_len + 2);
Clength = strlen(Module);
/* Open the console for messages */
@@ -790,11 +791,15 @@ void AdjustWindow(void)
char *makename(const char *string,long flags)
{
char *ptr;
- ptr=safemalloc(strlen(string)+3);
- *ptr = '\0';
- if (flags&ICONIFIED) strcpy(ptr,"(");
- strcat(ptr,string);
- if (flags&ICONIFIED) strcat(ptr,")");
+ size_t name_len = strlen(string);
+ size_t extra = (flags & ICONIFIED) ? 2 : 1;
+ ptr = safemalloc(name_len + extra);
+ ptr[0] = '\0';
+ if (flags & ICONIFIED)
+ strlcpy(ptr, "(", name_len + extra);
+ strlcat(ptr, string, name_len + extra);
+ if (flags & ICONIFIED)
+ strlcat(ptr, ")", name_len + extra);
return ptr;
}
Index: app/fvwm/modules/FvwmWinList/Mallocs.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmWinList/Mallocs.c,v
diff -u -p -u -r1.1.1.1 Mallocs.c
--- app/fvwm/modules/FvwmWinList/Mallocs.c 26 Nov 2006 10:53:56 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmWinList/Mallocs.c 25 Oct 2025 19:27:22 -0000
@@ -29,30 +29,36 @@
extern char *Module;
-/******************************************************************************
- saferealloc - safely reallocate memory or exit if fails. (Doesn't work right)
- (No kidding! Try it now ...)
-******************************************************************************/
char *saferealloc(char *ptr, size_t length)
{
-char *newptr;
+ char *newptr;
+ const char *name;
- if(length <=0) length=1;
+ if (length == 0) {
+ length = 1;
+ }
+
+ newptr = realloc(ptr, length);
+ if (newptr == NULL) {
+ name = (Module && *Module) ? Module : "FvwmWinList";
+ fprintf(stderr, "%s: realloc failed for %zu bytes\n", name, length);
+ exit(1);
+ }
- /* If ptr is NULL then realloc does a malloc */
- newptr=realloc(ptr,length);
- if (newptr == (char *)0) {
- fprintf(stderr,"%s:realloc failed",Module);
- exit(1);
- }
return newptr;
}
-void UpdateString(char **string,const char *value)
+void UpdateString(char **string, const char *value)
{
- if (value==NULL) return;
- *string = saferealloc(*string,strlen(value)+1);
- strcpy(*string,value);
+ if (value == NULL)
+ return;
+
+ size_t value_len = strlen(value);
+ if (*string == NULL)
+ *string = safemalloc(value_len + 1);
+ else
+ *string = saferealloc(*string, value_len + 1);
+ strlcpy(*string, value, value_len + 1);
}
Index: app/fvwm/modules/FvwmWinList/Mallocs.h
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmWinList/Mallocs.h,v
diff -u -p -u -r1.1.1.1 Mallocs.h
--- app/fvwm/modules/FvwmWinList/Mallocs.h 26 Nov 2006 10:53:56 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmWinList/Mallocs.h 25 Oct 2025 19:27:22 -0000
@@ -17,6 +17,7 @@
* are provided or implied in any way whatsoever. Use this program at your
* own risk. Permission to use this program for any purpose is given,
* as long as the copyright is kept intact. */
+#include <stddef.h>
/* Function Prototypes */
char *safemalloc(int length);
Index: app/fvwm/modules/FvwmWinList/README
===================================================================
RCS file: /cvs/xenocara/app/fvwm/modules/FvwmWinList/README,v
diff -u -p -u -r1.1.1.1 README
--- app/fvwm/modules/FvwmWinList/README 26 Nov 2006 10:53:56 -0000 1.1.1.1
+++ app/fvwm/modules/FvwmWinList/README 25 Oct 2025 19:27:22 -0000
@@ -72,11 +72,8 @@ To do: (in no particular order)
(ie. You make it wider you get 2 columns of buttons, etc.)
- Fix the following:
- - The function saferealloc, based on safemalloc by Rob Nation still doesn't
- work correctly, I left it in the Mallocs.c file but I use the normal
- realloc now. (Being lazy on this one)
- - Make compile compatability for all systems
- - Tune FvwmWinList to be more efficient (Low priority, right now)
+ - Make compile compatability for all systems
+ - Tune FvwmWinList to be more efficient (Low priority, right now)
I am open to, actually I am trolling for, suggestions/improvments/ideas/rags
on this.
Index: app/fvwm/utils/xpmroot.1
===================================================================
RCS file: /cvs/xenocara/app/fvwm/utils/xpmroot.1,v
diff -u -p -u -r1.1.1.1 xpmroot.1
--- app/fvwm/utils/xpmroot.1 26 Nov 2006 10:53:57 -0000 1.1.1.1
+++ app/fvwm/utils/xpmroot.1 25 Oct 2025 19:27:22 -0000
@@ -10,8 +10,5 @@ xpmroot \- Sets the root window of the c
.SH DESCRIPTION
\fIxpmroot\fP reads the Xpm file specified in the command line
and displays it in the root window.
-.SH BUGS
-Repeated use of xpmroot with different xpm pixmaps will use up slots in
-your color table pretty darn fast.
.SH AUTHOR
Rob Nation
Index: app/fvwm/utils/xpmroot.c
===================================================================
RCS file: /cvs/xenocara/app/fvwm/utils/xpmroot.c,v
diff -u -p -u -r1.1.1.1 xpmroot.c
--- app/fvwm/utils/xpmroot.c 26 Nov 2006 10:53:57 -0000 1.1.1.1
+++ app/fvwm/utils/xpmroot.c 25 Oct 2025 19:27:22 -0000
@@ -9,27 +9,27 @@
#include "config.h"
#include <stdio.h>
+#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <X11/Xos.h>
+#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "../libs/fvwmlib.h"
#include <X11/xpm.h> /* Has to be after Intrinsic.h gets included */
-int save_colors = 0;
Display *dpy;
int screen;
Window root;
char *display_name = NULL;
-void SetRootWindow(char *tline);
+static void SetRootWindow(char *tline, XWindowAttributes *root_attr, Atom colors_atom);
+static void FreePreviousResources(Atom pixmap_atom, Atom colors_atom, XWindowAttributes *root_attr);
Pixmap rootXpm;
int main(int argc, char **argv)
{
- Atom prop, type;
- int format;
- unsigned long length, after;
- unsigned char *data;
+ Atom prop, color_prop;
+ XWindowAttributes root_attr;
if(argc != 2)
{
@@ -47,15 +47,14 @@ int main(int argc, char **argv)
}
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
-
- SetRootWindow(argv[1]);
+ XGetWindowAttributes(dpy, root, &root_attr);
prop = XInternAtom(dpy, "_XSETROOT_ID", False);
-
- (void)XGetWindowProperty(dpy, root, prop, 0L, 1L, True, AnyPropertyType,
- &type, &format, &length, &after, &data);
- if ((type == XA_PIXMAP) && (format == 32) && (length == 1) && (after == 0))
- XKillClient(dpy, *((Pixmap *)data));
+ color_prop = XInternAtom(dpy, "_XSETROOT_COLORS", False);
+
+ FreePreviousResources(prop, color_prop, &root_attr);
+
+ SetRootWindow(argv[1], &root_attr, color_prop);
XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, PropModeReplace,
(unsigned char *) &rootXpm, 1);
@@ -64,20 +63,18 @@ int main(int argc, char **argv)
return 0;
}
-
-void SetRootWindow(char *tline)
+static void SetRootWindow(char *tline, XWindowAttributes *root_attr, Atom colors_atom)
{
- XWindowAttributes root_attr;
XpmAttributes xpm_attributes;
Pixmap shapeMask;
int val;
- XGetWindowAttributes(dpy,root,&root_attr);
- xpm_attributes.colormap = root_attr.colormap;
- xpm_attributes.valuemask = XpmSize | XpmReturnPixels|XpmColormap;
+ memset(&xpm_attributes, 0, sizeof(xpm_attributes));
+ xpm_attributes.colormap = root_attr->colormap;
+ xpm_attributes.valuemask = XpmSize | XpmReturnAllocPixels | XpmColormap;
if((val = XpmReadFileToPixmap(dpy,root, tline,
- &rootXpm, &shapeMask,
- &xpm_attributes))!= XpmSuccess)
+ &rootXpm, &shapeMask,
+ &xpm_attributes))!= XpmSuccess)
{
if(val == XpmOpenFailed)
fprintf(stderr, "Couldn't open pixmap file\n");
@@ -92,8 +89,59 @@ void SetRootWindow(char *tline)
exit(1);
}
+ if (shapeMask != None)
+ XFreePixmap(dpy, shapeMask);
+
XSetWindowBackgroundPixmap(dpy, root, rootXpm);
- save_colors = 1;
XClearWindow(dpy,root);
+ if ((xpm_attributes.valuemask & XpmReturnAllocPixels) &&
+ xpm_attributes.nalloc_pixels > 0 &&
+ xpm_attributes.alloc_pixels != NULL)
+ {
+ XChangeProperty(dpy, root, colors_atom, XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)xpm_attributes.alloc_pixels,
+ (int)xpm_attributes.nalloc_pixels);
+ }
+ else
+ {
+ XDeleteProperty(dpy, root, colors_atom);
+ }
+
+ XpmFreeAttributes(&xpm_attributes);
+
+}
+
+static void FreePreviousResources(Atom pixmap_atom, Atom colors_atom, XWindowAttributes *root_attr)
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ unsigned char *data = NULL;
+ int visual_class = (root_attr->visual != NULL) ? root_attr->visual->class : StaticGray;
+ Bool can_free_colors = (visual_class == PseudoColor ||
+ visual_class == GrayScale ||
+ visual_class == DirectColor);
+
+ if (XGetWindowProperty(dpy, root, colors_atom, 0L, (~0L), True, XA_CARDINAL,
+ &type, &format, &length, &after, &data) == Success)
+ {
+ if (can_free_colors && type == XA_CARDINAL && format == 32 && length > 0 && data != NULL)
+ {
+ Pixel *pixels = (Pixel *)data;
+ XFreeColors(dpy, root_attr->colormap, pixels, (int)length, 0);
+ }
+ if (data != NULL)
+ XFree(data);
+ }
+
+ data = NULL;
+ if (XGetWindowProperty(dpy, root, pixmap_atom, 0L, 1L, True, AnyPropertyType,
+ &type, &format, &length, &after, &data) == Success)
+ {
+ if ((type == XA_PIXMAP) && (format == 32) && (length == 1) && data != NULL)
+ XKillClient(dpy, *((Pixmap *)data));
+ if (data != NULL)
+ XFree(data);
+ }
}
fvwm(1): replace GPL-licensed code, fix bugs and add improvements