WebkitGTK+ API Reference
What I'm trying to do is run my HTML5 app on Linux that way I and my users can still use my app without relying on an internet connection.
My problem is when I go to download say a zip file. The download doesn't execute because there isn't an adequate url for the file to save to (like the desktop). Therefore it doesn't download.
Thus my question relies onto how am I suppose to get an adequate url to download this file when it's executed dynamically via JSZip. (It works fine in Chrome, just not in my app). Terminal says...
source.c:35:3: warning: ‘return’ with a value, in function returning
void [enabled by default] return TRUE; ^
Here's my code:
/*
Save this file as main.c and compile it using this command
(those are backticks, not single quotes):
gcc -Wall -g -o source source.c `pkg-config --cflags --libs gtk+-2.0 webkit-1.0` -export-dynamic
Then execute it using:
./source
If you can't compile chances are you don't have gcc installed.
Install gcc/c with the following terminal command. (This command is for Debian based Linux distros)
sudo apt-get install libgtk2.0-dev libgtk2.0-doc libglib2.0-doc
WebKit requires libraries to successfully aquire, configure, and compile. You can get libraries by issuing the following command in your terminal:
sudo apt-get install subversion gtk-doc-tools autoconf automake libtool libgtk2.0-dev libpango1.0-dev libicu-dev libxslt-dev libsoup2.4-dev libsqlite3-dev gperf bison flex libjpeg62-dev libpng12-dev libxt-dev autotools-dev libgstreamer-plugins-base0.10-dev libenchant-dev libgail-dev
WebkitGTK+ API Reference: http://webkitgtk.org/reference/webkitgtk/stable/webkitgtk-webkitdownload.html
Ubuntu Webkit information - https://help.ubuntu.com/community/WebKit
sudo apt-get install libwebkitgtk-dev python-webkit-dev python-webkit
Required dependencies for this build: (If you installed all the above this is not needed)
sudo apt-get install libgtk2.0-dev libgtk2.0-doc libglib2.0-doc subversion gtk-doc-tools autoconf automake libtool libgtk2.0-dev libpango1.0-dev libicu-dev libxslt-dev libsoup2.4-dev libsqlite3-dev gperf bison flex libjpeg62-dev libpng12-dev libxt-dev autotools-dev libgstreamer-plugins-base0.10-dev libenchant-dev libgail-dev libwebkitgtk-dev
*/
#include <gtk/gtk.h>
#include <webkit/webkit.h>
static void destroy_cb(GtkWidget* widget, gpointer data) {
gtk_main_quit();
}
static void download_requested_cb(WebKitWebView *web_view, WebKitDownload *download) {
const gchar* dest = g_strdup_printf("%s", "file:///home/michael/Downloads/test.zip");
//set the destination uri (eg, send the file to a downloads folder)
webkit_download_set_destination_uri(download, dest);
webkit_download_start();
return TRUE;
}
int main(int argc, char* argv[]) {
GtkWidget* window;
WebKitWebView* web_view;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_name (window, "AppName");
gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
//gtk_window_set_icon_from_file(window, "app/logo.png", NULL);
g_signal_connect(window, "destroy", G_CALLBACK(destroy_cb), NULL);
web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
/* Register a callback that gets invoked each time a download is requested */
g_object_connect(web_view, "download-requested", G_CALLBACK(download_requested_cb), NULL);
char uri[PATH_MAX];
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
if (argc > 1)
snprintf(uri, sizeof(uri), "%s", argv[1]);
else
snprintf(uri, sizeof(uri), "file://%s/app/index.html", cwd);
webkit_web_view_open (web_view, uri);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(web_view));
gtk_widget_grab_focus(GTK_WIDGET(web_view));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
1) Your basic premise is sound:
file:///home/michael/Downloads/test.zip // This syntax should allow you to "upload" a local file on your hard drve
2) This is a compile warning (not an error). In theory, you could ignore it:
source.c:35:3: warning: ‘return’ with a value, in function returning void [enabled by default] return TRUE; ^
3) This is the problem:
static void download_requested_cb(WebKitWebView *web_view, ...
...
return TRUE; // Delete this line. You can't return anything from a "void" function!
}
Related
I made a small sample code in gtk4 + vte to run a fake terminal with a button in the bottom to run a simple command when the button is clicked.
main.c
#include <gtk/gtk.h>
#include <vte/vte.h>
#define WINDOW_HEIGHT 400
#define WINDOW_WIDTH 600
GtkApplication *app;
GtkWidget *window, *terminal, *grid, *scrollview1,*button;
int status;
void run_button(void){
char **argv_test[2] = {
"echo\0",
"Hello!!\0"
};
// can't run this command in fake terminal!
vte_terminal_spawn_async(VTE_TERMINAL(terminal),VTE_PTY_NO_HELPER,NULL,argv_test,NULL,G_SPAWN_SEARCH_PATH,NULL,NULL,NULL,2000,NULL,NULL,NULL);
}
void window_renderer(GtkApplication *app, gpointer user_data) {
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window),"My terminal");
gtk_window_set_default_size (GTK_WINDOW(window), WINDOW_WIDTH, WINDOW_HEIGHT);
grid = gtk_grid_new();
gtk_window_set_child(GTK_WINDOW(window), grid);
gtk_widget_set_vexpand(grid,TRUE);
gtk_widget_set_hexpand(grid,TRUE);
scrollview1 = gtk_scrolled_window_new();
gtk_grid_attach(GTK_GRID(grid), scrollview1, 0, 0, 1, 1);
gtk_widget_set_size_request(GTK_WIDGET(scrollview1),WINDOW_WIDTH,WINDOW_HEIGHT);
button = gtk_button_new_with_label("Run!");
gtk_grid_attach(GTK_GRID(grid), button, 0, 1, 1, 1);
g_signal_connect(button,"clicked", G_CALLBACK(run_button), NULL);
terminal = vte_terminal_new();
gtk_window_set_child(GTK_WINDOW(scrollview1), terminal);
gtk_widget_show(window);
}
int main(int argc, char **argv)
{
app = gtk_application_new(NULL, G_APPLICATION_FLAGS_NONE);
g_signal_connect(app,"activate", G_CALLBACK(window_renderer), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
Makefile
CFLAGS += -Wall
CFLAGS += `pkg-config --cflags gtk4 vte-2.91-gtk4`
LIBS += `pkg-config --libs gtk4 vte-2.91-gtk4`
.PHONY: all clean
all: main
main:main.c
gcc $(CFLAGS) main.c -o main $(LIBS)
clean:
rm main
I have compiled VTE (for gtk4) and gtk4 developer package, building a gtk4 app is not an issue!
When running the built binary, the program crashes when I click the button with a segmentation fault, probably because of a pointer not properly initialized (according to tutorials point).
Can someone help me to find out what I have missed?
I tested out your code and I believe I found the main issue with your terminal command along with some warnings that were displayed when I tested. First off, from reviewing other sample code using the "vte_terminal_spawn_async" function, the character string set included an ending array element of "NULL". So instead of the following code snippet.
char **argv_test[2] = {
"echo\0",
"Hello!!\0"
};
You would need to add in a third array element as in the following revised code snippet.
char *argv_test[3] = {
"echo\0", "Hello!!\0", NULL
};
If you notice one other minor revision to the above code snippet, I revised the definition of the character array from "char ** argv_test[3]" to "char *argv_test[3]". The compiler was listing a warning about incompatible pointer references. Also, when I was testing out this code I was receiving a warning and not able to view the terminal when the "Run" button was clicked.
Gtk-CRITICAL **: 14:49:46.383: gtk_window_set_child: assertion 'GTK_IS_WINDOW (window)' failed
From some previous troubleshooting with another user, we had determined that the child setup for the scrolled window needed to utilize the scrolled window child reference function along with the scrolled window macro. So I revised the scrolled window child assignment to be as follows.
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollview1), terminal);
Making those small revisions resulted in displaying the terminal with your "echo Hello" command (I clicked the button twice in my testing).
I believe that if you try out those minor revisions to your code, you will be able to view your terminal and progress with your coding.
Regards.
Here is my simple program
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
SDL_Window *window = NULL;
if(SDL_Init(SDL_INIT_VIDEO) != 0)
{
SDL_Log("ERROR : SDL Initialization > %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
//Program
window = SDL_CreateWindow("My Viewer",SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
if(window == NULL)
{
SDL_Log("ERROR : SDL Window creation > %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_Delay(5000);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
When running the command line :
gcc main.c -o prog $(sdl2-config --cflags --libs) && ./prog
it display :
error: XDG_RUNTIME_DIR not set in the environment.
INFO: ERROR : SDL Initialization > No available video device
I search many forum and tried what they told us to do but nothing work.
I uninstall and re install (manually and also with command line) SDL2, change the env var "export DISPLAY=:0.0" or "export DISPLAY=:1", tried this forum but nothing seems to change.
I'm running this code in bash Ubuntu with WSL2.
Thank you everyone I manage to run my program with this solution :
Install Windows 11 (because Windows 10 is not able to run graphical app).
At This point, the following is run in the bash.exe
Install Xming and run Xming. (you can try running xeyes by installing xterm to check if it's working)
For SDL, just install sdl normally (sudo apt-get install libsdl2-2.0)
Run your program.
I didn't change any env var or any other library.
When compiling my program, the makefile outputs this error:
cc sherpa.c -o -O2 -Wall
sherpa.c:4:10: fatal error: vte/vte.h: No such file or directory
was gonna post the code here but the formatting is weird so here's the github link https://github.com/amogus3016/sherpa
EDIT: code below
// Sherpa Terminal Emulator //
// This program is licensed under the GNU GPL 3.0, which provides absolutely NO WARRANTY //
__________________
| |
| // |
| // |
| // |
| // |
| // |
|________________|
#include <vte/vte.h>
static void
child_ready(VteTerminal *terminal, GPid pid, GError *error, gpointer user_Data)
{
if (!terminal) return;
if (pid == -1) gtk_main_quit();
}
int
main(int argc, char *argv[])
{
GtkWidget *window, *terminal;
/* init gtk window and terminal */
gtk_init(&argc, &argv);
terminal = vte_terminal_new();
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Sherpa");
/* start new shell */
gchar **envp = g_get_environ();
gchar **command = (gchar *[]){g_strdup(g_environ_getenv(envp, "SHELL")), NULL };
g_strfreev(envp);
vte_terminal_spawn_async(VTE_TERMINAL(terminal),
VTE_PTY_DEFAULT,
NULL, /* working dir */
command, /* command */
NULL, /* environment */
0, /* spawn flags */
NULL, NULL, /* child setup */
NULL, /* child pid */
-1, /* timeout */
NULL, /* cancellable */
child_ready, /* callback */
NULL); /* user_data */
/* connect signals */
g_signal_connect(window, "delete-event", gtk_main_quit, NULL);
g_signal_connect(terminal, "child-exited", gtk_main_quit, NULL);
/* combine widgets and run main loop */
gtk_container_add(GTK_CONTAINER(window), terminal);
gtk_widget_show_all(window);
gtk_main();
}
and the makefile:
sherpa: sherpa.c
$(CC) sherpa.c -o -O2 -Wall
printf("Building executable [|]")
printf("Building executable [/]")
printf("Building executable [-]")
printf("Building executable [\]")
printf("Building executable [|]")
mv ./sherpa /usr/bin
printf("Installing [|]")
printf("Installing [/]")
printf("Installing [-]")
printf("Installing [\]")
printf("Installing [|]")
IMO, you should rely on the default rules that make uses. In your case, since you are building an executable named sherpa from a file named sherpa.c, you can pretty much rely on the built-in rules for everything. The only thing atypical you are doing is using mv to install the executable, and the more typical usage would be to put that in a separate rule. In other words, your entire Makefile could simply be:
CFLAGS += $$(pkg-config --cflags vte-2.91)
LDFLAGS += $$(pkg-config --libs vte-2.91)
.PHONY: install all
all: sherpa
install: sherpa
mv ./sherpa /usr/bin
If you don't include the install recipe (which, IMO, you should not. Installing a package should have more infrastructure than merely copying the executable to /usr/bin), you can delete the last 4 lines of the file. (This would require that the user type make sherpa instead of just make, so keeping all: sherpa is reasonable, but you don't need to specify the build command.)
By using += when assigning CFLAGS and LDFLAGS, you allow the user to add flags at run time. eg, you can invoke CFLAGS='-g -O2' make to build the executable with optimizations enabled.
I'm trying to create a simple gui using glade and gtk in C. In the GUI I want to add a widget that plots data (a line plot and a histogram are all I want) (constantly updating) and I dont know what to use. I've seen that gnuplot is popular, but I have no idea how to use it in an application. I would like some suggestions and some instructions because I cannot find it.
here is some sample code that is what I am using as a base, just to give you an idea
update:
I built gnuplot on my pc and now when I run the code it doesnt open a new window and seems to plot inside my window. the only problem is that the widget in my gtkbox container doesnt resize so it looks like a tiny white bar. Im assuming that it is working because i removed
gui.graph = gnuplot_init() ;
gnuplot_setstyle(gui.graph, "lines") ;
gnuplot_cmd(gui.graph, "set terminal x11 window \"%x\"", (int)gtk_socket_get_id (gui.socket));
gnuplot_plot_slope(gui.graph, 1.0, 0.0, "unity slope") ;
and ran the commands on a seperate terminal and the white bar i mentioned pops up.
#include <gtk/gtk.h>
#include <gtk/gtkx.h>
#include "variables.h"
#include "gnuplot_i.h"
struct test tv;
struct GUI gui;
// Functions
void GUISetup();
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
gui.builder = gtk_builder_new_from_file("glade/window_main.glade");
gui.window = GTK_WIDGET(gtk_builder_get_object(gui.builder, "window_main"));
gtk_builder_connect_signals(gui.builder, NULL);
GUISetup();
g_object_unref(gui.builder);
// start fullbuilderscreen
gtk_window_fullscreen(GTK_WINDOW(gui.window));
gtk_widget_show(gui.window);
gtk_main();
return 0;
}
void GUISetup(){
gui.socket = gtk_socket_new ();
gtk_container_add (GTK_CONTAINER (gui.MainContainer), gui.socket);
//gtk_widget_show (gui.socket);
//gtk_widget_realize (gui.socket);
gui.graph = gnuplot_init() ;
gnuplot_setstyle(gui.graph, "lines") ;
gnuplot_cmd(gui.graph, "set terminal x11 window \"%x\"", (int)gtk_socket_get_id (gui.socket));
gnuplot_plot_slope(gui.graph, 1.0, 0.0, "unity slope") ;
}
when I make I get this:
gcc -c -g -O0 -Wall -pthread -pipe src/main.c `pkg-config --cflags --libs gtk+-3.0` -o main.o
src/main.c: In function ‘GUISetup’:
src/main.c:66:86: warning: passing argument 1 of ‘gtk_socket_get_id’ from incompatible pointer type [-Wincompatible-pointer-types]
ui.graph, "set terminal x11 window \"%x\"", (int)gtk_socket_get_id (gui.socket));
^~~
In file included from /usr/include/gtk-3.0/gtk/gtkx.h:29:0,
from src/main.c:25:
/usr/include/gtk-3.0/gtk/gtksocket.h:81:12: note: expected ‘GtkSocket * {aka struct _GtkSocket *}’ but argument is of type ‘GtkWidget * {aka struct _GtkWidget *}’
Window gtk_socket_get_id (GtkSocket *socket_);
^~~~~~~~~~~~~~~~~
gcc -o interface main.o gnuplot_i.o -pthread `pkg-config --cflags --libs gtk+-3.0` -export-dynamic
i tested the code manually and got the same results as found here, so I am going to try building gnuplot and altering the config files. Is there any alternative to the solution found in that post?
For gnuplot:
http://ndevilla.free.fr/gnuplot/gnuplot_i/index.html
Or you can use Gtk::Socket, start by create an Gtk::Socket
and add it to your widget. Then pass the socket ID (as hex) to gnuplot 'set
terminal x11 window "ID"'. And that's it!
Matplot can be better:
https://github.com/lava/matplotlib-cpp
I built a shell that tries to make the tab (\t) key do something custom using rl_bind_key(), but it didn't work in macOS Sierra, but it works on Ubuntu, Fedora, and CentOS. Here's the mcve:
#include <stdlib.h>
#include <stdio.h>
#include <readline/readline.h>
static int cmd_complete(int count, int key)
{
printf("\nCustom tab action goes here...\n");
rl_forced_update_display();
return 0;
}
char *interactive_input()
{
char *buffer = readline(" > ");
return buffer;
}
int main(int argc, char **argv)
{
rl_bind_key('\t', cmd_complete); // this doesn't seem to work in macOS
char *buffer = 0;
while (!buffer || strncmp(buffer, "exit", 4)) {
if (buffer) { free(buffer); buffer=0; }
// get command
buffer = interactive_input();
printf("awesome command: %s\n", buffer);
}
free(buffer);
return 0;
}
I compile using Clang like this:
$ cc -lreadline cli.c -o cli
What is the cause of this behavior and how do I fix it?
I was using the flag -lreadline, however unbeknownst to me, Clang appears to secretly use libedit (I've seen it called editline also). In libedit, for some reason (which merits another question), rl_bind_key appears to not work with anything except rl_insert.
So one solution that I found is to use Homebrew to install GNU Readline (brew install readline), and then to ensure I use that version, I compile thusly:
$ cc -lreadline cli.c -o cli -L/usr/local/opt/readline/lib -I/usr/local/opt/readline/include
In fact, when you install readline, it will tell you this at the end of the installation or if you do brew info readline:
gns-mac1:~ gns$ brew info readline
readline: stable 7.0.3 (bottled) [keg-only]
Library for command-line editing
https://tiswww.case.edu/php/chet/readline/rltop.html
/usr/local/Cellar/readline/7.0.3_1 (46 files, 1.5MB)
Poured from bottle on 2017-10-24 at 12:21:35
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/readline.rb
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local,
because macOS provides the BSD libedit library, which shadows libreadline.
In order to prevent conflicts when programs look for libreadline we are
defaulting this GNU Readline installation to keg-only..
For compilers to find this software you may need to set:
LDFLAGS: -L/usr/local/opt/readline/lib
CPPFLAGS: -I/usr/local/opt/readline/include
Source of libedit rl_bind_key
So this is why it doesn't work in libedit. I downloaded the source and this is how the rl_bind_key function is defined:
/*
* bind key c to readline-type function func
*/
int
rl_bind_key(int c, rl_command_func_t *func)
{
int retval = -1;
if (h == NULL || e == NULL)
rl_initialize();
if (func == rl_insert) {
/* XXX notice there is no range checking of ``c'' */
e->el_map.key[c] = ED_INSERT;
retval = 0;
}
return retval;
}
So it seems designed to not work with anything except rl_insert. That seems like a bug, not a feature. I wish I knew how to become a contributor to libedit.