I have made sure that both my config and system packages are up to date
Linux distro: EndeavourOS
The issue
I've been dealing with scaling issues on my 3072x1920 16:10 display, particularly with AGS widgets. While adjusting font sizes and other settings worked for some apps, they didn’t impact AGS widgets. I discovered that changing the resolution using the gtf command, rather than adjusting the scaling, effectively fixed the scaling issues for AGS widgets. I came across this approach in a forum thread.
I want to contribute to the Hyprland theme, as I've been using and loving it for a long time. I tried adding a custom section to the right panel Live Configs to change the resolution, but the settings don’t seem to apply. The Resolution tab appears in the side panel, but modifying it doesn't affect any settings. Here’s the code for configure.js:
The issue
I've been dealing with scaling issues on my 3072x1920 16:10 display, particularly with AGS widgets. While adjusting font sizes and other settings worked for some apps, they didn’t impact AGS widgets. I discovered that changing the resolution using the gtf command, rather than adjusting the scaling, effectively fixed the scaling issues for AGS widgets. I came across this approach in a forum thread.
I want to contribute to the Hyprland theme, as I've been using and loving it for a long time. I tried adding a custom section to the right panel Live Configs to change the resolution, but the settings don’t seem to apply. The Resolution tab appears in the side panel, but modifying it doesn't affect any settings. Here’s the code for configure.js:
configure.js
```plain const { GLib } = imports.gi; import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, Icon, Label, Scrollable, Slider, Stack } = Widget; const { execAsync, exec } = Utils; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { ConfigGap, ConfigSpinButton, ConfigToggle } from '../../.commonwidgets/configwidgets.js'; const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disableValue = 0, extraOnChange = () => { } }) => ConfigToggle({ icon: icon, name: name, desc: desc, initValue: JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"] != 0, onChange: (self, newValue) => { execAsync(['hyprctl', 'keyword', option, `${newValue ? enableValue : disableValue}`]).catch(print); extraOnChange(self, newValue); } }); const HyprlandSpinButton = ({ icon, name, desc = null, option, ...rest }) => ConfigSpinButton({ icon: icon, name: name, desc: desc, initValue: Number(JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"]), onChange: (self, newValue) => { execAsync(['hyprctl', 'keyword', option, `${newValue}`]).catch(print); }, ...rest, }); const Subcategory = (children) => Box({ className: 'margin-left-20', vertical: true, children: children, }) const getResolution = () => { const output = exec('hyprctl monitors -j'); const monitors = JSON.parse(output); if (monitors.length > 0) { const { height, width, refreshRate } = monitors[0]; return { height, width, refreshRate: Math.round(refreshRate) }; } return { height: 1080, width: 1920, refreshRate: 60 }; }; const updateResolutionConfig = async (newWidth, newHeight, newRefreshRate) => { const currentRes = getResolution(); const width = newWidth !== undefined ? newWidth : currentRes.width; const height = newHeight !== undefined ? newHeight : currentRes.height; const refreshRate = newRefreshRate !== undefined ? newRefreshRate : currentRes.refreshRate; const modelineOutput = exec(`gtf ${width} ${height} ${refreshRate}`); const modelineMatch = modelineOutput.match(/Modeline "(.*)"/); if (!modelineMatch) { throw new Error('Failed to generate modeline'); } const modeline = modelineMatch[1].split('"')[1]; // Extract the modeline without the quotes const configPath = `${GLib.get_home_dir()}/.config/hypr/hyprland/general.conf`; const configContent = exec(`cat ${configPath}`); const newConfigContent = configContent.replace(/^monitor=.*$/m, `monitor=eDP-1, ${modeline}, auto, 1`); await execAsync(['bash', '-c', `echo "${newConfigContent}" > ${configPath}`]); }; export default (props) => { const { width, height, refreshRate } = getResolution(); const ConfigSection = ({ name, children }) => Box({ vertical: true, className: 'spacing-v-5', children: [ Label({ hpack: 'center', className: 'txt txt-large margin-left-10', label: name, }), Box({ className: 'margin-left-10 margin-right-10', vertical: true, children: children, }) ] }) const mainContent = Scrollable({ vexpand: true, child: Box({ vertical: true, className: 'spacing-v-10', children: [ ConfigSection({ name: 'Effects', children: [ ConfigToggle({ icon: 'border_clear', name: 'Transparency', desc: '[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this', initValue: exec(`bash -c "sed -n \'2p\' ${GLib.get_user_state_dir()}/ags/user/colormode.txt"`) == "transparent", onChange: (self, newValue) => { const transparency = newValue == 0 ? "opaque" : "transparent"; console.log(transparency); execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "2s/.*/${transparency}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`]) .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) .catch(print); }, }), HyprlandToggle({ icon: 'blur_on', name: 'Blur', desc: "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.", option: "decoration:blur:enabled" }), Subcategory([ HyprlandToggle({ icon: 'stack_off', name: 'X-ray', desc: "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ", option: "decoration:blur:xray" }), HyprlandSpinButton({ icon: 'target', name: 'Size', desc: '[Hyprland]\nAdjust the blur radius. Generally doesn\'t affect performance\nHigher = more color spread', option: 'decoration:blur:size', minValue: 1, maxValue: 1000 }), HyprlandSpinButton({ icon: 'repeat', name: 'Passes', desc: '[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.', option: 'decoration:blur:passes', minValue: 1, maxValue: 10 }), ]), ConfigGap({}), HyprlandToggle({ icon: 'animation', name: 'Animations', desc: '[Hyprland] [GTK]\nEnable animations', option: 'animations:enabled', extraOnChange: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', `${newValue}`]) }), Subcategory([ ConfigSpinButton({ icon: 'clear_all', name: 'Choreography delay', desc: 'In milliseconds, the delay between animations of a series', initValue: userOptions.animations.choreographyDelay, step: 10, minValue: 0, maxValue: 1000, onChange: (self, newValue) => { userOptions.animations.choreographyDelay = newValue }, }) ]), ] }), ConfigSection({ name: 'Developer', children: [ HyprlandToggle({ icon: 'speed', name: 'Show FPS', desc: "[Hyprland]\nShow FPS overlay on top-left corner", option: "debug:overlay" }), HyprlandToggle({ icon: 'sort', name: 'Log to stdout', desc: "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console", option: "debug:enable_stdout_logs" }), HyprlandToggle({ icon: 'motion_sensor_active', name: 'Damage tracking', desc: "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work", option: "debug:damage_tracking", enableValue: 2 }), HyprlandToggle({ icon: 'destruction', name: 'Damage blink', desc: "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes", option: "debug:damage_blink" }), ConfigSection({ name: 'Resolution', children: [ ConfigSpinButton({ icon: 'height', name: 'Height', desc: 'Set the screen height', initValue: width, step: 1, minValue: 480, maxValue: 4320, onChange: (self, newValue) => { newHeight = newValue; updateResolutionConfig(undefined, newHeight, undefined).catch(print); }, }), ConfigSpinButton({ icon: 'width', name: 'Width', desc: 'Set the screen width', initValue: height, step: 1, minValue: 640, maxValue: 7680, onChange: (self, newValue) => { newWidth = newValue; updateResolutionConfig(newWidth, undefined, undefined).catch(print); }, }), ConfigSpinButton({ icon: 'refresh', name: 'Refresh Rate', desc: 'Set the screen refresh rate', initValue:refreshRate, step: 1, minValue: 30, maxValue: 240, onChange: (self, newValue) => { newRefreshRate = newValue; updateResolutionConfig(undefined, undefined, newRefreshRate).catch(print); }, }), ] }) ] }), ] }) }); const footNote = Box({ homogeneous: true, children: [Label({ hpack: 'center', className: 'txt txt-italic txt-subtext margin-5', label: 'Not all changes are saved', })] }) return Box({ ...props, className: 'spacing-v-5', vertical: true, children: [ mainContent, footNote, ] }); } ```