OpenURL 25.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/* Copyright 1997 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/***************************************************/
/* File   : OpenURL.c                              */
/*                                                 */
/* Purpose: Functions relating to the Open URL     */
/*          dialogue box.                          */
/*                                                 */
/* Author : A.D.Hodgkinson                         */
/*                                                 */
/* History: 17-Apr-97: Created.                    */
/***************************************************/

#include <stdlib.h>
#include <string.h>

#include "swis.h"

31 32
#include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */

33 34 35 36 37 38 39 40 41
#include "wimp.h"
#include "wimplib.h"
#include "event.h"

#include "toolbox.h"
#include "window.h"

#include "svcprint.h"
#include "Global.h"
42
#include "FromROSLib.h"
43
#include "MiscDefs.h"
44 45
#include "Utils.h"

46
#include "Browser.h"
47 48 49
#include "Fetch.h" /* (For ISLINK macro) */
#include "FetchPage.h"
#include "History.h"
50
#include "Hotlist.h"
51 52
#include "Menus.h"
#include "URLutils.h"
53 54 55 56
#include "Windows.h"

#include "OpenURL.h"

57 58 59 60
/* Local structures */

typedef struct openurl_contents
{
61
  char         url[Limits_URLBarWrit];
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

  /* Where to open the URL to */

  unsigned int in_this   :1;
  unsigned int save_link :1;
  unsigned int in_new    :1;
  unsigned int in_parent :1;

} openurl_contents;

/* Local statics */

// We *really* want to be mallocing this...
static openurl_contents   contents;        /* Remember the old dialogue contents so the Cancel button can work */

static ObjectId           window_id   = 0; /* Remember the ID in case it needs closing 'out of the blue'. */
static ObjectId           ancestor_id = 0; /* Remember the ancestor ID in case the ancestor closes. */

static HStream          * open_hst = NULL; /* See openurl_to_show_from_menu */

/* Static function prototypes */

static _kernel_oserror * openurl_read_contents   (ObjectId dialogue, openurl_contents * contents);
static _kernel_oserror * openurl_set_contents    (ObjectId dialogue, openurl_contents * contents);

static int               openurl_ok              (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);
static int               openurl_cancel          (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);
static int               openurl_radio_group_one (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);
static int               openurl_click           (int eventcode, WimpPollBlock * b, IdBlock * idb, void * handle);
91
static int               openurl_key_handler     (int eventcode, WimpPollBlock * b, IdBlock * idb, void * handle);
92

93
/*************************************************/
94
/* openurl_read_contents()                       */
95
/*                                               */
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
/* Reads the contents of the Open URL dialogue   */
/* into an openurl_contents structure.           */
/*                                               */
/* Parameters: Object ID of the dialogue;        */
/*                                               */
/*             Pointer to the structure to write */
/*             to.                               */
/*************************************************/

static _kernel_oserror * openurl_read_contents(ObjectId dialogue, openurl_contents * contents)
{
  _kernel_oserror * e;
  int               state;

  /* Read the URL string */

  *contents->url = 0;

  e = writablefield_get_value(0,
                              dialogue,
                              OpenWrit,
                              contents->url,
                              sizeof(contents->url),
                              NULL);

  contents->url[sizeof(contents->url) - 1] = 0; /* (Ensure termination) */

  if (e) return e;

  /* Read radio group 1 - where to open the URL */

  RetError(radiobutton_get_state(0, dialogue, OpenInThis,   &state, NULL)); contents->in_this   = !!state;
  RetError(radiobutton_get_state(0, dialogue, OpenSaveLink, &state, NULL)); contents->save_link = !!state;
  RetError(radiobutton_get_state(0, dialogue, OpenInNew,    &state, NULL)); contents->in_new    = !!state;
  RetError(radiobutton_get_state(0, dialogue, OpenInParent, &state, NULL)); contents->in_parent = !!state;

  /* Finished */

  return NULL;
}

/*************************************************/
/* openurl_set_contents()                        */
/*                                               */
/* Sets the contents of the Open URL dialogue    */
/* from an openurl_contents structure.           */
/*                                               */
/* Parameters: Object ID of the dialogue;        */
/*                                               */
/*             Pointer to the structure to read  */
/*             from.                             */
/*************************************************/

static _kernel_oserror * openurl_set_contents(ObjectId dialogue, openurl_contents * contents)
{
  /* The URL entry field */

  RetError(writablefield_set_value(0,
                                   dialogue,
                                   OpenWrit,
                                   contents->url));

  /* Radio group 1 - where to open the URL */

  RetError(radiobutton_set_state(0, dialogue, OpenInThis,   contents->in_this));
  RetError(radiobutton_set_state(0, dialogue, OpenSaveLink, contents->save_link));
  RetError(radiobutton_set_state(0, dialogue, OpenInNew,    contents->in_new));
  return   radiobutton_set_state(0, dialogue, OpenInParent, contents->in_parent);
}

/*************************************************/
/* openurl_fill_in_url()                         */
/*                                               */
/* If an external function wants to set the URL  */
/* in the writable field of the Open URL         */
/* dialogue, this is the function to use.        */
/*                                               */
/* Parameters: Pointer to the null terminated    */
/*             URL string.                       */
/*************************************************/

_kernel_oserror * openurl_fill_in_url(char * url)
{
  if (!url || !window_id) return NULL;

  return writablefield_set_value(0,
                                 window_id,
                                 OpenWrit,
                                 url);
}

/*************************************************/
/* openurl_to_be_shown()                         */
/*                                               */
190 191 192 193 194
/* Called when the EOpenToBeShownMisc event is   */
/* generated, typically when the Open URL window */
/* is about to be shown. Handles any icon        */
/* processing commands in the writable,          */
/* registers event handlers, etc.                */
195 196 197 198 199 200 201
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

int openurl_to_be_shown(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
202
  char text[Limits_URLBarWrit];
203

204 205 206 207 208 209 210 211 212 213 214 215
  /* In multiuser builds, must be logged in... */

  #ifndef SINGLE_USER

    if (!logged_in)
    {
      toolbox_hide_object(0, idb->self_id);
      return 1;
    }

  #endif

216 217 218 219 220 221 222 223 224 225 226 227 228
  /* If the stored dialogue ID is non-zero on entry, the dialogue */
  /* was reopened without closing - so get rid of the various     */
  /* event handlers before we reregister them.                    */

  if (window_id) openurl_close(0, 1);

  /* Read the window ID and ancestor ID from the ID block */

  window_id   = idb->self_id;
  ancestor_id = idb->ancestor_id;

  /* Process the icon text */

229 230
  ChkError(windows_process_component_text(idb->self_id, OpenWrit, text, sizeof(text), 0, 1));

231 232 233 234 235 236
  /* Attach handlers for the various actions the window can perform */

  ChkError(event_register_toolbox_handler(idb->self_id, EOpenOK,     openurl_ok,              NULL));
  ChkError(event_register_toolbox_handler(idb->self_id, EOpenCancel, openurl_cancel,          NULL));
  ChkError(event_register_toolbox_handler(idb->self_id, EOpenRG1,    openurl_radio_group_one, NULL));

237 238 239 240 241
  ChkError(event_register_wimp_handler(idb->self_id,
                                       Wimp_EKeyPressed,
                                       openurl_key_handler,
                                       NULL));

242 243 244 245 246 247 248 249 250 251 252 253 254
  ChkError(event_register_wimp_handler(idb->self_id,
                                       Wimp_EMouseClick,
                                       openurl_click,
                                       NULL));

  /* Make sure the radios are up to date */

  openurl_radio_group_one(eventcode, event, idb, handle);

  /* Read the existing contents into the static openurl_contents block */

  ChkError(openurl_read_contents(idb->self_id, &contents));

255 256 257 258 259
  /* Do we have a History? */

  if (history_empty(NULL)) set_gadget_state(idb->self_id, OpenHistory, 1);
  else                     set_gadget_state(idb->self_id, OpenHistory, 0);

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  /* Was the menu that generated this dialogue - if any - opened */
  /* over a link? If so, write the URL to the dialogue.          */
  /*                                                             */
  /* See openurl_to_show_from_menu for more details.             */

  if (open_hst)
  {
    if (ISLINK(open_hst))
    {
      /* Don't put internal URLs in there! */

      if (!urlutils_internal_extra(open_hst->anchor))
      {
        StrNCpy0(contents.url, open_hst->anchor);
        ChkError(openurl_set_contents(idb->self_id, &contents));
      }
    }
    else if (
              open_hst->style & IMG ||
              (
                open_hst->tagno         == TAG_INPUT &&
                HtmlINPUTtype(open_hst) == inputtype_IMAGE
              )
            )
    {
      /* If it is an image, write the image source URL to the dialogue */

      StrNCpy0(contents.url, open_hst->src);
      ChkError(openurl_set_contents(idb->self_id, &contents));
    }
290
    else if (ISOBJECT(open_hst))
291
    {
292 293 294
      const char   * data;
      const char   * current;
      browser_data * b = NULL;
295

296 297 298 299 300
      if (ancestor_id) toolbox_get_client_handle(0, idb->self_id, (void *) &b);
      if (b && !is_known_browser(b)) b = NULL;

      /* If it is an Object, write an appropriate URL in there, */
      /* remembering to relativise it where possible.           */
301 302 303 304

      data            = HtmlOBJECTdata(open_hst);
      if (!data) data = HtmlOBJECTcodebase(open_hst);

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
      if (b)
      {
        current = browser_fetch_url(b);
        if (!current) current = browser_current_url(b);

        if (current)
        {
          const char * newdata;

          newdata = HtmlRelativiseURL(current, data, open_hst);

          if (newdata) data = newdata;
        }
      }

320 321 322
      StrNCpy0(contents.url, data);
      ChkError(openurl_set_contents(idb->self_id, &contents));
    }
323 324 325 326 327 328 329 330 331 332 333 334

    /* Clear the value */

    open_hst = NULL;
  }

  return 1;
}

/*************************************************/
/* openurl_to_show_from_menu()                   */
/*                                               */
335
/* Called when the EOpenToBeShownMenu event is   */
336 337 338 339 340 341 342 343 344 345 346
/* generated, typically when the Open URL window */
/* is about to be shown from a menu item.        */
/*                                               */
/* To be able to show the URL of a link in the   */
/* window, menu functions have to read the       */
/* token the pointer is over and remember it.    */
/* But to ensure this doesn't get out of date,   */
/* the value is cleared when the menu is hidden. */
/*                                               */
/* Unhelpfully, the Toolbox sends events out in  */
/* an order that means the value is cleared      */
347 348
/* before the EOpenToBeShownMisc event is        */
/* raised.                                       */
349 350
/*                                               */
/* To get round that, the menu entry itself      */
351
/* raises EOpenToBeShownMenu, so this function   */
352 353
/* is called. It reads the value and stores it   */
/* locally - great... Two copies hanging around. */
354 355 356 357 358
/* Anyway, when the EOpenToBeShownMisc event     */
/* finally arrives, openurl_to_be_shown is       */
/* called, reads the value set here, acts on it, */
/* and clears the value to ensure correct        */
/* behaviour on future calls.                    */
359 360 361 362 363 364 365 366 367 368
/*                                               */
/* All this because the events arrive in a silly */
/* order. Sigh.                                  */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

int openurl_to_show_from_menu(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
369
  open_hst = menus_document_opened_over();
370 371 372 373

  return 1;
}

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
/*************************************************/
/* openurl_update_popup()                        */
/*                                               */
/* Ensures that the greyed/ungreyed state of the */
/* History menu popup in the Open URL dialogue   */
/* is up to date.                                */
/*************************************************/

void openurl_update_popup(void)
{
  if (!window_id) return;

  if (history_empty(NULL)) set_gadget_state(window_id, OpenHistory, 1);
  else                     set_gadget_state(window_id, OpenHistory, 0);
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
/*************************************************/
/* openurl_ok()                                  */
/*                                               */
/* Handles clicks on the 'OK' button in the      */
/* Open URL dialogue.                            */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int openurl_ok(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  openurl_contents          localcontents;
  WimpGetPointerInfoBlock   info;
  browser_data            * b;
  browser_data            * ancestor;

  /* Work out where the dialogue came from */

  ChkError(wimp_get_pointer_info(&info));

  if (!idb->ancestor_id) b = ancestor = NULL;
  else
  {
    ChkError(toolbox_get_client_handle(0, idb->ancestor_id, (void *) &b));

    if (is_known_browser(b)) ancestor = b->ancestor;
    else                     ancestor = b = NULL;
  }

  /* Read the dialogue contents */

  ChkError(openurl_read_contents(idb->self_id, &localcontents));

  /* If Select was pressed, the dialogue will close, so */
  /* remember the current contents for future reference */
  /* (no button => Return was pressed)                  */

  if ((info.button_state & Wimp_MouseButtonSelect) || !info.button_state) contents = localcontents;

  /* Fetch the indicated URL */

  if (*localcontents.url)
  {
434 435 436 437 438
    /* If asked to open in a new window or saving the object, */
    /* open a new window (this will be a small fetch window   */
    /* in the latter case).                                   */

    if (localcontents.in_new || localcontents.save_link || !b)
439 440 441 442 443
    {
      ChkError(windows_create_browser(localcontents.url,
                                      NULL,
                                      NULL,
                                      NULL,
444
                                      localcontents.save_link ? Windows_CreateBrowser_SaveToFile : Windows_CreateBrowser_Normal));
445
    }
446 447 448 449

    /* Otherwise, open the URL in the browser window from which */
    /* the dialogue was obtained in the first place.            */

450 451 452 453 454 455 456 457 458
    else
    {
      browser_data * fetch;

      /* Work out which existing window to fetch to */

      if (localcontents.in_this || localcontents.save_link) fetch = b;
      else                                                  fetch = ancestor;

459 460
      /* Set that window's save_link and allow_cancel */
      /* flags according to the dialogue contents     */
461

462 463
      fetch->save_link = localcontents.save_link;
      if (fetch->save_link) b->allow_cancel = 0;
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642

      /* Initiate the fetch */

      ChkError(fetchpage_new(fetch, localcontents.url, 1, 1));
    }
  }

  if ((info.button_state & Wimp_MouseButtonSelect) || !info.button_state)
  {
    ChkError(openurl_close(0, 0));
  }

  return 1;
}

/*************************************************/
/* openurl_cancel()                              */
/*                                               */
/* Handles clicks on the 'Cancel' button in the  */
/* Open URL dialogue.                            */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int openurl_cancel(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  WimpGetPointerInfoBlock info;

  /* Restore the old contents */

  ChkError(openurl_set_contents(window_id, &contents));

  /* If Select was pressed, the dialogue should close. */
  /* (No button => Escape was pressed).                */

  ChkError(wimp_get_pointer_info(&info));

  if ((info.button_state & Wimp_MouseButtonSelect) || !info.button_state)
  {
    ChkError(openurl_close(0, 0));
  }

  return 1;
}

/*************************************************/
/* openurl_close()                               */
/*                                               */
/* If the Open URL dialogue is opened, this will */
/* close it, deregistering any associated event  */
/* handlers.                                     */
/*                                               */
/* Parameters: An object ID, or 0. If not zero,  */
/*             the ID must match the ancestor    */
/*             recorded when the dialogue was    */
/*             opened or no action is taken.     */
/*                                               */
/*             0 to close the dialogue, 1 to do  */
/*             everything except that.           */
/*************************************************/

_kernel_oserror * openurl_close(ObjectId ancestor, int do_not_close)
{
  _kernel_oserror * e = NULL;

  if (ancestor && ancestor != ancestor_id) return NULL;

  if (window_id)
  {
    /* Deregister associated event handlers */

    e = event_deregister_toolbox_handlers_for_object(window_id);
    if (e) goto openurl_close_exit;

    e = event_deregister_wimp_handlers_for_object(window_id);
    if (e) goto openurl_close_exit;

    /* Restore the old contents */

    e = openurl_set_contents(window_id, &contents);
    if (e) goto openurl_close_exit;

    /* Close the dialogue */

    if (!do_not_close) e = toolbox_hide_object(0, window_id);
  }

openurl_close_exit:

  ancestor_id = window_id = 0;
  return e;
}

/*************************************************/
/* openurl_radio_group_one()                     */
/*                                               */
/* Looks at radio group one and greys or ungreys */
/* items as required. Usually used as a handler  */
/* for when the selection therein changes, but   */
/* can be used in a more general purpose way.    */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int openurl_radio_group_one(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  _kernel_oserror * e;
  browser_data    * b;
  browser_data    * ancestor;
  int               state;

  /* Note that few errors are reported here - this allows items to be */
  /* removed from the window without causing errors to appear.        */

  if (!idb->ancestor_id) b = ancestor = NULL;
  else
  {
    ChkError(toolbox_get_client_handle(0, idb->ancestor_id, (void *) &b));

    if (is_known_browser(b)) ancestor = b->ancestor;
    else                     ancestor = b = NULL;
  }

  /* If b is NULL, this was not opened from a browser window */

  if (!b)
  {
    /* Grey out the gadget. Try to read its state, and, if this */
    /* succeds and the gadget was selected, then select the     */
    /* 'Open in new window' gadget instead - this will never be */
    /* greyed out.                                              */

    gadget_set_flags(0,
                     idb->self_id,
                     OpenInThis,
                     Gadget_Faded);

    e = radiobutton_get_state(0,
                              idb->self_id,
                              OpenInThis,
                              &state,
                              NULL);

    if (!e && state) radiobutton_set_state(0,
                                           idb->self_id,
                                           OpenInNew,
                                           1);
  }
  else gadget_set_flags(0,
                        idb->self_id,
                        OpenInThis,
                        0);

  /* If ancestor is NULL, this was not opened from a frame */

  if (!ancestor)
  {
    gadget_set_flags(0,
                     idb->self_id,
                     OpenInParent,
                     Gadget_Faded);

    e = radiobutton_get_state(0,
                              idb->self_id,
                              OpenInParent,
                              &state,
                              NULL);

    if (!e && state) radiobutton_set_state(0,
                                           idb->self_id,
                                           OpenInNew,
                                           1);
  }
  else gadget_set_flags(0,
                        idb->self_id,
                        OpenInParent,
                        0);
643 644
  return 1;
}
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667

/*************************************************/
/* openurl_click()                               */
/*                                               */
/* Handles Wimp mouse click events in the Open   */
/* URL dialogue.                                 */
/*                                               */
/* Parameters are as standard for a Wimp event   */
/* handler.                                      */
/*************************************************/

static int openurl_click(int eventcode, WimpPollBlock * b, IdBlock * idb, void * handle)
{
  int used = 0;

  switch (idb->self_component)
  {
    case OpenHistory:
    {
      ChkError(history_menu_popup(NULL,
                                  idb->self_id,
                                  idb->self_component,
                                  1,
668
                                  b->mouse_click.buttons & Wimp_MouseButtonAdjust ? !choices.show_urls : choices.show_urls));
669 670 671 672 673 674 675
      used = 1;
    }
    break;
  }

  return used;
}
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697

/*************************************************/
/* openurl_key_handler()                         */
/*                                               */
/* Handles a few key pressed events in the Open  */
/* URL dialogue.                                 */
/*                                               */
/* Parameters are as standard for a Wimp event   */
/* handler.                                      */
/*************************************************/

static int openurl_key_handler(int eventcode, WimpPollBlock * b, IdBlock * idb, void * handle)
{
  _kernel_oserror * e;
  int               key;

  key = ((WimpKeyPressedEvent *) b)->key_code;

  switch (key)
  {
    case akbd_TabK + akbd_Ctl:
    {
698
      char url[Limits_URLBarWrit];
699
      int  changed = 0;
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718

      /* Read whatever is in the URL bar writable */

      *url = 0;

      e = writablefield_get_value(0,
                                  idb->self_id,
                                  OpenWrit,
                                  url,
                                  sizeof(url),
                                  NULL);

      if (!e)
      {
        url[sizeof(url) - 1] = 0; /* (Ensure termination) */

        /* Try and find something appropriate in the hotlist, */
        /* then the history.                                  */

719 720 721 722
        #ifndef REMOTE_HOTLIST
          changed = hotlist_find_match(url, sizeof(url));
        #endif

723 724 725 726 727 728 729 730 731 732 733 734 735 736
        if (!changed) changed = history_find_match(url, sizeof(url));

        if (changed)
        {
          /* Update the URL writable */

          writablefield_set_value(0,
                                  idb->self_id,
                                  OpenWrit,
                                  url);
        }
      }

      key = 0;
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
    }
    break;

    case akbd_TabK + akbd_Sh:
    {
      char url[Limits_URLBarWrit];
      int  changed;

      /* Read whatever is in the URL bar writable */

      *url = 0;

      e = writablefield_get_value(0,
                                  idb->self_id,
                                  OpenWrit,
                                  url,
                                  sizeof(url),
                                  NULL);

      if (!e)
      {
        url[sizeof(url) - 1] = 0; /* (Ensure termination) */

        /* Cycle the protocol specifier (adding one in if not already present) */

        changed = urlutils_cycle_protocol(url, sizeof(url));

        if (changed)
        {
          /* Update the URL writable */

          writablefield_set_value(0,
                                  idb->self_id,
                                  OpenWrit,
                                  url);
        }
      }

      key = 0;
    }
    break;
  }

  if (key) wimp_process_key(key);

  return 1;
}