From http://www.jwz.org/xscreensaver/xscreensaver-5.15.tar.gz
[xscreensaver] / OSX / XScreenSaverConfigSheet.m
index 06804c70429b915d84eb34dcbe30ad90fde0889c..2b0cb916bf35a9e2269ab3d6a35d7f439de11863 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2006-2008 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2006-2011 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -172,7 +172,7 @@ parse_attrs (NSMutableDictionary *dict, NSXMLNode *node)
     if (! old) {
       NSAssert2 (0, @"unknown attribute \"%@\" in \"%@\"", key, [node name]);
     } else if ([old length] != 0) {
-      NSAssert2 (0, @"duplicate %@: \"%@\", \"%@\"", old, val);
+      NSAssert3 (0, @"duplicate %@: \"%@\", \"%@\"", key, old, val);
     } else {
       [dict setValue:val forKey:key];
     }
@@ -374,7 +374,8 @@ make_file_selector (NSUserDefaultsController *prefs,
                     const XrmOptionDescRec *opts, 
                     NSView *parent, NSXMLNode *node,
                     BOOL dirs_only_p,
-                    BOOL no_label_p)
+                    BOOL no_label_p,
+                    BOOL editable_text_p)
 {
   NSMutableDictionary *dict =
   [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -404,9 +405,9 @@ make_file_selector (NSUserDefaultsController *prefs,
   [txt setStringValue:@"123456789 123456789 "];
   [txt sizeToFit];
   [txt setSelectable:YES];
-  [txt setEditable:NO];
-  [txt setBezeled:NO];
-  [txt setDrawsBackground:NO];
+  [txt setEditable:editable_text_p];
+  [txt setBezeled:editable_text_p];
+  [txt setDrawsBackground:editable_text_p];
   [[txt cell] setWraps:NO];
   [[txt cell] setScrollable:YES];
   [[txt cell] setLineBreakMode:NSLineBreakByTruncatingHead];
@@ -424,10 +425,12 @@ make_file_selector (NSUserDefaultsController *prefs,
   bind_switch_to_preferences (prefs, txt, arg, opts);
   [txt release];
 
-  // Make the text field be the same height as the label.
+  // Make the text field and label be the same height, whichever is taller.
   if (lab) {
     rect = [txt frame];
-    rect.size.height = [lab frame].size.height;
+    rect.size.height = ([lab frame].size.height > [txt frame].size.height
+                        ? [lab frame].size.height
+                        : [txt frame].size.height);
     [txt setFrame:rect];
   }
 
@@ -483,7 +486,7 @@ do_file_selector (NSTextField *txt, BOOL dirs_p)
                                      types:nil];
   if (result == NSOKButton) {
     NSArray *files = [panel filenames];
-    NSString *file = ([files count] > 0 ? [files objectAtIndex:0] : @"");
+    file = ([files count] > 0 ? [files objectAtIndex:0] : @"");
     file = [file stringByAbbreviatingWithTildeInPath];
     [txt setStringValue:file];
 
@@ -837,6 +840,11 @@ make_option_menu (NSUserDefaultsController *prefs,
   rect.origin.x = rect.origin.y = 0;
   rect.size.width = 10;
   rect.size.height = 10;
+
+  // #### "Build and Analyze" says that all of our widgets leak, because it
+  //      seems to not realize that place_child -> addSubview retains them.
+  //      Not sure what to do to make these warnings go away.
+
   NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:rect
                                                      pullsDown:NO];
 
@@ -851,7 +859,7 @@ make_option_menu (NSUserDefaultsController *prefs,
     if ([child kind] == NSXMLCommentKind)
       continue;
     if ([child kind] != NSXMLElementKind) {
-      NSAssert2 (0, @"weird XML node kind: %d: %@", [child kind], node);
+      NSAssert2 (0, @"weird XML node kind: %d: %@", (int)[child kind], node);
       continue;
     }
 
@@ -1047,6 +1055,7 @@ static char *
 anchorize (const char *url)
 {
   const char *wiki = "http://en.wikipedia.org/wiki/";
+  const char *math = "http://mathworld.wolfram.com/";
   if (!strncmp (wiki, url, strlen(wiki))) {
     char *anchor = (char *) malloc (strlen(url) * 3 + 10);
     strcpy (anchor, "Wikipedia: \"");
@@ -1076,6 +1085,29 @@ anchorize (const char *url)
     *out = 0;
     return anchor;
 
+  } else if (!strncmp (math, url, strlen(math))) {
+    char *anchor = (char *) malloc (strlen(url) * 3 + 10);
+    strcpy (anchor, "MathWorld: \"");
+    const char *start = url + strlen(wiki);
+    const char *in = start;
+    char *out = anchor + strlen(anchor);
+    while (*in) {
+      if (*in == '_') {
+        *out++ = ' ';
+      } else if (in != start && *in >= 'A' && *in <= 'Z') {
+        *out++ = ' ';
+        *out++ = *in;
+      } else if (!strncmp (in, ".htm", 4)) {
+        break;
+      } else {
+        *out++ = *in;
+      }
+      in++;
+    }
+    *out++ = '"';
+    *out = 0;
+    return anchor;
+
   } else {
     return strdup (url);
   }
@@ -1214,6 +1246,8 @@ layout_group (NSView *group, BOOL horiz_p)
   }
   
   NSRect rect;
+  rect.origin.x = 0;
+  rect.origin.y = 0;
   rect.size.width = maxx;
   rect.size.height = -miny;
   [group setFrame:rect];
@@ -1245,18 +1279,22 @@ make_text_controls (NSUserDefaultsController *prefs,
      ( )  Text       [__________________________]
      ( )  Text file  [_________________] [Choose]
      ( )  URL        [__________________________]
+     ( )  Shell Cmd  [__________________________]
 
     textMode -text-mode date
     textMode -text-mode literal   textLiteral -text-literal %
     textMode -text-mode file      textFile    -text-file %
     textMode -text-mode url       textURL     -text-url %
+    textMode -text-mode program   textProgram -text-program %
    */
   NSRect rect;
   rect.size.width = rect.size.height = 1;
   rect.origin.x = rect.origin.y = 0;
-  NSView *group = [[NSView alloc] initWithFrame:rect];
+  NSView *group  = [[NSView alloc] initWithFrame:rect];
   NSView *rgroup = [[NSView alloc] initWithFrame:rect];
 
+  Bool program_p = TRUE;
+
 
   NSXMLElement *node2;
   NSView *control;
@@ -1272,7 +1310,7 @@ make_text_controls (NSUserDefaultsController *prefs,
                        initWithFrame:rect
                        mode:NSRadioModeMatrix
                        prototype:proto
-                       numberOfRows:4
+                       numberOfRows: 4 + (program_p ? 1 : 0)
                        numberOfColumns:1];
   [matrix setAllowsEmptySelection:NO];
 
@@ -1281,6 +1319,7 @@ make_text_controls (NSUserDefaultsController *prefs,
   [cnames addObject:@"Text"];
   [cnames addObject:@"File"];
   [cnames addObject:@"URL"];
+  if (program_p) [cnames addObject:@"Shell Cmd"];
   [matrix bind:@"content"
           toObject:cnames
           withKeyPath:@"arrangedObjects"
@@ -1302,7 +1341,7 @@ make_text_controls (NSUserDefaultsController *prefs,
   make_text_field (prefs, opts, rgroup, node2, YES);
   [node2 release];
 
-  rect = [last_child(rgroup) frame];
+//  rect = [last_child(rgroup) frame];
 
 /* // trying to make the text fields be enabled only when the checkbox is on..
   control = last_child (rgroup);
@@ -1320,10 +1359,10 @@ make_text_controls (NSUserDefaultsController *prefs,
                         @"textFile",           @"id",
                         @"-text-file %",       @"arg",
                         nil]];
-  make_file_selector (prefs, opts, rgroup, node2, NO, YES);
+  make_file_selector (prefs, opts, rgroup, node2, NO, YES, NO);
   [node2 release];
 
-  rect = [last_child(rgroup) frame];
+//  rect = [last_child(rgroup) frame];
 
   //  <string id="textURL" _label="" arg-set="text-url %"/>
   node2 = [[NSXMLElement alloc] initWithName:@"string"];
@@ -1335,7 +1374,21 @@ make_text_controls (NSUserDefaultsController *prefs,
   make_text_field (prefs, opts, rgroup, node2, YES);
   [node2 release];
 
-  rect = [last_child(rgroup) frame];
+//  rect = [last_child(rgroup) frame];
+
+  if (program_p) {
+    //  <string id="textProgram" _label="" arg-set="text-program %"/>
+    node2 = [[NSXMLElement alloc] initWithName:@"string"];
+    [node2 setAttributesAsDictionary:
+            [NSDictionary dictionaryWithObjectsAndKeys:
+                          @"textProgram",        @"id",
+                          @"-text-program %",    @"arg",
+                          nil]];
+    make_text_field (prefs, opts, rgroup, node2, YES);
+    [node2 release];
+  }
+
+//  rect = [last_child(rgroup) frame];
 
   layout_group (rgroup, NO);
 
@@ -1349,6 +1402,8 @@ make_text_controls (NSUserDefaultsController *prefs,
   control = last_child (rgroup);
   rect = [control frame];
   rect.size.width = 30;  // width of the string "Text", plus a bit...
+  if (program_p)
+    rect.size.width += 25;
   rect.size.height += LINE_SPACING;
   [matrix setCellSize:rect.size];
   [matrix sizeToCells];
@@ -1363,7 +1418,7 @@ make_text_controls (NSUserDefaultsController *prefs,
   // the text fields.
   // 
   rect.size = [matrix cellSize];
-  rect.size.width *= 10;
+  rect.size.width = 300;
   [matrix setCellSize:rect.size];
   [matrix sizeToCells];
 
@@ -1432,11 +1487,24 @@ make_image_controls (NSUserDefaultsController *prefs,
   [node2 setAttributesAsDictionary:
           [NSDictionary dictionaryWithObjectsAndKeys:
                         @"imageDirectory",     @"id",
-                        @"Images directory:",  @"_label",
+                        @"Images from:",       @"_label",
                         @"-image-directory %", @"arg",
                         nil]];
-  make_file_selector (prefs, opts, parent, node2, YES, NO);
+  make_file_selector (prefs, opts, parent, node2, YES, NO, YES);
   [node2 release];
+
+  // Add a second, explanatory label below the file/URL selector.
+
+  NSTextField *lab2 = 0;
+  lab2 = make_label (@"(Local folder, or URL of RSS or Atom feed)");
+  place_child (parent, lab2, NO);
+
+  // Pack it in a little tighter vertically.
+  NSRect r2 = [lab2 frame];
+  r2.origin.x += 20;
+  r2.origin.y += 14;
+  [lab2 setFrameOrigin:r2.origin];
+  [lab2 release];
 }
 
 
@@ -1452,7 +1520,7 @@ make_control (NSUserDefaultsController *prefs,
   if ([node kind] == NSXMLCommentKind)
     return;
   if ([node kind] != NSXMLElementKind) {
-    NSAssert2 (0, @"weird XML node kind: %d: %@", [node kind], node);
+    NSAssert2 (0, @"weird XML node kind: %d: %@", (int)[node kind], node);
     return;
   }
 
@@ -1472,7 +1540,7 @@ make_control (NSUserDefaultsController *prefs,
     make_text_field (prefs, opts, parent, node, NO);
 
   } else if ([name isEqualToString:@"file"]) {
-    make_file_selector (prefs, opts, parent, node, NO, NO);
+    make_file_selector (prefs, opts, parent, node, NO, NO, NO);
 
   } else if ([name isEqualToString:@"number"]) {
     make_number_selector (prefs, opts, parent, node);
@@ -1545,8 +1613,7 @@ fix_contentview_size (NSView *parent)
   NSRect f;
   NSArray *kids = [parent subviews];
   int nkids = [kids count];
-  NSView *text;  // the NSText at the bottom of the window
-  NSView *last;  // the last child before the NSText
+  NSView *text = 0;  // the NSText at the bottom of the window
   double maxx = 0, miny = 0;
   int i;
 
@@ -1562,7 +1629,6 @@ fix_contentview_size (NSView *parent)
     f = [kid frame];
     if (f.origin.x + f.size.width > maxx)  maxx = f.origin.x + f.size.width;
     if (f.origin.y - f.size.height < miny) miny = f.origin.y;
-    last = kid;
 //    NSLog(@"start: %3.0f x %3.0f @ %3.0f %3.0f  %3.0f  %@",
 //          f.size.width, f.size.height, f.origin.x, f.origin.y,
 //          f.origin.y + f.size.height, [kid class]);
@@ -1573,6 +1639,7 @@ fix_contentview_size (NSView *parent)
   /* Now that we know the width of the window, set the width of the NSText to
      that, so that it can decide what its height needs to be.
    */
+  if (! text) abort();
   f = [text frame];
 //  NSLog(@"text old: %3.0f x %3.0f @ %3.0f %3.0f  %3.0f  %@",
 //        f.size.width, f.size.height, f.origin.x, f.origin.y,
@@ -1606,6 +1673,10 @@ fix_contentview_size (NSView *parent)
   f = [text frame];
   float dh = f.size.height - oh;
   f.origin.y += dh;
+
+  // #### This is needed in OSX 10.5, but is wrong in OSX 10.6.  WTF??
+  //      If we do this in 10.6, the text field moves down, off the window.
+  //      So instead we repair it at the end, at the "WTF2" comment.
   [text setFrame:f];
 
   // Also adjust the parent height by the change in height of the text field.
@@ -1619,10 +1690,10 @@ fix_contentview_size (NSView *parent)
   /* Set the contentView to the size of the children.
    */
   f = [parent frame];
-  float yoff = f.size.height;
+//  float yoff = f.size.height;
   f.size.width = maxx + LEFT_MARGIN;
   f.size.height = -(miny - LEFT_MARGIN*2);
-  yoff = f.size.height - yoff;
+//  yoff = f.size.height - yoff;
   [parent setFrame:f];
 
 //  NSLog(@"max: %3.0f x %3.0f @ %3.0f %3.0f", 
@@ -1643,6 +1714,25 @@ fix_contentview_size (NSView *parent)
 //          f.origin.y + f.size.height, [kid class]);
   }
   
+/*
+Bad:
+ parent: 420 x 541 @   0   0
+ text:   380 x 100 @  20  22  miny=-501
+
+Good:
+ parent: 420 x 541 @   0   0
+ text:   380 x 100 @  20  50  miny=-501
+*/
+
+  // #### WTF2: See "WTF" above.  If the text field is off the screen,
+  //      move it up.  We need this on 10.6 but not on 10.5.  Auugh.
+  //
+  f = [text frame];
+  if (f.origin.y < 50) {    // magic numbers, yay
+    f.origin.y = 50;
+    [text setFrame:f];
+  }
+
   /* Set the kids to track the top left corner of the window when resized.
      Set the NSText to track the bottom right corner as well.
    */
@@ -1850,13 +1940,6 @@ traverse_tree (NSUserDefaultsController *prefs,
                             options:(NSXMLNodePreserveWhitespace |
                                      NSXMLNodePreserveCDATA)
                             error:&err];
-/* clean up?
-    if (!xmlDoc) {
-      xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl
-                                      options:NSXMLDocumentTidyXML
-                                      error:&err];
-    }
-*/
   if (!xmlDoc || err) {
     if (err)
       NSAssert2 (0, @"XML Error: %@: %@",
@@ -1865,6 +1948,7 @@ traverse_tree (NSUserDefaultsController *prefs,
   }
 
   traverse_tree (prefs, self, opts, [xmlDoc rootElement]);
+  [xmlDoc release];
 
   return self;
 }