unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Fwd: Tabs for console.
       [not found] <AANLkTim8zuFRh2L81g9KgtDon=U5Mvr+QO+HWGE1nqXP@mail.gmail.com>
@ 2010-10-27 16:39 ` Alin Soare
  2010-11-08 19:22   ` Stefan Monnier
  2010-10-27 20:34 ` Alin Soare
  1 sibling, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-10-27 16:39 UTC (permalink / raw)
  To: Emacs Dev


[-- Attachment #1.1: Type: text/plain, Size: 3308 bytes --]

I worked long time ago on tabs for console, as many of you already know.

1 year ago I reopened the tabs, and started from scratch, having a different
idea. Afterwards I realized the idea was not good, and gave up again.

3 days ago I reopned the problem, and started to re-written it again from
scratch.

Concretely, this time I do not want to miss again.

I do not want to work alone this time. I want to receive your suggestions.

I have already talked about this with Stefan Monnier, and I want to
implement it as agreed with him.

A tab is a formed from a few scripts: an initialization script, and
activation script, an deactivation script, etc.

Here is the patch.

I tried to create a tab that represents a frame with this code:

(setq init-tab
      '( (+ 1 2)
     (setq fr (make-terminal-frame '((tab . t)))) ) )

(setq act-tab
      '( (message "activate")
     (select-frame fr) ) )

(setq desact-tab
      '( (message "hide tab") ) )

(make-tab (list (cons 'tab-code:init init-tab )
        (cons 'tab-code:activate act-tab )
        (cons 'tab-code:desactivate desact-tab )
        ) )

(activate-tab 0)

The parameter '0' of `activate-tab' means to activate the first TAB of the
selected frame. It calls the activation script of the first tab, after it
calls the deactivation script of the last activated tab (if any).

I attach the output of git diff, and a test file test-tabs.el.

In order to test it, you have to evaluate make-tab a few times, and
afterwards (activate-tab 0)

There is some code inserted in patch, and commented . It rested from the
previous tries to do the tabs, and it is no longer useful.

Do not expect too much ; the patch I send today makes emacs crash after a
short period of use of tabs :). Do not install it on your good sources :).
(the garbage collector makes it crash, and i do not see what variable is not
protected using gcpro..). This is of second importance for now. The bugs
will be corrected. Also, take care that the cashes of fonts are not cleared,
and when you switch to the tab-frame, the redisplay-internat will not
display correctly, and crashes. I forgot how to initialize the fonts for a
frame. When you switch back with a command like

 (let ((f (car
(frame-list))))

  (select-frame f))

it displays the main frame correctly.

For me to be able to finish this work, it is important/crucial for you to
suggest me how to do it, in order to agree on the behavior of tabs. It is
sure I cannot do this job alone. On the other hand, please report me bugs,
and suggestions to solve them :) )

I definitively want to make the tabs as scripts. A particular set of scripts
will create tabs as frames, another set as window-configurations, another
set will be tabs for compilation, etc. Had emacs had lexical scoping, it
would be easier to define the scripts. In dynamic scoping, for each tab one
needs a variable with a different name to keep a tab-frame inside the
scripts of that tab. I also modified make-terminal-frame, in order to be
able to create frames that are not linked into frame-list. I call the frames
of frame-list "main frames" (as you see in frame.h).

For the next period of time I am able to work on this. I am waiting for your
suggestions. It depends only on you if I continue to work and finish the
tabs for console or not.


Alin.

[-- Attachment #1.2: Type: text/html, Size: 4220 bytes --]

[-- Attachment #2: test-tabs.el --]
[-- Type: text/x-emacs-lisp, Size: 872 bytes --]


(emacs-pid)

(set-frame-parameter (selected-frame) 'tab-bar-lines 3)

(custom-set-faces
 '(current-tab ((t ( :background "green"  :foreground "lightblue"))))
 '(odd-tabs    ((t ( :background "red"    :foreground "white" ))))
 '(even-tabs   ((t ( :background "green"  :foreground "black")))))

(setq init-tab
      '( (+ 1 2)
	 (setq fr (make-terminal-frame '((tab . t)))) ) )

(setq act-tab
      '( (message "activate")
	 (select-frame fr) ) )

(setq desact-tab
      '( (message "hide tab") ) )

(make-tab (list (cons 'tab-code:init init-tab )
		(cons 'tab-code:activate act-tab )
		(cons 'tab-code:desactivate desact-tab )
		) )

(activate-tab 0)

'(assoc 'tab-bar-lines (frame-parameters))

'(setq fr (make-terminal-frame '((tab . t))))

'(select-frame fr)

'(selected-frame)

'(delete-frame fr)

'(let ((f (car (frame-list))))
  (select-frame f))

'(frame-list)





[-- Attachment #3: tabs.diff.bz2 --]
[-- Type: application/x-bzip2, Size: 163354 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Tabs for console.
       [not found] <AANLkTim8zuFRh2L81g9KgtDon=U5Mvr+QO+HWGE1nqXP@mail.gmail.com>
  2010-10-27 16:39 ` Fwd: Tabs for console Alin Soare
@ 2010-10-27 20:34 ` Alin Soare
  1 sibling, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-10-27 20:34 UTC (permalink / raw)
  To: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 3605 bytes --]

I send again my previous message, because my previous message contained the
attachments, and on emacs-devel lists seems there were errors inside the
text.


I do not attach the patch again (it has unciompressed more than 700K, and it
is not complete ). I hope to send it without errors now.

------


I worked long time ago on tabs for console, as many of you already know.

1 year ago I reopened the tabs, and started from scratch, having a different
idea. Afterwards I realized the idea was not good, and gave up again.

3 days ago I reopened the problem, and started to re-written it again from
scratch.

Concretely, this time I do not want to miss again.

I do not want to work alone this time. I want to receive your suggestions.

I have already talked about this with Stefan Monnier, and I want to
implement it as agreed with him.

A tab is a formed from a few scripts: an initialization script, an
activation script, a deactivation script, etc.

Here is the patch.

I tried to create a tab that represents a frame with this code:

(setq init-tab
      '( (+ 1 2)
     (setq fr (make-terminal-frame '((tab . t)))) ) )

(setq act-tab
      '( (message "activate")
     (select-frame fr) ) )

(setq deact-tab
      '( (message "hide tab") ) )

(make-tab (list (cons 'tab-code:init init-tab )
        (cons 'tab-code:activate act-tab )
        (cons 'tab-code:deactivate deact-tab )
        ) )

(activate-tab 0)

The parameter '0' of `activate-tab' means to activate the first TAB of the
selected frame. It calls the activation script of the first tab, after it
calls the deactivation script of the last activated tab (if any).

I attach the output of git diff, and a test file test-tabs.el.

In order to test it, you have to evaluate make-tab a few times, and
afterwards (activate-tab 0)

There is some code inserted in patch, and commented . It rested from the
previous tries to do the tabs, and it is no longer useful.

Do not expect too much ; the patch I send today makes emacs crash after a
short period of use of tabs :). Do not install it on your good sources :).
(the garbage collector makes it crash, and i do not see what variable is not
protected using gcpro..). This is of second importance for now. The bugs
will be corrected. Also, take care that the cashes of fonts are not cleared,
and when you switch to the tab-frame, the redisplay-internal will not
display correctly, and crashes. I forgot how to initialize the fonts for a
frame. When you switch back with a command like

 (let ((f (car
(frame-list))))

  (select-frame f))

it displays the main frame correctly.

For me to be able to finish this work, it is important/crucial for you to
suggest me how to do it, in order to agree on the behavior of tabs. It is
sure I cannot do this job alone. On the other hand, please report me bugs,
and suggestions to solve them :) )

I definitively want to make the tabs as scripts. A particular set of scripts
will create tabs as frames, another set as window-configurations, another
set will be tabs for compilation, etc. Had emacs had lexical scoping, it
would be easier to define the scripts. In dynamic scoping, for each tab one
needs a variable with a different name to keep a tab-frame inside the
scripts of that tab. I also modified make-terminal-frame, in order to be
able to create frames that are not linked into frame-list. I call the frames
of frame-list "main frames" (as you see in frame.h).

For the next period of time I am able to work on this. I am waiting for your
suggestions. It depends only on you if I continue to work and finish the
tabs for console or not.


Alin.

[-- Attachment #2: Type: text/html, Size: 4535 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
@ 2010-10-29  7:49 Alin Soare
  0 siblings, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-10-29  7:49 UTC (permalink / raw)
  To: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 437 bytes --]

How can I create the diff using git, such that I see the hunks in the diff
file in Berkeley context format, and see only the changes I did ?

Please try to propose me scripts of creating tabs that keep frames. It is
not too clear for me how such scripts can be created , such that you find
the tabs of type frame useful for you. If you propose me such scripts as you
need it, I can modify the code to make it behave on your needs.

Alin

[-- Attachment #2: Type: text/html, Size: 476 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-10-27 16:39 ` Fwd: Tabs for console Alin Soare
@ 2010-11-08 19:22   ` Stefan Monnier
  2010-11-08 19:51     ` Alin Soare
       [not found]     ` <AANLkTikwua2bfyvJkt+sn2vR_CzTZA6Hs0Lw=NJSVwT4@mail.gmail.com>
  0 siblings, 2 replies; 34+ messages in thread
From: Stefan Monnier @ 2010-11-08 19:22 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

> A tab is a formed from a few scripts: an initialization script, and
> activation script, an deactivation script, etc.

> Here is the patch.

The patch is huge and includes a lot of irrelevant changes (mostly
reverting recent changes), so it's not readable as sent.
Make sure you send a diff that's relative to the code that you modified,
and not to some other version of the code: check the patch visually and
if you see a change in there which *you* did not write, then the patch
is wrong (i.e. you're calling git with incorrect arguments).

> I tried to create a tab that represents a frame with this code:

> (setq init-tab
>       '( (+ 1 2)
>      (setq fr (make-terminal-frame '((tab . t)))) ) )

> (setq act-tab
>       '( (message "activate")
>      (select-frame fr) ) )

> (setq desact-tab
>       '( (message "hide tab") ) )

> (make-tab (list (cons 'tab-code:init init-tab )
>         (cons 'tab-code:activate act-tab )
>         (cons 'tab-code:desactivate desact-tab )
>         ) )

> (activate-tab 0)

I don't know what the above means.  Please explain what the above is
meant to do and in what way.

One problem I see with the above is that it uses quoted code, which has
the major disadvantage of not being byte-compilable.  Always try and use
functions instead of quoted code.  Something like:

   (setq init-tab
         (lambda ()
           (+ 1 2)
           (setq fr (make-terminal-frame '((tab . t))))))
   
   (setq act-tab
         (lambda ()
           (message "activate")
           (select-frame fr)))
   
   (setq desact-tab
         (lambda ()
           (message "hide tab")))

> The parameter '0' of `activate-tab' means to activate the first TAB of the
> selected frame.

Why?  Are they numbered?

> For the next period of time I am able to work on this. I am waiting for your
> suggestions. It depends only on you if I continue to work and finish the
> tabs for console or not.

Are your tabs "per-frame" or "per-window", or something else?


        Stefan



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-11-08 19:22   ` Stefan Monnier
@ 2010-11-08 19:51     ` Alin Soare
       [not found]       ` <AANLkTim8BoGpECQUUNfPidbn2k_HP77sykR=HYqw9BOE@mail.gmail.com>
  2011-03-11  8:52       ` A Soare
       [not found]     ` <AANLkTikwua2bfyvJkt+sn2vR_CzTZA6Hs0Lw=NJSVwT4@mail.gmail.com>
  1 sibling, 2 replies; 34+ messages in thread
From: Alin Soare @ 2010-11-08 19:51 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 2592 bytes --]

The patch I sent contained a bug of garbage collerctor, and more than that
it was not commented. I am preparing now a patch that contains

- no bug
- comments
- minimal code, that takes no action apart from showing the tabs.

I will resend the patch again in a few days, when I have time to complete
it, and we will discuss again about what a tab should do, in order to
implementent what you ask for a tab, etc.

See you soon.


alin



2010/11/8 Stefan Monnier <monnier@iro.umontreal.ca>

> > A tab is a formed from a few scripts: an initialization script, and
> > activation script, an deactivation script, etc.
>
> > Here is the patch.
>
> The patch is huge and includes a lot of irrelevant changes (mostly
> reverting recent changes), so it's not readable as sent.
> Make sure you send a diff that's relative to the code that you modified,
> and not to some other version of the code: check the patch visually and
> if you see a change in there which *you* did not write, then the patch
> is wrong (i.e. you're calling git with incorrect arguments).
>
> > I tried to create a tab that represents a frame with this code:
>
> > (setq init-tab
> >       '( (+ 1 2)
> >      (setq fr (make-terminal-frame '((tab . t)))) ) )
>
> > (setq act-tab
> >       '( (message "activate")
> >      (select-frame fr) ) )
>
> > (setq desact-tab
> >       '( (message "hide tab") ) )
>
> > (make-tab (list (cons 'tab-code:init init-tab )
> >         (cons 'tab-code:activate act-tab )
> >         (cons 'tab-code:desactivate desact-tab )
> >         ) )
>
> > (activate-tab 0)
>
> I don't know what the above means.  Please explain what the above is
> meant to do and in what way.
>
> One problem I see with the above is that it uses quoted code, which has
> the major disadvantage of not being byte-compilable.  Always try and use
> functions instead of quoted code.  Something like:
>
>   (setq init-tab
>         (lambda ()
>            (+ 1 2)
>           (setq fr (make-terminal-frame '((tab . t))))))
>
>   (setq act-tab
>          (lambda ()
>            (message "activate")
>           (select-frame fr)))
>
>   (setq desact-tab
>          (lambda ()
>           (message "hide tab")))
>
> > The parameter '0' of `activate-tab' means to activate the first TAB of
> the
> > selected frame.
>
> Why?  Are they numbered?
>
> > For the next period of time I am able to work on this. I am waiting for
> your
> > suggestions. It depends only on you if I continue to work and finish the
> > tabs for console or not.
>
> Are your tabs "per-frame" or "per-window", or something else?
>
>
>        Stefan
>

[-- Attachment #2: Type: text/html, Size: 3544 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Tabs for console.
       [not found]           ` <jwvhbewqnjj.fsf-monnier+emacs@gnu.org>
@ 2010-12-02 22:43             ` Alin Soare
  2010-12-02 22:45               ` Alin Soare
  0 siblings, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-02 22:43 UTC (permalink / raw)
  To: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 1625 bytes --]

Here it is. I spent 2 weeks to learn git, in order to be able to work with
emacs confortably, and now I am almost? expert in git LOL.

A first functional version. It is difficult to believe, isn't it? Those who
love the console will enjoy.

It is the 3rd time when I restart the tabs from scratch, and the first time
when I manage to get a result.

The first time I started coding tabs as frames. Every frame had a list of
frames, and those secondary frames appeared as tabs. I realized the idea was
bad and gave up.

The second try, I modified the Vframe_list. From a list of frames, I
transformed it into a list of lists of frames. Every such list represented a
group of tabs. Every frame had as tabs the frames from the same group with
it. It worked, but to develop the idea should have been modified half of
emacs!

Next, I had the idea, after a discussion with Stefan Monnier that tabs must
be implemented programmable.

I attach you an example. Tabs that implement window configuration.

The tabs are not finished. this is just the beginning.

The programmable tabs should implement everything, from window
configurations up to compilations and frames, and many more.

In order to be able to implement tabs as frames, the frames functionality
must be extended.

Every tab should have its own environment (see the conflict of the variable
cwc). Actor model of evaluation is good for this, but emacs does not have
lexical scope yet.

The code is not completed yet. I did not add comments yet.

Please look over the code. I will send a commented version next days. Until
then , I hope to receive your suggestion.




Alin

[-- Attachment #2: Type: text/html, Size: 1742 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Tabs for console.
  2010-12-02 22:43             ` Alin Soare
@ 2010-12-02 22:45               ` Alin Soare
  2010-12-03  8:19                 ` martin rudalics
                                   ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-02 22:45 UTC (permalink / raw)
  To: Emacs Dev


[-- Attachment #1.1: Type: text/plain, Size: 1625 bytes --]

Here it is. I spent 2 weeks to learn git, in order to be able to work with
emacs confortably, and now I am almost? expert in git LOL.

A first functional version. It is difficult to believe, isn't it? Those who
love the console will enjoy.

It is the 3rd time when I restart the tabs from scratch, and the first time
when I manage to get a result.

The first time I started coding tabs as frames. Every frame had a list of
frames, and those secondary frames appeared as tabs. I realized the idea was
bad and gave up.

The second try, I modified the Vframe_list. From a list of frames, I
transformed it into a list of lists of frames. Every such list represented a
group of tabs. Every frame had as tabs the frames from the same group with
it. It worked, but to develop the idea should have been modified half of
emacs!

Next, I had the idea, after a discussion with Stefan Monnier that tabs must
be implemented programmable.

I attach you an example. Tabs that implement window configuration.

The tabs are not finished. this is just the beginning.

The programmable tabs should implement everything, from window
configurations up to compilations and frames, and many more.

In order to be able to implement tabs as frames, the frames functionality
must be extended.

Every tab should have its own environment (see the conflict of the variable
cwc). Actor model of evaluation is good for this, but emacs does not have
lexical scope yet.

The code is not completed yet. I did not add comments yet.

Please look over the code. I will send a commented version next days. Until
then , I hope to receive your suggestion.




Alin

[-- Attachment #1.2: Type: text/html, Size: 1828 bytes --]

[-- Attachment #2: test-tabs.el --]
[-- Type: text/x-emacs-lisp, Size: 1710 bytes --]


;; evaluate this file sexp after sexp and follow the comments.

;; set a minimal environment
(progn
  (custom-set-faces
   '(current-tab-face ((t ( :inherit 'default-face  :foreground "lightblue" :bold t :underline t))))
   '(odd-tab-face    ((t ( :background "red"    :foreground "white" ))))
   '(even-tab-face   ((t ( :background "green"  :foreground "black")))))
  (set-frame-parameter (selected-frame) 'tab-bar-lines 4)
  (set-frame-parameter (selected-frame) 'menu-bar-lines 0))

;;make a few tabs from index #0 up to #9
(dotimes (i 10)
  (make-terminal-frame '((tab . t))))

;; make a tab #10 that keeps a window configuration. When it is created,
;; it memories the current win config. When it is activated, it
;; restores the memorized win config
(make-terminal-frame
 '((tab . t)
   (tab:init . (lambda () (setq cwce (current-window-configuration))))
   (tab:activate . (lambda () (set-window-configuration cwce)))
   (tab:deactivate . (lambda () (message "qqq")))))

;; change the window configuration
((lambda nil
   (split-window-vertically)
   (split-window-vertically)
   (split-window-horizontally)))
 
;; now activate the tab that keeps the memorized win config.  this
;; function disovered a bug in window configuration . LOL.  If you
;; change the tab-bar-lines or menu-bar-lines after creating the tab
;; #10 and before activatin it here, emacs crashes. LOL.
(set-frame-parameter (selected-frame) 'current-tab 10)

;; try it: now try to change the window config, activate tab #0, and
;; reactivate tab #10.

;; dump frame params
(progn
  (setq  eval-expression-print-length 5000
	 eval-expression-print-level  5000
	 print-level 5000
	 )
  (frame-parameters) )

;; that's all for now.





[-- Attachment #3: 0001-tabs-for-console.patch --]
[-- Type: text/x-patch, Size: 18265 bytes --]

From 3ecdbb0c879ebcf6d011211d14d89392993fd503 Mon Sep 17 00:00:00 2001
From: root <root@alin.(none)>
Date: Thu, 2 Dec 2010 23:53:41 +0200
Subject: [PATCH] tabs for console

---
 src/dispextern.h |    3 +
 src/frame.c      |  224 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/frame.h      |   25 +++++-
 src/window.c     |    5 +
 src/xdisp.c      |   76 ++++++++++++++++++
 src/xfaces.c     |   10 +++
 6 files changed, 333 insertions(+), 10 deletions(-)

diff --git a/src/dispextern.h b/src/dispextern.h
index 7426c03..2a87044 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1697,6 +1697,9 @@ enum face_id
   MOUSE_FACE_ID,
   MENU_FACE_ID,
   VERTICAL_BORDER_FACE_ID,
+  CURRENT_TAB_FACE_ID,
+  ODD_TAB_FACE_ID,
+  EVEN_TAB_FACE_ID,
   BASIC_FACE_ID_SENTINEL
 };
 
diff --git a/src/frame.c b/src/frame.c
index ba675be..a012066 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -118,16 +118,19 @@ Lisp_Object Qwindow_id;
 Lisp_Object Qouter_window_id;
 #endif
 Lisp_Object Qparent_id;
-Lisp_Object Qtitle, Qname;
+Lisp_Object Qtitle, Qname, Qtab_name, Qtab, Qcurrent_tab;
+Lisp_Object Qtab_code_init, Qtab_code_activate, Qtab_code_deactivate;
 Lisp_Object Qexplicit_name;
 Lisp_Object Qunsplittable;
-Lisp_Object Qmenu_bar_lines, Qtool_bar_lines, Qtool_bar_position;
+Lisp_Object Qmenu_bar_lines, Qtool_bar_lines, Qtool_bar_position, Qtab_bar_lines;
 Lisp_Object Vmenu_bar_mode, Vtool_bar_mode;
 Lisp_Object Qleft_fringe, Qright_fringe;
 Lisp_Object Qbuffer_predicate, Qbuffer_list, Qburied_buffer_list;
 Lisp_Object Qtty_color_mode;
 Lisp_Object Qtty, Qtty_type;
 
+Lisp_Object Qtab_activate, Qtab_deactivate, Qtab_init;
+
 Lisp_Object Qfullscreen, Qfullwidth, Qfullheight, Qfullboth, Qmaximized;
 Lisp_Object Qsticky;
 Lisp_Object Qfont_backend;
@@ -197,6 +200,146 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
       adjust_glyphs (f);
     }
 }
+
+/* this is identical to set_menu_bar_lines_1 */
+static void
+set_tab_bar_lines_1 ( Lisp_Object window, int n)
+{
+  struct window *w = XWINDOW (window);
+
+  XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
+  XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
+
+  if (INTEGERP (w->orig_top_line))
+    XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
+  if (INTEGERP (w->orig_total_lines))
+    XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
+
+  /* Handle just the top child in a vertical split.  */
+  if (!NILP (w->vchild))
+    set_tab_bar_lines_1 (w->vchild, n);
+
+  /* Adjust all children in a horizontal split.  */
+  for (window = w->hchild; !NILP (window); window = w->next)
+    {
+      w = XWINDOW (window);
+      set_tab_bar_lines_1 (window, n);
+    }
+}
+
+static void
+set_tab_bar_lines (struct frame *f, Lisp_Object value)
+{
+    int nlines, olines, maxlines;
+    Lisp_Object frame, tab, dummy;
+
+    if (FRAME_MINIBUF_ONLY_P (f))
+	return;
+
+    XSETFRAME(frame, f);
+
+    if (INTEGERP (value))
+	nlines = XINT (value);
+    else
+	nlines = 0;
+
+    maxlines = FRAME_LINES (f) - 3 - /* editline + modeline + minibuf line = 3 */
+	FRAME_MENU_BAR_LINES (f) -
+	FRAME_TOOL_BAR_LINES (f);
+
+    (nlines > maxlines) && (nlines = maxlines);
+
+    struct frame *this;
+    this = XFRAME(frame);
+    olines = FRAME_TAB_BAR_LINES (this);
+    if (nlines != olines)
+    {
+	if (EQ (frame, selected_frame))
+            /* redisplay is required only when one changes the
+               selected tab */
+            windows_or_buffers_changed++;
+	FRAME_WINDOW_SIZES_CHANGED (this) = 1;
+	FRAME_TAB_BAR_LINES (this) = nlines;
+	set_tab_bar_lines_1 (this->root_window, nlines - olines);
+	adjust_glyphs (this);
+    }
+
+}
+
+void
+activate_tab (struct frame *f, int tab_index)
+{
+    Lisp_Object activatecode, tab;
+
+    FRAME_CURRENT_TAB (f) = tab_index;
+
+    tab = XCDR (AREF ( f->tab_bar_items, f->current_tab ) ) ;
+    
+    activatecode = Fassq (Qtab_activate, tab);
+    
+    if (! EQ (Qnil, activatecode))
+    {
+	activatecode = XCDR (activatecode);
+	return (void) Ffuncall (1, &activatecode);
+    }
+
+}
+
+void
+deactivate_tab (struct frame *f)
+{
+    Lisp_Object deactivatecode, tab;
+
+    tab = XCDR (AREF ( f->tab_bar_items, f->current_tab ) ) ;
+    
+    deactivatecode = Fassq (Qtab_deactivate, tab);
+    
+    if (! EQ (Qnil, deactivatecode))
+    {
+	deactivatecode = XCDR (deactivatecode);
+	return (void) Ffuncall (1, &deactivatecode);
+    }
+
+}
+
+void
+set_current_tab (struct frame *f, Lisp_Object value)
+{
+    int otab, tab;
+
+    if (FRAME_MINIBUF_ONLY_P (f))
+	return;
+
+    Lisp_Object frame;
+    XSETFRAME(frame, f);
+
+    if (INTEGERP (value))
+	tab = XINT (value);
+    else
+	return (void) deactivate_tab (f);
+
+    otab = FRAME_CURRENT_TAB (f);
+
+    /* no tag is active */
+    if (ASIZE (FRAME_TAB_BAR_ITEMS (f)) <= tab)
+	return (void) deactivate_tab (f);
+    
+    if (tab != otab)
+    {
+	if (EQ (frame, selected_frame))
+            /* redisplay is required only when one changes the
+               selected tab */
+            windows_or_buffers_changed++;
+	FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+	deactivate_tab (f);
+	activate_tab (f, tab);
+	adjust_glyphs (f);
+    }
+
+}
+
+
 \f
 Lisp_Object Vframe_list;
 
@@ -348,6 +491,10 @@ make_frame (int mini_p)
   f->font_driver_list = NULL;
   f->font_data_list = NULL;
 
+  f->tab_bar_items = Qnil;
+  f->current_tab = 0;
+  f->last_tab = 0;
+
   root_window = make_window ();
   if (mini_p)
     {
@@ -570,7 +717,6 @@ make_initial_frame (void)
   return f;
 }
 
-
 struct frame *
 make_terminal_frame (struct terminal *terminal)
 {
@@ -650,6 +796,44 @@ get_future_frame_param (Lisp_Object parameter,
   return result;
 }
 
+Lisp_Object
+add_tab (Lisp_Object parms)
+{
+  Lisp_Object tab, initcode, activatecode, deactivatecode;
+
+  Lisp_Object tab_object[4];
+
+
+  struct frame *sf = SELECTED_FRAME ();
+  if (sf->last_tab == 1000)
+    return;
+  char tab_name[]=" tab";
+
+  if (NILP (sf->tab_bar_items))
+    sf->tab_bar_items = Fmake_vector (make_number (1000), Qnil);
+
+  activatecode = Fassq (Qtab_activate, parms);
+  deactivatecode = Fassq (Qtab_deactivate, parms);
+
+  //tab = Fcons (make_string (tab_name, sizeof (tab_name)-1), Qnil);
+  tab_object[0] = make_string (tab_name, sizeof (tab_name)-1);
+  tab_object[1] = activatecode;
+  tab_object[2] = deactivatecode;
+  tab = Flist ( 3, tab_object );
+
+  ASET (sf->tab_bar_items, sf->last_tab++, tab);
+
+  initcode = Fassq (Qtab_init, parms);
+
+  if (! EQ (Qnil, initcode))
+    {
+      initcode = XCDR (initcode);
+      return Ffuncall (1, &initcode);
+    }
+
+  return Qnil;
+}
+
 DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame,
        1, 1, 0,
        doc: /* Create an additional terminal frame, possibly on another terminal.
@@ -674,10 +858,17 @@ affects all frames on the same terminal device.  */)
   Lisp_Object frame, tem;
   struct frame *sf = SELECTED_FRAME ();
 
+  Lisp_Object tab;
+
+  tab = Fassq (Qtab, parms);
+  if (! EQ (Qnil, tab))
+      return add_tab (parms);
+
+
 #ifdef MSDOS
   if (sf->output_method != output_msdos_raw
       && sf->output_method != output_termcap)
-    abort ();
+      abort ();
 #else /* not MSDOS */
 
 #ifdef WINDOWSNT                           /* This should work now! */
@@ -2286,9 +2477,13 @@ store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
   if (! FRAME_WINDOW_P (f))
     {
       if (EQ (prop, Qmenu_bar_lines))
-	set_menu_bar_lines (f, val, make_number (FRAME_MENU_BAR_LINES (f)));
+	  set_menu_bar_lines (f, val, make_number (FRAME_MENU_BAR_LINES (f)));
+      else if (EQ (prop, Qtab_bar_lines))
+	  set_tab_bar_lines (f, val);
       else if (EQ (prop, Qname))
 	set_term_frame_name (f, val);
+      else if (EQ (prop, Qcurrent_tab))
+      	set_current_tab (f, val);
     }
 
   if (EQ (prop, Qminibuffer) && WINDOWP (val))
@@ -2394,11 +2589,14 @@ If FRAME is omitted, return information on the currently selected frame.  */)
 #endif
     {
       /* This ought to be correct in f->param_alist for an X frame.  */
-      Lisp_Object lines;
+	Lisp_Object lines, items;
       XSETFASTINT (lines, FRAME_MENU_BAR_LINES (f));
       store_in_alist (&alist, Qmenu_bar_lines, lines);
+      XSETFASTINT (lines, FRAME_TAB_BAR_LINES (f));
+      store_in_alist (&alist, Qtab_bar_lines, lines);
+      XSETFASTINT (lines, FRAME_CURRENT_TAB (f));
+      store_in_alist (&alist, Qcurrent_tab, lines);
     }
-
   UNGCPRO;
   return alist;
 }
@@ -2822,6 +3020,8 @@ static const struct frame_parm_table frame_parms[] =
   {"icon-type",			&Qicon_type},
   {"internal-border-width",	&Qinternal_border_width},
   {"menu-bar-lines",		&Qmenu_bar_lines},
+  {"tab-bar-lines",		&Qtab_bar_lines},
+  {"current-tab",		&Qcurrent_tab},
   {"mouse-color",		&Qmouse_color},
   {"name",			&Qname},
   {"scroll-bar-width",		&Qscroll_bar_width},
@@ -4443,6 +4643,16 @@ syms_of_frame (void)
   Qterminal_live_p = intern_c_string ("terminal-live-p");
   staticpro (&Qterminal_live_p);
 
+  Qtab = intern_c_string ("tab");
+  staticpro (&Qtab);
+
+  Qtab_activate = intern_c_string ("tab:activate");
+  staticpro (&Qtab_activate);
+  Qtab_deactivate = intern_c_string ("tab:deactivate");
+  staticpro (&Qtab_deactivate);
+  Qtab_init = intern_c_string ("tab:init");
+  staticpro (&Qtab_init);
+
 #ifdef HAVE_NS
   Qns_parse_geometry = intern_c_string ("ns-parse-geometry");
   staticpro (&Qns_parse_geometry);
diff --git a/src/frame.h b/src/frame.h
index 31f6017..b9084a2 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -171,6 +171,12 @@ struct frame
      Only the X toolkit version uses this.  */
   Lisp_Object menu_bar_vector;
 
+    /*
+     * a list with conses of the form ("string_tab_name" . (alist_tab_parameters))
+     */
+    Lisp_Object tab_bar_items;
+
+
   /* Predicate for selecting buffers for other-buffer.  */
   Lisp_Object buffer_predicate;
 
@@ -203,6 +209,13 @@ struct frame
   /* Cache of realized faces.  */
   struct face_cache *face_cache;
 
+    /*
+      the index of the last activated tab.
+     */
+    int current_tab;
+
+    int last_tab;
+
   /* Number of elements in `menu_bar_vector' that have meaningful data.  */
   EMACS_INT menu_bar_items_used;
 
@@ -360,6 +373,8 @@ struct frame
   /* Number of lines of menu bar.  */
   int menu_bar_lines;
 
+    int tab_bar_lines;
+
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
     || defined (HAVE_NS) || defined (USE_GTK)
   /* Nonzero means using a menu bar that comes from the X toolkit.  */
@@ -590,6 +605,11 @@ typedef struct frame *FRAME_PTR;
    These lines are counted in FRAME_LINES.  */
 #define FRAME_MENU_BAR_LINES(f) (f)->menu_bar_lines
 
+#define FRAME_CURRENT_TAB(f) f -> current_tab
+#define FRAME_TAB_BAR_ITEMS(f) f -> tab_bar_items
+#define FRAME_TAB_BAR_LINES(f) f -> tab_bar_lines
+
+
 /* Nonzero if this frame should display a tool bar
    in a way that does not use any text lines.  */
 #if defined (USE_GTK) || defined (HAVE_NS)
@@ -606,7 +626,7 @@ typedef struct frame *FRAME_PTR;
 /* Lines above the top-most window in frame F.  */
 
 #define FRAME_TOP_MARGIN(F) \
-     (FRAME_MENU_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F))
+     (FRAME_MENU_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F) + FRAME_TAB_BAR_LINES(F))
 
 /* Pixel height of the top margin above.  */
 
@@ -835,10 +855,9 @@ typedef struct frame *FRAME_PTR;
 #define FOR_EACH_FRAME(list_var, frame_var)			\
   for ((list_var) = Vframe_list;				\
        (CONSP (list_var)					\
-	&& (frame_var = XCAR (list_var), 1));		\
+	&& (frame_var = XCAR (list_var), 1));			\
        list_var = XCDR (list_var))
 
-
 extern Lisp_Object Qframep, Qframe_live_p;
 extern Lisp_Object Qtty, Qtty_type;
 extern Lisp_Object Qtty_color_mode;
diff --git a/src/window.c b/src/window.c
index a2a0c79..7096488 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5832,6 +5832,7 @@ struct save_window_data
 
     int frame_cols, frame_lines, frame_menu_bar_lines;
     int frame_tool_bar_lines;
+    int frame_tab_bar_lines;
   };
 
 /* This is saved as a Lisp_Vector  */
@@ -5963,6 +5964,7 @@ the return value is nil.  Otherwise the value is t.  */)
       int previous_frame_cols =  FRAME_COLS  (f);
       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
       int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+      int previous_frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f);
 
       /* The mouse highlighting code could get screwed up
 	 if it runs during this.  */
@@ -6414,6 +6416,7 @@ redirection (see `redirect-frame-focus').  */)
   data->frame_lines = FRAME_LINES (f);
   data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
   data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+  data->frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f);
   data->selected_frame = selected_frame;
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSETBUFFER (data->current_buffer, current_buffer);
@@ -6910,6 +6913,8 @@ compare_window_configurations (Lisp_Object c1, Lisp_Object c2, int ignore_positi
     return 0;
   if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
     return 0;
+  if (d1->frame_tab_bar_lines != d2->frame_tab_bar_lines)
+    return 0;
   if (! EQ (d1->selected_frame, d2->selected_frame))
     return 0;
   /* Don't compare the current_window field directly.
diff --git a/src/xdisp.c b/src/xdisp.c
index 77e9db2..1865eb0 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -1059,6 +1059,8 @@ static int store_mode_line_string (const char *, Lisp_Object, int, int, int, Lis
 static const char *decode_mode_spec (struct window *, int, int, int,
 				     Lisp_Object *);
 static void display_menu_bar (struct window *);
+static void display_tab_bar (struct window *w);
+
 static int display_count_lines (EMACS_INT, EMACS_INT, EMACS_INT, int,
 				EMACS_INT *);
 static int display_string (const unsigned char *, Lisp_Object, Lisp_Object,
@@ -14575,6 +14577,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       && EQ (FRAME_SELECTED_WINDOW (f), window))
     {
       int redisplay_menu_p = 0;
+      int redisplay_tab_p = 0;
       int redisplay_tool_bar_p = 0;
 
       if (FRAME_WINDOW_P (f))
@@ -14589,9 +14592,14 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       else
         redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
 
+      redisplay_tab_p = FRAME_TAB_BAR_LINES (f) > 0;
+
       if (redisplay_menu_p)
         display_menu_bar (w);
 
+      if (redisplay_tab_p)
+	  display_tab_bar (w);
+
 #ifdef HAVE_WINDOW_SYSTEM
       if (FRAME_WINDOW_P (f))
         {
@@ -18176,6 +18184,74 @@ See also `bidi-paragraph-direction'.  */)
     }
 }
 
+void
+display_tab_bar (struct window *w)
+{
+    const int tab_length = 10;
+
+    struct frame *fr = XFRAME (WINDOW_FRAME (w));
+
+    struct it it;
+    int index;
+    init_iterator (&it, w, -1, -1,
+		   fr->desired_matrix->rows + FRAME_MENU_BAR_LINES (fr),
+		   DEFAULT_FACE_ID);
+    it.first_visible_x = 0;
+    it.last_visible_x = FRAME_COLS (fr);
+
+  /* Clear all rows of the menu bar.  */
+  for (index = 0;
+       index < FRAME_TAB_BAR_LINES (fr);
+       ++index)
+    {
+      struct glyph_row *row = it.glyph_row + index;
+      clear_glyph_row (row);
+      row->enabled_p = 1;
+      row->full_width_p = 1;
+    }
+
+  int ii=0, oddrow=0, oddcol=0;
+  Lisp_Object tab, s;
+  while (!NILP (tab = AREF (fr->tab_bar_items, ii))) 
+  {
+      if (it. hpos + tab_length > FRAME_COLS (fr))
+      {
+	  /* Fill out the line with spaces.  */
+	  it.base_face_id = DEFAULT_FACE_ID;
+	  while (it.current_x < it.last_visible_x)
+	      display_string (" ", Qnil, Qnil, 0, 0,  &it, 1, 0, 0, -1);
+
+  	  if (unix == (it.current_y + 1))
+	      oddcol = ii % 2;
+
+	  oddrow = (oddcol)? (ii%2) : !oddrow;
+
+      	  it.hpos = it.current_x = 0;
+	  it.current_y ++;
+      	  ++it.vpos;
+      	  it.glyph_row++;
+	  if (it.current_y > FRAME_TAB_BAR_LINES (fr))
+      	      break;
+      }
+
+      it.base_face_id = (ii == FRAME_CURRENT_TAB (fr)) ? CURRENT_TAB_FACE_ID :
+      	   oddrow ? ODD_TAB_FACE_ID :
+      	  EVEN_TAB_FACE_ID;
+      
+      int len = SCHARS (XCAR(tab)) > tab_length ? tab_length: SCHARS (XCAR (tab));
+      s = Fsubstring (XCAR (tab), make_number(0), make_number (len));
+      display_string (NULL, s, Qnil, 0, 0, &it, tab_length, 0, 0, -1);
+
+      oddrow = ! oddrow;
+      ii++;
+  }
+
+  
+  /* Compute the total height of the lines.  */
+  compute_line_metrics (&it);
+
+}
+
 
 \f
 /***********************************************************************
diff --git a/src/xfaces.c b/src/xfaces.c
index 5c7cfe6..3e14a64 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -348,6 +348,7 @@ Lisp_Object Qframe_set_background_mode;
 Lisp_Object Qdefault, Qtool_bar, Qregion, Qfringe;
 Lisp_Object Qheader_line, Qscroll_bar, Qcursor, Qborder, Qmouse, Qmenu;
 Lisp_Object Qmode_line_inactive, Qvertical_border;
+Lisp_Object Qodd_tab_face, Qeven_tab_face, Qcurrent_tab_face;
 
 /* The symbol `face-alias'.  A symbols having that property is an
    alias for another face.  Value of the property is the name of
@@ -5389,6 +5390,9 @@ realize_basic_faces (struct frame *f)
       realize_named_face (f, Qmouse, MOUSE_FACE_ID);
       realize_named_face (f, Qmenu, MENU_FACE_ID);
       realize_named_face (f, Qvertical_border, VERTICAL_BORDER_FACE_ID);
+      realize_named_face (f, Qcurrent_tab_face, CURRENT_TAB_FACE_ID);
+      realize_named_face (f, Qodd_tab_face, ODD_TAB_FACE_ID);
+      realize_named_face (f, Qeven_tab_face, EVEN_TAB_FACE_ID);
 
       /* Reflect changes in the `menu' face in menu bars.  */
       if (FRAME_FACE_CACHE (f)->menu_face_changed_p)
@@ -6659,6 +6663,12 @@ syms_of_xfaces (void)
   staticpro (&Qmode_line_inactive);
   Qvertical_border = intern_c_string ("vertical-border");
   staticpro (&Qvertical_border);
+  Qcurrent_tab_face = intern ("current-tab-face");
+  staticpro (&Qcurrent_tab_face);
+  Qodd_tab_face = intern ("odd-tab-face");
+  staticpro (&Qodd_tab_face);
+  Qeven_tab_face = intern ("even-tab-face");
+  staticpro (&Qeven_tab_face);
   Qtty_color_desc = intern_c_string ("tty-color-desc");
   staticpro (&Qtty_color_desc);
   Qtty_color_standard_values = intern_c_string ("tty-color-standard-values");
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-02 22:45               ` Alin Soare
@ 2010-12-03  8:19                 ` martin rudalics
  2010-12-03  9:37                 ` Andreas Schwab
  2010-12-03  9:52                 ` Andreas Schwab
  2 siblings, 0 replies; 34+ messages in thread
From: martin rudalics @ 2010-12-03  8:19 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

FWIW the code for set_menu_bar_lines has a bug which allows it to
virtually remove a one line high window at the top of a frame.  I never
investigated the consequences of this but would strongly advise you to
not do the same in set_tab_bar_lines.

martin



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-02 22:45               ` Alin Soare
  2010-12-03  8:19                 ` martin rudalics
@ 2010-12-03  9:37                 ` Andreas Schwab
  2010-12-04 21:48                   ` Alin Soare
  2010-12-03  9:52                 ` Andreas Schwab
  2 siblings, 1 reply; 34+ messages in thread
From: Andreas Schwab @ 2010-12-03  9:37 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

Alin Soare <as1789@gmail.com> writes:

> From 3ecdbb0c879ebcf6d011211d14d89392993fd503 Mon Sep 17 00:00:00 2001
> From: root <root@alin.(none)>

Never work as root.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-02 22:45               ` Alin Soare
  2010-12-03  8:19                 ` martin rudalics
  2010-12-03  9:37                 ` Andreas Schwab
@ 2010-12-03  9:52                 ` Andreas Schwab
  2010-12-03 11:11                   ` Alin Soare
  2 siblings, 1 reply; 34+ messages in thread
From: Andreas Schwab @ 2010-12-03  9:52 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

frame.c: In function ‘set_tab_bar_lines’:
frame.c:251: warning: value computed is not used
frame.c:253: warning: ISO C90 forbids mixed declarations and code
frame.c:235: warning: unused variable ‘dummy’
frame.c:235: warning: unused variable ‘tab’
frame.c: In function ‘set_current_tab’:
frame.c:314: warning: ISO C90 forbids mixed declarations and code
frame.c: In function ‘add_tab’:
frame.c:809: warning: ‘return’ with no value, in function returning non-void
frame.c:810: warning: ISO C90 forbids mixed declarations and code
frame.c: In function ‘Fframe_parameters’:
frame.c:2592: warning: unused variable ‘items’

xdisp.c: In function ‘display_tab_bar’:
xdisp.c:18213: warning: ISO C90 forbids mixed declarations and code
xdisp.c:18241: warning: ISO C90 forbids mixed declarations and code

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-03  9:52                 ` Andreas Schwab
@ 2010-12-03 11:11                   ` Alin Soare
  2010-12-03 12:29                     ` Dimitri Fontaine
  0 siblings, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-03 11:11 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 1271 bytes --]

2010/12/3 Andreas Schwab <schwab@linux-m68k.org>

> frame.c: In function ‘set_tab_bar_lines’:
> frame.c:251: warning: value computed is not used
> frame.c:253: warning: ISO C90 forbids mixed declarations and code
> frame.c:235: warning: unused variable ‘dummy’
> frame.c:235: warning: unused variable ‘tab’
> frame.c: In function ‘set_current_tab’:
> frame.c:314: warning: ISO C90 forbids mixed declarations and code
> frame.c: In function ‘add_tab’:
> frame.c:809: warning: ‘return’ with no value, in function returning
> non-void
> frame.c:810: warning: ISO C90 forbids mixed declarations and code
> frame.c: In function ‘Fframe_parameters’:
> frame.c:2592: warning: unused variable ‘items’
>
> xdisp.c: In function ‘display_tab_bar’:
> xdisp.c:18213: warning: ISO C90 forbids mixed declarations and code
> xdisp.c:18241: warning: ISO C90 forbids mixed declarations and code
>
>
I compiled using

CFLAGS="-g -O0 -Wdeclaration-after-statement -Wno-pointer-sign
-fno-crossjumping -g3 -gdwarf-2" ./configure --without-x

and I ommited -Wall...

I send another version soon.

Please come with ideas about extending the frames, such that to be able to
write scripts to create tabs that play with frames...

[-- Attachment #2: Type: text/html, Size: 1665 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-03 11:11                   ` Alin Soare
@ 2010-12-03 12:29                     ` Dimitri Fontaine
  2010-12-04 21:42                       ` Alin Soare
  2010-12-04 21:55                       ` Alin Soare
  0 siblings, 2 replies; 34+ messages in thread
From: Dimitri Fontaine @ 2010-12-03 12:29 UTC (permalink / raw)
  To: Alin Soare; +Cc: Andreas Schwab, Emacs Dev

Alin Soare <as1789@gmail.com> writes:
> Please come with ideas about extending the frames, such that to be able to
> write scripts to create tabs that play with frames...

What do you think about solutions such as escreen, elscreen or
workgroups?

  http://www.splode.com/~friedman/software/emacs-lisp/src/escreen.el
  http://www.morishima.net/~naoto/software/elscreen/index.php.en
  https://github.com/tlh/workgroups.el

Regards,
-- 
dim



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-03 12:29                     ` Dimitri Fontaine
@ 2010-12-04 21:42                       ` Alin Soare
  2010-12-04 21:55                       ` Alin Soare
  1 sibling, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-04 21:42 UTC (permalink / raw)
  To: Emacs Dev


[-- Attachment #1.1: Type: text/plain, Size: 400 bytes --]

This is a version in which I added an environment for every tab. For now,
there is no reason to make the environment an obarray, but this will be
required if others want to write scripts that give other definitions for a
tab, but for window configurations. For me, it is enough to know that only
the tab:init function changes that environment, and I find the winconfig
variable on the cadr position.

[-- Attachment #1.2: Type: text/html, Size: 423 bytes --]

[-- Attachment #2: 0001-tabs-for-console-tabs-as-window-configuration.patch --]
[-- Type: text/x-patch, Size: 19720 bytes --]

From e369ad3fc8c95e81e0d84758896297cf970b324a Mon Sep 17 00:00:00 2001
From: root <root@alin.(none)>
Date: Thu, 2 Dec 2010 23:53:41 +0200
Subject: [PATCH] tabs for console - tabs as window configuration

---
 src/dispextern.h |    3 +
 src/frame.c      |  240 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/frame.h      |   31 ++++++-
 src/window.c     |    5 +
 src/xdisp.c      |   79 ++++++++++++++++++
 src/xfaces.c     |   10 ++
 6 files changed, 359 insertions(+), 9 deletions(-)

diff --git a/src/dispextern.h b/src/dispextern.h
index 7426c03..2a87044 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1697,6 +1697,9 @@ enum face_id
   MOUSE_FACE_ID,
   MENU_FACE_ID,
   VERTICAL_BORDER_FACE_ID,
+  CURRENT_TAB_FACE_ID,
+  ODD_TAB_FACE_ID,
+  EVEN_TAB_FACE_ID,
   BASIC_FACE_ID_SENTINEL
 };
 
diff --git a/src/frame.c b/src/frame.c
index ba675be..b90bff3 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -118,16 +118,20 @@ Lisp_Object Qwindow_id;
 Lisp_Object Qouter_window_id;
 #endif
 Lisp_Object Qparent_id;
-Lisp_Object Qtitle, Qname;
+Lisp_Object Qtitle, Qname, Qtab_name, Qtab, Qcurrent_tab;
+Lisp_Object Qtab_env;
+Lisp_Object Qtab_list;
 Lisp_Object Qexplicit_name;
 Lisp_Object Qunsplittable;
-Lisp_Object Qmenu_bar_lines, Qtool_bar_lines, Qtool_bar_position;
+Lisp_Object Qmenu_bar_lines, Qtool_bar_lines, Qtool_bar_position, Qtab_bar_lines;
 Lisp_Object Vmenu_bar_mode, Vtool_bar_mode;
 Lisp_Object Qleft_fringe, Qright_fringe;
 Lisp_Object Qbuffer_predicate, Qbuffer_list, Qburied_buffer_list;
 Lisp_Object Qtty_color_mode;
 Lisp_Object Qtty, Qtty_type;
 
+Lisp_Object Qtab_activate, Qtab_deactivate, Qtab_init;
+
 Lisp_Object Qfullscreen, Qfullwidth, Qfullheight, Qfullboth, Qmaximized;
 Lisp_Object Qsticky;
 Lisp_Object Qfont_backend;
@@ -197,6 +201,149 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
       adjust_glyphs (f);
     }
 }
+
+/* this is identical to set_menu_bar_lines_1 */
+static void
+set_tab_bar_lines_1 ( Lisp_Object window, int n)
+{
+  struct window *w = XWINDOW (window);
+
+  XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
+  XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
+
+  if (INTEGERP (w->orig_top_line))
+    XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
+  if (INTEGERP (w->orig_total_lines))
+    XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
+
+  /* Handle just the top child in a vertical split.  */
+  if (!NILP (w->vchild))
+    set_tab_bar_lines_1 (w->vchild, n);
+
+  /* Adjust all children in a horizontal split.  */
+  for (window = w->hchild; !NILP (window); window = w->next)
+    {
+      w = XWINDOW (window);
+      set_tab_bar_lines_1 (window, n);
+    }
+}
+
+static void
+set_tab_bar_lines (struct frame *f, Lisp_Object value)
+{
+    int nlines, olines, maxlines;
+    Lisp_Object frame;
+
+    if (FRAME_MINIBUF_ONLY_P (f))
+	return;
+
+    XSETFRAME(frame, f);
+
+    if (INTEGERP (value))
+	nlines = XINT (value);
+    else
+	nlines = 0;
+
+    struct frame *this;
+    this = XFRAME(frame);
+    olines = FRAME_TAB_BAR_LINES (this);
+    if (nlines != olines)
+    {
+	if (EQ (frame, selected_frame))
+            /* redisplay is required only when one changes the
+               selected tab */
+            windows_or_buffers_changed++;
+	FRAME_WINDOW_SIZES_CHANGED (this) = 1;
+	FRAME_TAB_BAR_LINES (this) = nlines;
+	set_tab_bar_lines_1 (this->root_window, nlines - olines);
+	adjust_glyphs (this);
+    }
+
+}
+
+void
+activate_tab (struct frame *f, int tab_index)
+{
+    Lisp_Object activatecode, tab;
+    FRAME_CURRENT_TAB (f) = XINT (tab_index);
+    tab = Fnth ( tab_index, f -> tab_bar_items ) ;
+    activatecode = Fassq (Qtab_activate, tab);
+    if (! EQ (Qnil, activatecode))
+    {
+	activatecode = XCDR (activatecode);
+	return (void) Ffuncall (1, &activatecode);
+    }
+}
+
+void
+deactivate_tab (struct frame *f)
+{
+    return;
+    Lisp_Object deactivatecode, tab;
+    tab = AREF ( f->tab_bar_items, f->current_tab ) ;
+    deactivatecode = Fassq (Qtab_deactivate, tab);
+    if (! EQ (Qnil, deactivatecode))
+    {
+	deactivatecode = XCDR (deactivatecode);
+	return (void) Ffuncall (1, &deactivatecode);
+    }
+}
+
+void
+set_current_tab (struct frame *f, Lisp_Object value)
+{
+    int otab, tab;
+
+    if (FRAME_MINIBUF_ONLY_P (f))
+	return;
+
+    Lisp_Object frame;
+    XSETFRAME(frame, f);
+
+    if (INTEGERP (value))
+	tab = XINT (value);
+    else
+	return (void) deactivate_tab (f);
+
+    otab = FRAME_CURRENT_TAB (f);
+
+    /* no tag is active */
+    if (Flength (FRAME_TAB_BAR_ITEMS (f)) <= value)
+	return (void) deactivate_tab (f);
+    
+    if (tab != otab)
+    {
+	if (EQ (frame, selected_frame))
+            /* redisplay is required only when one changes the
+               selected tab */
+            windows_or_buffers_changed++;
+	FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+	deactivate_tab (f);
+	activate_tab (f, value);
+	adjust_glyphs (f);
+    }
+
+}
+
+void
+add_tab_environment (struct frame *f,
+		     Lisp_Object prop)
+{
+    Lisp_Object env, l;
+    l = Fnth (make_number (f->current_tab), f->tab_bar_items);
+    if (NILP(prop))
+	return;
+    return;
+    env = Fcons (prop,
+		 XCDR (Fassq (Qtab_env,
+			      XCDR ( AREF (f->tab_bar_items, f->current_tab)))));
+//    env = Fcons (Qtab_env, Fcons ( prop, XCDR (env) ) );
+    store_in_alist (&l, Qtab_env, env);
+    
+}
+
+
 \f
 Lisp_Object Vframe_list;
 
@@ -348,6 +495,10 @@ make_frame (int mini_p)
   f->font_driver_list = NULL;
   f->font_data_list = NULL;
 
+  f->tab_bar_items = Qnil;
+  f->current_tab = 0;
+  f->last_tab = 0;
+
   root_window = make_window ();
   if (mini_p)
     {
@@ -570,7 +721,6 @@ make_initial_frame (void)
   return f;
 }
 
-
 struct frame *
 make_terminal_frame (struct terminal *terminal)
 {
@@ -650,6 +800,44 @@ get_future_frame_param (Lisp_Object parameter,
   return result;
 }
 
+Lisp_Object
+add_tab (Lisp_Object parms)
+{
+    Lisp_Object tab_name, initcode, activatecode, deactivatecode, tab, env, name;
+    
+    Lisp_Object tab_object[4];
+
+  struct frame *sf = SELECTED_FRAME ();
+  if (sf->last_tab == 1000)
+    return Qnil;
+
+  activatecode = Fassq (Qtab_activate, parms);
+  deactivatecode = Fassq (Qtab_deactivate, parms);
+  env = Fassq (Qtab_env, parms);
+  name = Fassq (Qtab_name, parms);
+  
+  name = NILP (name) ? make_string (" tab", 4) : XCDR (name);
+
+  tab_name = Fcons (Qtab_name, name);
+  tab_object[0] = NILP (tab_name) ? Qnil:Fcons (tab_name, Qnil);
+  tab_object[1] = NILP (activatecode) ? Qnil: Fcons (activatecode, Qnil);
+  tab_object[2] = NILP (deactivatecode) ? Qnil:Fcons (deactivatecode, Qnil);
+  tab_object[3] = NILP (env) ? Qnil:Fcons (env, Qnil);
+  tab = Fappend ( 4, tab_object );
+
+  /* ASET (sf->tab_bar_items, sf->last_tab++, tab); */
+  Lisp_Object new[2];
+  new[0] = sf->tab_bar_items;
+  new[1] = Fcons (tab, Qnil);
+
+  sf->tab_bar_items = Fappend ( 2,  new);
+
+  initcode = Fassq (Qtab_init, parms);
+
+  /* sf->last_tab++; */
+  return make_number (sf->last_tab++);
+}
+
 DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame,
        1, 1, 0,
        doc: /* Create an additional terminal frame, possibly on another terminal.
@@ -674,6 +862,13 @@ affects all frames on the same terminal device.  */)
   Lisp_Object frame, tem;
   struct frame *sf = SELECTED_FRAME ();
 
+  Lisp_Object tab;
+
+  tab = Fassq (Qtab, parms);
+  if (! EQ (Qnil, tab))
+      return add_tab (parms);
+
+
 #ifdef MSDOS
   if (sf->output_method != output_msdos_raw
       && sf->output_method != output_termcap)
@@ -2286,9 +2481,15 @@ store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
   if (! FRAME_WINDOW_P (f))
     {
       if (EQ (prop, Qmenu_bar_lines))
-	set_menu_bar_lines (f, val, make_number (FRAME_MENU_BAR_LINES (f)));
+	  set_menu_bar_lines (f, val, make_number (FRAME_MENU_BAR_LINES (f)));
+      else if (EQ (prop, Qtab_bar_lines))
+	  set_tab_bar_lines (f, val);
       else if (EQ (prop, Qname))
 	set_term_frame_name (f, val);
+      else if (EQ (prop, Qcurrent_tab))
+      	set_current_tab (f, val);
+      else if (EQ (prop, Qtab_env))
+      	add_tab_environment (f, val);
     }
 
   if (EQ (prop, Qminibuffer) && WINDOWP (val))
@@ -2394,11 +2595,19 @@ If FRAME is omitted, return information on the currently selected frame.  */)
 #endif
     {
       /* This ought to be correct in f->param_alist for an X frame.  */
-      Lisp_Object lines;
+	Lisp_Object lines, tabenv;
       XSETFASTINT (lines, FRAME_MENU_BAR_LINES (f));
       store_in_alist (&alist, Qmenu_bar_lines, lines);
+      XSETFASTINT (lines, FRAME_TAB_BAR_LINES (f));
+      store_in_alist (&alist, Qtab_bar_lines, lines);
+      XSETFASTINT (lines, FRAME_CURRENT_TAB (f));
+      store_in_alist (&alist, Qcurrent_tab, lines);
+      tabenv= Fcdr ( Fassq (Qtab_env,
+			    Fnth (make_number (f->current_tab), f->tab_bar_items)));
+      store_in_alist (&alist, Qtab_env, tabenv);
+      /* provide an informal reference to tabs. */
+      store_in_alist (&alist, Qtab_list, f->tab_bar_items);
     }
-
   UNGCPRO;
   return alist;
 }
@@ -2822,6 +3031,9 @@ static const struct frame_parm_table frame_parms[] =
   {"icon-type",			&Qicon_type},
   {"internal-border-width",	&Qinternal_border_width},
   {"menu-bar-lines",		&Qmenu_bar_lines},
+  {"tab-bar-lines",		&Qtab_bar_lines},
+  {"current-tab",		&Qcurrent_tab},
+  {"tab-list",                  &Qtab_list},
   {"mouse-color",		&Qmouse_color},
   {"name",			&Qname},
   {"scroll-bar-width",		&Qscroll_bar_width},
@@ -4443,6 +4655,22 @@ syms_of_frame (void)
   Qterminal_live_p = intern_c_string ("terminal-live-p");
   staticpro (&Qterminal_live_p);
 
+  Qtab = intern_c_string ("tab");
+  staticpro (&Qtab);
+
+  Qtab_env = intern_c_string ("tab:env");
+  staticpro (&Qtab_env);
+
+  Qtab_name = intern_c_string ("tab:name");
+  staticpro (&Qtab_name);
+
+  Qtab_activate = intern_c_string ("tab:activate");
+  staticpro (&Qtab_activate);
+  Qtab_deactivate = intern_c_string ("tab:deactivate");
+  staticpro (&Qtab_deactivate);
+  Qtab_init = intern_c_string ("tab:init");
+  staticpro (&Qtab_init);
+
 #ifdef HAVE_NS
   Qns_parse_geometry = intern_c_string ("ns-parse-geometry");
   staticpro (&Qns_parse_geometry);
diff --git a/src/frame.h b/src/frame.h
index 31f6017..3110fd4 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -171,6 +171,12 @@ struct frame
      Only the X toolkit version uses this.  */
   Lisp_Object menu_bar_vector;
 
+    /*
+     * a list with conses of the form ("string_tab_name" . (alist_tab_parameters))
+     */
+    Lisp_Object tab_bar_items;
+
+
   /* Predicate for selecting buffers for other-buffer.  */
   Lisp_Object buffer_predicate;
 
@@ -203,6 +209,13 @@ struct frame
   /* Cache of realized faces.  */
   struct face_cache *face_cache;
 
+    /*
+      the index of the last activated tab.
+     */
+    int current_tab;
+
+    int last_tab;
+
   /* Number of elements in `menu_bar_vector' that have meaningful data.  */
   EMACS_INT menu_bar_items_used;
 
@@ -360,6 +373,8 @@ struct frame
   /* Number of lines of menu bar.  */
   int menu_bar_lines;
 
+    int tab_bar_lines;
+
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
     || defined (HAVE_NS) || defined (USE_GTK)
   /* Nonzero means using a menu bar that comes from the X toolkit.  */
@@ -590,6 +605,11 @@ typedef struct frame *FRAME_PTR;
    These lines are counted in FRAME_LINES.  */
 #define FRAME_MENU_BAR_LINES(f) (f)->menu_bar_lines
 
+#define FRAME_CURRENT_TAB(f) f -> current_tab
+#define FRAME_TAB_BAR_ITEMS(f) f -> tab_bar_items
+#define FRAME_TAB_BAR_LINES(f) f -> tab_bar_lines
+
+
 /* Nonzero if this frame should display a tool bar
    in a way that does not use any text lines.  */
 #if defined (USE_GTK) || defined (HAVE_NS)
@@ -606,7 +626,7 @@ typedef struct frame *FRAME_PTR;
 /* Lines above the top-most window in frame F.  */
 
 #define FRAME_TOP_MARGIN(F) \
-     (FRAME_MENU_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F))
+     (FRAME_MENU_BAR_LINES (F) + FRAME_TOOL_BAR_LINES (F) + FRAME_TAB_BAR_LINES(F))
 
 /* Pixel height of the top margin above.  */
 
@@ -832,13 +852,18 @@ typedef struct frame *FRAME_PTR;
    supported.  An alternate definition of the macro would expand to
    something which executes the statement once.  */
 
+#define FOR_EACH_TAB(frame, list_var, tab_var)			\
+    for ((list_var) = frame->tab_bar_items;			\
+	 (CONSP (list_var)					\
+	  && (tab_var = XCAR (list_var), 1));			\
+	 list_var = XCDR (list_var))
+
 #define FOR_EACH_FRAME(list_var, frame_var)			\
   for ((list_var) = Vframe_list;				\
        (CONSP (list_var)					\
-	&& (frame_var = XCAR (list_var), 1));		\
+	&& (frame_var = XCAR (list_var), 1));			\
        list_var = XCDR (list_var))
 
-
 extern Lisp_Object Qframep, Qframe_live_p;
 extern Lisp_Object Qtty, Qtty_type;
 extern Lisp_Object Qtty_color_mode;
diff --git a/src/window.c b/src/window.c
index a2a0c79..7096488 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5832,6 +5832,7 @@ struct save_window_data
 
     int frame_cols, frame_lines, frame_menu_bar_lines;
     int frame_tool_bar_lines;
+    int frame_tab_bar_lines;
   };
 
 /* This is saved as a Lisp_Vector  */
@@ -5963,6 +5964,7 @@ the return value is nil.  Otherwise the value is t.  */)
       int previous_frame_cols =  FRAME_COLS  (f);
       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
       int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+      int previous_frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f);
 
       /* The mouse highlighting code could get screwed up
 	 if it runs during this.  */
@@ -6414,6 +6416,7 @@ redirection (see `redirect-frame-focus').  */)
   data->frame_lines = FRAME_LINES (f);
   data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
   data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+  data->frame_tab_bar_lines = FRAME_TAB_BAR_LINES (f);
   data->selected_frame = selected_frame;
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSETBUFFER (data->current_buffer, current_buffer);
@@ -6910,6 +6913,8 @@ compare_window_configurations (Lisp_Object c1, Lisp_Object c2, int ignore_positi
     return 0;
   if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
     return 0;
+  if (d1->frame_tab_bar_lines != d2->frame_tab_bar_lines)
+    return 0;
   if (! EQ (d1->selected_frame, d2->selected_frame))
     return 0;
   /* Don't compare the current_window field directly.
diff --git a/src/xdisp.c b/src/xdisp.c
index 77e9db2..bbd8bd3 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -330,6 +330,8 @@ Lisp_Object Qinhibit_eval_during_redisplay;
 Lisp_Object Qbuffer_position, Qposition, Qobject;
 Lisp_Object Qright_to_left, Qleft_to_right;
 
+Lisp_Object Qtab_name;
+
 /* Cursor shapes */
 Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
 
@@ -1059,6 +1061,8 @@ static int store_mode_line_string (const char *, Lisp_Object, int, int, int, Lis
 static const char *decode_mode_spec (struct window *, int, int, int,
 				     Lisp_Object *);
 static void display_menu_bar (struct window *);
+static void display_tab_bar (struct window *w);
+
 static int display_count_lines (EMACS_INT, EMACS_INT, EMACS_INT, int,
 				EMACS_INT *);
 static int display_string (const unsigned char *, Lisp_Object, Lisp_Object,
@@ -14575,6 +14579,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       && EQ (FRAME_SELECTED_WINDOW (f), window))
     {
       int redisplay_menu_p = 0;
+      int redisplay_tab_p = 0;
       int redisplay_tool_bar_p = 0;
 
       if (FRAME_WINDOW_P (f))
@@ -14589,9 +14594,14 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       else
         redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
 
+      redisplay_tab_p = FRAME_TAB_BAR_LINES (f) > 0;
+
       if (redisplay_menu_p)
         display_menu_bar (w);
 
+      if (redisplay_tab_p)
+	  display_tab_bar (w);
+
 #ifdef HAVE_WINDOW_SYSTEM
       if (FRAME_WINDOW_P (f))
         {
@@ -18176,6 +18186,75 @@ See also `bidi-paragraph-direction'.  */)
     }
 }
 
+void
+display_tab_bar (struct window *w)
+{
+    const int tab_length = 10;
+
+    struct frame *fr = XFRAME (WINDOW_FRAME (w));
+
+    struct it it;
+    int index;
+    init_iterator (&it, w, -1, -1,
+		   fr->desired_matrix->rows + FRAME_MENU_BAR_LINES (fr),
+		   DEFAULT_FACE_ID);
+    it.first_visible_x = 0;
+    it.last_visible_x = FRAME_COLS (fr);
+
+  /* Clear all rows of the menu bar.  */
+  for (index = 0;
+       index < FRAME_TAB_BAR_LINES (fr);
+       ++index)
+    {
+      struct glyph_row *row = it.glyph_row + index;
+      clear_glyph_row (row);
+      row->enabled_p = 1;
+      row->full_width_p = 1;
+    }
+
+  int ii=0, oddrow=0, oddcol=0;
+  Lisp_Object tab, tab_list, s;
+  FOR_EACH_TAB (fr, tab_list, tab)
+  {
+      Lisp_Object tabname = Fcdr (Fassq (Qtab_name, tab));
+      if (it. hpos + tab_length > FRAME_COLS (fr))
+      {
+	  /* Fill out the line with spaces.  */
+	  it.base_face_id = DEFAULT_FACE_ID;
+	  while (it.current_x < it.last_visible_x)
+	      display_string (" ", Qnil, Qnil, 0, 0,  &it, 1, 0, 0, -1);
+
+  	  if (unix == (it.current_y + 1))
+	      oddcol = ii % 2;
+
+	  oddrow = (oddcol)? (ii%2) : !oddrow;
+
+      	  it.hpos = it.current_x = 0;
+	  it.current_y ++;
+      	  ++it.vpos;
+      	  it.glyph_row++;
+	  if (it.current_y > FRAME_TAB_BAR_LINES (fr))
+      	      break;
+      }
+
+      it.base_face_id = (ii == FRAME_CURRENT_TAB (fr)) ? CURRENT_TAB_FACE_ID :
+      	   oddrow ? ODD_TAB_FACE_ID :
+      	  EVEN_TAB_FACE_ID;
+      
+      int len = SCHARS (tabname) > tab_length ? tab_length: SCHARS (tabname);
+      s = Fsubstring (tabname, make_number(0), make_number (len));
+      display_string (NULL, s, Qnil, 0, 0, &it, tab_length, 0, 0, -1);
+
+      oddrow = ! oddrow;
+      ii++;
+  }
+
+  
+  /* Compute the total height of the lines.  */
+  compute_line_metrics (&it);
+
+}
+
 
 \f
 /***********************************************************************
diff --git a/src/xfaces.c b/src/xfaces.c
index 5c7cfe6..3e14a64 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -348,6 +348,7 @@ Lisp_Object Qframe_set_background_mode;
 Lisp_Object Qdefault, Qtool_bar, Qregion, Qfringe;
 Lisp_Object Qheader_line, Qscroll_bar, Qcursor, Qborder, Qmouse, Qmenu;
 Lisp_Object Qmode_line_inactive, Qvertical_border;
+Lisp_Object Qodd_tab_face, Qeven_tab_face, Qcurrent_tab_face;
 
 /* The symbol `face-alias'.  A symbols having that property is an
    alias for another face.  Value of the property is the name of
@@ -5389,6 +5390,9 @@ realize_basic_faces (struct frame *f)
       realize_named_face (f, Qmouse, MOUSE_FACE_ID);
       realize_named_face (f, Qmenu, MENU_FACE_ID);
       realize_named_face (f, Qvertical_border, VERTICAL_BORDER_FACE_ID);
+      realize_named_face (f, Qcurrent_tab_face, CURRENT_TAB_FACE_ID);
+      realize_named_face (f, Qodd_tab_face, ODD_TAB_FACE_ID);
+      realize_named_face (f, Qeven_tab_face, EVEN_TAB_FACE_ID);
 
       /* Reflect changes in the `menu' face in menu bars.  */
       if (FRAME_FACE_CACHE (f)->menu_face_changed_p)
@@ -6659,6 +6663,12 @@ syms_of_xfaces (void)
   staticpro (&Qmode_line_inactive);
   Qvertical_border = intern_c_string ("vertical-border");
   staticpro (&Qvertical_border);
+  Qcurrent_tab_face = intern ("current-tab-face");
+  staticpro (&Qcurrent_tab_face);
+  Qodd_tab_face = intern ("odd-tab-face");
+  staticpro (&Qodd_tab_face);
+  Qeven_tab_face = intern ("even-tab-face");
+  staticpro (&Qeven_tab_face);
   Qtty_color_desc = intern_c_string ("tty-color-desc");
   staticpro (&Qtty_color_desc);
   Qtty_color_standard_values = intern_c_string ("tty-color-standard-values");
-- 
1.7.1


[-- Attachment #3: test-tabs.el --]
[-- Type: text/x-emacs-lisp, Size: 2221 bytes --]


;; evaluate this file, sexp after sexp, and follow the comments.

;; set a minimal environment
(progn
  (custom-set-faces
   '(current-tab-face ((t ( :inherit 'default-face  :foreground "lightblue" :bold t :underline t))))
   '(odd-tab-face    ((t ( :background "red"    :foreground "white" ))))
   '(even-tab-face   ((t ( :background "green"  :foreground "black")))))
  (set-frame-parameter (selected-frame) 'tab-bar-lines 4)
  (set-frame-parameter (selected-frame) 'menu-bar-lines 0))

;; this is a definition of a tab as a window configuration
(defun make-wc-tab (parms)
  ;; save curent win config
  (setq sym (make-symbol "winconfig"))
  (set sym  (current-window-configuration))
  ;; make a tab that keeps a window configuration. When it is created,
  ;; it memories the current win config. When it is activated, it
  ;; restores the memorized win config
  (make-terminal-frame
   (list '(tab . t)
	 '(tab:name . "WinC")
	 '(tab:activate
	   .
	   (lambda ()
	     (set-window-configuration
	      (eval (cdr (assoc 'tab:env (frame-parameters) ) ) ) ) ) )
	 ;; save the current win config into the tab environment
	 (cons 'tab:env sym) ) ) )

;; make a first tab keeping current win config
(make-wc-tab nil)

;; alter the window configuration
((lambda nil
   (split-window-vertically)))

;; make a second tab keeping current win config
(make-wc-tab nil)

;; alter the window configuration
((lambda nil
   (split-window-horizontally)))

;; make a third tab keeping current win config
(make-wc-tab nil)

;; keep only the current window
(delete-other-windows)

;; now activate the tabs that keep the memorized win config.  this
;; function disovered a bug in window configuration . LOL.  If you
;; change the tab-bar-lines or menu-bar-lines after creating a tab
;; and before activatin it here, emacs crashes. LOL.

;; activate the second
(set-frame-parameter (selected-frame) 'current-tab 1)

;; the third
(set-frame-parameter (selected-frame) 'current-tab 2)

;; the first again
(set-frame-parameter (selected-frame) 'current-tab 0)

;; dump frame params
(progn
  (setq  eval-expression-print-length 5000
	 eval-expression-print-level  5000
	 print-level 5000
	 )
  (frame-parameters) )

;; that's all for now.





^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-03  9:37                 ` Andreas Schwab
@ 2010-12-04 21:48                   ` Alin Soare
  0 siblings, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-04 21:48 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 110 bytes --]

>
>
> Never work as root.
>

If sombody manages to crash my home network , I grant him 10 mugs of black
beer.

[-- Attachment #2: Type: text/html, Size: 307 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
  2010-12-03 12:29                     ` Dimitri Fontaine
  2010-12-04 21:42                       ` Alin Soare
@ 2010-12-04 21:55                       ` Alin Soare
  1 sibling, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-04 21:55 UTC (permalink / raw)
  To: Dimitri Fontaine; +Cc: Andreas Schwab, Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 959 bytes --]

>
> Alin Soare <as1789@gmail.com> writes:
> > Please come with ideas about extending the frames, such that to be able
> to
> > write scripts to create tabs that play with frames...
>
> What do you think about solutions such as escreen, elscreen or
> workgroups?
>
>  http://www.splode.com/~friedman/software/emacs-lisp/src/escreen.el<http://www.splode.com/%7Efriedman/software/emacs-lisp/src/escreen.el>
>  http://www.morishima.net/~naoto/software/elscreen/index.php.en<http://www.morishima.net/%7Enaoto/software/elscreen/index.php.en>
>  https://github.com/tlh/workgroups.el
>
>
Hi,

I did look a little on the web , and googled images to see what these are
about, but I do not understand too much about them.

My purpose was to make graphical tabs, and to attach to every such tab a
general action, whatever could be possible..

For now I attached only minimal window configuration to every tab, and in
the same time keeping it as simple as possible.

Alin

[-- Attachment #2: Type: text/html, Size: 1410 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
       [not found]                   ` <jwvsjyai7lv.fsf-monnier+emacs@gnu.org>
@ 2010-12-07  4:47                     ` Alin Soare
  2010-12-07  4:50                       ` Alin Soare
  2010-12-07 17:06                       ` Stefan Monnier
  0 siblings, 2 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-07  4:47 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 4670 bytes --]

> > The idea is that I added to struct frame a list of tabs.
>
> Where is it?  In the frame's parameters?  Or is it accessed via a new
> frame-tabs and set-frame-tabs?
>
> struct frame
{
...
    /*
     * an alist  of the form ((alist_tab_parameters))
     */
    Lisp_Object tab_bar_items;
...
}



> In any case, how difficult would it be to generalize your code so the
> tabs can be attached to a window rather than a frame, or even to an
> internal window (i.e. internal windows are those that are somewhere
> along the window tree and hold various actual windows: currently your
> tabs are at the root internal window).
>
>
I did not think about. Not too difficult.



> > A tab is an alist of
>
> > (
> >   (:name "string-name")
> >   (:init-code (lambda () ... code) )
> >   (:activate-code (lambda() ... code) )
> >   (:deactivate-code ... )
> >   (:environment list-of-symbols)
> > )
>
> What's the init-code for?
>

The init code is executed only when the tab is created. In my script it is
used to memorize the current window config into a variable 'sym. The
variable sym must be tab-local during the tab existence.


> I suspect activate is run when you click on the tab and deactivate is
> run when you click on some other tab.
> What's environment and how is it used?
>
>
An environment keeps tab-local variables. For example , every tabmust know
about the window-configuration when it was created , and extract from its
own environment the value of that win config.

No other tab needs to see its own windows config.


> > This is the function that defines a tab. It initialize a symbol sym with
> the
> > value of current-window-config. The symbol 'sym is passed to
> > (make-terminal-frame), that creates the tab.
>
> I don't understand this "symbol sym" business.
>
>

I have just explained. It is not interned in the main obarray, and it is
passed to the environment of the tab.



> > ;; this is a definition of a tab as a window configuration
> > (defun make-wc-tab (parms)
> >   ;; save curent win config
> >   (setq sym (make-symbol "winconfig"))
>
> Here, you're setting a global variable, which is wrong.  It's also very
> unclear why you want a symbol here.
>

It is not global. It is not interned, and it becomes tab-local.



> >   (set sym  (current-window-configuration))
> >   ;; make a tab that keeps a window configuration. When it is created,
> >   ;; it memorizes the current win config. When it is activated, it
> >   ;; restores the memorized win config
> >   (make-terminal-frame
> >    (list '(tab . t)
> >      '(tab:name . "WinC")
> >      '(tab:activate
> >        .
> >        (lambda ()
> >          (set-window-configuration
> >           (eval (cdr (assoc 'tab:env (frame-parameters) ) ) ) ) ) )
>
> `eval' is bad.  Stay very far away from it.
>
> >      ;; save the current win config into the tab environment
> >      (cons 'tab:env sym) ) ) )
>
> How do "tab:activate" and friends relate to the
> previous :activate-code thingies?
>


Via tab-local variables.

In this moment I added code to modify the environment of a tab only via the
initialization of the tab with make-terminal-frame, but I can add a function
to operate on tab-local variables even after the creation of a tab.

For example, I did not add the tab:init code to tab's alist, because it is
runned only to creation, in make-tab, before calling make-terminal-frame.

But if I want to be able to re-initialize a tab, then a function to operate
on tab's environment is required.


>
> I don't understand the above call to `make-terminal-frame': does it
> create a new frame, or just a new tab?  If the first, then I don't
> understand how it works, and if the second, it's wrong because adding
> a tab should have nothing to do with frame creation.
>

The fact that make-tab calls directly make-terminal-frame is just a legacy
of the old code, when a tab used to be just a frame.

Imagine that emacs had lexical binding. Then we woud not need a tab
environment, because that environment would be included insode the
evaluation process, when the closure that represents the tab is initialized.
But because emacs is not able of closures, I need a tab environment, to be
able to communicate between the

(:init-code (lambda () ... code) )
(:activate-code (lambda() ... code) )
(:deactivate-code ... )

of the same tab,

Note that inside my implementation of make-tab, the variable 'winconfig has
a different value for every tab. When :activatecode is called ,

> (lambda ()
>          (set-window-configuration
>           (eval (cdr (assoc 'tab:env (frame-parameters) )

(cdr (assoc 'tab:env (frame-parameters) )  returns the variable 'winconfig,
id est sym.

[-- Attachment #2: Type: text/html, Size: 6868 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-07  4:47                     ` Fwd: " Alin Soare
@ 2010-12-07  4:50                       ` Alin Soare
  2010-12-07 17:06                       ` Stefan Monnier
  1 sibling, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-07  4:50 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 5214 bytes --]

Try also to install the patch from Saturday and execute the code, to see how
the tab-local variables are used to communicate between :initcode, and
:activationcode.

I deactivated the :deactivationcode, because it is not useful for me, and I
wanted to keep the code minimal.



Alin



2010/12/7 Alin Soare <as1789@gmail.com>

>
> > The idea is that I added to struct frame a list of tabs.
>>
>> Where is it?  In the frame's parameters?  Or is it accessed via a new
>> frame-tabs and set-frame-tabs?
>>
>> struct frame
> {
> ...
>     /*
>      * an alist  of the form ((alist_tab_parameters))
>      */
>     Lisp_Object tab_bar_items;
> ...
> }
>
>
>
>> In any case, how difficult would it be to generalize your code so the
>> tabs can be attached to a window rather than a frame, or even to an
>> internal window (i.e. internal windows are those that are somewhere
>> along the window tree and hold various actual windows: currently your
>> tabs are at the root internal window).
>>
>>
> I did not think about. Not too difficult.
>
>
>
>>  > A tab is an alist of
>>
>> > (
>> >   (:name "string-name")
>> >   (:init-code (lambda () ... code) )
>> >   (:activate-code (lambda() ... code) )
>> >   (:deactivate-code ... )
>> >   (:environment list-of-symbols)
>> > )
>>
>> What's the init-code for?
>>
>
> The init code is executed only when the tab is created. In my script it is
> used to memorize the current window config into a variable 'sym. The
> variable sym must be tab-local during the tab existence.
>
>
>> I suspect activate is run when you click on the tab and deactivate is
>> run when you click on some other tab.
>> What's environment and how is it used?
>>
>>
> An environment keeps tab-local variables. For example , every tabmust know
> about the window-configuration when it was created , and extract from its
> own environment the value of that win config.
>
> No other tab needs to see its own windows config.
>
>
>> > This is the function that defines a tab. It initialize a symbol sym with
>> the
>> > value of current-window-config. The symbol 'sym is passed to
>> > (make-terminal-frame), that creates the tab.
>>
>> I don't understand this "symbol sym" business.
>>
>>
>
> I have just explained. It is not interned in the main obarray, and it is
> passed to the environment of the tab.
>
>
>
>>  > ;; this is a definition of a tab as a window configuration
>> > (defun make-wc-tab (parms)
>> >   ;; save curent win config
>> >   (setq sym (make-symbol "winconfig"))
>>
>> Here, you're setting a global variable, which is wrong.  It's also very
>> unclear why you want a symbol here.
>>
>
> It is not global. It is not interned, and it becomes tab-local.
>
>
>
>>  >   (set sym  (current-window-configuration))
>> >   ;; make a tab that keeps a window configuration. When it is created,
>> >   ;; it memorizes the current win config. When it is activated, it
>> >   ;; restores the memorized win config
>> >   (make-terminal-frame
>> >    (list '(tab . t)
>> >      '(tab:name . "WinC")
>> >      '(tab:activate
>> >        .
>> >        (lambda ()
>> >          (set-window-configuration
>> >           (eval (cdr (assoc 'tab:env (frame-parameters) ) ) ) ) ) )
>>
>> `eval' is bad.  Stay very far away from it.
>>
>> >      ;; save the current win config into the tab environment
>> >      (cons 'tab:env sym) ) ) )
>>
>> How do "tab:activate" and friends relate to the
>> previous :activate-code thingies?
>>
>
>
> Via tab-local variables.
>
> In this moment I added code to modify the environment of a tab only via the
> initialization of the tab with make-terminal-frame, but I can add a function
> to operate on tab-local variables even after the creation of a tab.
>
> For example, I did not add the tab:init code to tab's alist, because it is
> runned only to creation, in make-tab, before calling make-terminal-frame.
>
> But if I want to be able to re-initialize a tab, then a function to operate
> on tab's environment is required.
>
>
>>
>> I don't understand the above call to `make-terminal-frame': does it
>> create a new frame, or just a new tab?  If the first, then I don't
>> understand how it works, and if the second, it's wrong because adding
>> a tab should have nothing to do with frame creation.
>>
>
> The fact that make-tab calls directly make-terminal-frame is just a legacy
> of the old code, when a tab used to be just a frame.
>
> Imagine that emacs had lexical binding. Then we woud not need a tab
> environment, because that environment would be included insode the
> evaluation process, when the closure that represents the tab is initialized.
> But because emacs is not able of closures, I need a tab environment, to be
> able to communicate between the
>
>
> (:init-code (lambda () ... code) )
> (:activate-code (lambda() ... code) )
> (:deactivate-code ... )
>
> of the same tab,
>
> Note that inside my implementation of make-tab, the variable 'winconfig has
> a different value for every tab. When :activatecode is called ,
>
> > (lambda ()
> >          (set-window-configuration
> >           (eval (cdr (assoc 'tab:env (frame-parameters) )
>
> (cdr (assoc 'tab:env (frame-parameters) )  returns the variable 'winconfig,
> id est sym.
>
>
>
>
>
>
>

[-- Attachment #2: Type: text/html, Size: 7624 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-07  4:47                     ` Fwd: " Alin Soare
  2010-12-07  4:50                       ` Alin Soare
@ 2010-12-07 17:06                       ` Stefan Monnier
  2010-12-08  8:14                         ` Alin Soare
  1 sibling, 1 reply; 34+ messages in thread
From: Stefan Monnier @ 2010-12-07 17:06 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

>> > The idea is that I added to struct frame a list of tabs.
>> Where is it?  In the frame's parameters?  Or is it accessed via a new
>> frame-tabs and set-frame-tabs?
>> 
>> struct frame
> {
> ...
>     /*
>      * an alist  of the form ((alist_tab_parameters))
>      */
>     Lisp_Object tab_bar_items;
> ...
> }

So it's not in the frame's parameters: how is it accessible from Elisp?

>> > A tab is an alist of
>> 
>> > (
>> >   (:name "string-name")
>> >   (:init-code (lambda () ... code) )
>> >   (:activate-code (lambda() ... code) )
>> >   (:deactivate-code ... )
>> >   (:environment list-of-symbols)
>> > )
>> 
>> What's the init-code for?

> The init code is executed only when the tab is created. In my script it is
> used to memorize the current window config into a variable 'sym. The
> variable sym must be tab-local during the tab existence.

Who creates such a tab and how, then?  If the tab is created from Elisp
code, then that code can run the init-code without any special support in the
tabs code.  So why is there such a special init-code?

Oh, I think maybe I see: the tab creation is done in C and it calls this
init-code to setup the new tab.  I.e. when you wrote "a tab is an
alist", what you really meant was "a tabbar is an alist", is that right?

>> I suspect activate is run when you click on the tab and deactivate is
>> run when you click on some other tab.
>> What's environment and how is it used?
> An environment keeps tab-local variables.

I'm trying to move away from the "foo-local variable" business, so let's
not introduce new ones.

> For example , every tabmust know about the window-configuration when
> it was created , and extract from its own environment the value of
> that win config.

But the :environment is shared by all tabs of the same tabbar, isn't it?
Rather than "environment" I'd rather use some other word, not
associated with variables.  It's basically just some data specific to
the activate/deactivate code, so we could call it "aux data" or "private
data", tho of course, this all still depends on whether that data is
tab-specific or tabbar-specific.

>> > This is the function that defines a tab. It initialize a symbol sym
>> > with the value of current-window-config. The symbol 'sym is passed
>> > to (make-terminal-frame), that creates the tab.
>> I don't understand this "symbol sym" business.
> I have just explained. It is not interned in the main obarray, and it is
> passed to the environment of the tab.

No you haven't because you haven't explained why you need *variables*.
You explained what you need to store some auxiliary data, but usually
that's stored in a data-structure, not in a variable.

>> > ;; this is a definition of a tab as a window configuration
>> > (defun make-wc-tab (parms)
>> >   ;; save curent win config
>> >   (setq sym (make-symbol "winconfig"))
>> 
>> Here, you're setting a global variable, which is wrong.  It's also very
>> unclear why you want a symbol here.
> It is not global. It is not interned, and it becomes tab-local.

Yes, the symbol `sym' assigned by `setq' above is a global variable.
It is assigned a value which is itself a symbol and that symbol is
indeed uninterned, but I'm talking about the symbol `sym' not about the
value stored into its value cell.

>> How do "tab:activate" and friends relate to the
>> previous :activate-code thingies?
> Via tab-local variables.

That doesn't really answer my question, because we're not understanding
each other.
So from your answer I understand that they are indeed different things
(rather than typos, for example), but that doesn't tell me how they
relate: you described a tab(bar?) as having :activate-code but in the
example code you show you use tab:activate instead: does one somehow
morph into the other, or are the two completely independent and if so
how/where/when does the other appear in code?

> But if I want to be able to re-initialize a tab, then a function to operate
> on tab's environment is required.

I'm beginning to think that the init-code should return a value (the
tab's private data), which is then passed to the
(de)activate functions.  The tabbar code doesn't need to care about what
that value is, it just needs to store it and pass it along; the
init-code and (de)activate functions will decide what to do with it.
It can be a window-config or anything else.  That should make your
environment business unnecessary.

>> I don't understand the above call to `make-terminal-frame': does it
>> create a new frame, or just a new tab?  If the first, then I don't
>> understand how it works, and if the second, it's wrong because adding
>> a tab should have nothing to do with frame creation.
> The fact that make-tab calls directly make-terminal-frame is just a legacy
> of the old code, when a tab used to be just a frame.

So it will need to change.  But does `make-tab' create a new tab or
a tabbar?  If a tab, then I don't understand any more why the init-code
is needed.

> Imagine that emacs had lexical binding.

Elisp offers plenty of ways to do what one would do with lexical
bindings.  So please, just assume that lexical binding is available and
don't add weird things to try to work around its absence.  E.g. You can
simulate it with `(lambda () ... ,foo ...) or with `lexical-let' or with
`apply-partially', plus many many other ways (plus Emacs-24 will offer
true lexical binding, if all goes as planned).

> Then we woud not need a tab environment,

Then, please throw it away.

> Note that inside my implementation of make-tab, the variable 'winconfig has
> a different value for every tab. When :activatecode is called ,

That's really nasty for the programmer: there is no variable `winconfig'
in your code.  There's only a symbol `winconfig' whose value cell you
use as a place holder.  You could just as well replace

   (setq sym (make-symbol "winconfig"))
   (set sym (current-window-configuration))
   ...
   ...(eval (cdr (assoc 'tab:env (frame-parameters))))

with

   (let ((dataholder (list nil)))
     (setcar dataholder (current-window-configuration))
     ...
     ...(car (cdr (assoc 'tab:env (frame-parameters))))

and that would work just as well: `winconfig' is not a variable, but
a "box" data structure.
At least, if I've understood your code correctly.
     

        Stefan



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-07 17:06                       ` Stefan Monnier
@ 2010-12-08  8:14                         ` Alin Soare
       [not found]                           ` <AANLkTikaXr_4bVR2_v7HVFfPB93Sw10e63cKqTRwOunS@mail.gmail.com>
  2010-12-09  4:29                           ` Fwd: " Stefan Monnier
  0 siblings, 2 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-08  8:14 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 9506 bytes --]

> >> > The idea is that I added to struct frame a list of tabs.
> >> Where is it?  In the frame's parameters?  Or is it accessed via a new
> >> frame-tabs and set-frame-tabs?
> >>
> >> struct frame
> > {
> > ...
> >     /*
> >      * an alist  of the form ((alist_tab_parameters))
> >      */
> >     Lisp_Object tab_bar_items;
> > ...
> > }
>
> So it's not in the frame's parameters: how is it accessible from Elisp?
>

I defined the tabs inside the struct frame, because I thought that their
names are displayed on the upperside of a frame. Despite this, they have
nothing in common with a frame.

tab_bar_items is a list of tabs, so it looks like this:


(

 (
   (:name "tab1")
   (:init-code (lambda () ... code) )
   (:activate-code (lambda() ... code) )
   (:deactivate-code ... )
   (:environment list-of-symbols)
 )


 (
   (:name "tab2")
   (:init-code (lambda () ... code) )
   (:activate-code (lambda() ... code) )
   (:deactivate-code ... )
   (:environment list-of-symbols)
 )

)

So far it is accesible via frame-parameters, but in my code this access is
not useful/used.

I could separate all tabs parameters into a struct tab, and keep inside
struct frame only 3 fields.

struct frame
{

   bool subscribe_to_tabs;
   int tab_bar_lines;
   char *regexp;
}

when f->subscribe_to_tabs is true, then it is displayed on `tab_bar_lines'
the tabs that match regexp for example.

It is not required to keep a fixed number of parameters for a tab, like
:activate-code, :init-code, etc. One can add a parameter (:kill-buffer-xyz
(lambda () ... )) that is called when an event, like kill-buffer of a buffer
named "xyz" produces.

But for now we can suppose the number is fixed.


>
> >> > A tab is an alist of
> >>
> >> > (
> >> >   (:name "string-name")
> >> >   (:init-code (lambda () ... code) )
> >> >   (:activate-code (lambda() ... code) )
> >> >   (:deactivate-code ... )
> >> >   (:environment list-of-symbols)
> >> > )
> >>
> >> What's the init-code for?
>
> > The init code is executed only when the tab is created. In my script it
> is
> > used to memorize the current window config into a variable 'sym. The
> > variable sym must be tab-local during the tab existence.
>
> Who creates such a tab and how, then?  If the tab is created from Elisp
> code, then that code can run the init-code without any special support in
> the
> tabs code.  So why is there such a special init-code?
>
> Oh, I think maybe I see: the tab creation is done in C and it calls this
> init-code to setup the new tab.  I.e. when you wrote "a tab is an
> alist", what you really meant was "a tabbar is an alist", is that right?
>

Yes, like this. Or the :initcode is executed from (make-tab, like in my
example, and for my example there is no reason to keep it memorized as a
parameter in tab's alist parameters, because in this example it is not
useful any more).

But the :initcode can be very useful, because a tab should be re-initialized
sometimes.

Yes, I keep a tab as an alist, and all tabs as list of tabs.



>
> >> I suspect activate is run when you click on the tab and deactivate is
> >> run when you click on some other tab.
> >> What's environment and how is it used?
> > An environment keeps tab-local variables.
>
> I'm trying to move away from the "foo-local variable" business, so let's
> not introduce new ones.
>

OK


>
> > For example , every tabmust know about the window-configuration when
> > it was created , and extract from its own environment the value of
> > that win config.
>
> But the :environment is shared by all tabs of the same tabbar, isn't it?
> Rather than "environment" I'd rather use some other word, not
> associated with variables.  It's basically just some data specific to
> the activate/deactivate code, so we could call it "aux data" or "private
> data", tho of course, this all still depends on whether that data is
> tab-specific or tabbar-specific.
>

Every tab to me has a parameter :environment, and after it the symbols from
that env. Evaluating the first symbol, I got the value of the
tab-configuration, and pass it to set-win-config.



>
> >> > This is the function that defines a tab. It initialize a symbol sym
> >> > with the value of current-window-config. The symbol 'sym is passed
> >> > to (make-terminal-frame), that creates the tab.
> >> I don't understand this "symbol sym" business.
> > I have just explained. It is not interned in the main obarray, and it is
> > passed to the environment of the tab.
>
> No you haven't because you haven't explained why you need *variables*.
> You explained what you need to store some auxiliary data, but usually
> that's stored in a data-structure, not in a variable.


Yes, one can store private data, but if we need more private data than a
variable, we need to name every stored value.

A stored value can be stored

- using a plist
- using an alist
-using a list of symbols with values (as I did)
- using an actor
- probably more



>
>
>> > ;; this is a definition of a tab as a window configuration
> >> > (defun make-wc-tab (parms)
> >> >   ;; save curent win config
> >> >   (setq sym (make-symbol "winconfig"))
> >>
> >> Here, you're setting a global variable, which is wrong.  It's also very
> >> unclear why you want a symbol here.
> > It is not global. It is not interned, and it becomes tab-local.
>
> Yes, the symbol `sym' assigned by `setq' above is a global variable.
> It is assigned a value which is itself a symbol and that symbol is
> indeed uninterned, but I'm talking about the symbol `sym' not about the
> value stored into its value cell.
>

This is a mistake in my code, it should not be . I forgot to call  a
(make-unbound 'sym)



>
> >> How do "tab:activate" and friends relate to the
> >> previous :activate-code thingies?
> > Via tab-local variables.
>
> That doesn't really answer my question, because we're not understanding
> each other.
> So from your answer I understand that they are indeed different things
> (rather than typos, for example), but that doesn't tell me how they
> relate: you described a tab(bar?) as having :activate-code but in the
> example code you show you use tab:activate instead: does one somehow
>

ya, in my code I called the symbols tab:activate, and in messages I wrote
:activate. Sorry.



> morph into the other, or are the two completely independent and if so
> how/where/when does the other appear in code?
>

The same


>
> > But if I want to be able to re-initialize a tab, then a function to
> operate
> > on tab's environment is required.
>
> I'm beginning to think that the init-code should return a value (the
> tab's private data), which is then passed to the
> (de)activate functions.
>

This is a good idea.


> The tabbar code doesn't need to care about what that value is, it just
> needs to store it and pass it along; the init-code and (de)activate
> functions will decide what to do with it.
> It can be a window-config or anything else.  That should make your
> environment business unnecessary.
>

Yes, if it is only 1 value, we know that it is on the first position of
private-data list, and can access it via cadr.



>
> >> I don't understand the above call to `make-terminal-frame': does it
> >> create a new frame, or just a new tab?  If the first, then I don't
> >> understand how it works, and if the second, it's wrong because adding
> >> a tab should have nothing to do with frame creation.
> > The fact that make-tab calls directly make-terminal-frame is just a
> legacy
> > of the old code, when a tab used to be just a frame.
>
> So it will need to change.  But does `make-tab' create a new tab or
> a tabbar?  If a tab, then I don't understand any more why the init-code
> is needed.
>

Yes, tabs must be separate from frames, and keep indepedent of every other
thing.

A frame/window can subscribe to tabs, and show them when it is
activated/etc.



>
> > Imagine that emacs had lexical binding.
>
> Elisp offers plenty of ways to do what one would do with lexical
> bindings.  So please, just assume that lexical binding is available and
> don't add weird things to try to work around its absence.  E.g. You can
> simulate it with `(lambda () ... ,foo ...) or with `lexical-let' or with
> `apply-partially', plus many many other ways (plus Emacs-24 will offer
> true lexical binding, if all goes as planned).
>

OK. I will try to use it



>
> > Then we woud not need a tab environment,
>
> Then, please throw it away.
>
> > Note that inside my implementation of make-tab, the variable 'winconfig
> has
> > a different value for every tab. When :activatecode is called ,
>
> That's really nasty for the programmer: there is no variable `winconfig'
> in your code.  There's only a symbol `winconfig' whose value cell you
> use as a place holder.  You could just as well replace
>

true. I did not write look-for-variable function; I did not insert it within
an obarray, as Alyssa Hacker, Ben Bitdiddle or Louis Reasoner would have
done.



>
>   (setq sym (make-symbol "winconfig"))
>    (set sym (current-window-configuration))
>    ...
>   ...(eval (cdr (assoc 'tab:env (frame-parameters))))
>
> with
>
>   (let ((dataholder (list nil)))
>     (setcar dataholder (current-window-configuration))
>     ...
>     ...(car (cdr (assoc 'tab:env (frame-parameters))))
>
> and that would work just as well: `winconfig' is not a variable, but
> a "box" data structure.
>

true.


> At least, if I've understood your code correctly.
>
>
It would be very well to agree, before I start completing the code.



Alin.

[-- Attachment #2: Type: text/html, Size: 13851 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Tabs for console.
       [not found]                           ` <AANLkTikaXr_4bVR2_v7HVFfPB93Sw10e63cKqTRwOunS@mail.gmail.com>
@ 2010-12-08 11:16                             ` Alin Soare
  0 siblings, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-08 11:16 UTC (permalink / raw)
  To: Stefan Monnier, Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 1404 bytes --]

> >> I don't understand the above call to `make-terminal-frame': does it
> >> create a new frame, or just a new tab?  If the first, then I don't
> >> understand how it works, and if the second, it's wrong because adding
> >> a tab should have nothing to do with frame creation.
> > The fact that make-tab calls directly make-terminal-frame is just a
> legacy
> > of the old code, when a tab used to be just a frame.
>
> So it will need to change.  But does `make-tab' create a new tab or
> a tabbar?  If a tab, then I don't understand any more why the init-code
> is needed.
>

I did not insert :initcode inside the tab, because I should have written
more C code. I should add the :initcode after the (make-terminal-frame '(tab
. t)), or I should have written code to commute temporarly to a tab without
activating it.

This is why I executed the :initcode before calling (make-terminal-frame....
)

In my case the :initcode should be

  ;; save curent win config
  (setq sym (make-symbol "winconfig"))
  (set sym  (current-window-configuration))


My actual C code does not allow me to insert :initcode as parameter to
(make-terminal-frame (tab . t)), and this is why I created make-tab and
separated the :initcode.

I come into a vicious circle if I pass :initcode to make-terminal frame, and
I did not want to write more C code before to clarify with other emacs
developers how tabs should look like.

[-- Attachment #2: Type: text/html, Size: 1907 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-08  8:14                         ` Alin Soare
       [not found]                           ` <AANLkTikaXr_4bVR2_v7HVFfPB93Sw10e63cKqTRwOunS@mail.gmail.com>
@ 2010-12-09  4:29                           ` Stefan Monnier
  2010-12-09  8:26                             ` Alin Soare
  1 sibling, 1 reply; 34+ messages in thread
From: Stefan Monnier @ 2010-12-09  4:29 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

>> >> Where is it?  In the frame's parameters?  Or is it accessed via a new
>> >> frame-tabs and set-frame-tabs?
>> >>
>> >> struct frame
>> > {
>> > ...
>> >     /*
>> >      * an alist  of the form ((alist_tab_parameters))
>> >      */
>> >     Lisp_Object tab_bar_items;
>> > ...
>> > }
>> 
>> So it's not in the frame's parameters: how is it accessible from Elisp?
[...]
> So far it is accesible via frame-parameters, but in my code this access is
> not useful/used.

IIUC it is also (write-) accessible via `make-tab', right?

> I could separate all tabs parameters into a struct tab, and keep inside
> struct frame only 3 fields.

> struct frame
> {

>    bool subscribe_to_tabs;
>    int tab_bar_lines;
>    char *regexp;
> }

I don't care about such details for now: I'm concerned about the API it
presents to Elisp.

> Yes, like this. Or the :initcode is executed from (make-tab, like in my
> example, and for my example there is no reason to keep it memorized as a
> parameter in tab's alist parameters, because in this example it is not
> useful any more).

I'm still very far from understanding what you mean.
So here's how I imagine things working:

- some function to add/control/create a tabbar.
  (make-tab-bar PLACE)
  IIUC this function also accepts an INIT-CODE argument, which is run
  when the user presses the "+" button on the tab-bar.
- some function to add a tab to a tabbar
  (make-tab TABBAR ACTIVATE-FUNCTION DEACTIVATE-FUNCTION)
- probably also some function to delete a tab (delete-tab TABBAR TAB)
- probably also some deletion-hook in case the user presses the "X"
  button to delete a tab.

Now, all of ACTIVATE-FUNCTION, DEACTIVATE-FUNCTION, and DELETION-HOOK
could either be specified in make-tab or in make-tab-bar, depending on
whether we want to impose a uniform behavior.

If the ACTIVATE-FUNCTION is shared by all tabs, we'll also need each tab
to have a DATA argument, which is the equivalent of your environment.
  
> But the :initcode can be very useful, because a tab should be
> re-initialized sometimes.

That sounds odd.  When would that be?

> Yes, one can store private data, but if we need more private data than a
> variable, we need to name every stored value.

That doesn't matter to the tabbar code: the tab only ever needs 1 chunk of
private data passed to the activate-function.  That chunk can be
anything the activate-function needs: a struct, a list, an alist, you
name it: the tabbar code has no business looking inside.

>> Yes, the symbol `sym' assigned by `setq' above is a global variable.
>> It is assigned a value which is itself a symbol and that symbol is
>> indeed uninterned, but I'm talking about the symbol `sym' not about the
>> value stored into its value cell.
> This is a mistake in my code, it should not be . I forgot to call  a
> (make-unbound 'sym)

That doesn't solve the problem: it still affects the global variable
`sym'.

> ya, in my code I called the symbols tab:activate, and in messages I wrote
> :activate. Sorry.

No, you didn't write :activate, but :activate-code.  Such vagueness
makes it very difficult to figure out what you mean.

>> The tabbar code doesn't need to care about what that value is, it just
>> needs to store it and pass it along; the init-code and (de)activate
>> functions will decide what to do with it.
>> It can be a window-config or anything else.  That should make your
>> environment business unnecessary.
> Yes, if it is only 1 value, we know that it is on the first position of
> private-data list, and can access it via cadr.

"we" here would be the activate-function, right?

>> So it will need to change.  But does `make-tab' create a new tab or
>> a tabbar?  If a tab, then I don't understand any more why the init-code
>> is needed.

> Yes, tabs must be separate from frames, and keep indepedent of every
> other thing.  A frame/window can subscribe to tabs, and show them when
> it is activated/etc.

That doesn't answer my question: does `make-tab' create a new tab or
a tabbar?


        Stefan



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-09  4:29                           ` Fwd: " Stefan Monnier
@ 2010-12-09  8:26                             ` Alin Soare
  2010-12-10  3:35                               ` Stefan Monnier
  0 siblings, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-09  8:26 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 8014 bytes --]

>> >> Where is it?  In the frame's parameters?  Or is it accessed via a new
> >> >> frame-tabs and set-frame-tabs?
> >> >>
> >> >> struct frame
> >> > {
> >> > ...
> >> >     /*
> >> >      * an alist  of the form ((alist_tab_parameters))
> >> >      */
> >> >     Lisp_Object tab_bar_items;
> >> > ...
> >> > }
> >>
> >> So it's not in the frame's parameters: how is it accessible from Elisp?
> [...]
> > So far it is accesible via frame-parameters, but in my code this access
> is
> > not useful/used.
>
> IIUC it is also (write-) accessible via `make-tab', right?
>

No.

I'm still very far from understanding what you mean.
> So here's how I imagine things working:
>
> - some function to add/control/create a tabbar.
>  (make-tab-bar PLACE)
>  IIUC this function also accepts an INIT-CODE argument, which is run
>  when the user presses the "+" button on the tab-bar.
> - some function to add a tab to a tabbar
>  (make-tab TABBAR ACTIVATE-FUNCTION DEACTIVATE-FUNCTION)
> - probably also some function to delete a tab (delete-tab TABBAR TAB)
> - probably also some deletion-hook in case the user presses the "X"
>  button to delete a tab.
>
> Now, all of ACTIVATE-FUNCTION, DEACTIVATE-FUNCTION, and DELETION-HOOK
> could either be specified in make-tab or in make-tab-bar, depending on
> whether we want to impose a uniform behavior.
>
> If the ACTIVATE-FUNCTION is shared by all tabs, we'll also need each tab
> to have a DATA argument, which is the equivalent of your environment.
>


This is a good idea, to clarify first the elisp interface.

* TAB BAR

**  (make-tab-bar PLACE)

for now, suppose that PLACE can be a frame. In what I did, PLACE is only a
frame.

* TAB

** A TAB can be defined in many ways. All tabs have in common a :NAME , and
an :ID. :NAME is a string that is displayed on the display on the upperside
of a frame, and :ID is a number that allows to user to easyly access it.
Forget about :ID for now.

** A TAB also have an :INIT-CODE, a :ACTIVATE-FUNCTION, a
:DEACTIVATE-FUNCTION, :CLOSE-FUNCTION:, hooks, and probably more.

:INIT-CODE must be run to get some values that are useful for
:ACTIVATE-FUNCTION, :DEACTIVATE-FUNCTION, etc.

These values are not useful for other tabs. For example:

*** EXAMPLE1  If I want a tab that keeps a window-configuration, than we
need only 1 such variable: a #<window-configuration>. This is used by
:ACTIVATE-FUNCTION, when one switched to that tab.

*** EXAMPLE2 If I want to create a tab, which divides the frame in 2
windows: the upper window switches to buffer "xyz", and the second window
switches to buffer "*scratch". Then the INIT-CODE for THIS KIND OF TAB must
ask you the name of buffer1, the name of buffer2, and keep these values into
a place where these values are accessed ONLY BY :ACTIVATE-FUNCTION, and all
other functions of this tab. So the :ACTIVATE-FUNCTION of the next tab (that
probably keeps a window-configuration) MUST NOT SEE the  values kept by this
tab. The :ACTIVATE-FUNCTION of this kind of tab must do something like

(lambda ()
 ( delete-other-windows )
 (split-window-vertically)
 (balance-windows)
 (let ((buffer1 (get-variable "buffer1"))
        (buffer1 (get-variable "buffer2"))
 (switch-to-buffer buffer1)
 (other-window)
 (switch-to-buffer buffer2)
 (other-window) )

Ben Bitdiddle would say you so:

Please note the function get-variable, that expects to find the value of a
variable named "buffer1" INSIDE an environment private to tab1.

Alyssa Hacker would say: :INIT-CODE must read the name of the first buffer
and store it into a variable "buffer1" of an environment private to the tab
that it initializes. It also gets the value of a second buffer, and keeps it
in buffer2, etc. These values must be accessed by :ACT-CODE , etc.

Note that a variable like "buffer1" is not useful for next tab.

It is like in Mozilla: when you press C-k to go to search bar, you can chose
the kind of search (google, ebay, wikipedia, and you can add other kind of
searches). The search bar is for me the tab-bar, and every kind of search is
a tab.


** On the TAB BAR there is a "+" button, but here you did not understand
what it is. When pressed, it allows you to chose some kind of tab, and to
create such a tab.


** the HOOKS are very useful.

*** EXAMPLE:

**** Consider a tab that does the following:

:INIT-CODE looks like so:

(lambda ()
 (delete-other-windows)
 (read-variable "buffer")
 (switch-to-buffer (get-variable "buffer"))
 )

Alyssa Hacker would say: Note that I did write (switch-to-buffer
(get-variable "buffer")), and not
(switch-to-buffer buffer), because in this case the eval would look for
bufferin main obarray, but I need to look in tab's environment.

:ACTIVATE-CODE is so:

(lambda ()
 (delete-other-windows)
 (switch-to-buffer (get-variable "buffer"))
 )

Here (get-variable "buffer")) looks in tabs' environment, and finds exactly
the value it needs.

**** Now, suppose that the tab is deactivated, but you want to see when the
contest of the buffer named (get-variable "buffer") (in tab's environment)
changes. In this case you want to see the color of the tab changes , or you
want to see on the tab an asterisk, that notifies you that the buffer
changed.

In this case one can add another function like :CHANGE-FUNCTION. For now, I
do not show any code, because it is too advanced, and first of all one must
clarify the basics tags, like :INIT-CODE, :ACTIVATE-CODE, etc.




>
> > But the :initcode can be very useful, because a tab should be
> > re-initialized sometimes.
>
> That sounds odd.  When would that be?
>

It is very useful. Consider that you have a tab (like in EXAMPLE2).

You keep in the upper window the buffer "xyz", and in down window the buffer
"*scratch*"

But 1 hour later, you need to keep in upper window the buffer "abc" and down
"*scratch*". You need to re-initialize the tab, and the :INIT-FUNCTION will
read again the value of "buffer1" and buffer2.

Instead of deleting the tab, and creating a new tab of the same type (that
switches to a buffer), you simply re-initialize the tab.


>
> > Yes, one can store private data, but if we need more private data than a
> > variable, we need to name every stored value.
>
> That doesn't matter to the tabbar code: the tab only ever needs 1 chunk of
> private data passed to the activate-function.  That chunk can be
> anything the activate-function needs: a struct, a list, an alist, you
> name it: the tabbar code has no business looking inside.
>

It is still a problem to clarify how to pass arguments to :INIT-FUNCTION,
:ACTIVATION-FUNCTION, :CLOSE-FUNCTION, etc.


> > This is a mistake in my code, it should not be . I forgot to call  a
> > (make-unbound 'sym)
>
> That doesn't solve the problem: it still affects the global variable
> `sym'.
>

Do not consider it , it's not important, forget about. It was my
implementation, that is not the best one, but it is minimal and it works. My
purpose was to make tabs that keeps window-configurations.



> >> The tabbar code doesn't need to care about what that value is, it just
> >> needs to store it and pass it along; the init-code and (de)activate
> >> functions will decide what to do with it.
> >> It can be a window-config or anything else.  That should make your
> >> environment business unnecessary.
> > Yes, if it is only 1 value, we know that it is on the first position of
> > private-data list, and can access it via cadr.
>
> "we" here would be the activate-function, right?
>

No. Forget about this.


>
> >> So it will need to change.  But does `make-tab' create a new tab or
> >> a tabbar?  If a tab, then I don't understand any more why the init-code
> >> is needed.
>
> > Yes, tabs must be separate from frames, and keep indepedent of every
> > other thing.  A frame/window can subscribe to tabs, and show them when
> > it is activated/etc.
>
> That doesn't answer my question: does `make-tab' create a new tab or
> a tabbar?
>

Your idea of (make-tab-bar PLACE) was very good. The tab bar existed without
initialization inside a frame.

[-- Attachment #2: Type: text/html, Size: 10489 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-09  8:26                             ` Alin Soare
@ 2010-12-10  3:35                               ` Stefan Monnier
  2010-12-10  8:15                                 ` Alin Soare
  2010-12-14 15:25                                 ` Alin Soare
  0 siblings, 2 replies; 34+ messages in thread
From: Stefan Monnier @ 2010-12-10  3:35 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

> This is a good idea, to clarify first the elisp interface.

> * TAB BAR

> **  (make-tab-bar PLACE)

> for now, suppose that PLACE can be a frame. In what I did, PLACE is only a
> frame.

OK.

> * TAB

> ** A TAB can be defined in many ways.

Could you mention at least the main ways?

> All tabs have in common a :NAME , and
> an :ID. :NAME is a string that is displayed on the display on the upperside
> of a frame, and :ID is a number that allows to user to easyly access it.
> Forget about :ID for now.

> ** A TAB also have an :INIT-CODE, a :ACTIVATE-FUNCTION, a
> :DEACTIVATE-FUNCTION, :CLOSE-FUNCTION:, hooks, and probably more.

> :INIT-CODE must be run to get some values that are useful for
> :ACTIVATE-FUNCTION, :DEACTIVATE-FUNCTION, etc.

Please throw away the :init-code since it's useless for the tab:
by the time the tab is created the init-code has been run already so it
doesn't need to be part of the tab.

What is needed is a :data element.

> *** EXAMPLE1  If I want a tab that keeps a window-configuration, than we
> need only 1 such variable: a #<window-configuration>. This is used by
> :ACTIVATE-FUNCTION, when one switched to that tab.

That window-config is the :data.  It will be passed as argument to
the :activate-function.

> *** EXAMPLE2 If I want to create a tab, which divides the frame in 2
> windows: the upper window switches to buffer "xyz", and the second window
> switches to buffer "*scratch". Then the INIT-CODE for THIS KIND OF TAB must
> ask you the name of buffer1, the name of buffer2, and keep these values into
> a place where these values are accessed ONLY BY :ACTIVATE-FUNCTION, and all
> other functions of this tab. So the :ACTIVATE-FUNCTION of the next tab (that
> probably keeps a window-configuration) MUST NOT SEE the  values kept by this
> tab. The :ACTIVATE-FUNCTION of this kind of tab must do something like

No difference here: the two buffers will be stored in the :data, e.g. as
a cons cell.  So the :activate-function will simply be:

   (lambda (data)
    ( delete-other-windows )
    (split-window-vertically)
    (balance-windows)
    (let ((buffer1 (car data))
           (buffer1 (cdr data))
    (switch-to-buffer buffer1)
    (other-window)
    (switch-to-buffer buffer2)
    (other-window) )

Look ma!  No get-variable mess!

> Here (get-variable "buffer")) looks in tabs' environment, and finds exactly
> the value it needs.

Right, but luckily we neither want nor need any of that get-variable madness.

>> > But the :initcode can be very useful, because a tab should be
>> > re-initialized sometimes.
>> That sounds odd.  When would that be?
> It is very useful. Consider that you have a tab (like in EXAMPLE2).
> You keep in the upper window the buffer "xyz", and in down window the buffer
> "*scratch*"
> But 1 hour later, you need to keep in upper window the buffer "abc" and down
> "*scratch*". You need to re-initialize the tab, and the :INIT-FUNCTION will
> read again the value of "buffer1" and buffer2.
> Instead of deleting the tab, and creating a new tab of the same type (that
> switches to a buffer), you simply re-initialize the tab.

That should not be in the tabbar code, it can easily be handled from
outside, by providing a function to modify (rather than add) a tab.
Such a function would also be useful/needed in order to do things like
"add a * to the tab of a buffer that's been modified".

>> >> So it will need to change.  But does `make-tab' create a new tab or
>> >> a tabbar?  If a tab, then I don't understand any more why the init-code
>> >> is needed.
>> > Yes, tabs must be separate from frames, and keep indepedent of every
>> > other thing.  A frame/window can subscribe to tabs, and show them when
>> > it is activated/etc.
>> That doesn't answer my question: does `make-tab' create a new tab or
>> a tabbar?
> Your idea of (make-tab-bar PLACE) was very good. The tab bar existed without
> initialization inside a frame.

Not sure why you don't want to answer the question directly, but IIUC
you're indirectly here saying that makr-tab indeed creates a tab rather
than a tabbar.

OK, I think I understand how your code is expected to work.  Now can
someone tell me how this fits in with the x-tabs and the
gtk-tabs branches?  We need to come up with an API (at the Elisp level)
that works for most/all of those: that doesn't means all 3 provide the
same API, but just that we can create a common API on top of them
without jumping through too many hoops.


        Stefan



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10  3:35                               ` Stefan Monnier
@ 2010-12-10  8:15                                 ` Alin Soare
  2010-12-10 20:13                                   ` Stefan Monnier
  2010-12-14 15:25                                 ` Alin Soare
  1 sibling, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-10  8:15 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 3662 bytes --]

> > :INIT-CODE must be run to get some values that are useful for
> > :ACTIVATE-FUNCTION, :DEACTIVATE-FUNCTION, etc.
>
> Please throw away the :init-code since it's useless for the tab:
> by the time the tab is created the init-code has been run already so it
> doesn't need to be part of the tab.
>
> What is needed is a :data element.
>

I agree. It is enough to keep an ordered list of values, and you can know
that the car is the value allocated to a given object, the cadr to another
value, etc.


>
> > *** EXAMPLE1  If I want a tab that keeps a window-configuration, than we
> > need only 1 such variable: a #<window-configuration>. This is used by
> > :ACTIVATE-FUNCTION, when one switched to that tab.
>
> That window-config is the :data.  It will be passed as argument to
> the :activate-function.
>

True. You did I understand what I meant.



>  > *** EXAMPLE2 If I want to create a tab, which divides the frame in 2
> > windows: the upper window switches to buffer "xyz", and the second window
> > switches to buffer "*scratch". Then the INIT-CODE for THIS KIND OF TAB
> must
> > ask you the name of buffer1, the name of buffer2, and keep these values
> into
> > a place where these values are accessed ONLY BY :ACTIVATE-FUNCTION, and
> all
> > other functions of this tab. So the :ACTIVATE-FUNCTION of the next tab
> (that
> > probably keeps a window-configuration) MUST NOT SEE the  values kept by
> this
> > tab. The :ACTIVATE-FUNCTION of this kind of tab must do something like
>
> No difference here: the two buffers will be stored in the :data, e.g. as
> a cons cell.  So the :activate-function will simply be:
>
>   (lambda (data)
>     ( delete-other-windows )
>    (split-window-vertically)
>    (balance-windows)
>     (let ((buffer1 (car data))
>           (buffer1 (cdr data))
>     (switch-to-buffer buffer1)
>    (other-window)
>    (switch-to-buffer buffer2)
>    (other-window) )
>
> Look ma!  No get-variable mess!
>

True.


>  > Here (get-variable "buffer")) looks in tabs' environment, and finds
> exactly
> > the value it needs.
>
> Right, but luckily we neither want nor need any of that get-variable
> madness.
>

True. If you keep the variables, you need not to wonder about the order.
With variables you can keep buffer2 on the first position of :data, and
buffer2 on the second, or vice versa. Or you can conceive :data as an
obarray, as I wanted initially.


>  >> >> So it will need to change.  But does `make-tab' create a new tab or
> >> >> a tabbar?  If a tab, then I don't understand any more why the
> init-code
> >> >> is needed.
> >> > Yes, tabs must be separate from frames, and keep indepedent of every
> >> > other thing.  A frame/window can subscribe to tabs, and show them when
> >> > it is activated/etc.
> >> That doesn't answer my question: does `make-tab' create a new tab or
> >> a tabbar?
> > Your idea of (make-tab-bar PLACE) was very good. The tab bar existed
> without
> > initialization inside a frame.
>
> Not sure why you don't want to answer the question directly, but IIUC
> you're indirectly here saying that makr-tab indeed creates a tab rather
> than a tabbar.
>

For me, make-tab adds an element to the list f->tab_bar_items, and
display_tab_bar will display the :name of that element on tab-bar.



>
> OK, I think I understand how your code is expected to work.  Now can
> someone tell me how this fits in with the x-tabs and the
> gtk-tabs branches?  We need to come up with an API (at the Elisp level)
> that works for most/all of those: that doesn't means all 3 provide the
> same API, but just that we can create a common API on top of them
> without jumping through too many hoops.
>

[-- Attachment #2: Type: text/html, Size: 5249 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10  8:15                                 ` Alin Soare
@ 2010-12-10 20:13                                   ` Stefan Monnier
  2010-12-10 21:09                                     ` Alin Soare
  0 siblings, 1 reply; 34+ messages in thread
From: Stefan Monnier @ 2010-12-10 20:13 UTC (permalink / raw)
  To: Alin Soare; +Cc: Emacs Dev

> True. If you keep the variables, you need not to wonder about the order.
> With variables you can keep buffer2 on the first position of :data, and
> buffer2 on the second, or vice versa. Or you can conceive :data as an
> obarray, as I wanted initially.

The :data solution still allows that: the data can be a defstruct
(hence named slots), a has-table, or an obarray if you so wish.

>> >> >> So it will need to change.  But does `make-tab' create a new tab or
>> >> >> a tabbar?  If a tab, then I don't understand any more why the
>> init-code
>> >> >> is needed.
>> >> > Yes, tabs must be separate from frames, and keep indepedent of every
>> >> > other thing.  A frame/window can subscribe to tabs, and show them when
>> >> > it is activated/etc.
>> >> That doesn't answer my question: does `make-tab' create a new tab or
>> >> a tabbar?
>> > Your idea of (make-tab-bar PLACE) was very good. The tab bar existed
>> without
>> > initialization inside a frame.
>> 
>> Not sure why you don't want to answer the question directly, but IIUC
>> you're indirectly here saying that makr-tab indeed creates a tab rather
>> than a tabbar.
> For me, make-tab adds an element to the list f->tab_bar_items, and
> display_tab_bar will display the :name of that element on tab-bar.

That's called "adds a tab to the tabbar".


        Stefan



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10 20:13                                   ` Stefan Monnier
@ 2010-12-10 21:09                                     ` Alin Soare
  2010-12-10 21:23                                       ` Davis Herring
  0 siblings, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-10 21:09 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 770 bytes --]

>
>
> The :data solution still allows that: the data can be a defstruct
> (hence named slots), a has-table, or an obarray if you so wish.
>

I do not like to insert in elisp clisp stuff. That is why I did not want to
think in clisp .

I prefer all the time the style of Ben Bitdiddle.

If, in my loss of knowledge , emacs can make lexical scope, how do you
re-write this chunk of Scheme code in elisp ?



(define (create-tab x)
  (lambda (m)
    (cond ((equal? m ':init)
       (display (string-append x ":init") ) )
      ((equal? m ':activate)
       (display (string-append x ":activate") ) ) ) ) )

(define tab (create-tab "tab1"))

(tab ':init)

(tab ':activate)



Alin

----

Wenn ich 'Kultur' höre, nehme ich meine Pistole.

[-- Attachment #2: Type: text/html, Size: 1151 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10 21:09                                     ` Alin Soare
@ 2010-12-10 21:23                                       ` Davis Herring
  2010-12-10 21:34                                         ` Alin Soare
  0 siblings, 1 reply; 34+ messages in thread
From: Davis Herring @ 2010-12-10 21:23 UTC (permalink / raw)
  To: Alin Soare; +Cc: Stefan Monnier, Emacs Dev

> If, in my loss of knowledge , emacs can make lexical scope, how do you
> re-write this chunk of Scheme code in elisp ?
>
> (define (create-tab x)
>   (lambda (m)
>     (cond ((equal? m ':init)
>        (display (string-append x ":init") ) )
>       ((equal? m ':activate)
>        (display (string-append x ":activate") ) ) ) ) )

In the absence of lexbind, just put ` before the (lambda and , before each x.

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10 21:23                                       ` Davis Herring
@ 2010-12-10 21:34                                         ` Alin Soare
  2010-12-12 20:02                                           ` Alin Soare
  0 siblings, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-10 21:34 UTC (permalink / raw)
  To: herring; +Cc: Stefan Monnier, Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 745 bytes --]

2010/12/10 Davis Herring <herring@lanl.gov>

> > If, in my loss of knowledge , emacs can make lexical scope, how do you
> > re-write this chunk of Scheme code in elisp ?
> >
> > (define (create-tab x)
> >   (lambda (m)
> >     (cond ((equal? m ':init)
> >        (display (string-append x ":init") ) )
> >       ((equal? m ':activate)
> >        (display (string-append x ":activate") ) ) ) ) )
>
> In the absence of lexbind, just put ` before the (lambda and , before each
> x.
>
>

(defun create-tab (x)
  `(lambda (m)
    (cond ((equal m ':init)
       (message (concat ,x ":init") ) )
      ((equal m ':activate)
       (message (concat ,x ":activate") ) ) ) ) )

(setq tab (create-tab "xxx"))

(funcall tab :init)


LOL. It works :).

Alin

[-- Attachment #2: Type: text/html, Size: 1274 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10 21:34                                         ` Alin Soare
@ 2010-12-12 20:02                                           ` Alin Soare
  2010-12-13 17:23                                             ` Stefan Monnier
  0 siblings, 1 reply; 34+ messages in thread
From: Alin Soare @ 2010-12-12 20:02 UTC (permalink / raw)
  To: herring, rms, Stefan Monnier, Andreas Schwab, martin rudalics,
	Dimitri Fontaine
  Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 785 bytes --]

> Not sure why you don't want to answer the question directly, but IIUC
> you're indirectly here saying that makr-tab indeed creates a tab rather
> than a tabbar.
>
> OK, I think I understand how your code is expected to work.  Now can
> someone tell me how this fits in with the x-tabs and the
> gtk-tabs branches?  We need to come up with an API (at the Elisp level)
> that works for most/all of those: that doesn't means all 3 provide the
> same API, but just that we can create a common API on top of them
> without jumping through too many hoops.
>
>
So, can I start completing the code of tabs as we discussed in the previous
messages ?

Do you have some more suggestions ?

Do my implementation integrate with the others implementations of tabs ? If
not, what can I do ?


Alin

[-- Attachment #2: Type: text/html, Size: 1063 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-12 20:02                                           ` Alin Soare
@ 2010-12-13 17:23                                             ` Stefan Monnier
  2010-12-13 21:01                                               ` Alin Soare
  0 siblings, 1 reply; 34+ messages in thread
From: Stefan Monnier @ 2010-12-13 17:23 UTC (permalink / raw)
  To: Alin Soare
  Cc: rms, Emacs Dev, martin rudalics, Andreas Schwab, Dimitri Fontaine

> Do my implementation integrate with the others implementations of tabs?

I don't know, you'll have o investigate.

> If not, what can I do ?

Try and figure out how to change your approach and/or theirs so that they
can be made compatible.


        Stefan



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-13 17:23                                             ` Stefan Monnier
@ 2010-12-13 21:01                                               ` Alin Soare
  0 siblings, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-13 21:01 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: rms, Emacs Dev, martin rudalics, Andreas Schwab, Dimitri Fontaine

[-- Attachment #1: Type: text/plain, Size: 1634 bytes --]

>
>
>
> Try and figure out how to change your approach and/or theirs so that they
> can be made compatible.
>
>
>
For me integrating with the work of the others is quite evident.

I do not open now the manual of GTK/Xlib/Athena to exress myself in exact
terms, but I use generic terms, that I believe all X-windows programmers
understand.

To integrate my work with the others one does so:

1. keep from the work of the others the graphical representations (of the
notebook widget).

2. Every element of a notebook widget represent a tab, that has a pointer to
a data structure. I did not look over the code of the others, but I believe
that in their code this data structure is a frame. Drop that structure , and
replace it with the data structure <<tab>> that I explained in my previous
messages. I prefer the message passing style, that cannot be implemented in
emacs in this moment, apart from using macros, which are not a viable/smart
solution.

3. In X windows, every widget generates events. When such an event X comes
to a tab, execute the (tab :event-X), which is a lambda-expression.

4. Breef, from the work of the others , 1) keep the graphical
representations of notebook widget. 2) drop the data structure that
represents a tab and replace it with my data structure.

I do not know whether the others well see my solution, but I do not have any
other way to see the problem of integration.

What the other say ?

Thanks.


Alin












2010/12/13 Stefan Monnier <monnier@iro.umontreal.ca>

> > Do my implementation integrate with the others implementations of tabs?
>
> I don't know, you'll have o investigate.
>
>

[-- Attachment #2: Type: text/html, Size: 2303 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fwd: Tabs for console.
  2010-12-10  3:35                               ` Stefan Monnier
  2010-12-10  8:15                                 ` Alin Soare
@ 2010-12-14 15:25                                 ` Alin Soare
  1 sibling, 0 replies; 34+ messages in thread
From: Alin Soare @ 2010-12-14 15:25 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs Dev

[-- Attachment #1: Type: text/plain, Size: 340 bytes --]

Note that the functions provided by desktop.el can be implemented with a
kind of tab that I could call "saved desktop".

:init of this kind of tab looks for a saved file of configuration and
restores it

:deactivate saves the current configuration

:activate restores the config

:close asks whether to save the config into a file



Alin.

[-- Attachment #2: Type: text/html, Size: 404 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Tabs for console
@ 2010-12-21  1:14 Richard Stallman
  0 siblings, 0 replies; 34+ messages in thread
From: Richard Stallman @ 2010-12-21  1:14 UTC (permalink / raw)
  To: emacs-devel

Could someone please look at Alin Soare's tabs code and
give him feedback?

-- 
Richard Stallman
President, Free Software Foundation
51 Franklin St
Boston MA 02110
USA
www.fsf.org, www.gnu.org



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Tabs for console.
  2010-11-08 19:51     ` Alin Soare
       [not found]       ` <AANLkTim8BoGpECQUUNfPidbn2k_HP77sykR=HYqw9BOE@mail.gmail.com>
@ 2011-03-11  8:52       ` A Soare
  1 sibling, 0 replies; 34+ messages in thread
From: A Soare @ 2011-03-11  8:52 UTC (permalink / raw)
  To: emacs-devel


I wish to re-open the patch for tabs for console.

Does somebody want to help me to finish it , please ?


Alin.






^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2011-03-11  8:52 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <AANLkTim8zuFRh2L81g9KgtDon=U5Mvr+QO+HWGE1nqXP@mail.gmail.com>
2010-10-27 16:39 ` Fwd: Tabs for console Alin Soare
2010-11-08 19:22   ` Stefan Monnier
2010-11-08 19:51     ` Alin Soare
     [not found]       ` <AANLkTim8BoGpECQUUNfPidbn2k_HP77sykR=HYqw9BOE@mail.gmail.com>
     [not found]         ` <AANLkTinPBfV8OC7d9qOBWGW6130D2nXjg+=Nv2rKqMr1@mail.gmail.com>
     [not found]           ` <jwvhbewqnjj.fsf-monnier+emacs@gnu.org>
2010-12-02 22:43             ` Alin Soare
2010-12-02 22:45               ` Alin Soare
2010-12-03  8:19                 ` martin rudalics
2010-12-03  9:37                 ` Andreas Schwab
2010-12-04 21:48                   ` Alin Soare
2010-12-03  9:52                 ` Andreas Schwab
2010-12-03 11:11                   ` Alin Soare
2010-12-03 12:29                     ` Dimitri Fontaine
2010-12-04 21:42                       ` Alin Soare
2010-12-04 21:55                       ` Alin Soare
2011-03-11  8:52       ` A Soare
     [not found]     ` <AANLkTikwua2bfyvJkt+sn2vR_CzTZA6Hs0Lw=NJSVwT4@mail.gmail.com>
     [not found]       ` <jwvd3peoig0.fsf-monnier+emacs@gnu.org>
     [not found]         ` <AANLkTikPRKbvq0mg2X1Huio1z5sF3UvF6+cpT10mH-H-@mail.gmail.com>
     [not found]           ` <jwvzksilkfd.fsf-monnier+emacs@gnu.org>
     [not found]             ` <AANLkTi=MiubmGJ_Gk9OVzHY7uc+DOkHHpj5Ht+j7uNx8@mail.gmail.com>
     [not found]               ` <jwvtyiqk2al.fsf-monnier+emacs@gnu.org>
     [not found]                 ` <AANLkTi=0g00xn2P_yKE0gGkH-ZaZSvz+8yY=yy2=-6W=@mail.gmail.com>
     [not found]                   ` <jwvsjyai7lv.fsf-monnier+emacs@gnu.org>
2010-12-07  4:47                     ` Fwd: " Alin Soare
2010-12-07  4:50                       ` Alin Soare
2010-12-07 17:06                       ` Stefan Monnier
2010-12-08  8:14                         ` Alin Soare
     [not found]                           ` <AANLkTikaXr_4bVR2_v7HVFfPB93Sw10e63cKqTRwOunS@mail.gmail.com>
2010-12-08 11:16                             ` Alin Soare
2010-12-09  4:29                           ` Fwd: " Stefan Monnier
2010-12-09  8:26                             ` Alin Soare
2010-12-10  3:35                               ` Stefan Monnier
2010-12-10  8:15                                 ` Alin Soare
2010-12-10 20:13                                   ` Stefan Monnier
2010-12-10 21:09                                     ` Alin Soare
2010-12-10 21:23                                       ` Davis Herring
2010-12-10 21:34                                         ` Alin Soare
2010-12-12 20:02                                           ` Alin Soare
2010-12-13 17:23                                             ` Stefan Monnier
2010-12-13 21:01                                               ` Alin Soare
2010-12-14 15:25                                 ` Alin Soare
2010-10-27 20:34 ` Alin Soare
2010-10-29  7:49 Alin Soare
  -- strict thread matches above, loose matches on Subject: below --
2010-12-21  1:14 Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).