I started messing around with the Visual Studio 2005 C# Screen Saver Starter Kit as I wanted to make my own customized screen saver. The provided starter kit works great on a single monitor, however I have two monitors at my workstation and the screen saver from the kit only seems to show up on whichever monitor is flagged as the primary display.
I've got one video card that has one DVI output with some kind of Y connector attaching the two monitors.
The monitors are listed as 'Plug and Play Monitor on 256MB Radeon X600' and 'Plug and Play Monitor on 256MB Radeon X600 Secondary' in the Display section of the Settings tab of the display properties window thingy.
There is what appears to be an excellent tutorial here at Dreamincode.net but the sample screen saver provided only appears to run on the primary monitor as well...
Nevertheless, after reading over the tutorial it seemed simple enough to at least try converting the Screen Saver Starter Kit to support multi monitors. This is of course didn't work either. Here's the code I have now in the project:
In Program.cs
using System;
using System.Windows.Forms;
using System.Globalization;
namespace MultiMonitorScreenSaver
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
// Get the 2 character command line argument
string arg = args[0].ToLower(CultureInfo.InvariantCulture).Trim().Substring(0, 2);
switch (arg)
{
case "/c":
// Show the options dialog
ShowOptions();
break;
case "/p":
// Don't do anything for preview
break;
case "/s":
// Show screensaver form
ShowScreenSaver();
Application.Run();
break;
default:
MessageBox.Show("Invalid command line argument :" + arg, "Invalid Command Line Argument", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
}
else
{
// If no arguments were passed in, show the screensaver
ShowScreenSaver();
Application.Run();
}
}
static void ShowOptions()
{
OptionsForm optionsForm = new OptionsForm();
Application.Run(optionsForm);
}
static void ShowScreenSaver()
{
foreach (Screen screen in Screen.AllScreens)
{
ScreenSaverForm screenSaver = new ScreenSaverForm(screen.Bounds);
screenSaver.Show();
//Application.Run(screenSaver);
}
}
}
}
In ScreenSaverForm.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using MultiMonitorScreenSaver.UI;
using MultiMonitorScreenSaver.Rss;
namespace MultiMonitorScreenSaver
{
partial class ScreenSaverForm : Form
{
// The RssFeed to display articles from
private RssFeed rssFeed;
// Objects for displaying RSS contents
private ItemListView<RssItem> rssView;
private ItemDescriptionView<RssItem> rssDescriptionView;
// The images to display in the background
private List<Image> backgroundImages;
private int currentImageIndex;
// Keep track of whether the screensaver has become active.
private bool isActive = false;
// Keep track of the location of the mouse
private Point mouseLocation;
private List<string> imageExtensions = new List<string>(new string[] { "*.bmp", "*.gif", "*.png", "*.jpg", "*.jpeg" });
/* Parameter 'Rectangle Bounds' added by me for Multi-Display */
public ScreenSaverForm(Rectangle Bounds)
{
InitializeComponent();
this.Bounds = Bounds;
SetupScreenSaver();
LoadBackgroundImage();
LoadRssFeed();
// Initialize the ItemListView to display the list of items in the
// RssItem. It is placed on the left side of the screen.
rssView = new ItemListView<RssItem>(rssFeed.MainChannel.Title, rssFeed.MainChannel.Items);
InitializeRssView();
// Initialize the ItemDescriptionView to display the description of the
// RssItem. It is placed on the right side of the screen.
rssDescriptionView = new ItemDescriptionView<RssItem>();
InitializeRssDescriptionView();
}
public ScreenSaverForm()
{
InitializeComponent();
SetupScreenSaver();
LoadBackgroundImage();
LoadRssFeed();
// Initialize the ItemListView to display the list of items in the
// RssItem. It is placed on the left side of the screen.
rssView = new ItemListView<RssItem>(rssFeed.MainChannel.Title, rssFeed.MainChannel.Items);
InitializeRssView();
// Initialize the ItemDescriptionView to display the description of the
// RssItem. It is placed on the right side of the screen.
rssDescriptionView = new ItemDescriptionView<RssItem>();
InitializeRssDescriptionView();
}
/// <summary>
/// Set up the main form as a full screen screensaver.
/// </summary>
private void SetupScreenSaver()
{
// Use double buffering to improve drawing performance
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
// Capture the mouse
this.Capture = true;
// Set the application to full screen mode and hide the mouse
Cursor.Hide();
//Bounds = Screen.PrimaryScreen.Bounds;
WindowState = FormWindowState.Maximized;
ShowInTaskbar = false;
DoubleBuffered = true;
BackgroundImageLayout = ImageLayout.Stretch;
}
private void LoadBackgroundImage()
{
// Initialize the background images.
backgroundImages = new List<Image>();
currentImageIndex = 0;
if (Directory.Exists(Properties.Settings.Default.BackgroundImagePath))
{
try
{
// Try to load the images given by the users.
LoadImagesFromFolder();
}
catch
{
// If this fails, load the default images.
LoadDefaultBackgroundImages();
}
}
// If no images were loaded, load the defaults
if (backgroundImages.Count == 0)
{
LoadDefaultBackgroundImages();
}
}
private void LoadImagesFromFolder()
{
DirectoryInfo backgroundImageDir = new DirectoryInfo(Properties.Settings.Default.BackgroundImagePath);
// For each image extension (.jpg, .bmp, etc.)
foreach (string imageExtension in imageExtensions)
{
// For each file in the directory provided by the user
foreach (FileInfo file in backgroundImageDir.GetFiles(imageExtension))
{
// Try to load the image
try
{
Image image = Image.FromFile(file.FullName);
backgroundImages.Add(image);
}
catch (OutOfMemoryException)
{
// If the image can't be loaded, move on.
continue;
}
}
}
}
private void LoadDefaultBackgroundImages()
{
// If the background images could not be loaded for any reason
// use the image stored in the resources
backgroundImages.Add(Properties.Resources.SSaverBackground);
backgroundImages.Add(Properties.Resources.SSaverBackground2);
}
private void LoadRssFeed()
{
try
{
// Try to get it from the users settings
rssFeed = RssFeed.FromUri(Properties.Settings.Default.RssFeedUri);
}
catch
{
// If there is any problem loading the RSS load an error message RSS feed
rssFeed = RssFeed.FromText(Properties.Resources.DefaultRSSText);
}
}
/// <summary>
/// Initialize display properties of the rssView.
/// </summary>
private void InitializeRssView()
{
rssView.BackColor = Color.FromArgb(120, 240, 234, 232);
rssView.BorderColor = Color.White;
rssView.ForeColor = Color.FromArgb(255, 40, 40, 40);
rssView.SelectedBackColor = Color.FromArgb(200, 105, 61, 76);
rssView.SelectedForeColor = Color.FromArgb(255, 204, 184, 163);
rssView.TitleBackColor = Color.Empty;
rssView.TitleForeColor = Color.FromArgb(255, 240, 234, 232);
rssView.MaxItemsToShow = 20;
rssView.MinItemsToShow = 15;
rssView.Location = new Point(Width / 10, Height / 10);
rssView.Size = new Size(Width / 2, Height / 2);
}
/// <summary>
/// Initialize display properties of the rssDescriptionView.
/// </summary>
private void InitializeRssDescriptionView()
{
rssDescriptionView.DisplayItem = rssView.SelectedItem;
rssDescriptionView.ForeColor = Color.FromArgb(255, 240, 234, 232);
rssDescriptionView.TitleFont = rssView.TitleFont;
rssDescriptionView.LineColor = Color.FromArgb(120, 240, 234, 232);
rssDescriptionView.LineWidth = 2f;
rssDescriptionView.FadeTimer.Tick += new EventHandler(FadeTimer_Tick);
rssDescriptionView.FadeTimer.Interval = 40;
rssDescriptionView.Location = new Point(3 * Width / 4, Height / 3);
rssDescriptionView.Size = new Size(Width / 4, Height / 2);
rssDescriptionView.FadingComplete += new EventHandler(rssItemView_FadingComplete);
}
private void ScreenSaverForm_MouseMove(object sender, MouseEventArgs e)
{
// Set IsActive and MouseLocation only the first time this event is called.
if (!isActive)
{
mouseLocation = MousePosition;
isActive = true;
}
else
{
// If the mouse has moved significantly since first call, close.
if ((Math.Abs(MousePosition.X - mouseLocation.X) > 10) ||
(Math.Abs(MousePosition.Y - mouseLocation.Y) > 10))
{
Close();
}
}
}
private void ScreenSaverForm_KeyDown(object sender, KeyEventArgs e)
{
Close();
}
private void ScreenSaverForm_MouseDown(object sender, MouseEventArgs e)
{
Close();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Draw the current background image stretched to fill the full screen
e.Graphics.DrawImage(backgroundImages[currentImageIndex], 0, 0, this.Width, this.Height);
}
protected override void OnPaint(PaintEventArgs e)
{
rssView.Paint(e);
rssDescriptionView.Paint(e);
}
private void backgroundChangeTimerTick(object sender, EventArgs e)
{
// Change the background image to the next image.
currentImageIndex = (currentImageIndex + 1) % backgroundImages.Count;
}
void FadeTimer_Tick(object sender, EventArgs e)
{
this.Refresh();
}
void rssItemView_FadingComplete(object sender, EventArgs e)
{
rssView.NextArticle();
rssDescriptionView.DisplayItem = rssView.SelectedItem;
}
}
}
Interestingly enough, when I try to debug this project using the Visual Studio debugger, I can step through line by line until it hits the Application.Run() method after running the ShowScreenSaver() method. At this point the Visual Studio window seems to freeze (in fact everything on that monitor seems frozen) and the only way to 'unfreeze' is to kill the screensaver vshost process using the task manager. Just for fun I tried renaming the compiled executable to a .scr file and set that as my screen saver and it works, but once again only for the primary monitor.
Is there something inherently wrong with the way I have things set up? The default Microsoft screensavers that come stock with Windows XP work fine with multiple monitors, why won't mine?

New Topic/Question
Reply




MultiQuote






|