|
|
1.1 ! root 1: #ifndef lint ! 2: static char rcs_id[] = "$Header: screen.c,v 1.14 87/09/11 08:18:29 toddb Exp $"; ! 3: #endif lint ! 4: /* ! 5: * COPYRIGHT 1987 ! 6: * DIGITAL EQUIPMENT CORPORATION ! 7: * MAYNARD, MASSACHUSETTS ! 8: * ALL RIGHTS RESERVED. ! 9: * ! 10: * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND ! 11: * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. ! 12: * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ! 13: * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ! 14: * ! 15: * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS, ! 16: * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT ! 17: * SET FORTH ABOVE. ! 18: * ! 19: * ! 20: * Permission to use, copy, modify, and distribute this software and its ! 21: * documentation for any purpose and without fee is hereby granted, provided ! 22: * that the above copyright notice appear in all copies and that both that ! 23: * copyright notice and this permission notice appear in supporting documentation, ! 24: * and that the name of Digital Equipment Corporation not be used in advertising ! 25: * or publicity pertaining to distribution of the software without specific, ! 26: * written prior permission. ! 27: */ ! 28: ! 29: /* scrn.c -- management of scrns. */ ! 30: ! 31: #include "xmh.h" ! 32: ! 33: static int compscrncount = 0; /* How many comp screens we currently have. */ ! 34: ! 35: /* Handle geometry requests from the scrn. */ ! 36: /*ARGSUSED*/ /* -- keeps lint from complaining. */ ! 37: ! 38: XtGeometryReturnCode ! 39: ScrnGeometryRequest(window, request, requestBox, replyBox) ! 40: Window window; ! 41: XtGeometryRequest request; ! 42: WindowBox *requestBox, *replyBox; ! 43: { ! 44: return XtgeometryNo; ! 45: } ! 46: ! 47: ! 48: ! 49: /* Fill in the buttons for the view commands. */ ! 50: ! 51: static FillViewButtons(scrn) ! 52: Scrn scrn; ! 53: { ! 54: extern void ExecCloseView(), ExecViewReply(), ExecViewForward(); ! 55: extern void ExecViewUseAsComposition(), ExecEditView(); ! 56: extern void ExecSaveView(), ExecPrintView(); ! 57: ButtonBox buttonbox = scrn->viewbuttons; ! 58: BBoxStopUpdate(buttonbox); ! 59: if (scrn->tocwindow == NULL) ! 60: BBoxAddButton(buttonbox, "close", ExecCloseView, 999, TRUE); ! 61: BBoxAddButton(buttonbox, "reply", ExecViewReply, 999, TRUE); ! 62: BBoxAddButton(buttonbox, "forward", ExecViewForward, 999, TRUE); ! 63: BBoxAddButton(buttonbox, "useAsComp", ExecViewUseAsComposition, ! 64: 999, TRUE); ! 65: BBoxAddButton(buttonbox, "edit", ExecEditView, 999, TRUE); ! 66: BBoxAddButton(buttonbox, "save", ExecSaveView, 999, FALSE); ! 67: BBoxAddButton(buttonbox, "print", ExecPrintView, 999, TRUE); ! 68: BBoxStartUpdate(buttonbox); ! 69: BBoxForceFullSize(buttonbox); ! 70: BBoxAllowAnySize(buttonbox); ! 71: } ! 72: ! 73: ! 74: ! 75: static FillCompButtons(scrn) ! 76: Scrn scrn; ! 77: { ! 78: extern void ExecCloseView(); ! 79: extern void ExecCompReset(); ! 80: extern void ExecComposeMessage(); ! 81: extern void ExecSaveDraft(); ! 82: extern void ExecSendDraft(); ! 83: ButtonBox buttonbox = scrn->viewbuttons; ! 84: BBoxStopUpdate(buttonbox); ! 85: if (scrn->tocwindow == NULL) ! 86: BBoxAddButton(buttonbox, "close", ExecCloseView, 999, TRUE); ! 87: BBoxAddButton(buttonbox, "send", ExecSendDraft, 999, TRUE); ! 88: BBoxAddButton(buttonbox, "reset", ExecCompReset, 999, TRUE); ! 89: BBoxAddButton(buttonbox, "compose", ExecComposeMessage, 999, TRUE); ! 90: BBoxAddButton(buttonbox, "save", ExecSaveDraft, 999, TRUE); ! 91: BBoxStartUpdate(buttonbox); ! 92: BBoxForceFullSize(buttonbox); ! 93: BBoxAllowAnySize(buttonbox); ! 94: } ! 95: ! 96: ! 97: /* Figure out which buttons should and shouldn't be enabled in the given ! 98: screen. This should be called whenever something major happens to the ! 99: screen. */ ! 100: ! 101: #define SetButton(buttonbox, name, value) \ ! 102: if (value) BBoxEnable(BBoxFindButtonNamed(buttonbox, name)); \ ! 103: else BBoxDisable(BBoxFindButtonNamed(buttonbox, name)); ! 104: ! 105: void EnableProperButtons(scrn) ! 106: Scrn scrn; ! 107: { ! 108: int value, changed, reapable; ! 109: if (scrn) { ! 110: switch (scrn->kind) { ! 111: case STtocAndView: ! 112: SetButton(scrn->tocbuttons, "inc", TocCanIncorporate(scrn->toc)); ! 113: value = TocHasSequences(scrn->toc); ! 114: SetButton(scrn->tocbuttons, "openSeq", value); ! 115: SetButton(scrn->tocbuttons, "addToSeq", value); ! 116: SetButton(scrn->tocbuttons, "removeFromSeq", value); ! 117: SetButton(scrn->tocbuttons, "deleteSeq", value); ! 118: /* Fall through */ ! 119: ! 120: case STview: ! 121: value = (scrn->msg != NULL && !MsgGetEditable(scrn->msg)); ! 122: SetButton(scrn->viewbuttons, "edit", value); ! 123: SetButton(scrn->viewbuttons, "save", scrn->msg != NULL && !value); ! 124: break; ! 125: ! 126: case STcomp: ! 127: if (scrn->msg != NULL) { ! 128: changed = MsgChanged(scrn->msg); ! 129: reapable = MsgGetReapable(scrn->msg); ! 130: SetButton(scrn->viewbuttons, "send", changed || !reapable); ! 131: SetButton(scrn->viewbuttons, "save", changed || reapable); ! 132: if (!changed) MsgSetCallOnChange(scrn->msg, ! 133: EnableProperButtons, ! 134: (caddr_t) scrn); ! 135: else MsgClearCallOnChange(scrn->msg); ! 136: } else { ! 137: SetButton(scrn->viewbuttons, "send", FALSE); ! 138: SetButton(scrn->viewbuttons, "save", FALSE); ! 139: } ! 140: break; ! 141: } ! 142: } ! 143: } ! 144: ! 145: void PrepareDoubleClickFolder(scrn) ! 146: Scrn scrn; ! 147: { ! 148: extern void ExecOpenFolder(); ! 149: DoubleClickProc = ExecOpenFolder; ! 150: DoubleClickParam = (caddr_t)scrn; ! 151: } ! 152: ! 153: void PrepareDoubleClickSequence(scrn) ! 154: Scrn scrn; ! 155: { ! 156: extern void ExecOpenSeq(); ! 157: DoubleClickProc = ExecOpenSeq; ! 158: DoubleClickParam = (caddr_t)scrn; ! 159: } ! 160: ! 161: /* Create subwindows for a toc&view window. */ ! 162: ! 163: static MakeTocAndView(scrn) ! 164: Scrn scrn; ! 165: { ! 166: extern void ExecCloseScrn(); ! 167: extern void ExecComposeMessage(); ! 168: extern void ExecOpenFolder(); ! 169: extern void ExecOpenFolderInNewWindow(); ! 170: extern void ExecCreateFolder(); ! 171: extern void ExecDeleteFolder(); ! 172: extern XtEventReturnCode HandleTocButtons(); ! 173: extern void ExecIncorporate(); ! 174: extern void ExecNextView(); ! 175: extern void ExecPrevView(); ! 176: extern void ExecMarkDelete(); ! 177: extern void ExecMarkMove(); ! 178: extern void ExecMarkCopy(); ! 179: extern void ExecMarkUnmarked(); ! 180: extern void ExecViewNew(); ! 181: extern void ExecTocReply(); ! 182: extern void ExecTocForward(); ! 183: extern void ExecTocUseAsComposition(); ! 184: extern void ExecCommitChanges(); ! 185: extern void ExecOpenSeq(); ! 186: extern void ExecAddToSeq(); ! 187: extern void ExecRemoveFromSeq(); ! 188: extern void ExecPick(); ! 189: extern void ExecDeleteSeq(); ! 190: extern void ExecPrintMessages(); ! 191: extern void ExecPack(); ! 192: extern void ExecSort(); ! 193: extern void ExecForceRescan(); ! 194: int i, width, height, theight, vheight; ! 195: ButtonBox buttonbox; ! 196: static Arg arglist[] = { ! 197: {XtNtextSink, NULL} ! 198: }; ! 199: static XtSelectType sarray[] = {XtselectLine, ! 200: XtselectPosition, ! 201: XtselectWord, ! 202: XtselectAll, ! 203: XtselectNull}; ! 204: ! 205: ! 206: XtVPanedRefigureMode(DISPLAY scrn->window, FALSE); ! 207: scrn->folderbuttons = BBoxRadioCreate(scrn, 0, "folders", ! 208: &(scrn->curfolder)); ! 209: scrn->mainbuttons = BBoxCreate(scrn, 1, "folderButtons"); ! 210: scrn->toclabel = CreateTitleBar(scrn, 2); ! 211: scrn->tocwindow = CreateTextSW(scrn, 3, "toc", 0); ! 212: scrn->seqbuttons = BBoxRadioCreate(scrn, 4, "seqButtons", &scrn->curseq); ! 213: scrn->tocbuttons = BBoxCreate(scrn, 5, "tocButtons"); ! 214: scrn->viewlabel = CreateTitleBar(scrn, 6); ! 215: scrn->viewwindow = CreateTextSW(scrn, 7, "view", wordBreak); ! 216: scrn->viewbuttons = BBoxCreate(scrn, 8, "viewButtons"); ! 217: ! 218: XtTextGetValues(DISPLAY scrn->tocwindow, arglist, XtNumber(arglist)); ! 219: scrn->tocsink = (XtTextSink *) arglist[0].value; ! 220: ! 221: buttonbox = scrn->folderbuttons; ! 222: BBoxStopUpdate(buttonbox); ! 223: for (i=0 ; i<numFolders ; i++) ! 224: BBoxAddButton(buttonbox, TocGetFolderName(folderList[i]), ! 225: PrepareDoubleClickFolder, 999, TRUE); ! 226: BBoxForceFullSize(buttonbox); ! 227: BBoxStartUpdate(buttonbox); ! 228: ! 229: buttonbox = scrn->mainbuttons; ! 230: BBoxStopUpdate(buttonbox); ! 231: BBoxAddButton(buttonbox, "close", ExecCloseScrn, 999, TRUE); ! 232: BBoxAddButton(buttonbox, "compose", ExecComposeMessage, 999, TRUE); ! 233: BBoxAddButton(buttonbox, "open", ExecOpenFolder, 999, TRUE); ! 234: BBoxAddButton(buttonbox, "openInNew", ExecOpenFolderInNewWindow, ! 235: 999, TRUE); ! 236: BBoxAddButton(buttonbox, "create", ExecCreateFolder, 999, TRUE); ! 237: BBoxAddButton(buttonbox, "delete", ExecDeleteFolder, 999, TRUE); ! 238: BBoxForceFullSize(buttonbox); ! 239: BBoxStartUpdate(buttonbox); ! 240: ! 241: buttonbox = scrn->seqbuttons; ! 242: BBoxStopUpdate(buttonbox); ! 243: BBoxAddButton(buttonbox, "all", PrepareDoubleClickSequence, 999, TRUE); ! 244: BBoxForceFullSize(buttonbox); ! 245: BBoxStartUpdate(buttonbox); ! 246: ! 247: if (defDoubleClick) { ! 248: XtSetEventHandler(theDisplay, ! 249: XtTextGetInnerWindow(theDisplay, scrn->tocwindow), ! 250: HandleTocButtons, ButtonReleaseMask, (caddr_t) scrn); ! 251: sarray[1] = XtselectNull; ! 252: } ! 253: XtTextSetSelectionArray(DISPLAY scrn->tocwindow, (XtSelectType *)sarray); ! 254: ! 255: buttonbox = scrn->tocbuttons; ! 256: BBoxStopUpdate(buttonbox); ! 257: BBoxAddButton(buttonbox, "inc", ExecIncorporate, 999, TRUE); ! 258: BBoxAddButton(buttonbox, "next", ExecNextView, 999, TRUE); ! 259: BBoxAddButton(buttonbox, "prev", ExecPrevView, 999, TRUE); ! 260: BBoxAddButton(buttonbox, "delete", ExecMarkDelete, 999, TRUE); ! 261: BBoxAddButton(buttonbox, "move", ExecMarkMove, 999, TRUE); ! 262: BBoxAddButton(buttonbox, "copy", ExecMarkCopy, 999, TRUE); ! 263: BBoxAddButton(buttonbox, "unmark", ExecMarkUnmarked, 999, TRUE); ! 264: BBoxAddButton(buttonbox, "viewNew", ExecViewNew, 999, TRUE); ! 265: BBoxAddButton(buttonbox, "reply", ExecTocReply, 999, TRUE); ! 266: BBoxAddButton(buttonbox, "forward", ExecTocForward, 999, TRUE); ! 267: BBoxAddButton(buttonbox, "useAsComp", ExecTocUseAsComposition, ! 268: 999, TRUE); ! 269: BBoxAddButton(buttonbox, "commit", ExecCommitChanges, 999, TRUE); ! 270: BBoxAddButton(buttonbox, "print", ExecPrintMessages, 999, TRUE); ! 271: BBoxAddButton(buttonbox, "pack", ExecPack, 999, TRUE); ! 272: BBoxAddButton(buttonbox, "sort", ExecSort, 999, TRUE); ! 273: BBoxAddButton(buttonbox, "rescan", ExecForceRescan, 999, TRUE); ! 274: BBoxAddButton(buttonbox, "pick", ExecPick, 999, TRUE); ! 275: BBoxAddButton(buttonbox, "openSeq", ExecOpenSeq, 999, TRUE); ! 276: BBoxAddButton(buttonbox, "addToSeq", ExecAddToSeq, 999, TRUE); ! 277: BBoxAddButton(buttonbox, "removeFromSeq", ExecRemoveFromSeq, 999, TRUE); ! 278: BBoxAddButton(buttonbox, "deleteSeq", ExecDeleteSeq, 999, TRUE); ! 279: BBoxForceFullSize(buttonbox); ! 280: BBoxStartUpdate(buttonbox); ! 281: ! 282: FillViewButtons(scrn); ! 283: BBoxForceFullSize(scrn->viewbuttons); ! 284: XtVPanedRefigureMode(DISPLAY scrn->window, TRUE); ! 285: BBoxAllowAnySize(scrn->folderbuttons); ! 286: BBoxAllowAnySize(scrn->mainbuttons); ! 287: BBoxAllowAnySize(scrn->seqbuttons); ! 288: BBoxAllowAnySize(scrn->tocbuttons); ! 289: BBoxAllowAnySize(scrn->viewbuttons); ! 290: GetWindowSize(scrn->tocwindow, &width, &theight); ! 291: GetWindowSize(scrn->viewwindow, &width, &vheight); ! 292: height = theight + vheight; ! 293: theight = defTocPercentage * height / 100; ! 294: XtVPanedSetMinMax(DISPLAY scrn->window, scrn->tocwindow, theight, theight); ! 295: XtVPanedSetMinMax(DISPLAY scrn->window, scrn->tocwindow, 50, 1000); ! 296: } ! 297: ! 298: ! 299: MakeView(scrn) ! 300: Scrn scrn; ! 301: { ! 302: scrn->viewlabel = CreateTitleBar(scrn, 0); ! 303: scrn->viewwindow = CreateTextSW(scrn, 1, "view", wordBreak); ! 304: scrn->viewbuttons = BBoxCreate(scrn, 2, "viewButtons"); ! 305: FillViewButtons(scrn); ! 306: } ! 307: ! 308: ! 309: MakeComp(scrn) ! 310: Scrn scrn; ! 311: { ! 312: scrn->viewlabel = CreateTitleBar(scrn, 0); ! 313: scrn->viewwindow = CreateTextSW(scrn, 1, "comp", wordBreak); ! 314: scrn->viewbuttons = BBoxCreate(scrn, 2, "compButtons"); ! 315: FillCompButtons(scrn); ! 316: compscrncount++; ! 317: } ! 318: ! 319: ! 320: ! 321: /* Create a scrn of the given type. */ ! 322: ! 323: Scrn CreateNewScrn(kind) ! 324: ScrnKind kind; ! 325: { ! 326: extern XSetSizeHints(); ! 327: int i; ! 328: Position x, y; ! 329: Dimension width, height; ! 330: Scrn scrn; ! 331: char *geometry; ! 332: static Arg arglist[] = { ! 333: {XtNname, NULL}, ! 334: {XtNx, NULL}, ! 335: {XtNy, NULL}, ! 336: {XtNwidth, NULL}, ! 337: {XtNheight, NULL}, ! 338: }; ! 339: #ifdef X11 ! 340: int bits; ! 341: XSizeHints sizehints; ! 342: #endif ! 343: #ifdef X10 ! 344: Window window; ! 345: OpaqueFrame frame; ! 346: WindowInfo info; ! 347: static FontInfo *font = NULL; ! 348: #endif X10 ! 349: ! 350: for (i=0 ; i<numScrns ; i++) ! 351: if (scrnList[i]->kind == kind && !scrnList[i]->mapped) ! 352: return scrnList[i]; ! 353: switch (kind) { ! 354: case STtocAndView: geometry = defTocGeometry; break; ! 355: case STview: geometry = defViewGeometry; break; ! 356: case STcomp: geometry = defCompGeometry; break; ! 357: case STpick: geometry = defPickGeometry; break; ! 358: } ! 359: ! 360: #ifdef X11 ! 361: bits = XParseGeometry(geometry, &x, &y, &width, &height); ! 362: if (!(bits & XValue)) x = 0; ! 363: else if (bits & XNegative) x = rootwidth - abs(x) - width; ! 364: if (!(bits & YValue)) y = 0; ! 365: else if (bits & YNegative) y = rootheight - abs(y) - height; ! 366: #endif ! 367: #ifdef X10 ! 368: if (font == NULL) font = XOpenFont("vtsingle"); ! 369: EmptyEventQueue(); ! 370: ClearButtonTracks(); ! 371: frame.bdrwidth = 1; ! 372: frame.border = BlackPixmap; ! 373: frame.background = WhitePixmap; ! 374: window = XCreateTerm(progName, progName, geometry, geometry, ! 375: &frame, 20, 20, 0, 0, &width, &height, font, 1, 1); ! 376: (void) XQueryWindow(window, &info); ! 377: x = info.x; ! 378: y = info.y; ! 379: width = info.width; ! 380: height = info.height; ! 381: XDestroyWindow(window); ! 382: #endif X10 ! 383: ! 384: arglist[0].value = (XtArgVal)progName; ! 385: arglist[1].value = (XtArgVal)x; ! 386: arglist[2].value = (XtArgVal)y; ! 387: arglist[3].value = (XtArgVal)width; ! 388: arglist[4].value = (XtArgVal)height; ! 389: numScrns++; ! 390: scrnList = (Scrn *) ! 391: XtRealloc((char *) scrnList, (unsigned) numScrns*sizeof(Scrn)); ! 392: scrn = scrnList[numScrns - 1] = (Scrn)XtMalloc(sizeof(ScrnRec)); ! 393: bzero((char *)scrn, sizeof(ScrnRec)); ! 394: scrn->kind = kind; ! 395: scrn->window = XtVPanedWindowCreate(DISPLAY QDefaultRootWindow(theDisplay), ! 396: arglist, XtNumber(arglist)); ! 397: (void) XtSetGeometryHandler(DISPLAY scrn->window, ! 398: (XtGeometryHandler)ScrnGeometryRequest); ! 399: ! 400: #ifdef X11 ! 401: #include <Xatom.h> ! 402: XtMakeMaster(DISPLAY scrn->window); ! 403: sizehints.flags = 0; ! 404: sizehints.x = x; ! 405: sizehints.y = y; ! 406: sizehints.width = width; ! 407: sizehints.height = height; ! 408: if ((bits & XValue) && (bits & YValue)) ! 409: sizehints.flags |= USPosition; ! 410: if ((bits & WidthValue) && (bits & HeightValue)) ! 411: sizehints.flags |= USSize; ! 412: else ! 413: sizehints.flags |= PSize; ! 414: XSetSizeHints(theDisplay, scrn->window, &sizehints, XA_WM_NORMAL_HINTS); ! 415: scrn->hints.flags = InputHint; ! 416: scrn->hints.input = FALSE; ! 417: if (kind == STtocAndView) { ! 418: scrn->hints.flags |= IconPixmapHint; ! 419: scrn->hints.icon_pixmap = NoMailPixmap; ! 420: } ! 421: XSetWMHints(theDisplay, scrn->window, &(scrn->hints)); ! 422: XDefineCursor(theDisplay, scrn->window, XtGetCursor(DISPLAY XC_left_ptr)); ! 423: #endif X11 ! 424: #ifdef X10 ! 425: XDefineCursor(scrn->window, XtGetCursor("left_ptr")); ! 426: #endif ! 427: ! 428: switch (kind) { ! 429: case STtocAndView: MakeTocAndView(scrn); break; ! 430: case STview: MakeView(scrn); break; ! 431: case STcomp: MakeComp(scrn); break; ! 432: } ! 433: return scrn; ! 434: } ! 435: ! 436: ! 437: Scrn NewViewScrn() ! 438: { ! 439: /* ! 440: Scrn scrn; ! 441: int i; ! 442: for (i=0 ; i<numScrns ; i++) { ! 443: scrn = scrnList[i]; ! 444: if (scrn->kind == STview && scrn->msg == NULL) ! 445: return scrn; ! 446: } ! 447: */ ! 448: return CreateNewScrn(STview); ! 449: } ! 450: ! 451: Scrn NewCompScrn() ! 452: { ! 453: /* ! 454: Scrn scrn; ! 455: int i; ! 456: for (i=0 ; i<numScrns ; i++) { ! 457: scrn = scrnList[i]; ! 458: if (scrn->kind == STcomp && MsgGetReapable(scrn->msg)) { ! 459: (void) MsgSetScrn((Msg) NULL, scrn); ! 460: return scrn; ! 461: } ! 462: } ! 463: */ ! 464: return CreateNewScrn(STcomp); ! 465: } ! 466: ! 467: ! 468: /* Destroy the screen. If unsaved changes are in a msg, too bad. */ ! 469: ! 470: void DestroyScrn(scrn) ! 471: Scrn scrn; ! 472: { ! 473: DestroyConfirmWindow(); ! 474: TocSetScrn((Toc) NULL, scrn); ! 475: MsgSetScrnForce((Msg) NULL, scrn); ! 476: if (scrn->kind == STcomp) compscrncount--; ! 477: /* (void) XtSendDestroyNotify(DISPLAY scrn->window); ! 478: QXDestroyWindow(theDisplay, scrn->window); ! 479: for (i = 0; i < numScrns; i++) ! 480: if (scrnList[i] == scrn) ! 481: break; ! 482: scrnList[i] = scrnList[--numScrns]; ! 483: XtFree((char *) scrn); ! 484: */ ! 485: QXUnmapWindow(theDisplay, scrn->window); ! 486: scrn->mapped = FALSE; ! 487: #ifdef X10 ! 488: ClearButtonTracks(); ! 489: #endif ! 490: } ! 491: ! 492: ! 493: ! 494: void MapScrn(scrn) ! 495: Scrn scrn; ! 496: { ! 497: if (!scrn->mapped) { ! 498: XRaiseWindow(DISPLAY scrn->window); ! 499: QXMapWindow(theDisplay, scrn->window); ! 500: scrn->mapped = TRUE; ! 501: } ! 502: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.