Subject: new style PlacementBox

From: Sergey Babkin <[email-masked]>
Date: Mon, 19 Aug 2002 16:35:26 -0400

Hi all,

I want to propose a solution to a problem I have:

My configuration of fvwm includes the FvwmButtons module at the
bottom of the screen. I don't want to mark it as StaysOnTop because
it tends to interact really badly with the pop-up windows, and also
sometimes I want to actually enlarge some window to the maximal size
without being obscured. However when a new window is placed
(with MinOverlapPercentPlacement being my favorite so far), I
want it to not obscure the FvwmButtons.

The solution is: create a new style statement

Style * PlacementBox l t r b

that describes the part of the screen that can be used for window
placement. For example, my particular configuration gets handled
by 

Style *           PlacementBox 0 0 -0 -50

That is, exclude the bottom 50 pixels of the screen from the placement.

The patch is sufficiently small, so I have attached it here. It was
made against 2.4.8. If it gets accepted, I'm willing to write the
patch for the man page as well (or do any neccessary porting to -current
if it is non-trivial).

-SB

*** add_window.c	2002/08/16 19:57:24	1.1
--- add_window.c	2002/08/19 19:59:04
***************
*** 688,697 ****
      XrmDestroyDatabase(db);
    }
  
!   return PlaceWindow(
!       tmp_win, &pstyle->flags, SGET_START_DESK(*pstyle),
!       SGET_START_PAGE_X(*pstyle), SGET_START_PAGE_Y(*pstyle),
!       SGET_START_SCREEN(*pstyle), PLACE_INITIAL);
  }
  
  void get_default_window_attributes(
--- 688,694 ----
      XrmDestroyDatabase(db);
    }
  
!   return PlaceWindow(tmp_win, pstyle, PLACE_INITIAL);
  }
  
  void get_default_window_attributes(
*** fvwm.h	2002/08/16 19:58:57	1.1
--- fvwm.h	2002/08/19 19:52:49
***************
*** 153,158 ****
--- 153,164 ----
  
  typedef struct
  {
+   int box[4];
+   char sign[4];
+ } placement_box;
+ 
+ typedef struct
+ {
    Pixel fore;
    Pixel back;
  } ColorPair;
***************
*** 392,397 ****
--- 398,404 ----
    unsigned manual_placement_honors_starts_on_page : 1;
    unsigned capture_honors_starts_on_page : 1;
    unsigned recapture_honors_starts_on_page : 1;
+   unsigned has_placement_box : 1;
  } style_flags;
  
  /* only style.c and add_window.c are allowed to access this struct!! */
***************
*** 431,436 ****
--- 438,444 ----
    int max_window_height;
    int shade_anim_steps;
    icon_boxes *icon_boxes;
+   placement_box placement_box;
    style_flags flags;
    style_flags flag_mask;
    style_flags change_mask;
*** placement.c	2002/08/16 19:58:57	1.1
--- placement.c	2002/08/19 20:09:41
***************
*** 471,479 ****
   *   2 = OK, window must be resized too
   *
   **************************************************************************/
! Bool PlaceWindow(
!   FvwmWindow *tmp_win, style_flags *sflags,
!   int Desk, int PageX, int PageY, int XineramaScreen, int mode)
  {
    FvwmWindow *t;
    int xl = -1;
--- 471,477 ----
   *   2 = OK, window must be resized too
   *
   **************************************************************************/
! Bool PlaceWindow(FvwmWindow *tmp_win, window_style *pstyle, int mode)
  {
    FvwmWindow *t;
    int xl = -1;
***************
*** 500,505 ****
--- 498,511 ----
    } flags;
    extern Bool Restarting;
    extern Bool PPosOverride;
+   style_flags *sflags;
+   int Desk, PageX, PageY, XineramaScreen;
+ 
+   sflags = &pstyle->flags, 
+   Desk = SGET_START_DESK(*pstyle),
+   PageX = SGET_START_PAGE_X(*pstyle);
+   PageY = SGET_START_PAGE_Y(*pstyle);
+   XineramaScreen = SGET_START_SCREEN(*pstyle);
  
    memset(&flags, 0, sizeof(flags));
  
***************
*** 582,587 ****
--- 588,607 ----
        NULL, FSCREEN_CURRENT,
        &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height);
    }
+   if (pstyle->flag_mask.has_placement_box) {
+     placement_box b = SGET_PLACEMENT_BOX(*pstyle);
+     int i;
+ 
+     for(i=0; i<4; i++) {
+       if (b.sign[i] == '-')
+ 	b.box[i] += (i & 1) ? (screen_g.y + screen_g.height) 
+ 		: (screen_g.x + screen_g.width);
+     }
+     screen_g.x = b.box[0];
+     screen_g.y = b.box[1];
+     screen_g.width = b.box[2]-b.box[0];
+     screen_g.height = b.box[3]-b.box[1];
+   }
    PageLeft   = screen_g.x - pdeltax;
    PageTop    = screen_g.y - pdeltay;
    PageRight  = PageLeft + screen_g.width;
***************
*** 1062,1071 ****
      return;
  
    lookup_style(tmp_win, &style);
!   PlaceWindow(
!     tmp_win, &style.flags,
!     SGET_START_DESK(style), SGET_START_PAGE_X(style), SGET_START_PAGE_Y(style),
!     SGET_START_SCREEN(style), PLACE_AGAIN);
    x = tmp_win->attr.x;
    y = tmp_win->attr.y;
  
--- 1082,1088 ----
      return;
  
    lookup_style(tmp_win, &style);
!   PlaceWindow(tmp_win, &style, PLACE_AGAIN);
    x = tmp_win->attr.x;
    y = tmp_win->attr.y;
  
*** placement.h	2002/08/16 19:58:57	1.1
--- placement.h	2002/08/19 20:10:07
***************
*** 19,26 ****
  #define PLACE_INITIAL 0x0
  #define PLACE_AGAIN   0x1
  
! Bool PlaceWindow(
!   FvwmWindow *tmp_win, style_flags *sflags,
!   int Desk, int PageX, int PageY, int XineramaScreen, int mode);
  
  #endif /* PLACEMENT_H */
--- 19,24 ----
  #define PLACE_INITIAL 0x0
  #define PLACE_AGAIN   0x1
  
! Bool PlaceWindow(FvwmWindow *tmp_win, window_style *pstyle, int mode);
  
  #endif /* PLACEMENT_H */
*** style.c	2002/08/16 19:58:57	1.1
--- style.c	2002/08/19 20:11:30
***************
*** 460,465 ****
--- 460,469 ----
    {
      SSET_BORDER_COLORSET_HI(*merged_style,SGET_BORDER_COLORSET_HI(*add_style));
    }
+   if (add_style->flag_mask.has_placement_box)
+   {
+     SSET_PLACEMENT_BOX(*merged_style,SGET_PLACEMENT_BOX(*add_style));
+   }
  
    /* merge the style flags */
  
***************
*** 2168,2173 ****
--- 2172,2203 ----
  	  ptmpstyle->flags.use_parent_relative = 1;
  	  ptmpstyle->flag_mask.use_parent_relative = 1;
  	  ptmpstyle->change_mask.use_parent_relative = 1;
+         }
+ 	else if(StrEquals(token, "PlacementBox"))
+         {
+ 	  found = True;
+           /* try for 4 numbers x y x y */
+ 	  num = GetIntegerArguments(rest, NULL, val, 4);
+ 
+ 	  /* must be 4 numbers */
+           if (num == 4) {
+             for(i = 0; i < 4; i++) {
+ 	      /* make sure the value fits into a short */
+ 	      if (val[i] < -32768)
+ 		val[i] = -32768;
+ 	      if (val[i] > 32767)
+ 		val[i] = 32767;
+ 	      ptmpstyle->placement_box.box[i] = val[i];
+ 	      /* If leading minus sign */
+ 	      token = PeekToken(rest, &rest);
+ 	      ptmpstyle->placement_box.sign[i] = token[0];
+             }
+             /* Note: here there is no test for valid co-ords, use geom */
+             ptmpstyle->flag_mask.has_placement_box = 1;
+             ptmpstyle->change_mask.has_placement_box = 1;
+           } else {
+             fvwm_msg(ERR,"ProcessNewStyle", "PlacementBox requires 4 numbers");
+ 	  }
          }
          break;
  
*** style.h	2002/08/16 19:58:57	1.1
--- style.h	2002/08/19 19:48:19
***************
*** 423,428 ****
--- 423,430 ----
  #define SSET_WINDOW_SHADE_STEPS(s,x)  ((s).shade_anim_steps = (x))
  #define SGET_ICON_BOXES(s)            ((s).icon_boxes)
  #define SSET_ICON_BOXES(s,x)          ((s).icon_boxes = (x))
+ #define SGET_PLACEMENT_BOX(s)         ((s).placement_box)
+ #define SSET_PLACEMENT_BOX(s,x)       ((s).placement_box = (x))

  /* function prototypes */

---

From: Mikhael Goikhman <[email-masked]>
Date: Mon, 19 Aug 2002 20:51:10 +0000

> patch for the man page as well (or do any neccessary porting to -current

In 2.5.x try:

  EWMHBaseStrut 0 0 0 50

Regards,
Mikhael.
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]

---

From: Mikhael Goikhman <[email-masked]>
Date: Mon, 19 Aug 2002 21:59:56 +0000

On 19 Aug 2002 17:29:26 -0400, Sergey Babkin wrote:
> 
> Mikhael Goikhman wrote:
> > 
> > In 2.5.x try:
> > 
> >   EWMHBaseStrut 0 0 0 50
> 
> Thanks, that should do it.

It also makes Maximize work as expected, not just placement.

> By the way, I have found that CurrentAtEnd
> of WindowList does not quite do what I like: it does not switch the
> focus and does not raise the newly focused window before it
> posts the menu. It would be nice if when moving between the windows
> on the WindowList it sould raise and change the decoration to
> "focused" for the current window.

It seems you need a module to do this, you can't principally change
decorations while navigating a menu.

Regards,
Mikhael.

---

From: Sergey Babkin <[email-masked]>
Date: Tue, 20 Aug 2002 18:02:58 -0400

> > Thanks, that should do it.

I've tried it with Aug.19 snapshot and it does not work. Yes, I've checked
that ewmh is enabled in the makefile.
 
> It also makes Maximize work as expected, not just placement.

Maximize is not an issue for me: for fvwm1 I've defined a function to
do "Maximize 95 95".
 
A separate issue: something wrong seems to be going on with the focus
on the nested clients (such as a parent Tcl/Tk program providing a frame
with option -container and a child Tcl/Tk program running within this
frame with option -use). When the mouse pointer gets moved into the parent
window and then out of it, the child loses its focus. Since I use
the mode ClickToFocus, that should not happen (and indeed did not happen
with fvwm1 nor with CDE WM). This bug occurs both in the latest snapshot
and in 2.4.8.

Here is a small example of a Tcl script for demonstration:

-------------------------------

#!/usr/local/bin/wish8.0
#
# test of a client swallowed by another client

puts "swallow $argv"
if {![string compare [lindex $argv 0] {-child}]} {
    label .l -text "internal" -bg white -fg black
    pack .l
    bind .l <FocusIn> ".l config -bg yellow"
    bind .l <FocusOut> ".l config -bg white"
    focus .l
} else {
    frame .f -bd 10 -bg blue -relief sunken
    frame .f.f -container 1
    pack .f.f .f
    exec $argv0 -use [winfo id .f.f] -child &
    bind .f <FocusIn> ".f config -bg red"
    bind .f <FocusOut> ".f config -bg blue"
    focus .f.f
}
-------------------------------

(you may need to edit the interpreter path according to where you have
wish on your system). It contains two window one in another. The outer
(frame) window is blue when it does not have focus and red when it
has focus. The inner window is white when it does not have focus and
yellow when it does. The outer window is hardwired to pass the
focus to the inner window whenever it receives the focus.
Normally the only possible color combinations should be "red-yellow" 
and "blue-white" (well, except after the initial start before the focus 
gets switched for the first time - it's an independent Tk issue). However 
with fvwm2 many more strange combinations happen.

Thank you for your help!

-SB

---

From: Mikhael Goikhman <[email-masked]>
Date: Wed, 21 Aug 2002 10:22:04 +0000

> that ewmh is enabled in the makefile.

Hmm, currently EWMHBaseStrut for some reason does not work with
MinOverlapPlacement, but works with TileCascadePlacement.
I mean placement does not work as expected, Maximize does.

> Maximize is not an issue for me: for fvwm1 I've defined a function to

Try also Maximize -50p -50p, at least this is resolution independent.
With EWMHBaseStrut it works relatively to the defined base area.

Regards,
Mikhael.

---

From: Sergey Babkin <[email-masked]>
Date: Wed, 21 Aug 2002 16:29:01 -0400

> I mean placement does not work as expected, Maximize does.

That's because it's intentionally disabled, in placement.c:

  if (SPLACEMENT_MODE(sflags) != PLACE_MINOVERLAPPERCENT &&
      SPLACEMENT_MODE(sflags) != PLACE_MINOVERLAP)
  {  
    EWMH_GetWorkAreaIntersection(fw,
      &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height,
      SEWMH_PLACEMENT_MODE(sflags));
  }   

I think that this disabling is wrong but maybe whoever did this
had some good reason for it.
 
> With EWMHBaseStrut it works relatively to the defined base area.

Thanks again. This did not work in fvwm1, that's why I had to use percents.
Now I'm trying to adapt my confguration from fvwm1 to fvwm2.

-SB