2 Internal file viewer for the Midnight Commander
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009, 2011
7 The Free Software Foundation, Inc.
10 Miguel de Icaza, 1994, 1995, 1998
11 Janne Kukonlehto, 1994, 1995
13 Joseph M. Hinkle, 1996
16 Roland Illig <roland.illig@gmx.de>, 2004, 2005
17 Slava Zanko <slavazanko@google.com>, 2009
18 Andrew Borodin <aborodin@vmail.ru>, 2009
19 Ilia Maslakov <il.smind@gmail.com>, 2009
21 This file is part of the Midnight Commander.
23 The Midnight Commander is free software: you can redistribute it
24 and/or modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation, either version 3 of the License,
26 or (at your option) any later version.
28 The Midnight Commander is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with this program. If not, see <http://www.gnu.org/licenses/>.
41 #include "lib/global.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/mouse.h"
44 #include "lib/vfs/vfs.h"
45 #include "lib/strutil.h"
46 #include "lib/util.h" /* load_file_position() */
47 #include "lib/widget.h"
48 #include "lib/charsets.h"
52 #include "src/filemanager/layout.h" /* menubar_visible */
53 #include "src/filemanager/midnight.h" /* the_menubar */
58 /*** global variables ****************************************************************************/
60 int mcview_default_hex_mode
= 0;
61 int mcview_default_nroff_flag
= 0;
62 int mcview_global_wrap_mode
= 1;
63 int mcview_default_magic_flag
= 1;
65 int mcview_altered_hex_mode
= 0;
66 int mcview_altered_magic_flag
= 0;
67 int mcview_altered_nroff_flag
= 0;
69 int mcview_remember_file_position
= FALSE
;
71 /* Maxlimit for skipping updates */
72 int mcview_max_dirt_limit
= 10;
74 /* Scrolling is done in pages or line increments */
75 int mcview_mouse_move_pages
= 1;
77 /* end of file will be showen from mcview_show_eof */
78 char *mcview_show_eof
= NULL
;
80 /*** file scope macro definitions ****************************************************************/
82 /*** file scope type declarations ****************************************************************/
84 /*** file scope variables ************************************************************************/
87 /*** file scope functions ************************************************************************/
88 /* --------------------------------------------------------------------------------------------- */
92 do_mcview_event (mcview_t
* view
, Gpm_Event
* event
, int *result
)
96 Widget
*w
= (Widget
*) view
;
98 /* rest of the upper frame - call menu */
99 if (mcview_is_in_panel (view
) && (event
->type
& GPM_DOWN
) != 0 && event
->y
== w
->owner
->y
+ 1)
101 *result
= MOU_UNHANDLED
;
102 return FALSE
; /* don't draw viewer over menu */
105 *result
= MOU_NORMAL
;
107 local
= mouse_get_local (event
, w
);
109 /* We are not interested in the release events */
110 if ((local
.type
& (GPM_DOWN
| GPM_DRAG
)) == 0)
114 if ((local
.buttons
& GPM_B_UP
) != 0 && (local
.type
& GPM_DOWN
) != 0)
116 mcview_move_up (view
, 2);
119 if ((local
.buttons
& GPM_B_DOWN
) != 0 && (local
.type
& GPM_DOWN
) != 0)
121 mcview_move_down (view
, 2);
128 /* Scrolling left and right */
129 if (!view
->text_wrap_mode
)
131 if (x
< view
->data_area
.width
* 1 / 4)
133 mcview_move_left (view
, 1);
137 if (x
< view
->data_area
.width
* 3 / 4)
139 /* ignore the click */
143 mcview_move_right (view
, 1);
148 /* Scrolling up and down */
149 if (y
< view
->data_area
.top
+ view
->data_area
.height
* 1 / 3)
151 if (mcview_mouse_move_pages
)
152 mcview_move_up (view
, view
->data_area
.height
/ 2);
154 mcview_move_up (view
, 1);
157 else if (y
< view
->data_area
.top
+ view
->data_area
.height
* 2 / 3)
159 /* ignore the click */
163 if (mcview_mouse_move_pages
)
164 mcview_move_down (view
, view
->data_area
.height
/ 2);
166 mcview_move_down (view
, 1);
173 *result
= MOU_REPEAT
;
177 /* --------------------------------------------------------------------------------------------- */
179 /** Real view only */
181 mcview_event (Gpm_Event
* event
, void *data
)
183 mcview_t
*view
= (mcview_t
*) data
;
186 if (!mouse_global_in_widget (event
, (Widget
*) data
))
187 return MOU_UNHANDLED
;
189 if (do_mcview_event (view
, event
, &result
))
190 mcview_update (view
);
194 /* --------------------------------------------------------------------------------------------- */
195 /*** public functions ****************************************************************************/
196 /* --------------------------------------------------------------------------------------------- */
199 mcview_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
201 mcview_t
*view
= g_new0 (mcview_t
, 1);
203 init_widget (&view
->widget
, y
, x
, lines
, cols
, mcview_callback
, mcview_event
);
205 view
->hex_mode
= FALSE
;
206 view
->hexedit_mode
= FALSE
;
207 view
->locked
= FALSE
;
208 view
->hexview_in_text
= FALSE
;
209 view
->text_nroff_mode
= FALSE
;
210 view
->text_wrap_mode
= FALSE
;
211 view
->magic_mode
= FALSE
;
213 view
->dpy_frame_size
= is_panel
? 1 : 0;
214 view
->converter
= str_cnv_from_term
;
218 if (mcview_default_hex_mode
)
219 mcview_toggle_hex_mode (view
);
220 if (mcview_default_nroff_flag
)
221 mcview_toggle_nroff_mode (view
);
222 if (mcview_global_wrap_mode
)
223 mcview_toggle_wrap_mode (view
);
224 if (mcview_default_magic_flag
)
225 mcview_toggle_magic_mode (view
);
230 /* --------------------------------------------------------------------------------------------- */
231 /** Real view only */
234 mcview_viewer (const char *command
, const vfs_path_t
* file_vpath
, int start_line
)
240 /* Create dialog and widgets, put them on the dialog */
241 view_dlg
= create_dlg (FALSE
, 0, 0, LINES
, COLS
, NULL
, mcview_dialog_callback
, NULL
,
242 "[Internal File Viewer]", NULL
, DLG_WANT_TAB
);
244 lc_mcview
= mcview_new (0, 0, LINES
- 1, COLS
, FALSE
);
245 add_widget (view_dlg
, lc_mcview
);
247 add_widget (view_dlg
, buttonbar_new (TRUE
));
249 view_dlg
->get_title
= mcview_get_title
;
254 file
= vfs_path_to_str (file_vpath
);
255 succeeded
= mcview_load (lc_mcview
, command
, file
, start_line
);
262 view_dlg
->state
= DLG_CLOSED
;
264 if (view_dlg
->state
== DLG_CLOSED
)
265 destroy_dlg (view_dlg
);
270 /* {{{ Miscellaneous functions }}} */
272 /* --------------------------------------------------------------------------------------------- */
275 mcview_load (mcview_t
* view
, const char *command
, const char *file
, int start_line
)
277 gboolean retval
= FALSE
;
278 vfs_path_t
*vpath
= NULL
;
281 assert (view
->bytes_per_line
!= 0);
284 view
->filename_vpath
= vfs_path_from_str (file
);
286 /* get working dir */
287 if (file
!= NULL
&& file
[0] != '\0')
289 vfs_path_free (view
->workdir_vpath
);
291 if (!g_path_is_absolute (file
))
295 p
= vfs_path_clone (vfs_get_raw_current_dir ());
296 view
->workdir_vpath
= vfs_path_append_new (p
, file
, (char *) NULL
);
301 /* try extract path form filename */
305 fname
= x_basename (file
);
306 dir
= g_strndup (file
, (size_t) (fname
- file
));
307 view
->workdir_vpath
= vfs_path_from_str (dir
);
312 if (!mcview_is_in_panel (view
))
313 view
->dpy_text_column
= 0;
315 mcview_set_codeset (view
);
317 if (command
!= NULL
&& (view
->magic_mode
|| file
== NULL
|| file
[0] == '\0'))
318 retval
= mcview_load_command_output (view
, command
);
319 else if (file
!= NULL
&& file
[0] != '\0')
322 char tmp
[BUF_MEDIUM
];
326 vpath
= vfs_path_from_str (file
);
327 fd
= mc_open (vpath
, O_RDONLY
| O_NONBLOCK
);
330 g_snprintf (tmp
, sizeof (tmp
), _("Cannot open \"%s\"\n%s"),
331 file
, unix_error_string (errno
));
332 mcview_show_error (view
, tmp
);
333 vfs_path_free (view
->filename_vpath
);
334 view
->filename_vpath
= NULL
;
335 vfs_path_free (view
->workdir_vpath
);
336 view
->workdir_vpath
= NULL
;
340 /* Make sure we are working with a regular file */
341 if (mc_fstat (fd
, &st
) == -1)
344 g_snprintf (tmp
, sizeof (tmp
), _("Cannot stat \"%s\"\n%s"),
345 file
, unix_error_string (errno
));
346 mcview_show_error (view
, tmp
);
347 vfs_path_free (view
->filename_vpath
);
348 view
->filename_vpath
= NULL
;
349 vfs_path_free (view
->workdir_vpath
);
350 view
->workdir_vpath
= NULL
;
354 if (!S_ISREG (st
.st_mode
))
357 mcview_show_error (view
, _("Cannot view: not a regular file"));
358 vfs_path_free (view
->filename_vpath
);
359 view
->filename_vpath
= NULL
;
360 vfs_path_free (view
->workdir_vpath
);
361 view
->workdir_vpath
= NULL
;
365 if (st
.st_size
== 0 || mc_lseek (fd
, 0, SEEK_SET
) == -1)
367 /* Must be one of those nice files that grow (/proc) */
368 mcview_set_datasource_vfs_pipe (view
, fd
);
374 type
= get_compression_type (fd
, file
);
376 if (view
->magic_mode
&& (type
!= COMPRESSION_NONE
))
380 vfs_path_free (view
->filename_vpath
);
381 tmp_filename
= g_strconcat (file
, decompress_extension (type
), (char *) NULL
);
382 view
->filename_vpath
= vfs_path_from_str (tmp_filename
);
383 g_free (tmp_filename
);
385 mcview_set_datasource_file (view
, fd
, &st
);
391 view
->command
= g_strdup (command
);
393 view
->search_start
= 0;
394 view
->search_end
= 0;
395 view
->dpy_text_column
= 0;
397 mcview_compute_areas (view
);
398 mcview_update_bytes_per_line (view
);
400 if (mcview_remember_file_position
&& view
->filename_vpath
!= NULL
&& start_line
== 0)
403 off_t new_offset
, max_offset
;
405 load_file_position (view
->filename_vpath
, &line
, &col
, &new_offset
, &view
->saved_bookmarks
);
406 max_offset
= mcview_get_filesize (view
) - 1;
410 new_offset
= min (new_offset
, max_offset
);
412 view
->dpy_start
= mcview_bol (view
, new_offset
, 0);
415 view
->dpy_start
= new_offset
- new_offset
% view
->bytes_per_line
;
416 view
->hex_cursor
= new_offset
;
419 else if (start_line
> 0)
420 mcview_moveto (view
, start_line
- 1, 0);
422 view
->hexedit_lownibble
= FALSE
;
423 view
->hexview_in_text
= FALSE
;
424 view
->change_list
= NULL
;
425 vfs_path_free (vpath
);
429 /* --------------------------------------------------------------------------------------------- */