Print complete WebKitWebView (not only visible part) into PDF with gtk3 and cairo - pdf

I want to save a webpage using webkit, gtk3 and cairo into a pdf.
What works: The visible part (visible in window) gets correctly printed into the pdf
What doesn't work, but should work: The invisible part (the part when you scroll down) should be printed into that pdf, too. Any ideas?
That's my code:
#include <gtk/gtk.h>
#include <webkit/webkit.h>
#include <cairo-pdf.h>
static void save_as_pdf (GtkWidget *widget, const char *filename)
{
GtkAllocation allocation;
printf("Saving PDF to file %s\n", filename);
gtk_widget_get_allocation(GTK_WIDGET(widget), &allocation);
printf("height: %d width: %d\n", allocation.height, allocation.width);
cairo_surface_t *surface = cairo_pdf_surface_create( filename, allocation.width, allocation.height);
cairo_t *cr = cairo_create(surface);
gtk_widget_draw(widget, cr);
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
static void notifyProgressCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window)
{
float progress = webkit_web_view_get_progress(webView);
printf("\x1b[1G\t\x1b[1G%f", progress * 100); fflush(stdout);
if (progress == 1.0)
save_as_pdf(window, "test.pdf");
}
int main (int argc, char *argv[])
{
GtkWidget *window;
WebKitWebView *webView;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
gtk_container_set_resize_mode(GTK_CONTAINER(webView), GTK_RESIZE_PARENT);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(webView));
g_signal_connect(webView, "notify::progress", G_CALLBACK(notifyProgressCb), webView);
webkit_web_view_load_uri(webView, "http://www.heise.de");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main();
return 0;
}
compile with:
gcc pkg-config --cflags --libs gtk+-3.0 pkg-config --libs --cflags webkitgtk-3.0 yourfile.c

Supposedly the cairo_create() method only draws the part of the WebView widget, which is visible inside the window. In this case, I would completely circumvent the WebkitGtk objects and include some code which downloads the web page, renders it and saves the output into a PDF file; HTML2PDF, for instance. It may be a dirty low-level approach, but it's more robust and easier to implement.

You are looking for this:
Save a page as a PDF:
screenshot.pl --output cpan.pdf http://search.cpan.org/

Related

Updating the wxBitmap on wxBitmap

I'm using a single wxButton:
wxButtonAction::wxButtonAction(wxWindow* parent) : wxButton(parent,wxID_ANY) {
#if defined __WXMSW__
wxIcon ms_icon(wxT("START_ICON"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
wxBitmap button_bmp;
button_bmp.CopyFromIcon(ms_icon);
#else
wxFileName icon_path(DATA_DIR, wxT("start.ico"));
wxBitmap button_bmp(icon_path.GetFullPath(), wxBITMAP_TYPE_ICO);
#endif
SetLabel(_("&Start"));
SetBitmap(button_bmp);
}
The bitmaped button is show as expected. This method helps me change both bitmap and label when user clicks that button:
void wxButtonAction::updateOnAction(bool isRunning) {
#if defined __WXMSW__
wxIcon ms_icon((isRunning) ? wxT("STOP_ICON") : wxT("START_ICON"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
wxBitmap button_bmp;
button_bmp.CopyFromIcon(ms_icon);
#else
wxFileName icon_path(DATA_DIR, (!isRunning) ? wxT("stop.ico") : wxT("start.ico"));
wxBitmap button_bmp(icon_path.GetFullPath(), wxBITMAP_TYPE_ICO);
#endif
SetLabel((!isRunning) ? _("&Stop") : _("&Start"));
SetBitmap(button_bmp);
}
and now the resource file:
AAPP_ICON ICON DISCARDABLE "../data/app.ico"
ABOUT_ICON ICON "../data/about.ico"
CLOSE_ICON ICON "../data/close.ico"
START_ICON ICON "../data/start.ico"
STOP_ICON ICON "../data/stop.ico"
1 24 "../data/manifest.xml"
The label is changed propertly when the user toggle clicking the button, but not the icon is always in "start" bitmap. I can confirm that all icons exists in the same folder
You don't need to use CopyFromIcon() at all, there is an implicit conversion from wxIcon to wxBitmap under MSW (because under the other platforms they're exactly the same thing). This being said, calling it explicitly should still work, so it's not clear what the problem is.
I'd like to recommend two other things: first, prefer using PNG (with real alpha transparency) to ICO nowadays. You might find wxBITMAP_PNG() useful to avoid the preprocessor checks, too.
Second, remove the manifest line from your .rc file and add #include "wx/msw/wx.rc" instead. This will do the right thing for the manifest and also define other stuff needed by wxWidgets applications.

SDL left mouse button event without press on startup

On the start-up of my SDL program a left mouse button event is registered without me pressing the physical left mouse button. The next physical left button press is not registered. All other keys and buttons work normal. When clicking the .exe the mouse is not located within the location of the window.
Here are the specifications of that event (taken from the SDL_Event struct):
type=1025 (SDL_MOUSEBUTTONDOWN)
timestamp=24
windowID=1
which=0
button=1 (SDL_BUTTON_LEFT)
state=1
clicks=1
x=0
y=0
I am on windows 8.1 compiling with MinGW (gcc version 4.8.1).
I have SDL version 2.0.3
This is my source code:
#include <stdio.h>
#include <SDL.h>
int main(int argc, char* argv[])
{
SDL_Window* window = NULL;
SDL_Surface* screen = NULL;
SDL_Event ev;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0);
screen = SDL_GetWindowSurface(window);
while (1) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_QUIT)
return 0;
else {
if (ev.type == SDL_MOUSEBUTTONDOWN) {
if (ev.button.button == SDL_BUTTON_LEFT) {
printf("MOUSE DOWN\n");
printf("type=%d\n", ev.button.type);
printf("timestamp=%d\n", ev.button.timestamp);
printf("windowID=%d\n", ev.button.windowID);
printf("which=%d\n", ev.button.which);
printf("button=%d\n", ev.button.button);
printf("state=%d\n", ev.button.state);
printf("clicks=%d\n", ev.button.clicks);
printf("x=%d\n", ev.button.x);
printf("y=%d\n\n", ev.button.y);
}
}
}
}
SDL_UpdateWindowSurface(window);
SDL_Delay(5);
}
SDL_FreeSurface(screen);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I have tried to solve it by calling SDL_PumpEvents() and SDL_FlushEvents() and while this removed the first (erroneous) event, the second press was still not registered.
Something strange I noticed was that it worked as expected when I opened the program .exe by right clicking and then pressing 'open'.
It'd be very grateful if somebody could shed light on this issue.

How to maximize a window using GLUT

Do you know how can I create a maximized Window in GLUT ? (maximized, not full-screen)
I have searched in Google for the solution but I couldn't find it, so I started trying to do it with the Windows API, even tough I later will need to solve it for Linux as well :(
This is what I tried:
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, "GLUT", -1, wString, 4096);
HWND vWnd = FindWindow(wString, NULL);
long currentStyle = GetWindowLong(vWnd, GWL_STYLE);
SetWindowLong(vWnd, GWL_STYLE, currentStyle | WS_MAXIMIZE);
But it is not changing the Window's state. I also tried this:
ShowWindow(vWnd, WS_MAXIMIZE);
Because the documentation (here) states that this function: "Sets the specified window's show state". But I guess it is only for Windows that are not yet visible, and mine was created and shown using GLUT (glutCreateWindow).
Currently there is an answer stating that this cannot be done, but I'd like a confirmation on that from a credible source.
Thanks,
I spent a few hours testing and experimenting different solutions, but at the end what worked was:
/* Maximize window using Windows API after glutCreateWindow() has been called */
HWND win_handle = FindWindow(0, L"Stackoverflow");
if (!win_handle)
{
printf("!!! Failed FindWindow\n");
return -1;
}
SetWindowLong(win_handle, GWL_STYLE, (GetWindowLong(win_handle, GWL_STYLE) | WS_MAXIMIZE));
ShowWindowAsync(win_handle, SW_SHOWMAXIMIZED);
/* Activate GLUT main loop */
glutMainLoop();
It's pretty simple, and I just want to empathize that you can only call glutMainLoop() at the end.
Now, since you are looking for a cross-platform solution I must say that this approach is a terrible idea. Let me share a few other approaches:
Consider using Qt (a cross-platform C++ framework to build applications with GUI). Here's an example;
Consider writing individual platform code to retrieve the current monitor resolution. When glutInitWindowSize() is called, you can pass the right values instead of trying to hack the window to maximize it;
Here's the source code to a minimal, complete and verifiable example (for Windows):
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <GL/glut.h>
int WIDTH = 480;
int HEIGHT = 480;
void initializeGL()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat aspect = (GLfloat) WIDTH / HEIGHT;
gluPerspective(45, aspect, 1.0f, 500.0f);
glViewport(0, 0, WIDTH, HEIGHT);
glMatrixMode(GL_MODELVIEW);
glShadeModel( GL_SMOOTH );
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void displayGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-3.0f);
glBegin(GL_TRIANGLES);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutCreateWindow("Stackoverflow");
glutDisplayFunc(displayGL);
initializeGL();
/* Maximize window using Windows API */
HWND win_handle = FindWindow(0, L"Stackoverflow");
if (!win_handle)
{
printf("!!! Failed FindWindow\n");
return -1;
}
SetWindowLong(win_handle, GWL_STYLE, (GetWindowLong(win_handle, GWL_STYLE) | WS_MAXIMIZE));
ShowWindowAsync(win_handle, SW_SHOWMAXIMIZED);
/* Activate GLUT main loop */
glutMainLoop();
return 0;
}
As far as I know, there is no platform independent way to maximize windows from glut. One possible work around would be to forget maximizing the window and instead set its size to that of the display. That is, use glutGet(GLUT_SCREEN_WIDTH) and glutGet(GLUT_SCREEN_HEIGHT) to get the size of the display and then use those values in glutInitWindowSize.

Sleeping display using IOKit on Lion

I have the following code that is suppose to sleep the display on a Mac. I've tried it on Lion but it doesn't seem to do anything. I tested the code by creating a barebones window Mac app with a button in the window and an IBAction method. When the button is pressed, the function below is called, however nothing happens.
Any suggestions as to why it doesn't work?
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
int display_sleep(void)
{
io_registry_entry_t reg = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler");
if (reg)
{
IORegistryEntrySetCFProperty(reg, CFSTR("IORequestIdle"), kCFBooleanTrue);
IOObjectRelease(reg);
}
else
{
return 1;
}
return 0;
}

How to handle a custom URL scheme in Webkit GTK?

Let's say I want to use a WebKitWebView in GTK to display some static HTML pages. These pages use a custom URL scheme, let's call it custom://. This scheme represents a local file whose location is not known beforehand, at the time the HTML is generated. What I do is connect to the navigation-requested signal of the webview, and do this:
const gchar *uri = webkit_network_request_get_uri(request);
gchar *scheme = g_uri_parse_scheme(uri);
if(strcmp(scheme, "custom") == 0) {
/* DO FILE LOCATING MAGIC HERE */
webkit_web_view_open(webview, real_location_of_file);
return WEBKIT_NAVIGATION_RESPONSE_IGNORE;
}
/* etc. */
This seems to work fine, unless the scheme is used in an <img> tag, for example: <img src="custom://myfile.png">, apparently these don't go through the navigation-requested signal.
It seems to me there should be some way to register a handler for the custom URL scheme with Webkit. Is this possible?
I'm more familiar with the Chromium port of WebKit, but I believe that you might need to use webkit_web_resource_get_uri (see webkitwebresource.h) to handle resources such as images.
In WebKit GTK 2, there is a more official route for this:
WebKitWebContext *context = webkit_web_context_get_default();
webkit_web_context_register_uri_scheme(context, "custom",
(WebKitURISchemeRequestCallback)handle_custom,
NULL, NULL);
/* ... */
static void
handle_custom(WebKitURISchemeRequest *request)
{
/* DO FILE LOCATING MAGIC HERE */
GFile *file = g_file_new_for_path(real_location_of_file);
GFileInputStream *stream = g_file_read(file, NULL, NULL);
g_object_unref(file);
webkit_uri_scheme_request_finish(request, stream, -1, NULL);
g_object_unref(stream);
}