[dev][dwm] Floating window center position fix

2011-07-20 Thread lolilolicon
I have a rule in config.h for MPlayer to always float. The bug was
observed when I played a 720p video whose window was 1280 pixels so it
filled the width of my laptop screen. The MPlayer window was supposed to
be centered, but a border line on the left was clearly visible. For
further confirmation, I set borderpx to 20. My observation was obviously
right. The patch is appended at the end.

Another thing I've observed but didn't care to fix when playing the video:
If the MPlayer window is always created in tag 4 (as per a rule), but I
run the mplayer command in xterm in tag 1, the visibility of the MPlayer
window border depends on some timing:

1) If I switch from tag 1 to tag 4 _after_ the MPlayer window is created,
   the border is visible.
2) If I switch from tag 1 to tag 4 _before_ the MPlayer window is created,
   the border is invisible. It seems for dwm the border exists, just not
   drawn. If I switch to another tag and back, or do a focusstack()
   using the default mod1+j combo or pretty about anything, the border
   will then be drawn.

Relevant entries in my test config.h are:

static const unsigned int borderpx = 20;
static const Rule rules[] = {
  { "MPlayer", NULL, NULL, 1 << 3, True, -1 },
};

And following is my patch for the center position bug:

Patch for dwm 5.9
diff -up a/dwm.c b/dwm.c
--- a/dwm.c 1970-01-01 00:00:00.0 +
+++ b/dwm.c 1970-01-01 00:00:00.0 +
@@ -624,9 +624,9 @@ configurerequest(XEvent *e) {
if(ev->value_mask & CWHeight)
c->h = ev->height;
if((c->x + c->w) > m->mx + m->mw && c->isfloating)
-   c->x = m->mx + (m->mw / 2 - c->w / 2); /* 
center in x direction */
+   c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* 
center in x direction */
if((c->y + c->h) > m->my + m->mh && c->isfloating)
-   c->y = m->my + (m->mh / 2 - c->h / 2); /* 
center in y direction */
+   c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* 
center in y direction */
if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & 
(CWWidth|CWHeight)))
configure(c);
if(ISVISIBLE(c))



[dev][dmenu] loadfont() segmentation fault patch

2011-07-22 Thread lolilolicon
To reproduce the segmentation fault:

dmenu -fn 
"-windows-montecarlo-medium-r-normal--11-110-72-72-c-60-microsoft-cp1252"
<<< hello

The culprit is loadfont(). This font[1] triggers XLoadQueryFont(), and
loadfont()
fails in the for loop. At least that's what my quick debug indicated.

I did a diff between dmenu 4.3.1 and 4.4.
Do we really want this twisted pretentious piece of code inside loadfont()?
I for one like the 4.3.1 code better. And it worked.

Patch attached inline. I do it the humble way.

[1] The font is MonteCarlo:
http://bok.net/MonteCarlo/downloads/MonteCarlo-PCF.tgz

--- dmenu-4.4-a/draw.c  2011-07-19 20:31:28.0 +
+++ dmenu-4.4-b/draw.c  2011-07-22 12:34:35.026736893 +
@@ -121,23 +121,25 @@ initfont(DC *dc, const char *fontstr) {
 Bool
 loadfont(DC *dc, const char *fontstr) {
char *def, **missing, **names;
-   int i, n = 1;
+   int i, n;
XFontStruct **xfonts;

if(!*fontstr)
return False;
-   if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, 
&def)))
+   if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, 
&def))) {
n = XFontsOfFontSet(dc->font.set, &xfonts, &names);
-   else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr)))
-   xfonts = &dc->font.xfont;
-   else
-   n = 0;
-
-   for(i = 0; i < n; i++) {
-   dc->font.ascent  = MAX(dc->font.ascent,  xfonts[i]->ascent);
-   dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent);
-   dc->font.width   = MAX(dc->font.width,   
xfonts[i]->max_bounds.width);
+   for(i = 0; i < n; i++) {
+   dc->font.ascent  = MAX(dc->font.ascent,  
xfonts[i]->ascent);
+   dc->font.descent = MAX(dc->font.descent, 
xfonts[i]->descent);
+   dc->font.width   = MAX(dc->font.width,   
xfonts[i]->max_bounds.width);
+   }
+   }
+   else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) {
+   dc->font.ascent  = dc->font.xfont->ascent;
+   dc->font.descent = dc->font.xfont->descent;
+   dc->font.width   = dc->font.xfont->max_bounds.width;
}
+
if(missing)
XFreeStringList(missing);
return (dc->font.set || dc->font.xfont);



[dev] [dmenu] dmenu_run improvements

2011-07-23 Thread lolilolicon
dmenu_run doesn't really run the user input as a shell command line.
For instance, run dmenu_run from a terminal, then in the menu type:

  echo hello\ world

The terminal output is "hello\ world" instead of "hello world".

`eval' solves the problem, but when it comes to eval, I can't really
be sure, so please point out the possible errors/risks.

`LC_ALL=C' is for sort.

diff -up a/dmenu_run b/dmenu_run
--- a/dmenu_run 1970-01-01 00:00:00.0 +
+++ b/dmenu_run 1970-01-01 00:00:00.0 +
@@ -1,9 +1,9 @@
 #!/bin/sh
 CACHE=${XDG_CACHE_HOME:-"$HOME/.cache"}/dmenu_run
 (
-   IFS=:
+   IFS=: LC_ALL=C
if test "`ls -dt $PATH "$CACHE" 2> /dev/null | sed 1q`" != "$CACHE"; 
then
mkdir -p "`dirname "$CACHE"`" && lsx $PATH | sort -u > "$CACHE"
fi
 )
-cmd=`dmenu "$@" < "$CACHE"` && exec $cmd
+cmd=`dmenu "$@" < "$CACHE"` && eval exec "$cmd"



Re: [dev] [dmenu] dmenu_run improvements

2011-07-23 Thread lolilolicon
On 07/24/11 at 01:34am, Dave Reisner wrote:
> #!/bin/sh
> 
> CACHE=${XDG_CACHE_HOME:-"$HOME/.cache"}/dmenu_run
> IFS=:
> LC_COLLLATE=C
You got a typo here: LC_COLLATE

> 
> gencache() {
>   lsx $PATH | sort -u >"$CACHE"
> }
Since LC_COLLATE is only used for sort, we might as well just use:

  LC_COLLATE=C sort

> 
> if [ ! -e "$CACHE" ]; then
>   mkdir -p "${CACHE%/*}"
>   gencache
> fi
> 
> for path in $PATH; do
>   if [ "$path" -nt "$CACHE" ]; then
> gencache
> break
>   fi
> done
Much better than `ls -t', congratulations.
If $CACHE does not exist, there's no need to compare timestamps, so
let's puts an `else' there.

> unset IFS
> 
> cmd=$(dmenu "$@" < "$CACHE") && eval exec "$cmd"
Yeah, I see you just hate backticks :P



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On 07/24/11 at 11:38am, anonymous wrote:
> On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
> > > unset IFS
> > > 
> > > cmd=$(dmenu "$@" < "$CACHE") && eval exec "$cmd"
> > Yeah, I see you just hate backticks :P
> > 
> 
> There is a difference:
> 
> % echo `echo '\\'`
> \
> % echo $(echo '\\')
> \\

You're right. The backquoted form is "broken" even with no nesting.
Now I'm officially a member of the anti-backticks club. Thank you.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 4:40 PM, Anselm R Garbe  wrote:
> On 24 July 2011 08:38, anonymous  wrote:
>> On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
>>> > unset IFS
>>> >
>>> > cmd=$(dmenu "$@" < "$CACHE") && eval exec "$cmd"
>>> Yeah, I see you just hate backticks :P
>>>
>>
>> There is a difference:
>>
>>    % echo `echo '\\'`
>>    \
>>    % echo $(echo '\\')
>>    \\
>
> Yes, but bash'isms are a NO GO in suckless.org shell scripts :)
>
> Cheers,
> Anselm
>
>

This is no bashism.
AFAIK, $(command) is in the POSIX shell specification:
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 4:39 PM, Anselm R Garbe  wrote:
> On 24 July 2011 06:34, Dave Reisner  wrote:
>> On Sun, Jul 24, 2011 at 12:35:19PM +0800, lolilolicon wrote:
>>> dmenu_run doesn't really run the user input as a shell command line.
>>> For instance, run dmenu_run from a terminal, then in the menu type:
>>>
>>>   echo hello\ world
>>>
>>> The terminal output is "hello\ world" instead of "hello world".
>>>
>>> `eval' solves the problem, but when it comes to eval, I can't really
>>> be sure, so please point out the possible errors/risks.
>>
>> Assuredly the least of the evils in this script -- the eval is
>> necessary. More noteworthy is the parsing of ls here, which can easily
>> be refactored out and still be /bin/sh compat. It also explodes on first
>> run, and then there's the needless invocation of mkdir every time the
>> cache is regenerated. suckless could suck a lot less at shell scripting.
>> dmenu_run has gone through several iterations of bad and worse.
>>
>> d
>>
>>
>> #!/bin/sh
>>
>> CACHE=${XDG_CACHE_HOME:-"$HOME/.cache"}/dmenu_run
>> IFS=:
>> LC_COLLLATE=C
>>
>> gencache() {
>>  lsx $PATH | sort -u >"$CACHE"
>> }
>>
>> if [ ! -e "$CACHE" ]; then
>>  mkdir -p "${CACHE%/*}"
>>  gencache
>> fi
>>
>> for path in $PATH; do
>>  if [ "$path" -nt "$CACHE" ]; then
>>    gencache
>>    break
>>  fi
>> done
>
> Am I right that the previous loop runs gencache n times, under the
> assumption that each path component contains newer files?
>
> Kind regards,
> Anselm
>
>

No, note the `break'.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 5:06 PM, Anselm R Garbe  wrote:
> Nevertheless, I can see that script should be improved (not using the
> ls -dt invocation), but I prefer the back ticks (even if $(..) is
> POSIX, there were a couple of issues in the past that I barely
> remember) and I want explicit test calls, I don't like the [ ... ]
> syntax sugar.
>
> Thanks,
> Anselm
>
>

Fine, as long as it doesn't break anything, I can live with these two
backticks.
Since I'm the thread starter, may I conclude this with the following?

#!/bin/sh
CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/dmenu_run
(
IFS=:
gen_cache() {
lsx $PATH | LC_COLLATE=C sort -u > "$CACHE"
}
if test -e "$CACHE"; then
for path in $PATH; do
if test "$path" -nt "$CACHE"; then
gen_cache
break
fi
done
else
mkdir -p "${CACHE%/*}"
gen_cache
fi
)
cmd=`dmenu "$@" < "$CACHE"` && eval exec "$cmd"

NOTE:
The (subshell) is used so the declarations won't get inherented, but
the user still has access to the $CACHE and $cmd environments.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 6:41 PM, lolilolicon  wrote:
> cmd=`dmenu "$@" < "$CACHE"` && eval exec "$cmd"
>
> NOTE:
> The (subshell) is used so the declarations won't get inherented, but
> the user still has access to the $CACHE and $cmd environments.
>

Hmm, maybe instead of `eval exec', we could just use `exec sh -c' instead?

  cmd=`dmenu "$@" < "$CACHE"` || exit $?
  exec sh -c "$cmd"

The benefits are:

1. Only exported environment variables will be available to the user command.
2. The user can run any shell command, including, e.g.,

  if true; then echo hello\ world; fi

Correct me if I'm missing something here. Thanks.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 9:09 PM, Connor Lane Smith  wrote:
> On 24 July 2011 06:34, Dave Reisner  wrote:
>> if [ "$path" -nt "$CACHE" ]; then
>
> 'test -nt' is non-portable. I think you've just discovered why we use
> the 'ls -dt' hack.
>
> I agree that dmenu_run isn't the nicest script in existence. But
> because of the tedious limitations of POSIX we don't have much choice.

Sorry, but can you give an example where `test -nt' is not available?
Or can you point out what do you refer to to determine the portability
of a shell script?

According to Greg's wiki [1], `test -nt' is not supported by dash,
although it works here with dash 0.5.6.1. Even if you must support the
older versions that does not know about `test -nt', you can use find:

  test `find "$path" -prune -newer "$CACHE"`

as a drop-in replacement, which is better than `ls -dt' after all.

[1] http://mywiki.wooledge.org/Bashism



Re: [dev] Re: [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 10:08 PM, Christian Neukirchen
 wrote:
> anonymous  writes:
>
>> On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
>>> > unset IFS
>>> >
>>> > cmd=$(dmenu "$@" < "$CACHE") && eval exec "$cmd"
>>> Yeah, I see you just hate backticks :P
>>>
>>
>> There is a difference:
>>
>>     % echo `echo '\\'`
>>     \
>>     % echo $(echo '\\')
>>     \\
>
> That must be a bashism, can't reproduce in dash, mksh, zsh.
>
> --
> Christian Neukirchen    http://chneukirchen.org
>
>
>

The builtin echo may differ from /bin/echo. For example, here in dash:

$ echo '\\'
\
$ echo `echo '\\'`
\
$ echo $(echo '\\')
\

$ /bin/echo '\\'
\\
$ /bin/echo `/bin/echo '\\'`
\
$ /bin/echo $(/bin/echo '\\')
\\

In fact the builtin echo really sucks:

$ echo \\
\
$ echo 
\



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 10:09 PM, Dave Reisner  wrote:
> On Sun, Jul 24, 2011 at 10:00:09PM +0800, lolilolicon wrote:
>> Sorry, but can you give an example where `test -nt' is not available?
>> Or can you point out what do you refer to to determine the portability
>> of a shell script?
>
> I usually reference opengroup for POSIX util specs. I do love the
> wooledge wiki, though.
>
> http://pubs.opengroup.org/onlinepubs/95399/utilities/test.html
>
> d

Thanks Dave for the tip.
No wonder, I was looking at the Shell Command Language page.

Cheers.



Re: [dev] Re: [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 10:30 PM, lolilolicon  wrote:
> On Sun, Jul 24, 2011 at 10:08 PM, Christian Neukirchen
>  wrote:
>> anonymous  writes:
>>
>>> On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
>>>> > unset IFS
>>>> >
>>>> > cmd=$(dmenu "$@" < "$CACHE") && eval exec "$cmd"
>>>> Yeah, I see you just hate backticks :P
>>>>
>>>
>>> There is a difference:
>>>
>>>     % echo `echo '\\'`
>>>     \
>>>     % echo $(echo '\\')
>>>     \\
>>
>> That must be a bashism, can't reproduce in dash, mksh, zsh.
>>
>> --
>> Christian Neukirchen    http://chneukirchen.org
>>
>>
>>
>
> The builtin echo may differ from /bin/echo. For example, here in dash:
>
> $ echo '\\'
> \
> $ echo `echo '\\'`
> \
> $ echo $(echo '\\')
> \
>
> $ /bin/echo '\\'
> \\
> $ /bin/echo `/bin/echo '\\'`
> \
> $ /bin/echo $(/bin/echo '\\')
> \\
>
> In fact the builtin echo really sucks:
>
> $ echo \\
> \
> $ echo 
> \
>

Sorry, but please allow me to rephrase the issue.
The `echo' builtin in dash by default behaves like `echo -e' in bash.
So it's a bit tricky to reproduce the difference in dash:

$ echo `echo ''`
\
$ echo $(echo '')
\\

Or, just use `printf %s':

$ printf '%s\n' `printf '%s\n' '\\'`
\
$ printf '%s\n' $(printf '%s\n' '\\')
\\

For the record, the sucky `echo' is what POSIX defines:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html

And thank you Szabolcs Nagy for pointing me to the lastes spec.

Cheers.



Re: [dev] Ranger, a textbased filemanager

2011-10-23 Thread lolilolicon
On Mon, Oct 24, 2011 at 6:01 AM, Bjartur Thorlacius
 wrote:
>> if the task is 'waste a bunch of screen real estate' then no, ranger
>> is a far better choice
>>
> The current combination of a shell and a terminal emulator is
> horrible. I've found myself doing stuff like:
>
> exec /dev/tty2 2>/dev/tty1
> #optionally stty -echo
> while read
> do    clear
>      $REPLY
> done
>
> Why in Mímir's name do error messages and output get written to where
> my input is echoed?
>
>

This could to be an interesting idea. I'm thinking 3 column terminal
(stdin, stdout, stderr), as well as remote control...



[dev] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
The idea of having more than one master windows is brilliant.  The `tile'
layout in current hg tip basically splits the master and slave areas
vertically, and tiles windows in each of the two areas using a vertical
stacking algorithm.  The `ncol' layout does it slightly differently by
tilling the master windows using a horizontal stacking algorithm.  The
`n?bstack' layout also does it slightly differently, by splitting the
master and slave areas horizontally, and tiles windows in each of them
using a horizontal stacking algorithm.

All of these layouts fit in a generalized model.  Basically, there're two
things that differentiate one master-slave layout from another:

  1. How the master and slave areas are separated.  Practically, the most
  useful way to do this is simply split the screen in two parts, either
  vertically, or horizontally.

  2. What layout is used in each of the master and slave areas.  We can
  use different layouts for the masters and the slaves.  We should reuse
  the layout algorithms when we can.

With this model in mind, I came up with the function apply_mslts(), i.e.
"apply master-slave layouts", which takes care of the two things stated
above.  The actual layout algorithms are defined in the lt_* functions:

  lt_hstack tiles windows in a horizontal stack, i.e. columns.
  lt_vstack tiles windows in a vertical stack, i.e. rows.
  lt_grid tiles windows in a (gapless) grid.
  lt_monocle stacks windows, each maximized to fill the "booth".

The "booth" is the box in which the layout is performed.  Such functions
are simpler and easier to read.  And they are reusable.

To define a master-slave layout is as simple as:

  static void
  grid(Monitor *m) {
apply_mslts(m, False, lt_vstack, lt_grid);
  }

Here `False` means split master and slave areas vertically; lt_vstack is
applied to the master area, and lt_grid to the slaves.  I've never seen
such a layout before, you may find it interesting too.

To test this out, simply grab the hg tip, #include mslts.c in config.h,
add some example layouts such as `grid', bind a key combo, `make`, and
run.  Adjust the nmaster value with Mod + d/i, and mfact with Mod + h/j
to see the effects.

Also, this approach accepts nmaster being 0, in which case, all windows
are slaves, and are thus tiled using the slaves' layout algorithm.  This
should be the case for the current hg tip, too, IMO.

Finally, I'm not really good at C yet, so the code could probably use a
whole lot of improvement.  I'd really appreciate it if you could review
the code and help me improve it, because I really like this idea.

The code is in the attachment.
typedef struct {
	int x, y, w, h;
} Booth;

static void apply_lt(Monitor *m, void (*ltf)(Client **, Booth *, unsigned int));
static void apply_mslts(Monitor *m, Bool hsplit,
		void (*mltf)(Client **, Booth *, unsigned int),  /* master layout func */
		void (*sltf)(Client **, Booth *, unsigned int)); /* slave layout func */
static void lt_hstack(Client **c, Booth *b, unsigned int n);
static void lt_vstack(Client **c, Booth *b, unsigned int n);
static void lt_grid(Client **c, Booth *b, unsigned int n);
static void lt_monocle(Client **c, Booth *b, unsigned int n);

/* Example master-slave layouts */

static void ntile(Monitor *m);
static void ncol(Monitor *m);
static void bstack(Monitor *m);
static void grid(Monitor *m);

static void
ntile(Monitor *m) {
	apply_mslts(m, False, lt_vstack, lt_vstack);
}

static void
ncol(Monitor *m) {
	apply_mslts(m, False, lt_hstack, lt_vstack);
}

static void
bstack(Monitor *m) {
	apply_mslts(m, True, lt_hstack, lt_hstack);
}

static void
grid(Monitor *m) {
	apply_mslts(m, False, lt_vstack, lt_grid);
}

/* Functions that apply layouts */

static void
apply_lt(Monitor *m, void (*ltf)(Client **, Booth *, unsigned int)) {
  unsigned int n;
  Client *c;

	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
	if(n == 0)
		return;

	Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
	(*ltf)(&c, &b, n);
}

static void
apply_mslts(Monitor *m, Bool hsplit,
		void (*mltf)(Client **, Booth *, unsigned int),
		void (*sltf)(Client **, Booth *, unsigned int)) {
	unsigned int nm, n;
	Client *c;

	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
	if(n == 0)
		return;

	nm = MIN(n, m->nmaster);  /* number of masters */

	if (nm == 0) {
		/* all slaves */
		c = m->clients;
		Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
		(*sltf)(&c, &b, n);
	}
	else if(n > nm) {
		/* masters and slaves */
		c = m->clients;
		if(hsplit) {
			/* masters above slaves */
			Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh * m->mfact };
			(*mltf)(&c, &b, nm);
			b.y += b.h;
			b.h = m->wh - b.h;
			(*sltf)(&c, &b, n - nm);
		}
		else {
			/* masters at the left of slaves */
			Booth b = { .x = m->wx, .y = m->wy, .w = m->ww * m->mfact, .h = m->wh };
			(*mltf)(&c, &b, nm);
			b.x += b.w;
			b.w = m->ww - b.w;
			(*sltf)(&c, &b, n - nm);
		}
	}
	else {
		/* a

[dev] [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
The idea of having more than one master window is brilliant.  The `tile'
layout in current hg tip basically splits the master and slave areas
vertically, and tiles windows in each of the two areas using a vertical
stacking algorithm.  The `ncol' layout does it slightly differently by
tilling the master windows using a horizontal stacking algorithm.  The
`n?bstack' layout also does it slightly differently, by splitting the
master and slave areas horizontally, and tiles windows in each of them
using a horizontal stacking algorithm.

All of these layouts fit in a generalized model.  Basically, there're two
things that differentiate one master-slave layout from another:

  1. How the master and slave areas are separated.  Practically, the most
  useful way to do this is simply split the screen in two parts, either
  vertically, or horizontally.

  2. What layout is used in each of the master and slave areas.  We can
  use different layouts for the masters and the slaves.  We should reuse
  the layout algorithms when we can.

With this model in mind, I came up with the function apply_mslts(), i.e.
"apply master-slave layouts", which takes care of the two things stated
above.  The actual layout algorithms are defined in the lt_* functions:

  lt_hstack tiles windows in a horizontal stack, i.e. columns.
  lt_vstack tiles windows in a vertical stack, i.e. rows.
  lt_grid tiles windows in a (gapless) grid.
  lt_monocle stacks windows, each maximized to fill the "booth".

The "booth" is the box in which the layout is performed.  Such functions
are simpler and easier to read.  And they are reusable.

To define a master-slave layout is as simple as:

  static void
  grid(Monitor *m) {
apply_mslts(m, False, lt_vstack, lt_grid);
  }

Here `False` means split master and slave areas vertically; lt_vstack is
applied to the master area, and lt_grid to the slaves.  I've never seen
such a layout before, you may find it interesting too.

To test this out, simply grab the hg tip, #include mslts.c in config.h,
add some example layouts such as `grid', bind a key combo, `make`, and
run.  Adjust the nmaster value with Mod + d/i, and mfact with Mod + h/l
to see the effects.

Also, this approach accepts nmaster being 0, in which case, all windows
are slaves, and are thus tiled using the slaves' layout algorithm.  This
should be the case for the current hg tip, too, IMO.

Finally, I'm not really good at C yet, so the code could probably use a
whole lot of improvement.  I'd really appreciate it if you could review
the code and help me improve it, because I really like this idea.

The code is in the attachment.

/*
Resend this due to missing [dwm] tag in the subject, and an error in the
code.  Sorry for the inconvenience.
*/



[dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Mon, Oct 31, 2011 at 9:49 PM, lolilolicon  wrote:
>
> The code is in the attachment.
>

*huge facepalm*

Forgot to attach the fixed code.  Attached here.
typedef struct {
	int x, y, w, h;
} Booth;

static void apply_lt(Monitor *m, void (*ltf)(Client **, Booth *, unsigned int));
static void apply_mslts(Monitor *m, Bool hsplit,
		void (*mltf)(Client **, Booth *, unsigned int),  /* master layout func */
		void (*sltf)(Client **, Booth *, unsigned int)); /* slave layout func */
static void lt_hstack(Client **c, Booth *b, unsigned int n);
static void lt_vstack(Client **c, Booth *b, unsigned int n);
static void lt_grid(Client **c, Booth *b, unsigned int n);
static void lt_monocle(Client **c, Booth *b, unsigned int n);

/* Example master-slave layouts */

static void ntile(Monitor *m);
static void ncol(Monitor *m);
static void bstack(Monitor *m);
static void grid(Monitor *m);

static void
ntile(Monitor *m) {
	apply_mslts(m, False, lt_vstack, lt_vstack);
}

static void
ncol(Monitor *m) {
	apply_mslts(m, False, lt_hstack, lt_vstack);
}

static void
bstack(Monitor *m) {
	apply_mslts(m, True, lt_hstack, lt_hstack);
}

static void
grid(Monitor *m) {
	apply_mslts(m, False, lt_vstack, lt_grid);
}

/* Functions that apply layouts */

static void
apply_lt(Monitor *m, void (*ltf)(Client **, Booth *, unsigned int)) {
	unsigned int n;
	Client *c;

	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
	if(n == 0)
		return;

	c = m->clients;
	Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
	(*ltf)(&c, &b, n);
}

static void
apply_mslts(Monitor *m, Bool hsplit,
		void (*mltf)(Client **, Booth *, unsigned int),
		void (*sltf)(Client **, Booth *, unsigned int)) {
	unsigned int nm, n;
	Client *c;

	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
	if(n == 0)
		return;

	nm = MIN(n, m->nmaster);  /* number of masters */

	if (nm == 0) {
		/* all slaves */
		c = m->clients;
		Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
		(*sltf)(&c, &b, n);
	}
	else if(n > nm) {
		/* masters and slaves */
		c = m->clients;
		if(hsplit) {
			/* masters above slaves */
			Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh * m->mfact };
			(*mltf)(&c, &b, nm);
			b.y += b.h;
			b.h = m->wh - b.h;
			(*sltf)(&c, &b, n - nm);
		}
		else {
			/* masters at the left of slaves */
			Booth b = { .x = m->wx, .y = m->wy, .w = m->ww * m->mfact, .h = m->wh };
			(*mltf)(&c, &b, nm);
			b.x += b.w;
			b.w = m->ww - b.w;
			(*sltf)(&c, &b, n - nm);
		}
	}
	else {
		/* all masters */
		c = m->clients;
		Booth b = { .x = m->wx, .y = m->wy, .w = m->ww, .h = m->wh };
		(*mltf)(&c, &b, n);
	}
}

/* Layout functions: the actual algorithms */

static void
lt_hstack(Client **c, Booth *b, unsigned int n) {
	unsigned int i;
	int x, y, w, h;

	x = b->x;  /* x offset of the next cell */
	y = b->y;
	h = b->h;
	for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) {
		w = (b->x + b->w - x) / (n - i);
		resize(*c, x, y, w - 2 * (*c)->bw, h - 2 * (*c)->bw, False);
		x += WIDTH(*c);
	}
}

static void
lt_vstack(Client **c, Booth *b, unsigned int n) {
	unsigned int i;
	int x, y, w, h;

	x = b->x;
	y = b->y;  /* y offset of the next cell */
	w = b->w;
	for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) {
		h = (b->y + b->h - y) / (n - i);
		resize(*c, x, y, w - 2 * (*c)->bw, h - 2 * (*c)->bw, False);
		y += HEIGHT(*c);
	}
}

static void
lt_monocle(Client **c, Booth *b, unsigned int n) {
	unsigned int i;

	for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++)
		resize(*c, b->x, b->y, b->w - 2 * (*c)->bw, b->h - 2 * (*c)->bw, False);
}

static void
lt_grid(Client **c, Booth *b, unsigned int n) {
	unsigned int cols, rows, cn, rn, i, cx, cy, cw, ch;

	/* grid dimensions */
	for(cols = 0; cols <= n / 2; cols++)
		if(cols * cols >= n)
			break;
	if(n == 5)  /* set layout against the general rule: not 1:2:2, but 2:3 */
		cols = 2;
	rows = n / cols;

	/* window geometries */
	cw = cols ? b->w / cols : b->w;
	cn = 0;  /* current column number */
	rn = 0;  /* current row number */
	for(i = 0, *c = nexttiled(*c); *c && i < n; *c = nexttiled((*c)->next), i++) {
		if(i / rows + 1 > cols - n % cols)
			rows = n / cols + 1;
		ch = rows ? b->h / rows : b->h;
		cx = b->x + cn * cw;
		cy = b->y + rn * ch;
		resize(*c, cx, cy, cw - 2 * (*c)->bw, ch - 2 * (*c)->bw, False);
		rn++;
		if(rn >= rows) {
			rn = 0;
			cn++;
		}
	}
}


Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Mon, Oct 31, 2011 at 10:19 PM, Thomas Dahms  wrote:
>
> That looks interesting. I have one suggestion for a simplification:
> I guess you can get rid of the functions combining the master and
> slave layouts by modifying setlayout() to take three arguments (the
> two layouts and the direction of master/slave splitting). This way you
> could combine any two layouts in the key binding section of config.h.

I don't think we can do this with the current Arg.  I also don't see the
benefit of this over defining the layouts.  If the user wants to combine
two layout algorithms, he can always define a layout in as few as three
lines in config.h.  Please elaborate if I misunderstand.

Also, the code is so far in no way in conflict with the dwm code.  This
general approach is also more flexible.  For example, the example `ntile'
layout can replace `tile' in dwm.c, and `monocle' in dwm.c can be defined
via `apply_lt` using `lt_monocle`.

Actually, `apply_lt` can be removed, since `apply_mslts` does the same
thing when nmaster == 0.  I'm thinking of making nmaster a member of
the Layout structure, instead of the current Monitor.  This way, we can
make all windows slaves in the `grid' layout, while having two masters
when we switch to `tile'.  The same applies to mfact- the `ncol' layout
certainly needs a bigger mfact than `tile', for example.  Finally, neither
nmaster nor mfact makes sense in non-master-slave layouts (if you still
use those, that is ;).  Oh, and it would be nice if mfact increased when
nmaster increased in the `ncol' layout, too.  Maybe another function
as a member of Layout, which would be executed to set mfact as a hook
whenever nmaster changes?

Since the current tile, monocle, and proposed bstack layouts are each a
special case of the mslts approach, and mslts is more powerful (and I do
think is simpler and easier to read), and if you care, mslts will likely
decrease the SLOC due to removal of duplicated code, I think mslts could
be accepted into mainline.  What do you think?

>
> --
> Thomas Dahms
>
>



Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Tue, Nov 1, 2011 at 12:11 AM, lolilolicon  wrote:
>
> Actually, `apply_lt` can be removed, since `apply_mslts` does the same
> thing when nmaster == 0.  I'm thinking of making nmaster a member of
> the Layout structure, instead of the current Monitor.  This way, we can
> make all windows slaves in the `grid' layout, while having two masters
> when we switch to `tile'.  The same applies to mfact- the `ncol' layout
> certainly needs a bigger mfact than `tile', for example.  Finally, neither
> nmaster nor mfact makes sense in non-master-slave layouts (if you still
> use those, that is ;).  Oh, and it would be nice if mfact increased when
> nmaster increased in the `ncol' layout, too.  Maybe another function
> as a member of Layout, which would be executed to set mfact as a hook
> whenever nmaster changes?
>

Indeed mfact and nmaster being members of Layout does make more sense, and
I made a patch which includes this change.

Since I don't know much about hg, I just did a `hg export`, and attach the
produced patch as attachment instead of inline.  The commit message should
describe what has been done, and the code should explain itself.

Note that this may seem to add some SLOCs, but it actually reduces the
amount of code required to implement the same layouts by avoiding code
duplication.  See how tile, bstack and col are each defined using just a
one-liner.  By defining two layout algorithms `lt_vstack` and `lt_hstack`,
in combination with the hsplit switch, one can define 2 ** 2 * 2 = 8 such
layouts, and if you count the (masters|slaves)-only layouts as separate
ones, we got 10.  Add a third layout algorithm, and you have
3 ** 2 * 2 + 3 = 21.  Sure, not all layouts are useful for everyone, but
hopefully this will produce some interesting layouts suitable for your
particular setup.
# HG changeset patch
# User lolilolicon 
# Date 1320098001 -28800
# Node ID f35ce5cc96363a813f91e64f6eda30504052eeed
# Parent  904e923827cb010abb7a31298264548946616d92
A general approach to master-slave layouts

This makes the actual code implementing layout algorithms reusable.
Apply two separate layout algorithms to the master area and the slave
area.  The master and slave areas are separated by either vertical or
horizontal split.

The `tile' algorithm is split out as `lt_vstack` and the `tile' function
is now just a one-liner.  Due to the reusability, the `bstack' and `col'
layouts are added with few lines of code.  Other interesting layout
combinations can be easily added in the same manner.

Move mfact and nmaster to the Layout structure, so that each layout can
have its own mfact and nmaster.  This makes sense when using several
master-slave layouts, e.g., the `col' layout will usually use a mfact
larger than `tile'.

diff --git a/config.def.h b/config.def.h
--- a/config.def.h
+++ b/config.def.h
@@ -23,15 +23,15 @@
 };
 
 /* layout(s) */
-static const float mfact  = 0.55; /* factor of master area size [0.05..0.95] */
-static const int nmaster  = 1;/* number of clients in master area */
 static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
 
-static const Layout layouts[] = {
-	/* symbol arrange function */
-	{ "[]=",  tile },/* first entry is default */
-	{ "><>",  NULL },/* no layout function means floating behavior */
-	{ "[M]",  monocle },
+static Layout layouts[] = {
+	/* symbol arrange function mfactnmaster */
+	{ "[]=",  tile,0.55,1 },  /* first entry is default */
+	{ "><>",  NULL,0.5, 0 },  /* no layout function means floating behavior */
+	{ "[M]",  monocle, 0.5, 0 },
+	{ "TTT",  bstack,  0.55,1 },
+	{ "|||",  col, 0.75,2 },
 };
 
 /* key definitions */
@@ -66,6 +66,8 @@
 	{ MODKEY,   XK_t,  setlayout,  {.v = &layouts[0]} },
 	{ MODKEY,   XK_f,  setlayout,  {.v = &layouts[1]} },
 	{ MODKEY,   XK_m,  setlayout,  {.v = &layouts[2]} },
+	{ MODKEY,   XK_s,  setlayout,  {.v = &layouts[3]} },
+	{ MODKEY,   XK_c,  setlayout,  {.v = &layouts[4]} },
 	{ MODKEY,   XK_space,  setlayout,  {0} },
 	{ MODKEY|ShiftMask, XK_space,  togglefloating, {0} },
 	{ MODKEY,   XK_0,  view,   {.ui = ~0 } },
diff --git a/dwm.c b/dwm.c
--- a/dwm.c
+++ b/dwm.c
@@ -71,6 +71,10 @@
 } Arg;
 
 typedef struct {
+	int x, y, w, h;
+} Booth;
+
+typedef struct {
 	unsigned int click;
 	unsigned int mask;
 	unsigned int button;
@@ -120,12 +124,12 @@
 typedef struct {
 	const char *symbol;
 	void (*arrange)(Monitor *);
+	float mfact;

Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Tue, Nov 1, 2011 at 7:36 AM, Rob  wrote:
>
> I don't have much time today, or possibly tomorrow, but I'm interested
> in this patch, it sounds almost like it recurses on each sub-section of
> the total area, applying a different layout function each time, except
> it's limited to two calls, one for the master area and one for the
> slave.

It's only one patch, which I sent in my last mail, so not much really :)

The core is the `apply_mslts' funtion.  It walks all clients like any
tiling layout would do, e.g., the `tile' function defined in the patch
simply calls `apply_mslts(m, False, lt_vstack, lt_vstack)`, and it should
do the layout exactly the same way the original `tile' would do, no extra
wasted work.  The code should be clear, but maybe note that the mltf/sltf
functions modify `c'.

> Either way, I'm hoping to try out your patch(es) at some point
> this week, and hoping to mess around with the key bindings, I assume you
> can change the master layout while keeping the slave one the same with a
> binding, right?

Not really.  DWM knows only about a single layout per monitor, even if we
set the masters to temporarily use a different layout algorithm, but not
update the currently selected layout name, DWM will rearrange the masters
back to the selected layout whenever arrangemon() is called, which happens
probably before you realize it ;).  That said, you can always define two
layouts which differ only in the master layout, (e.g. `tile' and `col').
Or if we feel progressive, let's make DWM aware of the master layout as
well as the slave layout, although I don't see practical need so far.

Similarly, I also considered to enable toggling master/slave splitting
direction, effectively "rotating" the layout, or even allow "flipping",
but then thought it not useful in practice...

>
> Cheers,
> Rob
>



Re: [dev] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Tue, Nov 1, 2011 at 8:41 AM, Connor Lane Smith  wrote:
> Hey,
>
> On 31/10/2011, lolilolicon  wrote:
>> The idea of having more than one master windows is brilliant.  The `tile'
>> layout in current hg tip basically splits the master and slave areas
>> vertically, and tiles windows in each of the two areas using a vertical
>> stacking algorithm.
>
> I'll be interested to see where this goes. The code is still a bit raw
> at the moment, but I like the idea. I wonder how simple we can get
> this patch...

Indeed, I post it here for all your suckless energy to do my money laundry ;)

>
> cls
>
>



Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-11-01 Thread lolilolicon
On Tue, Nov 1, 2011 at 6:20 PM, Anselm R Garbe  wrote:
> On 1 November 2011 00:07, lolilolicon  wrote:
>> Indeed mfact and nmaster being members of Layout does make more sense, and
>> I made a patch which includes this change.
>>
>> Note that this may seem to add some SLOCs, but it actually reduces the
>> amount of code required to implement the same layouts by avoiding code
>> duplication.  See how tile, bstack and col are each defined using just a
>> one-liner.  By defining two layout algorithms `lt_vstack` and `lt_hstack`,
>> in combination with the hsplit switch, one can define 2 ** 2 * 2 = 8 such
>> layouts, and if you count the (masters|slaves)-only layouts as separate
>> ones, we got 10.  Add a third layout algorithm, and you have
>> 3 ** 2 * 2 + 3 = 21.  Sure, not all layouts are useful for everyone, but
>> hopefully this will produce some interesting layouts suitable for your
>> particular setup.
>
> Thanks for you patch, I looked at it and it is indeed interesting.
> However it needs further testing and review in order to be a candidate
> for mainline at some point.
>

Can't agree more.

> Some remarks:
>
> The change of the Layout struct makes it a lot harder to define
> layouts, as now one also has to understand the variables
> nmaster/mfact. Also nmaster/mfact are now layout specific variables
> that might not be used by other layouts. This lacks a bit conceptual
> clarity imho.
>

I also agree with what you said here, but let me clarify my intention.
I really think it more useful to make mfact/nmaster layout-specific,
otherwise I wounldn't have made the change to the Layout struct.  For
example, on my 1280x800 screen, mfact == 0.75 combined with nmaster == 2
in the n?col layout makes a nice layout, but the combination is very
bad for the tile layout.  As such, sharing mfact/nmaster across layouts
isn't exactly nice, nor is it "dynamic" enough.

But now I realize another problem with moving mfact/nmaster to Layout.
The issue is two monitors should be able to use different mfact/nmaster
values for the same layout; also, the setmfact/incnmaster functions
will not update the unselected monitor, but will have their effects all
of a sudden next time that monitor is arranged.
This makes me want to make nmaster/mfact specific to the monitor *and*
the layout.  And I also prefer achieving this in the least intrusive
way possible.

> What I'd really prefer is keeping the interface intact we had, a
> layout is just a function -- I have no objections that this function
> calls other functions or set up some variables to fit its needs. This
> would keep it equally simple to the user to define Layouts and leave
> the interface to be a function, rather than a function + variables.
>

You are absolutely right.  Now that I think of it, we can temporarily
set m->mfact and/or m->nmaster in a layout function before calling
apply_mslts, and restore the values afterwards.  For example, define
the col layout like this:

/* int term_width is the width of a terminal (e.g. 80 characters) */
void
col(Monitor *m) {
float mfact = m->mfact;
int nmaster = m->nmaster;
/* masters will be term_width wide */
m->nmaster = MIN(nmaster, m->ww / term_width);
m->mfact = (float)term_width * m->nmaster / m->ww;
apply_mslts(m, False, lt_hstack, lt_vstack);
m->mfact = mfact;
m->nmaster = nmaster;
}

A bit back-and-forth with the mfact calculation (since we will calculate
back to the width in apply_mslts), but it's a fair compromise, I guess.

> Also I'm not absolutely happy about the introduction of the Booth
> struct, I would rename that into Rect as we have used a similar name
> in other areas. Having said this, I'm in favor of *not* using
> XRectangle where possible, in order to keep the core code of dwm X
> agnostic (which is one 6.0 goal btw).
>

Bah, Booth is cute!  Just kidding; I knew it would sound strange and
probably have to be renamed.  Here we go, Rect it is.

> Cheers,
> Anselm
>
>



Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-11-01 Thread lolilolicon
On Tue, Nov 1, 2011 at 11:38 PM, Anselm R Garbe  wrote:
> On 1 November 2011 16:27, lolilolicon  wrote:
>> But now I realize another problem with moving mfact/nmaster to Layout.
>> The issue is two monitors should be able to use different mfact/nmaster
>> values for the same layout; also, the setmfact/incnmaster functions
>> will not update the unselected monitor, but will have their effects all
>> of a sudden next time that monitor is arranged.
>> This makes me want to make nmaster/mfact specific to the monitor *and*
>> the layout.  And I also prefer achieving this in the least intrusive
>> way possible.
>
> Exactly this is the main problem. You could work around it with
> changing monitor as follows:
>
>  struct Monitor {
>        char ltsymbol[16];
> -       float mfact;
> -       int nmaster;
> +       float mfact[LENGTH(layouts)];
> +       int nmaster[LENGTH(layouts)];
>        int num;
>        int by;               /* bar geometry */
>        int mx, my, mw, mh;   /* screen size */
>
> however this would require some reshuffling of the config.h inclusion
> and also changes in various places. So I doubt it would be necessary
> at all. Just stick with nmaster/mfact in Monitor.
>

Hmm, I think the difficulty is to track the index of the current layout
in the layouts array.  I'm not sure how.  I'd like to stick with the
current Monitor struct.

>> You are absolutely right.  Now that I think of it, we can temporarily
>> set m->mfact and/or m->nmaster in a layout function before calling
>> apply_mslts, and restore the values afterwards.  For example, define
>> the col layout like this:
>>
>>    /* int term_width is the width of a terminal (e.g. 80 characters) */
>>    void
>>    col(Monitor *m) {
>>        float mfact = m->mfact;
>>        int nmaster = m->nmaster;
>>        /* masters will be term_width wide */
>>        m->nmaster = MIN(nmaster, m->ww / term_width);
>>        m->mfact = (float)term_width * m->nmaster / m->ww;
>>        apply_mslts(m, False, lt_hstack, lt_vstack);
>>        m->mfact = mfact;
>>        m->nmaster = nmaster;
>>    }
>>
>> A bit back-and-forth with the mfact calculation (since we will calculate
>> back to the width in apply_mslts), but it's a fair compromise, I guess.
>
> This could work for a patch, but I don't think this is a great way of
> programming for mainline, since manipulating and restoring
> nmaster/mfact for the time being is quite ugly. ;)

Well, it's a compromise.  Would you feel it's less ugly if I define the
apply_mslts function like this:

tatic void apply_mslts(Monitor *m, Bool hsplit,
float mfact, int nmaster,
void (*mltf)(Client **, Booth *, unsigned int),
void (*sltf)(Client **, Booth *, unsigned int)) {
/* uses mfact instead of m->mfact, nmaster intead of m->nmaster */
}

and define the layouts like:

void
col(Monitor *m) {
      int nmaster = MIN(m->nmaster, m->ww / term_width);
      float mfact = (float)term_width * nmaster / m->ww;
  apply_mslts(m, False, mfact, nmaster, lt_hstack, lt_vstack);
}
void
tile(Monitor *m) {
  apply_mslts(m, False, m->mfact, m->nmaster, lt_vstack, lt_vstack);
}

Basically the same thing, I guess it's still ugly, but does it feel less
ugly? :D

>
> Cheers,
> Anselm
>
>



Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-11-02 Thread lolilolicon
I believe every master-slave layout, i.e., layouts where mfact/nmaster
make sense, should own its own mfact/nmaster value, not to be disturbed
by other layouts.  As said before, `col' and `tile' for example just
can't share the same mfact and still both look good.

Consequently, I decided to update the patch so mfact and nmaster are now
monitor- and layout-specific.  This should make the master-slave layouts
play nice with each other and thus make the idea more complete.

Also, the nice thing about this approach is that the config.h interface
is left unchanged.  mfact and nmaster values of each layout are
initialized to the global value mfact and nmaster; the user can also
implement layouts that force rules on mfact and nmaster if desired.

diff -r 904e923827cb -r 983f8ffd9f7c config.def.h
--- a/config.def.h  Mon Oct 31 20:09:27 2011 +0100
+++ b/config.def.h  Wed Nov 02 20:15:22 2011 +0800
@@ -32,6 +32,8 @@
{ "[]=",  tile },/* first entry is default */
{ "><>",  NULL },/* no layout function means floating behavior 
*/
{ "[M]",  monocle },
+   { "TTT",  bstack },
+   { "|||",  col },
 };

 /* key definitions */
@@ -66,6 +68,8 @@
{ MODKEY,   XK_t,  setlayout,  {.v =
&layouts[0]} },
{ MODKEY,   XK_f,  setlayout,  {.v =
&layouts[1]} },
{ MODKEY,   XK_m,  setlayout,  {.v =
&layouts[2]} },
+   { MODKEY,   XK_s,  setlayout,  {.v =
&layouts[3]} },
+   { MODKEY,   XK_c,  setlayout,  {.v =
&layouts[4]} },
{ MODKEY,   XK_space,  setlayout,  {0} },
{ MODKEY|ShiftMask, XK_space,  togglefloating, {0} },
{ MODKEY,   XK_0,  view,   {.ui = ~0 } 
},
diff -r 904e923827cb -r 983f8ffd9f7c dwm.c
--- a/dwm.c Mon Oct 31 20:09:27 2011 +0100
+++ b/dwm.c Wed Nov 02 20:15:22 2011 +0800
@@ -122,26 +122,9 @@
void (*arrange)(Monitor *);
 } Layout;

-struct Monitor {
-   char ltsymbol[16];
-   float mfact;
-   int nmaster;
-   int num;
-   int by;   /* bar geometry */
-   int mx, my, mw, mh;   /* screen size */
-   int wx, wy, ww, wh;   /* window area  */
-   unsigned int seltags;
-   unsigned int sellt;
-   unsigned int tagset[2];
-   Bool showbar;
-   Bool topbar;
-   Client *clients;
-   Client *sel;
-   Client *stack;
-   Monitor *next;
-   Window barwin;
-   const Layout *lt[2];
-};
+typedef struct {
+   int x, y, w, h;
+} Rect;

 typedef struct {
const char *class;
@@ -153,18 +136,23 @@
 } Rule;

 /* function declarations */
+static void apply_mslts(Monitor *m, Bool hsplit,
+   void (*mltf)(Client **, Rect *, unsigned int),  /* master 
layout function */
+   void (*sltf)(Client **, Rect *, unsigned int)); /* slave layout 
function */
 static void applyrules(Client *c);
 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h,
Bool interact);
 static void arrange(Monitor *m);
 static void arrangemon(Monitor *m);
 static void attach(Client *c);
 static void attachstack(Client *c);
+static void bstack(Monitor *);
 static void buttonpress(XEvent *e);
 static void checkotherwm(void);
 static void cleanup(void);
 static void cleanupmon(Monitor *mon);
 static void clearurgent(Client *c);
 static void clientmessage(XEvent *e);
+static void col(Monitor *);
 static void configure(Client *c);
 static void configurenotify(XEvent *e);
 static void configurerequest(XEvent *e);
@@ -185,6 +173,7 @@
 static void focusmon(const Arg *arg);
 static void focusstack(const Arg *arg);
 static unsigned long getcolor(const char *colstr);
+static unsigned int getlayoutindex(const Layout *lt);
 static Bool getrootptr(int *x, int *y);
 static long getstate(Window w);
 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
@@ -194,6 +183,8 @@
 static void initfont(const char *fontstr);
 static void keypress(XEvent *e);
 static void killclient(const Arg *arg);
+static void lt_hstack(Client **c, Rect *r, unsigned int n);
+static void lt_vstack(Client **c, Rect *r, unsigned int n);
 static void manage(Window w, XWindowAttributes *wa);
 static void mappingnotify(XEvent *e);
 static void maprequest(XEvent *e);
@@ -281,11 +272,92 @@
 /* configuration, allows nested code to access above variables */
 #include "config.h"

+struct Monitor {
+   char ltsymbol[16];
+   float mfact[LENGTH(layouts)];
+   int nmaster[LENGTH(layouts)];
+   int num;
+   int by;   /* bar geometry */
+   int mx, my, mw, mh;   /* screen size */
+   int wx, wy, ww, wh;   /* window area  */
+   unsigned int seltags;
+   unsigned int sellt;
+   unsigned int tagset[2];
+   Bool showbar;
+   Bool topbar;
+   Client *clients;
+   Client *sel;

Re: [dev] A general approach to master-slave layouts

2011-11-06 Thread lolilolicon
On Mon, Nov 7, 2011 at 3:28 AM, Connor Lane Smith  wrote:
> Hey,
>
> I've been thinking about this patch for a while, and I've knocked
> together a patch which takes an alternative approach, which seems to
> result in a simpler diff.
>
> In my patch each layout has three arrangement functions, one for the
> master, one the slave, and one a 'meta-layout' which defines how the
> master and slave "booths" are laid out. So dwm's tile() is achieved
> with an htile() meta-layout and vtile() master and slave.
>
> The patch is +12 lines over dwm tip.
>
> Thanks,
> cls
>

This is nice.
I've played around with it, and have had some progress:

  * Fixed the nmaster == 0 case.  The original patch would create an empty
master area.

  * Expoit the mfact < 0 possibility.  When mfact is set to negative, use
the slave area as master area, and vice versa.  This makes it possible
to put masters on the right in tile, for example.  Adjusting setmfact()
for this, for now, but we should probably make this more flexible...

  * Port my original spiral layout to play with this patch.

I've attached the patch and the spiral layout as attachments.

And a question.  What is your plan on dealing with mfact/nmaster?  As I've
always insisted, they should be both monitor- and layout-specific.  What's
your opinion, and how would you approach this?

Thanks
diff -r ee36ffbd4252 config.def.h
--- a/config.def.h	Sun Nov 06 20:36:23 2011 +0100
+++ b/config.def.h	Mon Nov 07 11:03:20 2011 +0800
@@ -29,9 +29,9 @@
 
 static const Layout layouts[] = {
 	/* symbol arrange function */
-	{ "[]=",  tile },/* first entry is default */
-	{ "><>",  NULL },/* no layout function means floating behavior */
-	{ "[M]",  monocle },
+	{ "[]=",  tileh,   tilev,   tilev },   /* first entry is default */
+	{ "><>",  NULL,NULL,NULL },/* no layout function means floating behavior */
+	{ "[M]",  monocle, monocle, monocle },
 };
 
 /* key definitions */
diff -r ee36ffbd4252 dwm.c
--- a/dwm.c	Sun Nov 06 20:36:23 2011 +0100
+++ b/dwm.c	Mon Nov 07 11:03:20 2011 +0800
@@ -121,7 +121,9 @@
 
 typedef struct {
 	const char *symbol;
-	void (*arrange)(Monitor *);
+	void (*arrange)(Client *, float, XRectangle *, XRectangle *);
+	void (*master)(Client *, float, XRectangle *, XRectangle *);
+	void (*slave)(Client *, float, XRectangle *, XRectangle *);
 } Layout;
 
 struct Monitor {
@@ -199,7 +201,7 @@
 static void manage(Window w, XWindowAttributes *wa);
 static void mappingnotify(XEvent *e);
 static void maprequest(XEvent *e);
-static void monocle(Monitor *m);
+static void monocle(Client *c, float fact, XRectangle *r, XRectangle *rp);
 static void movemouse(const Arg *arg);
 static Client *nexttiled(Client *c);
 static void pop(Client *);
@@ -226,7 +228,8 @@
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static int textnw(const char *text, unsigned int len);
-static void tile(Monitor *);
+static void tileh(Client *c, float fact, XRectangle *r, XRectangle *rp);
+static void tilev(Client *c, float fact, XRectangle *r, XRectangle *rp);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
 static void toggletag(const Arg *arg);
@@ -403,9 +406,28 @@
 
 void
 arrangemon(Monitor *m) {
+	XRectangle r, rm, rt = { m->wx, m->wy, m->ww, m->wh };
+	Client *c;
+	float f;
+	int i, n;
+
 	strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
-	if(m->lt[m->sellt]->arrange)
-		m->lt[m->sellt]->arrange(m);
+	if(m->lt[m->sellt]->arrange) {
+		for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+		if(n > 0) {
+			if((f = (n > m->nmaster) ? (m->nmaster == 0 ? 0 : m->mfact) : 1) < 0) {
+rm = rt;
+m->lt[m->sellt]->arrange(NULL, 1 + f, &rm, &rt);
+			}
+			else
+m->lt[m->sellt]->arrange(NULL, f, &rt, &rm);
+			for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+if(i < m->nmaster)
+	m->lt[m->sellt]->master(c, 1.0 / (MIN(n, m->nmaster) - i), &rm, &r);
+else
+	m->lt[m->sellt]->slave(c, 1.0 / (n - i), &rt, &r);
+		}
+	}
 	restack(m);
 }
 
@@ -1188,17 +1210,13 @@
 }
 
 void
-monocle(Monitor *m) {
-	unsigned int n = 0;
-	Client *c;
-
-	for(c = m->clients; c; c = c->next)
-		if(ISVISIBLE(c))
-			n++;
-	if(n > 0) /* override layout symbol */
-		snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
-	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
-		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
+monocle(Client *c, float fact, XRectangle *r, XRectangle *rp) {
+	rp->x  = r->x;
+	rp->y  = r->y;
+	rp->width  = r->width;
+	rp->height = r->height;
+	if(c)
+		resize(c, r->x, r->y, r->width - (2*c->bw), r->height - (2*c->bw), False);
 }
 
 void
@@ -1553,13 +1571,15 @@
 void
 setmfact(const Arg *arg) {
 	float f;
+	int i;
 
 	if(!arg || !selmon->lt[selmon->sellt]->arrange)
 		return;
-	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
+	i = selmon->mfact < 0 ? -1 : 1;
+	f = a

Re: [dev] A general approach to master-slave layouts

2011-11-06 Thread lolilolicon
On Mon, Nov 7, 2011 at 11:15 AM, lolilolicon  wrote:
>
>  * Port my original spiral layout to play with this patch.

I've simplified the spiral layout by rusing tile{h,v}. Nice.
void
spiral(Client *c, float fact, XRectangle *r, XRectangle *rp) {
	if(fact == 0) {
		rp->width = rp->height = 0;
		return;
	}

	static int pos = 1;
	float f = fact == 1 ? 1 : 0.5;

	switch(pos) {
		case 0:  /* left */
			tileh(c, f, r, rp);
			pos = 1;
			break;
		case 1:  /* top */
			tilev(c, f, r, rp);
			pos = 2;
			break;
		case 2:  /* right */
			tileh(c, f, &((XRectangle){ r->x + r->width * (1 - f), r->y, r->width, r->height }), rp);
			r->width  -= rp->width;
			pos = 3;
			break;
		case 3:  /* bottom */
			tilev(c, f, &((XRectangle){ r->x, r->y + r->height * (1 - f), r->width, r->height }), rp);
			r->height -= rp->height;
			pos = 0;
			break;
	}

	if(fact == 1)
		pos = 1;  /* reset to initial value */
}