/*
 * This program demonstrates a problem where the application hangs showing 
 * a dialog. 
 * 
 * To build:
 *    gcc demo_hang.c -o demo_hang -L /usr/X11R6/lib -l Xm -l Xt -l X11
 *
 * Run it, press the button - a dialog is displayed 
 *         press again      - the application hangs for a while
 *
 * Restart app and repeat but move dialog after first displayed. Problem
 * is not seen.
 */

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <Xm/XmAll.h>

static XtAppContext cxt;
static Widget b;
static Widget dlg;

static void make_dialog (Widget wapp)
{
  Arg args[5];
  int n = 0;
  XtSetArg(args[n], XmNmappedWhenManaged, FALSE);n++;
  dlg = XmCreateDialogShell(wapp, "Test", args, n);
  if (!dlg) 
  {
    printf("Failed to create dialog\n");
  }
  b = XtVaCreateManagedWidget("push", xmPushButtonWidgetClass,
      dlg, NULL);
  XtRealizeWidget (dlg);
}

static void pushed (Widget w, XtPointer c, XtPointer u)
{ 
  int     i, num_children;
  Widget  *children;
  XmString label;
  time_t start, end;
  static int count = 0;
  char buf[10];
  sprintf (buf, "%d", count++);
  Widget child;
  
  label = XmStringCreateLocalized (buf);
  XtVaSetValues(b, XmNlabelString, label, NULL);
  XmStringFree (label);
  XtVaGetValues (dlg,
                 XmNnumChildren, &num_children,
                 XmNchildren, &children,
                 0);

  /* We manage/unmanage the first rectObj child in the list.
   * Note that the check for rectObjClass is necessary since some
   * implementations of Motif add protocol children to the dialogShell.
   * Additionally, when the LANG is set to Japanese, a widget of class
   * Core is created. This widget should not be managed. We'll skip it.
   */

  for (i = 0; i < num_children; i++)
  {
          if (XtIsSubclass(children[i], rectObjClass) &&
                  (XtClass (children[i]) != coreWidgetClass))
          {
                  child = children[i];
                  break;
          }
  }
   
  XtUnmanageChild(child);
  XWithdrawWindow(XtDisplay(dlg), XtWindow(dlg), 0);
  XtManageChild(child);
    
  start = time(NULL);    
  XtVaSetValues (dlg, XmNx, 500, XmNy, 200, 0);
  end = time(NULL);
  fprintf (stderr, "%d seconds to position\n", end-start);
  XMapWindow(XtDisplay(dlg), XtWindow(dlg));
}

static void make_shell (Widget wapp)
{
  XmString label = XmStringCreateLocalized("Push");
  Widget button = XtVaCreateManagedWidget("push", xmPushButtonWidgetClass,
      wapp, XmNlabelString, label, NULL);
  XmStringFree (label);
  make_dialog(wapp);
  XtAddCallback (button, XmNactivateCallback, pushed, NULL);
}

int main (int argc, char** argv)
{
  Widget wapp;
  
  XtSetLanguageProc (NULL, NULL, NULL);
  wapp = XtVaAppInitialize (&cxt, "Test", NULL, 0, &argc, argv, NULL, NULL);
  if (!wapp) 
  {
    printf("Failed to create shell\n");
  }
  
  make_shell (wapp);
  
  XtRealizeWidget (wapp);
  XtAppMainLoop (cxt);
}
