unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* XPM via Lisp in the toolbar
@ 2002-11-12 17:32 Oliver Scholz
  2002-11-13 17:15 ` Oliver Scholz
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Oliver Scholz @ 2002-11-12 17:32 UTC (permalink / raw)


Some time ago I posted a library to deal with XPM images (internally:
convert them to PPM) to this group. I am currently working on this
again and at the same time I am hooking this library into the
functions that deal with images in general (mainly `create-image' and
`find-image'). The goal of the latter is that Emacs would support XPM
transparently wether it was compiled with xpmlib or not. I understood
that this was considered to be useful. My original purpose was to make
only gamegrid.el DTRT when Emacs was compiled without XPM support.

Now tool-bar.el uses `find-image' to find the appropriate image type
-- so far either XPM, PBM or XBM. With xpm.el hooked in, Emacs tries
to convert the icon in XPM format and put it on the tool-bar. I would
consider this as a feature, but: I am currently using MS Windows XP
and I noticed that the :mask property is not supported for images on
the toolbar. Images don't work properly on XP in general, but in the
normal case the image is displayed only with false colours. On the
toolbar they don't show up at all. This leads to a "tool-bar" which is
unusable.

So is this going to be fixed? The image support on MS Windows needs
some bug fixes anyways, but at least the toolbar currently works (with
the PBM icons). Or should I disable my stuff for toolbar-icons in
general?

    Oliver
-- 
22 Brumaire an 211 de la Révolution
Liberté, Egalité, Fraternité!

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

* Re: XPM via Lisp in the toolbar
  2002-11-12 17:32 XPM via Lisp in the toolbar Oliver Scholz
@ 2002-11-13 17:15 ` Oliver Scholz
  2002-11-15  2:36   ` Richard Stallman
  2002-11-14  4:10 ` Richard Stallman
  2002-11-15 17:47 ` W32 image patch (was Re: XPM via Lisp in the toolbar) Jason Rumney
  2 siblings, 1 reply; 21+ messages in thread
From: Oliver Scholz @ 2002-11-13 17:15 UTC (permalink / raw)


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

Oliver Scholz <alkibiades@gmx.de> writes:

> Some time ago I posted a library to deal with XPM images (internally:
> convert them to PPM) to this group. I am currently working on this
> again [...]

Maybe I should post my code, too (attached). I am finished with xpm.el
so far, except that I yet have to check whether transparency does work
on the X Windowing system -- it sure does not work on MS Windows XP.

So far my code provides a function `xpm-create-image' that returns an
image descriptor. This image descriptor contains a string containing
PPM image data as the value of the :data attribute and a value for the
:mask attribute that matches pixels for which the XPM image specified
transparency. Thus Emacs should be able to display the image correctly
if it has proper image support at all.

The question remains how to hook this into the rest of Emacs. The
simple way would be to do nothing but add this package (provided that
you like it, of course). Then packages like gamegrid could use
`xpm-create-image' directly. But this would lead to Emacs supporting
XPM in some cases and in other cases not.

Or I could hook `xpm-create-image' into the appropriate functions in
image.el. I have already done the work needed, save some more
extensive testing. Emacs would then always support XPM, albeit a
little bit slower if it was not compiled with support for XPM on the C
level. I think this is nicer and more consistent. But what to do with
the tool bar? On MS Windows this breaks the tool bar totally. And
whether the additional delay at startup is endurable or not is another
question. It is not notable on my new computer, but it might be on
older machines (I don't know). The delay at startup would not be an
issue anymore, of course, if we convert the XPM icons in lisp/toolbar/
to PPM as Dave Love suggested.

Or I could add a caching mechanism to toolbar.el so that the
conversion happens only once. This would allow to keep the XPM icons
and get rid of the PBM icons instead, because the XPM format allows to
tweak the image for different display types.


[-- Attachment #2: xpm.el --]
[-- Type: application/emacs-lisp, Size: 19938 bytes --]

[-- Attachment #3: Type: text/plain, Size: 121 bytes --]


xpm.el needs another package named state-m.el that provides an easy
way to write a state machine for reader functions:


[-- Attachment #4: state-m.el --]
[-- Type: application/emacs-lisp, Size: 24079 bytes --]

[-- Attachment #5: Type: text/plain, Size: 52 bytes --]


Patch for lispref/text.texi regarding state-m.el:


[-- Attachment #6: text.diff --]
[-- Type: text/x-patch, Size: 22395 bytes --]

Index: lispref/text.texi
===================================================================
RCS file: /cvsroot/emacs/emacs/lispref/text.texi,v
retrieving revision 1.57
diff -c -r1.57 text.texi
*** lispref/text.texi	13 Sep 2002 19:36:55 -0000	1.57
--- lispref/text.texi	7 Nov 2002 17:34:11 -0000
***************
*** 59,64 ****
--- 59,65 ----
  * Base 64::          Conversion to or from base 64 encoding.
  * MD5 Checksum::     Compute the MD5 ``message digest''/``checksum''.
  * Change Hooks::     Supplying functions to be run when text is changed.
+ * State Machines::   Writing reader functions.
  @end menu
  
  @node Near Point
***************
*** 3779,3781 ****
--- 3780,4267 ----
  
  This variable is available starting in Emacs 21.
  @end defvar
+ 
+ @node State Machines
+ @section Writing simple reader functions
+ @cindex state machines
+ 
+ A state machine is a model to describe complex control structures.  A
+ state machine is always in a certain state, it receives some input,
+ possibly generates some output, then it switches to another state,
+ where it repeats.
+ 
+ State machines are useful in a wide range of computing tasks.  In fact
+ a computer itself is only a very complex state machine.  One area,
+ however, where they are frequently used, is for reading and parsing
+ textual input.  Emacs provides the macro @code{run-state-machine} to
+ construct state machines for the purpose of reading text from a
+ buffer.
+ 
+ @menu
+ * State Machine Basics::     A short introduction to state machines.
+ * Example State Machine::    A basic example.
+ * Defining State Machines::  Defining state machines for reader 
+                              functions.
+ * Character Based Reading::  Switching states based on the character
+                              after point.
+ * Regexp Based Reading::     Switching states based on the buffer text
+                              after point.
+ * State Machine Notes::      Caveats and notes on performance.
+ @end menu
+ 
+ @node State Machine Basics
+ @subsection State Machines -- an Introduction
+ 
+ A traffic light may serve as a very basic example of a state
+ machine.  It has four states: a red state, a green state and two yellow
+ states.  There is one single input event, the signal ``Change the
+ colour now!''.  As ``output'' it turns certain electric bulbs on or
+ off.
+ 
+ @example
+ @group
+              +-------+
+     ,--------|  red  |<-------.
+     |        +-------+        |
+     |                         |
+     |                         |
+     v                         |
+ +-------+                 +-------+
+ |yellow1|                 |yellow2|
+ +-------+                 +-------+
+     |                         ^
+     |                         |
+     |        +-------+        |
+     `------->| green |--------´
+              +-------+
+ @end group
+ @end example
+ 
+ When a state machine receives input, it decides which state should be
+ the next state.  In a traffic light this decision is very simple,
+ because in each state there is only one type of input event and one
+ transition to another state possible: when the traffic light is in the
+ state ``red'' and it receives valid input, it switches to the state
+ ``yellow1'' unconditionally.  A more complex state machine would allow
+ more types of input events and would depend the decision about the
+ next state not only on the current state, but also on the
+ @emph{specific} input event.  A state machine that is made to read
+ textual input would typically depend the switching to the next state
+ on the actual character it received.
+ 
+ The way we describe the traffic light above, we assume that it was
+ always running and that it will run forever.  This is, of course, also
+ not true for a reader.  Most state machines would define one state as a
+ starting state and one or more states as final ones; so that the state
+ machine terminates after switching to a state declared to be a final
+ one.
+ 
+ @node Example State Machine
+ @subsection A Basic Example of a State Machine
+ 
+ The macro @code{run-state-machine} provides an easy way to define and
+ run state machines in Emacs Lisp for the purpose of reading input from
+ a buffer.  Here is a basic usage example as an introduction.
+ 
+ Suppose we need a function that parses the content of a buffer for
+ strings.  Each time we call this function, it should scan the buffer
+ for a quotation mark and return the buffer content up to the next
+ quotation mark, thereby moving point forward.  We could use this
+ function to get every string from the buffer if we call it often
+ enough.  Here is how it could be done with @code{run-state-machine}:
+ 
+ @lisp
+ @group
+ (defun read-next-string ()
+   (run-state-machine ()
+     (look-for-string (?\" nil t read-string)
+ 		     (t   nil t look-for-string))
+     (read-string (?\" nil t exit)
+ 		 (t   t   t read-string))))
+ @end group
+ @end lisp
+ 
+ This state machine has only two states, @code{look-for-string} and
+ @code{read-string}.  In each state the machine looks at the character
+ after point and decides whether it should stay in the same state or
+ switch to another one.  In both cases, however, it moves point forward
+ by one character.  The possible transitions to other states are
+ defined as lists after the name of the state.  Here each state has two
+ of them.
+ 
+ The starting state is @code{look-for-string}, because it is the first
+ one listed.  When the machine is in the state @code{look-for-string},
+ it checks wether the character after point is a @samp{"}.  This is
+ indicated by the @code{?\"} at the beginning of the first transition.
+ If it is, it switches to the state @code{read-string}.  If the
+ character after point is anything else but a @samp{"} (indicated by
+ the symbol @code{t} at the beginning of the second transition), the
+ machine stays in the state @code{look-for-string}.
+ 
+ When the state machine is in the state @code{read-string} it checks
+ again wether the character after point is a @samp{"}.  But this time
+ it terminates if it is.  This is specified by the special state name
+ @code{exit}.  In all other cases the string it currently reads is not
+ finished, so the machine stays it in the the state @code{read-string}.
+ 
+ On each transition to another state the state machine may store the
+ character after point internally.  The concatentation of all stored
+ characters is the return value of @code{run-state-machine}.  The
+ second element in the definition of a transition specifies if the
+ character after point should be appended to the return value in this
+ way or not.  In our example it is t only in the second transition of
+ @code{read-string}, because we want to return only characters between
+ two @samp{"}.  The third element indicates if the state machine should
+ move point forward in the buffer; here it is @code{t} in all
+ transitions.
+ 
+ This is a diagram of the states and transitions:
+ @example
+ @group
+                           Start
+                             |
+                             |
+                             |
+                             v
+                     +-------------------+
+                     |look-for-string    |<---.  Character is not a
+                     +-------------------+    |  quotation mark.
+                             |     |          |  * Do not store it.
+       Character is a        |     `----------´  * Move point forward.
+       quotation mark.       |
+       * Do not store it.    |
+       * Move point forward. |
+                             v
+                     +-------------------+
+                     |read-string        |<---.  Character is not a
+                     +-------------+-----+    |  quotation mark.
+                             |     |          |  * Store it.
+       Character is a        |     `----------´  * Move point forward.
+       quotation mark.       |
+       * Do not store it.    |
+       * Move point forward. |
+                             v
+                           Exit
+ @end group
+ @end example
+ 
+ @node Defining State Machines
+ @subsection Defining State Machines
+ @cindex writing a reader
+ 
+ The macro @code{run-state-machine} provides a mini-language to define
+ state machines for reader-functions.  To define a state machine, you
+ basically list a bunch of states and specify what the machine should
+ do in the different states by listing and defining the transitions
+ from each state to following ones.  This is explained in more detail
+ in @ref{Character Based Reading} and @ref{Regexp Based Reading}.
+ 
+ @deffn Macro run-state-machine spec &rest states
+ This macro defines and executes a state machine.
+ 
+ On each transition from one state to the next one the state machine
+ may accumulate characters or strings from the current buffer.  When
+ the machine terminates, it returns these per default as a concatenated
+ string; it returns @code{nil}, when no characters or strings were
+ accumulated.
+ 
+ The first argument @var{spec}, if non-@code{nil}, is a list of the
+ form
+ 
+ @example
+ (@var{result-variable} @var{end-of-buffer-expression}).
+ @end example
+ 
+ @var{result-variable} should be a symbol or @code{nil}.  The symbol is
+ used as the name of the variable that the state machine uses to store
+ its return value at run time.  Specify a symbol, if you want to access
+ this variable.  If you are not interested in what variable name the
+ state machine uses internally, specify @code{nil}.  In this case the
+ state machine still returns the accumulated characters or strings, but
+ it deals with them transparently.  Please note, that specifying a
+ symbol might not be necessary in many cases, because you can also
+ control the return value to a large extend by specifying a function as
+ @var{add-to-result} in the definition of a transition (see below).
+ 
+ When a state machine encounters the end of the buffer at run time, it
+ terminates and returns @code{nil} by default.  To change the
+ return-value, you can specify a Lisp expression as
+ @var{end-of-buffer-expression} that is executed in this case; the
+ return value of this expression becomes the return value of the state
+ machine.  To return the accumulated result in whatever state it may be
+ at that time, simply set @var{result-variable} to some symbol and
+ repeat that symbol as @var{end-of-buffer-expression}.  For example,
+ @code{(output output)} as @var{spec} leads to a state machine that
+ uses the variable @var{output} to store the result and returns the
+ value of @var{output} unmodified, when it terminates at the end of the
+ buffer.
+ 
+ @var{spec} may be @code{nil}.  This is equivalent to @code{(nil nil)}.
+ @var{spec} is followed by a number of one or more definitions of
+ states.
+ 
+ The definition of a state consists of the name of the state followed
+ by one or more definitions of transitions to following states.  The
+ starting state is always the first one listed.  Specifying the state
+ name @code{exit} as the following state in a transition means to
+ terminate processing; you can't define a state named @code{exit}.
+ 
+ A transition is a list of the form
+ 
+ @example
+ (@var{matcher} @var{add-to-result} @var{advance} @var{next-state})
+ @end example
+ 
+ @var{matcher} may be either a regular expression (@pxref{Regexp Based Reading}).
+ Or a single character (@pxref{Character Type}), a cons cell
+ of two characters indicating a range of characters or a list of
+ characters or character ranges indicating character
+ alternatives. @xref{Character Based Reading}.
+ 
+ If @var{add-to-result} is @code{t}, the character after point is
+ appended to the return-value (which--in the normal case--is a string).
+ If @var{advance} is @code{t}, the machine moves point forward by one
+ character.  Then it switches to the state specified by
+ @var{next-state}.  If @var{matcher} is a regular expression,
+ @var{add-to-result} and @var{advance} may be integers.  In this case
+ the integer specifies the subexpression of @var{matcher} which should
+ be added to the result or to whose end point should move,
+ respectively. @xref{Regexp Based Reading}.
+ 
+ @var{add-to-result} may be a function.  In this case the function
+ should take two arguments.  The first one being the current
+ return-value and the second one being the pending input-character (as
+ a string!).  The return value of the state machine is then set to the
+ value returned by this function.  If @var{advance} is a function, it
+ receives no argument.  This function takes the full resposibility for
+ moving point.  For example a transition
+ @code{(?a t t another-state)}
+ could be written equivalently (modulo performance) as
+ @code{(?a concat forward-char another-state)}.
+ @end deffn
+ 
+ @node Character Based Reading
+ @subsection Switching States Based on the Character after Point
+ 
+ In character-based reading, a state machine specified with
+ @code{run-state-machine} switches states based on the character after
+ point.
+ 
+ In the simple case @var{matcher} is either a character or the symbol
+ @code{t}.  To find the right transition, the state machine looks for a
+ transition whose @var{matcher} is @code{eq} to the character after
+ point.  If it finds none, it looks for a transition whose @var{matcher}
+ is @code{t}.
+ 
+ For example, a state could look like this:
+ 
+ @example
+ @group
+ ;;           MATCHER ADD-TO-RESULT ADVANCE NEXT-STATE
+ (look-for-a (?a      t             t       another-state-1)
+             (t       nil           nil     another-state-2))
+ @end group
+ @end example
+ 
+ When the state machine is in the state @code{look-for-a}, it checks if
+ the character after point is an @samp{a}.  If it is, it adds an
+ @samp{a} to the return value, moves point forward and switches to the
+ state @code{another-state-1}.  Else, it does not add anything to the
+ return value, leaves point where it is and switches to the state
+ @code{another-state-2}.
+ 
+ You can specify alternative characters or a range of characters as
+ @var{matcher} in a transition.  To specify a range of characters,
+ define a cons cell of the first and the last character.  @code{(?a
+ . ?z)} as @var{matcher} matches all characters from @samp{a} up to
+ @samp{z}.  To specify alternative matches, use a list of characters or
+ of character ranges.  For example @code{(?a ?b ?c)} as @var{matcher}
+ matches the characters @samp{a}, @samp{b} or @samp{c}, while
+ @code{((?0 . ?9) ?-)} matches digits and hyphens.
+ 
+ As an extended example, here is the definition of a reader-function
+ @code{example-reader} that returns everything inside @samp{"} as a
+ string, digits as integers and everything else as a symbol.  Each time
+ the function is called it reads the next object from the current
+ buffer and returns it according to its type.  If it encounters the end
+ of the buffer, it raises an error.
+ 
+ @smalllisp
+ @group
+ (defun exmpl-make-number (output ignore)
+   (string-to-number output))
+ @end group
+ 
+ @group
+ (defun exmpl-make-symbol (output ignore)
+   (make-symbol output))
+ @end group
+ 
+ @group
+ (defun example-reader ()
+   (run-state-machine (nil (error "End of buffer"))
+     ;; @r{Starting state.}
+     (start (?\" nil t read-string)
+            ((?0 . ?9) t t read-integer)
+            ((?\n ?\t ?\ ) nil t skip-white-space)
+            (t t t read-symbol))
+     ;; @r{Skip white-space}
+     (skip-white-space ((?\t ?\n ?\ ) nil t skip-white-space)
+                       (t nil nil start))
+     ;; @r{Read a string: add everything to the return value up to the}
+     ;; @r{next `"'.  Then exit.}
+     (read-string (?\" nil t exit)
+                  (t t t read-string))
+     ;; @r{Read an integer: add every digit to the return value.  Every}
+     ;; @r{other character causes the machine to exit.  Convert the}
+     ;; @r{return-value to an integer upon exit.}
+     (read-integer ((?0 . ?9) t t read-integer)
+                   (t exmpl-make-number nil exit))
+     ;; @r{Read a symbol: read everything which is not a digit, a `"' or a}
+     ;; @r{white-space character.  Return a symbol.}
+     (read-symbol ((?\" ?\  ?\t ?\n (?0 . ?9))
+                   exmpl-make-symbol nil exit)
+                  (t t t read-symbol))))
+ @end group
+ @end smalllisp
+ 
+ @node Regexp Based Reading
+ @subsection Switching States Based on the Buffer Text after Point
+ 
+ Instead of a character (or a list of character-alternatives) or the
+ symbol @code{t}, @var{matcher} may be a regular expression.
+ @xref{Regular Expressions}.  In this case the state machine checks for
+ a matching transition by applying the regexp with @code{looking-at} to
+ the text after point.
+ 
+ When @var{matcher} is a regexp @var{add-to-result} and @var{advance}
+ may be integers.  An integer as @var{add-to-result} specifies the
+ subexpression which is added to the return-value.  An integer as
+ @var{advance} specifies to the end of which subexpression point should
+ move.  In both cases @code{t} is interpreted as @code{0}.
+ 
+ As an example, suppose we have a silly database file in which we store
+ information about persons, animals and text editors.  Now we want to
+ extract the names of persons by consecutive calls to a function
+ @code{read-person-name}; i. e. the function should skip the records
+ for animals and text editors as well as records for persons where the
+ name field is omitted.  The entries could look like this:
+ 
+ @example
+ @group
+ Type Animal
+ Name Frog
+ Colour Green
+ @end group
+ 
+ @group
+ Type Person
+ # name unknown
+ Colour Red # colour of hair
+ Number 12345 # postal code
+ @end group
+ 
+ @group
+ Type Text-Editor
+ # The One True Editor
+ Name Emacs
+ Number 21.4 # version
+ @end group
+ 
+ @group
+ Type Person
+ Name Tars Tarkas # This is the name we want.
+ Colour Green
+ @end group
+ 
+ @end example
+ 
+ To simplify things, we assume that the entry for each field is on a
+ line of it's own, so we can do the parsing line-wise.  Fields may
+ occur in abitrary order, except for the @samp{type} field, which must
+ be the first field in the record.  Each record starts with a
+ declaration of the @samp{type}; @samp{#}s are comment-characters;
+ empty lines and leading whitespace are legal, but not significant;
+ case is also insignificant.
+ 
+ @lisp
+ @group
+ (defun read-person-name ()
+   "Read the next name in the category \"Person\"."
+   (let ((case-fold-search t)) ; ignore case
+     (run-state-machine ()
+       (look-for-person
+        ("\\s-*type\\s-+person" nil forward-line get-name) ; @r{person found}
+        (t nil forward-line look-for-person)) ; @r{keep on searching}
+       (get-name
+        ("\\s-*type" nil nil look-for-person) ; @r{no name was provided}
+        ("\\s-*name\\s-+\\(.*?\\)\\s-*#.*$" 1 forward-line exit) ; @r{name found}
+        (t nil forward-line get-name))))) ; @r{keep on searching}
+ @end group
+ @end lisp
+ 
+ This function parses the text line by line, because @var{advance} is
+ either @code{nil} or the function @code{forward-line}; one effect of
+ this is that all the regular expressions match from the beginning of
+ the line.  When it is in the state @code{look-for-person} the function
+ moves forward in the buffer until it finds a record that starts with
+ @samp{type person}.  Then it switches to the state @code{get-name}.
+ Again it moves point forward line by line until it finds a @samp{name}
+ field.  When it finds one, the state machine terminates and returns
+ the name; this happens in the second transition of @code{get-name}:
+ the regexp is constructed in such a way that characters after
+ @samp{name} and before any @samp{#} match the first subexpression,
+ which is added to the return value, because @var{add-to-result} is
+ @code{1} in this transition.
+ 
+ But when the state machine encounters another @samp{type} field
+ indicating a new record before it finds a name, it switches back to
+ the state @code{look-for-person}.  This is specified in the first
+ transition of @code{get-name}. (@var{advance} is @code{nil} here,
+ because @samp{type} could be @samp{person} again.  Then the state
+ @code{look-for-person} should switch back to @code{get-name}
+ immediately.) So if point is at the beginning of the first record in
+ the example (@samp{Type Animal}), the first call to
+ @code{read-person-name} will return @samp{"Tars Tarkas"}, although
+ there is another person in between.  But this other record provides no
+ name and is therefore ignored.
+ 
+ @node State Machine Notes
+ @subsection Caveats and Notes on Performance
+ 
+ @enumerate
+ 
+ @item
+ Although it is possible to apply both transitions with regular
+ expressions and with characters as @var{matcher} in one and the same
+ state machine, this might add some undesirable additional overhead,
+ especially if the majority of transitions has characters as
+ @var{matcher}.  In this case it might be worth the extra effort to get
+ rid of regexp entirely for the sake of performance.  This is due to
+ the internal handling of the transitions.  As far as this note is
+ concerned, character alternatives and character ranges count as
+ @var{matcher} of the type ``character''.
+ 
+ @item
+ The checking for transitions with regexps as @var{matcher}, characters
+ as @var{matcher} and the default transitions is done independently and
+ in this order: regexps first, defaults last.
+ 
+ @item
+ The order of transitions in the definition of a state is significant.
+ If any two transitions whose @var{matcher} is of the same type would
+ match in the current current buffer, the state machine chooses the
+ transition that comes first in the state-definition.  For example if
+ one transition has @code{?y} as @var{matcher} and another transition
+ has @code{(?a . ?z)} as @var{matcher} and the character after point is
+ a @samp{y}, then the transition that comes first in the definition of
+ the state is chosen.  @emph{But}: regexps as @var{matcher} come always
+ before characters as @var{matcher} and defaults come always last,
+ regardless of where they were defined.
+ 
+ @item
+ The macro @code{run-state-machine} does quite some computation on each
+ expansion.  Therefore it is strongly recommended to byte-compile a
+ package that uses it.
+ 
+ @end enumerate

[-- Attachment #7: Type: text/plain, Size: 250 bytes --]



    Oliver
-- 
Oliver Scholz               23 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* Re: XPM via Lisp in the toolbar
  2002-11-12 17:32 XPM via Lisp in the toolbar Oliver Scholz
  2002-11-13 17:15 ` Oliver Scholz
@ 2002-11-14  4:10 ` Richard Stallman
  2002-11-15 17:47 ` W32 image patch (was Re: XPM via Lisp in the toolbar) Jason Rumney
  2 siblings, 0 replies; 21+ messages in thread
From: Richard Stallman @ 2002-11-14  4:10 UTC (permalink / raw)
  Cc: emacs-devel

    Some time ago I posted a library to deal with XPM images (internally:
    convert them to PPM) to this group. I am currently working on this
    again and at the same time I am hooking this library into the
    functions that deal with images in general (mainly `create-image' and
    `find-image'). The goal of the latter is that Emacs would support XPM
    transparently wether it was compiled with xpmlib or not. I understood
    that this was considered to be useful.

It would be quite useful, I think.

    So is this going to be fixed? The image support on MS Windows needs
    some bug fixes anyways, but at least the toolbar currently works (with
    the PBM icons). Or should I disable my stuff for toolbar-icons in
    general?

Since it is a Windows-only issue, I won't have an opinion about it.

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

* Re: XPM via Lisp in the toolbar
  2002-11-13 17:15 ` Oliver Scholz
@ 2002-11-15  2:36   ` Richard Stallman
  2002-11-15  3:31     ` alkibiades
  2002-11-15 15:06     ` Jason Rumney
  0 siblings, 2 replies; 21+ messages in thread
From: Richard Stallman @ 2002-11-15  2:36 UTC (permalink / raw)
  Cc: emacs-devel

    Or I could hook `xpm-create-image' into the appropriate functions in
    image.el.

This seems like the cleanest result.  If Emacs does not support XPM
format internally, it can use your package.  So XPM will always "just
work" as far as the user is concerned.

    But what to do with
    the tool bar? On MS Windows this breaks the tool bar totally. 

Could you explain why it has that effect?  That is not obvious.  It is
surprising that adding XPM support via conversion should break
anything that worked previously.

    Or I could add a caching mechanism to toolbar.el so that the
    conversion happens only once.

Why not add the caching feature in your conversion library?
Then it would apply to anything that tries to display XPM
and works via conversion.

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

* Re: XPM via Lisp in the toolbar
  2002-11-15  2:36   ` Richard Stallman
@ 2002-11-15  3:31     ` alkibiades
  2002-11-15 14:08       ` Stefan Monnier
                         ` (2 more replies)
  2002-11-15 15:06     ` Jason Rumney
  1 sibling, 3 replies; 21+ messages in thread
From: alkibiades @ 2002-11-15  3:31 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     Or I could hook `xpm-create-image' into the appropriate functions in
>     image.el.
>
> This seems like the cleanest result.  If Emacs does not support XPM
> format internally, it can use your package.  So XPM will always "just
> work" as far as the user is concerned.

O.k.

>     But what to do with
>     the tool bar? On MS Windows this breaks the tool bar totally. 
>
> Could you explain why it has that effect?  That is not obvious.  It is
> surprising that adding XPM support via conversion should break
> anything that worked previously.

Unfortunately Emacs' internals are just a big black box for me (and
this won't change for a long time). All I can say is: if I try to put
an icon on the toolbar on MS Windows XP via an image descriptor that
contains PPM data *and* sets the :mask attribute to gain transparency,
then the according button does not appear on the toolbar at all. Since
this is what happens to all images in the tool bar, the tool bar stays
empty.

However: If I apply the same image descriptor *without* the mask
attribute, the image appears on the tool bar as expected. But this "as
expected" is very ugly, because the background is not transparent in
that case.

Actually I doubt that it worked previously (for certain values of
`worked'). AFAICS the :mask attribute does not have any effect on MS
Windows at all. The tool bar seems to be special, because the image
does not show up -- while in a normal buffer the image appears, albeit
without any visible difference to the same image without the :mask
attribute. Currently the tool bar on MS Windows shows the PBM
(black&white) versions of the icons. "Transparency" works different
for PBM and does not involve the :mask property.

>     Or I could add a caching mechanism to toolbar.el so that the
>     conversion happens only once.
>
> Why not add the caching feature in your conversion library?
> Then it would apply to anything that tries to display XPM
> and works via conversion.

Hmm. I would do it. I hesitate only, because this would mean that
*every* XPM image viewed within an Emacs buffer would be stored as a
PBM/PGN/PPM file on the disk. So if a user, say, uses
`auto-image-file-mode' and dired to review a directory with 100 XPM
icons, she would have additional 100 PPM files on her hard disk after
that.

Or do you mean to do caching without storing the image data on the
disk? So that only in a single instance of Emacs no image file is
converted twice? I think this would only be useful in very few cases;
for example if the user from my example above decided to review the
directory a second time. I doubt that this is worth the trouble.

WDYT?

    Oliver
-- 
Oliver Scholz               25 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* Re: XPM via Lisp in the toolbar
  2002-11-15  3:31     ` alkibiades
@ 2002-11-15 14:08       ` Stefan Monnier
  2002-11-16 14:51       ` Richard Stallman
  2002-11-16 14:51       ` Richard Stallman
  2 siblings, 0 replies; 21+ messages in thread
From: Stefan Monnier @ 2002-11-15 14:08 UTC (permalink / raw)
  Cc: rms, emacs-devel

> Unfortunately Emacs' internals are just a big black box for me (and
> this won't change for a long time). All I can say is: if I try to put
> an icon on the toolbar on MS Windows XP via an image descriptor that
> contains PPM data *and* sets the :mask attribute to gain transparency,
> then the according button does not appear on the toolbar at all. Since
> this is what happens to all images in the tool bar, the tool bar stays
> empty.

Jason sent a message recently to this very list explaining that
someone should get images working on w32 because the current code
is only a "first cut" with many problems left open.

It should be in the archive.


	Stefan

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

* Re: XPM via Lisp in the toolbar
  2002-11-15  2:36   ` Richard Stallman
  2002-11-15  3:31     ` alkibiades
@ 2002-11-15 15:06     ` Jason Rumney
  2002-11-15 18:06       ` Jason Rumney
  2002-11-18 14:08       ` Oliver Scholz
  1 sibling, 2 replies; 21+ messages in thread
From: Jason Rumney @ 2002-11-15 15:06 UTC (permalink / raw)
  Cc: alkibiades, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     But what to do with
>     the tool bar? On MS Windows this breaks the tool bar totally. 
> 
> Could you explain why it has that effect?  That is not obvious.  It is
> surprising that adding XPM support via conversion should break
> anything that worked previously.

Image support is very incomplete on MS-Windows. It works for the
standard PBM toolbar images and splash-screen, but as soon as you try
to do anything else, images either appear garbled or not at all.

I had some time last night to look more closely, and I think I now
have image masks working, and have fixed some of the more serious
bugs. So I should be able to send a patch later today, or tomorrow.


Although my gnu account has been enabled now, I have never been able
to figure out how to use SSH successfully.  William Perry gave me some
advice in November 2001 that worked when I tested it out, but I didn't
properly switch over from kerberos at the time, and that message is
not in the archives (the rest of the thread is). It is somewhat
confusing that the mail I received when my account was reenabled said
I must use SSH version 2, but the advice on savannah says I must use
SSH version 1, but I have tried both types of keys, and ssh always
ends up falling back to plaintext password mode.

If anyone can give clear instructions on getting OpenSSH going with
savannah, I would appreciate it.

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

* W32 image patch (was Re: XPM via Lisp in the toolbar)
  2002-11-12 17:32 XPM via Lisp in the toolbar Oliver Scholz
  2002-11-13 17:15 ` Oliver Scholz
  2002-11-14  4:10 ` Richard Stallman
@ 2002-11-15 17:47 ` Jason Rumney
  2002-11-19  8:51   ` bootstrap fails with current CVS on MS Windows XP Oliver Scholz
  2 siblings, 1 reply; 21+ messages in thread
From: Jason Rumney @ 2002-11-15 17:47 UTC (permalink / raw)


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


Below is a patch to improve image support on MS-Windows. Hopefully it
is enough to make images with masks work in the toolbar. I currently
am unable to check this in, so if someone else with write access to
CVS and access to MS-Windows to ensure the patch applies cleanly,
compiles and works can check this in, it would be greatly appreciated.

If this patch works as well for others as it does for me, then I'll
take back what I said last week about needing to disable image
support on Windows if we start pretesting from HEAD in the near
future.



2002-11-15  Jason Rumney  <jasonr@gnu.org>

	* w32term.c (x_draw_image_foreground, x_draw_image_glyph_string)
	(w32_draw_image_foreground_1): Handle image masks.
	(x_draw_image_glyph_string): Don't BitBlt transparently.

	* w32fns.c (w32_defined_color): Adjust RGB values for Emacs.
	(x_from_xcolors): Adjust RGB values for W32.
	(image_background, image_background_transparent)
	(postprocess_image, x_to_xcolors, x_disable_image)
	(x_build_heuristic_mask): Adapt for W32 and enable.
	(x_create_x_image_and_pixmap): Mark images with palettes as such.
	(xbm_load): Remove unused variable.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: W32 image patch --]
[-- Type: text/x-patch, Size: 28333 bytes --]

*** src/w32term.c.~1.170.~	Thu Nov 14 16:02:54 2002
--- src/w32term.c	Fri Nov 15 15:42:01 2002
*************** x_draw_image_foreground (s)
*** 3888,3945 ****
  
    if (s->img->pixmap)
      {
! #if 0 /* TODO: image mask */
        if (s->img->mask)
  	{
! 	  /* We can't set both a clip mask and use XSetClipRectangles
! 	     because the latter also sets a clip mask.  We also can't
! 	     trust on the shape extension to be available
! 	     (XShapeCombineRegion).  So, compute the rectangle to draw
! 	     manually.  */
! 	  unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
! 				| GCFunction);
! 	  XGCValues xgcv;
! 	  XRectangle clip_rect, image_rect, r;
! 
! 	  xgcv.clip_mask = s->img->mask;
! 	  xgcv.clip_x_origin = x;
! 	  xgcv.clip_y_origin = y;
! 	  xgcv.function = GXcopy;
! 	  XChangeGC (s->display, s->gc, mask, &xgcv);
! 
! 	  w32_get_glyph_string_clip_rect (s, &clip_rect);
! 	  image_rect.x = x;
! 	  image_rect.y = y;
! 	  image_rect.width = s->img->width;
! 	  image_rect.height = s->img->height;
! 	  if (IntersectRect (&r, &clip_rect, &image_rect))
! 	    XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
! 		       r.x - x, r.y - y, r.width, r.height, r.x, r.y);
  	}
        else
- #endif
  	{
!           HDC compat_hdc = CreateCompatibleDC (s->hdc);
!           HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
!           HBRUSH orig_brush = SelectObject (s->hdc, fg_brush);
!           HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
!           x_set_glyph_string_clipping (s);
! 
!           SetTextColor (s->hdc, s->gc->foreground);
!           SetBkColor (s->hdc, s->gc->background);
! #if 0 /* From w32bdf.c (which is from Meadow).  */
!           BitBlt (s->hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, SRCCOPY);
!           BitBlt (s->hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, 0xB8074A);
! #else
            BitBlt (s->hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, 0xE20746);
! #endif
!           SelectObject (s->hdc, orig_brush);
!           DeleteObject (fg_brush);
! 	  SelectObject (compat_hdc, orig_obj);
!           DeleteDC (compat_hdc);
  
  	  /* When the image has a mask, we can expect that at
  	     least part of a mouse highlight or a block cursor will
--- 3888,3927 ----
  
    if (s->img->pixmap)
      {
!       HDC compat_hdc = CreateCompatibleDC (s->hdc);
!       HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
!       HBRUSH orig_brush = SelectObject (s->hdc, fg_brush);
!       HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
!       SetBkColor (compat_hdc, RGB (255, 255, 255));
!       SetTextColor (s->hdc, RGB (0, 0, 0));
!       x_set_glyph_string_clipping (s);
! 
        if (s->img->mask)
  	{
! 	  HDC mask_dc = CreateCompatibleDC (s->hdc);
! 	  HGDIOBJ mask_orig_obj = SelectObject (mask_dc, s->img->mask);
! 
! 	  SetTextColor (s->hdc, RGB (255, 255, 255));
! 	  SetBkColor (s->hdc, RGB (0, 0, 0));
! 
! 	  BitBlt (s->hdc, x, y, s->img->width, s->img->height,
! 		  compat_hdc, 0, 0, 0x990066);
! 	  BitBlt (s->hdc, x, y, s->img->width, s->img->height,
! 		  mask_dc, 0, 0, SRCAND);
! 	  BitBlt (s->hdc, x, y, s->img->width, s->img->height,
! 		  compat_hdc, 0, 0, 0x990066);
! 
! 	  SelectObject (mask_dc, mask_orig_obj);
! 	  DeleteDC (mask_dc);
  	}
        else
  	{
! 	  SetTextColor (s->hdc, s->gc->foreground);
! 	  SetBkColor (s->hdc, s->gc->background);
! 
            BitBlt (s->hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, NOTSRCCOPY);
! 	  /* Meadow uses 0xE20746, previously SRCCOPY and 0xB8074A.  */
  
  	  /* When the image has a mask, we can expect that at
  	     least part of a mouse highlight or a block cursor will
*************** x_draw_image_foreground (s)
*** 3954,3961 ****
  	      w32_draw_rectangle (s->hdc, s->gc, x - r, y - r ,
  				  s->img->width + r*2 - 1, s->img->height + r*2 - 1);
  	    }
-           w32_set_clip_rectangle (s->hdc, NULL);
  	}
      }
    else
      w32_draw_rectangle (s->hdc, s->gc, x, y, s->img->width -1,
--- 3936,3948 ----
  	      w32_draw_rectangle (s->hdc, s->gc, x - r, y - r ,
  				  s->img->width + r*2 - 1, s->img->height + r*2 - 1);
  	    }
  	}
+ 
+       w32_set_clip_rectangle (s->hdc, NULL);
+       SelectObject (s->hdc, orig_brush);
+       DeleteObject (fg_brush);
+       SelectObject (compat_hdc, orig_obj);
+       DeleteDC (compat_hdc);
      }
    else
      w32_draw_rectangle (s->hdc, s->gc, x, y, s->img->width -1,
*************** w32_draw_image_foreground_1 (s, pixmap)
*** 4040,4090 ****
  
    if (s->img->pixmap)
      {
! #if 0 /* TODO: image mask */
        if (s->img->mask)
  	{
! 	  /* We can't set both a clip mask and use XSetClipRectangles
! 	     because the latter also sets a clip mask.  We also can't
! 	     trust on the shape extension to be available
! 	     (XShapeCombineRegion).  So, compute the rectangle to draw
! 	     manually.  */
! 	  unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
! 				| GCFunction);
! 	  XGCValues xgcv;
! 
! 	  xgcv.clip_mask = s->img->mask;
! 	  xgcv.clip_x_origin = x;
! 	  xgcv.clip_y_origin = y;
! 	  xgcv.function = GXcopy;
! 	  XChangeGC (s->display, s->gc, mask, &xgcv);
  
! 	  XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
! 		     0, 0, s->img->width, s->img->height, x, y);
! 	  XSetClipMask (s->display, s->gc, None);
  	}
        else
- #endif
  	{
!           HDC compat_hdc = CreateCompatibleDC (hdc);
!           HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
!           HBRUSH orig_brush = SelectObject (hdc, fg_brush);
!           HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
! 
!           SetTextColor (hdc, s->gc->foreground);
!           SetBkColor (hdc, s->gc->background);
! #if 0 /* From w32bdf.c (which is from Meadow).  */
!           BitBlt (hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, SRCCOPY);
!           BitBlt (hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, 0xB8074A);
! #else
            BitBlt (hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, 0xE20746);
! #endif
!           SelectObject (hdc, orig_brush);
!           DeleteObject (fg_brush);
! 	  SelectObject (compat_hdc, orig_obj);
!           DeleteDC (compat_hdc);
  
  	  /* When the image has a mask, we can expect that at
  	     least part of a mouse highlight or a block cursor will
--- 4027,4061 ----
  
    if (s->img->pixmap)
      {
!       HDC compat_hdc = CreateCompatibleDC (hdc);
!       HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
!       HBRUSH orig_brush = SelectObject (hdc, fg_brush);
!       HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
! 
        if (s->img->mask)
  	{
! 	  HDC mask_dc = CreateCompatibleDC (hdc);
! 	  HGDIOBJ mask_orig_obj = SelectObject (mask_dc, s->img->mask);
  
! 	  SetTextColor (hdc, RGB (0, 0, 0));
! 	  SetBkColor (hdc, RGB (255, 255, 255));
! 	  BitBlt (hdc, x, y, s->img->width, s->img->height,
! 		  compat_hdc, 0, 0, SRCINVERT);
! 	  BitBlt (hdc, x, y, s->img->width, s->img->height,
! 		  mask_dc, 0, 0, SRCAND);
! 	  BitBlt (hdc, x, y, s->img->width, s->img->height,
! 		  compat_hdc, 0, 0, SRCINVERT);
! 
! 	  SelectObject (mask_dc, mask_orig_obj);
! 	  DeleteDC (mask_dc);
  	}
        else
  	{
! 	  SetTextColor (hdc, s->gc->foreground);
! 	  SetBkColor (hdc, s->gc->background);
! 
            BitBlt (hdc, x, y, s->img->width, s->img->height,
!                   compat_hdc, 0, 0, NOTSRCCOPY);
  
  	  /* When the image has a mask, we can expect that at
  	     least part of a mouse highlight or a block cursor will
*************** w32_draw_image_foreground_1 (s, pixmap)
*** 4096,4105 ****
  	    {
  	      int r = s->img->relief;
  	      if (r < 0) r = -r;
! 	      w32_draw_rectangle (s->hdc, s->gc, x - r, y - r ,
  				  s->img->width + r*2 - 1, s->img->height + r*2 - 1);
  	    }
  	}
      }
    else
      w32_draw_rectangle (hdc, s->gc, x, y, s->img->width - 1,
--- 4067,4081 ----
  	    {
  	      int r = s->img->relief;
  	      if (r < 0) r = -r;
! 	      w32_draw_rectangle (hdc, s->gc, x - r, y - r ,
  				  s->img->width + r*2 - 1, s->img->height + r*2 - 1);
  	    }
  	}
+ 
+       SelectObject (hdc, orig_brush);
+       DeleteObject (fg_brush);
+       SelectObject (compat_hdc, orig_obj);
+       DeleteDC (compat_hdc);
      }
    else
      w32_draw_rectangle (hdc, s->gc, x, y, s->img->width - 1,
*************** x_draw_image_glyph_string (s)
*** 4165,4173 ****
    if (height > s->img->height
        || s->img->hmargin
        || s->img->vmargin
- #if 0 /* TODO: image mask */
        || s->img->mask
- #endif
        || s->img->pixmap == 0
        || s->width != s->background_width)
      {
--- 4141,4147 ----
*************** x_draw_image_glyph_string (s)
*** 4177,4183 ****
  	x = s->x;
  
        y = s->y + box_line_vwidth;
! #if 0 /* TODO: image mask */
        if (s->img->mask)
  	{
  	  /* Create a pixmap as large as the glyph string.  Fill it
--- 4151,4157 ----
  	x = s->x;
  
        y = s->y + box_line_vwidth;
! #if 0 /* TODO: figure out if we need to do this on Windows.  */
        if (s->img->mask)
  	{
  	  /* Create a pixmap as large as the glyph string.  Fill it
*************** x_draw_image_glyph_string (s)
*** 4235,4249 ****
  
          SetTextColor (s->hdc, s->gc->foreground);
          SetBkColor (s->hdc, s->gc->background);
- #if 0 /* From w32bdf.c (which is from Meadow).  */
          BitBlt (s->hdc, s->x, s->y, s->background_width, s->height,
                  compat_hdc, 0, 0, SRCCOPY);
!         BitBlt (s->hdc, s->x, s->y, s->background_width, s->height,
!                 compat_hdc, 0, 0, 0xB8074A);
! #else
!         BitBlt (s->hdc, s->x, s->y, s->background_width, s->height,
!                 compat_hdc, 0, 0, 0xE20746);
! #endif
          SelectObject (s->hdc, orig_brush);
          DeleteObject (fg_brush);
          SelectObject (compat_hdc, orig_obj);
--- 4209,4217 ----
  
          SetTextColor (s->hdc, s->gc->foreground);
          SetBkColor (s->hdc, s->gc->background);
          BitBlt (s->hdc, s->x, s->y, s->background_width, s->height,
                  compat_hdc, 0, 0, SRCCOPY);
! 
          SelectObject (s->hdc, orig_brush);
          DeleteObject (fg_brush);
          SelectObject (compat_hdc, orig_obj);

*** src/w32fns.c.~1.186.~	Thu Nov 14 16:02:51 2002
--- src/w32fns.c	Fri Nov 15 15:39:34 2002
*************** w32_defined_color (f, color, color_def, 
*** 1948,1956 ****
        w32_color_ref = XUINT (tem) | 0x2000000;
  
        color_def->pixel = w32_color_ref;
!       color_def->red = GetRValue (w32_color_ref);
!       color_def->green = GetGValue (w32_color_ref);
!       color_def->blue = GetBValue (w32_color_ref);
  
        return 1;
      }
--- 1948,1956 ----
        w32_color_ref = XUINT (tem) | 0x2000000;
  
        color_def->pixel = w32_color_ref;
!       color_def->red = GetRValue (w32_color_ref) * 256;
!       color_def->green = GetGValue (w32_color_ref) * 256;
!       color_def->blue = GetBValue (w32_color_ref) * 256;
  
        return 1;
      }
*************** DEFUN ("image-mask-p", Fimage_mask_p, Si
*** 8540,8545 ****
--- 8540,8546 ----
  
  static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
  static void free_image P_ ((struct frame *f, struct image *img));
+ static void x_destroy_x_image P_ ((XImage *));
  
  
  /* Allocate and return a new image structure for image specification
*************** image_ascent (img, face)
*** 8646,8663 ****
  /* Find the "best" corner color of a bitmap.  XIMG is assumed to a device
     context with the bitmap selected.  */
  static COLORREF
! four_corners_best (ximg, width, height)
!      HDC ximg;
       unsigned long width, height;
  {
    COLORREF corners[4], best;
    int i, best_count;
  
!   /* Get the colors at the corners of ximg.  */
!   corners[0] = GetPixel (ximg, 0, 0);
!   corners[1] = GetPixel (ximg, width - 1, 0);
!   corners[2] = GetPixel (ximg, width - 1, height - 1);
!   corners[3] = GetPixel (ximg, 0, height - 1);
  
    /* Choose the most frequently found color as background.  */
    for (i = best_count = 0; i < 4; ++i)
--- 8647,8664 ----
  /* Find the "best" corner color of a bitmap.  XIMG is assumed to a device
     context with the bitmap selected.  */
  static COLORREF
! four_corners_best (img_dc, width, height)
!      HDC img_dc;
       unsigned long width, height;
  {
    COLORREF corners[4], best;
    int i, best_count;
  
!   /* Get the colors at the corners of img_dc.  */
!   corners[0] = GetPixel (img_dc, 0, 0);
!   corners[1] = GetPixel (img_dc, width - 1, 0);
!   corners[2] = GetPixel (img_dc, width - 1, height - 1);
!   corners[3] = GetPixel (img_dc, 0, height - 1);
  
    /* Choose the most frequently found color as background.  */
    for (i = best_count = 0; i < 4; ++i)
*************** four_corners_best (ximg, width, height)
*** 8676,8707 ****
  }
  
  /* Return the `background' field of IMG.  If IMG doesn't have one yet,
!    it is guessed heuristically.  If non-zero, XIMG is an existing XImage
!    object to use for the heuristic.  */
  
  unsigned long
! image_background (img, f, ximg)
       struct image *img;
       struct frame *f;
!      XImage *ximg;
  {
    if (! img->background_valid)
      /* IMG doesn't have a background yet, try to guess a reasonable value.  */
      {
! #if 0 /* TODO: Image support.  */
!       int free_ximg = !ximg;
  
!       if (! ximg)
! 	ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
! 			  0, 0, img->width, img->height, ~0, ZPixmap);
  
!       img->background = four_corners_best (ximg, img->width, img->height);
  
        if (free_ximg)
! 	XDestroyImage (ximg);
  
        img->background_valid = 1;
- #endif
      }
  
    return img->background;
--- 8677,8715 ----
  }
  
  /* Return the `background' field of IMG.  If IMG doesn't have one yet,
!    it is guessed heuristically.  If non-zero, IMG_DC is an existing
!    device context with the image selected to use for the heuristic.  */
  
  unsigned long
! image_background (img, f, img_dc)
       struct image *img;
       struct frame *f;
!      HDC img_dc;
  {
    if (! img->background_valid)
      /* IMG doesn't have a background yet, try to guess a reasonable value.  */
      {
!       int free_ximg = !img_dc;
!       HGDIOBJ prev;
! 
!       if (free_ximg)
! 	{
! 	  HDC frame_dc = get_frame_dc (f);
! 	  img_dc = CreateCompatibleDC (frame_dc);
! 	  release_frame_dc (f, frame_dc);
  
! 	  prev = SelectObject (img_dc, img->pixmap);
! 	}
  
!       img->background = four_corners_best (img_dc, img->width, img->height);
  
        if (free_ximg)
! 	{
! 	  SelectObject (img_dc, prev);
! 	  DeleteDC (img_dc);
! 	}
  
        img->background_valid = 1;
      }
  
    return img->background;
*************** image_background (img, f, ximg)
*** 8715,8742 ****
  image_background_transparent (img, f, mask)
       struct image *img;
       struct frame *f;
!      XImage *mask;
  {
    if (! img->background_transparent_valid)
      /* IMG doesn't have a background yet, try to guess a reasonable value.  */
      {
- #if 0 /* TODO: Image support.  */
        if (img->mask)
  	{
  	  int free_mask = !mask;
  
! 	  if (! mask)
! 	    mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
! 			      0, 0, img->width, img->height, ~0, ZPixmap);
  
  	  img->background_transparent
  	    = !four_corners_best (mask, img->width, img->height);
  
  	  if (free_mask)
! 	    XDestroyImage (mask);
  	}
        else
- #endif
  	img->background_transparent = 0;
  
        img->background_transparent_valid = 1;
--- 8723,8757 ----
  image_background_transparent (img, f, mask)
       struct image *img;
       struct frame *f;
!      HDC mask;
  {
    if (! img->background_transparent_valid)
      /* IMG doesn't have a background yet, try to guess a reasonable value.  */
      {
        if (img->mask)
  	{
  	  int free_mask = !mask;
+ 	  HGDIOBJ prev;
  
! 	  if (free_mask)
! 	    {
! 	      HDC frame_dc = get_frame_dc (f);
! 	      mask = CreateCompatibleDC (frame_dc);
! 	      release_frame_dc (f, frame_dc);
! 
! 	      prev = SelectObject (mask, img->mask);	      
! 	    }
  
  	  img->background_transparent
  	    = !four_corners_best (mask, img->width, img->height);
  
  	  if (free_mask)
! 	    {
! 	      SelectObject (mask, prev);
! 	      DeleteDC (mask);
! 	    }
  	}
        else
  	img->background_transparent = 0;
  
        img->background_transparent_valid = 1;
*************** x_alloc_image_color (f, img, color_name,
*** 8879,8884 ****
--- 8894,8900 ----
  
  static void cache_image P_ ((struct frame *f, struct image *img));
  static void postprocess_image P_ ((struct frame *, struct image *));
+ static void x_disable_image P_ ((struct frame *, struct image *));
  
  
  /* Return a new, initialized image cache that is allocated from the
*************** postprocess_image (f, img)
*** 9018,9024 ****
       struct frame *f;
       struct image *img;
  {
- #if 0  /* TODO: image support.  */
    /* Manipulation of the image's mask.  */
    if (img->pixmap)
      {
--- 9034,9039 ----
*************** postprocess_image (f, img)
*** 9083,9089 ****
  			      Fplist_get (tem, QCcolor_adjustment));
  	}
      }
- #endif
  }
  
  
--- 9098,9103 ----
*************** forall_images_in_image_cache (f, fn)
*** 9275,9281 ****
  
  static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
                                              XImage **, Pixmap *));
- static void x_destroy_x_image P_ ((XImage *));
  static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
  
  
--- 9289,9294 ----
*************** x_create_x_image_and_pixmap (f, width, h
*** 9338,9348 ****
    header->biCompression = BI_RGB;
    header->biClrUsed = palette_colors;
  
    hdc = get_frame_dc (f);
  
    /* Create a DIBSection and raster array for the bitmap,
       and store its handle in *pixmap.  */
!   *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
  			      &((*ximg)->data), NULL, 0);
  
    /* Realize display palette and garbage all frames. */
--- 9351,9364 ----
    header->biCompression = BI_RGB;
    header->biClrUsed = palette_colors;
  
+   /* TODO: fill in palette.  */
+ 
    hdc = get_frame_dc (f);
  
    /* Create a DIBSection and raster array for the bitmap,
       and store its handle in *pixmap.  */
!   *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
! 			      (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
  			      &((*ximg)->data), NULL, 0);
  
    /* Realize display palette and garbage all frames. */
*************** x_put_x_image (f, ximg, pixmap, width, h
*** 9388,9401 ****
       XImage *ximg;
       Pixmap pixmap;
  {
! 
! #if TODO  /* W32 specific image code.  */
!   GC gc;
! 
!   xassert (interrupt_input_blocked);
!   gc = XCreateGC (NULL, pixmap, 0, NULL);
!   XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
!   XFreeGC (NULL, gc);
  #endif
  }
  
--- 9404,9413 ----
       XImage *ximg;
       Pixmap pixmap;
  {
! #if 0  /* I don't think this is necessary looking at where it is used.  */
!   HDC hdc = get_frame_dc (f);
!   SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS);
!   release_frame_dc (f, hdc);
  #endif
  }
  
*************** xbm_load (f, img)
*** 10065,10071 ****
      {
        struct image_keyword fmt[XBM_LAST];
        Lisp_Object data;
-       int depth;
        unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
        unsigned long background = FRAME_BACKGROUND_PIXEL (f);
        char *bits;
--- 10077,10082 ----
*************** xbm_load (f, img)
*** 10127,10133 ****
  	    bits = XBOOL_VECTOR (data)->data;
  
  	  /* Create the pixmap.  */
- 	  depth = one_w32_display_info.n_cbits;
  	  img->pixmap
  	    = w32_create_pixmap_from_bitmap_data (img->width, img->height,
  						  bits);
--- 10138,10143 ----
*************** xbm_load (f, img)
*** 10200,10206 ****
    {":background",       IMAGE_STRING_OR_NIL_VALUE,              0}
  };
  
! /* Structure describing the image type XBM.  */
  
  static struct image_type xpm_type =
  {
--- 10210,10216 ----
    {":background",       IMAGE_STRING_OR_NIL_VALUE,              0}
  };
  
! /* Structure describing the image type XPM.  */
  
  static struct image_type xpm_type =
  {
*************** x_to_xcolors (f, img, rgb_p)
*** 10641,10653 ****
  {
    int x, y;
    XColor *colors, *p;
!   XImage *ximg;
  
    colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
! #if 0 /* TODO: implement image colors.  */
!   /* Get the X image IMG->pixmap.  */
!   ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
! 		    0, 0, img->width, img->height, ~0, ZPixmap);
  
    /* Fill the `pixel' members of the XColor array.  I wished there
       were an easy and portable way to circumvent XGetPixel.  */
--- 10651,10666 ----
  {
    int x, y;
    XColor *colors, *p;
!   HDC hdc, bmpdc;
!   HGDIOBJ prev;
  
    colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
! 
!   /* Load the image into a memory device context.  */
!   hdc = get_frame_dc (f);
!   bmpdc = CreateCompatibleDC (hdc);
!   release_frame_dc (f, hdc);
!   prev = SelectObject (bmpdc, img->pixmap);
  
    /* Fill the `pixel' members of the XColor array.  I wished there
       were an easy and portable way to circumvent XGetPixel.  */
*************** x_to_xcolors (f, img, rgb_p)
*** 10657,10670 ****
        XColor *row = p;
  
        for (x = 0; x < img->width; ++x, ++p)
! 	p->pixel = XGetPixel (ximg, x, y);
  
!       if (rgb_p)
! 	x_query_colors (f, row, img->width);
      }
  
!   XDestroyImage (ximg);
! #endif
    return colors;
  }
  
--- 10670,10691 ----
        XColor *row = p;
  
        for (x = 0; x < img->width; ++x, ++p)
! 	{
! 	  /* TODO: palette support needed here?  */
! 	  p->pixel = GetPixel (bmpdc, x, y);
  
! 	  if (rgb_p)
! 	    {
! 	      p->red = 256 * GetRValue (p->pixel);
! 	      p->green = 256 * GetGValue (p->pixel);
! 	      p->blue = 256 * GetBValue (p->pixel);
! 	    }
! 	}
      }
  
!   SelectObject (bmpdc, prev);
!   DeleteDC (bmpdc);
! 
    return colors;
  }
  
*************** x_from_xcolors (f, img, colors)
*** 10723,10729 ****
  #if 0  /* TODO: color tables.  */
  	pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
  #else
! 	pixel = PALETTERGB (p->red, p->green, p->blue);
  #endif
  	XPutPixel (oimg, x, y, pixel);
        }
--- 10744,10750 ----
  #if 0  /* TODO: color tables.  */
  	pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
  #else
! 	pixel = PALETTERGB (p->red / 256, p->green / 256, p->blue / 256);
  #endif
  	XPutPixel (oimg, x, y, pixel);
        }
*************** x_disable_image (f, img)
*** 10916,10944 ****
       should.  */
    if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
      {
! #if 0 /* TODO: full image support  */
!       Display *dpy = FRAME_X_DISPLAY (f);
!       GC gc;
! 
!       gc = XCreateGC (dpy, img->pixmap, 0, NULL);
!       XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
!       XDrawLine (dpy, img->pixmap, gc, 0, 0,
! 		 img->width - 1, img->height - 1);
!       XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
! 		 img->width - 1, 0);
!       XFreeGC (dpy, gc);
  
        if (img->mask)
  	{
! 	  gc = XCreateGC (dpy, img->mask, 0, NULL);
! 	  XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
! 	  XDrawLine (dpy, img->mask, gc, 0, 0,
! 		     img->width - 1, img->height - 1);
! 	  XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
! 		     img->width - 1, 0);
! 	  XFreeGC (dpy, gc);
  	}
! #endif
      }
  }
  
--- 10937,10968 ----
       should.  */
    if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
      {
!       HDC hdc, bmpdc;
!       HGDIOBJ prev;
! 
!       hdc = get_frame_dc (f);
!       bmpdc = CreateCompatibleDC (hdc);
!       release_frame_dc (f, hdc);
! 
!       prev = SelectObject (bmpdc, img->pixmap);
! 
!       SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f));
!       MoveToEx (bmpdc, 0, 0, NULL);
!       LineTo (bmpdc, img->width - 1, img->height - 1);
!       MoveToEx (bmpdc, 0, img->height - 1, NULL);
!       LineTo (bmpdc, img->width - 1, 0);
  
        if (img->mask)
  	{
! 	  SelectObject (bmpdc, img->mask);
! 	  SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f));
! 	  MoveToEx (bmpdc, 0, 0, NULL);
! 	  LineTo (bmpdc, img->width - 1, img->height - 1);
! 	  MoveToEx (bmpdc, 0, img->height - 1, NULL);
! 	  LineTo (bmpdc, img->width - 1, 0);
  	}
!       SelectObject (bmpdc, prev);
!       DeleteDC (bmpdc);
      }
  }
  
*************** x_build_heuristic_mask (f, img, how)
*** 10956,10985 ****
       struct image *img;
       Lisp_Object how;
  {
! #if 0 /* TODO: full image support.  */
!   Display *dpy = FRAME_W32_DISPLAY (f);
!   XImage *ximg, *mask_img;
    int x, y, rc, use_img_background;
    unsigned long bg = 0;
  
    if (img->mask)
      {
!       XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
!       img->mask = None;
        img->background_transparent_valid = 0;
      }
  
!   /* Create an image and pixmap serving as mask.  */
!   rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
! 				    &mask_img, &img->mask);
!   if (!rc)
!     return 0;
! 
!   /* Get the X image of IMG->pixmap.  */
!   ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
! 		    ~0, ZPixmap);
  
!   /* Determine the background color of ximg.  If HOW is `(R G B)'
       take that as color.  Otherwise, use the image's background color.  */
    use_img_background = 1;
  
--- 10980,11011 ----
       struct image *img;
       Lisp_Object how;
  {
!   HDC img_dc, frame_dc;
!   HGDIOBJ prev;
!   char *mask_img;
    int x, y, rc, use_img_background;
    unsigned long bg = 0;
+   int row_width;
  
    if (img->mask)
      {
!       DeleteObject (img->mask);
!       img->mask = NULL;
        img->background_transparent_valid = 0;
      }
  
!   /* Create the bit array serving as mask.  */
!   row_width = (img->width + 7) / 8;
!   mask_img = xmalloc (row_width * img->height);
!   bzero (mask_img, row_width * img->height);
! 
!   /* Create a memory device context for IMG->pixmap.  */
!   frame_dc = get_frame_dc (f);
!   img_dc = CreateCompatibleDC (frame_dc);
!   release_frame_dc (f, frame_dc);
!   prev = SelectObject (img_dc, img->pixmap);
  
!   /* Determine the background color of img_dc.  If HOW is `(R G B)'
       take that as color.  Otherwise, use the image's background color.  */
    use_img_background = 1;
  
*************** x_build_heuristic_mask (f, img, how)
*** 11003,11028 ****
      }
  
    if (use_img_background)
!     bg = four_corners_best (ximg, img->width, img->height);
  
    /* Set all bits in mask_img to 1 whose color in ximg is different
       from the background color bg.  */
    for (y = 0; y < img->height; ++y)
      for (x = 0; x < img->width; ++x)
!       XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
  
    /* Fill in the background_transparent field while we have the mask handy. */
!   image_background_transparent (img, f, mask_img);
  
    /* Put mask_img into img->mask.  */
-   x_put_x_image (f, mask_img, img->mask, img->width, img->height);
    x_destroy_x_image (mask_img);
!   XDestroyImage (ximg);
  
    return 1;
- #else
-   return 0;
- #endif
  }
  
  \f
--- 11029,11061 ----
      }
  
    if (use_img_background)
!     bg = four_corners_best (img_dc, img->width, img->height);
  
    /* Set all bits in mask_img to 1 whose color in ximg is different
       from the background color bg.  */
    for (y = 0; y < img->height; ++y)
      for (x = 0; x < img->width; ++x)
!       {
! 	COLORREF p = GetPixel (img_dc, x, y);
! 	if (p != bg)
! 	  mask_img[y * row_width + x / 8] |= 1 << (x % 8);
!       }
! 
!   /* Create the mask image.  */
!   img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height,
! 						  mask_img);
  
    /* Fill in the background_transparent field while we have the mask handy. */
!   SelectObject (img_dc, img->mask);
! 
!   image_background_transparent (img, f, img_dc);
  
    /* Put mask_img into img->mask.  */
    x_destroy_x_image (mask_img);
!   SelectObject (img_dc, prev);
!   DeleteDC (img_dc);
  
    return 1;
  }
  
  \f

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

* Re: XPM via Lisp in the toolbar
  2002-11-15 15:06     ` Jason Rumney
@ 2002-11-15 18:06       ` Jason Rumney
  2002-11-18 14:08       ` Oliver Scholz
  1 sibling, 0 replies; 21+ messages in thread
From: Jason Rumney @ 2002-11-15 18:06 UTC (permalink / raw)
  Cc: alkibiades, emacs-devel

Jason Rumney <jasonr@gnu.org> writes:

> If anyone can give clear instructions on getting OpenSSH going with
> savannah, I would appreciate it.

OK, it works now. It seems I just didn't wait long enough before
giving up after uploading my public key to savannah.

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

* Re: XPM via Lisp in the toolbar
  2002-11-15  3:31     ` alkibiades
  2002-11-15 14:08       ` Stefan Monnier
@ 2002-11-16 14:51       ` Richard Stallman
  2002-11-16 14:51       ` Richard Stallman
  2 siblings, 0 replies; 21+ messages in thread
From: Richard Stallman @ 2002-11-16 14:51 UTC (permalink / raw)
  Cc: emacs-devel

    However: If I apply the same image descriptor *without* the mask
    attribute, the image appears on the tool bar as expected. But this "as
    expected" is very ugly, because the background is not transparent in
    that case.

I don't have expertise about this.  However, I guess we can continue
having tool bar icons in XPM format (or ost of them at least).

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

* Re: XPM via Lisp in the toolbar
  2002-11-15  3:31     ` alkibiades
  2002-11-15 14:08       ` Stefan Monnier
  2002-11-16 14:51       ` Richard Stallman
@ 2002-11-16 14:51       ` Richard Stallman
  2002-11-16 18:44         ` alkibiades
  2 siblings, 1 reply; 21+ messages in thread
From: Richard Stallman @ 2002-11-16 14:51 UTC (permalink / raw)
  Cc: emacs-devel

    > Why not add the caching feature in your conversion library?
    > Then it would apply to anything that tries to display XPM
    > and works via conversion.

    Hmm. I would do it. I hesitate only, because this would mean that
    *every* XPM image viewed within an Emacs buffer would be stored as a
    PBM/PGN/PPM file on the disk.

I would expect the cache to be within Emacs only.  If we wanted to have
copies on disk, we may as well include them in the Emacs distribution
as we do now.

    Or do you mean to do caching without storing the image data on the
    disk? So that only in a single instance of Emacs no image file is
    converted twice? I think this would only be useful in very few cases;

Yes.

    for example if the user from my example above decided to review the
    directory a second time. I doubt that this is worth the trouble.

Many icons will be used over and over within one Emacs session.
I think caching within a session is important.

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

* Re: XPM via Lisp in the toolbar
  2002-11-16 14:51       ` Richard Stallman
@ 2002-11-16 18:44         ` alkibiades
  2002-11-17  7:15           ` Richard Stallman
  0 siblings, 1 reply; 21+ messages in thread
From: alkibiades @ 2002-11-16 18:44 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     Or do you mean to do caching without storing the image data on the
>     disk? So that only in a single instance of Emacs no image file is
>     converted twice? I think this would only be useful in very few cases;
>
> Yes.
>
>     for example if the user from my example above decided to review the
>     directory a second time. I doubt that this is worth the trouble.
>
> Many icons will be used over and over within one Emacs session.
> I think caching within a session is important.

As long as the image is not _explicitly_ re-read from disk as in my
example and as long as the image descriptor is not garbage collected,
this should already be the case. Not even clearing the image cache (I
mean the built-in image cache) would cause a second conversion,
because the image descriptor contains all image data as a value of the
:data attribute.

    Oliver
-- 
Oliver Scholz               26 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* Re: XPM via Lisp in the toolbar
  2002-11-16 18:44         ` alkibiades
@ 2002-11-17  7:15           ` Richard Stallman
  2002-11-17 12:30             ` alkibiades
  0 siblings, 1 reply; 21+ messages in thread
From: Richard Stallman @ 2002-11-17  7:15 UTC (permalink / raw)
  Cc: emacs-devel

    As long as the image is not _explicitly_ re-read from disk as in my
    example and as long as the image descriptor is not garbage collected,
    this should already be the case. Not even clearing the image cache (I
    mean the built-in image cache) would cause a second conversion,
    because the image descriptor contains all image data as a value of the
    :data attribute.

Are you sure that the same image is not likely to be read from disk
many times in an Emacs session?  I don't know for certain, but I would
have expected that to be common.

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

* Re: XPM via Lisp in the toolbar
  2002-11-17  7:15           ` Richard Stallman
@ 2002-11-17 12:30             ` alkibiades
  2002-11-17 12:49               ` Oliver Scholz
  0 siblings, 1 reply; 21+ messages in thread
From: alkibiades @ 2002-11-17 12:30 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     As long as the image is not _explicitly_ re-read from disk as in my
>     example and as long as the image descriptor is not garbage collected,
>     this should already be the case. Not even clearing the image cache (I
>     mean the built-in image cache) would cause a second conversion,
>     because the image descriptor contains all image data as a value of the
>     :data attribute.
>
> Are you sure that the same image is not likely to be read from disk
> many times in an Emacs session?  I don't know for certain, but I would
> have expected that to be common.

I don't know the C code behind that -- so please read the following
with that reservatio mentalis. But as far as I understand the issue,
it won't happen.

AFAICS it is prevented on two stages:

The Emacs Lisp Reference says about the image cache:

,----
|    Emacs stores images in an image cache when it displays them, so it
| can display them again more efficiently.  It removes an image from the
| cache when it hasn't been displayed for a specified period of time.
| 
|    When an image is looked up in the cache, its specification is
| compared with cached image specifications using `equal'.  This means
| that all images with equal specifications share the same image in the
| cache.
`----

The variable `image-cache-eviction-delay' controls how long an image
may remain in the image cache without being displayed. The default is
30 minutes.

Normally -- that is: without xpm.el -- the image descriptor for an
icon in the tool bar would look like this:

(image :file "/some/path/search.xpm" :type xpm ... )

So if the icon was not displayed for 30 minutes and Emacs has to
display it again, it would read "search.xpm" from the disk again. That
is how I understand it.

But with `xpm-create-image' hooked into `find-image' as a fall-back
for XPMs the image descriptor looks like this:

(image :data "P6 32 32 255 ... <binary data> ..." :type pbm ... )

So as far as Emacs is concerned there is no file attached to the image
anymore. The string after :data contains the whole information
necessary to display the image.

I don't know whether an image descriptor in `tool-bar-map' has any
chance to get garbage collected. As long as this does not happen,
there is no need to read the image from the disk again. To read the
image from the disk again, it would need another explicit call to
`find-image'. I wouldn't know where in the code this latter could take
place, BTW.

    Oliver
-- 
Oliver Scholz               27 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* Re: XPM via Lisp in the toolbar
  2002-11-17 12:30             ` alkibiades
@ 2002-11-17 12:49               ` Oliver Scholz
  0 siblings, 0 replies; 21+ messages in thread
From: Oliver Scholz @ 2002-11-17 12:49 UTC (permalink / raw)
  Cc: emacs-devel

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

I wrote:

[...]
> But with `xpm-create-image' hooked into `find-image' as a fall-back
> for XPMs the image descriptor looks like this:
>
> (image :data "P6 32 32 255 ... <binary data> ..." :type pbm ... )
[...]

I guess, I should show my code. Attached is a patch to image.el. But I
would like to test it more extensively.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: image.diff --]
[-- Type: text/x-patch, Size: 2356 bytes --]

Index: lisp/image.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/image.el,v
retrieving revision 1.33
diff -u -r1.33 image.el
--- lisp/image.el	3 Nov 2002 08:34:45 -0000	1.33
+++ lisp/image.el	17 Nov 2002 12:45:00 -0000
@@ -49,6 +49,12 @@
 a non-nil value, TYPE is the image's type ")
 
 
+;;;###autoload
+(defcustom use-lisp-xpm t
+  "If non-nil, use lisp functions to read XPM files.
+This happens only if Emacs was compiled without XPM support on the C
+level.")
+
 (defun image-jpeg-p (data)
   "Value is non-nil if DATA, a string, consists of JFIF image data.
 We accept the tag Exif because that is the same format."
@@ -143,9 +149,12 @@
     (error "Cannot determine image type"))
   (unless (symbolp type)
     (error "Invalid image type `%s'" type))
-  (when (image-type-available-p type)
-    (append (list 'image :type type (if data-p :data :file) file-or-data)
-	    props)))
+  (if (image-type-available-p type)
+      (append (list 'image :type type (if data-p :data :file) file-or-data)
+	      props)
+    (when (and (eq type 'xpm) use-lisp-xpm)
+      ;; Use Lisp to deal with the XPM.
+      (apply 'xpm-create-image file-or-data data-p props))))
 
 
 ;;;###autoload
@@ -245,7 +254,8 @@
 	     (data (plist-get spec :data))
 	     (file (plist-get spec :file))
 	     found)
-	(when (image-type-available-p type)
+	(when (or (image-type-available-p type)
+		  (and (eq type 'xpm) use-lisp-xpm))
 	  (cond ((stringp file)
 		 (let ((path load-path))
 		   (while (and (not found) path)
@@ -257,12 +267,18 @@
 		     (let ((try-file (expand-file-name file data-directory)))
 		       (if (file-readable-p try-file)
 			   (setq found try-file))))
-		   (if found
+		   (when found
+		     (if (image-type-available-p type)
+			 (setq image
+			       (cons 'image (plist-put (copy-sequence spec)
+						       :file found)))
+		       ;; Use Lisp functions to deal with XPMs.
 		       (setq image
-			     (cons 'image (plist-put (copy-sequence spec)
-						     :file found))))))
+			     (apply 'xpm-create-image found nil spec))))))
 		((not (null data))
-		 (setq image (cons 'image spec)))))
+		 (if (image-type-available-p type)
+		     (setq image (cons 'image spec))
+		   (setq image (apply 'xpm-create-image data t spec))))))
 	(setq specs (cdr specs))))
     image))
 

[-- Attachment #3: Type: text/plain, Size: 250 bytes --]



    Oliver
-- 
Oliver Scholz               27 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* Re: XPM via Lisp in the toolbar
  2002-11-15 15:06     ` Jason Rumney
  2002-11-15 18:06       ` Jason Rumney
@ 2002-11-18 14:08       ` Oliver Scholz
  2002-11-18 16:59         ` mushroom icon [was: Re: XPM via Lisp in the toolbar] John Paul Wallington
  2002-11-18 19:38         ` XPM via Lisp in the toolbar Jason Rumney
  1 sibling, 2 replies; 21+ messages in thread
From: Oliver Scholz @ 2002-11-18 14:08 UTC (permalink / raw)
  Cc: emacs-devel

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

Jason Rumney <jasonr@gnu.org> writes:
[...]
> I had some time last night to look more closely, and I think I now
> have image masks working, and have fixed some of the more serious
> bugs.

Great! Many thanks. This is a *huge* improvement:


[-- Attachment #2: tool-barx.png --]
[-- Type: image/png, Size: 5798 bytes --]

[-- Attachment #3: Type: text/plain, Size: 1382 bytes --]


However, I noticed two things:

The image mask seems to be supported only for `:mask 'heuristic'. This
determines the image mask by looking at the four corners of the
image. This is o.k. for almost any icon in the tool bar. But to get
its job done correctly in the general case, xpm.el needs to specify a
certain colour as the image mask, like: `:mask '(heuristic (0 0 0))'. 
This is so, because an XPM image may specify transparancy in arbitrary
places. For example: it could be a square containing a transparent
circle in the middle.

Unfortunately Emacs on MS Windows does not deal with 
`:mask '(heuristic (0 0 0)'. I generated the result in the attached
image by making a small change in xpm.el in order test your fix,
otherwise the icons would appear on a black background. But as I said
above, this is wrong in the general case. So could you implement this?
Or at least make Emacs on MS Windows ignore the part after
`heuristic'. This should do for most cases as far as icons are
concerned.

Another thing is, that it seems that the :ascent attribute does not
work; gamegrid.el needs to specify `:ascent 'center' for images.

    Oliver
-- 
Oliver Scholz               27 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* mushroom icon [was: Re: XPM via Lisp in the toolbar]
  2002-11-18 14:08       ` Oliver Scholz
@ 2002-11-18 16:59         ` John Paul Wallington
  2002-11-18 19:38         ` XPM via Lisp in the toolbar Jason Rumney
  1 sibling, 0 replies; 21+ messages in thread
From: John Paul Wallington @ 2002-11-18 16:59 UTC (permalink / raw)
  Cc: emacs-devel

Looking at the screenshot, I can understand why some Windows users
were complaining about the mushroom icon.

-- 
John Paul Wallington

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

* Re: XPM via Lisp in the toolbar
  2002-11-18 14:08       ` Oliver Scholz
  2002-11-18 16:59         ` mushroom icon [was: Re: XPM via Lisp in the toolbar] John Paul Wallington
@ 2002-11-18 19:38         ` Jason Rumney
  1 sibling, 0 replies; 21+ messages in thread
From: Jason Rumney @ 2002-11-18 19:38 UTC (permalink / raw)
  Cc: emacs-devel

Oliver Scholz <alkibiades@gmx.de> writes:

> The image mask seems to be supported only for `:mask 'heuristic'. This
> determines the image mask by looking at the four corners of the
> image. This is o.k. for almost any icon in the tool bar. But to get
> its job done correctly in the general case, xpm.el needs to specify a
> certain colour as the image mask, like: `:mask '(heuristic (0 0
> 0))'.

This is a bug, which I found last night. I will check in the fix
shortly. But shouldn't xpm.el use a monochrome image for the mask? I'm
not sure exactly how the heuristic algorithm works, but it would seem
there is a danger of confusing transparency with real black.

> Another thing is, that it seems that the :ascent attribute does not
> work; gamegrid.el needs to specify `:ascent 'center' for images.

I was wondering what was preventing gamegrid from working. Thanks.

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

* bootstrap fails with current CVS on MS Windows XP
  2002-11-15 17:47 ` W32 image patch (was Re: XPM via Lisp in the toolbar) Jason Rumney
@ 2002-11-19  8:51   ` Oliver Scholz
  2002-11-19  9:30     ` Juanma Barranquero
  2002-11-20 21:13     ` Richard Stallman
  0 siblings, 2 replies; 21+ messages in thread
From: Oliver Scholz @ 2002-11-19  8:51 UTC (permalink / raw)
  Cc: emacs-devel

I don't understand enough of the bootstrap process to make further
investigations. The error message I get is:

,----
| gcc -o oo-spd/i386/temacs.bin  -g -mno-cygwin  -Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -g -Wl,-subsystem,console -Wl,-entry,__start -Wl,-Map,oo-spd/i386/temacs.map oo-spd/i386/firstfile.o oo-spd/i386/emacs.res oo-spd/i386/temacs0.a oo-spd/i386/temacs1.a oo-spd/i386/temacw32.a oo-spd/i386/lastfile.a -ladvapi32 -lgdi32 -lcomdlg32 -luser32 -lmpr -lshell32 
| oo-spd/i386/temacs0.a(emacs.o.b): In function `main':
| /home/egoge/akt/cvs/emacs/src/emacs.c:1573: undefined reference to `init_sound'
| /home/egoge/akt/cvs/emacs/src/emacs.c:1479: undefined reference to `syms_of_sound'
| mmake.exe[2]: *** [oo-spd/i386/temacs.exe] Error 1
| mmake.exe[2]: Leaving directory `C:/cygwin/home/egoge/akt/cvs/emacs/src'
| mmake.exe[1]: *** [bootstrap-temacs] Error 2
| mmake.exe[1]: Leaving directory `C:/cygwin/home/egoge/akt/cvs/emacs/src'
| c:\Programme\bin\mmake.exe: *** [bootstrap-gmake] Error 2
`----

"mmake" is the mingw make; gcc is the cygwin build. Maybe it is my
fault; I don't understand the cygwin vs. mingw issue fully. But it
worked before ...

    Oliver
-- 
Oliver Scholz               29 Brumaire an 211 de la Révolution
Taunusstr. 25               Liberté, Egalité, Fraternité!
60329 Frankfurt a. M.       http://www.jungdemokratenhessen.de
Tel. (069) 97 40 99 42      http://www.jdjl.org

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

* Re: bootstrap fails with current CVS on MS Windows XP
  2002-11-19  8:51   ` bootstrap fails with current CVS on MS Windows XP Oliver Scholz
@ 2002-11-19  9:30     ` Juanma Barranquero
  2002-11-20 21:13     ` Richard Stallman
  1 sibling, 0 replies; 21+ messages in thread
From: Juanma Barranquero @ 2002-11-19  9:30 UTC (permalink / raw)
  Cc: Jason Rumney, emacs-devel

On Tue, 19 Nov 2002 09:51:43 +0100, Oliver Scholz <alkibiades@gmx.de> wrote:

> The error message I get is:

> | oo-spd/i386/temacs0.a(emacs.o.b): In function `main':
> | /home/egoge/akt/cvs/emacs/src/emacs.c:1573: undefined reference to `init_sound'
> | /home/egoge/akt/cvs/emacs/src/emacs.c:1479: undefined reference to `syms_of_sound'

That must be related to recent changes by Ben Key to support sound on
Windows. Try reverting his sound-related patches (see nt/ChangeLog and
src/ChangeLog, they're quite recent) and bootstrapping again.


                                                           /L/e/k/t/u

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

* Re: bootstrap fails with current CVS on MS Windows XP
  2002-11-19  8:51   ` bootstrap fails with current CVS on MS Windows XP Oliver Scholz
  2002-11-19  9:30     ` Juanma Barranquero
@ 2002-11-20 21:13     ` Richard Stallman
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Stallman @ 2002-11-20 21:13 UTC (permalink / raw)
  Cc: jasonr, emacs-devel

    | gcc -o oo-spd/i386/temacs.bin  -g -mno-cygwin  -Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -g -Wl,-subsystem,console -Wl,-entry,__start -Wl,-Map,oo-spd/i386/temacs.map oo-spd/i386/firstfile.o oo-spd/i386/emacs.res oo-spd/i386/temacs0.a oo-spd/i386/temacs1.a oo-spd/i386/temacw32.a oo-spd/i386/lastfile.a -ladvapi32 -lgdi32 -lcomdlg32 -luser32 -lmpr -lshell32 
    | oo-spd/i386/temacs0.a(emacs.o.b): In function `main':
    | /home/egoge/akt/cvs/emacs/src/emacs.c:1573: undefined reference to `init_sound'
    | /home/egoge/akt/cvs/emacs/src/emacs.c:1479: undefined reference to `syms_of_sound'

This is the original problem that causes the rest.  It looks like the
file with the sound code is not being included in the link.  You need
to find the list of object files to be linked, and see where that file
ought to be added.

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

end of thread, other threads:[~2002-11-20 21:13 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-11-12 17:32 XPM via Lisp in the toolbar Oliver Scholz
2002-11-13 17:15 ` Oliver Scholz
2002-11-15  2:36   ` Richard Stallman
2002-11-15  3:31     ` alkibiades
2002-11-15 14:08       ` Stefan Monnier
2002-11-16 14:51       ` Richard Stallman
2002-11-16 14:51       ` Richard Stallman
2002-11-16 18:44         ` alkibiades
2002-11-17  7:15           ` Richard Stallman
2002-11-17 12:30             ` alkibiades
2002-11-17 12:49               ` Oliver Scholz
2002-11-15 15:06     ` Jason Rumney
2002-11-15 18:06       ` Jason Rumney
2002-11-18 14:08       ` Oliver Scholz
2002-11-18 16:59         ` mushroom icon [was: Re: XPM via Lisp in the toolbar] John Paul Wallington
2002-11-18 19:38         ` XPM via Lisp in the toolbar Jason Rumney
2002-11-14  4:10 ` Richard Stallman
2002-11-15 17:47 ` W32 image patch (was Re: XPM via Lisp in the toolbar) Jason Rumney
2002-11-19  8:51   ` bootstrap fails with current CVS on MS Windows XP Oliver Scholz
2002-11-19  9:30     ` Juanma Barranquero
2002-11-20 21:13     ` 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).