Drop old mouse API and use the new one.
[midnight-commander.git] / src / viewer / mcviewer.c
blobb327dcaec8b84d8dbd537e07c014857c12fe2939
1 /*
2 Internal file viewer for the Midnight Commander
3 Interface 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
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>
37 #include <errno.h>
39 #include "lib/global.h"
40 #include "lib/tty/tty.h"
41 #include "lib/vfs/vfs.h"
42 #include "lib/strutil.h"
43 #include "lib/util.h" /* load_file_position() */
44 #include "lib/widget.h"
46 #include "src/filemanager/layout.h" /* menubar_visible */
47 #include "src/filemanager/midnight.h" /* the_menubar */
49 #include "internal.h"
51 /*** global variables ****************************************************************************/
53 int mcview_default_hex_mode = 0;
54 int mcview_default_nroff_flag = 0;
55 int mcview_global_wrap_mode = 1;
56 int mcview_default_magic_flag = 1;
58 int mcview_altered_hex_mode = 0;
59 int mcview_altered_magic_flag = 0;
60 int mcview_altered_nroff_flag = 0;
62 int mcview_remember_file_position = FALSE;
64 /* Maxlimit for skipping updates */
65 int mcview_max_dirt_limit = 10;
67 /* Scrolling is done in pages or line increments */
68 int mcview_mouse_move_pages = 1;
70 /* end of file will be showen from mcview_show_eof */
71 char *mcview_show_eof = NULL;
73 /*** file scope macro definitions ****************************************************************/
75 /*** file scope type declarations ****************************************************************/
77 /*** file scope variables ************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
80 /*** file scope functions ************************************************************************/
81 /* --------------------------------------------------------------------------------------------- */
83 static void
84 mcview_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
86 WView *view = (WView *) w;
87 gboolean ok = TRUE;
89 switch (msg)
91 case MSG_MOUSE_DOWN:
92 if (mcview_is_in_panel (view))
94 if (event->y == WIDGET (w->owner)->y)
96 /* return MOU_UNHANDLED */
97 event->result.abort = TRUE;
98 /* don't draw viewer over menu */
99 ok = FALSE;
100 break;
103 if (!view->active)
105 /* Grab focus */
106 change_panel ();
109 /* fall throught */
111 case MSG_MOUSE_CLICK:
112 if (!view->text_wrap_mode)
114 /* Scrolling left and right */
115 screen_dimen x;
117 x = event->x + 1; /* FIXME */
119 if (x < view->data_area.width * 1 / 4)
121 mcview_move_left (view, 1);
122 event->result.repeat = msg == MSG_MOUSE_DOWN;
124 else if (x < view->data_area.width * 3 / 4)
126 /* ignore the click */
127 ok = FALSE;
129 else
131 mcview_move_right (view, 1);
132 event->result.repeat = msg == MSG_MOUSE_DOWN;
135 else
137 /* Scrolling up and down */
138 screen_dimen y;
140 y = event->y + 1; /* FIXME */
142 if (y < view->data_area.top + view->data_area.height * 1 / 3)
144 if (mcview_mouse_move_pages)
145 mcview_move_up (view, view->data_area.height / 2);
146 else
147 mcview_move_up (view, 1);
149 event->result.repeat = msg == MSG_MOUSE_DOWN;
151 else if (y < view->data_area.top + view->data_area.height * 2 / 3)
153 /* ignore the click */
154 ok = FALSE;
156 else
158 if (mcview_mouse_move_pages)
159 mcview_move_down (view, view->data_area.height / 2);
160 else
161 mcview_move_down (view, 1);
163 event->result.repeat = msg == MSG_MOUSE_DOWN;
166 break;
168 case MSG_MOUSE_SCROLL_UP:
169 mcview_move_up (view, 2);
170 break;
172 case MSG_MOUSE_SCROLL_DOWN:
173 mcview_move_down (view, 2);
174 break;
176 default:
177 ok = FALSE;
178 break;
181 if (ok)
182 mcview_update (view);
185 /* --------------------------------------------------------------------------------------------- */
186 /*** public functions ****************************************************************************/
187 /* --------------------------------------------------------------------------------------------- */
189 WView *
190 mcview_new (int y, int x, int lines, int cols, gboolean is_panel)
192 WView *view;
194 view = g_new0 (WView, 1);
195 widget_init (WIDGET (view), y, x, lines, cols, mcview_callback, mcview_mouse_callback);
197 view->hex_mode = FALSE;
198 view->hexedit_mode = FALSE;
199 view->locked = FALSE;
200 view->hexview_in_text = FALSE;
201 view->text_nroff_mode = FALSE;
202 view->text_wrap_mode = FALSE;
203 view->magic_mode = FALSE;
205 view->active = FALSE;
206 view->dpy_frame_size = is_panel ? 1 : 0;
207 view->converter = str_cnv_from_term;
209 mcview_init (view);
211 if (mcview_default_hex_mode)
212 mcview_toggle_hex_mode (view);
213 if (mcview_default_nroff_flag)
214 mcview_toggle_nroff_mode (view);
215 if (mcview_global_wrap_mode)
216 mcview_toggle_wrap_mode (view);
217 if (mcview_default_magic_flag)
218 mcview_toggle_magic_mode (view);
220 return view;
223 /* --------------------------------------------------------------------------------------------- */
224 /** Real view only */
226 gboolean
227 mcview_viewer (const char *command, const vfs_path_t * file_vpath, int start_line,
228 off_t search_start, off_t search_end)
230 gboolean succeeded;
231 WView *lc_mcview;
232 WDialog *view_dlg;
234 /* Create dialog and widgets, put them on the dialog */
235 view_dlg = dlg_create (FALSE, 0, 0, LINES, COLS, NULL, mcview_dialog_callback, NULL,
236 "[Internal File Viewer]", NULL, DLG_WANT_TAB);
238 lc_mcview = mcview_new (0, 0, LINES - 1, COLS, FALSE);
239 add_widget (view_dlg, lc_mcview);
241 add_widget (view_dlg, buttonbar_new (TRUE));
243 view_dlg->get_title = mcview_get_title;
245 succeeded =
246 mcview_load (lc_mcview, command, vfs_path_as_str (file_vpath), start_line, search_start,
247 search_end);
249 if (succeeded)
250 dlg_run (view_dlg);
251 else
252 view_dlg->state = DLG_CLOSED;
254 if (view_dlg->state == DLG_CLOSED)
255 dlg_destroy (view_dlg);
257 return succeeded;
260 /* {{{ Miscellaneous functions }}} */
262 /* --------------------------------------------------------------------------------------------- */
264 gboolean
265 mcview_load (WView * view, const char *command, const char *file, int start_line,
266 off_t search_start, off_t search_end)
268 gboolean retval = FALSE;
269 vfs_path_t *vpath = NULL;
271 #ifdef HAVE_ASSERT_H
272 assert (view->bytes_per_line != 0);
273 #endif
275 view->filename_vpath = vfs_path_from_str (file);
277 /* get working dir */
278 if (file != NULL && file[0] != '\0')
280 vfs_path_free (view->workdir_vpath);
282 if (!g_path_is_absolute (file))
284 vfs_path_t *p;
286 p = vfs_path_clone (vfs_get_raw_current_dir ());
287 view->workdir_vpath = vfs_path_append_new (p, file, (char *) NULL);
288 vfs_path_free (p);
290 else
292 /* try extract path from filename */
293 const char *fname;
294 char *dir;
296 fname = x_basename (file);
297 dir = g_strndup (file, (size_t) (fname - file));
298 view->workdir_vpath = vfs_path_from_str (dir);
299 g_free (dir);
303 if (!mcview_is_in_panel (view))
304 view->dpy_text_column = 0;
306 mcview_set_codeset (view);
308 if (command != NULL && (view->magic_mode || file == NULL || file[0] == '\0'))
309 retval = mcview_load_command_output (view, command);
310 else if (file != NULL && file[0] != '\0')
312 int fd;
313 char tmp[BUF_MEDIUM];
314 struct stat st;
316 /* Open the file */
317 vpath = vfs_path_from_str (file);
318 fd = mc_open (vpath, O_RDONLY | O_NONBLOCK);
319 if (fd == -1)
321 g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\"\n%s"),
322 file, unix_error_string (errno));
323 mcview_close_datasource (view);
324 mcview_show_error (view, tmp);
325 vfs_path_free (view->filename_vpath);
326 view->filename_vpath = NULL;
327 vfs_path_free (view->workdir_vpath);
328 view->workdir_vpath = NULL;
329 goto finish;
332 /* Make sure we are working with a regular file */
333 if (mc_fstat (fd, &st) == -1)
335 mc_close (fd);
336 g_snprintf (tmp, sizeof (tmp), _("Cannot stat \"%s\"\n%s"),
337 file, unix_error_string (errno));
338 mcview_close_datasource (view);
339 mcview_show_error (view, tmp);
340 vfs_path_free (view->filename_vpath);
341 view->filename_vpath = NULL;
342 vfs_path_free (view->workdir_vpath);
343 view->workdir_vpath = NULL;
344 goto finish;
347 if (!S_ISREG (st.st_mode))
349 mc_close (fd);
350 mcview_close_datasource (view);
351 mcview_show_error (view, _("Cannot view: not a regular file"));
352 vfs_path_free (view->filename_vpath);
353 view->filename_vpath = NULL;
354 vfs_path_free (view->workdir_vpath);
355 view->workdir_vpath = NULL;
356 goto finish;
359 if (st.st_size == 0 || mc_lseek (fd, 0, SEEK_SET) == -1)
361 /* Must be one of those nice files that grow (/proc) */
362 mcview_set_datasource_vfs_pipe (view, fd);
364 else
366 if (view->magic_mode)
368 int type;
370 type = get_compression_type (fd, file);
372 if (type != COMPRESSION_NONE)
374 char *tmp_filename;
375 vfs_path_t *vpath1;
376 int fd1;
378 tmp_filename = g_strconcat (file, decompress_extension (type), (char *) NULL);
379 vpath1 = vfs_path_from_str (tmp_filename);
380 g_free (tmp_filename);
381 fd1 = mc_open (vpath1, O_RDONLY | O_NONBLOCK);
382 vfs_path_free (vpath1);
384 if (fd1 == -1)
386 g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\" in parse mode\n%s"),
387 file, unix_error_string (errno));
388 mcview_close_datasource (view);
389 mcview_show_error (view, tmp);
391 else
393 mc_close (fd);
394 fd = fd1;
395 mc_fstat (fd, &st);
400 mcview_set_datasource_file (view, fd, &st);
402 retval = TRUE;
405 finish:
406 view->command = g_strdup (command);
407 view->dpy_start = 0;
408 view->dpy_paragraph_skip_lines = 0;
409 mcview_state_machine_init (&view->dpy_state_top, 0);
410 view->dpy_wrap_dirty = FALSE;
411 view->force_max = -1;
412 view->dpy_text_column = 0;
414 mcview_compute_areas (view);
415 mcview_update_bytes_per_line (view);
417 if (mcview_remember_file_position && view->filename_vpath != NULL && start_line == 0)
419 long line, col;
420 off_t new_offset, max_offset;
422 load_file_position (view->filename_vpath, &line, &col, &new_offset, &view->saved_bookmarks);
423 max_offset = mcview_get_filesize (view) - 1;
424 if (max_offset < 0)
425 new_offset = 0;
426 else
427 new_offset = min (new_offset, max_offset);
428 if (!view->hex_mode)
430 view->dpy_start = mcview_bol (view, new_offset, 0);
431 view->dpy_wrap_dirty = TRUE;
433 else
435 view->dpy_start = new_offset - new_offset % view->bytes_per_line;
436 view->hex_cursor = new_offset;
439 else if (start_line > 0)
440 mcview_moveto (view, start_line - 1, 0);
442 view->search_start = search_start;
443 view->search_end = search_end;
444 view->hexedit_lownibble = FALSE;
445 view->hexview_in_text = FALSE;
446 view->change_list = NULL;
447 vfs_path_free (vpath);
448 return retval;
451 /* --------------------------------------------------------------------------------------------- */