Index: etc/NEWS =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/etc/NEWS,v retrieving revision 1.58.2.36 diff -u -r1.58.2.36 NEWS --- etc/NEWS 2000/03/10 10:15:12 1.58.2.36 +++ etc/NEWS 2000/03/16 10:55:36 @@ -70,8 +70,12 @@ location called "gutter". If you dislike the buffer tabs, you can disable them by specifying: - (set-specifier default-gutter-visible-p nil) + (customize-set-variable 'gutter-buffers-tab-visible-p nil) +or + + (set-gutter-element-visible-p default-gutter-visible-p 'buffers-tab nil) + in your `.emacs'. You can change the location of the gutter with `set-default-gutter-position', however currently only MS-Windows supports tab widgets with orientations other than vertical. @@ -192,6 +196,11 @@ By default this will attempt to scroll in increments equal to the height of the default face. Set `window-pixel-scroll-increment' to modify this behaviour. + +** Operation progress can be displayed using graphical widgets. +See `lprogress' for details. This support has been switched on by +default for font-lock and some web browsing functions. If you do not +like this behaviour set `progress-use-echo-area'. ** Etags changes. Index: lisp/font-lock.el =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lisp/font-lock.el,v retrieving revision 1.7.2.11 diff -u -r1.7.2.11 font-lock.el --- lisp/font-lock.el 2000/03/13 07:27:41 1.7.2.11 +++ lisp/font-lock.el 2000/03/16 10:55:52 @@ -840,8 +840,9 @@ ((or (null maximum-size) (<= (buffer-size) maximum-size)) (font-lock-fontify-buffer)) (font-lock-verbose - (lmessage 'command "Fontifying %s... buffer too big." - (buffer-name))))) + (lprogress 'font-lock + "Fontifying %s... buffer too big." 'abort + (buffer-name))))) (font-lock-fontified (setq font-lock-fontified nil) (remove-hook 'before-revert-hook 'font-lock-revert-setup t) @@ -1010,7 +1011,7 @@ (font-lock-mode 0))) (set (make-local-variable 'font-lock-fontified) t) (when (and aborted font-lock-verbose) - (lmessage 'command "Fontifying %s... aborted." (buffer-name)))) + (lprogress 'font-lock "Fontifying %s... aborted." 'abort (buffer-name)))) (run-hooks 'font-lock-after-fontify-buffer-hook)) (defun font-lock-default-unfontify-buffer () @@ -1049,7 +1050,7 @@ (defun font-lock-default-unfontify-region (beg end &optional maybe-loudly) (when (and maybe-loudly font-lock-verbose (>= (- end beg) font-lock-message-threshold)) - (lmessage 'progress "Fontifying %s..." (buffer-name))) + (lprogress 'font-lock "Fontifying %s..." 0 (buffer-name))) (let ((modified (buffer-modified-p)) (buffer-undo-list t) (inhibit-read-only t) buffer-file-name buffer-file-truename) @@ -1311,8 +1312,8 @@ nil (when (and font-lock-verbose (>= (- end start) font-lock-message-threshold)) - (lmessage 'progress "Fontifying %s... (syntactically...)" - (buffer-name))) + (lprogress 'font-lock "Fontifying %s... (syntactically)" 5 + (buffer-name))) (font-lock-unfontify-region start end loudly) (goto-char start) (if (> end (point-max)) (setq end (point-max))) @@ -1499,14 +1500,13 @@ (keywords (cdr (if (eq (car-safe font-lock-keywords) t) font-lock-keywords (font-lock-compile-keywords)))) - (bufname (buffer-name)) (count 0) + (bufname (buffer-name)) (count 5) keyword matcher highlights) ;; ;; Fontify each item in `font-lock-keywords' from `start' to `end'. (while keywords - (when loudly (lmessage 'progress "Fontifying %s... (regexps..%s)" - bufname - (make-string (setq count (1+ count)) ?.))) + (when loudly (lprogress 'font-lock "Fontifying %s... (regexps)" + (setq count (+ count 5)) bufname)) ;; ;; Find an occurrence of `matcher' from `start' to `end'. (setq keyword (car keywords) matcher (car keyword)) @@ -1529,7 +1529,7 @@ (font-lock-fontify-anchored-keywords (car highlights) end)) (setq highlights (cdr highlights)))) (setq keywords (cdr keywords)))) - (if loudly (lmessage 'progress "Fontifying %s... done." (buffer-name))))) + (if loudly (lprogress 'font-lock "Fontifying %s... " 100 (buffer-name))))) ;; Various functions. @@ -1554,17 +1554,26 @@ (lazy-lock-after-fontify-buffer)))) ;; If the buffer is about to be reverted, it won't be fontified afterward. -(defun font-lock-revert-setup () - (setq font-lock-fontified nil)) +;(defun font-lock-revert-setup () +; (setq font-lock-fontified nil)) ;; If the buffer has just been reverted, normally that turns off ;; Font Lock mode. So turn the mode back on if necessary. ;; sb 1999-03-03 -- The above comment no longer appears to be operative as ;; the first call to normal-mode *will* restore the font-lock state and ;; this call forces a second font-locking to occur when reverting a buffer, -;; which is wasteful at best. -;(defalias 'font-lock-revert-cleanup 'turn-on-font-lock) -(defun font-lock-revert-cleanup ()) +;; which is wasteful at best. +;;(defun font-lock-revert-cleanup ()) + +;; 12-10-99. This still does not work right, I think +;; after change functions will still get us. The simplest thing to do +;; is unconditionally turn-off font-lock before revert (and thus nuke +;; all hooks) and then turn it on again afterwards. This also happens +;; to be much faster because fontifying from scratch is better than +;; trying to do incremental changes for the whole buffer. + +(defalias 'font-lock-revert-cleanup 'turn-on-font-lock) +(defalias 'font-lock-revert-setup 'turn-off-font-lock) ;; Various functions. Index: lisp/gutter-items.el =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lisp/Attic/gutter-items.el,v retrieving revision 1.1.2.34 diff -u -r1.1.2.34 gutter-items.el --- lisp/gutter-items.el 2000/03/08 22:03:49 1.1.2.34 +++ lisp/gutter-items.el 2000/03/16 10:55:56 @@ -368,19 +368,23 @@ (cond ((eq gutter-buffers-tab-orientation 'top) ;; This looks better than a 3d border (set-specifier top-gutter-border-width 0 'global x) - (set-gutter-element top-gutter 'buffers-tab gutter-string 'global x)) + (set-gutter-element top-gutter 'buffers-tab + gutter-string 'global x)) ((eq gutter-buffers-tab-orientation 'bottom) (set-specifier bottom-gutter-border-width 0 'global x) - (set-gutter-element bottom-gutter 'buffers-tab gutter-string 'global x)) + (set-gutter-element bottom-gutter 'buffers-tab + gutter-string 'global x)) ((eq gutter-buffers-tab-orientation 'left) (set-specifier left-gutter-border-width 0 'global x) - (set-gutter-element left-gutter 'buffers-tab gutter-string 'global x) + (set-gutter-element left-gutter 'buffers-tab + gutter-string 'global x) (set-specifier left-gutter-width (glyph-width gutter-buffers-tab) 'global x)) ((eq gutter-buffers-tab-orientation 'right) (set-specifier right-gutter-border-width 0 'global x) - (set-gutter-element right-gutter 'buffers-tab gutter-string 'global x) + (set-gutter-element right-gutter 'buffers-tab + gutter-string 'global x) (set-specifier right-gutter-width (glyph-width gutter-buffers-tab) 'global x)) @@ -433,6 +437,14 @@ ;; progress display ;; ripped off from message display ;; +(defcustom progress-use-echo-area nil + "*Whether progress gauge display should display in the echo area. +If NIL then progress gauges will be displayed with whatever native widgets +are available on the current console. If non-NIL then progress display will be +textual and displayed in the echo area." + :type 'boolean + :group 'gutter) + (defvar progress-stack nil "An alist of label/string pairs representing active progress gauges. The first element in the list is currently displayed in the gutter area. @@ -505,7 +517,7 @@ ;;; Returns the string which remains in the echo area, or nil if none. ;;; If label is nil, the whole message stack is cleared. (defun clear-progress (&optional label frame no-restore) - "Remove any progress gauge with the given LABEL from the progress gauge-stack, + "Remove any progress gauge with LABEL from the progress gauge-stack, erasing it from the gutter area if it's currently displayed there. If a message remains at the head of the progress-stack and NO-RESTORE is nil, it will be displayed. The string which remains in the gutter @@ -514,21 +526,24 @@ Unless you need the return value or you need to specify a label, you should just use (progress nil)." - (or frame (setq frame (selected-frame))) - (remove-progress label frame) - (let ((inhibit-read-only t) - (zmacs-region-stays zmacs-region-stays)) ; preserve from change - (erase-buffer " *Echo Area*") - (erase-buffer (get-buffer-create " *Gutter Area*"))) - (if no-restore - nil ; just preparing to put another msg up - (if progress-stack - (let ((oldmsg (cdr (car progress-stack)))) - (raw-append-progress oldmsg frame) - oldmsg) - ;; nothing to display so get rid of the gauge - (set-specifier bottom-gutter-border-width 0 frame) - (set-gutter-element-visible-p bottom-gutter-visible-p 'progress nil frame)))) + (if (or (not (valid-image-instantiator-format-p 'progress-gauge frame)) + progress-use-echo-area) + (clear-message label frame nil no-restore) + (or frame (setq frame (selected-frame))) + (remove-progress label frame) + (let ((inhibit-read-only t) + (zmacs-region-stays zmacs-region-stays)) ; preserve from change + (erase-buffer (get-buffer-create " *Gutter Area*"))) + (if no-restore + nil ; just preparing to put another msg up + (if progress-stack + (let ((oldmsg (cdr (car progress-stack)))) + (raw-append-progress oldmsg frame) + oldmsg) + ;; nothing to display so get rid of the gauge + (set-specifier bottom-gutter-border-width 0 frame) + (set-gutter-element-visible-p bottom-gutter-visible-p + 'progress nil frame))))) (defun remove-progress (&optional label frame) ;; If label is nil, we want to remove all matching progress gauges. @@ -552,49 +567,50 @@ (if (eq label (car top)) (progn (setcdr top message) - (if (eq tmsg message) + (if (equal tmsg message) (set-image-instance-property (glyph-image-instance progress-gauge-glyph) :percent value) (raw-append-progress message value frame)) - (redisplay-gutter-area) - (when (input-pending-p) - (dispatch-event (next-command-event)))) + (redisplay-gutter-area)) (push (cons label message) progress-stack) (raw-append-progress message value frame)) + (dispatch-non-command-events) + (when (input-pending-p) + (dispatch-event (next-command-event))) (when (eq value 100) (sit-for 0.5 nil) (clear-progress label)))) (defun abort-progress (label message &optional frame) - (or frame (setq frame (selected-frame))) - ;; Add a new entry to the message-stack, or modify an existing one - (let* ((top (car progress-stack)) - (inhibit-read-only t) - (zmacs-region-stays zmacs-region-stays)) - (if (eq label (car top)) - (setcdr top message) - (push (cons label message) progress-stack)) - (unless (equal message "") - (insert-string message (get-buffer-create " *Gutter Area*")) - ;; Do what the device is able to cope with. - (if (not (valid-image-instantiator-format-p 'progress-gauge frame)) - (progn - (insert-string message " *Echo Area*") - (if (not executing-kbd-macro) - (redisplay-echo-area))) + (if (or (not (valid-image-instantiator-format-p 'progress-gauge frame)) + progress-use-echo-area) + (display-message label (concat message "aborted.") frame) + (or frame (setq frame (selected-frame))) + ;; Add a new entry to the message-stack, or modify an existing one + (let* ((top (car progress-stack)) + (inhibit-read-only t) + (zmacs-region-stays zmacs-region-stays)) + (if (eq label (car top)) + (setcdr top message) + (push (cons label message) progress-stack)) + (unless (equal message "") + (insert-string message (get-buffer-create " *Gutter Area*")) + ;; Do what the device is able to cope with. ;; do some funky display here. (unless progress-extent (setq progress-extent (make-extent 0 1 progress-extent-text))) (let ((bglyph (extent-begin-glyph progress-extent))) (set-extent-begin-glyph progress-extent progress-abort-glyph) ;; fixup the gutter specifiers - (set-gutter-element bottom-gutter 'progress progress-extent-text frame) + (set-gutter-element bottom-gutter + 'progress progress-extent-text frame) (set-specifier bottom-gutter-border-width 2 frame) (set-image-instance-property (glyph-image-instance progress-text-glyph) :data message) (set-specifier bottom-gutter-height 'autodetect frame) - (set-gutter-element-visible-p bottom-gutter-visible-p 'progress t frame) + (set-gutter-element-visible-p bottom-gutter-visible-p + 'progress t frame) ;; we have to do this so redisplay is up-to-date and so ;; redisplay-gutter-area performs optimally. (redisplay-gutter-area) @@ -607,54 +623,55 @@ (unless (equal message "") (let ((inhibit-read-only t) (zmacs-region-stays zmacs-region-stays) - (val (or value 0))) ; preserve from change + (val (or value 0))) (insert-string message (get-buffer-create " *Gutter Area*")) - ;; Do what the device is able to cope with. - (if (not (valid-image-instantiator-format-p 'progress-gauge frame)) + ;; do some funky display here. + (unless progress-extent + (setq progress-extent (make-extent 0 1 progress-extent-text)) + (set-extent-begin-glyph progress-extent progress-layout-glyph)) + ;; fixup the gutter specifiers + (set-gutter-element bottom-gutter 'progress progress-extent-text frame) + (set-specifier bottom-gutter-border-width 2 frame) + (set-image-instance-property + (glyph-image-instance progress-gauge-glyph) :percent val) + (set-image-instance-property + (glyph-image-instance progress-text-glyph) :data message) + (if (and (eq (specifier-instance bottom-gutter-height frame) + 'autodetect) + (gutter-element-visible-p bottom-gutter-visible-p + 'progress frame)) (progn - (insert-string - (concat message (if (eq val 100) "done.") - (make-string (/ val 5) ?.)) - " *Echo Area*") - (if (not executing-kbd-macro) - (redisplay-echo-area))) - ;; do some funky display here. - (unless progress-extent - (setq progress-extent (make-extent 0 1 progress-extent-text)) - (set-extent-begin-glyph progress-extent progress-layout-glyph)) - ;; fixup the gutter specifiers - (set-gutter-element bottom-gutter 'progress progress-extent-text frame) - (set-specifier bottom-gutter-border-width 2 frame) - (set-image-instance-property - (glyph-image-instance progress-gauge-glyph) :percent val) - (set-image-instance-property - (glyph-image-instance progress-text-glyph) :data message) - (if (and (eq (specifier-instance bottom-gutter-height frame) - 'autodetect) - (gutter-element-visible-p bottom-gutter-visible-p 'progress frame)) - (progn - ;; if the gauge is already visible then just draw the gutter - ;; checking for user events - (redisplay-gutter-area) - (when (input-pending-p) - (dispatch-event (next-command-event)))) - ;; otherwise make the gutter visible and redraw the frame - (set-specifier bottom-gutter-height 'autodetect frame) - (set-gutter-element-visible-p bottom-gutter-visible-p 'progress t frame) - ;; we have to do this so redisplay is up-to-date and so - ;; redisplay-gutter-area performs optimally. - (redisplay-frame) - ))))) + ;; if the gauge is already visible then just draw the gutter + ;; checking for user events + (redisplay-gutter-area) + (dispatch-non-command-events) + (when (input-pending-p) + (dispatch-event (next-command-event)))) + ;; otherwise make the gutter visible and redraw the frame + (set-specifier bottom-gutter-height 'autodetect frame) + (set-gutter-element-visible-p bottom-gutter-visible-p + 'progress t frame) + ;; we have to do this so redisplay is up-to-date and so + ;; redisplay-gutter-area performs optimally. + (dispatch-non-command-events) + (redisplay-frame) + )))) (defun display-progress (label message &optional value frame) "Display a progress gauge and message in the bottom gutter area. First argument LABEL is an identifier for this message. MESSAGE is the string to display. Use `clear-progress' to remove a labelled message." - (clear-progress label frame t) - (if (eq value 'abort) - (abort-progress label message frame) - (append-progress label message value frame))) + (cond ((eq value 'abort) + (abort-progress label message frame)) + ((or (not (valid-image-instantiator-format-p 'progress-gauge frame)) + progress-use-echo-area) + (display-message label + (concat message (if (eq value 100) "done." + (make-string (/ value 5) ?.))) + frame)) + (t + (append-progress label message value frame)))) (defun current-progress (&optional frame) "Return the current progress gauge in the gutter area, or nil. Index: src/event-Xt.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/event-Xt.c,v retrieving revision 1.41.2.22 diff -u -r1.41.2.22 event-Xt.c --- src/event-Xt.c 2000/03/13 07:27:54 1.41.2.22 +++ src/event-Xt.c 2000/03/16 10:56:14 @@ -1455,6 +1455,7 @@ case FocusIn: case FocusOut: FROB(xfocus, window); break; case VisibilityNotify: FROB(xvisibility, window); break; + case CreateNotify: FROB(xcreatewindow, window); break; default: w = x_event->xany.window; *x_event_copy = *x_event; @@ -1714,6 +1715,25 @@ } static void +emacs_Xt_force_event_pending (struct frame* f) +{ + XEvent event; + + Display* dpy = DEVICE_X_DISPLAY (XDEVICE (FRAME_DEVICE (f))); + event.xclient.type = ClientMessage; + event.xclient.display = dpy; + event.xclient.message_type = XInternAtom (dpy, "BumpQueue", False); + event.xclient.format = 32; + event.xclient.window = 0; + + /* Send the drop message */ + XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)), + True, NoEventMask, &event); + /* Force event pending to check the X queue. */ + quit_check_signal_tick_count++; +} + +static void emacs_Xt_handle_magic_event (Lisp_Event *emacs_event) { /* This function can GC */ @@ -1826,6 +1846,9 @@ #endif break; + case CreateNotify: + printf ("window created\n"); + break; default: break; } @@ -3072,6 +3095,7 @@ { Xt_event_stream = xnew (struct event_stream); Xt_event_stream->event_pending_p = emacs_Xt_event_pending_p; + Xt_event_stream->force_event_pending = emacs_Xt_force_event_pending; Xt_event_stream->next_event_cb = emacs_Xt_next_event; Xt_event_stream->handle_magic_event_cb = emacs_Xt_handle_magic_event; Xt_event_stream->add_timeout_cb = emacs_Xt_add_timeout; Index: src/event-msw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/event-msw.c,v retrieving revision 1.38.2.40 diff -u -r1.38.2.40 event-msw.c --- src/event-msw.c 2000/03/13 07:27:54 1.38.2.40 +++ src/event-msw.c 2000/03/16 10:56:27 @@ -184,11 +184,11 @@ struct ntpipe_slurp_stream_shared_data { HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ - /* This is a manual-reset object. */ + /* This is a manual-reset object. */ HANDLE hev_caller; /* Caller blocks on this, and we signal it */ - /* This is a manual-reset object. */ + /* This is a manual-reset object. */ HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ - /* This is a manual-reset object. */ + /* This is a manual-reset object. */ HANDLE hpipe; /* Pipe read end handle. */ LONG die_p; /* Thread must exit ASAP if non-zero */ BOOL eof_p : 1; /* Set when thread saw EOF */ @@ -474,7 +474,7 @@ { LPARAM user_data; /* Any user data stored in the stream object */ HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ - /* This is an auto-reset object. */ + /* This is an auto-reset object. */ HANDLE hpipe; /* Pipe write end handle. */ HANDLE hthread; /* Reader thread handle. */ char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ @@ -876,9 +876,9 @@ int user_p = mswindows_user_event_p (XEVENT(event)); enqueue_event (event, user_p ? &mswindows_u_dispatch_event_queue : - &mswindows_s_dispatch_event_queue, + &mswindows_s_dispatch_event_queue, user_p ? &mswindows_u_dispatch_event_queue_tail : - &mswindows_s_dispatch_event_queue_tail); + &mswindows_s_dispatch_event_queue_tail); /* Avoid blocking on WaitMessage */ PostMessage (NULL, XM_BUMPQUEUE, 0, 0); @@ -1005,10 +1005,10 @@ !NILP(mswindows_s_dispatch_event_queue)); event = dequeue_event ( - NILP(mswindows_u_dispatch_event_queue) ? + NILP(mswindows_u_dispatch_event_queue) ? &mswindows_s_dispatch_event_queue : &mswindows_u_dispatch_event_queue, - NILP(mswindows_u_dispatch_event_queue) ? + NILP(mswindows_u_dispatch_event_queue) ? &mswindows_s_dispatch_event_queue_tail : &mswindows_u_dispatch_event_queue_tail); @@ -1039,9 +1039,9 @@ Lisp_Object previous_event = Qnil; int user_p = mswindows_user_event_p (match); Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : - &mswindows_s_dispatch_event_queue; + &mswindows_s_dispatch_event_queue; Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : - &mswindows_s_dispatch_event_queue_tail; + &mswindows_s_dispatch_event_queue_tail; assert (match->event_type == timeout_event || match->event_type == key_press_event); @@ -1226,7 +1226,7 @@ GCPRO1 (result); if (NILP(mswindows_error_caught_in_modal_loop)) - result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); + result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); UNGCPRO; return result; } @@ -1265,7 +1265,7 @@ /* Queue a magic event for handling when safe */ msframe = FRAME_MSWINDOWS_DATA ( - XFRAME (mswindows_find_frame (msg.hwnd))); + XFRAME (mswindows_find_frame (msg.hwnd))); if (!msframe->paint_pending) { msframe->paint_pending = 1; @@ -1369,48 +1369,51 @@ { mswindows_drain_windows_queue (); } -#ifdef HAVE_TTY - /* Look for a TTY event */ - for (i = 0; i < MAXDESC-1; i++) + else { - /* To avoid race conditions (among other things, an infinite - loop when called from Fdiscard_input()), we must return - user events ahead of process events. */ - if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) +#ifdef HAVE_TTY + /* Look for a TTY event */ + for (i = 0; i < MAXDESC-1; i++) { - struct console *c = tty_find_console_from_fd (i); - Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - Lisp_Event* event = XEVENT (emacs_event); - - assert (c); - if (read_event_from_tty_or_stream_desc (event, c, i)) + /* To avoid race conditions (among other things, an infinite + loop when called from Fdiscard_input()), we must return + user events ahead of process events. */ + if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) { - mswindows_enqueue_dispatch_event (emacs_event); - return; + struct console *c = tty_find_console_from_fd (i); + Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); + Lisp_Event* event = XEVENT (emacs_event); + + assert (c); + if (read_event_from_tty_or_stream_desc (event, c, i)) + { + mswindows_enqueue_dispatch_event (emacs_event); + return; + } } } - } #endif - /* Look for a process event */ - for (i = 0; i < MAXDESC-1; i++) - { - if (FD_ISSET (i, &temp_mask)) + /* Look for a process event */ + for (i = 0; i < MAXDESC-1; i++) { - if (FD_ISSET (i, &process_only_mask)) + if (FD_ISSET (i, &temp_mask)) { - Lisp_Process *p = - get_process_from_usid (FD_TO_USID(i)); - - mswindows_enqueue_process_event (p); - } - else - { - /* We might get here when a fake event came - through a signal. Return a dummy event, so - that a cycle of the command loop will - occur. */ - drain_signal_event_pipe (); - mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); + if (FD_ISSET (i, &process_only_mask)) + { + Lisp_Process *p = + get_process_from_usid (FD_TO_USID(i)); + + mswindows_enqueue_process_event (p); + } + else + { + /* We might get here when a fake event came + through a signal. Return a dummy event, so + that a cycle of the command loop will + occur. */ + drain_signal_event_pipe (); + mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); + } } } } @@ -1429,53 +1432,53 @@ } #else /* Now try getting a message or process event */ - active = MsgWaitForMultipleObjects (mswindows_waitable_count, - mswindows_waitable_handles, - FALSE, badly_p ? INFINITE : 0, - QS_ALLINPUT); - - /* This will assert if handle being waited for becomes abandoned. - Not the case currently tho */ - assert ((!badly_p && active == WAIT_TIMEOUT) || - (active >= WAIT_OBJECT_0 && - active <= WAIT_OBJECT_0 + mswindows_waitable_count)); + active = MsgWaitForMultipleObjects (mswindows_waitable_count, + mswindows_waitable_handles, + FALSE, badly_p ? INFINITE : 0, + QS_ALLINPUT); + + /* This will assert if handle being waited for becomes abandoned. + Not the case currently tho */ + assert ((!badly_p && active == WAIT_TIMEOUT) || + (active >= WAIT_OBJECT_0 && + active <= WAIT_OBJECT_0 + mswindows_waitable_count)); - if (active == WAIT_TIMEOUT) - { - /* No luck trying - just return what we've already got */ - return; - } - else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) - { - /* Got your message, thanks */ - mswindows_drain_windows_queue (); - } - else - { - int ix = active - WAIT_OBJECT_0; - /* First, try to find which process' output has signaled */ - Lisp_Process *p = - get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); - if (p != NULL) - { - /* Found a signaled process input handle */ - mswindows_enqueue_process_event (p); - } - else - { - /* None. This means that the process handle itself has signaled. - Remove the handle from the wait vector, and make status_notify - note the exited process */ - mswindows_waitable_handles [ix] = - mswindows_waitable_handles [--mswindows_waitable_count]; - kick_status_notify (); - /* Have to return something: there may be no accompanying - process event */ - mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); - } - } + if (active == WAIT_TIMEOUT) + { + /* No luck trying - just return what we've already got */ + return; + } + else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) + { + /* Got your message, thanks */ + mswindows_drain_windows_queue (); + } + else + { + int ix = active - WAIT_OBJECT_0; + /* First, try to find which process' output has signaled */ + Lisp_Process *p = + get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); + if (p != NULL) + { + /* Found a signaled process input handle */ + mswindows_enqueue_process_event (p); + } + else + { + /* None. This means that the process handle itself has signaled. + Remove the handle from the wait vector, and make status_notify + note the exited process */ + mswindows_waitable_handles [ix] = + mswindows_waitable_handles [--mswindows_waitable_count]; + kick_status_notify (); + /* Have to return something: there may be no accompanying + process event */ + mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); + } + } #endif - } /* while */ + } /* while */ } /************************************************************************/ @@ -1630,34 +1633,34 @@ */ static void mswindows_handle_paint (struct frame *frame) - { - HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame); - - /* According to the docs we need to check GetUpdateRect() before - actually doing a WM_PAINT */ - if (GetUpdateRect (hwnd, NULL, FALSE)) - { - PAINTSTRUCT paintStruct; - int x, y, width, height; +{ + HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame); - BeginPaint (hwnd, &paintStruct); - x = paintStruct.rcPaint.left; - y = paintStruct.rcPaint.top; - width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; - height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; - /* Normally we want to ignore expose events when child - windows are unmapped, however once we are in the guts of - WM_PAINT we need to make sure that we don't register - unmaps then because they will not actually occur. */ - if (!check_for_ignored_expose (frame, x, y, width, height)) - { - hold_ignored_expose_registration = 1; - mswindows_redraw_exposed_area (frame, x, y, width, height); - hold_ignored_expose_registration = 0; - } - EndPaint (hwnd, &paintStruct); - } - } + /* According to the docs we need to check GetUpdateRect() before + actually doing a WM_PAINT */ + if (GetUpdateRect (hwnd, NULL, FALSE)) + { + PAINTSTRUCT paintStruct; + int x, y, width, height; + + BeginPaint (hwnd, &paintStruct); + x = paintStruct.rcPaint.left; + y = paintStruct.rcPaint.top; + width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; + height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; + /* Normally we want to ignore expose events when child + windows are unmapped, however once we are in the guts of + WM_PAINT we need to make sure that we don't register + unmaps then because they will not actually occur. */ + if (!check_for_ignored_expose (frame, x, y, width, height)) + { + hold_ignored_expose_registration = 1; + mswindows_redraw_exposed_area (frame, x, y, width, height); + hold_ignored_expose_registration = 0; + } + EndPaint (hwnd, &paintStruct); + } +} /* * Returns 1 if a key is a real modifier or special key, which @@ -1687,820 +1690,821 @@ struct frame *frame; struct mswindows_frame* msframe; + assert (!GetWindowLong (hwnd, GWL_USERDATA)); switch (message) - { - case WM_DESTROYCLIPBOARD: - /* We own the clipboard and someone else wants it. Delete our - cached copy of the clipboard contents so we'll ask for it from - Windows again when someone does a paste. */ - handle_selection_clear(QCLIPBOARD); - break; - - case WM_ERASEBKGND: - /* Erase background only during non-dynamic sizing */ - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - if (msframe->sizing && !mswindows_dynamic_frame_resize) - goto defproc; - return 1; - - case WM_CLOSE: - fobj = mswindows_find_frame (hwnd); - mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); - break; - - case WM_KEYUP: - case WM_SYSKEYUP: - /* See Win95 comment under WM_KEYDOWN */ { - BYTE keymap[256]; - int should_set_keymap = 0; - - if (wParam == VK_CONTROL) - { - GetKeyboardState (keymap); - keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; - should_set_keymap = 1; - } - else if (wParam == VK_MENU) - { - GetKeyboardState (keymap); - keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; - should_set_keymap = 1; - } - - if (should_set_keymap - && (message != WM_SYSKEYUP - || NILP (Vmenu_accelerator_enabled))) - SetKeyboardState (keymap); - - } - if (key_needs_default_processing_p (wParam)) - goto defproc; - else + case WM_DESTROYCLIPBOARD: + /* We own the clipboard and someone else wants it. Delete our + cached copy of the clipboard contents so we'll ask for it from + Windows again when someone does a paste. */ + handle_selection_clear(QCLIPBOARD); break; - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - /* In some locales the right-hand Alt key is labelled AltGr. This key - * should produce alternative charcaters when combined with another key. - * eg on a German keyboard pressing AltGr+q should produce '@'. - * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if - * TranslateMessage() is called with *any* combination of Ctrl+Alt down, - * it translates as if AltGr were down. - * We get round this by removing all modifiers from the keymap before - * calling TranslateMessage() unless AltGr is *really* down. */ - { - BYTE keymap[256]; - int has_AltGr = mswindows_current_layout_has_AltGr (); - int mods; - int extendedp = lParam & 0x1000000; - Lisp_Object keysym; - - frame = XFRAME (mswindows_find_frame (hwnd)); - GetKeyboardState (keymap); - mods = mswindows_modifier_state (keymap, has_AltGr); - - /* Handle non-printables */ - if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, - extendedp))) - mswindows_enqueue_keypress_event (hwnd, keysym, mods); - else /* Normal keys & modifiers */ - { - Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); - BYTE keymap_orig[256]; - POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; - MSG msg, tranmsg; - int potential_accelerator = 0; - int got_accelerator = 0; - - msg.hwnd = hwnd; - msg.message = message; - msg.wParam = wParam; - msg.lParam = lParam; - msg.time = GetMessageTime(); - msg.pt = pnt; - - /* GetKeyboardState() does not work as documented on Win95. We have - * to loosely track Left and Right modifiers on behalf of the OS, - * without screwing up Windows NT which tracks them properly. */ - if (wParam == VK_CONTROL) - keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; - else if (wParam == VK_MENU) - keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80; - - memcpy (keymap_orig, keymap, 256); - - if (!NILP (Vmenu_accelerator_enabled) && - !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN) - potential_accelerator = 1; - - /* Remove shift modifier from an ascii character */ - mods &= ~XEMACS_MOD_SHIFT; - - /* Clear control and alt modifiers unless AltGr is pressed */ - keymap [VK_RCONTROL] = 0; - keymap [VK_LMENU] = 0; - if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) - || !(keymap [VK_RMENU] & 0x80)) - { - keymap [VK_LCONTROL] = 0; - keymap [VK_CONTROL] = 0; - keymap [VK_RMENU] = 0; - keymap [VK_MENU] = 0; - } - SetKeyboardState (keymap); - - /* Maybe generate some WM_[SYS]CHARs in the queue */ - TranslateMessage (&msg); - - while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) - || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) - { - int mods1 = mods; - WPARAM ch = tranmsg.wParam; + case WM_ERASEBKGND: + /* Erase background only during non-dynamic sizing */ + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + if (msframe->sizing && !mswindows_dynamic_frame_resize) + goto defproc; + return 1; - /* If a quit char with no modifiers other than control and - shift, then mark it with a fake modifier, which is removed - upon dequeueing the event */ - /* #### This might also not withstand localization, if - quit character is not a latin-1 symbol */ - if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) && quit_ch + 'a' - 1 == ch) - || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) && quit_ch == ch)) - && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) == 0)) - { - mods1 |= FAKE_MOD_QUIT; - ++mswindows_quit_chars_count; - } - else if (potential_accelerator && !got_accelerator && - msw_char_is_accelerator (frame, ch)) - { - got_accelerator = 1; - break; - } - mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1); - } /* while */ - SetKeyboardState (keymap_orig); - /* This generates WM_SYSCHAR messages, which are interpreted - by DefWindowProc as the menu selections. */ - if (got_accelerator) - { - TranslateMessage (&msg); - goto defproc; - } - } /* else */ - } - if (key_needs_default_processing_p (wParam)) - goto defproc; - else + case WM_CLOSE: + fobj = mswindows_find_frame (hwnd); + mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); break; - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - /* Real middle mouse button has nothing to do with emulated one: - if one wants to exercise fingers playing chords on the mouse, - he is allowed to do that! */ - mswindows_enqueue_mouse_button_event (hwnd, message, - MAKEPOINTS (lParam), GetMessageTime()); - break; - - case WM_LBUTTONUP: - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - msframe->last_click_time = GetMessageTime(); - - KillTimer (hwnd, BUTTON_2_TIMER_ID); - msframe->button2_need_lbutton = 0; - if (msframe->ignore_next_lbutton_up) + case WM_KEYUP: + case WM_SYSKEYUP: + /* See Win95 comment under WM_KEYDOWN */ { - msframe->ignore_next_lbutton_up = 0; - } - else if (msframe->button2_is_down) - { - msframe->button2_is_down = 0; - msframe->ignore_next_rbutton_up = 1; - mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); - } - else - { - if (msframe->button2_need_rbutton) + BYTE keymap[256]; + int should_set_keymap = 0; + + if (wParam == VK_CONTROL) { - msframe->button2_need_rbutton = 0; - mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + GetKeyboardState (keymap); + keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; + should_set_keymap = 1; } - mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); - } - break; - - case WM_RBUTTONUP: - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - msframe->last_click_time = GetMessageTime(); - - KillTimer (hwnd, BUTTON_2_TIMER_ID); - msframe->button2_need_rbutton = 0; - if (msframe->ignore_next_rbutton_up) - { - msframe->ignore_next_rbutton_up = 0; - } - else if (msframe->button2_is_down) - { - msframe->button2_is_down = 0; - msframe->ignore_next_lbutton_up = 1; - mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); - } - else - { - if (msframe->button2_need_lbutton) + else if (wParam == VK_MENU) { - msframe->button2_need_lbutton = 0; - mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + GetKeyboardState (keymap); + keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; + should_set_keymap = 1; } - mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); - } - break; - case WM_LBUTTONDOWN: - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + if (should_set_keymap + && (message != WM_SYSKEYUP + || NILP (Vmenu_accelerator_enabled))) + SetKeyboardState (keymap); - if (msframe->button2_need_lbutton) - { - KillTimer (hwnd, BUTTON_2_TIMER_ID); - msframe->button2_need_lbutton = 0; - msframe->button2_need_rbutton = 0; - if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) - { - mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); - msframe->button2_is_down = 1; - } - else - { - mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); - mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); - } } - else - { - mswindows_set_chord_timer (hwnd); - msframe->button2_need_rbutton = 1; - msframe->last_click_point = MAKEPOINTS (lParam); - } - msframe->last_click_time = GetMessageTime(); - break; - - case WM_RBUTTONDOWN: - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + if (key_needs_default_processing_p (wParam)) + goto defproc; + else + break; - if (msframe->button2_need_rbutton) - { - KillTimer (hwnd, BUTTON_2_TIMER_ID); - msframe->button2_need_lbutton = 0; - msframe->button2_need_rbutton = 0; - if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) - { - mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); - msframe->button2_is_down = 1; - } - else + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + /* In some locales the right-hand Alt key is labelled AltGr. This key + * should produce alternative charcaters when combined with another key. + * eg on a German keyboard pressing AltGr+q should produce '@'. + * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if + * TranslateMessage() is called with *any* combination of Ctrl+Alt down, + * it translates as if AltGr were down. + * We get round this by removing all modifiers from the keymap before + * calling TranslateMessage() unless AltGr is *really* down. */ + { + BYTE keymap[256]; + int has_AltGr = mswindows_current_layout_has_AltGr (); + int mods; + int extendedp = lParam & 0x1000000; + Lisp_Object keysym; + + frame = XFRAME (mswindows_find_frame (hwnd)); + GetKeyboardState (keymap); + mods = mswindows_modifier_state (keymap, has_AltGr); + + /* Handle non-printables */ + if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, + extendedp))) + mswindows_enqueue_keypress_event (hwnd, keysym, mods); + else /* Normal keys & modifiers */ { - mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); - mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); - } - } - else - { - mswindows_set_chord_timer (hwnd); - msframe->button2_need_lbutton = 1; - msframe->last_click_point = MAKEPOINTS (lParam); - } - msframe->last_click_time = GetMessageTime(); - break; + Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); + BYTE keymap_orig[256]; + POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; + MSG msg, tranmsg; + int potential_accelerator = 0; + int got_accelerator = 0; + + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetMessageTime(); + msg.pt = pnt; + + /* GetKeyboardState() does not work as documented on Win95. We have + * to loosely track Left and Right modifiers on behalf of the OS, + * without screwing up Windows NT which tracks them properly. */ + if (wParam == VK_CONTROL) + keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + else if (wParam == VK_MENU) + keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80; + + memcpy (keymap_orig, keymap, 256); + + if (!NILP (Vmenu_accelerator_enabled) && + !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN) + potential_accelerator = 1; + + /* Remove shift modifier from an ascii character */ + mods &= ~XEMACS_MOD_SHIFT; + + /* Clear control and alt modifiers unless AltGr is pressed */ + keymap [VK_RCONTROL] = 0; + keymap [VK_LMENU] = 0; + if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) + || !(keymap [VK_RMENU] & 0x80)) + { + keymap [VK_LCONTROL] = 0; + keymap [VK_CONTROL] = 0; + keymap [VK_RMENU] = 0; + keymap [VK_MENU] = 0; + } + SetKeyboardState (keymap); - case WM_TIMER: - if (wParam == BUTTON_2_TIMER_ID) - { - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - KillTimer (hwnd, BUTTON_2_TIMER_ID); + /* Maybe generate some WM_[SYS]CHARs in the queue */ + TranslateMessage (&msg); - if (msframe->button2_need_lbutton) - { - msframe->button2_need_lbutton = 0; - mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); - } - else if (msframe->button2_need_rbutton) - { - msframe->button2_need_rbutton = 0; - mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); - } + while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) + || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) + { + int mods1 = mods; + WPARAM ch = tranmsg.wParam; + + /* If a quit char with no modifiers other than control and + shift, then mark it with a fake modifier, which is removed + upon dequeueing the event */ + /* #### This might also not withstand localization, if + quit character is not a latin-1 symbol */ + if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) && quit_ch + 'a' - 1 == ch) + || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) && quit_ch == ch)) + && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) == 0)) + { + mods1 |= FAKE_MOD_QUIT; + ++mswindows_quit_chars_count; + } + else if (potential_accelerator && !got_accelerator && + msw_char_is_accelerator (frame, ch)) + { + got_accelerator = 1; + break; + } + mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1); + } /* while */ + SetKeyboardState (keymap_orig); + /* This generates WM_SYSCHAR messages, which are interpreted + by DefWindowProc as the menu selections. */ + if (got_accelerator) + { + TranslateMessage (&msg); + goto defproc; + } + } /* else */ } - else - assert ("Spurious timer fired" == 0); - break; + if (key_needs_default_processing_p (wParam)) + goto defproc; + else + break; - case WM_MOUSEMOVE: - /* Optimization: don't report mouse movement while size is changing */ - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - if (!msframe->sizing) - { - /* When waiting for the second mouse button to finish - button2 emulation, and have moved too far, just pretend - as if timer has expired. This improves drag-select feedback */ - if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) - && !mswindows_button2_near_enough (msframe->last_click_point, - MAKEPOINTS (lParam))) + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + /* Real middle mouse button has nothing to do with emulated one: + if one wants to exercise fingers playing chords on the mouse, + he is allowed to do that! */ + mswindows_enqueue_mouse_button_event (hwnd, message, + MAKEPOINTS (lParam), GetMessageTime()); + break; + + case WM_LBUTTONUP: + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + msframe->last_click_time = GetMessageTime(); + + KillTimer (hwnd, BUTTON_2_TIMER_ID); + msframe->button2_need_lbutton = 0; + if (msframe->ignore_next_lbutton_up) + { + msframe->ignore_next_lbutton_up = 0; + } + else if (msframe->button2_is_down) + { + msframe->button2_is_down = 0; + msframe->ignore_next_rbutton_up = 1; + mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, + MAKEPOINTS (lParam), GetMessageTime()); + } + else { - KillTimer (hwnd, BUTTON_2_TIMER_ID); - SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); + if (msframe->button2_need_rbutton) + { + msframe->button2_need_rbutton = 0; + mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, + MAKEPOINTS (lParam), GetMessageTime()); + } + mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, + MAKEPOINTS (lParam), GetMessageTime()); } - - emacs_event = Fmake_event (Qnil, Qnil); - event = XEVENT(emacs_event); - - event->channel = mswindows_find_frame(hwnd); - event->timestamp = GetMessageTime(); - event->event_type = pointer_motion_event; - event->event.motion.x = MAKEPOINTS(lParam).x; - event->event.motion.y = MAKEPOINTS(lParam).y; - event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); - - mswindows_enqueue_dispatch_event (emacs_event); - } - break; + break; - case WM_CANCELMODE: - ReleaseCapture (); - /* Queue a `cancel-mode-internal' misc user event, so mouse - selection would be canceled if any */ - mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), - Qcancel_mode_internal, Qnil); - break; + case WM_RBUTTONUP: + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + msframe->last_click_time = GetMessageTime(); + + KillTimer (hwnd, BUTTON_2_TIMER_ID); + msframe->button2_need_rbutton = 0; + if (msframe->ignore_next_rbutton_up) + { + msframe->ignore_next_rbutton_up = 0; + } + else if (msframe->button2_is_down) + { + msframe->button2_is_down = 0; + msframe->ignore_next_lbutton_up = 1; + mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, + MAKEPOINTS (lParam), GetMessageTime()); + } + else + { + if (msframe->button2_need_lbutton) + { + msframe->button2_need_lbutton = 0; + mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, + MAKEPOINTS (lParam), GetMessageTime()); + } + mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, + MAKEPOINTS (lParam), GetMessageTime()); + } + break; - case WM_NOTIFY: - { - LPNMHDR nmhdr = (LPNMHDR)lParam; + case WM_LBUTTONDOWN: + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - if (nmhdr->code == TTN_NEEDTEXT) + if (msframe->button2_need_lbutton) { -#ifdef HAVE_TOOLBARS - LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; - Lisp_Object btext; - - /* find out which toolbar */ - frame = XFRAME (mswindows_find_frame (hwnd)); - btext = mswindows_get_toolbar_button_text ( frame, - nmhdr->idFrom ); + KillTimer (hwnd, BUTTON_2_TIMER_ID); + msframe->button2_need_lbutton = 0; + msframe->button2_need_rbutton = 0; + if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) + { + mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, + MAKEPOINTS (lParam), GetMessageTime()); + msframe->button2_is_down = 1; + } + else + { + mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, + msframe->last_click_point, msframe->last_click_time); + mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, + MAKEPOINTS (lParam), GetMessageTime()); + } + } + else + { + mswindows_set_chord_timer (hwnd); + msframe->button2_need_rbutton = 1; + msframe->last_click_point = MAKEPOINTS (lParam); + } + msframe->last_click_time = GetMessageTime(); + break; - tttext->lpszText = NULL; - tttext->hinst = NULL; + case WM_RBUTTONDOWN: + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - if (!NILP(btext)) + if (msframe->button2_need_rbutton) + { + KillTimer (hwnd, BUTTON_2_TIMER_ID); + msframe->button2_need_lbutton = 0; + msframe->button2_need_rbutton = 0; + if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) { - /* I think this is safe since the text will only go away - when the toolbar does...*/ - TO_EXTERNAL_FORMAT (LISP_STRING, btext, - C_STRING_ALLOCA, tttext->lpszText, - Qnative); + mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, + MAKEPOINTS (lParam), GetMessageTime()); + msframe->button2_is_down = 1; } -#endif + else + { + mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, + msframe->last_click_point, msframe->last_click_time); + mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, + MAKEPOINTS (lParam), GetMessageTime()); + } } - /* handle tree view callbacks */ - else if (nmhdr->code == TVN_SELCHANGED) + else { - NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam; - frame = XFRAME (mswindows_find_frame (hwnd)); - mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); + mswindows_set_chord_timer (hwnd); + msframe->button2_need_lbutton = 1; + msframe->last_click_point = MAKEPOINTS (lParam); } - /* handle tab control callbacks */ - else if (nmhdr->code == TCN_SELCHANGE) + msframe->last_click_time = GetMessageTime(); + break; + + case WM_TIMER: + if (wParam == BUTTON_2_TIMER_ID) { - TC_ITEM item; - int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); - frame = XFRAME (mswindows_find_frame (hwnd)); + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + KillTimer (hwnd, BUTTON_2_TIMER_ID); + + if (msframe->button2_need_lbutton) + { + msframe->button2_need_lbutton = 0; + mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, + msframe->last_click_point, msframe->last_click_time); + } + else if (msframe->button2_need_rbutton) + { + msframe->button2_need_rbutton = 0; + mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, + msframe->last_click_point, msframe->last_click_time); + } + } + else + assert ("Spurious timer fired" == 0); + break; + + case WM_MOUSEMOVE: + /* Optimization: don't report mouse movement while size is changing */ + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + if (!msframe->sizing) + { + /* When waiting for the second mouse button to finish + button2 emulation, and have moved too far, just pretend + as if timer has expired. This improves drag-select feedback */ + if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) + && !mswindows_button2_near_enough (msframe->last_click_point, + MAKEPOINTS (lParam))) + { + KillTimer (hwnd, BUTTON_2_TIMER_ID); + SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); + } - item.mask = TCIF_PARAM; - SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx, - (LPARAM)&item); + emacs_event = Fmake_event (Qnil, Qnil); + event = XEVENT(emacs_event); - mswindows_handle_gui_wm_command (frame, 0, item.lParam); + event->channel = mswindows_find_frame(hwnd); + event->timestamp = GetMessageTime(); + event->event_type = pointer_motion_event; + event->event.motion.x = MAKEPOINTS(lParam).x; + event->event.motion.y = MAKEPOINTS(lParam).y; + event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); + + mswindows_enqueue_dispatch_event (emacs_event); } - } - break; + break; - case WM_PAINT: - /* hdc will be NULL unless this is a subwindow - in which case we - shouldn't have received a paint message for it here. */ - assert (wParam == 0); + case WM_CANCELMODE: + ReleaseCapture (); + /* Queue a `cancel-mode-internal' misc user event, so mouse + selection would be canceled if any */ + mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), + Qcancel_mode_internal, Qnil); + break; - /* Can't queue a magic event because windows goes modal and sends paint - messages directly to the windows procedure when doing solid drags - and the message queue doesn't get processed. */ - mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); - break; + case WM_NOTIFY: + { + LPNMHDR nmhdr = (LPNMHDR)lParam; - case WM_SIZE: - /* We only care about this message if our size has really changed */ - if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) - { - RECT rect; - int columns, rows; + if (nmhdr->code == TTN_NEEDTEXT) + { +#ifdef HAVE_TOOLBARS + LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; + Lisp_Object btext; - fobj = mswindows_find_frame (hwnd); - frame = XFRAME (fobj); - msframe = FRAME_MSWINDOWS_DATA (frame); + /* find out which toolbar */ + frame = XFRAME (mswindows_find_frame (hwnd)); + btext = mswindows_get_toolbar_button_text ( frame, + nmhdr->idFrom ); - /* We cannot handle frame map and unmap hooks right in - this routine, because these may throw. We queue - magic events to run these hooks instead - kkm */ - - if (wParam==SIZE_MINIMIZED) - { - /* Iconified */ - FRAME_VISIBLE_P (frame) = 0; - mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); - } - else - { - GetClientRect(hwnd, &rect); - FRAME_PIXWIDTH(frame) = rect.right; - FRAME_PIXHEIGHT(frame) = rect.bottom; - - pixel_to_real_char_size (frame, rect.right, rect.bottom, - &FRAME_MSWINDOWS_CHARWIDTH (frame), - &FRAME_MSWINDOWS_CHARHEIGHT (frame)); - - pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); - change_frame_size (frame, rows, columns, 1); - - /* If we are inside frame creation, we have to apply geometric - properties now. */ - if (FRAME_MSWINDOWS_TARGET_RECT (frame)) + tttext->lpszText = NULL; + tttext->hinst = NULL; + + if (!NILP(btext)) + { + /* I think this is safe since the text will only go away + when the toolbar does...*/ + TO_EXTERNAL_FORMAT (LISP_STRING, btext, + C_STRING_ALLOCA, tttext->lpszText, + Qnative); + } +#endif + } + /* handle tree view callbacks */ + else if (nmhdr->code == TVN_SELCHANGED) + { + NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam; + frame = XFRAME (mswindows_find_frame (hwnd)); + mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); + } + /* handle tab control callbacks */ + else if (nmhdr->code == TCN_SELCHANGE) + { + TC_ITEM item; + int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); + frame = XFRAME (mswindows_find_frame (hwnd)); + + item.mask = TCIF_PARAM; + SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx, + (LPARAM)&item); + + mswindows_handle_gui_wm_command (frame, 0, item.lParam); + } + } + break; + + case WM_PAINT: + /* hdc will be NULL unless this is a subwindow - in which case we + shouldn't have received a paint message for it here. */ + assert (wParam == 0); + + /* Can't queue a magic event because windows goes modal and sends paint + messages directly to the windows procedure when doing solid drags + and the message queue doesn't get processed. */ + mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); + break; + + case WM_SIZE: + /* We only care about this message if our size has really changed */ + if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) + { + RECT rect; + int columns, rows; + + fobj = mswindows_find_frame (hwnd); + frame = XFRAME (fobj); + msframe = FRAME_MSWINDOWS_DATA (frame); + + /* We cannot handle frame map and unmap hooks right in + this routine, because these may throw. We queue + magic events to run these hooks instead - kkm */ + + if (wParam==SIZE_MINIMIZED) { - /* Yes, we have to size again */ - mswindows_size_frame_internal ( frame, - FRAME_MSWINDOWS_TARGET_RECT - (frame)); - /* Reset so we do not get here again. The SetWindowPos call in - * mswindows_size_frame_internal can cause recursion here. */ - if (FRAME_MSWINDOWS_TARGET_RECT (frame)) - { - xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); - FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; - } + /* Iconified */ + FRAME_VISIBLE_P (frame) = 0; + mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); } else { - if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) - mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); - FRAME_VISIBLE_P (frame) = 1; + GetClientRect(hwnd, &rect); + FRAME_PIXWIDTH(frame) = rect.right; + FRAME_PIXHEIGHT(frame) = rect.bottom; + + pixel_to_real_char_size (frame, rect.right, rect.bottom, + &FRAME_MSWINDOWS_CHARWIDTH (frame), + &FRAME_MSWINDOWS_CHARHEIGHT (frame)); + + pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); + change_frame_size (frame, rows, columns, 1); + + /* If we are inside frame creation, we have to apply geometric + properties now. */ + if (FRAME_MSWINDOWS_TARGET_RECT (frame)) + { + /* Yes, we have to size again */ + mswindows_size_frame_internal ( frame, + FRAME_MSWINDOWS_TARGET_RECT + (frame)); + /* Reset so we do not get here again. The SetWindowPos call in + * mswindows_size_frame_internal can cause recursion here. */ + if (FRAME_MSWINDOWS_TARGET_RECT (frame)) + { + xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); + FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; + } + } + else + { + if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) + mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); + FRAME_VISIBLE_P (frame) = 1; - if (!msframe->sizing || mswindows_dynamic_frame_resize) - redisplay (); + if (!msframe->sizing || mswindows_dynamic_frame_resize) + redisplay (); + } } } - } - break; + break; - case WM_DISPLAYCHANGE: - { - struct device *d; + case WM_DISPLAYCHANGE: + { + struct device *d; - fobj = mswindows_find_frame (hwnd); - frame = XFRAME (fobj); - d = XDEVICE (FRAME_DEVICE (frame)); + fobj = mswindows_find_frame (hwnd); + frame = XFRAME (fobj); + d = XDEVICE (FRAME_DEVICE (frame)); - DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam); - DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam); - DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam; + DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam); + DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam); + DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam; + break; + } + + /* Misc magic events which only require that the frame be identified */ + case WM_SETFOCUS: + case WM_KILLFOCUS: + mswindows_enqueue_magic_event (hwnd, message); break; - } - /* Misc magic events which only require that the frame be identified */ - case WM_SETFOCUS: - case WM_KILLFOCUS: - mswindows_enqueue_magic_event (hwnd, message); - break; + case WM_WINDOWPOSCHANGING: + { + WINDOWPOS *wp = (LPWINDOWPOS) lParam; + WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; + GetWindowPlacement(hwnd, &wpl); + + /* Only interested if size is changing and we're not being iconified */ + if (wpl.showCmd != SW_SHOWMINIMIZED + && wpl.showCmd != SW_SHOWMAXIMIZED + && !(wp->flags & SWP_NOSIZE)) + { + RECT ncsize = { 0, 0, 0, 0 }; + int pixwidth, pixheight; + AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), + GetMenu(hwnd) != NULL, + GetWindowLong (hwnd, GWL_EXSTYLE)); + + round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), + wp->cx - (ncsize.right - ncsize.left), + wp->cy - (ncsize.bottom - ncsize.top), + &pixwidth, &pixheight); + + /* Convert client sizes to window sizes */ + pixwidth += (ncsize.right - ncsize.left); + pixheight += (ncsize.bottom - ncsize.top); - case WM_WINDOWPOSCHANGING: - { - WINDOWPOS *wp = (LPWINDOWPOS) lParam; - WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; - GetWindowPlacement(hwnd, &wpl); + if (wpl.showCmd != SW_SHOWMAXIMIZED) + { + /* Adjust so that the bottom or right doesn't move if it's + * the top or left that's being changed */ + RECT rect; + GetWindowRect (hwnd, &rect); + + if (rect.left != wp->x) + wp->x += wp->cx - pixwidth; + if (rect.top != wp->y) + wp->y += wp->cy - pixheight; + } - /* Only interested if size is changing and we're not being iconified */ - if (wpl.showCmd != SW_SHOWMINIMIZED - && wpl.showCmd != SW_SHOWMAXIMIZED - && !(wp->flags & SWP_NOSIZE)) - { - RECT ncsize = { 0, 0, 0, 0 }; - int pixwidth, pixheight; - AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), - GetMenu(hwnd) != NULL, - GetWindowLong (hwnd, GWL_EXSTYLE)); - - round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), - wp->cx - (ncsize.right - ncsize.left), - wp->cy - (ncsize.bottom - ncsize.top), - &pixwidth, &pixheight); - - /* Convert client sizes to window sizes */ - pixwidth += (ncsize.right - ncsize.left); - pixheight += (ncsize.bottom - ncsize.top); + wp->cx = pixwidth; + wp->cy = pixheight; + } + /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts + window position if the user tries to track window too small */ + } + goto defproc; + + case WM_ENTERSIZEMOVE: + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + msframe->sizing = 1; + return 0; + + case WM_EXITSIZEMOVE: + msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); + msframe->sizing = 0; + /* Queue noop event */ + mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); + return 0; - if (wpl.showCmd != SW_SHOWMAXIMIZED) +#ifdef HAVE_SCROLLBARS + case WM_VSCROLL: + case WM_HSCROLL: + { + /* Direction of scroll is determined by scrollbar instance. */ + int code = (int) LOWORD(wParam); + int pos = (short int) HIWORD(wParam); + HWND hwndScrollBar = (HWND) lParam; + struct gcpro gcpro1, gcpro2; + + mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); + GCPRO2 (emacs_event, fobj); + if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ { - /* Adjust so that the bottom or right doesn't move if it's - * the top or left that's being changed */ - RECT rect; - GetWindowRect (hwnd, &rect); - - if (rect.left != wp->x) - wp->x += wp->cx - pixwidth; - if (rect.top != wp->y) - wp->y += wp->cy - pixheight; + /* Error during event pumping - cancel scroll */ + SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); } - - wp->cx = pixwidth; - wp->cy = pixheight; + UNGCPRO; + break; } - /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts - window position if the user tries to track window too small */ - } - goto defproc; - - case WM_ENTERSIZEMOVE: - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - msframe->sizing = 1; - return 0; - case WM_EXITSIZEMOVE: - msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); - msframe->sizing = 0; - /* Queue noop event */ - mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); - return 0; + case WM_MOUSEWHEEL: + { + int keys = LOWORD (wParam); /* Modifier key flags */ + int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ + struct gcpro gcpro1, gcpro2; -#ifdef HAVE_SCROLLBARS - case WM_VSCROLL: - case WM_HSCROLL: - { - /* Direction of scroll is determined by scrollbar instance. */ - int code = (int) LOWORD(wParam); - int pos = (short int) HIWORD(wParam); - HWND hwndScrollBar = (HWND) lParam; - struct gcpro gcpro1, gcpro2; + if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) + { + GCPRO2 (emacs_event, fobj); + mswindows_pump_outstanding_events (); /* Can GC */ + UNGCPRO; + } + else + goto defproc; + break; + } +#endif - mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); - GCPRO2 (emacs_event, fobj); - if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ - { - /* Error during event pumping - cancel scroll */ - SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); - } - UNGCPRO; +#ifdef HAVE_MENUBARS + case WM_INITMENU: + if (UNBOUNDP (mswindows_handle_wm_initmenu ( + (HMENU) wParam, + XFRAME (mswindows_find_frame (hwnd))))) + SendMessage (hwnd, WM_CANCELMODE, 0, 0); break; - } - - case WM_MOUSEWHEEL: - { - int keys = LOWORD (wParam); /* Modifier key flags */ - int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ - struct gcpro gcpro1, gcpro2; - if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) + case WM_INITMENUPOPUP: + if (!HIWORD(lParam)) { - GCPRO2 (emacs_event, fobj); - mswindows_pump_outstanding_events (); /* Can GC */ - UNGCPRO; + if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( + (HMENU) wParam, + XFRAME (mswindows_find_frame (hwnd))))) + SendMessage (hwnd, WM_CANCELMODE, 0, 0); } - else - goto defproc; break; - } -#endif - -#ifdef HAVE_MENUBARS - case WM_INITMENU: - if (UNBOUNDP (mswindows_handle_wm_initmenu ( - (HMENU) wParam, - XFRAME (mswindows_find_frame (hwnd))))) - SendMessage (hwnd, WM_CANCELMODE, 0, 0); - break; - case WM_INITMENUPOPUP: - if (!HIWORD(lParam)) - { - if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( - (HMENU) wParam, - XFRAME (mswindows_find_frame (hwnd))))) - SendMessage (hwnd, WM_CANCELMODE, 0, 0); - } - break; - #endif /* HAVE_MENUBARS */ - case WM_COMMAND: - { - WORD id = LOWORD (wParam); - WORD nid = HIWORD (wParam); - HWND cid = (HWND)lParam; - frame = XFRAME (mswindows_find_frame (hwnd)); + case WM_COMMAND: + { + WORD id = LOWORD (wParam); + WORD nid = HIWORD (wParam); + HWND cid = (HWND)lParam; + frame = XFRAME (mswindows_find_frame (hwnd)); #ifdef HAVE_TOOLBARS - if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) - break; + if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) + break; #endif - /* widgets in a buffer only eval a callback for suitable events.*/ - switch (nid) - { - case BN_CLICKED: - case EN_CHANGE: - case CBN_EDITCHANGE: - case CBN_SELCHANGE: - if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) - return 0; - } - /* menubars always must come last since the hashtables do not - always exist*/ + /* widgets in a buffer only eval a callback for suitable events.*/ + switch (nid) + { + case BN_CLICKED: + case EN_CHANGE: + case CBN_EDITCHANGE: + case CBN_SELCHANGE: + if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) + return 0; + } + /* menubars always must come last since the hashtables do not + always exist*/ #ifdef HAVE_MENUBARS - if (!NILP (mswindows_handle_wm_command (frame, id))) - break; + if (!NILP (mswindows_handle_wm_command (frame, id))) + break; #endif - return DefWindowProc (hwnd, message, wParam, lParam); - /* Bite me - a spurious command. This used to not be able to - happen but with the introduction of widgets its now - possible. */ - } - break; - - case WM_CTLCOLORBTN: - case WM_CTLCOLORLISTBOX: - case WM_CTLCOLOREDIT: - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORSCROLLBAR: - { - /* if we get an opportunity to paint a widget then do so if - there is an appropriate face */ - HWND crtlwnd = (HWND)lParam; - LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); - if (ii) - { - Lisp_Object image_instance; - VOID_TO_LISP (image_instance, ii); - if (IMAGE_INSTANCEP (image_instance) - && - IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) - { - /* set colors for the buttons */ - HDC hdc = (HDC)wParam; - if (last_widget_brushed != ii) - { - if (widget_brush) - DeleteObject (widget_brush); - widget_brush = CreateSolidBrush - (COLOR_INSTANCE_MSWINDOWS_COLOR - (XCOLOR_INSTANCE - (FACE_BACKGROUND - (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); - } - last_widget_brushed = ii; - SetTextColor - (hdc, - COLOR_INSTANCE_MSWINDOWS_COLOR - (XCOLOR_INSTANCE - (FACE_FOREGROUND - (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); - SetBkMode (hdc, OPAQUE); - SetBkColor - (hdc, - COLOR_INSTANCE_MSWINDOWS_COLOR - (XCOLOR_INSTANCE - (FACE_BACKGROUND - (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); - return (LRESULT)widget_brush; - } - } - } - goto defproc; + return DefWindowProc (hwnd, message, wParam, lParam); + /* Bite me - a spurious command. This used to not be able to + happen but with the introduction of widgets its now + possible. */ + } + break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORSCROLLBAR: + { + /* if we get an opportunity to paint a widget then do so if + there is an appropriate face */ + HWND crtlwnd = (HWND)lParam; + LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); + if (ii) + { + Lisp_Object image_instance; + VOID_TO_LISP (image_instance, ii); + if (IMAGE_INSTANCEP (image_instance) + && + IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) + { + /* set colors for the buttons */ + HDC hdc = (HDC)wParam; + if (last_widget_brushed != ii) + { + if (widget_brush) + DeleteObject (widget_brush); + widget_brush = CreateSolidBrush + (COLOR_INSTANCE_MSWINDOWS_COLOR + (XCOLOR_INSTANCE + (FACE_BACKGROUND + (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), + XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + } + last_widget_brushed = ii; + SetTextColor + (hdc, + COLOR_INSTANCE_MSWINDOWS_COLOR + (XCOLOR_INSTANCE + (FACE_FOREGROUND + (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), + XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + SetBkMode (hdc, OPAQUE); + SetBkColor + (hdc, + COLOR_INSTANCE_MSWINDOWS_COLOR + (XCOLOR_INSTANCE + (FACE_BACKGROUND + (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), + XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + return (LRESULT)widget_brush; + } + } + } + goto defproc; + #ifdef HAVE_DRAGNDROP - case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ - { - UINT filecount, i, len; - POINT point; - char* filename; - char* fname; - - Lisp_Object l_dndlist = Qnil, l_item = Qnil; - struct gcpro gcpro1, gcpro2, gcpro3; - - emacs_event = Fmake_event (Qnil, Qnil); - event = XEVENT(emacs_event); - - GCPRO3 (emacs_event, l_dndlist, l_item); - - if (!DragQueryPoint ((HDROP) wParam, &point)) - point.x = point.y = -1; /* outside client area */ - - event->event_type = misc_user_event; - event->channel = mswindows_find_frame(hwnd); - event->timestamp = GetMessageTime(); - event->event.misc.button = 1; /* #### Should try harder */ - event->event.misc.modifiers = mswindows_modifier_state (NULL, 0); - event->event.misc.x = point.x; - event->event.misc.y = point.y; - event->event.misc.function = Qdragdrop_drop_dispatch; - - filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); - for (i=0; i/ part and - * because they may contain reserved characters. But that's OK - - * they just need to be good enough to keep dragdrop.el happy. */ - fname = (char *)xmalloc (len+1); - DragQueryFile ((HANDLE) wParam, i, fname, len+1); + case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ + { + UINT filecount, i, len; + POINT point; + char* filename; + char* fname; + + Lisp_Object l_dndlist = Qnil, l_item = Qnil; + struct gcpro gcpro1, gcpro2, gcpro3; + + emacs_event = Fmake_event (Qnil, Qnil); + event = XEVENT(emacs_event); + + GCPRO3 (emacs_event, l_dndlist, l_item); + + if (!DragQueryPoint ((HDROP) wParam, &point)) + point.x = point.y = -1; /* outside client area */ + + event->event_type = misc_user_event; + event->channel = mswindows_find_frame(hwnd); + event->timestamp = GetMessageTime(); + event->event.misc.button = 1; /* #### Should try harder */ + event->event.misc.modifiers = mswindows_modifier_state (NULL, 0); + event->event.misc.x = point.x; + event->event.misc.y = point.y; + event->event.misc.function = Qdragdrop_drop_dispatch; - /* May be a shell link aka "shortcut" - replace fname if so */ -#if !(defined(__CYGWIN32__) || defined(__MINGW32__)) - /* cygwin doesn't define this COM stuff */ - if (!stricmp (fname + strlen (fname) - 4, ".LNK")) - { - IShellLink* psl; + filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); + for (i=0; i/ part and + * because they may contain reserved characters. But that's OK - + * they just need to be good enough to keep dragdrop.el happy. */ + fname = (char *)xmalloc (len+1); + DragQueryFile ((HANDLE) wParam, i, fname, len+1); - if (CoCreateInstance (&CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK) - { - IPersistFile* ppf; + /* May be a shell link aka "shortcut" - replace fname if so */ +#if !(defined(__CYGWIN32__) || defined(__MINGW32__)) + /* cygwin doesn't define this COM stuff */ + if (!stricmp (fname + strlen (fname) - 4, ".LNK")) + { + IShellLink* psl; - if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, - &ppf) == S_OK) - { - WORD wsz[MAX_PATH]; - WIN32_FIND_DATA wfd; - LPSTR resolved = (char *) xmalloc (MAX_PATH+1); - - MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH); - - if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) && - (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH, - &wfd, 0)==S_OK)) - { - xfree (fname); - fname = resolved; - len = strlen (fname); - } + if (CoCreateInstance (&CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK) + { + IPersistFile* ppf; + + if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, + &ppf) == S_OK) + { + WORD wsz[MAX_PATH]; + WIN32_FIND_DATA wfd; + LPSTR resolved = (char *) xmalloc (MAX_PATH+1); + + MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH); + + if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) && + (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH, + &wfd, 0)==S_OK)) + { + xfree (fname); + fname = resolved; + len = strlen (fname); + } - ppf->lpVtbl->Release (ppf); - } + ppf->lpVtbl->Release (ppf); + } - psl->lpVtbl->Release (psl); - } - } + psl->lpVtbl->Release (psl); + } + } #endif #ifdef __CYGWIN32__ - filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); - strcpy (filename, "file:"); - cygwin32_win32_to_posix_path_list (fname, filename+5); + filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); + strcpy (filename, "file:"); + cygwin32_win32_to_posix_path_list (fname, filename+5); #else - filename = (char *)xmalloc (len+6); - strcat (strcpy (filename, "file:"), fname); - dostounix_filename (filename+5); -#endif - xfree (fname); - l_item = make_string (filename, strlen (filename)); - l_dndlist = Fcons (l_item, l_dndlist); - xfree (filename); - } - DragFinish ((HDROP) wParam); + filename = (char *)xmalloc (len+6); + strcat (strcpy (filename, "file:"), fname); + dostounix_filename (filename+5); +#endif + xfree (fname); + l_item = make_string (filename, strlen (filename)); + l_dndlist = Fcons (l_item, l_dndlist); + xfree (filename); + } + DragFinish ((HDROP) wParam); - event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist); - mswindows_enqueue_dispatch_event (emacs_event); - UNGCPRO; - } - break; + event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist); + mswindows_enqueue_dispatch_event (emacs_event); + UNGCPRO; + } + break; #endif - defproc: - default: - return DefWindowProc (hwnd, message, wParam, lParam); - } + defproc: + default: + return DefWindowProc (hwnd, message, wParam, lParam); + } return (0); } @@ -2646,8 +2650,8 @@ case VK_DELETE: return KEYSYM ("kp-delete"); case VK_HELP: return KEYSYM ("help"); #if 0 /* FSF Emacs allows these to return configurable syms/mods */ - case VK_LWIN return KEYSYM (""); - case VK_RWIN return KEYSYM (""); + case VK_LWIN return KEYSYM (""); + case VK_RWIN return KEYSYM (""); #endif case VK_APPS: return KEYSYM ("menu"); case VK_NUMPAD0: return KEYSYM ("kp-0"); @@ -2874,7 +2878,7 @@ ? get_winsock_stream_waitable (XLSTREAM (instr)) : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); #else - return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); + return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); #endif } @@ -3046,7 +3050,7 @@ USID emacs_mswindows_delete_stream_pair (Lisp_Object instream, - Lisp_Object outstream) + Lisp_Object outstream) { /* Oh nothing special here for Win32 at all */ #if defined (HAVE_UNIX_PROCESSES) @@ -3108,6 +3112,7 @@ mswindows_event_stream = xnew (struct event_stream); mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; + mswindows_event_stream->force_event_pending = 0; mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; Index: src/event-stream.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/event-stream.c,v retrieving revision 1.45.2.23 diff -u -r1.45.2.23 event-stream.c --- src/event-stream.c 2000/03/13 07:27:55 1.45.2.23 +++ src/event-stream.c 2000/03/16 10:57:00 @@ -442,6 +442,13 @@ return event_stream && event_stream->event_pending_p (user); } +static void +event_stream_force_event_pending (struct frame* f) +{ + if (event_stream->force_event_pending) + event_stream->force_event_pending (f); +} + static int maybe_read_quit_event (Lisp_Event *event) { @@ -2336,6 +2343,55 @@ return event; } +DEFUN ("dispatch-non-command-events", Fdispatch_non_command_events, 0, 0, 0, /* +Dispatch any pending "magic" events. + +This function is useful for forcing the redisplay of native +widgets. Normally these are redisplayed through a native window-system +event encoded as magic event, rather than by the redisplay code. This +function does not call redisplay or do any of the other things that +`next-event' does. +*/ + ()) +{ + /* This function can GC */ + Lisp_Object event = Qnil; + struct gcpro gcpro1; + GCPRO1 (event); + event = Fmake_event (Qnil, Qnil); + + /* Make sure that there will be something in the native event queue + so that externally managed things (e.g. widgets) get some CPU + time. */ + event_stream_force_event_pending (selected_frame ()); + + while (event_stream_event_pending_p (0)) + { + QUIT; /* next_event_internal() does not QUIT. */ + + /* We're a generator of the command_event_queue, so we can't be a + consumer as well. Also, we have no reason to consult the + command_event_queue; there are only user and eval-events there, + and we'd just have to put them back anyway. + */ + next_event_internal (event, 0); /* blocks */ + /* See the comment in accept-process-output about Vquit_flag */ + if (XEVENT_TYPE (event) == magic_event || + XEVENT_TYPE (event) == timeout_event || + XEVENT_TYPE (event) == process_event || + XEVENT_TYPE (event) == pointer_motion_event) + execute_internal_event (event); + else + { + enqueue_command_event_1 (event); + break; + } + } + + Fdeallocate_event (event); + UNGCPRO; +} + static void reset_current_events (struct command_builder *command_builder) { @@ -4389,6 +4445,7 @@ DEFSUBR (Fadd_async_timeout); DEFSUBR (Fdisable_async_timeout); DEFSUBR (Fdispatch_event); + DEFSUBR (Fdispatch_non_command_events); DEFSUBR (Fread_key_sequence); DEFSUBR (Fthis_command_keys); DEFSUBR (Freset_this_command_lengths); Index: src/event-tty.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/event-tty.c,v retrieving revision 1.4.2.4 diff -u -r1.4.2.4 event-tty.c --- src/event-tty.c 2000/02/07 07:59:59 1.4.2.4 +++ src/event-tty.c 2000/03/16 10:57:11 @@ -249,6 +249,7 @@ tty_event_stream = xnew (struct event_stream); tty_event_stream->event_pending_p = emacs_tty_event_pending_p; + tty_event_stream->force_event_pending = 0; tty_event_stream->next_event_cb = emacs_tty_next_event; tty_event_stream->handle_magic_event_cb = emacs_tty_handle_magic_event; tty_event_stream->add_timeout_cb = emacs_tty_add_timeout; Index: src/events.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/events.h,v retrieving revision 1.20.2.9 diff -u -r1.20.2.9 events.h --- src/events.h 2000/03/13 07:27:56 1.20.2.9 +++ src/events.h 2000/03/16 10:57:28 @@ -329,6 +329,7 @@ void (*select_process_cb) (Lisp_Process *); void (*unselect_process_cb) (Lisp_Process *); void (*quit_p_cb) (void); + void (*force_event_pending) (struct frame* f); USID (*create_stream_pair_cb) (void* /* inhandle*/, void* /*outhandle*/ , Lisp_Object* /* instream */, Lisp_Object* /* outstream */, Index: src/faces.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/faces.h,v retrieving revision 1.6.2.7 diff -u -r1.6.2.7 faces.h --- src/faces.h 2000/02/07 07:59:31 1.6.2.7 +++ src/faces.h 2000/03/16 10:57:34 @@ -125,7 +125,7 @@ corresponding single-face cachels. Formerly we didn't bother to keep track of the faces used for - merging. We do know because we need to do so because there is no + merging. We do now because we need to do so because there is no other way to properly handle multiple charsets for Mule in the presence of display tables short of always computing the values for all charsets, which is very expensive. Instead, we use a Index: src/frame-msw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/frame-msw.c,v retrieving revision 1.29.2.18 diff -u -r1.29.2.18 frame-msw.c --- src/frame-msw.c 2000/03/13 07:27:57 1.29.2.18 +++ src/frame-msw.c 2000/03/16 10:57:52 @@ -613,7 +613,6 @@ int pixel_width, pixel_height; int size_p = (dest->width >=0 || dest->height >=0); int move_p = (dest->top >=0 || dest->left >=0); - struct device* d = XDEVICE (FRAME_DEVICE (f)); char_to_real_pixel_size (f, dest->width, dest->height, &pixel_width, &pixel_height); if (dest->width < 0) Index: src/glyphs-x.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs-x.c,v retrieving revision 1.49.2.59 diff -u -r1.49.2.59 glyphs-x.c --- src/glyphs-x.c 2000/03/11 18:09:22 1.49.2.59 +++ src/glyphs-x.c 2000/03/16 10:58:48 @@ -2695,6 +2695,11 @@ IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii)) { widget_value* wv = lw_get_all_values (IMAGE_INSTANCE_X_WIDGET_LWID (ii)); + + /* #### I don't know why this can occur. */ + if (!wv) + return; + update_tab_widget_face (wv, ii, IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)); Index: src/glyphs.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs.c,v retrieving revision 1.23.2.56 diff -u -r1.23.2.56 glyphs.c --- src/glyphs.c 2000/03/08 22:03:44 1.23.2.56 +++ src/glyphs.c 2000/03/16 11:00:21 @@ -59,6 +59,7 @@ Lisp_Object Qpointer_image_instance_p; Lisp_Object Qsubwindow_image_instance_p; Lisp_Object Qlayout_image_instance_p; +Lisp_Object Qupdate_widget_instances; Lisp_Object Qwidget_image_instance_p; Lisp_Object Qconst_glyph_variable; Lisp_Object Qmono_pixmap, Qcolor_pixmap, Qsubwindow; @@ -932,6 +933,22 @@ } static unsigned long +full_list_hash (Lisp_Object obj, int depth) +{ + unsigned long hash = 0; + Lisp_Object rest; + + if (!CONSP (obj)) + return internal_hash (obj, depth + 1); + + LIST_LOOP (rest, obj) + { + hash = HASH2 (internal_hash (XCAR (rest), depth + 1), hash); + } + return hash; +} + +static unsigned long image_instance_hash (Lisp_Object obj, int depth) { Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj); @@ -962,9 +979,9 @@ case IMAGE_WIDGET: case IMAGE_LAYOUT: hash = HASH4 (hash, - internal_hash (IMAGE_INSTANCE_WIDGET_TYPE (i), depth + 1), - internal_hash (IMAGE_INSTANCE_WIDGET_PROPS (i), depth + 1), - internal_hash (IMAGE_INSTANCE_WIDGET_ITEMS (i), depth + 1)); + LISP_HASH (IMAGE_INSTANCE_WIDGET_TYPE (i)), + full_list_hash (IMAGE_INSTANCE_WIDGET_PROPS (i), depth + 1), + full_list_hash (IMAGE_INSTANCE_WIDGET_ITEMS (i), depth + 1)); case IMAGE_SUBWINDOW: hash = HASH2 (hash, (int) IMAGE_INSTANCE_SUBWINDOW_ID (i)); break; @@ -4279,19 +4296,14 @@ /* Update the displayed characteristics of a subwindow. This function should generally only get called if the subwindow is actually - dirty. The only other time it gets called is if subwindow state - changed, when we can't actually tell whether its going to be dirty - or not. - - #### I suspect what we should really do is re-evaluate all the - gui slots that could affect this and then mark the instance as - dirty. Right now, updating everything is safe but expensive. */ + dirty. */ void update_subwindow (Lisp_Object subwindow) { Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow); int count = specpdl_depth (); - unsigned long display_hash = internal_hash (subwindow, -1); + unsigned long display_hash = internal_hash (subwindow, + IMAGE_INSTANCE_HASH_DEPTH); /* The update method is allowed to call eval. Since it is quite common for this function to get called from somewhere in @@ -4340,28 +4352,36 @@ } /* Update all the subwindows on a frame. */ -void -update_frame_subwindows (struct frame *f) +DEFUN ("update-widget-instances", Fupdate_widget_instances,1, 1, 0, /* +Given a FRAME, re-evaluate the display hash code for all widgets in the frame. +Don't use this. +*/ + (frame)) { int elt; + struct frame* f; + CHECK_FRAME (frame); + f = XFRAME (frame); - /* #### Checking all of these might be overkill now that we update - subwindows in the actual redisplay code. */ - if (f->subwindows_changed || f->subwindows_state_changed || f->faces_changed) - for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++) + /* If we get called we know something has changed. */ + for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++) { struct subwindow_cachel *cachel = Dynarr_atp (f->subwindow_cachels, elt); - if (cachel->being_displayed - && - /* We only want to update if something has really - changed. */ - (f->subwindows_state_changed - || - XIMAGE_INSTANCE_DIRTYP (cachel->subwindow))) + if (cachel->being_displayed && + XIMAGE_INSTANCE_TYPE (cachel->subwindow) + == IMAGE_WIDGET) { - update_subwindow (cachel->subwindow); + /* If a subwindow hash changed mark it so that redisplay + will fix it. */ + if (internal_hash (cachel->subwindow, + IMAGE_INSTANCE_HASH_DEPTH) != + XIMAGE_INSTANCE_DISPLAY_HASH (cachel->subwindow)) + { + set_image_instance_dirty_p (cachel->subwindow, 1); + MARK_FRAME_GLYPHS_CHANGED (f); + } } } } @@ -4724,6 +4744,7 @@ DEFSUBR (Fvalid_image_instantiator_format_p); DEFSUBR (Fset_console_type_image_conversion_list); DEFSUBR (Fconsole_type_image_conversion_list); + DEFSUBR (Fupdate_widget_instances); defkeyword (&Q_file, ":file"); defkeyword (&Q_data, ":data"); @@ -4759,6 +4780,7 @@ defsymbol (&Qwidget_image_instance_p, "widget-image-instance-p"); defsymbol (&Qsubwindow_image_instance_p, "subwindow-image-instance-p"); defsymbol (&Qlayout_image_instance_p, "layout-image-instance-p"); + defsymbol (&Qupdate_widget_instances, "update-widget-instances"); DEFSUBR (Fmake_image_instance); DEFSUBR (Fimage_instance_p); Index: src/glyphs.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs.h,v retrieving revision 1.18.2.40 diff -u -r1.18.2.40 glyphs.h --- src/glyphs.h 2000/03/08 15:06:52 1.18.2.40 +++ src/glyphs.h 2000/03/16 11:00:31 @@ -504,6 +504,7 @@ unsigned int size_changed : 1; unsigned int text_changed : 1; unsigned int layout_changed : 1; + unsigned int optimize_output : 1; /* For outputting layouts. */ union { @@ -564,6 +565,8 @@ #define LAYOUT_JUSTIFY_RIGHT 1 #define LAYOUT_JUSTIFY_CENTER 2 +#define IMAGE_INSTANCE_HASH_DEPTH -1 + /* Accessor macros. */ #define IMAGE_INSTANCE_DEVICE(i) ((i)->device) #define IMAGE_INSTANCE_NAME(i) ((i)->name) @@ -594,8 +597,8 @@ ((i)->u.subwindow.items_changed) #define IMAGE_INSTANCE_WIDGET_PERCENT_CHANGED(i) \ ((i)->u.subwindow.percent_changed) -#define IMAGE_INSTANCE_LAYOUT_CHANGED(i) \ - ((i)->layout_changed) +#define IMAGE_INSTANCE_LAYOUT_CHANGED(i) ((i)->layout_changed) +#define IMAGE_INSTANCE_OPTIMIZE_OUTPUT(i) ((i)->optimize_output) /* Text properties */ #define IMAGE_INSTANCE_TEXT_STRING(i) ((i)->u.text.string) @@ -878,7 +881,7 @@ extern Lisp_Object Q_foreground, Q_background, Q_face, Q_descriptor, Q_group; extern Lisp_Object Q_width, Q_height, Q_pixel_width, Q_pixel_height, Q_text; extern Lisp_Object Q_items, Q_properties, Q_image, Q_percent, Qimage_conversion_error; -extern Lisp_Object Q_orientation; +extern Lisp_Object Q_orientation, Qupdate_widget_instances; extern Lisp_Object Vcontinuation_glyph, Vcontrol_arrow_glyph, Vhscroll_glyph; extern Lisp_Object Vinvisible_text_glyph, Voctal_escape_glyph, Vtruncation_glyph; extern Lisp_Object Vxemacs_logo; @@ -1001,7 +1004,6 @@ void unmap_subwindow (Lisp_Object subwindow); void map_subwindow (Lisp_Object subwindow, int x, int y, struct display_glyph_area *dga); -void update_frame_subwindows (struct frame *f); int find_matching_subwindow (struct frame* f, int x, int y, int width, int height); void update_widget (Lisp_Object widget); void update_subwindow (Lisp_Object subwindow); Index: src/gui-msw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/Attic/gui-msw.c,v retrieving revision 1.1.2.8 diff -u -r1.1.2.8 gui-msw.c --- src/gui-msw.c 2000/03/13 07:27:58 1.1.2.8 +++ src/gui-msw.c 2000/03/16 11:00:32 @@ -50,11 +50,14 @@ if (NILP (data) || UNBOUNDP (data)) return Qnil; - MARK_SUBWINDOWS_STATE_CHANGED; /* Ok, this is our one. Enqueue it. */ get_gui_callback (data, &fn, &arg); XSETFRAME (frame, f); mswindows_enqueue_misc_user_event (frame, fn, arg); + /* The result of this evaluation could cause other instances to change so + enqueue an update callback to check this. */ + mswindows_enqueue_misc_user_event (frame, Qeval, + list2 (Qupdate_widget_instances, frame)); return Qt; } Index: src/gui-x.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/gui-x.c,v retrieving revision 1.14.2.20 diff -u -r1.14.2.20 gui-x.c --- src/gui-x.c 2000/03/13 08:16:19 1.14.2.20 +++ src/gui-x.c 2000/03/16 11:00:35 @@ -213,6 +213,7 @@ Lisp_Object fn, arg; Lisp_Object data; Lisp_Object frame; + int update_subwindows_p = 0; struct device *d = get_device_from_display (XtDisplay (widget)); struct frame *f = x_any_widget_or_parent_to_frame (d, widget); @@ -245,7 +246,7 @@ } else { - MARK_SUBWINDOWS_STATE_CHANGED; + update_subwindows_p = 1; get_gui_callback (data, &fn, &arg); } @@ -258,6 +259,11 @@ DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d); #endif signal_special_Xt_user_event (frame, fn, arg); + /* The result of this evaluation could cause other instances to change so + enqueue an update callback to check this. */ + if (update_subwindows_p) + signal_special_Xt_user_event (frame, Qeval, + list2 (Qupdate_widget_instances, frame)); } #if 1 Index: src/gui.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/gui.c,v retrieving revision 1.10.2.21 diff -u -r1.10.2.21 gui.c --- src/gui.c 2000/03/13 07:27:59 1.10.2.21 +++ src/gui.c 2000/03/16 11:00:42 @@ -497,7 +497,7 @@ } static unsigned long -gui_item_hash (Lisp_Object obj, int depth) +gui_item_hash_internal (Lisp_Object obj, int depth) { Lisp_Gui_Item *p = XGUI_ITEM (obj); @@ -513,10 +513,29 @@ internal_hash (p->keys, depth + 1))); } +static unsigned long +gui_item_hash (Lisp_Object obj, int depth) +{ + Lisp_Gui_Item *p = XGUI_ITEM (obj); + + /* Note that this evaluates the active and selected slots so that + the hash changes when the result of these changes. */ + return HASH2 (HASH5 (internal_hash (p->name, depth + 1), + internal_hash (p->callback, depth + 1), + internal_hash (p->suffix, depth + 1), + gui_item_active_p (obj), + internal_hash (p->included, depth + 1)), + HASH5 (internal_hash (p->config, depth + 1), + internal_hash (p->filter, depth + 1), + internal_hash (p->style, depth + 1), + gui_item_selected_p (obj), + internal_hash (p->keys, depth + 1))); +} + int gui_item_id_hash (Lisp_Object hashtable, Lisp_Object gitem, int slot) { - int hashid = gui_item_hash (gitem, 0); + int hashid = gui_item_hash_internal (gitem, 0); int id = GUI_ITEM_ID_BITS (hashid, slot); while (!NILP (Fgethash (make_int (id), hashtable, Qnil))) Index: src/gutter.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/Attic/gutter.c,v retrieving revision 1.1.2.27 diff -u -r1.1.2.27 gutter.c --- src/gutter.c 2000/03/11 18:09:23 1.1.2.27 +++ src/gutter.c 2000/03/16 11:00:47 @@ -770,25 +770,50 @@ static void gutter_specs_changed (Lisp_Object specifier, struct window *w, - Lisp_Object oldval) + Lisp_Object oldval, enum gutter_pos pos) { - enum gutter_pos pos; - GUTTER_POS_LOOP (pos) + w->real_gutter[pos] = construct_window_gutter_spec (w, pos); + w->real_gutter_size[pos] = w->gutter_size[pos]; + + if (EQ (w->real_gutter_size[pos], Qautodetect) + && !NILP (w->gutter_visible_p[pos])) { - w->real_gutter[pos] = construct_window_gutter_spec (w, pos); - w->real_gutter_size[pos] = w->gutter_size[pos]; - - if (EQ (w->real_gutter_size[pos], Qautodetect) - && !NILP (w->gutter_visible_p[pos])) - { - w->real_gutter_size [pos] = calculate_gutter_size (w, pos); - } + w->real_gutter_size [pos] = calculate_gutter_size (w, pos); } MARK_GUTTER_CHANGED; MARK_MODELINE_CHANGED; MARK_WINDOWS_CHANGED (w); } +/* We define all of these so we can access which actual gutter changed. */ +static void +top_gutter_specs_changed (Lisp_Object specifier, struct window *w, + Lisp_Object oldval) +{ + gutter_specs_changed (specifier, w, oldval, TOP_GUTTER); +} + +static void +bottom_gutter_specs_changed (Lisp_Object specifier, struct window *w, + Lisp_Object oldval) +{ + gutter_specs_changed (specifier, w, oldval, BOTTOM_GUTTER); +} + +static void +left_gutter_specs_changed (Lisp_Object specifier, struct window *w, + Lisp_Object oldval) +{ + gutter_specs_changed (specifier, w, oldval, LEFT_GUTTER); +} + +static void +right_gutter_specs_changed (Lisp_Object specifier, struct window *w, + Lisp_Object oldval) +{ + gutter_specs_changed (specifier, w, oldval, RIGHT_GUTTER); +} + static void default_gutter_specs_changed (Lisp_Object specifier, struct window *w, Lisp_Object oldval) @@ -1119,7 +1144,7 @@ Vgutter[TOP_GUTTER] = Fmake_specifier (Qgutter); set_specifier_caching (Vgutter[TOP_GUTTER], offsetof (struct window, gutter[TOP_GUTTER]), - gutter_specs_changed, + top_gutter_specs_changed, 0, 0); DEFVAR_SPECIFIER ("bottom-gutter", @@ -1136,7 +1161,7 @@ Vgutter[BOTTOM_GUTTER] = Fmake_specifier (Qgutter); set_specifier_caching (Vgutter[BOTTOM_GUTTER], offsetof (struct window, gutter[BOTTOM_GUTTER]), - gutter_specs_changed, + bottom_gutter_specs_changed, 0, 0); DEFVAR_SPECIFIER ("left-gutter", @@ -1153,7 +1178,7 @@ Vgutter[LEFT_GUTTER] = Fmake_specifier (Qgutter); set_specifier_caching (Vgutter[LEFT_GUTTER], offsetof (struct window, gutter[LEFT_GUTTER]), - gutter_specs_changed, + left_gutter_specs_changed, 0, 0); DEFVAR_SPECIFIER ("right-gutter", @@ -1170,7 +1195,7 @@ Vgutter[RIGHT_GUTTER] = Fmake_specifier (Qgutter); set_specifier_caching (Vgutter[RIGHT_GUTTER], offsetof (struct window, gutter[RIGHT_GUTTER]), - gutter_specs_changed, + right_gutter_specs_changed, 0, 0); /* initially, top inherits from default; this can be @@ -1433,7 +1458,7 @@ set_specifier_caching (Vgutter_visible_p[TOP_GUTTER], offsetof (struct window, gutter_visible_p[TOP_GUTTER]), - gutter_specs_changed, 0, 0); + top_gutter_specs_changed, 0, 0); DEFVAR_SPECIFIER ("bottom-gutter-visible-p", &Vgutter_visible_p[BOTTOM_GUTTER] /* @@ -1446,7 +1471,7 @@ set_specifier_caching (Vgutter_visible_p[BOTTOM_GUTTER], offsetof (struct window, gutter_visible_p[BOTTOM_GUTTER]), - gutter_specs_changed, 0, 0); + bottom_gutter_specs_changed, 0, 0); DEFVAR_SPECIFIER ("left-gutter-visible-p", &Vgutter_visible_p[LEFT_GUTTER] /* @@ -1459,7 +1484,7 @@ set_specifier_caching (Vgutter_visible_p[LEFT_GUTTER], offsetof (struct window, gutter_visible_p[LEFT_GUTTER]), - gutter_specs_changed, 0, 0); + left_gutter_specs_changed, 0, 0); DEFVAR_SPECIFIER ("right-gutter-visible-p", &Vgutter_visible_p[RIGHT_GUTTER] /* @@ -1472,7 +1497,7 @@ set_specifier_caching (Vgutter_visible_p[RIGHT_GUTTER], offsetof (struct window, gutter_visible_p[RIGHT_GUTTER]), - gutter_specs_changed, 0, 0); + right_gutter_specs_changed, 0, 0); /* initially, top inherits from default; this can be changed with `set-default-gutter-position'. */ Index: src/redisplay-msw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay-msw.c,v retrieving revision 1.28.2.21 diff -u -r1.28.2.21 redisplay-msw.c --- src/redisplay-msw.c 2000/03/01 17:47:09 1.28.2.21 +++ src/redisplay-msw.c 2000/03/16 11:00:54 @@ -1123,6 +1123,7 @@ Lisp_Object instance; struct display_box dbox; struct display_glyph_area dga; + redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset, start_pixpos, rb->width, &dbox, &dga); @@ -1133,69 +1134,72 @@ findex = rb->findex; if (IMAGE_INSTANCEP (instance)) - switch (XIMAGE_INSTANCE_TYPE (instance)) - { - case IMAGE_TEXT: + { + switch (XIMAGE_INSTANCE_TYPE (instance)) { - /* #### This is way losing. See the comment in - add_glyph_rune(). */ - Lisp_Object string = - XIMAGE_INSTANCE_TEXT_STRING (instance); - convert_bufbyte_string_into_emchar_dynarr - (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); - + case IMAGE_TEXT: + { + /* #### This is way losing. See the comment in + add_glyph_rune(). */ + Lisp_Object string = + XIMAGE_INSTANCE_TEXT_STRING (instance); + convert_bufbyte_string_into_emchar_dynarr + (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); + + if (rb->cursor_type == CURSOR_ON) + mswindows_output_cursor (w, dl, xpos, cursor_width, + findex, Dynarr_at (buf, 0), 0); + else /* #### redisplay-x passes -1 as the width: why ? */ + mswindows_output_string (w, dl, buf, xpos, + rb->object.dglyph.xoffset, + start_pixpos, rb->width, findex, + 0, 0, 0, 0); + Dynarr_reset (buf); + } + break; + + case IMAGE_MONO_PIXMAP: + case IMAGE_COLOR_PIXMAP: + redisplay_output_pixmap (w, instance, &dbox, &dga, findex, + cursor_start, cursor_width, + cursor_height, 0); + if (rb->cursor_type == CURSOR_ON) + mswindows_output_cursor (w, dl, xpos, cursor_width, + findex, 0, 1); + break; + + case IMAGE_POINTER: + abort (); + + case IMAGE_SUBWINDOW: + case IMAGE_WIDGET: + redisplay_output_subwindow (w, instance, &dbox, &dga, findex, + cursor_start, cursor_width, + cursor_height); if (rb->cursor_type == CURSOR_ON) mswindows_output_cursor (w, dl, xpos, cursor_width, - findex, Dynarr_at (buf, 0), 0); - else /* #### redisplay-x passes -1 as the width: why ? */ - mswindows_output_string (w, dl, buf, xpos, - rb->object.dglyph.xoffset, - start_pixpos, rb->width, findex, - 0, 0, 0, 0); - Dynarr_reset (buf); + findex, 0, 1); + break; + + case IMAGE_LAYOUT: + redisplay_output_layout (w, instance, &dbox, &dga, findex, + cursor_start, cursor_width, + cursor_height); + if (rb->cursor_type == CURSOR_ON) + mswindows_output_cursor (w, dl, xpos, cursor_width, + findex, 0, 1); + break; + + case IMAGE_NOTHING: + /* nothing is as nothing does */ + break; + + default: + abort (); } - break; - - case IMAGE_MONO_PIXMAP: - case IMAGE_COLOR_PIXMAP: - redisplay_output_pixmap (w, instance, &dbox, &dga, findex, - cursor_start, cursor_width, - cursor_height, 0); - if (rb->cursor_type == CURSOR_ON) - mswindows_output_cursor (w, dl, xpos, cursor_width, - findex, 0, 1); - break; - - case IMAGE_POINTER: - abort (); - - case IMAGE_SUBWINDOW: - case IMAGE_WIDGET: - redisplay_output_subwindow (w, instance, &dbox, &dga, findex, - cursor_start, cursor_width, - cursor_height); - if (rb->cursor_type == CURSOR_ON) - mswindows_output_cursor (w, dl, xpos, cursor_width, - findex, 0, 1); - break; - - case IMAGE_LAYOUT: - redisplay_output_layout (w, instance, &dbox, &dga, findex, - cursor_start, cursor_width, - cursor_height); - if (rb->cursor_type == CURSOR_ON) - mswindows_output_cursor (w, dl, xpos, cursor_width, - findex, 0, 1); - break; - - case IMAGE_NOTHING: - /* nothing is as nothing does */ - break; - - default: - abort (); - } - + IMAGE_INSTANCE_OPTIMIZE_OUTPUT + (XIMAGE_INSTANCE (instance)) = 0; + } xpos += rb->width; elt++; } Index: src/redisplay-output.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay-output.c,v retrieving revision 1.11.2.32 diff -u -r1.11.2.32 redisplay-output.c --- src/redisplay-output.c 2000/03/10 08:24:38 1.11.2.32 +++ src/redisplay-output.c 2000/03/16 11:01:03 @@ -211,11 +211,8 @@ #### It would really be worth it to arrange for this function to be (almost) a single call to memcmp. */ - if ((crb->findex != drb->findex) || - (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))) + if (crb->xpos != drb->xpos) return 0; - else if (crb->xpos != drb->xpos) - return 0; else if (crb->width != drb->width) return 0; else if (crb->cursor_type != drb->cursor_type) @@ -236,25 +233,67 @@ return 0; /* Only check dirtiness if we know something has changed. */ else if (crb->type == RUNE_DGLYPH && - XFRAME (w->frame)->glyphs_changed && - XGLYPH_DIRTYP (crb->object.dglyph.glyph)) - { + ((XFRAME (w->frame)->glyphs_changed && + XGLYPH_DIRTYP (crb->object.dglyph.glyph)) || + crb->findex != drb->findex)) + { + /* We need some way of telling redisplay_output_layout () that the + only reason we are outputting it is because something has + changed internally. That way we can optimize whether we need + to clear the layout first and also only output the components + that have changed. The image_instance dirty flag and + display_hash are no good to us because these will invariably + have been set anyway if the layout has changed. So it looks + like we need yet another change flag that we can set here and + then clear in redisplay_output_layout (). */ Lisp_Object window, image; + Lisp_Image_Instance* ii; XSETWINDOW (window, w); image = glyph_image_instance (crb->object.dglyph.glyph, window, ERROR_ME_NOT, 1); + ii = XIMAGE_INSTANCE (image); + + if (TEXT_IMAGE_INSTANCEP (image) && + (crb->findex != drb->findex || + WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))) + return 0; + /* It is quite common of the two glyphs to be EQ since in many cases they will actually be the same object. This does not mean, however, that nothing has changed. We therefore need to check the current hash of the glyph against the last recorded display hash. See update_subwindow (). */ - if (XIMAGE_INSTANCE_DISPLAY_HASH (image) == 0 - || - XIMAGE_INSTANCE_DISPLAY_HASH (image) != internal_hash (image, -1)) - return 0; + if (IMAGE_INSTANCE_DISPLAY_HASH (ii) == 0 || + IMAGE_INSTANCE_DISPLAY_HASH (ii) != + internal_hash (image, IMAGE_INSTANCE_HASH_DEPTH) || + crb->findex != drb->findex || + WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)) + { + /* We now now we are going to re-output the glyph, but since + this is for some internal reason not related to geometry + changes, send a hint to the output routines that they can + take some short cuts. This is most useful for + layouts. This flag should get reset by the output + routines. + + #### It is possible for us to get here when the + face_cachel is dirty. I do not know what the implications + of this are.*/ + IMAGE_INSTANCE_OPTIMIZE_OUTPUT (ii) = 1; + return 0; + } else return 1; } + /* We now do this last so that glyph checks can do their own thing + for face changes. Face changes quite often happen when we are + trying to output something in the gutter, this would normally + lead to a lot of flashing. The indices can quite often be + different and yet the faces are the same, we do not want to + re-output in this instance. */ + else if (crb->findex != drb->findex || + WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)) + return 0; else return 1; } @@ -1254,17 +1293,6 @@ struct frame *f = XFRAME (w->frame); struct device *d = XDEVICE (f->device); int layout_height, layout_width; - /* We bogusly don't take f->extents_changed and f->glyphs_changed - into account. This is because if we do we always redisplay the - entire layout. So far I have seen no ill effects so we'll see. */ - int frame_really_changed = (f->buffers_changed || - f->clip_changed || - f->faces_changed || - f->frame_changed || - f->modeline_changed || - f->subwindows_changed || - f->windows_changed || - f->windows_structure_changed); XSETWINDOW (window, w); @@ -1280,7 +1308,7 @@ /* Highly dodgy optimization. We want to only output the whole layout if we really have to. */ - if (frame_really_changed + if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p) || IMAGE_INSTANCE_LAYOUT_CHANGED (p) || IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p) || IMAGE_INSTANCE_SIZE_CHANGED (p) @@ -1353,6 +1381,7 @@ if (IMAGE_INSTANCEP (child)) { Lisp_Image_Instance* childii = XIMAGE_INSTANCE (child); + /* The enclosing layout offsets are +ve at this point */ struct display_glyph_area cdga; cdga.xoffset = IMAGE_INSTANCE_XOFFSET (childii) - dga->xoffset; @@ -1360,6 +1389,9 @@ cdga.width = glyph_width (child, window); cdga.height = glyph_height (child, window); + IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = + IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p); + /* Although normalization is done by the output routines we have to do it here so that they don't try and clear all of db. This is true below also. */ @@ -1386,7 +1418,8 @@ generalisation.*/ if (redisplay_normalize_glyph_area (&cdb, &cdga) && - (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii))) + (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) || + IMAGE_INSTANCE_DIRTYP (childii))) { struct display_line dl; /* this is fake */ Lisp_Object string = @@ -1420,14 +1453,16 @@ case IMAGE_MONO_PIXMAP: case IMAGE_COLOR_PIXMAP: - if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii)) + if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) + || IMAGE_INSTANCE_DIRTYP (childii)) redisplay_output_pixmap (w, child, &cdb, &cdga, findex, 0, 0, 0, 0); break; case IMAGE_WIDGET: case IMAGE_SUBWINDOW: - if (frame_really_changed || IMAGE_INSTANCE_DIRTYP (childii)) + if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) || + IMAGE_INSTANCE_DIRTYP (childii)) redisplay_output_subwindow (w, child, &cdb, &cdga, findex, 0, 0, 0); break; @@ -1446,6 +1481,7 @@ abort (); } } + IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 0; } } Index: src/redisplay-tty.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay-tty.c,v retrieving revision 1.15.2.8 diff -u -r1.15.2.8 redisplay-tty.c --- src/redisplay-tty.c 2000/03/13 07:28:03 1.15.2.8 +++ src/redisplay-tty.c 2000/03/16 11:01:08 @@ -333,79 +333,83 @@ window, ERROR_ME_NOT, 1); if (IMAGE_INSTANCEP (instance)) - switch (XIMAGE_INSTANCE_TYPE (instance)) - { - case IMAGE_TEXT: + { + switch (XIMAGE_INSTANCE_TYPE (instance)) { - Bufbyte *temptemp; - Lisp_Object string = - XIMAGE_INSTANCE_TEXT_STRING (instance); - Bytecount len = XSTRING_LENGTH (string); - - /* In the unlikely instance that a garbage-collect - occurs during encoding, we at least need to - copy the string. - */ - temptemp = (Bufbyte *) alloca (len); - memcpy (temptemp, XSTRING_DATA (string), len); + case IMAGE_TEXT: { - int i; - - /* Now truncate the first rb->object.dglyph.xoffset - columns. */ - for (i = 0; i < rb->object.dglyph.xoffset;) - { + Bufbyte *temptemp; + Lisp_Object string = + XIMAGE_INSTANCE_TEXT_STRING (instance); + Bytecount len = XSTRING_LENGTH (string); + + /* In the unlikely instance that a garbage-collect + occurs during encoding, we at least need to + copy the string. + */ + temptemp = (Bufbyte *) alloca (len); + memcpy (temptemp, XSTRING_DATA (string), len); + { + int i; + + /* Now truncate the first rb->object.dglyph.xoffset + columns. */ + for (i = 0; i < rb->object.dglyph.xoffset;) + { #ifdef MULE - Emchar ch = charptr_emchar (temptemp); - i += XCHARSET_COLUMNS (CHAR_CHARSET (ch)); + Emchar ch = charptr_emchar (temptemp); + i += XCHARSET_COLUMNS (CHAR_CHARSET (ch)); #else - i++; /* telescope this */ + i++; /* telescope this */ #endif - INC_CHARPTR (temptemp); - } - - /* If we truncated one column too many, then - add a space at the beginning. */ - if (i > rb->object.dglyph.xoffset) + INC_CHARPTR (temptemp); + } + + /* If we truncated one column too many, then + add a space at the beginning. */ + if (i > rb->object.dglyph.xoffset) + { + assert (i > 0); + *--temptemp = ' '; + i--; + } + len -= i; + } + + tty_output_bufbyte_string (w, dl, temptemp, len, + xpos, findex, 0); + + if (xpos >= cursor_start + && (cursor_start < + xpos + (bufbyte_string_displayed_columns + (temptemp, len)))) { - assert (i > 0); - *--temptemp = ' '; - i--; + cmgoto (f, dl->ypos - 1, cursor_start); } - len -= i; } - - tty_output_bufbyte_string (w, dl, temptemp, len, - xpos, findex, 0); - - if (xpos >= cursor_start - && (cursor_start < - xpos + (bufbyte_string_displayed_columns - (temptemp, len)))) - { - cmgoto (f, dl->ypos - 1, cursor_start); - } + break; + + case IMAGE_MONO_PIXMAP: + case IMAGE_COLOR_PIXMAP: + case IMAGE_SUBWINDOW: + case IMAGE_WIDGET: + case IMAGE_LAYOUT: + /* just do nothing here */ + break; + + case IMAGE_POINTER: + abort (); + + case IMAGE_NOTHING: + /* nothing is as nothing does */ + break; + + default: + abort (); } - break; - - case IMAGE_MONO_PIXMAP: - case IMAGE_COLOR_PIXMAP: - case IMAGE_SUBWINDOW: - case IMAGE_WIDGET: - case IMAGE_LAYOUT: - /* just do nothing here */ - break; - - case IMAGE_POINTER: - abort (); - - case IMAGE_NOTHING: - /* nothing is as nothing does */ - break; - - default: - abort (); - } + IMAGE_INSTANCE_OPTIMIZE_OUTPUT + (XIMAGE_INSTANCE (instance)) = 0; + } xpos += rb->width; elt++; Index: src/redisplay-x.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay-x.c,v retrieving revision 1.23.2.22 diff -u -r1.23.2.22 redisplay-x.c --- src/redisplay-x.c 2000/03/13 07:28:03 1.23.2.22 +++ src/redisplay-x.c 2000/03/16 11:01:16 @@ -449,55 +449,59 @@ findex = rb->findex; if (IMAGE_INSTANCEP (instance)) - switch (XIMAGE_INSTANCE_TYPE (instance)) - { - case IMAGE_TEXT: + { + switch (XIMAGE_INSTANCE_TYPE (instance)) { - /* #### This is way losing. See the comment in - add_glyph_rune(). */ - Lisp_Object string = - XIMAGE_INSTANCE_TEXT_STRING (instance); - convert_bufbyte_string_into_emchar_dynarr - (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); - - x_output_string (w, dl, buf, xpos, - rb->object.dglyph.xoffset, - start_pixpos, -1, findex, - (rb->cursor_type == CURSOR_ON), - cursor_start, cursor_width, - cursor_height); - Dynarr_reset (buf); + case IMAGE_TEXT: + { + /* #### This is way losing. See the comment in + add_glyph_rune(). */ + Lisp_Object string = + XIMAGE_INSTANCE_TEXT_STRING (instance); + convert_bufbyte_string_into_emchar_dynarr + (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); + + x_output_string (w, dl, buf, xpos, + rb->object.dglyph.xoffset, + start_pixpos, -1, findex, + (rb->cursor_type == CURSOR_ON), + cursor_start, cursor_width, + cursor_height); + Dynarr_reset (buf); + } + break; + + case IMAGE_MONO_PIXMAP: + case IMAGE_COLOR_PIXMAP: + redisplay_output_pixmap (w, instance, &dbox, &dga, findex, + cursor_start, cursor_width, + cursor_height, 0); + break; + + case IMAGE_WIDGET: + case IMAGE_SUBWINDOW: + redisplay_output_subwindow (w, instance, &dbox, &dga, findex, + cursor_start, cursor_width, + cursor_height); + break; + + case IMAGE_LAYOUT: + redisplay_output_layout (w, instance, &dbox, &dga, findex, + cursor_start, cursor_width, + cursor_height); + break; + + case IMAGE_NOTHING: + /* nothing is as nothing does */ + break; + + case IMAGE_POINTER: + default: + abort (); } - break; - - case IMAGE_MONO_PIXMAP: - case IMAGE_COLOR_PIXMAP: - redisplay_output_pixmap (w, instance, &dbox, &dga, findex, - cursor_start, cursor_width, - cursor_height, 0); - break; - - case IMAGE_WIDGET: - case IMAGE_SUBWINDOW: - redisplay_output_subwindow (w, instance, &dbox, &dga, findex, - cursor_start, cursor_width, - cursor_height); - break; - - case IMAGE_LAYOUT: - redisplay_output_layout (w, instance, &dbox, &dga, findex, - cursor_start, cursor_width, - cursor_height); - break; - - case IMAGE_NOTHING: - /* nothing is as nothing does */ - break; - - case IMAGE_POINTER: - default: - abort (); - } + IMAGE_INSTANCE_OPTIMIZE_OUTPUT + (XIMAGE_INSTANCE (instance)) = 0; + } xpos += rb->width; elt++; Index: src/redisplay.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay.c,v retrieving revision 1.55.2.48 diff -u -r1.55.2.48 redisplay.c --- src/redisplay.c 2000/03/11 18:09:24 1.55.2.48 +++ src/redisplay.c 2000/03/16 11:01:53 @@ -364,8 +364,7 @@ int glyphs_changed; int glyphs_changed_set; -/* non-zero if any displayed subwindow is in need of updating - somewhere. */ +/* non-zero if any subwindow has been deleted. */ int subwindows_changed; int subwindows_changed_set; @@ -6336,11 +6335,6 @@ being handled. */ update_frame_menubars (f); #endif /* HAVE_MENUBARS */ - /* widgets are similar to menus in that they can call lisp to - determine activation etc. Therefore update them before we get - into redisplay. This is primarily for connected widgets such as - radio buttons. */ - update_frame_subwindows (f); #ifdef HAVE_TOOLBARS /* Update the toolbars. */ update_frame_toolbars (f); @@ -6360,7 +6354,7 @@ like the clicked state of button. We have to do this before redisplaying the gutters as subwindows get unmapped in the process.*/ - if (f->frame_changed) + if (f->frame_changed || f->subwindows_changed) { reset_subwindow_cachels (f); /* we have to do this so the gutter gets regenerated. */ Index: src/specifier.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/specifier.c,v retrieving revision 1.15.2.16 diff -u -r1.15.2.16 specifier.c --- src/specifier.c 2000/02/26 21:26:12 1.15.2.16 +++ src/specifier.c 2000/03/16 11:02:25 @@ -2818,6 +2818,13 @@ method. */ location = (Lisp_Object *) ((char *) w + XSPECIFIER (specifier)->caching->offset_into_struct_window); + /* #### What's the point of this check, other than to optimize image + instance instantiation? Unless you specify a caching instantiate + method the instantiation that specifier_instance will do will + always create a new copy. Thus EQ will always fail. Unfortunately + calling equal is no good either as this doesn't take into account + things attached to the specifier - for instance strings on + extents. --andyp */ if (!EQ (newval, *location)) { Lisp_Object oldval = *location;