Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / customdrawn / 2012-03

Some patches

21 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Giuliano Colla

Here enclosed a svn diff file with a number of patches.

1) I've modified AppRun and AppWaitMessage, in order to achieve a behavior similar to that of both GTK and Qt. This change makes mouse movements on the form to wake up the main loop (I think this to be necessary for hints on controls, and that's what both GTK and Qt do), and gets rid of an useless wake up of main loop each second. No adverse effects that I can tell. Most changes can be reverted by unsetting /CD_X11_UseLCL_MainLoop/.

2) I've fixed form repositioning on the screen, by removing a harmful XTranslateCoordinates in customdrawnforms_x11.

3) I've fixed the crash at the end of the program by modifying EvClientMessage always in customdrawnforms_X11. I left there a lengthy explanation on what SendCloseQueryMsg does, which can be suppressed without hesitation.

4) Again in customdrawnforms_X11 I've modified ShowHide, to fix the bug which didn't hide or close the second form in nonandroidtest.

5) I've fixed the double slashes on some font paths. Just a cosmetic fix, because Linux doesn't care, and TT_Load doesn't tamper with paths.

6) I inserted a different mechanism to handle timers, because I was unhappy with a timers behavior, which is, well, let's say, less than perfect. A resolution of one millisecond, and errors in the order of one second are a bit contradictory. I tested with a small application, and I compared the results with those obtained with GTK2 and Qt. Also GTK2 shows errors, but by far much smaller, while Qt is reasonably accurate.

Basically there are two flaws:

* GetSmallestTimerInterval isn't the best way to handle timers, if you have more than one. If two timers start approximately at the same time one with interval 700, the second with 1000, when the first one expires, the next to fire is the one with larger Interval, because it expires after 300 ms.
* Handling the timers in the AppWaitMessage (i.e. in the main thread) makes timing too much disturbed by external unpredictable events, like mouse activity on the form, other X events, OS scheduling, etc.

I tried to solve at least the first one by using a different technique, which I've been using since the dawn of times in my real time systems. A queue of timers, kept in order of firing, so that the head of the queue is always the first timer to handle. The queue is built as a double linked list, so that insertion and deletion are very fast. Actually, if there are no disturbances, the timing is much more accurate (even better than that of Qt), but when there are too many X events, and maybe some repaints, the timing becomes quite bad. Not a big step forward. One can revert to the old situation, by unsetting /CD_X11_UseNewTimer/.

The real solution would be to handle timers in a separate thread, which isn't disturbed by main thread events, and just send an appropriate message if and when a timer expires. In this context my queue could be much more useful than now. Other "native" widgetsets run in their own thread, or multiple threads, and this allows cleaner solutions. After all we have multitasking since more that forty years, multiple core CPU's since at least ten years: we're not obliged to put everything in a single thread as it was customary fifty years ago, when computers were powered by vacuum tubes instead of IC's.

That's all about the patches. I've also began to look what is required for ATI-SPI and ATK. I gathered that GLoop is only the top of the iceberg, and maybe not even of the right iceberg, but I'll tell in more detail another time.

Giuliano

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/customdrawn/attachments/20120330/b93b837a/attachment.html> -------------- next part --------------
A non-text attachment was scrubbed...
Name: commit.diff
Type: text/x-patch
Size: 19014 bytes
Desc: not available
URL: <http://lists.lazarus.freepascal.org/pipermail/customdrawn/attachments/20120330/b93b837a/attachment.bin>

Felipe Monteiro de Carvalho
to Giuliano Colla

Ok, everything great =) But on the timer I have some comments:

Giuliano Colla wrote
6) I inserted a different mechanism to handle timers...

Ok, I will apply the new timer but not make it default, because I think that the use case of lots of messages going around it a critically important use case, much more then precision when there are few events. The new timer would negatively affect LazClock heavily for example.

Felipe Monteiro de Carvalho
Michael Schnell
to Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho wrote 5 lines
Ok, I will apply the new timer but not make it default, because I think that the use case of lots of messages going around it a critically important use case, much more then precision when there are few events. The new timer would negatively affect LazClock heavily for example.

Regarding Timers:

This is one of the reasons that made me try to test Customdrawn.

I recon that it should be possible to use Customdrawn to create a project that has no local GUI (e.g.: no user interface at all or working "remote" by passing the GUI calls and events through a pipe, such as a Linux Fifo, a Windows messages based mechanism (to have some normal GUI "remote-control" program communicate with a Daemon / Service), a TCP/IP port or a serial interface (remote control from a different box). This also would enable doing long living (i.e. "embedded") CGI projects that use internal TTimers and allow communication via the WebServer.

To me this sound rather in sync with the effort necessary to do a decent Android GUI interface (using the Java-based Android libraries) which also seems to ask for a kind of "remote GUI".

For such purposes the TTimer and the thread communication (TThread.Synchronize and TApplication.QueueAsyncCall) need to work without any GUI binding that would provide an event queuing mechanism, but nonetheless GUI generated events need to be queued to be handled by the main thread one after the other.

I hope that there will be an (optional) Timer / Event Queue implementation that allows for all this.

-Michael

Felipe Monteiro de Carvalho
to Michael Schnell
Michael Schnell wrote
To me this sound rather in sync with the effort necessary to do a decent Android GUI interface (using the Java-based Android libraries) which also seems to ask for a kind of "remote GUI".

Some corrections:

1> The Android GUI is not remote. It does link to Java APIs, but that's not the same as remote. The link to Java is a very direct one with JNI. Our code runs as a library linked to the virtual machine executable and communicates directly with the virtual machine via normal plain procedures, just like one talks for example to Gtk (except that the roles are inverted, we are the library and the virtual machine the executable in Android). I wrote a "remote" LCL interface to Android in the past but I deleted it in favor of LCL-CustomDrawn. Remote stuff is always too slow when it comes to drawing graphics.

2> Each backend needs a separate timer implementation, so a theorical nogui backend would need it's own timer, although it could copy code from X11. The Android backend uses the timer provided by the Android API, so it does not need to implement this on it's own.

Felipe Monteiro de Carvalho
Michael Schnell
to Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho wrote
I wrote a "remote" LCL interface to Android in the past but I deleted it in favor of LCL-CustomDrawn. Remote stuff is always too slow when it comes to drawing graphics.

I see. Sounds like a good choice.

Each backend needs a separate timer implementation, so a theorical nogui backend would need it's own timer, although it could copy code from X11.

As long as there is a decent way to allow for such multiple backend implementations (e.g. if the common code provides abstract classes the actual backend code can be plugged in). This holds for any events that need to be queued to be handled by the main thread one after the other. May they generated by the User, a Timer, or a worker Thread.

The Android backend uses the timer provided by the Android API, so it does not need to implement this on it's own.

This of supposedly is the best performing implementation. OTOH this does not help with TThread.Synchronize() and Application.QueuAsyncCall() (and friends). Theses Events somehow need to mixed as targets towards the same Queue-Output as the GUI generated user and Timer events.

As you might know I wrote a testing program for this stuff

-Michael

Michael Schnell
to Michael Schnell
Michael Schnell wrote
As long as there is a decent way ...

By "decent", among other things, I mean that it should be not necessary to copy the code that simply implements an Event queue in Pascal. Same will be necessary for different backend implementations. The Queue will need to handle all events if there is no direct link to a GUI framework. If there is a GUI framework same might provide an Event queue, that also can be fed by worker threads (Windows works that way), or an event Queue without an input interface and thus asks for implementing a parallel Queue (GTK works that way).

At best this would even be done outside of CustomDrawn in a common effort for all "Widget Type" interfaces, but this of course would need to greatly modify the legacy code, which obviously is out of question. So doing this within CustomDrawn for all possible backends is the next best alternative.

Thanks,
-Michael

Felipe Monteiro de Carvalho
to Michael Schnell

Hello,

Some more patch comments:

1> TCDX11Timer should be added in customdrawn_x11proc.pas we should keep as few as possible stuff in customdrawnint.pas

2> Could you explain these 2 changes?

-    XFlush(FDisplay);
+    //XFlush(FDisplay);
     if XPending(FDisplay) > 0 then Exit; // We have a X message to process
@@ -562,9 +713,25 @@
     for i := 0 to XConnections.Count-1 do
       fpFD_SET(cint(PtrInt(XConnections.Items[i])), rfds);
-    selectresult := fpSelect(xconnnum + 1, @rfds, nil, nil, lTimeoutInterval);
+    selectresult := fpSelect(fpFD_SETSIZE, @rfds, nil, nil, lTimeoutInterval);

thanks,

Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho
to Felipe Monteiro de Carvalho

I thought of simply apply the patch and add the parts which I don't understand under a ifdef for the new loop. But applying fails, it looks like it conflicts with changes in the mean time.

Could you please regenerate it with my proposed changes?

thanks =)

Felipe Monteiro de Carvalho
Giuliano Colla
to Felipe Monteiro de Carvalho: Some more patch comments: 1> TCDX11Timer should be added in customdrawn_x11proc.pas we…

Il 30/03/2012 14:06, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 7 lines
Hello, Some more patch comments: 1> TCDX11Timer should be added in customdrawn_x11proc.pas we should keep as few as possible stuff in customdrawnint.pas

I'll do it ASAP, and send the revised patch. Unless you prefer do it yourself. Let me know.

Show quoted text 5 lines
2> Could you explain these 2 changes? - XFlush(FDisplay); + //XFlush(FDisplay);

Xpending which is called immediately after already performs an XFlush, therefore this call is unnecessary. xlib docs say that XFlush is normally pretty much useless, as the same function is performed by XPending, which is the standard way to check if there are pending messages:

http://tronche.com/gui/x/xlib/event-handling/XFlush.html

Harmless, but just to save an useless call.

Show quoted text 9 lines
if XPending(FDisplay)> 0 then Exit; // We have a X message to process @@ -562,9 +713,25 @@ for i := 0 to XConnections.Count-1 do fpFD_SET(cint(PtrInt(XConnections.Items[i])), rfds); - selectresult := fpSelect(xconnnum + 1, @rfds, nil, nil, lTimeoutInterval); + selectresult := fpSelect(fpFD_SETSIZE, @rfds, nil, nil, lTimeoutInterval);

The nfds parameter for the POSIX function select sets a limit to the set numbers which are taken into account (see man select). If you add other connections to your first one (xconnum), then you should put nfds equal to the highest connection number you have (which is not necessarily xconnum+1), otherwise some connections will not be considered: if you have two forms (as in androidtest), it's likely (but not 100% sure) that the connection for the second form will be xconnum+1, but if you open a third form (maybe a dialog, a popup, anything), the connection number may be xconnum+2 or more, and you won't receive any X message generated on that form.

This parameter becomes important only if you have added (via FD_SET) some connections, but
a) you don't want look at them
b) the ones you don't want to see are the highest in number which is very rarely the case.

In all practical situations it's normal practice to set nfds to a value high enough to encompass all your connection numbers, and enable the ones you want to check via FD_SET.
Delphi people, in Kylix, provided a default parameter FD_SETSIZE, with value 1024, which is good enough for any practical purpose. This parameter can still be found in fpc libc, but it has not been replicated in BaseUnix, which only includes the macros FD_ZERO and FD_SET. Therefore I've added it.

Giuliano

Felipe Monteiro de Carvalho
to Giuliano Colla
Giuliano Colla wrote
> 2> ?Could you explain these 2 changes? Xpending which is called immediately after already performs an XFlush, ...

Ok, so please add comments into the code about those issues then =)

Comments are never too many =)

Felipe Monteiro de Carvalho
Giuliano Colla
to Felipe Monteiro de Carvalho: I thought of simply apply the patch and add the parts which I don't understand under a…

Il 30/03/2012 15:05, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 6 lines
I thought of simply apply the patch and add the parts which I don't understand under a ifdef for the new loop. But applying fails, it looks like it conflicts with changes in the mean time. Could you please regenerate it with my proposed changes?

ASAP.
Giuliano

Giuliano Colla
to Felipe Monteiro de Carvalho: I thought of simply apply the patch and add the parts which I don't understand under a…

Il 30/03/2012 15:05, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 7 lines
I thought of simply apply the patch and add the parts which I don't understand under a ifdef for the new loop. But applying fails, it looks like it conflicts with changes in the mean time. Could you please regenerate it with my proposed changes? thanks =)

Here's a new diff, against last revision.
I have added some comments, and moved TCDX11Timer from customdrawnint to customdrawn_x11proc.
I've added there the include of customdrawndefines, and uses CustomDrawnInt but under ifdef.

Conflicts were caused by very stupid things, such as a blank line before an ifdef.

I hope that it works. Here it does.

Giuliano

-------------- next part --------------
A non-text attachment was scrubbed...
Name: Commit.diff
Type: text/x-patch
Size: 20585 bytes
Desc: not available
URL: <http://lists.lazarus.freepascal.org/pipermail/customdrawn/attachments/20120330/2e2dbace/attachment-0001.bin>

Giuliano Colla
to Felipe Monteiro de Carvalho: Ok, everything great =) But on the timer I have some comments: On Fri, Mar 30, 2012 at…

Il 30/03/2012 08:58, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 11 lines
Ok, everything great =) But on the timer I have some comments: On Fri, Mar 30, 2012 at 1:50 AM, Giuliano Colla wrote: > 6) I inserted a different mechanism to handle timers... Ok, I will apply the new timer but not make it default, because I think that the use case of lots of messages going around it a critically important use case, much more then precision when there are few events. The new timer would negatively affect LazClock heavily for example.

Maybe you've had no time to look at it in detail. Actually there's absolutely no difference in the amount of messages going around, with respect with the old timer.
There are just two differences:

1) You don't need to scan all the list to know which one is the first timer which will expire, because it's always at the head of the list. The list is scanned only when either a timer expires, or when a new timer in inserted, and then not completely, but only to the point where the timer must be inserted.

2) Each timer doesn't carry only the interval information, but also at which moment it is expected to fire, which can make it much more exact, provided the main thread isn't busy doing something else.

Felipe Monteiro de Carvalho
to Giuliano Colla: Il 30/03/2012 15:05, Felipe Monteiro de Carvalho ha scritto: Here's a new diff, against…
Giuliano Colla wrote 5 lines
Here's a new diff, against last revision. I have added some comments, and moved TCDX11Timer from customdrawnint to customdrawn_x11proc. I've added there the include of customdrawndefines, and uses CustomDrawnInt but under ifdef.

Hello,

Ok, now this is a pretty excellent patch with many comments =)

I applied it, but I had to disabled the new timer by default because it crashes one of our test cases:

lazarus/examples/android/nonandroidtest.lpi

It probably crashes the timer of TCDEdit

Sorry for the long delay in applying, but in weekends I am less available.

I think that we should consider from now on giving you direct commit rights to the customdrawn directory. 1.0 was already branched so there will be a long time till trunk becomes a release again and clearly you know more about X11 then I do. And I am also focused in the Android and Cocoa backends now.

My main challange now is to speed up the painting. I already wrote many optimizations, but it is still too slow in the Virtual Magnifying Glass, which is a full screen application which makes custom drawings. In this case there is no easy way to cache operations because it really repaints the entire screen each time.

It also could be faster in scrolling the form in Android.

Felipe Monteiro de Carvalho
Giuliano Colla
to Felipe Monteiro de Carvalho

Il 02/04/2012 09:52, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 18 lines
On Fri, Mar 30, 2012 at 9:50 PM, Giuliano Colla wrote: > Here's a new diff, against last revision. > I have added some comments, and moved TCDX11Timer from customdrawnint to > customdrawn_x11proc. > I've added there the include of customdrawndefines, and uses CustomDrawnInt > but under ifdef. Hello, Ok, now this is a pretty excellent patch with many comments =) I applied it, but I had to disabled the new timer by default because it crashes one of our test cases: lazarus/examples/android/nonandroidtest.lpi It probably crashes the timer of TCDEdit

I have used nonandroidtest as one of my benchmark programs, and here it worked just fine.
I'll look again once I've updated from svn (now I must go to the dentist! -( )

Sorry for the long delay in applying, but in weekends I am less available.

This will be considered in your next salary! =)

Show quoted text 6 lines
I think that we should consider from now on giving you direct commit rights to the customdrawn directory. 1.0 was already branched so there will be a long time till trunk becomes a release again and clearly you know more about X11 then I do. And I am also focused in the Android and Cocoa backends now.

I also believe it would make things run more smoothly. I would not touch anything non X11 specific without your previous approval, of course.

Show quoted text 6 lines
My main challange now is to speed up the painting. I already wrote many optimizations, but it is still too slow in the Virtual Magnifying Glass, which is a full screen application which makes custom drawings. In this case there is no easy way to cache operations because it really repaints the entire screen each time.

Coming back from dentist! =)

This is your domain. My ideas stop at "only update what's necessary", unless you're willing to implement some more deep changes.

A solution I've frequently used in other fields, is to use multiple buffers, and a separate thread.

A separate thread for painting means, on modern MPU's, that painting occurs in parallel with other activities. Multiple buffers means that the client thread just fills up the next available buffer, and then continues its processing. If the client thread fills buffers at a faster rate than the painting thread can handle, the painting thread just skips some updates. The user don't notice it, because what gets painted is always the most recent image.
It works like that: the painting engine running in its thread, gets a buffer to paint. When it's done, it frees the buffer, and looks if there are more buffers to paint. If there's more than one, it frees all except the last one, and paints the last one. That way you always paint the most recent buffer.

It's not a child's play to implement, because you must find the right splitting of operations, in order to give each thread an appropriate amount of work to do. Then you must activate multithreading (which in Lazarus isn't enabled by default, in Unix environment), define what must be thread-safe, and what not, etc. etc.

But if slowness is not an X11-only issue, then this approach should be considered. After all that's the reason why other widgesets are faster. It is not that they're smarter in painting than you. They just distribute activity between the main thread and their own threads.

It also could be faster in scrolling the form in Android.

See above.

Giuliano

Felipe Monteiro de Carvalho
to Giuliano Colla
Giuliano Colla wrote
But if slowness is not an X11-only issue, then this approach should be considered. After all that's the reason why other widgesets are faster. It is not that they're smarter in painting than you. They just distribute activity between the main thread and their own threads.

One of my main interrests now in LCL-CustomDrawn is using it to build the next Mac OS X release of the Virtual Magnifying Glass. The VMG takes a fullscreen screenshot and draws it and then draws a movable lens in the screen which magnifies part of the screen.

The nasty thing is that it works so fast in LCL-Win32, even in a huge screen, really extremelly fast despite painting the entire screen in every single drawing operation and doing a very large number of refreshes because it needs to follow the mouse (I'd say it makes at least 20FPS). In LCL-Gtk2 in Linux it is also fast, I think that LCL-Qt in Linux too.

But then in LCL-Carbon, LCL-Qt (running in Mac OS X) and also in LCL-CustomDrawn-Cocoa it is far too slow. (LCL-Cocoa can't run it so cannot compare the result, but surely will be very slow).

And this is a huge shock. Why is in Windows so much faster? Maybe some Mac limitation since even Qt is slow there? Or can I do something? Since I have full control of the source code I'd like to do everything in my power to make it fast and be able to make my release.

I think it will probably be slow in LCL-CustomDrawn-X11, although I haven't tested yet since it requires screenshot support and this backend lacks this feature. It would be really interresting to investigate how to make screenshots in X11 and implement this to test the Virtual Magnifying Glass.

Felipe Monteiro de Carvalho
Giuliano Colla
to Felipe Monteiro de Carvalho

Il 02/04/2012 14:56, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 11 lines
On Mon, Apr 2, 2012 at 12:27 PM, Giuliano Colla wrote: > But if slowness is not an X11-only issue, then this approach should be > considered. After all that's the reason why other widgesets are faster. It > is not that they're smarter in painting than you. They just distribute > activity between the main thread and their own threads. One of my main interrests now in LCL-CustomDrawn is using it to build the next Mac OS X release of the Virtual Magnifying Glass. The VMG takes a fullscreen screenshot and draws it and then draws a movable lens in the screen which magnifies part of the screen.

...

Show quoted text 6 lines
I think it will probably be slow in LCL-CustomDrawn-X11, although I haven't tested yet since it requires screenshot support and this backend lacks this feature. It would be really interresting to investigate how to make screenshots in X11 and implement this to test the Virtual Magnifying Glass.

I think that what you need is XGetImage:

http://tronche.com/gui/x/xlib/graphics/XGetImage.html

which will return a pointer to an XImage structure, described here:

http://tronche.com/gui/x/xlib/graphics/images.html#XImage

(as you already know, because you've used it in DrawRawImageToGc_XPutimage)

XGetImage is defined in Xlib, so it should be a child play for you to implement it.

The only difference with your XPutImage call is that you get an XImage instead of sending one, and that the window you must use isn't the form window, but the root window of the display.

You may obtain the root window with a call to XRootWindow, or XDefaultRootWindow. (it makes a difference only if you have more than one display, e.g. using Xinerama)

Then you'll need to perform the conversion, in order to transform the raw image in the format you need.

I've never used that myself. It's also possible that that way you get only the desktop background, but the only way to know is to test.

Giuliano

Giuliano Colla
to Giuliano Colla

Il 03/04/2012 00:56, Giuliano Colla ha scritto:

Show quoted text 48 lines
Il 02/04/2012 14:56, Felipe Monteiro de Carvalho ha scritto: > On Mon, Apr 2, 2012 at 12:27 PM, Giuliano Colla > wrote: >> But if slowness is not an X11-only issue, then this approach should be >> considered. After all that's the reason why other widgesets are >> faster. It >> is not that they're smarter in painting than you. They just distribute >> activity between the main thread and their own threads. > One of my main interrests now in LCL-CustomDrawn is using it to build > the next Mac OS X release of the Virtual Magnifying Glass. The VMG > takes a fullscreen screenshot and draws it and then draws a movable > lens in the screen which magnifies part of the screen. > ... > I think it will probably be slow in LCL-CustomDrawn-X11, although I > haven't tested yet since it requires screenshot support and this > backend lacks this feature. It would be really interresting to > investigate how to make screenshots in X11 and implement this to test > the Virtual Magnifying Glass. > I think that what you need is XGetImage: http://tronche.com/gui/x/xlib/graphics/XGetImage.html which will return a pointer to an XImage structure, described here: http://tronche.com/gui/x/xlib/graphics/images.html#XImage (as you already know, because you've used it in DrawRawImageToGc_XPutimage) XGetImage is defined in Xlib, so it should be a child play for you to implement it. The only difference with your XPutImage call is that you get an XImage instead of sending one, and that the window you must use isn't the form window, but the root window of the display. You may obtain the root window with a call to XRootWindow, or XDefaultRootWindow. (it makes a difference only if you have more than one display, e.g. using Xinerama) Then you'll need to perform the conversion, in order to transform the raw image in the format you need. I've never used that myself. It's also possible that that way you get only the desktop background, but the only way to know is to test.

I've verified that with XGetImage on the root window you really get the image of your screen, and not only the desktop background:

http://www.copeca.it/colla/snap1.jpg

If you give me some hints (e.g. which backend supports screen capture, where it's implemented, and how the main program uses that feature. IOW which are the source files to look at), I can try and do the same for X11, just to see what happens.

Giuliano

Felipe Monteiro de Carvalho
to Giuliano Colla
Giuliano Colla wrote
I've verified that with XGetImage on the root window you really get the image of your screen, and not only the desktop background: http://www.copeca.it/colla/snap1.jpg

Great! =)

If you give me some hints (e.g. which backend supports screen capture, where it's implemented, and how the main program uses that feature. IOW which are the source files to look at), I can try and do the same for X11, just to see what happens.

I am already starting to forget what was already implemented and where ... because this thing has just grown huge =)

But the Cocoa backend supports screenshot taking.

From the LCL side the screenshot is TBitmap.LoadFromDevice which will

call customdrawnlclintfh.inc this routine:

function RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const
ARect: TRect): Boolean; override;

Each backend needs to implement this routine so implement it in customdrawnlclintf_x11.inc

See how Cocoa does it:

function TCDWidgetSet.RawImage_FromDevice(out ARawImage: TRawImage;
ADC: HDC; const ARect: TRect): Boolean;
var
  screenshotImage: CGImageRef;
  lRect: CGRect;
  lScreenRawImage: TRawImage;
  lDataLength: Integer;
begin
  Result := True;
  ARawImage.Init;
  ARawImage.Description.Init_BPP32_A8R8G8B8_BIO_TTB(ScreenBitmapWidth,
ScreenBitmapHeight);
  // Take the screenshot
  screenshotImage := CGDisplayCreateImage(CGMainDisplayID()); // Requires 10.6+
  // Draw it to our screen bitmap
  lRect := CGRectMake(0, 0, ScreenBitmapWidth, ScreenBitmapHeight);
  CGContextDrawImage(ScreenBitmapContext, lRect, screenshotImage);
  // Now copy the data
  ScreenImage.GetRawImage(lScreenRawImage, False);
  ARawImage.CreateData(False);
  lDataLength := Min(lScreenRawImage.DataSize, ARawImage.DataSize);
  System.Move(lScreenRawImage.Data^, ARawImage.Data^, lDataLength);
end;
Felipe Monteiro de Carvalho
Giuliano Colla
to Felipe Monteiro de Carvalho

Il 03/04/2012 10:40, Felipe Monteiro de Carvalho ha scritto:

Show quoted text 15 lines
On Tue, Apr 3, 2012 at 10:29 AM, Giuliano Colla wrote: > I've verified that with XGetImage on the root window you really get the > image of your screen, and not only the desktop background: > > http://www.copeca.it/colla/snap1.jpg Great! =) > If you give me some hints (e.g. which backend supports screen capture, where > it's implemented, and how the main program uses that feature. IOW which are > the source files to look at), I can try and do the same for X11, just to see > what happens. I am already starting to forget what was already implemented and where ... because this thing has just grown huge =)

Sometimes I think that virtual abstract things have been conceived to make life harder.
They would be great if you wanted to change widgetset on the fly (which isn't very usual...), but if you're trying to follow the path of anything starting from LCL, you're stuck at a virtual abstract declaration, and either you remember how it's been implemented, or you must single step in debug! You save a few ifdefs, and you loose hours trying to reconstruct what you've done!

Show quoted text 16 lines
But the Cocoa backend supports screenshot taking. From the LCL side the screenshot is TBitmap.LoadFromDevice which will call customdrawnlclintfh.inc this routine: function RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean; override; Each backend needs to implement this routine so implement it in customdrawnlclintf_x11.inc See how Cocoa does it: function TCDWidgetSet.RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean; var

.....
I think that X11 will look pretty much the same.
Thanks,

Giuliano

Michael Schnell
to Michael Schnell: By "decent", among other things, I mean that it should be not necessary to copy the code…
Michael Schnell wrote 5 lines
At best this would even be done outside of CustomDrawn in a common effort for all "Widget Type" interfaces, but this of course would need to greatly modify the legacy code, which obviously is out of question. So doing this within CustomDrawn for all possible backends is the next best alternative.

I learned that for v 1.x , now Lazarus has a packet called "LCLBase".

Same of course is the perfect location for an "Event Queue" class that is versatile enough to be used (e.g. doing and instanciating a derived class) with all "Widget Types" (aka "Interfaces" / "Platforms" / "Backends" ...) that need a Queue implementation in Pascal code (i.e. AFAIK all of them but Windows).

-Michael