Wednesday, June 28, 2006

Multi-monitor Delphi

As many developers have already noted, developing with Delphi 2005/2006 on a single monitor is a major pain in every part of the body. That's why I hate developing on my notebook. Code fixing is doable, barely, but serious development is out of the question.

Many developers have also noted that 'undocked' layout works better on multiple
monitors. I don't think so - D2006 works just fine in 'docked' mode. The important
thing is to undock some of the windows and keep others docked or everything goes
kaboom.

Something you definitely don't want to do is undock Object Inspector and Messages.
Weirdest things start happening if you do.

In case you're wondering how I have organized my Delphi desktop, here's the picture:

normal work environment



As you can see, my primary monitor is on the right and secondary on the left. This configuration alone makes problems in VCL-based programs. For example, poDesktopCenter form position is calculated incorrectly - but that's another story.

Main monitor is filled with the Editor (of course!), onto which Object Inspector, Tool Palette, and Messages are docked. I said it before and I'll say it again: it is a wise man who keeps Object Inspector and Messages docked to the Editor.

On the left monitor I have Project Manager and ModelMake Code Explorer docked together (also, when needed, Model View appears here), small windows for To-Do List and Structure (to see syntax errors while I'm typing), another window shared between Find References and Refactorings and one hold-them-all container where other useful stuff is bunched together (Clipboard History from GExperts, Breakpoint List, Event Log etc).

I also have a slightly narrower layout for the time when I need more space (to watch TV, for example):

slightly narrower layout



In this layout, Refactorings and Find References are moved into the hold-them-all window and other windows are rearranged to use less space.

Sometimes I need lots of space - for example when comparing current code with an older version, or to look at the project specifications, various standards, internet pages ... To use Delphi on a single monitor, I keep Project Manager and Tool Palete docked and minimized on the right side of the Editor:

tweaked 'default' layout



Rarely used windows (Refactorings, Find References etc) take their share off the Editor space (for the short time they are visible):

tweaked 'default' layout with Find References



When debugging, I'm usually only using one monitor (and in some rare cases even less):

debug layout



That leaves me one full monitor to run the application on. This helps a lot, especially when debugging OnPaint handlers.

Monday, June 26, 2006

Remote access to the fourth power

Just a little list of what I'm using when I need remote access or remote control.

On the top of the list is Microsoft's Remote Deskop. Besides the accessibility (included in standard Windows XP installation), it is also blindingly fast, especially on DSL connections. Even more, it still works fine on dual ISDN connection (128 Kb/s).

What I hate about it is that it messes with my desktop. I'm running dual monitor configuration and everytime I connect remotely to my computer, RD moves all my desktop icons to the primary monitor. Yuck! (A small shell extension named Desktop Icons Save and Restore helps me restore them, but still - Yuck!)

That's why I sometimes use TightVNC for the same purpose. Not so fast, not so good (sometimes the screen is not redrawn when it should be), but it works quite fine on very fast networks; for example on the internal 100 Mb/s Ethernet.

When I'm using notebook and main computer at the same time, I usually use Synergy to control both machines with one keyboard and mouse. Read more about it in Steve Trefethen's blog.

Most rarely used of the great four (and the only one that is not free) is the MaxiVista. It allows you to turn additional computer (a notebook, for example) into an additional screen for your main computer. So when my two displays are not enough, I place the notebook on the table next to them, fire MaxiVista client on the notebook, MaxiVista server on the main computer and configure screen options to use the third monitor. MaxiVista handles image transfer over the network very well and most of the time I don't even notice that the third screen is not physically attached to my main computer.

Saturday, June 24, 2006

Compiler-generated getters and setters

(Sorry, not today. Maybe in a not-too-distant future.)

A very common task when implementing interfaces is writing getter and setter methods. In many cases, getters only access internal fields. In some cases, even setters only access internal fields. Still, we have to code those pesky methods by hand (or in a slightly simpler way using great ModelMaker Code Explorer - oh I like it so much!). I think that Delphi compiler could lend us a hand here and automatically generate trivial accessors when needed.

Let’s take a look at the example:

type
ISimpleInterface = interface
function GetProp1: integer;
procedure SetProp1(value: integer);
property Prop1: integer read GetProp1 write SetProp1;
end;
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
function GetProp1: integer;
procedure SetProp1(value: integer);
end;
{ TSimpleObject }
function TSimpleObject.GetProp1: integer;
begin
Result := FProp1;
end;
procedure TSimpleObject.SetProp1(value: integer);
begin
FProp1 := value;
end;

Even though we only want to implement the Prop1 property using direct access to a field, we still have to write two very dull methods.

We should be able to tell the compiler to do that for us. It is quite obvious that the compiler has enough data (it already knows the getter/setter signatures from the interface declaration) to generate both methods. The main question is how to instruct it to do so.

At the beginning I intended to abuse the ‘automated’ keyword (as it is already tokenized by the parser) like so:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer
public
property Prop1: integer read GetProp1 automated FProp1 write SetProp1 automated FProp1;
end;

This was not very optimal as it requires you to declare the Prop1 property in the TSimpleObject, which is not requirement per se when implementing interfaces.

Next idea was:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
property Prop1: integer read GetProp1 = FProp1 write SetProp1 = FProp1;
end;

It doesn’t abuse the ‘automated’ keyword but carries same problems.

My current favorite, suggested by a fellow programmer Lee_Nover, uses same syntax as method aliasing:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
function ISimpleInterface.GetProp1 = FProp1;
procedure ISimpleInterface.SetProp1 = FProp1;
end;

Although this syntax is very clear and self-describing, I would prefer to see a following simplified form:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
function GetProp1 = FProp1;
procedure SetProp1 = FProp1;
end;

So, dear reader, what do you think? If you like the suggestion, open QC #30533 and vote for it.

Friday, June 23, 2006

GpProfile, encore

Once upon a time, there was a nice little profiler called GpProfile. Admittedly, it could be better, faster, and more user friendly, but I wrote it and I liked it. That was then.

But now, now is seven years later and that is in programmer's years, which is 49 normal years. Or something like that. And those years are showing, trust me if I tell you.

So there came a time to rewrite the damn thing from scratch. I'm a great fan of Office 2007 GUI and I like to have my internals modularized and organised (OK, not really my internals ...) so the new version will have a nice clean look and even nicer and cleaner source code.

Just for teaser, here is the old interface:
GpProfile 1.3

and here's the new one:
GpProfile 2.0 alpha

There is always a beginning ...

And it is now. 20060623T201433 UTC.

(Hey, time is important. And time is interesting. I wrote an article on time a long time ago.)

If you want to know more about me, read the profile. Or Google me. Or ask. I'll tell. Or not.

Enough for now.

... and there is always an end. But we have yet to see when that will be.