system theme won't apply to program - gtk

I'm training in Vala and everything was going ok until I applied a pkexec executable, now my system theme(dark) won't apply to the app
Here's my code:
public class Thinkfan : Gtk.Application {
public Thinkfan() {
Object (
application_id: "com.github.isa-pp.thinkfan-control-gui",
flags: ApplicationFlags.FLAGS_NONE
);
}
protected override void activate() {
settings();
build_window();
}
private void build_window () {
var window = new Gtk.ApplicationWindow(this);
window.title = "Thinkfan Control";
window.window_position = Gtk.WindowPosition.CENTER;
window.set_default_size (280,113);
window.show_all ();
}
private void settings (){
var granite_settings = Granite.Settings.get_default ();
var gtk_settings = Gtk.Settings.get_default ();
gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK;
granite_settings.notify["prefers-color-scheme"].connect (() => {
gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK;
});
}
public static int main(string[] args) {
var thinkfan = new Thinkfan();
return thinkfan.run(args);
}
}
and my pkexec is pretty simple, just
#!/bin/sh
pkexec "/home/azure/thinkfan-vala/thinkfan"

Related

MVVM AsyncExecute causing lag

AsyncExecute method causing lag in my treeview application when I am expanding a branch.
Important parts of my TreeView
public DirectoryItemViewModel(string fullPath, DirectoryItemType type, long size)
{
this.ExpandCommand = new AsyncCommand(Expand, CanExecute);
this.FullPath = fullPath;
this.Type = type;
this.Size = size;
this.ClearChildren();
}
public bool CanExecute()
{
return !isBusy;
}
public IAsyncCommand ExpandCommand { get; set; }
private async Task Expand()
{
isBusy = true;
if (this.Type == DirectoryItemType.File)
{
return;
}
List<Task<long>> tasks = new();
var children = DirectoryStructure.GetDirectoryContents(this.FullPath);
this.Children = new ObservableCollection<DirectoryItemViewModel>(
children.Select(content => new DirectoryItemViewModel(content.FullPath, content.Type, 0)));
//If I delete the remaining part of code in this method everything works fine,
in my idea it should output the folders without lag, and then start calculating their size in other threads, but it first lags for 1-2 sec, then output the content of the folder, and then start calculating.
foreach (var item in children)
{
if (item.Type == DirectoryItemType.Folder)
{
tasks.Add(Task.Run(() => GetDirectorySize(new DirectoryInfo(item.FullPath))));
}
}
var results = await Task.WhenAll(tasks);
for (int i = 0; i < results.Length; i++)
{
Children[i].Size = results[i];
}
isBusy = false;
}
My command Interface and class
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync();
bool CanExecute();
}
public class AsyncCommand : IAsyncCommand
{
public event EventHandler CanExecuteChanged;
private bool _isExecuting;
private readonly Func<Task> _execute;
private readonly Func<bool> _canExecute;
public AsyncCommand(
Func<Task> execute,
Func<bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute()
{
return !_isExecuting && (_canExecute?.Invoke() ?? true);
}
public async Task ExecuteAsync()
{
if (CanExecute())
{
try
{
_isExecuting = true;
await _execute();
}
finally
{
_isExecuting = false;
}
}
RaiseCanExecuteChanged();
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute();
}
void ICommand.Execute(object parameter)
{
//I suppose that here is the problem cause IDE is hinting me that I am not awaiting here, but I don't know how to change it if it is.
ExecuteAsync();
}
}

Update Gtk.Label dynamicall when time changes

I'm using this code to write the current time as a Gtk.Label in an app.
public bool update_time () {
var now = new GLib.DateTime.now_local ();
var settings = new GLib.Settings ("org.gnome.desktop.interface");
var time_format = Granite.DateTime.get_default_time_format (settings.get_enum ("clock-format") == 1, false);
time1_label = new Gtk.Label (now.format (time_format)) {
halign = Gtk.Align.CENTER,
valign = Gtk.Align.CENTER,
margin_top = 5
};
time1_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL);
time1_label.tooltip_text = time_format;
time1_label.xalign = 0;
return true;
}
The time shows correctly, but I want the label to update to the latest time when it changes. How can I do that?
Maybe use Timeout in some way, but I can't figure out how.
You'll have to create a Timeout, and in its callback change the text of time1_label. (Use Gdk.threads_add_timeout() to add the timeout callback in case any dependencies might be using deprecated GTK locking mechanisms.)
You can use the Timeout as in this example:
public class RefreshLabel : Gtk.Application {
private uint[] timeout_id;
private Gtk.Label label;
public RefreshLabel () {
Object (
application_id: "refreh.my.label",
flags: ApplicationFlags.FLAGS_NONE
);
}
protected override void activate () {
Gtk.ApplicationWindow window = new Gtk.ApplicationWindow (this);
window.set_default_size (100, 50);
window.window_position = Gtk.WindowPosition.CENTER;
window.set_border_width(10);
// create the timeout with your callback that update the label every 1 second
timeout_id += Timeout.add_seconds_full (GLib.Priority.DEFAULT, 1, update_time);
label = new Gtk.Label ("");
var now = new GLib.DateTime.now_local ();
label.set_markup ("<big>" + now.format ("%x %X") + "</big>");
Gtk.Box vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
vbox.pack_start (label, false, false, 0);
window.add (vbox);
window.show_all ();
}
protected override void shutdown () {
// On close all instance of the timeout must be closed
foreach (var id in timeout_id)
GLib.Source.remove (id);
base.shutdown ();
}
public bool update_time () {
var now = new GLib.DateTime.now_local ();
label.set_markup ("<big>" + now.format ("%x %X") + "</big>");
return true;
}
public static int main (string[] args) {
RefreshLabel app = new RefreshLabel ();
return app.run (args);
}
}

How to write nunit test case for singleton class

NAudioEngine is a singleton class how to write the can execute in the following code snippet:
private bool CanAddNew(object parameter)
{
if (NAudioEngine.Instance.SelectionEnd.Milliseconds != 0)
{
return true;
}
return false;
}
[Test]
public void AddNewCommandMainVMTestTrue()
{
MainVm mainVM = new MainVm();
RelayCommand command = (RelayCommand)mainVM.AddNewCommand;
bool canAddNew = command.CanExecute(null);
Assert.IsTrue(canAddNew);
}
[Test]
public void AddNewCommandMainVMTest()
{
NAudioEngine.Instance.OpenFile(WAV_FILE);
NAudioEngine.Instance.SelectionBegin = new TimeSpan(0, 0, 0);
NAudioEngine.Instance.SelectionEnd = new TimeSpan(0, 0, 0);
MainVm mainVM = new MainVm();
RelayCommand command = (RelayCommand)mainVM.AddNewCommand;
bool canAddNew = command.CanExecute(mainVM);
Assert.IsFalse(canAddNew);
}

JList update freezes display but not JFrame setTitle

If I update a JList with a long number of html formatted items then the controls stop responding and indicators won't update. This makes sense, the event thread is busy. The title can still be set though. Why is this?
Here's some (long) code demonstrating this:
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
public class JListTest extends JFrame {
class TestListModel extends AbstractListModel<String> {
private static final long serialVersionUID = JListTest.serialVersionUID;
private boolean useHtml;
private String[] formattedList = new String[] {};
public int getSize() {
return formattedList.length;
}
public String getElementAt(int index) {
return formattedList[index];
}
public void setUseHtml(boolean useHtml) {
this.useHtml = useHtml;
}
public String getNewListItem() {
if (useHtml) {
return "<html><div style='padding:2px"
+ ";background-color:#EDF5F4;color:black'><div style='padding:2px;font-weight:500;'>"
+ "Item " + (100 * Math.random())
+ "</div>"
+ "This will change!"
+ "</div></html>";
} else {
return "Item " + (100 * Math.random());
}
}
public void updateItems() {
formattedList = new String[] {"<html><h1>Loading!</h1></html>"};
fireContentsChanged(this, 0, 1);
Thread buildItems = new Thread() {
#Override
public void run() {
final String[] tempList = new String[3000];
for (int i=0; i<tempList.length; i++) {
tempList[i] = getNewListItem();
}
// Just show the string bashing's done
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
formattedList = new String[] {"<html><h1>Updating!</h1></html>"};
fireContentsChanged(TestListModel.this, 0, 1);
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Update
SwingUtilities.invokeLater(new Runnable() {
public void run() {
formattedList = tempList;
fireContentsChanged(TestListModel.this, 0, formattedList.length);
}
});
}
};
buildItems.start();
}
}
protected static final long serialVersionUID = 1L;
public JListTest() {
JPanel controlPanel = new JPanel();
JButton updaterControl = new JButton("Add 3000");
final JCheckBox useHtmlControl = new JCheckBox("Use HTML");
final TestListModel model = new TestListModel();
JList<String> list = new JList<String>(model);
JScrollPane scrollPane = new JScrollPane(list);
final JLabel durationIndicator = new JLabel("0");
controlPanel.add(useHtmlControl, BorderLayout.WEST);
controlPanel.add(updaterControl, BorderLayout.EAST);
getContentPane().add(controlPanel, BorderLayout.PAGE_START);
getContentPane().add(scrollPane, BorderLayout.CENTER);
getContentPane().add(durationIndicator, BorderLayout.PAGE_END);
useHtmlControl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
model.setUseHtml(useHtmlControl.isSelected());
}
});
useHtmlControl.setSelected(false);
updaterControl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
model.updateItems();
}
});
Timer counter = new Timer();
counter.schedule(new TimerTask() {
#Override
public void run() {
String previousCounter = durationIndicator.getText();
String newCounter = Integer.toString(
Integer.parseInt(previousCounter) + 1);
durationIndicator.setText(newCounter);
setTitle(newCounter);
}
}, 0, 100);
}
public static void main(String args[]) {
JListTest jlt = new JListTest();
jlt.pack();
jlt.setSize(300, 300);
jlt.setVisible( true );
}
}
The answer is pretty obvious - because Window title is not a Swing component, it's OS native entity.
So changes don't have to go through Swing Event Queue, but go to XDecoratedPeer.updateWMName directly in case of Unix and to some other class in other OSes.
The more interesting question would be how to avoid that UI blocking, but I don't think that's possible with just Swing, you'll have to implement some lazy loading, or rendering in batches.

Connecting to scroll_event in Vala

I've been struggling to connect to the scroll_event of a TextView widget. I can connect a lambda to it, and then run my method, but I'd like to understand why directly connecting doesn't work. I've been using the code below
using Gtk;
public class TextFileViewer : Gtk.Window {
private TextView text_view;
public TextFileViewer () {
this.title = "Text File Viewer";
this.position = WindowPosition.CENTER;
set_default_size (400, 300);
this.text_view = new TextView ();
this.text_view.editable = true;
this.text_view.cursor_visible = true;
var scroll = new ScrolledWindow (null, null);
scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
scroll.add (this.text_view);
this.text_view.scroll_event.connect (on_scroll_event);
var vbox = new VBox (true, 0);
vbox.pack_start (this.text_view, true, true, 0);
add (vbox);
}
private void on_scroll_event () {
stderr.printf("We scrollin breds");
}
public static int main (string[] args) {
Gtk.init (ref args);
var window = new TextFileViewer ();
window.destroy.connect (Gtk.main_quit);
window.show_all ();
Gtk.main ();
return 0;
}
}
That code gives me the error:
gtkviewer.vala:20.46-20.60: error: Argument 1: Cannot convert from `TextFileViewer.on_scroll_event' to `Gtk.Widget.scroll_event'
scroll.scroll_event.connect (on_scroll_event);
vala is at version 0.12.0
Check the scroll-event signal arguments:
public virtual signal bool scroll_event (Gdk.EventScroll event);
private bool on_scroll_event (Gdk.EventScroll e) {
stderr.printf("We scrollin breds");
return true;
}

Categories