/* scrollbar.c -- Eterm scrollbar module * This file is original work by Michael Jennings and * Tuomo Venalainen . This file, and any other file * bearing this same message or a similar one, is distributed under * the GNU Public License (GPL) as outlined in the COPYING file. * * Copyright (C) 1997-1999, Michael Jennings and Tuomo Venalainen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ static const char cvs_ident[] = "$Id$"; #include "config.h" #include "feature.h" #include #include "../libmej/debug.h" #include "../libmej/mem.h" #include "command.h" #include "e.h" #include "events.h" #include "startup.h" #include "options.h" #ifdef PIXMAP_SCROLLBAR # include "pixmap.h" #endif #include "screen.h" #include "scrollbar.h" #include "term.h" #include "windows.h" event_dispatcher_data_t scrollbar_event_data; #ifdef PIXMAP_SCROLLBAR scrollbar_t scrollBar = {0, 1, 0, 1, 0, SCROLLBAR_DEFAULT_TYPE, 0, 0, SB_WIDTH, 0, 0, 0, 0, 0, 0, 0, None, None, None, None}; #else scrollbar_t scrollBar = {0, 1, 0, 1, 0, SCROLLBAR_DEFAULT_TYPE, 0, 0, SB_WIDTH, 0, 0, 0, 0, 0, 0, 0, None}; #endif #ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING short scroll_arrow_delay; #endif static GC scrollbarGC; static short last_top = 0, last_bot = 0; /* old (drawn) values */ #ifdef XTERM_SCROLLBAR /* bitmap scrollbar */ static GC shadowGC; static unsigned char xterm_sb_bits[] = {0xaa, 0x0a, 0x55, 0x05}; /* 12x2 bitmap */ #endif #if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR) static GC topShadowGC, botShadowGC; /* draw triangular up button with a shadow of SHADOW (1 or 2) pixels */ void Draw_up_button(int x, int y, int state) { const unsigned int sz = (scrollBar.width), sz2 = (scrollBar.width / 2); XPoint pt[3]; GC top = None, bot = None; D_SCROLLBAR(("Draw_up_button(%d, %d, %d)\n", x, y, state)); switch (state) { case +1: top = topShadowGC; bot = botShadowGC; break; case -1: top = botShadowGC; bot = topShadowGC; break; case 0: default: top = bot = scrollbarGC; break; } /* fill triangle */ pt[0].x = x; pt[0].y = y + sz - 1; pt[1].x = x + sz - 1; pt[1].y = y + sz - 1; pt[2].x = x + sz2; pt[2].y = y; XFillPolygon(Xdisplay, scrollBar.win, scrollbarGC, pt, 3, Convex, CoordModeOrigin); /* draw base */ XDrawLine(Xdisplay, scrollBar.win, bot, pt[0].x, pt[0].y, pt[1].x, pt[1].y); /* draw shadow */ pt[1].x = x + sz2 - 1; pt[1].y = y; XDrawLine(Xdisplay, scrollBar.win, top, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # if (SHADOW > 1) /* doubled */ pt[0].x++; pt[0].y--; pt[1].y++; XDrawLine(Xdisplay, scrollBar.win, top, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # endif /* draw shadow */ pt[0].x = x + sz2; pt[0].y = y; pt[1].x = x + sz - 1; pt[1].y = y + sz - 1; XDrawLine(Xdisplay, scrollBar.win, bot, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # if (SHADOW > 1) /* doubled */ pt[0].y++; pt[1].x--; pt[1].y--; XDrawLine(Xdisplay, scrollBar.win, bot, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # endif } /* draw triangular down button with a shadow of SHADOW (1 or 2) pixels */ void Draw_dn_button(int x, int y, int state) { const unsigned int sz = (scrollBar.width), sz2 = (scrollBar.width / 2); XPoint pt[3]; GC top = None, bot = None; D_SCROLLBAR(("Draw_dn_button(%d, %d, %d)\n", x, y, state)); switch (state) { case +1: top = topShadowGC; bot = botShadowGC; break; case -1: top = botShadowGC; bot = topShadowGC; break; case 0: default: top = bot = scrollbarGC; break; } /* fill triangle */ pt[0].x = x; pt[0].y = y; pt[1].x = x + sz - 1; pt[1].y = y; pt[2].x = x + sz2; pt[2].y = y + sz; XFillPolygon(Xdisplay, scrollBar.win, scrollbarGC, pt, 3, Convex, CoordModeOrigin); /* draw base */ XDrawLine(Xdisplay, scrollBar.win, top, pt[0].x, pt[0].y, pt[1].x, pt[1].y); /* draw shadow */ pt[1].x = x + sz2 - 1; pt[1].y = y + sz - 1; XDrawLine(Xdisplay, scrollBar.win, top, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # if (SHADOW > 1) /* doubled */ pt[0].x++; pt[0].y++; pt[1].y--; XDrawLine(Xdisplay, scrollBar.win, top, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # endif /* draw shadow */ pt[0].x = x + sz2; pt[0].y = y + sz - 1; pt[1].x = x + sz - 1; pt[1].y = y; XDrawLine(Xdisplay, scrollBar.win, bot, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # if (SHADOW > 1) /* doubled */ pt[0].y--; pt[1].x--; pt[1].y++; XDrawLine(Xdisplay, scrollBar.win, bot, pt[0].x, pt[0].y, pt[1].x, pt[1].y); # endif } #endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */ void scrollbar_init(void) { Cursor cursor; long mask; Attributes.background_pixel = PixColors[scrollColor]; Attributes.border_pixel = PixColors[bgColor]; Attributes.override_redirect = TRUE; Attributes.save_under = TRUE; cursor = XCreateFontCursor(Xdisplay, XC_left_ptr); mask = ExposureMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | Button1MotionMask | Button2MotionMask | Button3MotionMask; scrollBar.win = XCreateWindow(Xdisplay, TermWin.parent, 0, 0, 1, 1, 0, Xdepth, InputOutput, CopyFromParent, CWOverrideRedirect | CWBackingStore | CWBackPixel | CWBorderPixel | CWColormap, &Attributes); XDefineCursor(Xdisplay, scrollBar.win, cursor); XSelectInput(Xdisplay, scrollBar.win, mask); #ifdef PIXMAP_SCROLLBAR if (scrollbar_uparrow_is_pixmapped()) { scrollBar.up_win = XCreateWindow(Xdisplay, scrollBar.win, 0, 0, 1, 1, 0, Xdepth, InputOutput, CopyFromParent, CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWColormap, &Attributes); XSelectInput(Xdisplay, scrollBar.up_win, mask); } if (scrollbar_downarrow_is_pixmapped()) { scrollBar.dn_win = XCreateWindow(Xdisplay, scrollBar.win, 0, 0, 1, 1, 0, Xdepth, InputOutput, CopyFromParent, CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWColormap, &Attributes); XSelectInput(Xdisplay, scrollBar.dn_win, mask); } if (scrollbar_anchor_is_pixmapped()) { scrollBar.sa_win = XCreateWindow(Xdisplay, scrollBar.win, 0, 0, 1, 1, 0, Xdepth, InputOutput, CopyFromParent, CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWColormap, &Attributes); XSelectInput(Xdisplay, scrollBar.sa_win, mask); } #endif event_register_dispatcher(scrollbar_dispatch_event, scrollbar_event_init_dispatcher); } void scrollbar_event_init_dispatcher(void) { MEMSET(&scrollbar_event_data, 0, sizeof(event_dispatcher_data_t)); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, ConfigureNotify, sb_handle_configure_notify); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, EnterNotify, sb_handle_enter_notify); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, LeaveNotify, sb_handle_leave_notify); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, FocusIn, sb_handle_focus_in); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, FocusOut, sb_handle_focus_out); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, GraphicsExpose, sb_handle_expose); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, Expose, sb_handle_expose); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, ButtonPress, sb_handle_button_press); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, ButtonRelease, sb_handle_button_release); EVENT_DATA_ADD_HANDLER(scrollbar_event_data, MotionNotify, sb_handle_motion_notify); event_data_add_mywin(&scrollbar_event_data, scrollBar.win); #ifdef PIXMAP_SCROLLBAR if (scrollbar_is_pixmapped()) { event_data_add_mywin(&scrollbar_event_data, scrollBar.up_win); event_data_add_mywin(&scrollbar_event_data, scrollBar.dn_win); event_data_add_mywin(&scrollbar_event_data, scrollBar.sa_win); } #endif event_data_add_parent(&scrollbar_event_data, TermWin.vt); event_data_add_parent(&scrollbar_event_data, TermWin.parent); } unsigned char sb_handle_configure_notify(event_t * ev) { D_EVENTS(("sb_handle_configure_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_PARENT(ev, &scrollbar_event_data), 0); redraw_image(image_sb); return 0; } unsigned char sb_handle_enter_notify(event_t * ev) { D_EVENTS(("sb_handle_enter_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); if (scrollbar_uparrow_is_pixmapped() && scrollbar_win_is_uparrow(ev->xany.window)) { images[image_up].current = images[image_up].selected; render_simage(images[image_up].current, scrollbar_get_uparrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0); } if (scrollbar_downarrow_is_pixmapped() && scrollbar_win_is_downarrow(ev->xany.window)) { images[image_down].current = images[image_down].selected; render_simage(images[image_down].current, scrollbar_get_downarrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0); } if (scrollbar_anchor_is_pixmapped() && scrollbar_win_is_anchor(ev->xany.window)) { images[image_sa].current = images[image_sa].selected; render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } if (scrollbar_is_pixmapped() && scrollbar_win_is_scrollbar(ev->xany.window)) { images[image_sb].current = images[image_sb].selected; render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } return 0; } unsigned char sb_handle_leave_notify(event_t * ev) { D_EVENTS(("sb_handle_leave_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); if (scrollbar_uparrow_is_pixmapped() && scrollbar_win_is_uparrow(ev->xany.window)) { images[image_up].current = images[image_up].norm; render_simage(images[image_up].current, scrollbar_get_uparrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0); } if (scrollbar_downarrow_is_pixmapped() && scrollbar_win_is_downarrow(ev->xany.window)) { images[image_down].current = images[image_down].norm; render_simage(images[image_down].current, scrollbar_get_downarrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0); } if (scrollbar_anchor_is_pixmapped() && scrollbar_win_is_anchor(ev->xany.window)) { images[image_sa].current = images[image_sa].norm; render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } if (scrollbar_is_pixmapped() && scrollbar_win_is_scrollbar(ev->xany.window)) { images[image_sb].current = images[image_sb].norm; render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } return 0; } unsigned char sb_handle_focus_in(event_t * ev) { D_EVENTS(("sb_handle_focus_in(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); return 0; } unsigned char sb_handle_focus_out(event_t * ev) { D_EVENTS(("sb_handle_focus_out(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); return 0; } unsigned char sb_handle_expose(event_t * ev) { XEvent unused_xevent; D_EVENTS(("sb_handle_expose(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, Expose, &unused_xevent)); while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, GraphicsExpose, &unused_xevent)); if (scrollbar_win_is_scrollbar(ev->xany.window)) { scrollbar_show(0); } return 0; } unsigned char sb_handle_button_press(event_t * ev) { D_EVENTS(("sb_handle_button_press(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); button_state.bypass_keystate = (ev->xbutton.state & (Mod1Mask | ShiftMask)); button_state.report_mode = (button_state.bypass_keystate ? 0 : ((PrivateModes & PrivMode_mouse_report) ? 1 : 0)); scrollbar_setNone(); #ifndef NO_SCROLLBAR_REPORT if (button_state.report_mode) { /* Mouse report disabled scrollbar. Arrows send cursor key up/down, trough sends pageup/pagedown */ if (scrollbar_upButton(ev->xany.window, ev->xbutton.y)) tt_printf((unsigned char *) "\033[A"); else if (scrollbar_dnButton(ev->xany.window, ev->xbutton.y)) tt_printf((unsigned char *) "\033[B"); else switch (ev->xbutton.button) { case Button2: tt_printf((unsigned char *) "\014"); break; case Button1: tt_printf((unsigned char *) "\033[6~"); break; case Button3: tt_printf((unsigned char *) "\033[5~"); break; } } else #endif /* NO_SCROLLBAR_REPORT */ { D_EVENTS(("ButtonPress event for window 0x%08x at %d, %d\n", ev->xany.window, ev->xbutton.x, ev->xbutton.y)); D_EVENTS((" up [0x%08x], down [0x%08x], anchor [0x%08x], trough [0x%08x]\n", scrollBar.up_win, scrollBar.dn_win, scrollBar.sa_win, scrollBar.win)); if (scrollbar_upButton(ev->xany.window, ev->xbutton.y)) { if (scrollbar_uparrow_is_pixmapped() && images[image_up].current != images[image_up].clicked) { images[image_up].current = images[image_up].clicked; render_simage(images[image_up].current, scrollbar_get_uparrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0); } #ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY; #endif if (scr_page(UP, 1)) { scrollbar_setUp(); } } else if (scrollbar_dnButton(ev->xany.window, ev->xbutton.y)) { if (scrollbar_downarrow_is_pixmapped() && images[image_down].current != images[image_down].clicked) { images[image_down].current = images[image_down].clicked; render_simage(images[image_down].current, scrollbar_get_downarrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0); } #ifdef SCROLLBAR_BUTTON_CONTINUAL_SCROLLING scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY; #endif if (scr_page(DN, 1)) { scrollbar_setDn(); } } else { if (scrollbar_anchor_is_pixmapped() && images[image_sa].current != images[image_sa].clicked) { images[image_sa].current = images[image_sa].clicked; render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } switch (ev->xbutton.button) { case Button2: button_state.mouse_offset = scrollbar_anchor_height() / 2; /* Align to center */ if (scrollbar_is_above_anchor(ev->xany.window, ev->xbutton.y) || scrollbar_is_below_anchor(ev->xany.window, ev->xbutton.y) || scrollBar.type == SCROLLBAR_XTERM) { scr_move_to(scrollbar_position(ev->xbutton.y) - button_state.mouse_offset, scrollbar_scrollarea_height()); } scrollbar_setMotion(); break; case Button1: button_state.mouse_offset = ev->xbutton.y - (scrollbar_anchor_is_pixmapped()? 0 : scrollBar.top); MAX_IT(button_state.mouse_offset, 1); /* drop */ case Button3: #if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR) if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) { if (scrollbar_is_above_anchor(ev->xany.window, ev->xbutton.y)) { if (images[image_sb].current != images[image_sb].clicked) { images[image_sb].current = images[image_sb].clicked; render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } scr_page(UP, TermWin.nrow - 1); } else if (scrollbar_is_below_anchor(ev->xany.window, ev->xbutton.y)) { if (images[image_sb].current != images[image_sb].clicked) { images[image_sb].current = images[image_sb].clicked; render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } scr_page(DN, TermWin.nrow - 1); } else { if (scrollbar_anchor_is_pixmapped() && images[image_sa].current != images[image_sa].clicked) { images[image_sa].current = images[image_sa].clicked; render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } scrollbar_setMotion(); } } #endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */ #ifdef XTERM_SCROLLBAR if (scrollBar.type == SCROLLBAR_XTERM) { scr_page((ev->xbutton.button == Button1 ? DN : UP), (TermWin.nrow * scrollbar_position(ev->xbutton.y) / scrollbar_scrollarea_height())); } #endif /* XTERM_SCROLLBAR */ break; } } } return 1; } unsigned char sb_handle_button_release(event_t * ev) { Window root, child; int root_x, root_y, win_x, win_y; unsigned int mask; D_EVENTS(("sb_handle_button_release(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); button_state.mouse_offset = 0; button_state.report_mode = (button_state.bypass_keystate ? 0 : ((PrivateModes & PrivMode_mouse_report) ? 1 : 0)); #ifdef PIXMAP_SCROLLBAR XQueryPointer(Xdisplay, scrollbar_get_win(), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask); if (scrollbar_uparrow_is_pixmapped()) { if (scrollbar_win_is_uparrow(child)) { images[image_up].current = images[image_up].selected; render_simage(images[image_up].current, scrollbar_get_uparrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0); } else if (images[image_up].current != images[image_up].norm) { images[image_up].current = images[image_up].norm; render_simage(images[image_up].current, scrollbar_get_uparrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0); } } if (scrollbar_downarrow_is_pixmapped()) { if (scrollbar_win_is_downarrow(child)) { images[image_down].current = images[image_down].selected; render_simage(images[image_down].current, scrollbar_get_downarrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0); } else if (images[image_down].current != images[image_down].norm) { images[image_down].current = images[image_down].norm; render_simage(images[image_down].current, scrollbar_get_downarrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0); } } if (scrollbar_anchor_is_pixmapped()) { if (scrollbar_win_is_anchor(child)) { images[image_sa].current = images[image_sa].selected; render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } else if (images[image_sa].current != images[image_sa].norm) { images[image_sa].current = images[image_sa].norm; render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } } if (scrollbar_is_pixmapped()) { if (scrollbar_win_is_scrollbar(child)) { images[image_sb].current = images[image_sb].selected; render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } else if (images[image_sb].current != images[image_sb].norm) { images[image_sb].current = images[image_sb].norm; render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } } #endif if (scrollbar_isUpDn()) { scrollbar_setNone(); scrollbar_show(0); } return 1; } unsigned char sb_handle_motion_notify(event_t * ev) { D_EVENTS(("sb_handle_motion_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window)); REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &scrollbar_event_data), 0); if ((PrivateModes & PrivMode_mouse_report) && !(button_state.bypass_keystate)) return 1; D_EVENTS(("MotionNotify event for window 0x%08x\n", ev->xany.window)); D_EVENTS((" up [0x%08x], down [0x%08x], anchor [0x%08x], trough [0x%08x]\n", scrollBar.up_win, scrollBar.dn_win, scrollBar.sa_win, scrollBar.win)); if ((scrollbar_win_is_scrollbar(ev->xany.window) #ifdef PIXMAP_SCROLLBAR || (scrollbar_anchor_is_pixmapped() && scrollbar_win_is_anchor(ev->xany.window)) #endif ) && scrollbar_isMotion()) { Window unused_root, unused_child; int unused_root_x, unused_root_y; unsigned int unused_mask; while (XCheckTypedWindowEvent(Xdisplay, scrollBar.win, MotionNotify, ev)); XQueryPointer(Xdisplay, scrollBar.win, &unused_root, &unused_child, &unused_root_x, &unused_root_y, &(ev->xbutton.x), &(ev->xbutton.y), &unused_mask); scr_move_to(scrollbar_position(ev->xbutton.y) - button_state.mouse_offset, scrollbar_scrollarea_height()); refresh_count = refresh_limit = 0; scr_refresh(refresh_type); scrollbar_show(button_state.mouse_offset); } return 1; } unsigned char scrollbar_dispatch_event(event_t * ev) { if (scrollbar_event_data.handlers[ev->type] != NULL) { return ((scrollbar_event_data.handlers[ev->type]) (ev)); } return (0); } unsigned char scrollbar_mapping(unsigned char show) { unsigned char change = 0; D_SCROLLBAR(("scrollbar_mapping(%d)\n", show)); if (show && !scrollbar_visible()) { scrollBar.state = 1; XMapWindow(Xdisplay, scrollBar.win); #ifdef PIXMAP_SCROLLBAR if (scrollbar_uparrow_is_pixmapped()) { XMapWindow(Xdisplay, scrollBar.up_win); } if (scrollbar_downarrow_is_pixmapped()) { XMapWindow(Xdisplay, scrollBar.dn_win); } if (scrollbar_anchor_is_pixmapped()) { XMapWindow(Xdisplay, scrollBar.sa_win); } #endif change = 1; } else if (!show && scrollbar_visible()) { scrollBar.state = 0; #ifdef PIXMAP_SCROLLBAR if (scrollbar_uparrow_is_pixmapped()) { XUnmapWindow(Xdisplay, scrollBar.up_win); } if (scrollbar_downarrow_is_pixmapped()) { XUnmapWindow(Xdisplay, scrollBar.dn_win); } if (scrollbar_anchor_is_pixmapped()) { XUnmapWindow(Xdisplay, scrollBar.sa_win); } #endif XUnmapWindow(Xdisplay, scrollBar.win); change = 1; } return change; } void scrollbar_reset(void) { if (scrollbarGC != None) { XFreeGC(Xdisplay, scrollbarGC); scrollbarGC = None; } #if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR) if (topShadowGC != None) { XFreeGC(Xdisplay, topShadowGC); topShadowGC = None; } if (botShadowGC != None) { XFreeGC(Xdisplay, botShadowGC); botShadowGC = None; } #endif #ifdef XTERM_SCROLLBAR if (shadowGC != None) { XFreeGC(Xdisplay, shadowGC); shadowGC = None; } #endif last_top = last_bot = 0; if (scrollBar.type == SCROLLBAR_XTERM) { scrollbar_set_shadow(0); } else { scrollbar_set_shadow((Options & Opt_scrollBar_floating) ? 0 : SHADOW); } scrollBar.init = 0; } void scrollbar_resize(int width, int height) { if (!scrollbar_visible()) { return; } D_SCROLLBAR(("scrollbar_resize(%d, %d)\n", width, height)); scrollBar.beg = 0; scrollBar.end = height; #ifdef MOTIF_SCROLLBAR if (scrollBar.type == SCROLLBAR_MOTIF) { /* arrows are as high as wide - leave 1 pixel gap */ scrollBar.beg += scrollbar_arrow_height() + scrollbar_get_shadow() + 1; scrollBar.end -= scrollbar_arrow_height() + scrollbar_get_shadow() + 1; } #endif #ifdef NEXT_SCROLLBAR if (scrollBar.type == SCROLLBAR_NEXT) { scrollBar.beg = scrollbar_get_shadow(); scrollBar.end -= (scrollBar.width * 2 + (scrollbar_get_shadow() ? scrollbar_get_shadow() : 1) + 2); } #endif width -= scrollbar_trough_width(); XMoveResizeWindow(Xdisplay, scrollBar.win, ((Options & Opt_scrollBar_right) ? (width) : (0)), 0, scrollbar_trough_width(), height); scrollBar.init = 0; scrollbar_show(0); } unsigned char scrollbar_show(short mouseoffset) { unsigned char xsb = 0, force_update = 0; static int focus = -1; if (!scrollbar_visible()) { return 0; } D_SCROLLBAR(("scrollbar_show(%d)\n", mouseoffset)); if (scrollbarGC == None) { XGCValues gcvalue; #ifdef XTERM_SCROLLBAR if (scrollBar.type == SCROLLBAR_XTERM) { gcvalue.stipple = XCreateBitmapFromData(Xdisplay, scrollBar.win, (char *) xterm_sb_bits, 12, 2); if (!gcvalue.stipple) { print_error("Unable to create xterm scrollbar bitmap. Reverting to default scrollbar."); scrollBar.type = SCROLLBAR_MOTIF; } else { gcvalue.fill_style = FillOpaqueStippled; gcvalue.foreground = PixColors[fgColor]; gcvalue.background = PixColors[bgColor]; scrollbarGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground | GCBackground | GCFillStyle | GCStipple, &gcvalue); gcvalue.foreground = PixColors[borderColor]; shadowGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground, &gcvalue); } } #endif /* XTERM_SCROLLBAR */ #if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR) if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) { gcvalue.foreground = (Xdepth <= 2 ? PixColors[fgColor] : PixColors[scrollColor]); scrollbarGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground, &gcvalue); if ((Options & Opt_scrollBar_floating) && !scrollbar_is_pixmapped() && !background_is_pixmap()) { XSetWindowBackground(Xdisplay, scrollBar.win, PixColors[bgColor]); } else { render_simage(images[image_sb].current, scrollBar.win, scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); if (image_mode_is(image_sb, MODE_AUTO)) { enl_ipc_sync(); XClearWindow(Xdisplay, scrollBar.win); } } gcvalue.foreground = PixColors[topShadowColor]; topShadowGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground, &gcvalue); gcvalue.foreground = PixColors[bottomShadowColor]; botShadowGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground, &gcvalue); } #endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */ } #if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR) else if (image_mode_is(image_sb, (MODE_TRANS | MODE_VIEWPORT))) { render_simage(images[image_sb].current, scrollBar.win, scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0); } if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) { if (focus != TermWin.focus) { XGCValues gcvalue; focus = TermWin.focus; gcvalue.foreground = PixColors[focus ? scrollColor : unfocusedScrollColor]; XChangeGC(Xdisplay, scrollbarGC, GCForeground, &gcvalue); gcvalue.foreground = PixColors[focus ? topShadowColor : unfocusedTopShadowColor]; XChangeGC(Xdisplay, topShadowGC, GCForeground, &gcvalue); gcvalue.foreground = PixColors[focus ? bottomShadowColor : unfocusedBottomShadowColor]; XChangeGC(Xdisplay, botShadowGC, GCForeground, &gcvalue); force_update = 1; } } #endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */ if (mouseoffset) { int top = (TermWin.nscrolled - TermWin.view_start); int bot = top + (TermWin.nrow - 1); int len = max((TermWin.nscrolled + (TermWin.nrow - 1)), 1); scrollBar.top = (scrollBar.beg + (top * scrollbar_scrollarea_height()) / len); scrollBar.bot = (scrollBar.beg + (bot * scrollbar_scrollarea_height()) / len); if (rs_min_anchor_size && scrollBar.type != SCROLLBAR_XTERM) { if ((scrollbar_scrollarea_height() > rs_min_anchor_size) && (scrollbar_anchor_height() < rs_min_anchor_size)) { int grab_point = scrollBar.top + mouseoffset; if (grab_point - mouseoffset < scrollBar.beg) { scrollBar.top = scrollBar.beg; scrollBar.bot = rs_min_anchor_size + scrollBar.beg; } else if (scrollBar.top + rs_min_anchor_size > scrollBar.end) { scrollBar.top = scrollBar.end - rs_min_anchor_size; scrollBar.bot = scrollBar.end; } else { scrollBar.top = grab_point - mouseoffset; scrollBar.bot = scrollBar.top + rs_min_anchor_size; } if (scrollBar.bot == scrollBar.end) { scr_move_to(scrollBar.end, scrollbar_scrollarea_height()); scr_refresh(DEFAULT_REFRESH); } } } /* no change */ if (!force_update && (scrollBar.top == last_top) && (scrollBar.bot == last_bot)) return 0; } #ifdef XTERM_SCROLLBAR xsb = ((scrollBar.type == SCROLLBAR_XTERM) && (Options & Opt_scrollBar_right)) ? 1 : 0; #endif if (last_top < scrollBar.top) { XClearArea(Xdisplay, scrollBar.win, scrollbar_get_shadow() + xsb, last_top, scrollBar.width, (scrollBar.top - last_top), False); } if (scrollBar.bot < last_bot) { XClearArea(Xdisplay, scrollBar.win, scrollbar_get_shadow() + xsb, scrollBar.bot, scrollBar.width, (last_bot - scrollBar.bot), False); } #ifdef PIXMAP_SCROLLBAR if (scrollbar_anchor_is_pixmapped()) { if ((last_top != scrollBar.top) || (scrollBar.bot != last_bot)) { XMoveResizeWindow(Xdisplay, scrollBar.sa_win, scrollbar_get_shadow(), scrollBar.top, scrollBar.width, scrollbar_anchor_height()); } render_simage(images[image_sa].current, scrollBar.sa_win, scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0); } #endif last_top = scrollBar.top; last_bot = scrollBar.bot; /* scrollbar anchor */ #ifdef XTERM_SCROLLBAR if (scrollBar.type == SCROLLBAR_XTERM) { XFillRectangle(Xdisplay, scrollBar.win, scrollbarGC, xsb + 1, scrollBar.top, scrollBar.width - 2, scrollbar_anchor_height()); XDrawLine(Xdisplay, scrollBar.win, shadowGC, xsb ? 0 : scrollBar.width, scrollBar.beg, xsb ? 0 : scrollBar.width, scrollBar.end); } #endif /* XTERM_SCROLLBAR */ #if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR) if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) { if (!scrollbar_anchor_is_pixmapped()) { /* Draw the scrollbar anchor in if it's not pixmapped. */ if (scrollbar_is_pixmapped()) { XSetTSOrigin(Xdisplay, scrollbarGC, scrollbar_get_shadow(), scrollBar.top); XFillRectangle(Xdisplay, scrollBar.win, scrollbarGC, scrollbar_get_shadow(), scrollBar.top, scrollBar.width, scrollbar_anchor_height()); XSetTSOrigin(Xdisplay, scrollbarGC, 0, 0); } else { XFillRectangle(Xdisplay, scrollBar.win, scrollbarGC, scrollbar_get_shadow(), scrollBar.top, scrollBar.width, scrollbar_anchor_height()); } } /* Draw trough shadow */ if (scrollbar_get_shadow() && !scrollbar_is_pixmapped()) { Draw_Shadow(scrollBar.win, botShadowGC, topShadowGC, 0, 0, scrollbar_trough_width(), scrollbar_trough_height()); } /* Draw anchor shadow */ if (!scrollbar_anchor_is_pixmapped()) { Draw_Shadow(scrollBar.win, topShadowGC, botShadowGC, scrollbar_get_shadow(), scrollBar.top, scrollBar.width, scrollbar_anchor_height()); } /* Draw scrollbar arrows */ if (scrollbar_uparrow_is_pixmapped()) { if (scrollBar.init == 0) { XMoveResizeWindow(Xdisplay, scrollBar.up_win, scrollbar_get_shadow(), scrollbar_up_loc(), scrollbar_arrow_width(), scrollbar_arrow_height()); render_simage(images[image_up].current, scrollBar.up_win, scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0); } } else { Draw_up_button(scrollbar_get_shadow(), scrollbar_up_loc(), (scrollbar_isUp()? -1 : +1)); } if (scrollbar_downarrow_is_pixmapped()) { if (scrollBar.init == 0) { XMoveResizeWindow(Xdisplay, scrollBar.dn_win, scrollbar_get_shadow(), scrollbar_dn_loc(), scrollbar_arrow_width(), scrollbar_arrow_height()); render_simage(images[image_down].current, scrollBar.dn_win, scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0); } } else { Draw_dn_button(scrollbar_get_shadow(), scrollbar_dn_loc(), (scrollbar_isDn()? -1 : +1)); } } if (image_mode_is(image_up, MODE_AUTO) || image_mode_is(image_down, MODE_AUTO) || image_mode_is(image_sb, MODE_AUTO) || image_mode_is(image_sa, MODE_AUTO)) { enl_ipc_sync(); } #endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */ scrollBar.init = 1; return 1; }