Recent

Author Topic: how to use SetSysColors?  (Read 1480 times)

robert rozee

  • Sr. Member
  • ****
  • Posts: 254
how to use SetSysColors?
« on: February 12, 2025, 02:20:20 pm »
can anyone tell me how to use the function SetSysColors?

O/S is x86-64 Linux Mint 22 XFCE, widgetset is GTK2, Lazarus 3.6, FPC 3.2.2

i have this code in a program that compiles fine, and consists of just a form and a button:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var C:TColor;
  3.     I:LongInt;
  4. begin
  5.   I:=COLOR_BACKGROUND;
  6.   C:=clRed;
  7.   SetSysColors(1, I, C)
  8. end;
  9.  

the constant COLOR_BACKGROUND is defined in LCLType and equals 1.

when i click on the button i get this:

Project project1 raised exception class 'External: SIGSEGV'.
In file 'gtk2winapi.inc' at line 9066


and the IDE takes me to here:

Code: Pascal  [Select][+][-]
  1. {------------------------------------------------------------------------------
  2.   Function: SetSysColors
  3.   Params:  cElements: the number of elements
  4.            lpaElements: array with element numbers
  5.            lpaRgbValues: array with colors
  6.   Returns: 0 if unsuccesful
  7.  
  8.   The SetSysColors function sets the colors for one or more display elements.
  9.  ------------------------------------------------------------------------------}
  10. function TGtk2WidgetSet.SetSysColors(cElements: Integer; const lpaElements;
  11.   const lpaRgbValues): Boolean;
  12. var
  13.   n: Integer;
  14.   Element: LongInt;
  15. begin
  16.   Result := False;
  17.   if cElements > MAX_SYS_COLORS then Exit;
  18.  
  19.   for n := 0 to cElements - 1 do
  20.   begin
  21.     Element := PInteger(lpaElements)[n];
  22.     if (Element > MAX_SYS_COLORS) or (Element < 0) then
  23.       Exit;
  24.     SysColorMap[Element] := PDword(@lpaRgbValues)[n];
  25.     //DebugLn(Format('Trace:[TGtk2WidgetSet.SetSysColor] Index %d (%8x) --> %8x', [PLongArray(lpaElements)^[n], SysColorMap[PLongArray(lpaElements)^[n]], PLongArray(lpaRgbValues)^[n]]));
  26.   end;
  27.  
  28.   //TODO send WM_SYSCOLORCHANGE
  29.   Result := True;
  30. end;

with line 9066 being:

    Element := PInteger(lpaElements)[n];

(line 21 in the above)


would much appreciate any help.


cheers,
rob   :-)

« Last Edit: February 12, 2025, 02:29:34 pm by robert rozee »

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: how to use SetSysColors?
« Reply #1 on: February 12, 2025, 02:47:19 pm »
Function describes to be requiring arrays with values, not values themselves ?
Today is tomorrow's yesterday.

Zvoni

  • Hero Member
  • *****
  • Posts: 2895
Re: how to use SetSysColors?
« Reply #2 on: February 12, 2025, 03:32:49 pm »
?
Code: Pascal  [Select][+][-]
  1. SetSysColors(1, [I], [C])

Or (untested)
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var C:Array Of TColor;
  3.     I:Array Of LongInt;
  4. begin
  5.     SetLength(I,1);
  6.     SetLength(C,1);
  7.     I[0]:=COLOR_BACKGROUND;
  8.     C[0]:=clRed;
  9.     SetSysColors(1, I, C)
  10. end;
« Last Edit: February 12, 2025, 03:36:24 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: how to use SetSysColors?
« Reply #3 on: February 12, 2025, 03:39:29 pm »
Nah, the first won't compile. The second does (and is imho how it should be done) but.... Is there anything else that changes the colours ? Because I seem unable to locate the value clred at the syscolormap when debugging.
Today is tomorrow's yesterday.

Zvoni

  • Hero Member
  • *****
  • Posts: 2895
Re: how to use SetSysColors?
« Reply #4 on: February 12, 2025, 03:41:35 pm »
Nah, the first won't compile. The second does (and is imho how it should be done) but.... Is there anything else that changes the colours ? Because I seem unable to locate the value clred at the syscolormap when debugging.
Uses LCLType?
I remember having to include it in Uses to get access to the values.

Or i missed your meaning completely
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: how to use SetSysColors?
« Reply #5 on: February 12, 2025, 03:54:53 pm »
I remember having to include it in Uses to get access to the values.
Yeah, no it was not about that.

this
Code: Pascal  [Select][+][-]
  1.     SetSysColors(1, [I], [C])
  2.  

throws:
Code: [Select]
unit1.pas(77,25) Error: Variable identifier expected
for [i] and [C]

The second example does seem to work:
Code: Pascal  [Select][+][-]
  1. var
  2.   colvalues : array of TColor  = (clRed);
  3.   colmapidx : array of integer = (COLOR_BACKGROUND);
  4.  
  5. procedure TForm1.Button1Click(Sender: TObject);
  6. begin
  7.   SetSysColors(length(colvalues), colmapidx, colvalues);
  8. end;
  9.  

But knowing that COLOR_BACKGROUND = 1 and clred = $0000ff, syscolormap shows
Code: [Select]
Len=32: (11184810,
8570064,
5675641,
9737364,
16777215,
16250871,
9618860,
2894892,
2894892,
16777215,
13290186,
13290186,
16250871,
8176544,
16119285,
13290186,
9276813,
9737364,
2894892,
16777215,
16777215,
0,
13290186,
0,
11924981,
0,
16777215,
13627616,
16250871,
9096620,
13948116,
13948116)
Which (if I did my calculations correctly) does not show/contain clRed.

PS: to avoid any confusion about integer vs longint, my setsyscolors reads:
Code: Pascal  [Select][+][-]
  1. function TGtk2WidgetSet.SetSysColors(cElements: Integer; const lpaElements;
  2.   const lpaRgbValues): Boolean;
  3. var
  4.   n: Integer;
  5.   Element: LongInt;
  6. begin
  7.   Result := False;
  8.   if cElements > MAX_SYS_COLORS then Exit;
  9.  
  10.   for n := 0 to cElements - 1 do
  11.   begin
  12.     Element := PInteger(lpaElements)[n];
  13.     if (Element > MAX_SYS_COLORS) or (Element < 0) then
  14.       Exit;
  15.     SysColorMap[Element] := PDword(@lpaRgbValues)[n];
  16.     //DebugLn(Format('Trace:[TGtk2WidgetSet.SetSysColor] Index %d (%8x) --> %8x', [PLongArray(lpaElements)^[n], SysColorMap[PLongArray(lpaElements)^[n]], PLongArray(lpaRgbValues)^[n]]));
  17.   end;
  18.  
  19.   //TODO send WM_SYSCOLORCHANGE
  20.   Result := True;
  21. end;
  22.  
Which casts the element as integer;

« Last Edit: February 12, 2025, 03:59:03 pm by TRon »
Today is tomorrow's yesterday.

robert rozee

  • Sr. Member
  • ****
  • Posts: 254
Re: how to use SetSysColors?
« Reply #6 on: February 13, 2025, 11:14:11 am »
many thanks for everyone's replies. although, the solution (that it turns out doesn't work as i wanted) was a slight variation:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var C:array of TColor;
  3.     I:array of LongInt;
  4. begin
  5.   setlength(I, 2);
  6.   setlength(C, 2);
  7.   I[0]:=COLOR_FORM;
  8.   C[0]:=clLime;
  9.   I[1]:=COLOR_BACKGROUND;
  10.   C[1]:=clRed;
  11.   SetSysColors(length(I), I, C[0]);
  12.   Label1.Caption:='clBackGround' +#13+ 'clForm';
  13.   Label2.Caption:='0x'+IntToHex(clBackground, 8) +#13+ '0x'+IntToHex(clForm,       8);
  14.   Label3.Caption:='0x'+IntToHex(WidgetSet.GetSysColor(COLOR_BACKGROUND)) +#13+
  15.                   '0x'+IntToHex(WidgetSet.GetSysColor(COLOR_FORM))
  16. end;

notice we need to pass C[0] as the last parameter, not just C.

this produces the results, returned by GetSysColor...

before clicking button1    clBackGround maps to    0x00F5F5F5
clForm maps to 0x00F0F0F0
 
after clicking button1       clBackGround maps to    0x000000FF
clForm map to 0x0000FF00

but unfortunately NONE OF THIS had any effect on the colours of components in the running application!

attached is my test program, it has two buttons - button2 displays an InputQuery window, button1 should reassign the colours. so:
  • observe the numbers displayed,
  • click button2,
  • close the Input query,
  • click button1,
  • observe the numbers,
  • click button 2 and nothing has changed   >:(

any ideas?


cheers,
rob   :-)
« Last Edit: February 13, 2025, 11:16:03 am by robert rozee »

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: how to use SetSysColors?
« Reply #7 on: February 13, 2025, 11:19:05 am »
I had the same question so went on a quest  :)

There is a very informative hint inside the sources at syscolormap (gtkglobals.pp)
Quote
// PDB: note this is a hack. Windows maintains a system wide
//      system color table we will have to have our own
//      to be able to do the translations required from
//      window manager to window manager this means every
//      application will carry its own color table
//      we set the defaults here to reduce the initial
//      processing of creating a default table
// MWE: Naaaaah, not a hack, just something temporary
e.g, it seems to be treated as a pass-through table.
« Last Edit: February 13, 2025, 11:22:17 am by TRon »
Today is tomorrow's yesterday.

robert rozee

  • Sr. Member
  • ****
  • Posts: 254
Re: how to use SetSysColors?
« Reply #8 on: February 13, 2025, 12:43:38 pm »
e.g, it seems to be treated as a pass-through table.

hmmm, i feared that may be the situation, in which case SetSysColors should not really be exposed as a function accessible to programmers. unless, of course, there is some way to tell the LCL to reload from the 'System Colour Map'!

hmmm #2: the above makes me wonder if we could somehow access SetSysColors just before or after Application.Initialize?
answer: NO. adding Graphics, LCLType, LCLintf to project1.lpr allows us to call SetSysColors, but no matter where i place it before/after  Application.Initialize or Application.CreateForm has no effect.

any idea who PDB and MWE are?

btw - my end goal is to be able to significantly change system colours in a running application, so as to identify places where 'style bugs' exist - like the (sometimes observable) slightly different shade of grey of a ButtonPanel (or just a regular Panel) placed on a Form.


cheers,
rob   :-)
« Last Edit: February 13, 2025, 12:58:41 pm by robert rozee »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10897
  • Debugger - SynEdit - and more
    • wiki
Re: how to use SetSysColors?
« Reply #9 on: February 13, 2025, 12:54:47 pm »
MWE might be Marc (as in admin of this forum).

PDB - no idea. (If those are initials, then likely no longer active)

Thaddy

  • Hero Member
  • *****
  • Posts: 16625
  • Kallstadt seems a good place to evict Trump to.
Re: how to use SetSysColors?
« Reply #10 on: February 13, 2025, 12:55:44 pm »
First check with export without parameters if they are accessible.
If they are, you can change them in code, otherwise unlikely or difficult,
But I am sure they don't want the Trumps back...

TRon

  • Hero Member
  • *****
  • Posts: 4133
Re: how to use SetSysColors?
« Reply #11 on: February 13, 2025, 12:56:41 pm »
Indeed, MWE is MarcW, PDB is most probably Paul (but to my knowledge not active anymore).

BTW typo, it should have read gtkglobals2.pp

BTW2: if you do a grep on the sources for syscolormap then you are able to locate all kind of related procs/funcs such as f.e. UpdateSysColorMap, InitSystemColors etc.
« Last Edit: February 13, 2025, 01:04:46 pm by TRon »
Today is tomorrow's yesterday.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10897
  • Debugger - SynEdit - and more
    • wiki
Re: how to use SetSysColors?
« Reply #12 on: February 13, 2025, 01:07:31 pm »
Indeed, MWE is MarcW, PDB is most probably Paul (but to my knowledge not active anymore).

Not sure if there was another Paul back then. The Paul (P.I.) that I know (and that is not active now) joined later. This comment is from 2002.


Also I doubt that SetSysColors will work, or even can work. Not sure about gtk... But in other WS many elements are painted by the OS (or the installed Desktop, like gtk libs) directly. So unless those have an API to accept those changes, SetSysColors can only affect custom painted parts.
I don't know if gtk2 has such an API, and if it has which versions support it, and in combination with which other dependencies....

robert rozee

  • Sr. Member
  • ****
  • Posts: 254
Re: how to use SetSysColors?
« Reply #13 on: February 13, 2025, 01:37:56 pm »
Indeed, MWE is MarcW, PDB is most probably Paul (but to my knowledge not active anymore).
[...]
related procs/funcs such as f.e. UpdateSysColorMap, InitSystemColors etc.

how do i get in touch with MarcW, and will he even be interested in any of this?

UpdateSysColorMap and InitSystemColors look interesting, but i can't for the life of me figure out what unit i need to add to uses to access them!

think i'll give up for the night... it is 1:40am here. so far my bug report on gitlab seems to have gone nowhere   :-(


cheers,
rob   :-)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10897
  • Debugger - SynEdit - and more
    • wiki
Re: how to use SetSysColors?
« Reply #14 on: February 13, 2025, 02:34:43 pm »
I pinged him.

 

TinyPortal © 2005-2018