Using saved parent location: http://bzr.savannah.gnu.org/r/emacs/trunk/ Now on revision 102734. ------------------------------------------------------------ revno: 102734 committer: Chong Yidong branch nick: trunk timestamp: Sat 2011-01-01 01:02:36 -0500 message: Reduce GTK tool-bar switching delay by avoiding selective show/hide of widgets. * src/gtkutil.c (xg_get_tool_bar_widgets): Use NULL for a missing image or label in the container. (xg_make_tool_item): Replace VERT_ONLY arg with HORIZ, TEXT_IMAGE. (xg_show_toolbar_item): Function deleted. (xg_tool_item_stale_p): New function. (update_frame_tool_bar): Calculate tool-bar style once per call. Instead of hiding text labels, omit them. Don't use xg_show_toolbar_item; create new GtkToolItems from scratch if necessary, instead of trying to re-use them. This avoids an annoying animation when changing tool-bars. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2010-12-31 13:16:16 +0000 +++ src/ChangeLog 2011-01-01 06:02:36 +0000 @@ -1,3 +1,16 @@ +2011-01-01 Chong Yidong + + * gtkutil.c (xg_get_tool_bar_widgets): Use NULL for a missing + image or label in the container. + (xg_make_tool_item): Replace VERT_ONLY arg with HORIZ, TEXT_IMAGE. + (xg_show_toolbar_item): Function deleted. + (xg_tool_item_stale_p): New function. + (update_frame_tool_bar): Calculate tool-bar style once per call. + Instead of hiding text labels, omit them. Don't use + xg_show_toolbar_item; create new GtkToolItems from scratch if + necessary, instead of trying to re-use them. This avoids an + annoying animation when changing tool-bars. + 2010-12-31 Jan Djärv * nsfns.m (ns_set_name_as_filename): Always use buffer name for === modified file 'src/gtkutil.c' --- src/gtkutil.c 2010-12-17 04:04:06 +0000 +++ src/gtkutil.c 2011-01-01 06:02:36 +0000 @@ -3664,7 +3664,8 @@ { GList *clist = gtk_container_get_children (GTK_CONTAINER (vb)); GtkWidget *c1 = (GtkWidget *) clist->data; - GtkWidget *c2 = (GtkWidget *) clist->next->data; + GtkWidget *c2 = clist->next ? (GtkWidget *) clist->next->data : NULL; + *wimage = GTK_IS_IMAGE (c1) ? c1 : c2; g_list_free (clist); return GTK_IS_LABEL (c1) ? c1 : c2; @@ -4039,28 +4040,17 @@ GtkWidget *wimage, GtkWidget **wbutton, const char *label, - int i, - int vert_only) + int i, int horiz, int text_image) { GtkToolItem *ti = gtk_tool_item_new (); - Lisp_Object style = Ftool_bar_get_system_style (); - int both_horiz = EQ (style, Qboth_horiz); - int text_image = EQ (style, Qtext_image_horiz); - - GtkWidget *vb = both_horiz || text_image - ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0); + GtkWidget *vb = horiz ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0); GtkWidget *wb = gtk_button_new (); GtkWidget *weventbox = gtk_event_box_new (); - /* We are not letting Gtk+ alter display on this, we only keep it here - so we can get it later in xg_show_toolbar_item. */ - gtk_tool_item_set_is_important (ti, !vert_only); - - if (wimage && ! text_image) + if (wimage && !text_image) gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX (vb), gtk_label_new (label), TRUE, TRUE, 0); - + if (label) + gtk_box_pack_start (GTK_BOX (vb), gtk_label_new (label), TRUE, TRUE, 0); if (wimage && text_image) gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0); @@ -4121,58 +4111,49 @@ return ti; } -static void -xg_show_toolbar_item (GtkToolItem *ti) +static int +xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name, + const char *icon_name, const struct image *img, + const char *label, int horiz) { - Lisp_Object style = Ftool_bar_get_system_style (); - int both_horiz = EQ (style, Qboth_horiz); - int text_image = EQ (style, Qtext_image_horiz); - - int horiz = both_horiz || text_image; - int vert_only = ! gtk_tool_item_get_is_important (ti); - int show_label = ! EQ (style, Qimage) && ! (vert_only && horiz); - int show_image = ! EQ (style, Qtext); - - GtkWidget *weventbox = XG_BIN_CHILD (ti); - GtkWidget *wbutton = XG_BIN_CHILD (weventbox); - GtkWidget *vb = XG_BIN_CHILD (wbutton); + gpointer old; GtkWidget *wimage; + GtkWidget *vb = XG_BIN_CHILD (wbutton); GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage); - GtkWidget *new_box = NULL; - - if (GTK_IS_VBOX (vb) && horiz) - new_box = gtk_hbox_new (FALSE, 0); - else if (GTK_IS_HBOX (vb) && !horiz && show_label && show_image) - new_box = gtk_vbox_new (FALSE, 0); - - if (!new_box && horiz) - gtk_box_reorder_child (GTK_BOX (vb), wlbl, text_image ? 0 : 1); - else if (new_box) - { - g_object_ref (G_OBJECT (wimage)); - g_object_ref (G_OBJECT (wlbl)); - gtk_container_remove (GTK_CONTAINER (vb), wimage); - gtk_container_remove (GTK_CONTAINER (vb), wlbl); - gtk_widget_destroy (GTK_WIDGET (vb)); - if (! text_image) - gtk_box_pack_start (GTK_BOX (new_box), wimage, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (new_box), wlbl, TRUE, TRUE, 0); - if (text_image) - gtk_box_pack_start (GTK_BOX (new_box), wimage, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (wbutton), new_box); - g_object_unref (G_OBJECT (wimage)); - g_object_unref (G_OBJECT (wlbl)); - vb = new_box; - } - - if (show_label) gtk_widget_show (wlbl); - else gtk_widget_hide (wlbl); - if (show_image) gtk_widget_show (wimage); - else gtk_widget_hide (wimage); - gtk_widget_show (GTK_WIDGET (weventbox)); - gtk_widget_show (GTK_WIDGET (vb)); - gtk_widget_show (GTK_WIDGET (wbutton)); - gtk_widget_show (GTK_WIDGET (ti)); + + /* Check if the tool icon matches. */ + if (stock_name) + { + old = g_object_get_data (G_OBJECT (wimage), + XG_TOOL_BAR_STOCK_NAME); + if (!old || strcmp (old, stock_name)) + return 1; + } + else if (icon_name) + { + old = g_object_get_data (G_OBJECT (wimage), + XG_TOOL_BAR_ICON_NAME); + if (!old || strcmp (old, icon_name)) + return 1; + } + else + { + Pixmap old_img + = (Pixmap) g_object_get_data (G_OBJECT (wimage), + XG_TOOL_BAR_IMAGE_DATA); + if (old_img != img->pixmap) + return 1; + } + + /* Check button configuration and label. */ + if ((horiz ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb)) + || (label ? (wlbl == NULL) : (wlbl != NULL))) + return 1; + + /* Ensure label is correct. */ + if (label) + gtk_label_set_text (GTK_LABEL (wlbl), label); + return 0; } static int @@ -4225,7 +4206,7 @@ void update_frame_tool_bar (FRAME_PTR f) { - int i; + int i, j; struct x_output *x = f->output_data.x; int hmargin = 0, vmargin = 0; GtkToolbar *wtoolbar; @@ -4233,6 +4214,9 @@ GtkTextDirection dir; int pack_tool_bar = x->handlebox_widget == NULL; + Lisp_Object style; + int text_image, horiz; + if (! FRAME_GTK_WIDGET (f)) return; @@ -4268,7 +4252,11 @@ wtoolbar = GTK_TOOLBAR (x->toolbar_widget); dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar)); - for (i = 0; i < f->n_tool_bar_items; ++i) + style = Ftool_bar_get_system_style (); + text_image = EQ (style, Qtext_image_horiz); + horiz = EQ (style, Qboth_horiz) || text_image; + + for (i = j = 0; i < f->n_tool_bar_items; ++i) { int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); @@ -4284,11 +4272,14 @@ Lisp_Object rtl; GtkWidget *wbutton = NULL; Lisp_Object specified_file; - const char *label = (STRINGP (PROP (TOOL_BAR_ITEM_LABEL)) - ? SSDATA (PROP (TOOL_BAR_ITEM_LABEL)) : ""); int vert_only = ! NILP (PROP (TOOL_BAR_ITEM_VERT_ONLY)); + const char *label + = (EQ (style, Qimage) || (vert_only && horiz)) ? NULL + : STRINGP (PROP (TOOL_BAR_ITEM_LABEL)) + ? SSDATA (PROP (TOOL_BAR_ITEM_LABEL)) + : ""; - ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), i); + ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j); /* If this is a separator, use a gtk separator item. */ if (EQ (PROP (TOOL_BAR_ITEM_TYPE), Qt)) @@ -4299,9 +4290,9 @@ gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti)); ti = gtk_separator_tool_item_new (); - gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, i); + gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j); } - gtk_widget_show (GTK_WIDGET (ti)); + j++; continue; } @@ -4313,14 +4304,15 @@ ti = NULL; } - if (ti) - wbutton = XG_BIN_CHILD (XG_BIN_CHILD (ti)); + if (ti) wbutton = XG_BIN_CHILD (XG_BIN_CHILD (ti)); /* Ignore invalid image specifications. */ image = PROP (TOOL_BAR_ITEM_IMAGES); if (!valid_image_p (image)) { - if (wbutton) gtk_widget_hide (wbutton); + if (ti) + gtk_container_remove (GTK_CONTAINER (wtoolbar), + GTK_WIDGET (ti)); continue; } @@ -4356,16 +4348,13 @@ if (stock_name == NULL && icon_name == NULL) { - /* No stock image, or stock item not known. Try regular image. */ - - /* If image is a vector, choose the image according to the + /* No stock image, or stock item not known. Try regular + image. If image is a vector, choose it according to the button state. */ if (dir == GTK_TEXT_DIR_RTL && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE)) && STRINGP (rtl)) - { - image = find_rtl_image (f, image, rtl); - } + image = find_rtl_image (f, image, rtl); if (VECTORP (image)) { @@ -4391,21 +4380,31 @@ if (img->load_failed_p || img->pixmap == None) { if (ti) - gtk_widget_hide_all (GTK_WIDGET (ti)); - else - { - /* Insert an empty (non-image) button */ - ti = xg_make_tool_item (f, NULL, NULL, "", i, 0); - gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, i); - } + gtk_container_remove (GTK_CONTAINER (wtoolbar), + GTK_WIDGET (ti)); continue; } } + /* If there is an existing widget, check if it's stale; if so, + remove it and make a new tool item from scratch. */ + if (ti && xg_tool_item_stale_p (wbutton, stock_name, icon_name, + img, label, horiz)) + { + gtk_container_remove (GTK_CONTAINER (wtoolbar), + GTK_WIDGET (ti)); + ti = NULL; + } + if (ti == NULL) { GtkWidget *w; - if (stock_name) + + /* Save the image so we can see if an update is needed the + next time we call xg_tool_item_match_p. */ + if (EQ (style, Qtext)) + w = NULL; + else if (stock_name) { w = gtk_image_new_from_stock (stock_name, icon_size); g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME, @@ -4422,93 +4421,34 @@ else { w = xg_get_image_for_pixmap (f, img, x->widget, NULL); - /* Save the image so we can see if an update is needed when - this function is called again. */ g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA, (gpointer)img->pixmap); } - gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin); - ti = xg_make_tool_item (f, w, &wbutton, label, i, vert_only); - gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, i); - gtk_widget_set_sensitive (wbutton, enabled_p); - } - else - { - GtkWidget *vb = XG_BIN_CHILD (wbutton); - GtkWidget *wimage; - GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage); - - Pixmap old_img = (Pixmap) g_object_get_data (G_OBJECT (wimage), - XG_TOOL_BAR_IMAGE_DATA); - gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage), - XG_TOOL_BAR_STOCK_NAME); - gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage), - XG_TOOL_BAR_ICON_NAME); - gtk_label_set_text (GTK_LABEL (wlbl), label); - gtk_tool_item_set_is_important (ti, !vert_only); - if (stock_name && - (! old_stock_name || strcmp (old_stock_name, stock_name) != 0)) - { - gtk_image_set_from_stock (GTK_IMAGE (wimage), - stock_name, icon_size); - g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME, - (gpointer) xstrdup (stock_name), - (GDestroyNotify) xfree); - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, - NULL); - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, - NULL); - } - else if (icon_name && - (! old_icon_name || strcmp (old_icon_name, icon_name) != 0)) - { - gtk_image_set_from_icon_name (GTK_IMAGE (wimage), - icon_name, icon_size); - g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, - (gpointer) xstrdup (icon_name), - (GDestroyNotify) xfree); - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, - NULL); - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME, - NULL); - } - else if (img && old_img != img->pixmap) - { - (void) xg_get_image_for_pixmap (f, img, x->widget, - GTK_IMAGE (wimage)); - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, - (gpointer)img->pixmap); - - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME, - NULL); - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, - NULL); - } - - gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin); - - gtk_widget_set_sensitive (wbutton, enabled_p); - } - xg_show_toolbar_item (ti); + if (w) gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin); + ti = xg_make_tool_item (f, w, &wbutton, label, i, horiz, text_image); + gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j); + } #undef PROP + + gtk_widget_set_sensitive (wbutton, enabled_p); + j++; } - /* Remove buttons not longer needed. We just hide them so they - can be reused later on. */ + /* Remove buttons not longer needed. */ do { - ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), i++); - if (ti) gtk_widget_hide_all (GTK_WIDGET (ti)); + ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j++); + if (ti) + gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti)); } while (ti != NULL); if (f->n_tool_bar_items != 0) { if (pack_tool_bar) xg_pack_tool_bar (f, f->tool_bar_position); - gtk_widget_show (x->toolbar_widget); - gtk_widget_show (x->handlebox_widget); + gtk_widget_show_all (GTK_WIDGET (x->handlebox_widget)); if (xg_update_tool_bar_sizes (f)) xg_height_or_width_changed (f); } ------------------------------------------------------------ revno: 102733 committer: Michael Albinus branch nick: trunk timestamp: Fri 2010-12-31 20:57:05 +0100 message: * net/tramp-sh.el (tramp-methods): Add recursive options to "scpc" and "scpx". diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2010-12-30 18:08:18 +0000 +++ lisp/ChangeLog 2010-12-31 19:57:05 +0000 @@ -1,3 +1,8 @@ +2010-12-31 Michael Albinus + + * net/tramp-sh.el (tramp-methods): Add recursive options to "scpc" + and "scpx". + 2010-12-30 Tassilo Horn * doc-view.el (doc-view-set-doc-type): New function refactored === modified file 'lisp/net/tramp-sh.el' --- lisp/net/tramp-sh.el 2010-12-30 09:04:15 +0000 +++ lisp/net/tramp-sh.el 2010-12-31 19:57:05 +0000 @@ -161,10 +161,11 @@ (tramp-async-args (("-q"))) (tramp-remote-sh "/bin/sh") (tramp-copy-program "scp") - (tramp-copy-args (("-P" "%p") ("%k" "-p") ("-q") + (tramp-copy-args (("-P" "%p") ("%k" "-p") ("-q") ("-r") ("-o" "ControlPath=%t.%%r@%%h:%%p") ("-o" "ControlMaster=auto"))) (tramp-copy-keep-date t) + (tramp-copy-recursive t) (tramp-gw-args (("-o" "GlobalKnownHostsFile=/dev/null") ("-o" "UserKnownHostsFile=/dev/null") ("-o" "StrictHostKeyChecking=no"))) @@ -179,8 +180,9 @@ (tramp-async-args (("-q"))) (tramp-remote-sh "/bin/sh") (tramp-copy-program "scp") - (tramp-copy-args (("%k" "-p"))) + (tramp-copy-args (("-P" "%p") ("%k" "-p") ("-q") ("-r"))) (tramp-copy-keep-date t) + (tramp-copy-recursive t) (tramp-gw-args (("-o" "GlobalKnownHostsFile=/dev/null") ("-o" "UserKnownHostsFile=/dev/null") ("-o" "StrictHostKeyChecking=no"))) ------------------------------------------------------------ revno: 102732 committer: Jan D. branch nick: trunk timestamp: Fri 2010-12-31 14:16:16 +0100 message: For nextstep: Handle bad utf-8 in buffer name, always use buffer name for title. * nsfns.m (ns_set_name_as_filename): Always use buffer name for title and buffer filename only for RepresentedFilename. Handle bad UTF-8 in buffer name. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2010-12-30 11:30:55 +0000 +++ src/ChangeLog 2010-12-31 13:16:16 +0000 @@ -1,3 +1,9 @@ +2010-12-31 Jan Djärv + + * nsfns.m (ns_set_name_as_filename): Always use buffer name for + title and buffer filename only for RepresentedFilename. + Handle bad UTF-8 in buffer name (Bug#7517). + 2010-12-30 Jan Djärv * coding.h (ENCODE_UTF_8): Remove "Used by ..." comment. === modified file 'src/nsfns.m' --- src/nsfns.m 2010-12-30 11:30:55 +0000 +++ src/nsfns.m 2010-12-31 13:16:16 +0000 @@ -602,12 +602,13 @@ ns_set_name_as_filename (struct frame *f) { NSView *view; - Lisp_Object name; + Lisp_Object name, filename; Lisp_Object buf = XWINDOW (f->selected_window)->buffer; const char *title; NSAutoreleasePool *pool; struct gcpro gcpro1; - Lisp_Object encoded_name; + Lisp_Object encoded_name, encoded_filename; + NSString *str; NSTRACE (ns_set_name_as_filename); if (f->explicit_name || ! NILP (f->title) || ns_in_resize) @@ -615,16 +616,16 @@ BLOCK_INPUT; pool = [[NSAutoreleasePool alloc] init]; - name = XBUFFER (buf)->filename; - if (NILP (name) || FRAME_ICONIFIED_P (f)) name = XBUFFER (buf)->name; - - if (FRAME_ICONIFIED_P (f) && !NILP (f->icon_name)) - name = f->icon_name; + filename = XBUFFER (buf)->filename; + name = XBUFFER (buf)->name; if (NILP (name)) - name = build_string ([ns_app_name UTF8String]); - else - CHECK_STRING (name); + { + if (! NILP (filename)) + name = Ffile_name_nondirectory (filename); + else + name = build_string ([ns_app_name UTF8String]); + } GCPRO1 (name); encoded_name = ENCODE_UTF_8 (name); @@ -642,33 +643,39 @@ return; } - if (! FRAME_ICONIFIED_P (f)) + str = [NSString stringWithUTF8String: SDATA (encoded_name)]; + if (str == nil) str = @"Bad coding"; + + if (FRAME_ICONIFIED_P (f)) + [[view window] setMiniwindowTitle: str]; + else { + NSString *fstr; + + if (! NILP (filename)) + { + GCPRO1 (filename); + encoded_filename = ENCODE_UTF_8 (filename); + UNGCPRO; + + fstr = [NSString stringWithUTF8String: SDATA (encoded_filename)]; + if (fstr == nil) fstr = @""; #ifdef NS_IMPL_COCOA - /* work around a bug observed on 10.3 where - setTitleWithRepresentedFilename does not clear out previous state - if given filename does not exist */ - NSString *str = [NSString stringWithUTF8String: SDATA (encoded_name)]; - if (![[NSFileManager defaultManager] fileExistsAtPath: str]) - { - [[view window] setTitleWithRepresentedFilename: @""]; - [[view window] setTitle: str]; + /* work around a bug observed on 10.3 and later where + setTitleWithRepresentedFilename does not clear out previous state + if given filename does not exist */ + if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr]) + [[view window] setRepresentedFilename: @""]; +#endif } else - { - [[view window] setTitleWithRepresentedFilename: str]; - } -#else - [[view window] setTitleWithRepresentedFilename: - [NSString stringWithUTF8String: SDATA (encoded_name)]]; -#endif + fstr = @""; + + [[view window] setRepresentedFilename: fstr]; + [[view window] setTitle: str]; f->name = name; } - else - { - [[view window] setMiniwindowTitle: - [NSString stringWithUTF8String: SDATA (encoded_name)]]; - } + [pool release]; UNBLOCK_INPUT; } ------------------------------------------------------------ revno: 102731 committer: Tassilo Horn branch nick: trunk timestamp: Thu 2010-12-30 21:23:13 +0100 message: * misc.texi (Document View): Update DocView section with newly supported document formats. diff: === modified file 'doc/emacs/ChangeLog' --- doc/emacs/ChangeLog 2010-12-21 07:54:27 +0000 +++ doc/emacs/ChangeLog 2010-12-30 20:23:13 +0000 @@ -1,3 +1,8 @@ +2010-12-30 Tassilo Horn + + * misc.texi (Document View): Update DocView section with newly + supported document formats. + 2010-12-21 Chong Yidong * killing.texi: Resection the Info version to conform to the === modified file 'doc/emacs/misc.texi' --- doc/emacs/misc.texi 2010-10-02 02:46:13 +0000 +++ doc/emacs/misc.texi 2010-12-30 20:23:13 +0000 @@ -27,28 +27,39 @@ @cindex PDF file @cindex PS file @cindex Postscript file +@cindex OpenDocument file +@cindex Microsoft Office file @cindex DocView mode @cindex mode, DocView @cindex document viewer (DocView) @findex doc-view-mode DocView mode (@code{doc-view-mode}) is a viewer for DVI, Postscript -(PS), and PDF documents. It provides features such as slicing, -zooming, and searching inside documents. It works by converting the -document to a set of images using the @command{gs} (GhostScript) -command, and displaying those images. +(PS), PDF, OpenDocument, and Microsoft Office documents. It provides +features such as slicing, zooming, and searching inside documents. It +works by converting the document to a set of images using the +@command{gs} (GhostScript) command and other external tools +@footnote{@code{gs} is a hard requirement. For DVI files, +@code{dvipdf} or @code{dvipdfm} is needed. For OpenDocument and +Microsoft Office documents, the @code{unoconv} tool is needed.}, and +displaying those images. @findex doc-view-toggle-display @findex doc-view-toggle-display @cindex doc-view-minor-mode - When you visit a PDF or DVI file, Emacs automatically switches to -DocView mode. When you visit a Postscript file, Emacs switches to PS -mode, a major mode for editing Postscript files as text; however, it -also enables DocView minor mode, so you can type @kbd{C-c C-c} to view -the document with DocView. (PDF and DVI files, unlike Postscript -files, are not usually human-editable.) In either case, repeating -@kbd{C-c C-c} (@code{doc-view-toggle-display}) toggles between DocView -and the file text. + When you visit a document file with the exception of Postscript +files, Emacs automatically switches to DocView mode if possible +@footnote{The needed external tools for this document type have to be +available, emacs needs to run in a graphical frame, and PNG image +support has to be compiled into emacs. If any of these requirements +is not fulfilled, DocView falls back to an appropriate mode.}. When +you visit a Postscript file, Emacs switches to PS mode, a major mode +for editing Postscript files as text; however, it also enables DocView +minor mode, so you can type @kbd{C-c C-c} to view the document with +DocView. (PDF and DVI files, unlike Postscript files, are not usually +human-editable.) In either case, repeating @kbd{C-c C-c} +(@code{doc-view-toggle-display}) toggles between DocView and the file +text. You can explicitly toggle DocView mode with the command @code{M-x doc-view-mode}, and DocView minor mode with the command @code{M-x