#include <xterm.h>
#include <X11/Xatom.h>
#if defined(HAVE_LIB_XAW)
#include <X11/Xaw/Scrollbar.h>
#elif defined(HAVE_LIB_XAW3D)
#include <X11/Xaw3d/Scrollbar.h>
#elif defined(HAVE_LIB_NEXTAW)
#include <X11/neXtaw/Scrollbar.h>
#elif defined(HAVE_LIB_XAWPLUS)
#include <X11/XawPlus/Scrollbar.h>
#endif
#include <data.h>
#include <error.h>
#include <menu.h>
#include <xcharmouse.h>
static void ScrollTextTo PROTO_XT_CALLBACK_ARGS;
static void ScrollTextUpDownBy PROTO_XT_CALLBACK_ARGS;
static void
ResizeScreen(XtermWidget xw, int min_width, int min_height)
{
TScreen *screen = &xw->screen;
#ifndef nothack
XSizeHints sizehints;
long supp;
#endif
XtGeometryResult geomreqresult;
Dimension reqWidth, reqHeight, repWidth, repHeight;
#ifndef NO_ACTIVE_ICON
struct _vtwin *saveWin = screen->whichVwin;
screen->whichVwin = &screen->fullVwin;
#endif
TRACE(("ResizeScreen(min_width=%d, min_height=%d) xw=%#lx\n",
min_width, min_height, (long) xw));
#ifndef nothack
if (!XGetWMNormalHints(screen->display, XtWindow(XtParent(xw)),
&sizehints, &supp))
bzero(&sizehints, sizeof(sizehints));
sizehints.base_width = min_width;
sizehints.base_height = min_height;
sizehints.width_inc = FontWidth(screen);
sizehints.height_inc = FontHeight(screen);
sizehints.min_width = sizehints.base_width + sizehints.width_inc;
sizehints.min_height = sizehints.base_height + sizehints.height_inc;
sizehints.flags |= (PBaseSize | PMinSize | PResizeInc);
sizehints.width = (screen->max_col + 1) * FontWidth(screen)
+ min_width;
sizehints.height = (screen->max_row + 1) * FontHeight(screen)
+ min_height;
#endif
XtVaSetValues(XtParent(xw),
XtNbaseWidth, min_width,
XtNbaseHeight, min_height,
XtNwidthInc, FontWidth(screen),
XtNheightInc, FontHeight(screen),
XtNminWidth, min_width + FontWidth(screen),
XtNminHeight, min_height + FontHeight(screen),
(XtPointer) 0);
reqWidth = screen->fullVwin.f_width * (screen->max_col + 1) + min_width;
reqHeight = screen->fullVwin.f_height * (screen->max_row + 1) + min_height;
TRACE(("...requesting screensize chars %dx%d, pixels %dx%d\n",
(screen->max_row + 1),
(screen->max_col + 1),
reqHeight, reqWidth));
geomreqresult = XtMakeResizeRequest((Widget) xw, reqWidth, reqHeight,
&repWidth, &repHeight);
if (geomreqresult == XtGeometryAlmost) {
TRACE(("...almost, retry screensize %dx%d\n", repHeight, repWidth));
geomreqresult = XtMakeResizeRequest((Widget) xw, repWidth,
repHeight, NULL, NULL);
}
XSync(screen->display, FALSE);
if (XtAppPending(app_con))
xevents();
#ifndef nothack
XSetWMNormalHints(screen->display, XtWindow(XtParent(xw)), &sizehints);
#endif
#ifndef NO_ACTIVE_ICON
screen->whichVwin = saveWin;
#endif
}
void
DoResizeScreen(XtermWidget xw)
{
int border = 2 * xw->screen.border;
ResizeScreen(xw, border + xw->screen.fullVwin.sb_info.width, border);
}
static Widget
CreateScrollBar(XtermWidget xw, int x, int y, int height)
{
Widget scrollWidget;
Arg args[6];
XtSetArg(args[0], XtNx, x);
XtSetArg(args[1], XtNy, y);
XtSetArg(args[2], XtNheight, height);
XtSetArg(args[3], XtNreverseVideo, xw->misc.re_verse);
XtSetArg(args[4], XtNorientation, XtorientVertical);
XtSetArg(args[5], XtNborderWidth, 1);
scrollWidget = XtCreateWidget("scrollbar", scrollbarWidgetClass,
(Widget) xw, args, XtNumber(args));
XtAddCallback(scrollWidget, XtNscrollProc, ScrollTextUpDownBy, 0);
XtAddCallback(scrollWidget, XtNjumpProc, ScrollTextTo, 0);
return (scrollWidget);
}
void
ScrollBarReverseVideo(Widget scrollWidget)
{
SbInfo *sb = &(term->screen.fullVwin.sb_info);
Arg args[4];
Cardinal nargs = XtNumber(args);
if (sb->rv_cached == False) {
XtSetArg(args[0], XtNbackground, &(sb->bg));
XtSetArg(args[1], XtNforeground, &(sb->fg));
XtSetArg(args[2], XtNborderColor, &(sb->bdr));
XtSetArg(args[3], XtNborderPixmap, &(sb->bdpix));
XtGetValues(scrollWidget, args, nargs);
sb->rv_cached = True;
sb->rv_active = 0;
}
sb->rv_active = !(sb->rv_active);
XtSetArg(args[!(sb->rv_active)], XtNbackground, sb->bg);
XtSetArg(args[(sb->rv_active)], XtNforeground, sb->fg);
nargs = 2;
if (sb->bdpix == XtUnspecifiedPixmap) {
if (sb->rv_active) {
XtSetArg(args[2], XtNborderColor, args[1].value);
} else {
XtSetArg(args[2], XtNborderColor, sb->bdr);
}
nargs = 3;
}
XtSetValues(scrollWidget, args, nargs);
}
void
ScrollBarDrawThumb(Widget scrollWidget)
{
TScreen *screen = &term->screen;
int thumbTop, thumbHeight, totalHeight;
thumbTop = screen->topline + screen->savedlines;
thumbHeight = screen->max_row + 1;
totalHeight = thumbHeight + screen->savedlines;
XawScrollbarSetThumb(scrollWidget,
((float) thumbTop) / totalHeight,
((float) thumbHeight) / totalHeight);
}
void
ResizeScrollBar(TScreen * screen)
{
XtConfigureWidget(
screen->scrollWidget,
#ifdef SCROLLBAR_RIGHT
(term->misc.useRight)
? (screen->fullVwin.fullwidth -
screen->scrollWidget->core.width -
screen->scrollWidget->core.border_width)
: -1,
#else
-1,
#endif
-1,
screen->scrollWidget->core.width,
screen->fullVwin.height + screen->border * 2,
screen->scrollWidget->core.border_width);
ScrollBarDrawThumb(screen->scrollWidget);
}
void
WindowScroll(TScreen * screen, int top)
{
int i, lines;
int scrolltop, scrollheight, refreshtop;
int x = 0;
if (top < -screen->savedlines)
top = -screen->savedlines;
else if (top > 0)
top = 0;
if ((i = screen->topline - top) == 0) {
ScrollBarDrawThumb(screen->scrollWidget);
return;
}
if (screen->cursor_state)
HideCursor();
lines = i > 0 ? i : -i;
if (lines > screen->max_row + 1)
lines = screen->max_row + 1;
scrollheight = screen->max_row - lines + 1;
if (i > 0)
refreshtop = scrolltop = 0;
else {
scrolltop = lines;
refreshtop = scrollheight;
}
x = OriginX(screen);
scrolling_copy_area(screen, scrolltop, scrollheight, -i);
screen->topline = top;
ScrollSelection(screen, i);
XClearArea(
screen->display,
VWindow(screen),
(int) x,
(int) refreshtop * FontHeight(screen) + screen->border,
(unsigned) Width(screen),
(unsigned) lines * FontHeight(screen),
FALSE);
ScrnRefresh(screen, refreshtop, 0, lines, screen->max_col + 1, False);
ScrollBarDrawThumb(screen->scrollWidget);
}
void
ScrollBarOn(XtermWidget xw, int init, int doalloc)
{
TScreen *screen = &xw->screen;
int i, j, k;
if (screen->fullVwin.sb_info.width)
return;
if (init) {
if (screen->scrollWidget)
return;
if ((screen->scrollWidget = CreateScrollBar(xw, -1, -1, 5))
== NULL) {
Bell(XkbBI_MinorError, 0);
return;
}
return;
}
if (!screen->scrollWidget) {
Bell(XkbBI_MinorError, 0);
Bell(XkbBI_MinorError, 0);
return;
}
if (doalloc && screen->allbuf) {
if ((screen->allbuf =
(ScrnBuf) realloc((char *) screen->visbuf,
(unsigned) MAX_PTRS * (screen->max_row + 2 +
screen->savelines) *
sizeof(char *)))
== NULL)
SysError(ERROR_SBRALLOC);
screen->visbuf = &screen->allbuf[MAX_PTRS * screen->savelines];
memmove((char *) screen->visbuf, (char *) screen->allbuf,
MAX_PTRS * (screen->max_row + 2) * sizeof(char *));
for (i = k = 0; i < screen->savelines; i++) {
k += BUF_HEAD;
for (j = BUF_HEAD; j < MAX_PTRS; j++) {
if ((screen->allbuf[k++] =
(Char *) calloc((unsigned) screen->max_col + 1,
sizeof(Char))
) == NULL)
SysError(ERROR_SBRALLOC2);
}
}
}
ResizeScrollBar(screen);
xtermAddInput(screen->scrollWidget);
XtRealizeWidget(screen->scrollWidget);
TRACE_TRANS("scrollbar", screen->scrollWidget);
screen->fullVwin.sb_info.rv_cached = False;
screen->fullVwin.sb_info.width = screen->scrollWidget->core.width +
screen->scrollWidget->core.border_width;
ScrollBarDrawThumb(screen->scrollWidget);
DoResizeScreen(xw);
#ifdef SCROLLBAR_RIGHT
if (term->misc.useRight
&& screen->fullVwin.fullwidth < term->core.width)
XtVaSetValues(screen->scrollWidget,
XtNx, screen->fullVwin.fullwidth - screen->scrollWidget->core.border_width,
(XtPointer) 0);
#endif
XtMapWidget(screen->scrollWidget);
update_scrollbar();
if (screen->visbuf) {
XClearWindow(screen->display, XtWindow(term));
Redraw();
}
}
void
ScrollBarOff(TScreen * screen)
{
if (!screen->fullVwin.sb_info.width)
return;
XtUnmapWidget(screen->scrollWidget);
screen->fullVwin.sb_info.width = 0;
DoResizeScreen(term);
update_scrollbar();
if (screen->visbuf) {
XClearWindow(screen->display, XtWindow(term));
Redraw();
}
}
void
ToggleScrollBar(XtermWidget w)
{
TScreen *screen = &w->screen;
if (screen->fullVwin.sb_info.width) {
ScrollBarOff(screen);
} else {
ScrollBarOn(w, FALSE, FALSE);
}
update_scrollbar();
}
static void
ScrollTextTo(
Widget scrollbarWidget GCC_UNUSED,
XtPointer client_data GCC_UNUSED,
XtPointer call_data)
{
float *topPercent = (float *) call_data;
TScreen *screen = &term->screen;
int thumbTop;
int newTopLine;
thumbTop = (int) (*topPercent * (screen->savedlines + screen->max_row + 1));
newTopLine = thumbTop - screen->savedlines;
WindowScroll(screen, newTopLine);
}
static void
ScrollTextUpDownBy(
Widget scrollbarWidget GCC_UNUSED,
XtPointer client_data GCC_UNUSED,
XtPointer call_data)
{
long pixels = (long) call_data;
TScreen *screen = &term->screen;
int rowOnScreen, newTopLine;
rowOnScreen = pixels / FontHeight(screen);
if (rowOnScreen == 0) {
if (pixels < 0)
rowOnScreen = -1;
else if (pixels > 0)
rowOnScreen = 1;
}
newTopLine = screen->topline + rowOnScreen;
WindowScroll(screen, newTopLine);
}
static int
specialcmplowerwiths(char *a, char *b, int *modifier)
{
char ca, cb;
*modifier = 0;
if (!a || !b)
return 0;
while (1) {
ca = char2lower(*a);
cb = *b;
if (ca != cb || ca == '\0')
break;
a++, b++;
}
if (cb != '\0')
return 0;
if (ca == 's')
ca = *++a;
switch (ca) {
case '+':
case '-':
*modifier = (ca == '-' ? -1 : 1) * atoi(a + 1);
return 1;
case '\0':
return 1;
default:
return 0;
}
}
static long
params_to_pixels(TScreen * screen, String * params, Cardinal n)
{
int mult = 1;
char *s;
int modifier;
switch (n > 2 ? 2 : n) {
case 2:
s = params[1];
if (specialcmplowerwiths(s, "page", &modifier)) {
mult = (screen->max_row + 1 + modifier) * FontHeight(screen);
} else if (specialcmplowerwiths(s, "halfpage", &modifier)) {
mult = ((screen->max_row + 1 + modifier) * FontHeight(screen)) / 2;
} else if (specialcmplowerwiths(s, "pixel", &modifier)) {
mult = 1;
} else {
mult = FontHeight(screen);
}
mult *= atoi(params[0]);
break;
case 1:
mult = atoi(params[0]) * FontHeight(screen);
break;
default:
mult = screen->scrolllines * FontHeight(screen);
break;
}
return mult;
}
static long
AmountToScroll(Widget gw, String * params, Cardinal nparams)
{
if (gw != 0) {
if (IsXtermWidget(gw)) {
TScreen *screen = &((XtermWidget) gw)->screen;
if (nparams > 2
&& screen->send_mouse_pos != MOUSE_OFF)
return 0;
return params_to_pixels(screen, params, nparams);
} else {
return AmountToScroll(XtParent(gw), params, nparams);
}
}
return 0;
}
void
HandleScrollForward(
Widget gw,
XEvent * event GCC_UNUSED,
String * params,
Cardinal * nparams)
{
long amount;
if ((amount = AmountToScroll(gw, params, *nparams)) != 0) {
ScrollTextUpDownBy(gw, (XtPointer) 0, (XtPointer) amount);
}
}
void
HandleScrollBack(
Widget gw,
XEvent * event GCC_UNUSED,
String * params,
Cardinal * nparams)
{
long amount;
if ((amount = -AmountToScroll(gw, params, *nparams)) != 0) {
ScrollTextUpDownBy(gw, (XtPointer) 0, (XtPointer) amount);
}
}