From da2cae2e72a7302bb9771df5d8d76796fca5faf9 Mon Sep 17 00:00:00 2001
From: Fons Rademakers <Fons.Rademakers@cern.ch>
Date: Thu, 8 Jan 2004 23:06:52 +0000
Subject: [PATCH] uses new splash screen. Screen does not need modification
 anymore for each new minor release. Version is printed over it and taken from
 the ROOT_RELEASE define. All core developers are credited. When called as
 "root -a" the credit text scrolls and shows names of all people in CREDITS
 file. The "About ROOT..." menu items in the Help menus of TCanvas, TBrowser
 and TTreeViewer call "root -a &" and show the scrolling credits. To close
 splash screen click with mouse in it. Not yet tested on display with < 255
 colors so some tuning might be needed for these old enviroments.

git-svn-id: http://root.cern.ch/svn/root/trunk@7869 27541ba8-7e3a-0410-8455-c3a389f83636
---
 rootx/src/rootx.cxx  |  39 ++--
 rootx/src/rootxx.cxx | 447 ++++++++++++++++++++++++++++++++++---------
 2 files changed, 387 insertions(+), 99 deletions(-)

diff --git a/rootx/src/rootx.cxx b/rootx/src/rootx.cxx
index 851de8b40cf..904a3157142 100644
--- a/rootx/src/rootx.cxx
+++ b/rootx/src/rootx.cxx
@@ -1,4 +1,4 @@
-// @(#)root/rootx:$Name:  $:$Id: rootx.cxx,v 1.10 2003/07/27 08:05:07 brun Exp $
+// @(#)root/rootx:$Name:  $:$Id: rootx.cxx,v 1.11 2003/10/13 18:20:18 rdm Exp $
 // Author: Fons Rademakers   19/02/98
 
 //////////////////////////////////////////////////////////////////////////
@@ -78,14 +78,14 @@
 #define ROOTBINARY "root.exe"
 #endif
 
-extern void PopupLogo();
+extern void PopupLogo(bool);
+extern void WaitLogo();
 extern void PopdownLogo();
 extern void CloseDisplay();
 
 
 static STRUCT_UTMP *gUtmpContents;
-static int          gBatch  = 0;
-static int          gNoLogo = 0;
+static bool gNoLogo = false;
 
 
 static int GetErrno()
@@ -233,7 +233,7 @@ static void SigUsr1(int)
 {
    // When we get SIGUSR1 from child (i.e. ROOT) then pop down logo.
 
-   if (!gBatch)
+   if (!gNoLogo)
       PopdownLogo();
 }
 
@@ -293,24 +293,38 @@ int main(int argc, char **argv)
    }
 #endif
 
-   // In batch mode don't show splash screen
+   // In batch mode don't show splash screen, idem for no logo mode,
+   // in about mode show always splash screen
+   bool batch = false, about = false;
    int i;
    for (i = 1; i < argc; i++) {
       if (!strcmp(argv[i], "-?") || !strncmp(argv[i], "-h", 2)) {
          PrintUsage(argv[0]);
          return 1;
       }
-      if (!strcmp(argv[i], "-b")) gBatch  = 1;
-      if (!strcmp(argv[i], "-l")) gNoLogo = 1;
+      if (!strcmp(argv[i], "-b")) batch   = true;
+      if (!strcmp(argv[i], "-l")) gNoLogo = true;
+      if (!strcmp(argv[i], "-a")) about   = true;
+   }
+   if (batch)
+      gNoLogo = true;
+   if (about) {
+      batch   = false;
+      gNoLogo = false;
    }
 
-   if (!gBatch) {
+   if (!batch) {
       SetDisplay();
       if (!getenv("DISPLAY")) {
          fprintf(stderr, "%s: can't figure out DISPLAY, set it manually\n", argv[0]);
          return 1;
       }
-      if (!gNoLogo) PopupLogo();
+      if (about) {
+         PopupLogo(true);
+         WaitLogo();
+         return 0;
+      } else if (!gNoLogo)
+         PopupLogo(false);
    }
 
    // Ignore SIGINT and SIGQUIT. Install handler for SIGUSR1.
@@ -350,8 +364,11 @@ int main(int argc, char **argv)
    if ((childpid = fork()) < 0) {
       fprintf(stderr, "%s: error forking child\n", argv[0]);
       return 1;
-   } else if (childpid > 0)
+   } else if (childpid > 0) {
+      if (!gNoLogo)
+         WaitLogo();
       WaitChild(childpid);
+   }
 
    // Continue with child...
 
diff --git a/rootx/src/rootxx.cxx b/rootx/src/rootxx.cxx
index 3f7570dac03..99ef45626e9 100644
--- a/rootx/src/rootxx.cxx
+++ b/rootx/src/rootxx.cxx
@@ -1,4 +1,4 @@
-// @(#)root/rootx:$Name:  $:$Id: rootxx.cxx,v 1.1.1.1 2000/05/16 17:00:48 rdm Exp $
+// @(#)root/rootx:$Name:  $:$Id: rootxx.cxx,v 1.2 2001/06/22 16:10:21 rdm Exp $
 // Author: Fons Rademakers   19/02/98
 
 //////////////////////////////////////////////////////////////////////////
@@ -10,8 +10,16 @@
 //                                                                      //
 //////////////////////////////////////////////////////////////////////////
 
+#ifdef HAVE_CONFIG
+#include "config.h"
+#endif
+
 #include <stdio.h>
 #include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/types.h>
 #include <X11/Xlib.h>
 
 #include "RConfig.h"
@@ -23,55 +31,98 @@
 #include <time.h>
 #include <sys/time.h>
 
-#ifdef XpmVersion
-#ifndef XpmSuccess
-#define XpmSuccess       0
-#endif
-#ifndef XpmColorError
-#define XpmColorError    1
-#endif
-#endif
-
-// X bitmaps
-#include "rootlogo_xbm.h"
-#ifdef XpmVersion
-#include "rootlogo_xpm.h"
-#endif
-
-
-static Display *gDisplay    = 0;
-static Window   gLogoWindow = 0;
-static Pixmap   gLogoPixmap = 0;
+static Display     *gDisplay       = 0;
+static Window       gLogoWindow    = 0;
+static Pixmap       gLogoPixmap    = 0;
+static Pixmap       gCreditsPixmap = 0;
+static GC           gGC            = 0;
+static XFontStruct *gFont          = 0;
+static bool         gDone          = false;
+static bool         gMayPopdown    = false;
+static bool         gAbout         = false;
+static unsigned int gWidth         = 0;
+static unsigned int gHeight        = 0;
+static int          gStayUp        = 4000;   // 4 seconds
+static XRectangle   gCreditsRect   = { 15, 155, 285, 130 }; // clip rect in logo
+static unsigned int gCreditsWidth  = gCreditsRect.width; // credits pixmap size
+static unsigned int gCreditsHeight = 0;
 
 static struct timeval gPopupTime;
 
-
-
-static void StayUp(int milliSec)
+static const char *gConception[] = {
+   "Rene Brun",
+   "Fons Rademakers",
+   0
+};
+
+static const char *gRootDevelopers[] = {
+   "Ilka Antcheva",
+   "Maarten Ballintijn",
+   "Bertrand Bellenot",
+   "Rene Brun",
+   "Philippe Canal",
+   "Olivier Couet",
+   "Gerardo Ganis",
+   "Eddy Offermann",
+   "Valeriy Onuchin",
+   "Fons Rademakers",
+   0
+};
+
+static const char *gCintDevelopers[] = {
+   "Masaharu Goto",
+   0
+};
+
+static const char *gRootDocumentation[] = {
+   "Ilka Antcheva",
+   "Susan Panachek",
+   0
+};
+
+static char **gContributors = 0;
+
+
+
+static bool StayUp(int milliSec)
 {
-   // Make sure milliSec milliseconds have passed since logo was popped up.
+   // Returns false if milliSec milliseconds have passed since logo
+   // was popped up, true otherwise.
 
-   // get current time
-   struct timeval ctv, dtv, tv;
+   struct timeval ctv, dtv, tv, ptv = gPopupTime;
 
    tv.tv_sec  = milliSec / 1000;
    tv.tv_usec = (milliSec % 1000) * 1000;
 
    gettimeofday(&ctv, 0);
-   if ((dtv.tv_usec = ctv.tv_usec - gPopupTime.tv_usec) < 0) {
+   if ((dtv.tv_usec = ctv.tv_usec - ptv.tv_usec) < 0) {
       dtv.tv_usec += 1000000;
-      gPopupTime.tv_sec++;
+      ptv.tv_sec++;
    }
-   dtv.tv_sec = ctv.tv_sec - gPopupTime.tv_sec;
+   dtv.tv_sec = ctv.tv_sec - ptv.tv_sec;
 
    if ((ctv.tv_usec = tv.tv_usec - dtv.tv_usec) < 0) {
-      tv.tv_usec += 1000000;
+      ctv.tv_usec += 1000000;
       dtv.tv_sec++;
    }
    ctv.tv_sec = tv.tv_sec - dtv.tv_sec;
-   if (ctv.tv_sec < 0) return;
 
-   select(0, 0, 0, 0, &ctv);
+   if (ctv.tv_sec < 0) return false;
+
+   return true;
+}
+
+static void Sleep(int milliSec)
+{
+   // Sleep for specified amount of milli seconds.
+
+   // get current time
+   struct timeval tv;
+
+   tv.tv_sec  = milliSec / 1000;
+   tv.tv_usec = (milliSec % 1000) * 1000;
+
+   select(0, 0, 0, 0, &tv);
 }
 
 static Pixel Color(const char *name)
@@ -88,76 +139,214 @@ static Pixel Color(const char *name)
 
 static Pixmap GetRootLogo()
 {
+   // Get logo from xpm file.
+
    Pixmap logo = 0;
    int depth = PlanesOfScreen(XDefaultScreenOfDisplay(gDisplay));
 
-#ifdef XpmVersion
-   if (depth > 1) {
-      XWindowAttributes win_attr;
-      XGetWindowAttributes(gDisplay, gLogoWindow, &win_attr);
+   XWindowAttributes win_attr;
+   XGetWindowAttributes(gDisplay, gLogoWindow, &win_attr);
 
-      XpmAttributes attr;
-      attr.valuemask    = XpmVisual | XpmColormap | XpmDepth;
-      attr.visual       = win_attr.visual;
-      attr.colormap     = win_attr.colormap;
-      attr.depth        = win_attr.depth;
+   XpmAttributes attr;
+   attr.valuemask    = XpmVisual | XpmColormap | XpmDepth;
+   attr.visual       = win_attr.visual;
+   attr.colormap     = win_attr.colormap;
+   attr.depth        = win_attr.depth;
 
 #ifdef XpmColorKey              // Not available in XPM 3.2 and earlier
-      attr.valuemask |= XpmColorKey;
-      if (depth > 4)
-         attr.color_key = XPM_COLOR;
-      else if (depth > 2)
-         attr.color_key = XPM_GRAY4;
-      else if (depth > 1)
-         attr.color_key = XPM_GRAY;
-      else if (depth == 1)
-         attr.color_key = XPM_MONO;
-      else
-         attr.valuemask &= ~XpmColorKey;
+   attr.valuemask |= XpmColorKey;
+   if (depth > 4)
+      attr.color_key = XPM_COLOR;
+   else if (depth > 2)
+      attr.color_key = XPM_GRAY4;
+   else if (depth > 1)
+      attr.color_key = XPM_GRAY;
+   else if (depth == 1)
+      attr.color_key = XPM_MONO;
+   else
+      attr.valuemask &= ~XpmColorKey;
 
 #endif // defined(XpmColorKey)
 
-      int ret = XpmCreatePixmapFromData(gDisplay, gLogoWindow,
-                                        (char **)rootlogo, &logo,
-                                        (Pixmap *)0, &attr);
-      XpmFreeAttributes(&attr);
+   char file[2048];
+#ifdef ROOTICONPATH
+   sprintf(file, "%s/Splash.xpm", ROOTICONPATH);
+#else
+   sprintf(file, "%s/icons/Splash.xpm", getenv("ROOTSYS"));
+#endif
+   int ret = XpmReadFileToPixmap(gDisplay, gLogoWindow,
+                                 file, &logo, 0, &attr);
+   XpmFreeAttributes(&attr);
+
+   if (ret == XpmSuccess || ret == XpmColorError)
+       return logo;
+
+   printf("rootx xpm error: %s\n", XpmGetErrorString(ret));
+
+   if (logo) XFreePixmap(gDisplay, logo);
+   logo = 0;
+
+   return logo;
+}
+
+static void ReadContributors()
+{
+   // Read the file $ROOTSYS/README/CREDITS for the names of the
+   // contributors.
+
+   char buf[2048];
+#ifdef ROOTDOCDIR
+   sprintf(buf, "%s/CREDITS", ROOTDOCDIR);
+#else
+   sprintf(buf, "%s/README/CREDITS", getenv("ROOTSYS"));
+#endif
+
+   gContributors = 0;
 
-      if (ret == XpmSuccess || ret == XpmColorError)
-          return logo;
+   FILE *f = fopen(buf, "r");
+   if (!f) return;
 
-      if (logo)
-         XFreePixmap(gDisplay, logo);
-      logo = 0;
+   int cnt = 0;
+   while (fgets(buf, sizeof(buf), f)) {
+      if (!strncmp(buf, "N: ", 3)) {
+         cnt++;
+      }
+   }
+   gContributors = new char*[cnt+1];
+
+   cnt = 0;
+   rewind(f);
+   while (fgets(buf, sizeof(buf), f)) {
+      if (!strncmp(buf, "N: ", 3)) {
+         int len = strlen(buf);
+         buf[len-1] = 0;    // remove \n
+         len -= 3;          // remove "N: "
+         gContributors[cnt] = new char[len];
+         strncpy(gContributors[cnt], buf+3, len);
+         cnt++;
+      }
    }
+   gContributors[cnt] = 0;
 
-#endif // defined(XpmVersion)
+   fclose(f);
+}
 
-   if (depth > 4)
-      logo = XCreatePixmapFromBitmapData(gDisplay, gLogoWindow,
-                                         rootlogo_bits,
-                                         rootlogo_width, rootlogo_height,
-                                         Color("brown"),
-                                         Color("white"),
-                                         depth);
-   else {
-      int screen = DefaultScreen(gDisplay);
-      logo = XCreatePixmapFromBitmapData(gDisplay, gLogoWindow,
-                                         rootlogo_bits,
-                                         rootlogo_width, rootlogo_height,
-                                         BlackPixel(gDisplay, screen),
-                                         WhitePixel(gDisplay, screen),
-                                         depth);
+static void DrawVersion()
+{
+   // Draw version string.
+
+   char version[80];
+   sprintf(version, "Version %s", ROOT_RELEASE);
+
+   XDrawString(gDisplay, gLogoWindow, gGC, 15, gHeight - 15, version,
+               strlen(version));
+}
+
+static int DrawCreditItem(const char *creditItem, const char **members,
+                          int y, bool draw)
+{
+   // Draw credit item.
+
+   char credit[1024];
+   int i;
+   int lineSpacing = gFont->max_bounds.ascent + gFont->max_bounds.descent;
+
+   strcpy(credit, creditItem);
+   for (i = 0; members && members[i]; i++) {
+      if (i) strcat(credit, ", ");
+      if (XTextWidth(gFont, credit, strlen(credit)) +
+          XTextWidth(gFont, members[i], strlen(members[i])) > (int) gCreditsWidth) {
+         if (draw)
+            XDrawString(gDisplay, gCreditsPixmap, gGC, 0, y, credit, strlen(credit));
+         y += lineSpacing;
+         strcpy(credit, "   ");
+      }
+      strcat(credit, members[i]);
    }
-   return logo;
+   if (draw)
+      XDrawString(gDisplay, gCreditsPixmap, gGC, 0, y, credit, strlen(credit));
+
+   return y;
+}
+
+static int DrawCredits(bool draw, bool extended)
+{
+   // Draw credits. If draw is true draw credits,
+   // otherwise just return size of all credit text.
+   // If extended is true draw or returns size for extended full
+   // credits list.
+
+   int lineSpacing = gFont->max_bounds.ascent + gFont->max_bounds.descent;
+   int y = 2*lineSpacing;
+
+   y = DrawCreditItem("Conception: ", gConception, y, draw);
+
+   y += 2*lineSpacing;
+
+   y = DrawCreditItem("Engineering: ", gRootDevelopers, y, draw);
+
+   y += 2*lineSpacing;
+
+   y = DrawCreditItem("CINT C/C++ Intepreter: ", gCintDevelopers, y, draw);
+
+   y += 2*lineSpacing;
+
+   y = DrawCreditItem("Documentation: ", gRootDocumentation, y, draw);
+
+   if (extended && gContributors) {
+      y += 2*lineSpacing;
+      y = DrawCreditItem("Contributors: ", (const char **)gContributors, y, draw);
+
+      y += 2*lineSpacing;
+      y = DrawCreditItem("Special thanks to the neglected families and friends", 0, y, draw);
+      y += lineSpacing;
+      y = DrawCreditItem("of the aforementioned persons.", 0, y, draw);
+
+      y += 2*lineSpacing;
+      y = DrawCreditItem("Our sincere thanks and apologies to anyone who deserves", 0, y, draw);
+      y += lineSpacing;
+      y = DrawCreditItem("credit but fails to appear in this list.", 0, y, draw);
+
+      struct passwd *pwd = getpwuid(getuid());
+      if (pwd) {
+         char *name = new char [strlen(pwd->pw_gecos)+1];
+         strcpy(name, pwd->pw_gecos);
+         char *s = strchr(name, ',');
+         if (s) *s = 0;
+         char line[1024];
+         sprintf(line, "Extra special thanks go to %s,", name);
+         delete [] name;
+         y += 2*lineSpacing;
+         y = DrawCreditItem(line, 0, y, draw);
+         y += lineSpacing;
+         y = DrawCreditItem("one of our favorite users.", 0, y, draw);
+      }
+   }
+
+   return y;
+}
+
+void ScrollCredits(int ypos)
+{
+   XRectangle crect[1];
+   crect[0] = gCreditsRect;
+   XSetClipRectangles(gDisplay, gGC, 0, 0, crect, 1, Unsorted);
+
+   XCopyArea(gDisplay, gCreditsPixmap, gLogoWindow, gGC,
+             0, ypos, gCreditsWidth, gCreditsHeight, gCreditsRect.x, gCreditsRect.y);
+
+   XSetClipMask(gDisplay, gGC, None);
 }
 
-void PopupLogo()
+void PopupLogo(bool about)
 {
    // Popup logo, waiting till ROOT is ready to run.
 
    gDisplay = XOpenDisplay("");
    if (!gDisplay) return;
 
+   gAbout = about;
+
    Pixel back, fore;
    int screen = DefaultScreen(gDisplay);
 
@@ -168,17 +357,23 @@ void PopupLogo()
                                      -100, -100, 50, 50, 0, fore, back);
 
    gLogoPixmap = GetRootLogo();
+   if (!gLogoPixmap) {
+      XCloseDisplay(gDisplay);
+      gDisplay = 0;
+      return;
+   }
 
    Window root;
    int x, y;
-   unsigned int w, h, bw, depth;
-   XGetGeometry(gDisplay, gLogoPixmap, &root, &x, &y, &w, &h, &bw, &depth);
+   unsigned int bw, depth;
+   XGetGeometry(gDisplay, gLogoPixmap, &root, &x, &y, &gWidth, &gHeight,
+                &bw, &depth);
 
    Screen *xscreen = XDefaultScreenOfDisplay(gDisplay);
-   x = (WidthOfScreen(xscreen) - w) / 2;
-   y = (HeightOfScreen(xscreen) - h) / 2;
+   x = (WidthOfScreen(xscreen) - gWidth) / 2;
+   y = (HeightOfScreen(xscreen) - gHeight) / 2;
 
-   XMoveResizeWindow(gDisplay, gLogoWindow, x, y, w, h);
+   XMoveResizeWindow(gDisplay, gLogoWindow, x, y, gWidth, gHeight);
    XSync(gDisplay, False);   // make sure move & resize is done before mapping
 
    unsigned long valmask;
@@ -188,17 +383,74 @@ void PopupLogo()
    xswa.override_redirect = True;
    XChangeWindowAttributes(gDisplay, gLogoWindow, valmask, &xswa);
 
+   gGC = XCreateGC(gDisplay, gLogoWindow, 0, 0);
+   gFont = XLoadQueryFont(gDisplay, "-adobe-helvetica-medium-r-*-*-10-*-*-*-*-*-iso8859-1");
+   XSetFont(gDisplay, gGC, gFont->fid);
+   XSetForeground(gDisplay, gGC, fore);
+   XSetBackground(gDisplay, gGC, back);
+
+   if (about)
+      ReadContributors();
+
+   gCreditsHeight = DrawCredits(false, about) + gCreditsRect.height + 50;
+   gCreditsPixmap = XCreatePixmap(gDisplay, gLogoWindow, gCreditsWidth, gCreditsHeight, depth);
+   XSetForeground(gDisplay, gGC, back);
+   XFillRectangle(gDisplay, gCreditsPixmap, gGC, 0, 0, gCreditsWidth, gCreditsHeight);
+   XSetForeground(gDisplay, gGC, fore);
+   DrawCredits(true, about);
+
+   XSelectInput(gDisplay, gLogoWindow, ButtonPressMask | ExposureMask);
+
    XMapRaised(gDisplay, gLogoWindow);
-   XSync(gDisplay, False);
 
    gettimeofday(&gPopupTime, 0);
 }
 
-void PopdownLogo()
+void WaitLogo()
 {
-   // Pop down the logo. ROOT is ready to run.
+   // Main event loop waiting till time arrives to pop down logo
+   // or when forced by button press event.
 
-   StayUp(4000);
+   if (!gDisplay) return;
+
+   int ypos = 0;
+
+   ScrollCredits(ypos);
+   DrawVersion();
+   XFlush(gDisplay);
+
+   while (!gDone) {
+      XEvent event;
+      if (XCheckMaskEvent(gDisplay, ButtonPressMask | ExposureMask, &event)) {
+         switch (event.type) {
+            case Expose:
+               if (event.xexpose.count == 0) {
+                  ScrollCredits(ypos);
+                  DrawVersion();
+               }
+               break;
+            case ButtonPress:
+               gDone = true;
+               break;
+            default:
+               break;
+         }
+      }
+
+      Sleep(100);
+
+      if (!gAbout && !StayUp(gStayUp) && gMayPopdown)
+         gDone = true;
+
+      if (gAbout) {
+         if (ypos == 0) Sleep(2000);
+         ypos++;
+         if (ypos > (int) (gCreditsHeight - gCreditsRect.height - 50))
+            ypos = -int(gCreditsRect.height);
+         ScrollCredits(ypos);
+         XFlush(gDisplay);
+      }
+   }
 
    if (gLogoWindow) {
       XUnmapWindow(gDisplay, gLogoWindow);
@@ -209,6 +461,18 @@ void PopdownLogo()
       XFreePixmap(gDisplay, gLogoPixmap);
       gLogoPixmap = 0;
    }
+   if (gCreditsPixmap) {
+      XFreePixmap(gDisplay, gCreditsPixmap);
+      gCreditsPixmap = 0;
+   }
+   if (gFont) {
+      XFreeFont(gDisplay, gFont);
+      gFont = 0;
+   }
+   if (gGC) {
+      XFreeGC(gDisplay, gGC);
+      gGC = 0;
+   }
    if (gDisplay) {
       XSync(gDisplay, False);
       XCloseDisplay(gDisplay);
@@ -216,6 +480,13 @@ void PopdownLogo()
    }
 }
 
+void PopdownLogo()
+{
+   // ROOT is ready to run, may pop down the logo if stay up time expires.
+
+   gMayPopdown = true;
+}
+
 void CloseDisplay()
 {
    // Close connection to X server (called by child).
-- 
GitLab