Set WOP_TOP_SELECT options for panel widgets: WPanel, WView and WTree.
[midnight-commander.git] / src / viewer / lib.c
blobc7d808444b356d51f22c96fcae37abf54687e1c9
1 /*
2 Internal file viewer for the Midnight Commander
3 Common finctions (used from some other mcviewer functions)
5 Copyright (C) 1994-2016
6 Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Joseph M. Hinkle, 1996
13 Norbert Warmuth, 1997
14 Pavel Machek, 1998
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009, 2013
17 Andrew Borodin <aborodin@vmail.ru>, 2009, 2013, 2014
18 Ilia Maslakov <il.smind@gmail.com>, 2009
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software: you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation, either version 3 of the License,
25 or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program. If not, see <http://www.gnu.org/licenses/>.
36 #include <config.h>
38 #include <limits.h>
39 #include <sys/types.h>
41 #include "lib/global.h"
42 #include "lib/vfs/vfs.h"
43 #include "lib/strutil.h"
44 #include "lib/util.h" /* save_file_position() */
45 #include "lib/widget.h"
46 #ifdef HAVE_CHARSET
47 #include "lib/charsets.h"
48 #endif
50 #ifdef HAVE_CHARSET
51 #include "src/selcodepage.h"
52 #endif
54 #include "internal.h"
56 /*** global variables ****************************************************************************/
58 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
59 const off_t OFFSETTYPE_MAX = ((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1;
61 /*** file scope macro definitions ****************************************************************/
63 /*** file scope type declarations ****************************************************************/
65 /*** file scope variables ************************************************************************/
67 /*** file scope functions ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
70 /* --------------------------------------------------------------------------------------------- */
71 /*** public functions ****************************************************************************/
72 /* --------------------------------------------------------------------------------------------- */
74 void
75 mcview_toggle_magic_mode (WView * view)
77 char *filename, *command;
78 dir_list *dir;
79 int *dir_idx;
81 mcview_altered_magic_flag = 1;
82 view->magic_mode = !view->magic_mode;
84 /* reinit view */
85 filename = g_strdup (vfs_path_as_str (view->filename_vpath));
86 command = g_strdup (view->command);
87 dir = view->dir;
88 dir_idx = view->dir_idx;
89 view->dir = NULL;
90 view->dir_idx = NULL;
91 mcview_done (view);
92 mcview_init (view);
93 mcview_load (view, command, filename, 0, 0, 0);
94 view->dir = dir;
95 view->dir_idx = dir_idx;
96 g_free (filename);
97 g_free (command);
99 view->dpy_bbar_dirty = TRUE;
100 view->dirty++;
103 /* --------------------------------------------------------------------------------------------- */
105 void
106 mcview_toggle_wrap_mode (WView * view)
108 view->text_wrap_mode = !view->text_wrap_mode;
109 view->dpy_wrap_dirty = TRUE;
110 view->dpy_bbar_dirty = TRUE;
111 view->dirty++;
114 /* --------------------------------------------------------------------------------------------- */
116 void
117 mcview_toggle_nroff_mode (WView * view)
119 view->text_nroff_mode = !view->text_nroff_mode;
120 mcview_altered_nroff_flag = 1;
121 view->dpy_wrap_dirty = TRUE;
122 view->dpy_bbar_dirty = TRUE;
123 view->dirty++;
126 /* --------------------------------------------------------------------------------------------- */
128 void
129 mcview_toggle_hex_mode (WView * view)
131 view->hex_mode = !view->hex_mode;
133 if (view->hex_mode)
135 view->hex_cursor = view->dpy_start;
136 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
137 widget_want_cursor (WIDGET (view), TRUE);
139 else
141 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
142 view->hex_cursor = view->dpy_start;
143 widget_want_cursor (WIDGET (view), FALSE);
145 mcview_altered_hex_mode = 1;
146 view->dpy_paragraph_skip_lines = 0;
147 view->dpy_wrap_dirty = TRUE;
148 view->dpy_bbar_dirty = TRUE;
149 view->dirty++;
152 /* --------------------------------------------------------------------------------------------- */
154 void
155 mcview_init (WView * view)
157 size_t i;
159 view->filename_vpath = NULL;
160 view->workdir_vpath = NULL;
161 view->command = NULL;
162 view->search_nroff_seq = NULL;
164 mcview_set_datasource_none (view);
166 view->growbuf_in_use = FALSE;
167 /* leave the other growbuf fields uninitialized */
169 view->hexedit_lownibble = FALSE;
170 view->locked = FALSE;
171 view->coord_cache = NULL;
173 view->dpy_start = 0;
174 view->dpy_paragraph_skip_lines = 0;
175 mcview_state_machine_init (&view->dpy_state_top, 0);
176 view->dpy_wrap_dirty = FALSE;
177 view->force_max = -1;
178 view->dpy_text_column = 0;
179 view->dpy_end = 0;
180 view->hex_cursor = 0;
181 view->cursor_col = 0;
182 view->cursor_row = 0;
183 view->change_list = NULL;
185 /* {status,ruler,data}_area are left uninitialized */
187 view->dirty = 0;
188 view->dpy_bbar_dirty = TRUE;
189 view->bytes_per_line = 1;
191 view->search_start = 0;
192 view->search_end = 0;
194 view->marker = 0;
195 for (i = 0; i < G_N_ELEMENTS (view->marks); i++)
196 view->marks[i] = 0;
198 view->update_steps = 0;
199 view->update_activate = 0;
201 view->saved_bookmarks = NULL;
204 /* --------------------------------------------------------------------------------------------- */
206 void
207 mcview_done (WView * view)
209 /* Save current file position */
210 if (mcview_remember_file_position && view->filename_vpath != NULL)
212 save_file_position (view->filename_vpath, -1, 0,
213 view->hex_mode ? view->hex_cursor : view->dpy_start,
214 view->saved_bookmarks);
215 view->saved_bookmarks = NULL;
218 /* Write back the global viewer mode */
219 mcview_default_hex_mode = view->hex_mode;
220 mcview_default_nroff_flag = view->text_nroff_mode;
221 mcview_default_magic_flag = view->magic_mode;
222 mcview_global_wrap_mode = view->text_wrap_mode;
224 /* Free memory used by the viewer */
226 /* view->widget needs no destructor */
228 vfs_path_free (view->filename_vpath);
229 view->filename_vpath = NULL;
230 vfs_path_free (view->workdir_vpath);
231 view->workdir_vpath = NULL;
232 MC_PTR_FREE (view->command);
234 mcview_close_datasource (view);
235 /* the growing buffer is freed with the datasource */
237 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
239 if (view->converter == INVALID_CONV)
240 view->converter = str_cnv_from_term;
242 if (view->converter != str_cnv_from_term)
244 str_close_conv (view->converter);
245 view->converter = str_cnv_from_term;
248 mc_search_free (view->search);
249 view->search = NULL;
250 MC_PTR_FREE (view->last_search_string);
251 mcview_nroff_seq_free (&view->search_nroff_seq);
252 mcview_hexedit_free_change_list (view);
254 if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
256 /* mcviewer is the owner of file list */
257 dir_list_clean (view->dir);
258 g_free (view->dir->list);
259 g_free (view->dir_idx);
260 g_free (view->dir);
263 view->dir = NULL;
266 /* --------------------------------------------------------------------------------------------- */
268 void
269 mcview_set_codeset (WView * view)
271 #ifdef HAVE_CHARSET
272 const char *cp_id = NULL;
274 view->utf8 = TRUE;
275 cp_id =
276 get_codepage_id (mc_global.source_codepage >=
277 0 ? mc_global.source_codepage : mc_global.display_codepage);
278 if (cp_id != NULL)
280 GIConv conv;
281 conv = str_crt_conv_from (cp_id);
282 if (conv != INVALID_CONV)
284 if (view->converter != str_cnv_from_term)
285 str_close_conv (view->converter);
286 view->converter = conv;
288 view->utf8 = (gboolean) str_isutf8 (cp_id);
289 view->dpy_wrap_dirty = TRUE;
291 #else
292 (void) view;
293 #endif
296 /* --------------------------------------------------------------------------------------------- */
298 #ifdef HAVE_CHARSET
299 void
300 mcview_select_encoding (WView * view)
302 if (do_select_codepage ())
303 mcview_set_codeset (view);
305 #endif
307 /* --------------------------------------------------------------------------------------------- */
309 void
310 mcview_show_error (WView * view, const char *msg)
312 if (mcview_is_in_panel (view))
313 mcview_set_datasource_string (view, msg);
314 else
315 message (D_ERROR, MSG_ERROR, "%s", msg);
318 /* --------------------------------------------------------------------------------------------- */
319 /** returns index of the first char in the line
320 * it is constant for all line characters
323 off_t
324 mcview_bol (WView * view, off_t current, off_t limit)
326 int c;
327 off_t filesize;
328 filesize = mcview_get_filesize (view);
329 if (current <= 0)
330 return 0;
331 if (current > filesize)
332 return filesize;
333 if (!mcview_get_byte (view, current, &c))
334 return current;
335 if (c == '\n')
337 if (!mcview_get_byte (view, current - 1, &c))
338 return current;
339 if (c == '\r')
340 current--;
342 while (current > 0 && current > limit)
344 if (!mcview_get_byte (view, current - 1, &c))
345 break;
346 if (c == '\r' || c == '\n')
347 break;
348 current--;
350 return current;
353 /* --------------------------------------------------------------------------------------------- */
354 /** returns index of last char on line + width EOL
355 * mcview_eol of the current line == mcview_bol next line
358 off_t
359 mcview_eol (WView * view, off_t current, off_t limit)
361 int c, prev_ch = 0;
362 off_t filesize;
363 filesize = mcview_get_filesize (view);
364 if (current < 0)
365 return 0;
366 if (current >= filesize)
367 return filesize;
368 while (current < filesize && current < limit)
370 if (!mcview_get_byte (view, current, &c))
371 break;
372 if (c == '\n')
374 current++;
375 break;
377 else if (prev_ch == '\r')
379 break;
381 current++;
382 prev_ch = c;
384 return current;
387 /* --------------------------------------------------------------------------------------------- */
389 char *
390 mcview_get_title (const WDialog * h, size_t len)
392 const WView *view = (const WView *) find_widget_type (h, mcview_callback);
393 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
394 const char *file_label;
395 const char *view_filename;
396 char *ret_str;
398 view_filename = vfs_path_as_str (view->filename_vpath);
400 len -= 4;
402 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
403 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
405 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
406 return ret_str;
409 /* --------------------------------------------------------------------------------------------- */
412 mcview_calc_percent (WView * view, off_t p)
414 const screen_dimen right = view->status_area.left + view->status_area.width;
415 const screen_dimen height = view->status_area.height;
416 off_t filesize;
417 int percent;
419 if (height < 1 || right < 4)
420 return (-1);
421 if (mcview_may_still_grow (view))
422 return (-1);
424 filesize = mcview_get_filesize (view);
425 if (view->hex_mode && filesize > 0)
427 /* p can't be beyond the last char, only over that. Compensate for this. */
428 filesize--;
431 if (filesize == 0 || p >= filesize)
432 percent = 100;
433 else if (p > (INT_MAX / 100))
434 percent = p / (filesize / 100);
435 else
436 percent = p * 100 / filesize;
438 return percent;
441 /* --------------------------------------------------------------------------------------------- */