It is currently March 28th, 2024, 4:21 pm

Plugin: Chameleon

Plugins and Addons popular with the Community
User avatar
StArL0rd84
Posts: 424
Joined: February 8th, 2015, 10:07 pm
Location: EU, Denmark.

Re: Plugin: Chameleon

Post by StArL0rd84 »

Have run into a issue with my skin which is a menu based skin.
A main menu measure controls the menu which shows or hides content of the tabs.
It also changes the colors of the tab icons in the menu with !SetOption.
The colors of these icons wont change whenever i change the wallpaper, everything else does.
And i have it set up with a chameleon-switch to turn chameleon on or off.
The image used in the switch does not change color either, because the color has been set by the switch measure previously.
And i have DynamicVariables=1 on both meters and measures.
What is happening here?

Code: Select all

[ChameleonSwitch]
 Meter=Image
 LeftMouseUpAction=[!WriteKeyValue Variables ChameleonMode "(1-#ChameleonMode#)" "#Var#"][!SetVariable ChameleonMode "(1-#ChameleonMode#)"][!UpdateMeasure mChameleonMode][!UpdateMeter *][!Redraw] 
 X=2
 Y=100
 W=88
 H=44
 DynamicVariables=1
 SolidColor=#FGColor1#
 Hidden=1
 Group=ColorComponents

[mChameleonMode]
 Measure=Calc
 Formula=#ChameleonMode#
 DynamicVariables=1
 IfEqualValue=0
 IfEqualAction=[!EnableMeasureGroup Chameleon][!SetOption ChameleonSwitch SolidColor #FGColor2#][!SetOption ChameleonSwitch X 99][!UpdateMeter *][!Redraw]
 IfAboveValue=0
 IfAboveAction=[!DisableMeasureGroup Chameleon][!SetOption ChameleonSwitch SolidColor #FGColor1#][!SetOption ChameleonSwitch X 2][!UpdateMeter *][!Redraw]
 UpdateDivider=-1
 Disabled=1
 Group=ColorMeasures

[ChameleonDesktop]
 Measure=Plugin
 Plugin=Chameleon
 Type=Desktop
 Disabled=1
 Group=Chameleon

[ChameleonBackground1]
 Measure=Plugin
 Plugin=Chameleon
 Parent=ChameleonDesktop
 Format=Dec
 Color=Background1
 Disabled=1
 Group=Chameleon
 IfMatch=#BGColor1#
 IfNotMatchAction=[!SetVariable BGColor1 [ChameleonBackground1]][!WriteKeyValue Variables BGColor1 "[ChameleonBackground1]" "#Var#"][!UpdateMeter *][!Redraw]
 DynamicVariables=1

[ChameleonBackground2]
 Measure=Plugin
 Plugin=Chameleon
 Parent=ChameleonDesktop
 Format=Dec
 Color=Background2
 Disabled=1
 Group=Chameleon
 IfMatch=#BGColor2#
 IfNotMatchAction=[!SetVariable BGColor2 [ChameleonBackground2]][!WriteKeyValue Variables BGColor2 "[ChameleonBackground2]" "#Var#"][!UpdateMeter *][!Redraw]
 DynamicVariables=1

[ChameleonForeground1]
 Measure=Plugin
 Plugin=Chameleon
 Parent=ChameleonDesktop
 Format=Dec
 Color=Foreground1
 Disabled=1
 Group=Chameleon
 IfMatch=#FGColor1#
 IfNotMatchAction=[!SetVariable FGColor1 [ChameleonForeground1]][!WriteKeyValue Variables FGColor1 "[ChameleonForeground1]" "#Var#"][!UpdateMeter *][!Redraw]
 DynamicVariables=1

[ChameleonForeground2]
 Measure=Plugin
 Plugin=Chameleon
 Parent=ChameleonDesktop
 Format=Dec
 Color=Foreground2
 Disabled=1
 Group=Chameleon
 IfMatch=#FGColor2#
 IfNotMatchAction=[!SetVariable FGColor2 [ChameleonForeground2]][!WriteKeyValue Variables FGColor2 "[ChameleonForeground2]" "#Var#"][!UpdateMeter *][!Redraw]
 DynamicVariables=1
 
[mMainMenu]
 Measure=Calc
 Formula=#MainMenuMode#
 DynamicVariables=1
 IfCondition=mMainMenu=1
 IfTrueAction=[!SetOption MainMenu1 ImageTint #FGColor2#]#OtherMenuActions#[!UpdateMeter *][!Redraw]
 IfFalseAction=[!SetOption MainMenu1 ImageTint #FGColor1#][!UpdateMeter *][!Redraw]
 IfCondition2=mMainMenu=2
 IfTrueAction2=[!SetOption MainMenu2 ImageTint #FGColor2#]#OtherMenuActions#[!UpdateMeter *][!Redraw]
 IfFalseAction2=[!SetOption MainMenu2 ImageTint #FGColor1#][!UpdateMeter *][!Redraw]

[MainMenu1]
 Meter=Image
 ImageName=#@#Images\Icons\UI\Programs.png
 LeftMouseUpAction=[!WriteKeyValue Variables MainMenuMode "1" "#Var#"][!SetVariable MainMenuMode "1"][!UpdateMeasure mMainMenu][!UpdateMeter *][!Redraw]
 ImageTint=#FGColor1#
 X=10
 Y=55
 DynamicVariables=1
 AntiAlias=1
 Group=MenuComponents
 
[MainMenu2]
 Meter=Image
 ImageName=#@#Images\Icons\UI\Folders.png
 LeftMouseUpAction=[!WriteKeyValue Variables MainMenuMode "2" "#Var#"][!SetVariable MainMenuMode "2"][!UpdateMeasure mMainMenu][!UpdateMeter *][!Redraw]
 ImageTint=#FGColor1#
 X=r
 Y=48r
 DynamicVariables=1
 AntiAlias=1
 Group=MenuComponents
User avatar
eclectic-tech
Rainmeter Sage
Posts: 5382
Joined: April 12th, 2012, 9:40 pm
Location: Cedar Point, Ohio, USA
Contact:

Re: Plugin: Chameleon

Post by eclectic-tech »

After adding a few local variables, I see you are trying to update a disabled measure in the LeftMouseUpAction of [ChameleonSwitch]; [mChameleonMode] is disabled in this code. I enabled the measure, then updated it.

Code: Select all

[Variables]
MainMenuMode=1
ChameleonMode=0

[ChameleonSwitch]
 Meter=Image
 LeftMouseUpAction=[!WriteKeyValue Variables ChameleonMode "(1-#ChameleonMode#)" "#Var#"][!SetVariable ChameleonMode "(1-#ChameleonMode#)"][!EnableMeasure mChameleonMode][!UpdateMeasure mChameleonMode][!UpdateMeter *][!Redraw]
This seems to work with the posted code... not sure what you have in the code not posted, that enables/disables the [mChameleonMode] section. :???:
User avatar
StArL0rd84
Posts: 424
Joined: February 8th, 2015, 10:07 pm
Location: EU, Denmark.

Re: Plugin: Chameleon

Post by StArL0rd84 »

Something funky is going on...
When the skin is on monitor 2 It samples all the colors from monitor 1, and vice versa.
Using DisplayFusion for different slideshows on each monitor, but i doubt that is the culprit.
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Plugin: Chameleon

Post by jsmorley »

StArL0rd84 wrote: October 19th, 2018, 2:32 pm Something funky is going on...
When the skin is on monitor 2 It samples all the colors from monitor 1, and vice versa.
Using DisplayFusion for different slideshows on each monitor, but i doubt that is the culprit.
I don't know the inner workings of the Chameleon plugin, but my understanding is that it will sample the desktop background image of the monitor that the skin is currently residing on. However, Rainmeter by default treats two monitors as one "virtual screen". You might want to try forcing the skin in question to actually reside on the second monitor by using:

WindowX=520@2
WindowY=41@2

https://docs.rainmeter.net/manual/settings/skin-sections/#WindowXY

This would be hard to "distribute", unless you use a Layout. However, I would suggest that 99.9% of users have the same background on both monitors.
User avatar
StArL0rd84
Posts: 424
Joined: February 8th, 2015, 10:07 pm
Location: EU, Denmark.

Re: Plugin: Chameleon

Post by StArL0rd84 »

jsmorley wrote: October 19th, 2018, 2:42 pm I don't know the inner workings of the Chameleon plugin, but my understanding is that it will sample the desktop background image of the monitor that the skin is currently residing on. However, Rainmeter by default treats two monitors as one "virtual screen". You might want to try forcing the skin in question to actually reside on the second monitor by using:

WindowX=520@2
WindowY=41@2

https://docs.rainmeter.net/manual/settings/skin-sections/#WindowXY

This would be hard to "distribute", unless you use a Layout. However, I would suggest that 99.9% of users have the same background on both monitors.
Forcing the skin to the 2nd monitor did not work.
I suspect some ones and zeros got switched around in the development of the plugin.
Ill wait for a response from op.
Until then ill just rock the same wallpaper on both monitors like the other 99.9%.
User avatar
Socks the Fox
Posts: 104
Joined: August 25th, 2015, 6:40 pm
Contact:

Re: Plugin: Chameleon

Post by Socks the Fox »

Hm, strange. I'm currently on a multi-background multi-monitor setup and haven't seen this issue.

The code Chameleon uses to figure out which wallpaper to sample is fairly simple... or at least as simple as Microsoft lets it.

Basically:
  • Get where the window is
  • Check each monitor's viewspace to see if it contains the window
  • Grab that monitor's background

Code: Select all

	RECT monitorRect;

	// If we're sampling the desktop, grab that
	if (img->type == IMG_DESKTOP)
	{
		std::wstring path = L"";

		// First, get the info we need from the old API

		HMONITOR mon = MonitorFromWindow(img->hWnd, MONITOR_DEFAULTTONEAREST);
		MONITORINFO monInf;
		monInf.cbSize = sizeof(MONITORINFO);
		GetMonitorInfo(mon, &monInf);

		if (IsWindows8OrGreater())
		{
			// Use the multi-desktop fun version!

			// Set up the new API

			LPWSTR monPath;
			LPWSTR wallPath;

			// Because making these just a few loose functions would have been too easy
			IDesktopWallpaper *wp = nullptr;

			CoCreateInstance(__uuidof(DesktopWallpaper), NULL, CLSCTX_ALL, IID_PPV_ARGS(&wp));
			if (wp == nullptr)
			{
				// We couldn't get the wallpaper info. Just use the fallback colors
				useDefaultColors(img);

				img->dirty = false;

				return;
			}

			// Count the monitors
			UINT monCount = 0;
			wp->GetMonitorDevicePathCount(&monCount);

			// Compare the rectangles

			for (UINT i = 0; i < monCount; ++i)
			{
				if (wp->GetMonitorDevicePathAt(i, &monPath) == S_OK)
				{
					RECT testRect;
					wp->GetMonitorRECT(monPath, &testRect);

					if (testRect.left == monInf.rcMonitor.left && testRect.top == monInf.rcMonitor.top)
					{
						// It's the monitor we're looking for!
						wp->GetWallpaper(monPath, &wallPath);
						path = wallPath; // because path is a c++ str and wallPath is a wchar_t* it makes a copy
						CoTaskMemFree(wallPath);
						CoTaskMemFree(monPath);
						break;
					}

					CoTaskMemFree(monPath);
				}
			}

			// Clean up
			wp->Release();
		}
		else
		{
			// Use the "boring" WinXP - Win7 version
			WCHAR wallPath[MAX_PATH + 1];
			ZeroMemory((void*)wallPath, sizeof(WCHAR) * (MAX_PATH + 1));

			if (SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, (void*)wallPath, 0))
			{
				path = wallPath;
			}
			else
			{
				path = L"";
			}
		}

		// First, is the current path the same as the new path
		if (img->path.compare(path) != 0)
		{
			// It's different, mark it dirty!
			img->path = path;
			img->dirty = true;
		}

		// Prepare cropping info
		monitorRect.left = 0;
		monitorRect.top = 0;
		monitorRect.right = monInf.rcMonitor.right - monInf.rcMonitor.left;
		monitorRect.bottom = monInf.rcMonitor.bottom - monInf.rcMonitor.top;
	}
	
	// Do more stuff
(I suspect there's a memory leak in there somewhere, it's not uncommon for me to find rainmeter using 1gb of RAM using my high update-rate skins, though there's a slim chance it may be due to NowPlaying not playing well with iTunes)

I know the code is capable of handling some of the odd situations one might encounter, such as negative coordinates (when a user places a monitor to the left of the main one, and puts a window on there) because.... well that's the setup I use.

If you could describe for me roughly what setup you have when you're getting this oddity that would help me try and reproduce it...
User avatar
StArL0rd84
Posts: 424
Joined: February 8th, 2015, 10:07 pm
Location: EU, Denmark.

Re: Plugin: Chameleon

Post by StArL0rd84 »

Socks the Fox wrote: October 19th, 2018, 5:03 pm Hm, strange. I'm currently on a multi-background multi-monitor setup and haven't seen this issue.

(I suspect there's a memory leak in there somewhere, it's not uncommon for me to find rainmeter using 1gb of RAM using my high update-rate skins, though there's a slim chance it may be due to NowPlaying not playing well with iTunes)

I know the code is capable of handling some of the odd situations one might encounter, such as negative coordinates (when a user places a monitor to the left of the main one, and puts a window on there) because.... well that's the setup I use.

If you could describe for me roughly what setup you have when you're getting this oddity that would help me try and reproduce it...
So I have one main monitor, and a small screen to the left of it.
Tried to put the small screen on the right in windows but it's still acting weirdly.

Having a hard time trying to describe exactly, but when the 2nd monitor is on the left of 1st, both skins sample from 1st monitor.
And when the 2nd monitor is on the right, then the skin on 2nd monitor samples from 1st, and vice versa.

2nd mon on left:
cham2.jpg
2nd mon on right:
cham.png
Do you use DisplayFusion to set [multi-background/multi-monitor]?
User avatar
Socks the Fox
Posts: 104
Joined: August 25th, 2015, 6:40 pm
Contact:

Re: Plugin: Chameleon

Post by Socks the Fox »

I do not, I just use the normal built in Windows system. If you're using Display Fusion, I bet what's happening is that DF is causing Chameleon to only see one big monitor with one big background, or it's only finding the main monitor's background.

Unfortunately, though admittedly it was a fairly cursory glance, I don't see any way of querying DF for the info I'd need to make it work like it does with vanilla Windows.

If you're using static wallpapers (i.e. not changing every X minutes) and the skins stay put, you could always use the workaround of just directly telling Chameleon which image to read. It doesn't *quite* work the same (there's no scaling or clipping) but it should land you close enough.
jrkmtf
Posts: 1
Joined: April 8th, 2019, 7:27 pm

Re: Plugin: Chameleon

Post by jrkmtf »

Any idea what causes the error message "Chameleon: Could not get handle on "C:\....jpg" in my Rainmeter logs? Just noticed my skins aren't updating with my wallpapers and my logs are going crazy with hundreds of these error messages.
User avatar
Socks the Fox
Posts: 104
Joined: August 25th, 2015, 6:40 pm
Contact:

Re: Plugin: Chameleon

Post by Socks the Fox »

Hm, strange. The only two reasons I can think of that you'd get that is if something is preventing Chameleon from getting a shared-access lock on the file (so nothing can yank the file out from under it, but will still allow other stuff that plays nice to open the file too), or if the file doesn't actually exist.

The first one can be caused by any number of reasons, such as the file permissions or another program having a non-shared lock, but if that is the cause it might help narrow down what the issue is.

The second cause is more obvious but will involve trying to figure out why Chameleon is getting a non-existent file to check.

If anyone who knows Windows coding wants to look, here's the specific part of the code that emits that debug error:

Code: Select all

HANDLE file = CreateFileW(img->path.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (file == INVALID_HANDLE_VALUE)
{
	// Couldn't get the last accessed time for the file.
	std::wstring debug = L"Chameleon: Could not get handle on ";
	debug += img->path;
	RmLog(LOG_ERROR, debug.c_str());

	useDefaultColors(img);

	img->dirty = false;

	return;
}

// ... More code that uses the file handle past here to check the file's properties ...
Post Reply