Compare commits
4 Commits
92c1bf783f
...
a20e4c74d8
Author | SHA1 | Date | |
---|---|---|---|
a20e4c74d8 | |||
d33c17b888 | |||
6033f6a869 | |||
88e86724c3 |
2
NEWS
2
NEWS
@ -2,6 +2,8 @@ Unreleased
|
|||||||
|
|
||||||
* Added an optional X11 user interface
|
* Added an optional X11 user interface
|
||||||
|
|
||||||
|
* Implemented mouse drags on the elapsed time gauge and the scrollbar
|
||||||
|
|
||||||
* Added a "z" binding to center the view on the selected item
|
* Added a "z" binding to center the view on the selected item
|
||||||
|
|
||||||
* Fixed possibility of connection timeouts with PulseAudio integration
|
* Fixed possibility of connection timeouts with PulseAudio integration
|
||||||
|
88
nncmpp.c
88
nncmpp.c
@ -1144,7 +1144,7 @@ pulse_volume_status (struct pulse *self, struct str *s)
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
WIDGET_NONE = 0, WIDGET_BUTTON, WIDGET_GAUGE, WIDGET_TAB, WIDGET_SPECTRUM,
|
WIDGET_NONE = 0, WIDGET_BUTTON, WIDGET_GAUGE, WIDGET_TAB, WIDGET_SPECTRUM,
|
||||||
WIDGET_LIST, WIDGET_SCROLLBAR,
|
WIDGET_LIST, WIDGET_SCROLLBAR, WIDGET_MESSAGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct widget;
|
struct widget;
|
||||||
@ -1335,6 +1335,7 @@ static struct app_context
|
|||||||
int ui_hunit; ///< Horizontal unit
|
int ui_hunit; ///< Horizontal unit
|
||||||
int ui_vunit; ///< Vertical unit
|
int ui_vunit; ///< Vertical unit
|
||||||
bool ui_focused; ///< Whether the window has focus
|
bool ui_focused; ///< Whether the window has focus
|
||||||
|
short ui_dragging; ///< ID of any dragged widget
|
||||||
|
|
||||||
#ifdef WITH_FFTW
|
#ifdef WITH_FFTW
|
||||||
struct spectrum spectrum; ///< Spectrum analyser
|
struct spectrum spectrum; ///< Spectrum analyser
|
||||||
@ -2187,12 +2188,19 @@ app_layout_mpd_status (void)
|
|||||||
static void
|
static void
|
||||||
app_layout_statusbar (void)
|
app_layout_statusbar (void)
|
||||||
{
|
{
|
||||||
|
struct layout l = {};
|
||||||
if (g.message)
|
if (g.message)
|
||||||
app_layout_text (g.message, APP_ATTR (HIGHLIGHT));
|
{
|
||||||
|
app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1))
|
||||||
|
->id = WIDGET_MESSAGE;
|
||||||
|
app_push_fill (&l, g.ui->label (APP_ATTR (HIGHLIGHT), g.message))
|
||||||
|
->id = WIDGET_MESSAGE;
|
||||||
|
app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1))
|
||||||
|
->id = WIDGET_MESSAGE;
|
||||||
|
app_flush_layout (&l);
|
||||||
|
}
|
||||||
else if (g.editor.line)
|
else if (g.editor.line)
|
||||||
{
|
{
|
||||||
struct layout l = {};
|
|
||||||
app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1));
|
app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1));
|
||||||
app_push (&l, g.ui->editor (APP_ATTR (HIGHLIGHT)));
|
app_push (&l, g.ui->editor (APP_ATTR (HIGHLIGHT)));
|
||||||
app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1));
|
app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1));
|
||||||
@ -2536,6 +2544,7 @@ app_process_action (enum action action)
|
|||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
print_error ("can't do that here: %s", g_action_descriptions[action]);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case ACTION_MULTISELECT:
|
case ACTION_MULTISELECT:
|
||||||
@ -2666,6 +2675,7 @@ app_editor_process_action (enum action action)
|
|||||||
g.editor.on_end = NULL;
|
g.editor.on_end = NULL;
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
print_error ("can't do that here: %s", g_action_descriptions[action]);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case ACTION_EDITOR_B_CHAR:
|
case ACTION_EDITOR_B_CHAR:
|
||||||
@ -2706,6 +2716,7 @@ app_process_left_mouse_click (struct widget *w, int x, int y, bool double_click)
|
|||||||
break;
|
break;
|
||||||
case WIDGET_GAUGE:
|
case WIDGET_GAUGE:
|
||||||
{
|
{
|
||||||
|
// TODO: We should avoid queuing up too many.
|
||||||
float position = (float) x / w->width;
|
float position = (float) x / w->width;
|
||||||
if (g.song_duration >= 1)
|
if (g.song_duration >= 1)
|
||||||
{
|
{
|
||||||
@ -2750,7 +2761,12 @@ app_process_left_mouse_click (struct widget *w, int x, int y, bool double_click)
|
|||||||
tab->item_top = (float) y / w->height
|
tab->item_top = (float) y / w->height
|
||||||
* (int) tab->item_count - visible_items / 2;
|
* (int) tab->item_count - visible_items / 2;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case WIDGET_MESSAGE:
|
||||||
|
cstr_set (&g.message, NULL);
|
||||||
|
poller_timer_reset (&g.message_timer);
|
||||||
|
app_invalidate ();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2762,8 +2778,27 @@ app_process_mouse (termo_mouse_event_t type, int x, int y, int button,
|
|||||||
// XXX: Terminals don't let us know which button has been released,
|
// XXX: Terminals don't let us know which button has been released,
|
||||||
// so we can't press buttons at that point. We'd need a special "click"
|
// so we can't press buttons at that point. We'd need a special "click"
|
||||||
// event handler that could be handled better under X11.
|
// event handler that could be handled better under X11.
|
||||||
if (type != TERMO_MOUSE_PRESS)
|
if (type == TERMO_MOUSE_RELEASE)
|
||||||
|
{
|
||||||
|
g.ui_dragging = WIDGET_NONE;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == TERMO_MOUSE_DRAG)
|
||||||
|
{
|
||||||
|
if (g.ui_dragging != WIDGET_GAUGE
|
||||||
|
&& g.ui_dragging != WIDGET_SCROLLBAR)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
struct widget *target = NULL;
|
||||||
|
LIST_FOR_EACH (struct widget, w, g.widgets.head)
|
||||||
|
if (w->id == g.ui_dragging)
|
||||||
|
target = w;
|
||||||
|
|
||||||
|
x -= target->x;
|
||||||
|
y -= target->y;
|
||||||
|
return app_process_left_mouse_click (target, x, y, double_click);
|
||||||
|
}
|
||||||
|
|
||||||
if (g.editor.line)
|
if (g.editor.line)
|
||||||
{
|
{
|
||||||
@ -2784,6 +2819,7 @@ app_process_mouse (termo_mouse_event_t type, int x, int y, int button,
|
|||||||
switch (button)
|
switch (button)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
|
g.ui_dragging = target->id;
|
||||||
return app_process_left_mouse_click (target, x, y, double_click);
|
return app_process_left_mouse_click (target, x, y, double_click);
|
||||||
case 4:
|
case 4:
|
||||||
if (target->id == WIDGET_LIST)
|
if (target->id == WIDGET_LIST)
|
||||||
@ -5244,6 +5280,8 @@ tui_init (void)
|
|||||||
if (!termo_start (g.tk) || !initscr () || nonl () == ERR)
|
if (!termo_start (g.tk) || !initscr () || nonl () == ERR)
|
||||||
exit_fatal ("failed to set up the terminal");
|
exit_fatal ("failed to set up the terminal");
|
||||||
|
|
||||||
|
termo_set_mouse_tracking_mode (g.tk, TERMO_MOUSE_TRACKING_DRAG);
|
||||||
|
|
||||||
g.ui = &tui_ui;
|
g.ui = &tui_ui;
|
||||||
g.ui_width = COLS;
|
g.ui_width = COLS;
|
||||||
g.ui_height = LINES;
|
g.ui_height = LINES;
|
||||||
@ -5941,6 +5979,13 @@ on_x11_input_event (XEvent *ev)
|
|||||||
on_x11_keypress (ev);
|
on_x11_keypress (ev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ev->type == MotionNotify)
|
||||||
|
{
|
||||||
|
// We only select for Button1MotionMask, so this works out.
|
||||||
|
int x = ev->xmotion.x, y = ev->xmotion.y;
|
||||||
|
app_process_mouse (TERMO_MOUSE_DRAG, x, y, 1, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// See tui_on_tty_event(). Just here we know the button on button release.
|
// See tui_on_tty_event(). Just here we know the button on button release.
|
||||||
int x = ev->xbutton.x, y = ev->xbutton.y;
|
int x = ev->xbutton.x, y = ev->xbutton.y;
|
||||||
@ -5986,6 +6031,7 @@ on_x11_event (XEvent *ev)
|
|||||||
case KeyPress:
|
case KeyPress:
|
||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
case ButtonRelease:
|
case ButtonRelease:
|
||||||
|
case MotionNotify:
|
||||||
on_x11_input_event (ev);
|
on_x11_input_event (ev);
|
||||||
break;
|
break;
|
||||||
case UnmapNotify:
|
case UnmapNotify:
|
||||||
@ -6182,7 +6228,8 @@ x11_init (void)
|
|||||||
XSetWindowAttributes attrs =
|
XSetWindowAttributes attrs =
|
||||||
{
|
{
|
||||||
.event_mask = StructureNotifyMask | ExposureMask | FocusChangeMask
|
.event_mask = StructureNotifyMask | ExposureMask | FocusChangeMask
|
||||||
| KeyPressMask | ButtonPressMask | ButtonReleaseMask,
|
| KeyPressMask | ButtonPressMask | ButtonReleaseMask
|
||||||
|
| Button1MotionMask,
|
||||||
.bit_gravity = NorthWestGravity,
|
.bit_gravity = NorthWestGravity,
|
||||||
.background_pixel = default_bg.pixel,
|
.background_pixel = default_bg.pixel,
|
||||||
};
|
};
|
||||||
@ -6307,6 +6354,8 @@ signals_setup_handlers (void)
|
|||||||
|
|
||||||
// --- Initialisation, event handling ------------------------------------------
|
// --- Initialisation, event handling ------------------------------------------
|
||||||
|
|
||||||
|
static bool g_verbose_mode = false;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
app_on_signal_pipe_readable (const struct pollfd *fd, void *user_data)
|
app_on_signal_pipe_readable (const struct pollfd *fd, void *user_data)
|
||||||
{
|
{
|
||||||
@ -6352,19 +6401,16 @@ app_log_handler (void *user_data, const char *quote, const char *fmt,
|
|||||||
str_append (&message, quote);
|
str_append (&message, quote);
|
||||||
str_append_vprintf (&message, fmt, ap);
|
str_append_vprintf (&message, fmt, ap);
|
||||||
|
|
||||||
// If the standard error output isn't redirected, try our best at showing
|
// Show it to the user, then maybe log it elsewhere as well.
|
||||||
// the message to the user
|
cstr_set (&g.message, xstrdup (message.str));
|
||||||
if (!isatty (STDERR_FILENO))
|
poller_timer_set (&g.message_timer, 5000);
|
||||||
|
app_invalidate ();
|
||||||
|
|
||||||
|
if (g_verbose_mode && (g.ui != &tui_ui || !isatty (STDERR_FILENO)))
|
||||||
fprintf (stderr, "%s\n", message.str);
|
fprintf (stderr, "%s\n", message.str);
|
||||||
else if (g_debug_tab.active)
|
if (g_debug_tab.active)
|
||||||
debug_tab_push (str_steal (&message),
|
debug_tab_push (str_steal (&message),
|
||||||
user_data == NULL ? 0 : g.attrs[(intptr_t) user_data].attrs);
|
user_data == NULL ? 0 : g.attrs[(intptr_t) user_data].attrs);
|
||||||
else
|
|
||||||
{
|
|
||||||
cstr_set (&g.message, xstrdup (message.str));
|
|
||||||
app_invalidate ();
|
|
||||||
poller_timer_set (&g.message_timer, 5000);
|
|
||||||
}
|
|
||||||
str_free (&message);
|
str_free (&message);
|
||||||
|
|
||||||
in_processing = false;
|
in_processing = false;
|
||||||
@ -6434,6 +6480,7 @@ main (int argc, char *argv[])
|
|||||||
{ 'x', "x11", NULL, 0, "use X11 even when run from a terminal" },
|
{ 'x', "x11", NULL, 0, "use X11 even when run from a terminal" },
|
||||||
#endif // WITH_X11
|
#endif // WITH_X11
|
||||||
{ 'h', "help", NULL, 0, "display this help and exit" },
|
{ 'h', "help", NULL, 0, "display this help and exit" },
|
||||||
|
{ 'v', "verbose", NULL, 0, "log messages on standard error" },
|
||||||
{ 'V', "version", NULL, 0, "output version information and exit" },
|
{ 'V', "version", NULL, 0, "output version information and exit" },
|
||||||
{ 0, NULL, NULL, 0, NULL }
|
{ 0, NULL, NULL, 0, NULL }
|
||||||
};
|
};
|
||||||
@ -6449,15 +6496,18 @@ main (int argc, char *argv[])
|
|||||||
case 'd':
|
case 'd':
|
||||||
g_debug_mode = true;
|
g_debug_mode = true;
|
||||||
break;
|
break;
|
||||||
|
case 'x':
|
||||||
|
requested_x11 = true;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
g_verbose_mode = true;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
opt_handler_usage (&oh, stdout);
|
opt_handler_usage (&oh, stdout);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'V':
|
case 'V':
|
||||||
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'x':
|
|
||||||
requested_x11 = true;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
print_error ("wrong options");
|
print_error ("wrong options");
|
||||||
opt_handler_usage (&oh, stderr);
|
opt_handler_usage (&oh, stderr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user