Flutter PDF Viewer for Linux desktop - linux

I developing some kind of chat application with PDF viewing functions on Flutter for Android and Linux desktop platforms.
So i want to embed PDF viewer in flutter application using some kind of PDF reader or WebBrowser. There is no problems with PDF's on Android - more than 100 plugins on pub.dev for PDF's and WebViews, but none of them supported Linux desktop.
I have tried to add Linux desktop support for Android and IOS plugins, but look's like all of them using PlatformView and webview_flutter classes, which not supported on Linux desktop yet: webview_flutter PlatformView. They have P4 priority and no milestone assigned. I can't wait undefinitely long time, i should end this project in 2 months. So what should i do?
I have read that Flutter uses GTK+ to display on Linux desktop, and i know that there is GTK+ components to display PDF. So is it possible to inject somehow this component in flutter ui? Is there any example?
Or maybe better will be to convert PDF in jpeg and show images instead? (But i don't want lost zoom and document navigation)
Opening PDF into external program with File.Open() is not solution for me, because in this case user's should constantly switch between flutter app (where we have list of PDF files) and PDF reader windows.
I am new to both Flutter and Linux, so any help would be appreciated.

So is it possible to inject somehow this component in flutter ui?
That is exactly what PlatformView is, so that's equivalent to the question of whether PlatformView is supported on Linux.
Two options that could work without PlatformView support:
Swap the window between displaying the Flutter view and a PDF view (if you want the PDF to fill the window while displayed).
Place the Flutter view and the PDF view side by side in the window (if you want both Flutter content—like your list of files—and PDF content visible at the same time).
Both would require the work to be done in the native code, so you would need to either write a plugin, or implement it directly in your runner, and use a method channel to coordinate between Dart and native code.

So just to clarify how we can achive this using webkit, as example:
CMakeLists.txt:
#add webkit package reference
pkg_check_modules(WEBKIT2 REQUIRED IMPORTED_TARGET webkit2gtk-4.0)
...
#remove -Werror flag to allow compilation with warnings
target_compile_options(${TARGET} PRIVATE -Wall)
...
#link webkit libraries
target_link_libraries(${BINARY_NAME} PUBLIC PkgConfig::WEBKIT2)
#somehow this line causes 'flutter run' to crash on "Linking CXX executable" step.
#Looks like it compiles, but fails to link.
#I think there is should be other question opened for this issue.
my_application.cc:
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#include <webkit2/webkit2.h>
#include "flutter/generated_plugin_registrant.h"
static void my_application_activate(GApplication* application) {
GtkWidget *vbox1 = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox1);
// we can insert any gtk controls in this window outside of FlView
GtkWidget *label = gtk_label_new ("Hello GNOME!");
gtk_box_pack_start (GTK_BOX (vbox1), label, TRUE, TRUE, 2);
gtk_widget_show (label);
// webkit/poppler/evince should work perfect because they gtk+
WebKitWebView *pWebKitView = WEBKIT_WEB_VIEW(webkit_web_view_new());
gtk_box_pack_start (GTK_BOX (vbox1), GTK_WIDGET(pWebKitView), TRUE, TRUE, 2);
gtk_widget_show(GTK_WIDGET(pWebKitView));
// finally add FlView
g_autoptr(FlDartProject) project = fl_dart_project_new();
FlView *view = fl_view_new(project);
gtk_box_pack_start (GTK_BOX (vbox1), GTK_WIDGET(view), TRUE, TRUE, 2);
gtk_widget_show (GTK_WIDGET (view));
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
gtk_container_add (GTK_CONTAINER (window), vbox1);
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "client");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
}

Related

How to start building a GUI toolkit for wayland

I want to create a GUI toolkit for my desktop environment (because neither gtk nor qt don't fit to my needs) but I don't know how to start. I don't want a cross-platform or display-server independent library, theming options, configurable icons etc. just a few basic widgets for making wayland clients. (widgets like button, entry, label, window and images... and I want to use CSD if it's important)
My problem is that I can't understand how graphics work in wayland (in X you only need to create a window and use XDrawLine etc. right?) also I don't know how to write a graphical toolkit. Can you give me some articles or recommendations on how can I do this?
The easiest way to create a wayland client is to use the wayland-client library. Basically, it abstracts the wire format.
example:
#include <stdio.h>
#include <wayland-client.h>
int main(void)
{
struct wl_display *display = wl_display_connect(NULL);
if (display) {
printf("Connected!\n");
} else {
printf("Error connecting ;(\n");
return 1;
}
wl_display_disconnect(display);
return 0;
}

How to write a Qt application that uses Kvantum blur

I'm trying to build an application (with nodegui) that uses the blur effect that is applied via Kvantum.
If this is not possible with node.js, I'm fine to use any other language (would be nice if it just work with VS Code instead of QT Creator)
Currently I'm using PlasmaSur-dark and apps like Dolphin works fine.
But when I write a simple Qt app like
import { QMainWindow } from "#nodegui/nodegui";
const win = new QMainWindow();
win.setWindowTitle("pacman UI");
win.resize(800, 600);
win.show();
(global as any).win = win;
it doesn't apply the blur configured in Kvantum like for Dolphin :/
I used this as a base: https://github.com/nodegui/nodegui-starter

X Client requests fail for GTK based window

I have created a simple gstreamer+gtk based application to play video file. "filesrc", "decodebin", "autovideosink", "autoaudiosink" gstreamer elements are used for that.
Main window is created using gtk_window_new(GTK_WINDOW_TOPLEVEL) and drawing area is created using gtk_drawing_area_new(). Drawing window is embedded in main window.
To render on gtk drawing window, its handle is passed to gstreamer video plugin as overlay using gstreamer api gst_video_overlay_set_window_handle()
By doing so video is not rendered only audio gets played.
Instead of GTK window if i pass XCreateWindow() handle to gstreamer video plugin as overlay then everything works fine. But i have to create GTK based player.
Now, when i start debugging the issue i have found below details.
"autovideosink" plugin gets blocked on XNextEvent inside mainloop thread(Luckily i have source code and verified using logs)
Then using xtrace utility it was found that most of X Request gets failed(See below) whereas in case of XCreateWindow all such Request gets successful Response.
002:<:000f: 52: Request(1): CreateWindow depth=0x18 window=0x01600001 parent=0x01400007 x=0 y=0 width=640 height=368 border-width=0 class=InputOutput(0x0001) visual=0x00000021 value-list={background-pixel=0x00000000 border-pixel=0x00000000 backing-store=NotUseful(0x00) override-redirect=false(0x00) colormap=CopyFromParent(0x00000000)}
002:<:0010: 24: Request(16): InternAtom only-if-exists=true(0x01) name='_NET_WM_STATE'
002:>:000f:Error 8=Match: major=1, minor=0, bad=20971527
002:<:001d: 8: Request(3): GetWindowAttributes window=0x01600001
002:<:001e: 8: Request(14): GetGeometry drawable=0x01600001
002:>:001d:Error 3=Window: major=3, minor=0, bad=23068673
002:>:001e:Error 9=Drawable: major=14, minor=0, bad=23068673
I have no idea why these requests gets failed for GTK window. Whereas in my old system(ubuntu 14.04) i can run the same player very well. Current system is ubuntu 16.04
Any X Server related configuration setting doing that?
Please suggest some solution or any idea how to debug it further to catch the real cause.
Prototype:
XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes)
autovideosink mentioned in question is actually imxeglvivsink. imxeglvivsink creates child window with gtk-window as parent(Check second parameter of XCreateWindow api).
Now GDK default Visual used for Parent Windodw(GTK) were different from X default Visual and this is the reason X CreateWindow Request gets failed.
I solved this problem with 2 solutions.
Solution 1:
In imxeglvivsink, while creating child window i used 'CopyFromParent' flag for 'visual' parameter of XCreateWindow api. By doing so, Visual for Parent and Child matches and X request CreateWindow gets successful.
I didn't like this solution as i have to replace original imxeglvivsink library with my new library.
Solution 2:
My ultimate goal is still same. I have to keep same visual for parent and child window. In this solution i changed Visual of Parent window(GTK) to X Default Visual. I did this change at application level and i don't have any dependency of imxeglvivsink. Code snippet to change GDK visual is below:
static int change_visual(GtkWidget *widget)
{
int nitems_return;
Display *x_display = XOpenDisplay(NULL);
Visual *x_visual = XDefaultVisual(x_display, DefaultScreen(x_display));
GdkScreen *gdk_screen = gdk_screen_get_default();
GList *gdk_visual_list = gdk_screen_list_visuals(gdk_screen);
GList *l;
for (l = gdk_visual_list; l != NULL; l = l->next)
{
Visual *temp = gdk_x11_visual_get_xvisual((GdkVisual *)l->data);
if(temp->visualid == x_visual->visualid) break;
}
//l is pointing the visual which is similar to system x visual. Lets change it.
gtk_widget_set_visual (widget, (GdkVisual *)l->data);
return 0;
}
I know i don't take care if visualid don't match inside the for loop. For me i always find GDK visual same to X Default Visual.

Change visual c++ application font

How to change font in all dialog forms in a visual c++ application?
I want to set Tahoma style.
Thanks.
You can set the font for a dialog in the resource it's created from. I believe that'll change the font on all the standard controls as well. If you have custom controls, you'll have to do additional work.
Note that if you want to have the font match the default UI font for the computer, then you can use a virtual font like "MS Shell Dlg 2" which will be mapped to Tahoma on XP, and Segoe UI on Vista+.
Replacing font in each dialog of your application would be rather tedious job.
You can employ MFC to do it for you.
Check InitInstance of your app. Look at AfxEnableControlContainer();
It is being called woithout any parameter even though AfxEnableControlContainer is declared as
void AFX_CDECL AfxEnableControlContainer(COccManager* pOccManager=NULL);
COccManager is a very interesting class and is used when has occ ( OLE custom controls) support, managing OLE container and site classes. All MFC applications are created by default with occ support. If you do not see AfxEnableControlContainer in the code generated by wizard, you do not have occ support enabled.
Anyway, instead using default occ implementation, use own and change it to change the font.
Derive class from COccManager. In this sample I call it CDlgOccManager. Override virtual PreCreateDialog:
virtual const DLGTEMPLATE* PreCreateDialog(_AFX_OCC_DIALOG_INFO* pOccDialogInfo,
const DLGTEMPLATE* pOrigTemplate);
In the implementation:
const DLGTEMPLATE* CDlgOccManager::PreCreateDialog(_AFX_OCC_DIALOG_INFO* pOccDialogInfo, const DLGTEMPLATE* pOrigTemplate)
{
CDialogTemplate RevisedTemplate(pOrigTemplate);
// here replace font for the template
RevisedTemplate.SetFont(_T("Tahoma"), -16);
return COccManager::PreCreateDialog (pOccDialogInfo, (DLGTEMPLATE*)RevisedTemplate.Detach());
}
Now you are changin font for all dialogs. Remember changing AfxEnableControlContainer call:
PROCESS_LOCAL(CDlgOccManager, pManager);
BOOL CDlgFontChangeApp::InitInstance()
{
AfxEnableControlContainer(pManager.GetData());
.
.
.
}
DO not forget to
#include "DlgOccManager.h"
For new verion of the MFC include afxdisp.h for older, occimpl.h for COccManager.
I just noticed something. It is not a blunder but it needs an explanation.
I have kept this code in my repository for a very, very, very long time.
It was a time when DLLs kept all data as global, making data available to all modules that loaded this dll. In order to force data to be stored in TLS area, I used PROCESS_LOCAL macro that expands to invoking CProcessLocal class that is still alive.
You can remove this macro and replace it with:
BOOL CDlgFontChangeApp::InitInstance()
{
CDlgOccManager* pManager = new CDlgOccManager();
AfxEnableControlContainer(pManager);
.
.
.
}

How to change the border style of applications main window in visual c++ win32 API

I have an application in Visual c++ (Win32 API). In my application the main window boarder is displayed in old windows styled. I have tried changing the wndWc.style values to WS_OVERLAPPED,WS_POPUP and other which are given in WinUser.h but there is no change in the appearance of the main window were as all my pop-up window are displayed in windows 7 style how this can be rectified. Any help in this regards will be highly appreciated. I have attached both the images the main window and the pop up window.
Code :
// our window class
WNDCLASS wndWc;
// ---------------------------------------------------------
// fill window class members
// ---------------------------------------------------------
wndWc.style = CS_GLOBALCLASS;
wndWc.lpfnWndProc = (WNDPROC) WndProc;
wndWc.cbClsExtra = 0;
wndWc.cbWndExtra = 0;
wndWc.hInstance = GetModuleHandle(NULL);
wndWc.hIcon = NULL;
wndWc.hCursor = LoadCursor(0, IDC_ARROW);
wndWc.hbrBackground = (HBRUSH)GetStockObject(0);
wndWc.lpszMenuName = NULL;
wndWc.lpszClassName = "XYZ";
// register class
if (!RegisterClass(&wndWc)) return false;
// ---------------------------------------------------------
// get actual screen resolution
int iSw = (WORD)GetSystemMetrics(SM_CXSCREEN); // height
int iSh = (WORD)GetSystemMetrics(SM_CYSCREEN); // height
// make a rectangle on the center of the screen
RECT rc = {(iSw - iWidth)/2, (iSh - iHeight)/2, width, height};
// create the window. the spaces on the window title
// are just to make sure this will be visible when the region
// is active. just run the app and you'll understand. =)
hWnd = CreateWindow("XYZ", "XYZ",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT, width,height,
NULL, NULL, GetModuleHandle(NULL), NULL);
It could be that your EXE has been flagged to run in compatibility mode for a previous OS version. Right-click the EXE, choose Properties, then ensure everything is switched off on the Compatibility tab. (Especially "Disable visual themes" and "run this program in compatibility mode for...")
Failing that...
It's unusual to need to do anything at all, but try this at the start of the app:
SetThemeAppProperties(STAP_ALLOW_NONCLIENT|STAP_ALLOW_CONTROLS)
If that doesn't work, try explicitly setting the theme for your window:
SetWindowTheme(hWnd, "WINDOW", NULL);
FWIW, I pasted your code in to a new Visual Studio 2008 project created using the "Win32 project" wizard, and it came out with a Windows 7 border. You usually have to go out of your way not to get the border, in fact.
There could be something unusual about the EXE you are building, like a flag in the EXE's header being set incorrectly. e.g. If it isn't specifying that it is a Windows GUI app, or maybe there are some version fields...
The EXE's manifest may also play a part, but I just tried deleting the manifest completely and my program still got a themed window, so it's probably not that.
If you look closely, you'll see that it's not just the border. The close button also uses the old visual style. Therefore, it's not sufficient that you change the window style. You must indicate that your app is Vista- and Aero-aware

Resources