grab icon, save position

This commit is contained in:
Artem Anufrij 2018-02-04 18:09:24 +01:00
parent 5f45d85e04
commit 5bd378c9ff
8 changed files with 1804 additions and 203 deletions

16
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,16 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "cd ${workspaceFolder}/build && make",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View file

@ -32,6 +32,19 @@
</screenshot> </screenshot>
</screenshots> </screenshots>
<releases> <releases>
<release version="0.2.6" date="2018-02-07">
<description>
<p>New:</p>
<ul>
<li>Save and restore window position</li>
<li>Grab favorite icon</li>
</ul>
<p>Fix:</p>
<ul>
<li>Grab website color</li>
</ul>
</description>
</release>
<release version="0.2.5" date="2017-12-17"> <release version="0.2.5" date="2017-12-17">
<description> <description>
<p>Translation:</p> <p>Translation:</p>

View file

@ -28,6 +28,7 @@
namespace Webpin { namespace Webpin {
public class WebpinApp : Gtk.Application { public class WebpinApp : Gtk.Application {
public string CACHE_FOLDER { get; private set; }
static WebpinApp _instance = null; static WebpinApp _instance = null;
@ -49,10 +50,24 @@ namespace Webpin {
start_webapp (parameter.get_string ()); start_webapp (parameter.get_string ());
} }
}); });
create_cache_folders ();
} }
public Gtk.Window mainwindow { get; private set; default = null; } public Gtk.Window mainwindow { get; private set; default = null; }
public void create_cache_folders () {
CACHE_FOLDER = GLib.Path.build_filename (GLib.Environment.get_user_cache_dir (), "com.github.artemanufrij.webpin");
try {
File file = File.new_for_path (CACHE_FOLDER);
if (!file.query_exists ()) {
file.make_directory ();
}
} catch (Error e) {
warning (e.message);
}
}
protected override void activate () { protected override void activate () {
if (mainwindow != null) { if (mainwindow != null) {
mainwindow.present (); mainwindow.present ();

View file

@ -42,7 +42,7 @@ namespace Webpin {
Categories=Network; Categories=Network;
X-GNOME-FullName=webpin X-GNOME-FullName=webpin
StartupWMClass=Webpin StartupWMClass=Webpin
X-Webpin-PrimaryColor=none"""; X-Webpin-PrimaryColor=rgba (222,222,222,1)""";
GLib.KeyFile file; GLib.KeyFile file;

View file

@ -120,23 +120,6 @@ namespace Webpin.Widgets {
app_notification.reveal_child = false; app_notification.reveal_child = false;
} }
request_finished (); request_finished ();
var source = web_view.get_main_resource ();
source.get_data.begin (null, (obj, res) => {
try {
var body = (string)source.get_data.end (res);
var regex = new Regex ("(?<=<meta name=\"theme-color\" content=\")#[0-9a-fA-F]{6}");
MatchInfo match_info;
if (regex.match (body, 0, out match_info)) {
var result = match_info.fetch (0);
Gdk.RGBA return_value = {0, 0, 0, 1};
if (return_value.parse (result)) {
found_website_color (return_value);
}
}
} catch (Error err) {
warning (err.message);
}
});
} }
}); });

View file

@ -1,6 +1,6 @@
/*- /*-
* Copyright (c) 2015 Erasmo Marín <erasmo.marin@gmail.com> * Copyright (c) 2015 Erasmo Marín <erasmo.marin@gmail.com>
* Copyright (c) 2017-2017 Artem Anufrij <artem.anufrij@live.de> * Copyright (c) 2017-2018 Artem Anufrij <artem.anufrij@live.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@ -28,7 +28,6 @@
namespace Webpin.Widgets.Views { namespace Webpin.Widgets.Views {
public class Editor : Gtk.Box { public class Editor : Gtk.Box {
public enum assistant_mode { new_app, edit_app } public enum assistant_mode { new_app, edit_app }
public signal void application_created (GLib.DesktopAppInfo ? new_file); public signal void application_created (GLib.DesktopAppInfo ? new_file);
@ -59,19 +58,23 @@ namespace Webpin.Widgets.Views {
Gdk.RGBA default_color; Gdk.RGBA default_color;
string tmp_icon_file;
string tmp_icon_ext;
uint grab_timer = 0;
construct { construct {
default_color = { 222, 222, 222, 255 }; default_color = { 0, 0, 0, 1 };
default_color.parse ("rgba (222, 222, 222, 1)");
} }
public Editor () { public Editor () {
GLib.Object (orientation : Gtk.Orientation.VERTICAL); GLib.Object (orientation : Gtk.Orientation.VERTICAL);
apps = Services.DesktopFilesManager.get_applications (); apps = Services.DesktopFilesManager.get_applications ();
this.margin = 15; this.margin = 15;
try { try {
this.protocol_regex = new Regex ("""https?\:\/\/[\w+\d+]((\:\d+)?\/\S*)?"""); this.protocol_regex = new Regex ("https?://[\\w+\\d+]((:\\d+)?/\\S*)?");
} catch (RegexError e) { } catch (RegexError e) {
critical ("%s", e.message); critical ("%s", e.message);
} }
@ -115,7 +118,8 @@ namespace Webpin.Widgets.Views {
primary_color_button = new Gtk.ColorButton.with_rgba (default_color); primary_color_button = new Gtk.ColorButton.with_rgba (default_color);
primary_color_button.use_alpha = false; primary_color_button.use_alpha = false;
primary_color_button.color_activated.connect ((color) => { primary_color_button.color_activated.connect (
(color) => {
stdout.printf ("COLOR %s\n", color.to_string ()); stdout.printf ("COLOR %s\n", color.to_string ());
}); });
@ -161,30 +165,37 @@ namespace Webpin.Widgets.Views {
pack_end (accept_button, false, false, 0); pack_end (accept_button, false, false, 0);
//signals and handlers //signals and handlers
icon_button.clicked.connect(() => { icon_button.clicked.connect (
() => {
icon_selector_popover.show_all (); icon_selector_popover.show_all ();
}); });
app_url_entry.changed.connect (() => { app_url_entry.changed.connect (
() => {
if (!this.protocol_regex.match (app_url_entry.get_text ())) { if (!this.protocol_regex.match (app_url_entry.get_text ())) {
reset_grab_color_and_icon ();
app_url_entry.get_style_context ().add_class ("error"); app_url_entry.get_style_context ().add_class ("error");
app_url_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "dialog-information"); app_url_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "dialog-information");
app_url_entry.set_icon_tooltip_text (Gtk.EntryIconPosition.SECONDARY, _ ("url must start with http:// or https://")); app_url_entry.set_icon_tooltip_text (Gtk.EntryIconPosition.SECONDARY, _ ("url must start with http:// or https://"));
app_url_valid = false; app_url_valid = false;
} else { } else {
grab_color_and_icon ();
app_url_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, null);
app_url_entry.get_style_context ().remove_class ("error"); app_url_entry.get_style_context ().remove_class ("error");
app_url_valid = true; app_url_valid = true;
} }
validate (); validate ();
}); });
app_name_entry.changed.connect (() => { app_name_entry.changed.connect (
() => {
if (mode == assistant_mode.new_app && Services.DesktopFilesManager.get_applications ().has_key (app_name_entry.get_text ())) { if (mode == assistant_mode.new_app && Services.DesktopFilesManager.get_applications ().has_key (app_name_entry.get_text ())) {
app_name_entry.get_style_context ().add_class ("error"); app_name_entry.get_style_context ().add_class ("error");
app_name_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "dialog-information"); app_name_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "dialog-information");
app_name_entry.set_icon_tooltip_text (Gtk.EntryIconPosition.SECONDARY, _ ("App already exist")); app_name_entry.set_icon_tooltip_text (Gtk.EntryIconPosition.SECONDARY, _ ("App already exist"));
app_name_valid = false; app_name_valid = false;
} else { } else {
app_name_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, null);
app_name_entry.get_style_context ().remove_class ("error"); app_name_entry.get_style_context ().remove_class ("error");
app_name_valid = true; app_name_valid = true;
} }
@ -197,6 +208,108 @@ namespace Webpin.Widgets.Views {
icon_name_entry.changed.connect (update_app_icon); icon_name_entry.changed.connect (update_app_icon);
} }
private void grab_color_and_icon () {
reset_grab_color_and_icon ();
grab_timer = Timeout.add (
500,
() => {
var url = app_url_entry.text;
var session = new Soup.Session.with_options ("user_agent", "WebPin/0.1.0 (https://github.com/artemanufrij/webpin)");
session.timeout = 2;
var msg = new Soup.Message ("GET", url);
session.send_message (msg);
if (msg.status_code == 200) {
var body = (string)msg.response_body.data;
stdout.printf ("%s\n", body);
var regex = new Regex ("(?<=<meta name=\"theme-color\" content=\")#[0-9a-fA-F]{6}");
MatchInfo match_info;
if (regex.match (body, 0, out match_info)) {
var result = match_info.fetch (0);
Gdk.RGBA return_value = {0, 0, 0, 1};
if (return_value.parse (result)) {
primary_color_button.set_rgba (return_value);
}
}
regex = new Regex ("(?<=\"apple-touch-icon\" href=\")[/\\w\\.]*");
if (regex.match (body, 0, out match_info)) {
var result = match_info.fetch (0);
var icon_path = result;
if (!result.has_prefix ("http")) {
result = Path.build_filename (url, result);
}
download_icon (icon_path);
icon_name_entry.set_text (tmp_icon_file);
}
if (tmp_icon_file == "") {
regex = new Regex ("(?<=\"fluid-icon\" href=\")[/\\w\\.:\\-]*");
if (regex.match (body, 0, out match_info)) {
var result = match_info.fetch (0);
var icon_path = result;
if (!result.has_prefix ("http")) {
result = Path.build_filename (url, result);
}
download_icon (icon_path);
icon_name_entry.set_text (tmp_icon_file);
}
}
if (tmp_icon_file == "") {
regex = new Regex ("(?<=\"mask-icon\" href=\")[/\\w\\.:\\-]*");
if (regex.match (body, 0, out match_info)) {
var result = match_info.fetch (0);
var icon_path = result;
if (!result.has_prefix ("http")) {
result = Path.build_filename (url, result);
}
download_icon (icon_path);
icon_name_entry.set_text (tmp_icon_file);
}
}
}
msg.dispose ();
session.dispose ();
reset_grab_color_and_icon ();
return false;
});
}
private void reset_grab_color_and_icon () {
if (grab_timer != 0) {
Source.remove (grab_timer);
grab_timer = 0;
}
}
public bool download_icon (string url) {
var session = new Soup.Session.with_options ("user_agent", "WebPin/0.1.0 (https://github.com/artemanufrij/webpin)");
var msg = new Soup.Message ("GET", url);
session.send_message (msg);
if (msg.status_code == 200) {
tmp_icon_ext = ".png";
if (url.has_suffix (".svg")) {
tmp_icon_ext = ".svg";
}
tmp_icon_file = GLib.Path.build_filename (WebpinApp.instance.CACHE_FOLDER, Random.next_int ().to_string () + tmp_icon_ext);
var fs = FileStream.open (tmp_icon_file, "w");
fs.write (msg.response_body.data, (size_t)msg.response_body.length);
}
msg.dispose ();
session.dispose ();
return true;
}
private void update_app_icon () { private void update_app_icon () {
string icon = icon_name_entry.get_text (); string icon = icon_name_entry.get_text ();
@ -237,7 +350,7 @@ namespace Webpin.Widgets.Views {
filter.set_filter_name (_ ("Images")); filter.set_filter_name (_ ("Images"));
filter.add_mime_type ("image/*"); filter.add_mime_type ("image/*");
file_chooser = new Gtk.FileChooserDialog ("", null, file_chooser = new Gtk.FileChooserDialog ("", WebpinApp.instance.mainwindow,
Gtk.FileChooserAction.OPEN, Gtk.FileChooserAction.OPEN,
_ ("Cancel"), Gtk.ResponseType.CANCEL, _ ("Cancel"), Gtk.ResponseType.CANCEL,
_ ("Open"), Gtk.ResponseType.ACCEPT); _ ("Open"), Gtk.ResponseType.ACCEPT);
@ -247,7 +360,8 @@ namespace Webpin.Widgets.Views {
var preview = new Gtk.Image (); var preview = new Gtk.Image ();
preview.valign = Gtk.Align.START; preview.valign = Gtk.Align.START;
file_chooser.update_preview.connect (()=> { file_chooser.update_preview.connect (
()=> {
string filename = file_chooser.get_preview_filename (); string filename = file_chooser.get_preview_filename ();
Gdk.Pixbuf pix = null; Gdk.Pixbuf pix = null;
@ -269,14 +383,12 @@ namespace Webpin.Widgets.Views {
}); });
if (file_chooser.run () == Gtk.ResponseType.ACCEPT) { if (file_chooser.run () == Gtk.ResponseType.ACCEPT) {
icon_name_entry.set_text (file_chooser.get_filename ()); icon_name_entry.set_text (file_chooser.get_filename ());
file_chooser.destroy (); file_chooser.destroy ();
} }
file_chooser.destroy (); file_chooser.destroy ();
} }
private void validate () { private void validate () {
if (app_icon_valid && app_name_valid && app_url_valid) { if (app_icon_valid && app_name_valid && app_url_valid) {
accept_button.set_sensitive (true); accept_button.set_sensitive (true);
@ -285,8 +397,8 @@ namespace Webpin.Widgets.Views {
accept_button.set_sensitive (false); accept_button.set_sensitive (false);
} }
public void reset_fields () { public void reset_fields () {
tmp_icon_file = "";
icon_name_entry.set_text (""); icon_name_entry.set_text ("");
app_name_entry.set_text (""); app_name_entry.set_text ("");
app_name_entry.set_sensitive (true); app_name_entry.set_sensitive (true);
@ -299,6 +411,12 @@ namespace Webpin.Widgets.Views {
private void on_accept () { private void on_accept () {
string icon = icon_name_entry.get_text (); string icon = icon_name_entry.get_text ();
if (tmp_icon_file != "") {
var new_icon = GLib.Path.build_filename (WebpinApp.instance.CACHE_FOLDER, app_name_entry.get_text () + tmp_icon_ext);
FileUtils.rename (tmp_icon_file, new_icon);
FileUtils.remove (tmp_icon_file);
icon = new_icon;
}
string name = app_name_entry.get_text (); string name = app_name_entry.get_text ();
string url = app_url_entry.get_text ().replace ("%", "%%"); string url = app_url_entry.get_text ().replace ("%", "%%");
bool stay_open = stay_open_when_closed.active; bool stay_open = stay_open_when_closed.active;
@ -337,6 +455,7 @@ namespace Webpin.Widgets.Views {
} else { } else {
primary_color_button.set_rgba (default_color); primary_color_button.set_rgba (default_color);
} }
reset_grab_color_and_icon ();
update_app_icon (); update_app_icon ();
} }
} }

View file

@ -1,6 +1,6 @@
/*- /*-
* Copyright (c) 2015 Erasmo Marín <erasmo.marin@gmail.com> * Copyright (c) 2015 Erasmo Marín <erasmo.marin@gmail.com>
* Copyright (c) 2017-2017 Artem Anufrij <artem.anufrij@live.de> * Copyright (c) 2017-2018 Artem Anufrij <artem.anufrij@live.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
@ -28,7 +28,6 @@
namespace Webpin.Windows { namespace Webpin.Windows {
public class WebApp : Gtk.Window { public class WebApp : Gtk.Window {
Gdk.WindowState current_state; Gdk.WindowState current_state;
Widgets.Browser browser; Widgets.Browser browser;
@ -53,7 +52,8 @@ namespace Webpin.Windows {
var copy_url = new Gtk.Button.from_icon_name ("insert-link-symbolic", Gtk.IconSize.MENU); var copy_url = new Gtk.Button.from_icon_name ("insert-link-symbolic", Gtk.IconSize.MENU);
copy_url.tooltip_text = _ ("Copy URL into clipboard"); copy_url.tooltip_text = _ ("Copy URL into clipboard");
copy_url.clicked.connect (() => { copy_url.clicked.connect (
() => {
Gtk.Clipboard.get_default (Gdk.Display.get_default ()).set_text (browser.web_view.uri, -1); Gtk.Clipboard.get_default (Gdk.Display.get_default ()).set_text (browser.web_view.uri, -1);
}); });
headerbar.pack_end (copy_url); headerbar.pack_end (copy_url);
@ -66,7 +66,8 @@ namespace Webpin.Windows {
stay_open.active = desktop_file.hide_on_close; stay_open.active = desktop_file.hide_on_close;
stay_open.tooltip_text = _ ("Run in background if closed"); stay_open.tooltip_text = _ ("Run in background if closed");
stay_open.image = new Gtk.Image.from_icon_name ("view-pin-symbolic", Gtk.IconSize.MENU); stay_open.image = new Gtk.Image.from_icon_name ("view-pin-symbolic", Gtk.IconSize.MENU);
stay_open.toggled.connect (() => { stay_open.toggled.connect (
() => {
desktop_file.edit_property ("X-Webpin-StayOpen", stay_open.active.to_string ()); desktop_file.edit_property ("X-Webpin-StayOpen", stay_open.active.to_string ());
desktop_file.save_to_file (); desktop_file.save_to_file ();
}); });
@ -74,7 +75,8 @@ namespace Webpin.Windows {
this.set_titlebar (headerbar); this.set_titlebar (headerbar);
this.delete_event.connect (() => { this.delete_event.connect (
() => {
save_settings (); save_settings ();
if (desktop_file.hide_on_close) { if (desktop_file.hide_on_close) {
this.hide_on_delete (); this.hide_on_delete ();
@ -82,12 +84,14 @@ namespace Webpin.Windows {
return desktop_file.hide_on_close; return desktop_file.hide_on_close;
}); });
this.window_state_event.connect ((event) => { this.window_state_event.connect (
(event) => {
current_state = event.new_window_state; current_state = event.new_window_state;
return false; return false;
}); });
browser.external_request.connect ((action) => { browser.external_request.connect (
(action) => {
debug ("Web app external request: %s", action.get_request ().uri); debug ("Web app external request: %s", action.get_request ().uri);
try { try {
Process.spawn_command_line_async ("xdg-open " + action.get_request ().uri); Process.spawn_command_line_async ("xdg-open " + action.get_request ().uri);
@ -96,7 +100,8 @@ namespace Webpin.Windows {
} }
}); });
browser.desktop_notification.connect ((title, body, icon) => { browser.desktop_notification.connect (
(title, body, icon) => {
var desktop_notification = new Notification (title); var desktop_notification = new Notification (title);
desktop_notification.set_body (body); desktop_notification.set_body (body);
desktop_notification.set_icon (icon); desktop_notification.set_icon (icon);
@ -104,15 +109,19 @@ namespace Webpin.Windows {
WebpinApp.instance.send_notification (null, desktop_notification); WebpinApp.instance.send_notification (null, desktop_notification);
}); });
browser.request_begin.connect (() => { browser.request_begin.connect (
() => {
spinner.active = true; spinner.active = true;
}); });
browser.request_finished.connect (() => { browser.request_finished.connect (
() => {
spinner.active = false; spinner.active = false;
}); });
browser.found_website_color.connect ((color) => { browser.found_website_color.connect (
(color) => {
stdout.printf ("%s\n", color.to_string ());
int gray_val = (int)(desktop_file.color.red * 255); int gray_val = (int)(desktop_file.color.red * 255);
if (desktop_file.color == null || ((gray_val == 222 || gray_val == 255) && desktop_file.color.red == desktop_file.color.green && desktop_file.color.red == desktop_file.color.blue)) { if (desktop_file.color == null || ((gray_val == 222 || gray_val == 255) && desktop_file.color.red == desktop_file.color.green && desktop_file.color.red == desktop_file.color.blue)) {
set_color (color); set_color (color);
@ -147,6 +156,8 @@ namespace Webpin.Windows {
private void load_settings () { private void load_settings () {
var width = desktop_file.info.get_string ("X-Webpin-WindowWidth"); var width = desktop_file.info.get_string ("X-Webpin-WindowWidth");
var height = desktop_file.info.get_string ("X-Webpin-WindowHeight"); var height = desktop_file.info.get_string ("X-Webpin-WindowHeight");
var x = desktop_file.info.get_string ("X-Webpin-WindowX");
var y = desktop_file.info.get_string ("X-Webpin-WindowY");
var state = desktop_file.info.get_string ("X-Webpin-WindowMaximized"); var state = desktop_file.info.get_string ("X-Webpin-WindowMaximized");
var zoom = desktop_file.info.get_string ("X-Webpin-WindowZoom"); var zoom = desktop_file.info.get_string ("X-Webpin-WindowZoom");
@ -156,6 +167,12 @@ namespace Webpin.Windows {
set_default_size (1000, 600); set_default_size (1000, 600);
} }
if (x != null && y != null) {
this.move (int.parse (x), int.parse (y));
} else {
this.window_position = Gtk.WindowPosition.CENTER;
}
if (state != null && state == "max") { if (state != null && state == "max") {
this.maximize (); this.maximize ();
} }
@ -169,6 +186,10 @@ namespace Webpin.Windows {
if (this.is_maximized) { if (this.is_maximized) {
desktop_file.edit_property ("X-Webpin-WindowMaximized", "max"); desktop_file.edit_property ("X-Webpin-WindowMaximized", "max");
} else { } else {
int x, y;
this.get_position (out x, out y);
desktop_file.edit_property ("X-Webpin-WindowX", x.to_string ());
desktop_file.edit_property ("X-Webpin-WindowY", y.to_string ());
desktop_file.edit_property ("X-Webpin-WindowWidth", this.get_allocated_width ().to_string ()); desktop_file.edit_property ("X-Webpin-WindowWidth", this.get_allocated_width ().to_string ());
desktop_file.edit_property ("X-Webpin-WindowHeight", this.get_allocated_height ().to_string ()); desktop_file.edit_property ("X-Webpin-WindowHeight", this.get_allocated_height ().to_string ());
desktop_file.edit_property ("X-Webpin-WindowMaximized", "norm"); desktop_file.edit_property ("X-Webpin-WindowMaximized", "norm");

1434
uncrustify.cfg Normal file

File diff suppressed because it is too large Load diff