How can I safely use WebKitGTK from a forked thread? - multithreading

I'm trying to make a simple app in Haskell using GTK3 and WebKit. This code creates and shows a window containing a WebView inside, which displays a random number each time a key gets pressed.
import Control.Monad.Trans (lift)
import Control.Concurrent (forkOS)
import System.Random (randomIO)
import Graphics.UI.Gtk -- gtk3
import Graphics.UI.Gtk.WebKit.WebView -- webkitgtk3
main = forkOS $ do
-- Init GTK.
initGUI
-- Create a window which would finish the GTK loop
-- after being closed.
window <- windowNew
window `after` objectDestroy $
mainQuit
-- Create a WebView inside.
webView <- webViewNew
set window [containerChild := webView]
-- Make the WebView display a random number on key press.
webView `on` keyReleaseEvent $ lift $ do
x <- randomIO :: IO Int
webViewLoadString webView (show x) Nothing Nothing ""
return True
-- Run GTK.
widgetShowAll window
mainGUI
When I run it in GHCi (7.8.3), it works fine. However, when I run it again without quitting GHCi, the WebView never shows anything – just plain white area. This is upsetting, as I like to tinker with code in GHCi.
Of course, everything works just fine if I don't use forkOS and run the whole thing in the main thread. What's the reason for this limitation (I thought all GTK functions considered the “main” thread to be the one in which initGUI was called), and can it be overcome somehow?

If it works like python(I don't know haskell) you should keep the gtk main loop in the main thread.
In your second thread call g_idle_add with a callback to make changes with gtk, and transport data between your second thread, and gtk. You should start your non-main thread before gtk main so it's not blocked.
I'm sure there is a binding of g_idle_add in haskell. There is also g_timeout_add which works for this too.
This all has something to do with gtk not being thread safe.

Related

What are the equivalent of these functions in gtk2Hs when migrating from gtk2 to gtk3

I'm converting a Haskell program written with Gtk2Hs gtk2 to Gtk2Hs gtk3 and I'm looking the equivalent function of Gtk2Hs gtk2 for:
onActivateLeaf to catch the activation of a menu item.
onExpose to draw in a widget.
onClicked to catch the clicked event of a button.
onDestroy to catch the destroy event of a Widget.
I had a look at these function in the documentation but they are used to send a signal not to catch one.
menuItemActivate buttonClicked widgetDestroy
Can you tell me the right way to catch event for widget with the Gtk2Hs gtk3 API ?
I'm not 100% sure, but I would start by checking these:
menuItemActivated
draw
buttonActivated
destroyEvent
The on prefixes have been done away with in favor of a single function named on.

Xmonad showing only 1 window on screen

I decided to try Xmonad today and installed it on VM with Arch linux. Without spacing it works perfectly, but when I am adding it, Xmonad only show one newest window on screen (if I open new window, old one just disappear).
There is my simple configuration I made using information from there:
import XMonad
import Xmonad.Layout.Spacing
main :: IO ()
main = xmonad $ def
{ layoutHook = spacingWithEdge 10 $ Full
}
Sorry if I am being dumb. This is my first time using Xmonad and Haskell.
Your configuration replaces the default layoutHook with one that only makes the Full layout available. Changing the relevant line to...
{ layoutHook = spacingWithEdge 10 $ layoutHook def
... should add the spacing while keeping all the default layouts available. Note that:
You can switch between the available layouts, with the default key binding being Alt + Space; and
You can switch the focused window, even while using the Full layout, with the default key binding being Alt + Tab.

Dialog and button callback in Haskell OpenGL

Graphics.UI.GLUT has a Dial and Button callback. I don't find any example of use of this callback. I wanted to have one because currently I use the keyboard and the mouse callbacks and this is not enough and not user-friendly.
I've tried to do one such callback. In my program:
dial :: IORef GLdouble -> DialAndButtonBoxCallback
dial zoom index =
case index of
DialAndButtonBoxDial 1 1 -> zoom $~! (+1)
_ -> return ()
Then I expect to see a button (button 1) in the OpenGL window which would increment zoom when I press on this button (zoom $~! (+1) zooms the graphic, I use it in the keyboard callback currently, no problem with that).
Then in my main file:
zoom <- newIORef 0.0
dialAndButtonBoxCallback $= Just (dial zoom)
The code compiles. But when I run the program, there's no dialog box appearing anywhere.
I would appreciate any help. Maybe I have to create a dialog box first ? I don't see anything like this in the documentation.
A dial and button box is not a dialog box. It’s a special purpose type of hardware, like a mouse, keyboard, joystick, or steering wheel. Eg this company makes some.
Glut is not a gui library like gtk. It lets you get user input and draw things on the screen. You need to figure out exactly how to draw all your user interface components if you want to use glut

abaqus thread tkinter Tk window refreshing never

I have run into a problem durring abaqus programming with phyton 2.7.
I'm using Tkinter and making a window with a lot of controls on it.
My main problem is that durring my plugin window is opened, the user needs to click on abaqus menuitems, browse modells, etc. So using the main program while my plugin still works on screen.
If I do create my Tk window without thread, than when the user clicks on abaqus main windo functions while my plugin is opened, then abaqus will not respond or crash with "LoadlibraryA error 193"
(example: while plugin runs and user clicks on Viewvport menü/ViewPort Annotation Options then he/she wont be able to change tabs)
If i do create my Tk window inside a thread, then the al the Tk window controls will only responds the mouse events after I leave the Tk window with my cursor.
(example: I make 2 notebook page and after start i click on the not selected one. then nothing happens until my mous inside the Tk window, but as soon as i move it out, the click takes effect and the tab changes...)
The threaded version of my code:
import threading
class pilotDB(threading.Thread):
def shutdown_ttk_repeat(self):
self.root.eval('::ttk::CancelRepeat')
self.root.destroy()
def __init__(self):
import threading
threading.Thread.__init__(self)
def refresh(self):
self.root.after(50, self.refresh)
def tabpage(self):
import ttk
import sys
self.notebook = ttk.Notebook(self.root)
self.tabpage_tab1 = ttk.Frame(self.notebook,width=400,height=500)
self.tabpage_tab2 = ttk.Frame(self.notebook,width=400,height=500)
self.notebook.add(self.tabpage_tab1, text='Tab1')
self.notebook.add(self.tabpage_tab2, text='Tab2')
self.notebook.place(x=30, y=40)
def run(self):
import Tkinter
self.root = Tkinter.Tk()
self.root.protocol("WM_DELETE_WINDOW", self.shutdown_ttk_repeat)
self.tabpage()
self.root.after(1000, self.refresh())
self.root.mainloop()
app = pilotDB()
app.start()
app/pilotDB has no function named "start" (last line of the code posted). If I put a call to self.run() in init, and delete threading, then the program works as expected, i.e. opens a window and displays 2 tabs and the user can switch between tabs, all the time the mouse is in the window as is normal. Note also that the refresh() function does nothing but call itself repeatedly. You should try to find the offending code by first commenting the lines for the "WM_DELETE_WINDOW", shutdown_ttk_repeat and the call to execute the function tabpage() which leaves a basic window. Then uncomment one and run it, and repeat until you find the error.

Is there an 'Onload' sort of a signal for QMainWindow?

PyQt noob here.
I need to call a dialog window as soon as the main window is loaded.
I also need the main window to be displayed in the background when this dialog is shown on top of it.
So, I'm looking for a 'onload' sort of a signal for the main window to call the function which in turn calls the dialog. Is there any other way around?
You can override the QWidget.showEvent for your QMainWindow to achieve the same effect. However, you need to keep track of whether it is the first time the window is shown or not since that method will be called every time the window is displayed after being hidden. Then use a modal QDialog so that the main window is shown in the background, but not enabled.

Resources