Screen capture with gtk2hs using gtk3 - haskell

I'm aware that using gtk2 it was possible to capture a screen into a pixbuf using gtk2hs. The solution is given here: Screen capture in Haskell?.
The problem is that pixbufGetFromDrawable is absent in gtk3 (at least in gtk2hs). Can somebody recommend the solution to this problem? I need this for linux, not windows.
The solution from the link is duplicated here for convenience.
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Gdk.Screen
import System.Environment
main = do
[fileName] <- getArgs
initGUI
Just screen <- screenGetDefault
window <- screenGetRootWindow screen
size <- drawableGetSize window
origin <- drawWindowGetOrigin window
Just pxbuf <- pixbufGetFromDrawable window ((uncurry . uncurry Rectangle) origin size)
pixbufSave pxbuf filename "png" []

Related

Config No Border For Specific Windows in Xmonad

The Goal
Set no border for specific windows in Xmonad.
Concrete example: I'd like firefox and feh always have no border. I want to set this not only for specific layout (e.g., single window) or specific window mode like float.
Attempt A
The most straight forward idea I have is to add a line in manageHook, which supposes to handle window creation. So I put a line in my customized ManageHook:
className =? "firefox" --> ask >>= \w -> liftX $ withDisplay $ \d -> io $ setWindowBorderWidth d w 0 >> idHook
It compiles, but unfortunately nothing happens when I start firefox.
Then I try to debug it:
Tested the following and it works (new firefox window is floated), which indicates my customized ManageHook works, and my logic (modify the window followed by idHook) should be OK.
className =? "firefox" --> ask >>= liftX . float >> idHook
Tested setWindowBorderWidth function by trying toggleBorder in XMonad.Actions.NoBorders. toggleBorder does something similarly calling setWindowBorderWidth. I used a key binding to invoke toggleBorder and it works. So setWindowBorderWidth works well during a Xmonad session after the window is created.
Tested the following (found it here) but it doesn't work, same as my code (Attempt A).
className =? "firefox" --> ask >>= liftX . toggleBorder >> idHook
Attempt B
I find the hasBorder function in XMonad.Layout.NoBorders and also this answer, but I did not succeed.
If I only put className =? "firefox" --> hasBorder False in ManageHook but does not use layoutHook, nothing happens. I checked the source code of hasBorder and found it only broadcast a message but not set the border. I think I may need to invoke a layoutHook from XMonad.Layout.NoBorders to really set the border but I am not sure which one I should use. And I am also not sure if I need to specify any layout to use XMonad.Layout.NoBorders.
Questions
Does Xmonad set border after ManageHook so my code in Attempt A is nullified?
If Q1 is true, does it mean I can only set no border at LayoutHook (likely using XMonad.Layout.NoBorders) when the window is drawn on the screen?
If Q2 is true, do I need to specify a layout and which layoutHook I can use?
I'd go with attempt B:
Import the NoBorders module from xmonad-contrib:
import XMonad.Layout.NoBorders
Define your constraints in your manageHook:
className =? "feh" --> hasBorder False
className =? "firefox" --> hasBorder False
And apply one of the module's layout modifiers, e.g. smartBorders to all of your layouts at once:
layoutHook = smartBorders $ Full ||| ResizableTall 1 (3/100) (1/2) [] ||| ...
Note: This will only affect windows created after recompiling and restarting XMonad. Already existing instances of firefox and feh would still have their borders until closed and restarted.
I think I find the answers to my questions.
Does Xmonad set border after ManageHook so my code in Attempt A is nullified?
Yes.
Looks like xmonad window init logic is in XMonad/Operations.hs. When a window is created, the function manage() is called. The last three lines of the function:
load ManageHook,
apply ManageHook with runQuery(),
run the windows() function, which loads border information from config and applies setInitialProperties() function to set borders according to the border config.
The last step setInitialProperties() calls setWindowBorderWidth() with border width loaded from config, which nullifies my setWindowBorderWidth() as a ManageHook step.
If I do not change this logic in XMonad/Operations.hs, it looks like I can only go with Attempt B. However, I really find the windows jumping issue annoying. This does not only occur in Full layout, I am using Tall with a single window. When I switch between two workspaces, both of which have a single window with no border, I see this jumping. The visual effect affects all pixels on screen since it needs to scale the entire window.
If Q1 is true, does it mean I can only set no border at LayoutHook (likely using XMonad.Layout.NoBorders) when the window is drawn on the screen?
No. Another possibility besides LayoutHook is logHook.
If Q2 is true, do I need to specify a layout and which layoutHook I can use?
Yes. However, if logHook is used, there is no need to overwrite the default layouts.
Solution
Let's put up a new XMonad extension to achieve this functionality that people asked 12 years ago.

How to get the value of a pixel from the screen (GTK 3, Shell, Linux) [duplicate]

This question already has answers here:
How can I grab the color of a pixel on my desktop? (Linux)
(4 answers)
Closed 2 years ago.
I am trying to do some automation on Linux, and I can't find a good way to get a pixel value from the screen, given 2 coordinates.
I have this python code:
#!/usr/bin/env python3
import pyautogui
import sys
image = pyautogui.screenshot()
print(str(image.getpixel((int(sys.argv[1]), int(sys.argv[2])))))
How can I do this without taking a screenshot and instead read from the pixel buffer?
If there is a program that someone knows about that can do this (I've heard AutoHotkey on windows can), that would also be helpful, as I'm using shell script (and lots of xdotool) to do the automation.
The following code, when called like this: ./getColor.py [X coordinate] [Y coordinate], will print the decimal RGB color value of the specified pixel on the screen in the form (R, G, B)
#!/usr/bin/python
import gi, sys
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
pixbuf = Gdk.pixbuf_get_from_window(Gdk.get_default_root_window(), int(sys.argv[1]), int(sys.argv[2]), 1, 1)
print(tuple(pixbuf.get_pixels()))

Set display font family in wxhaskell?

I'm trying to build a little program to learn some wxHaskell, a haskell library for wxwidgets.
It would be beneficial for this particular one if I could set the font of a text field to monospaced, but I have no idea how to do that if it is possible.
In wxwidgets there seems to be setFamily and wxFONTFAMILY_TELETYPE, but I can't find anything about this being implemented in wxHaskell, nor how to use it if it were.
Is it possible to do this?
Here's an example, in the change the line in the Hello, World program in the wxHaskell Quick Start from:
= do f <- frame [text := "Hello!"]
to
= do f <- frame [text := "Hello!", font := fontFixed]
Found this by digging down in the docs here

XMonad cycle through all windows on visible workspaces

I'm using XMonad on a dual screen set up, and would like to be able to cycle focus through every window visible on either screen (say, with alt+tab). The behavior would be similar to XMonad.Actions.WindowNavigation, except it wouldn't be bound to a direction, and just cycle through them in some order that makes sense (left to right, top to bottom for instance).
I've found some code here that claims to manipulate the StackSet to solve this problem, and I got it to compile but it wouldn't do what I wanted. Unfortunately my understanding of Haskell is pretty limited, so I've been unable to either write my own or fix whatever is wrong with the code above.
You can use the CycleWS module in xmonad-contrib
It has bindings that you can use to cycle through non-empty workspaces:
import XMonad.Actions.CycleWS
myKeys homeDir conf#(XConfig {XMonad.modMask = modm}) = M.fromList $
[ -- (your own bindings here)
-- Cycle non-empty workspaces with mod+tab or mod+shift+tab
, ((modm , xK_Tab ), moveTo Next NonEmptyWS)
, ((modm .|. shiftMask, xK_Tab ), moveTo Prev NonEmptyWS)
]
My full config is here if you want a complete example.
This functionality has since been added to xmonad-contrib by this pull request.
Example usage:
import XMonad.Actions.GroupNavigation
within the keys section
-- use Alt+Tab and Alt+Shift+Tab to change focus to different windows across workspaces
((alt, xK_Tab ), nextMatch Forward isOnAnyVisibleWS),
((alt .|. shift, xK_Tab ), nextMatch Backward isOnAnyVisibleWS),

What is the right way to render Cairo updates in Gtk2hs?

I'm writing a Haskell program with click-and-drag functionality, so with each mouse movement event an update gets painted to the window. At the moment I'm using
renderWithDrawable myCanvas update
However this is flickering a lot. My understanding is that I need to create a separate drawable (a "surface"?), render to that, and then blit it onto the screen window in a single operation. However I'm confused as to the right way to do this.
I've found drawWindowBeginPaintRegion, which talks about eliminating flicker.
However it is removed in Gtk3 according to the Haddock docs. So I'm not sure if I should use this, as it seems to be deprecated.
I've also found renderWithSimilarSurface in Cairo, which seems to do something similar.
I'm also not sure how these functions relate to renderWithDrawable: do I have to use them inside that function, or what?
What is the right way to do this?
Edit
This seems to be a known thing in Cairo. I'm trying to figure out how to handle this in Haskell.
Explanation and solution in Python
Description of how to handle this issue in raw C
The right way to do this is to make sure all your drawing comes from within expose events, and operates on the draw window provided by the event. You can mark a region as "dirty" and trigger a synthetic expose event using drawWindowInvalidateRect, drawWindowInvalidateRegion, or widgetQueueDraw.
A quick worked example of setting up the drawing pipeline follows. It is excerpted from a custom Viewport type, which does Google-maps style panning with smooth motions on drag-and-release operations, that I built for a side-project some time ago. To support that, it has to redraw on mouse motion events, so it addresses a similar use case to your described problem. I've elided irrelevant stuff with ... to highlight the important bits. I've uploaded the complete project to github just now, so you can browse the repo to see the full details of Viewport. (It's been years though, so there's probably a fair bit of bitrot -- don't expect the project to just build and run with modern GHCs/packages.)
viewportNew :: Viewport -> IO DrawingArea
viewportNew v = do
da <- drawingAreaNew
-- ...
on da exposeEvent $ exposeViewport posRef (draw v)
-- ...
exposeViewport :: IORef Position -> RegionRenderer -> EventM EExpose Bool
exposeViewport posRef draw = do
dw <- eventWindow
region <- eventRegion >>= liftIO . regionGetRectangles
-- ...
liftIO . renderWithDrawable dw $ do
-- Cairo () action goes here
-- can reference region to decide which things to draw
draw region
return True -- see documentation of exposeEvent for what this means
This template should take advantage of gtk's built-in double-buffering and work with both the gtk and gtk3 packages.

Resources