Patch scrolling back in suckless ST terminal to support mouse wheel - c

The ST terminal has a patch for scrolling back. I want to update said patch to enable mouse wheel up and down signals in additions to "PageUp" and "PageDown". I suspect that a small change in config.h is what is needed but I have no experience in terminal code thus my plea for help.
In the source code, in config.h these lines appear:
static Mousekey mshortcuts[] = {
/* button mask string */
{ Button4, XK_ANY_MOD, "\031" },
{ Button5, XK_ANY_MOD, "\005" },
};
So, clearly, we know what Button4/5 are. In addition, we have these:
static Shortcut shortcuts[] = {
/* mask keysym function argument */
[...]
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
};
So, naively, I a assuming that adding another two raw (one for wheel up, one for wheel down) would do the trick. However, what?
Note: I know that suckless recommends using a terminal multiplexer such as tmux. I use that already. However, sometimes (rarely) I just want to use a terminal without tmux and this feature would be useful. Please do not comment/answer to use tmux, this is not what this question is about.

It is not that simple. This question occasionally arises when someone wants left/right scrolling for a mouse trackball.
On the left column of the tables is an X event. Those are limited to combinations of predefined symbols.
Button4 and Button5 are mentioned because those are conventionally used to pass the mouse wheel events. That has been the case for quite a while; there was a resource file used before modifying xterm in 1999 (patch #120) to make this a built-in feature.
The possible X events are laid out in C header files — X.h — and tables in the X source code; no wheel mouse events are provided for as such. For instance, there is a table in the X Toolkit library which lists all of the possibilities (for clients using X Toolkit such as xterm). xev uses the header-definitions.
If X were to support wheel mouse events in a different way, it would probably use new function calls for this purpose since the existing information may be packed into bit-fields in a way that precludes easy extensibility.

There is now a standalone program scroll that provides scrollback buffer for any terminal emulator. At the time of writing this answer, it is still in an experimental state, a lot of bugs are expected. In spite of that, it already handles scrollback better than the scrollback patches for st. E.g. resizing the terminal will wrap previous output instead of cut off and lose them.
To enable it, first of course download/clone the source code from suckless website and build it locally.
Then modify this line in config.def.h of st (you have to fetch the recent git commits to get support for scroll)
char *scroll = NULL;
to
char *scroll = "/path/to/scroll";
Now rebuild st, and run st. It will automatically use scroll to provide the scrollback buffer.
As stated in the manual, another way without modifying st's source code is to run st with the following command after you have installed both st and scroll:
/path/to/st -e /path/to/scroll /bin/sh

From the suckless site, there are some scroll back patches that allow scrolling using Shift+MouseWheel as well as full mouse scroll. The last patch might break other mkeys excluding scrolling functions.

Related

How do I temporarily mask touchscreen touches events in C on Linux?

I've written a program in C that activates commands when the user flicks from the edges of the screen. For instance, flicking upward from the bottom edge brings up the keyboard. This portion of my code is working fine.
The issue I am having is that the very making of the flicking motion also interrupts applications, as one's fingers need to drag across some of the screen to activate the trigger. I don't want this action to affect apps that are on screen while the user flicks the screen edge.
I would like to add some C code that will temporarily mask touch events. I can handle the code that activates the masking properly (such as events which originate from the edges of the screen) and when to unmask.
I can handle all of the above with exception to the code that does the masking and unmask of the touch events. I am not asking for a full complete code but just a pointer in the right direction. I would like to know what library to use and the appropriate command which does the masking.
I'll not post the code as it is a couple hundred lines long and would surely lead to straying from the question; the code works fine, aside from the issue above.
I am on a Raspberry Pi 3b+ with Rasbian OS and an Official Raspberry Pi 7" touch screen. The main C libraries which I am using for the program are linux/input.h and X11/extensions/XTest.h.
I will supply any additional info if asked.
* EDIT *
Finally figured it out! The biggest issue what finding what to search for...
I masked the pointer/touch events with the following command:
XGrabPointer(dpy, root, False, PointerMotionMask, GrabModeSync, GrabModeAsync, None, None, CurrentTime);
In the code above, the touch motion is masked (PointerMotionMask), the pointer/touch for windows is masked (GrabModeSync), and the keyboard key events are not masked (GrabModeAsync).
To unmask, I used these commands:
XQueryPointer(dpy, RootWindow (dpy, 0),
&event.xbutton.root, &event.xbutton.window,
&event.xbutton.x_root, &event.xbutton.y_root,
&event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
usleep(10000);
XUngrabPointer(dpy, CurrentTime);
usleep(10000);
XQueryPointer(dpy, RootWindow (dpy, 0),
&event.xbutton.root, &event.xbutton.window,
&event.xbutton.x_root, &event.xbutton.y_root,
&event.xbutton.x, &event.xbutton.y,
&event.xbutton.state);
I'm still learning Xlib, so I don't entirely know why one needs to add usleep and XQueryPointer, but I found that it's needed or the program is unpredictable. I merely copied this type of code from my buttonPress() function. I couldn't find any complete, simple, and clear answer, so a lot of try/fail was required on this one.
Now, I am able to swipe from the edges on my Raspberry Pi touchscreen, and there is no interruption to the currently active window.
If anyone wants to see the code, just ask and I'll post it in full. And if anyone knows how this code works and why I need to add usleep and XQueryPointer, I'd like to hear.
Sources used:
X11: will XGrabPointer prevent other apps from any mouse event?
https://tronche.com/gui/x/xlib/input/pointer-grabbing.html

SDL_CreateRenderer() vs SDL_CreateSoftwareRenderer()

Does a renderer created with SDL_CreateSoftwareRenderer() behave any differently than one created with SDL_CreateRenderer() using the SDL_RENDERER_SOFTWARE flag?
There are differences on how these two operate, or even their intended use. SDL_CreateSoftwareRenderer creates software renderer drawing to given surface. There is no requirement for this surface to be window surface, you can draw to backbuffer, convert it to texture and feed the result to d3d or opengl renderer.
SDL_CreateRenderer creates renderer for a given window, meaning it is supposed to draw to that window - with some checks, like opengl or vulkan requires window to be created with specific flags. It goes through list of available rendering backends and tries to find the one that matches your flags the best. Eventually if it decides to use software renderer (either nothing else is supported or software is explicitly requested, although there is more than one way to do so - see the last paragraph) it calls more-or-less SDL_CreateSoftwareRenderer(SDL_GetWindowSurface(window)) (not exactly so, but if you'll trace the code it is the same).
flags in SDL_CreateRenderer are not absolute; if a hint says to use direct3d or opengl, your SDL_RENDERER_SOFTWARE will be ignored. SDL_CreateSoftwareRenderer is always software.
Nope! They should behave the same.
SDL2 has quite a list of convenience functions which are equivalent to simply calling another function with a specific set of arguments. For instance, looking at the API listing by name, you'll find that the SDL_LogMessage () function is matched with a variety of other functions that implicitly specify the priority field, like SDL_LogVerbose () or SDL_LogError ().
To some extent, in addition to providing ease-of-use, these combined convenience functions help provide brevity to code while still maintaining clarity. As such, I would advise and advocate for their use when possible!

speed mismatch in linux and windows

void myDisplay(void) //glutDIsplayFunc(mydisplay)
{
while(1)
{
glClear(GL_COLOR_BUFFER_BIT);
x=rand()%680;
y=rand()%680;
sx=(x-p)/100;
sy=(y-q)/100;
glColor3f(0.7+sx,0.1-sy,0.6);
for(g=0;g<120;g++)
{
p+=sx;
q+=sy;
glBegin(GL_POINTS);
glVertex2i(p,q);
glEnd();
glutSwapBuffers();
}
}
}
This code just chooses one arbitrary point on screen and do smooth translation.
I compiled this same code in visual C++ and on linux and I noticed that the translation (from one point to another) happens fast on windows while on linux it drags slow.
why this is so?
Your are using a movement vector which is totally independent of the fps. This means that it will run with a different speed on a different machine.From your description I guess that on your Linux machine, sync to vblank is enabled, limiting your framerate to the refresh rate of the display (typically 60Hz), while on the windows machine, it is disabled, running with a much higher frequency.
You should use a timer to control animations, and define your animation speeds in sapce-units per time-unit.
Furthermore, you should follow Andon M. Coleman's advice: The GLUT display callback is mean to draw a single frame. If you want an animation over many frames, use some variables to store your current state (for example, the current position and direction vector) and update them for each step. The way you currently implemented it, GLUT's event handling will by blocked for the whole duration of the animation. On windows, this might even trigger "the application is not responding" warning, when your animation takes too long.

Ncurses mouse wheel scroll up

I want to handle scroll with the mouse wheel using ncurses but I am having a problem similar to this issue :
http://lists.gnu.org/archive/html/bug-ncurses/2012-01/msg00011.html
Besides, mouse wheel-up event is only reported as mask 02000000
(BUTTON4_PRESSED) just one time, even if I scroll the wheel continuously.
I tried ncurses 5.7 to 5.9 on debian 5,6,7 and archlinux.
Every single ncurses lib had NCURSES_MOUSE_VERSION 1, tried recompiling with --enable-ext-mouse.
Scrolling down works perfectly, ncurses reports multiple REPORT_MOUSE_POSITION 0x8000000 per scroll and a single BUTTON2_PRESSED 0x128.
Scrolling up causes only a single report of BUTTON4_PRESSED 0x80000
MEVENT event;
mousemask(BUTTON1_CLICKED|BUTTON4_PRESSED|BUTTON2_PRESSED, NULL); // Tried with REPORT_MOUSE_POSITION also
while(run)
{
switch(in = getch())
{
case KEY_MOUSE:
if(getmouse(&event) == OK)
{
else if (event.bstate & BUTTON4_PRESSED)
line_up();
else if (event.bstate & BUTTON2_PRESSED || event.bstate == 0x8000000)
line_down();
}
break;
}
}
Add mouseinterval(0); somewhere outside of your main loop. (Perhaps right after keypad(stdscr, TRUE);)
This command causes there to be no delay with mouse events, so you won't be able to detect BUTTON1_CLICKED or BUTTON1_DOUBLE_CLICKED and similar things (though you can implement that yourself by keeping track of BUTTON1_PRESSED, BUTTON1_RELEASED, and the time between mouse events).
A small caveat though, when I tested this with C everything worked, except that getmouse returned ERR on scroll wheel down events. This could potentially still be useful though, as it was the only event which gave this result. When I tested the same code in Rust it worked perfectly though, so your mileage may vary.
ncurses5 does not support wheel mouse, except as an optional feature. That is because the layout of bits in mousemask_t chose in the mid-1990s left insufficient space for a fifth mouse-button. At the time, some other devices (for playing games) seemed more important; this was before X provided a protocol for wheel mice.
The "extended mouse" is an optional feature (since it would change the application binary interface), and has not been incorporated in ncurses5 packages, although it has been available for some time.
For reference, see the discussion of --enable-ext-mouse in the ncurses changelog, starting in 2005.
ncurses6 does support wheel mouse (see release notes). Perhaps that will be standard in Debian 9.

UIPageViewController navigates to wrong page with Scroll transition style

My UIPageViewController was working fine in iOS 5. But when iOS 6 came along, I wanted to use the new scroll transition style (UIPageViewControllerTransitionStyleScroll) instead of the page curl style. This caused my UIPageViewController to break.
It works fine except right after I've called setViewControllers:direction:animated:completion:. After that, the next time the user scrolls manually by one page, we get the wrong page. What's wrong here?
My workaround of this bug was to create a block when finished that was setting the same viewcontroller but without animation
__weak YourSelfClass *blocksafeSelf = self;
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){
if(finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
[blocksafeSelf.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];// bug fix for uipageview controller
});
}
}];
This is actually a bug in UIPageViewController. It occurs only with the scroll style (UIPageViewControllerTransitionStyleScroll) and only after calling setViewControllers:direction:animated:completion: with animated:YES. Thus there are two workarounds:
Don't use UIPageViewControllerTransitionStyleScroll.
Or, if you call setViewControllers:direction:animated:completion:, use only animated:NO.
To see the bug clearly, call setViewControllers:direction:animated:completion: and then, in the interface (as user), navigate left (back) to the preceding page manually. You will navigate back to the wrong page: not the preceding page at all, but the page you were on when setViewControllers:direction:animated:completion: was called.
The reason for the bug appears to be that, when using the scroll style, UIPageViewController does some sort of internal caching. Thus, after the call to setViewControllers:direction:animated:completion:, it fails to clear its internal cache. It thinks it knows what the preceding page is. Thus, when the user navigates leftward to the preceding page, UIPageViewController fails to call the dataSource method pageViewController:viewControllerBeforeViewController:, or calls it with the wrong current view controller.
I have posted a movie that clearly demonstrates how to see the bug:
http://www.apeth.com/PageViewControllerBug.mov
EDIT This bug will probably be fixed in iOS 8.
EDIT For another interesting workaround for this bug, see this answer: https://stackoverflow.com/a/21624169/341994
Here is a "rough" gist I put together. It contains a UIPageViewController alternative that suffers from Alzheimer (ie: it doesn't have the internal caching of the Apple implementation).
This class isn't complete but it works in my situation (namely: horizontal scroll).
As of iOS 12 the problem described in the original question seems to be almost fixed. I came to this question because I experienced it in my particular setup, in which it does still happen, hence the word "almost" here.
The setup I experienced this issue was:
1) the app was opened via a deep link
2) based on the link the app had to switch to a particular tab and open a given item there via push
3) described issue happened only when the target tab was not previously selected by user (so that UIPageViewController was supposed to animate to that tab) and only when setViewControllers:direction:animated:completion: had animated = true
4) after the push returning back to the view controller containing the UIPageViewController, the latter was found to be a big mess - it was presenting completely wrong view controllers, even though debugging showed everything was fine on the logic level
I supposed that the root of the problem was that I was pushing view controller very quick after setViewControllers:direction:animated:completion: called, so that the UIPageViewController had no chance to finish something (maybe animation, or caching, or something else).
Simply giving UIPageViewController some spare time by delaying my programmatic navigation in UI via
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { ... }
fixed the issue for me. And it also made the programmatic opening of the linked item more user friendly visually.
Hope this helps someone in similar situation.
Because pageviewVC call multi childVC when swipe it. But we just need last page that visible.
In my case, I need to change index for segmented control when change pageView.
Hope this help someone :)
extension ViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard let pageView = pageViewController.viewControllers?.first as? ChildViewController else { return }
segmentedControl.set(pageView.index)
}
}
This bug still exists in iOS9. I am using the same workaround that George Tsifrikas posted above, but a Swift version:
pageViewController.setViewControllers([page], direction: direction, animated: true) { done in
if done {
dispatch_async(dispatch_get_main_queue()) {
self.pageViewController.setViewControllers([page], direction: direction, animated: false, completion: {done in })
}
}
}
Another simple workaround in Swift: Just reset the UIPageViewController's datasource. This apparently clears its cache and works around the bug. Here's a method to go directly to a page without breaking subsequent swipes. In the following, m_pages is an array of your view controllers. I show how to find currPage (the index of the current page) below.
func goToPage(_ index: Int, animated: Bool)
{
if m_pages.count > 0 && index >= 0 && index < m_pages.count && index != currPage
{
var dir: UIPageViewController.NavigationDirection
if index < currPage
{
dir = UIPageViewController.NavigationDirection.reverse
}
else
{
dir = UIPageViewController.NavigationDirection.forward
}
m_pageViewController.setViewControllers([m_pages[index]], direction: dir, animated: animated, completion: nil)
delegate?.tabDisplayed(sender: self, index: index)
m_pageViewController.dataSource = self;
}
}
How to find the current page:
var currPage: Int
{
get
{
if let currController = m_pageViewController.viewControllers?[0]
{
return m_pages.index(of: currController as! AtomViewController) ?? 0
}
return 0
}
}
STATEMENT:
It seems that Apple has spotted that developers are using UIPageViewController in very different applications that go way beyond the
originally intended ones Apple based their design-choices on in the first place. Rather than using it in a gesture driven linear fashion
PVC is often used to programmatically jump to random
positions within a structured environment. So they have enhanced their implementation of UIPageViewController and the class is now calling both DataSource
callbacks
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
after setting a new contentViewController on UIPageViewController with
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
even if an animated turn of pages rather suggests a linear progress in an e.g. page hierarchy like a book or PDF with consecutive pages. Although - I doubt that Apple from a HIG standpoint
is very fond of seeing PVC being used this way, but - it doesn't break backwards compatibility, it was an easy fix, so - they eventually did it. Actually it is just one more call of one of the two DataSource methods that is absolutely unnecessary in a linear environment where pages (ViewControllers) have already been cashed for later use.
However, even if this enhancement might come in very handy for certain use-cases the initial behavior of the class is NOT to be considered a bug. The fact that a lot of developers do - also in other
posts on SO that accuse UIPageViewController of misbehavior - rather emphasizes a widely spread misconception of its design, purpose and functionality.
Without trying to offend any of my fellow developers here in this great facility I nonetheless decided not to remove my initial 'disquisition' that clearly explains to the OP the mechanics of PVC and why his assumption is wrong that he has to deal with a bug here.
This might also be of use for any other fellow developer too who struggles with some intricacies in the implementation of UIPageViewController!
ORIGINAL ANSWER:
After having read all the answers over and over again - included the
accepted one - there is just one more thing left to say...
The design of UIPageViewController is absolutely FLAWLESS and all the
hacks you submit in order to circumvent an alleged bug is nothing but
remedies for your own faulty assumptions because you goofed it up in the
first place!!!
THERE IS NO BUG AT ALL! You are just fighting the framework. I'll explain why!
There is so much talk about page numbers and indices! These are concepts the
controller knows NOTHING about! The only thing it knows is - it is showing
some content (btw. provided by you as a dataViewController) and that it can
do something like a right/left animation in order to imitate a page turn.
CURL or SCROLL...!!!
In the pageViewController's world there only exists a current SPACE (let's call
it just this way to avoid confusion with pages and indices).
When you initially set a pageViewController it only minds about this very SPACE.
Only when you start panning its view it starts asking its DataSource what it
eventually should display in case a left/right flip should happen. When you start
panning to the left the PVC asks first for the BEFORE-SPACE and then for the
AFTER-SPACE, in case you start to the right it does it the other way round.
After the completed animation (a new SPACE is displayed by the PVC's view) the
PVC considers this SPACE as its new center of the universe and while it is at it, it
asks the DataSource about the one it still does not know anything about. In case of
a completed turn to the right it wants to know about the new AFTER space and in
case of a completed turn to the left it asks for a new BEFORE space.
The old BEFORE space (from before the animation) is in case of a completed turn to
the right completely obsolete and gets deallocated as soon as possible. The old center
is now the new BEFORE and the former AFTER is the new center. Everything just
shifted one step to the right.
So - no talk of 'which page' or 'whatever index' - just simply - is there a BEFORE or
an AFTER space. If you return NIL to one of the DataSource callbacks the PVC just
assumes it is at one extreme of your range of SPACES. If you return NIL to both
callbacks it assumes it is showing the one and only SPACE there is and will never
ever again call a DataSource callback anymore! The logic is up to you! You define
pages and indices in your code! Not the PVC!!!
For the user of the class there are two means of interacting with the PVC.
A pan-gesture that indicates whether a turn to the BEFORE/AFTER space is desired
A method - namely setViewControllers:direction:animated:completion:
This method does exactly the same than the pan gesture is doing. You are indicating the
direction (e.g. UIPageViewControllerNavigationDirectionBackward/Forward)
for the animation - if there is one intended - which in other words just means -> going to
BEFORE or AFTER...
Again - no mentioning of indices, page-numbers etc....!!!
It is just a programmatically way of achieving the same a gesture would!
And the PVC is doing right by showing the old content again when moving back
to the left after having moved to the right in the first place. Remember
- it is just showing content (that you provide) in a structured way - which is a 'single page turn' by design!!!
That is the concept of a page turn - or BOOK, if you like that term better!
Just because you goof it up by submitting PAGE 8 after PAGE 1 doesn't mean the PVC
cares at all about your twisted opinion of how a book should work. And the user of your
apps neither. Flipping to the right and back to the left should definitely result in reaching
the original page - IF done with an animation. And it is up to YOU to correct the goof by
finding a solution for the disaster. Don't blame it on the UIPageViewController. It is doing
its job perfectly!
Just ask yourself - would you do the same thing with a PAGE-CURL animation? NO ?
Well, neither should you with a SCROLL animation!!! An animated page turn is a page turn and only a page turn!
In either mode!
And if you decide to tear out PAGE 2 to PAGE 7 of your BOOK that's perfectly fine!
But just don't expect UIPageViewController to invent a non-existing PAGE 7 when turning back to the recent page unless YOU tell it that things have changed...
If you really want to achieve an uncoordinated jump to elsewhere, well - do it without an
animation! In most cases this will not be very elegant but - it's possible... -
And the PVC even plays nicely along! When jumping to a new SPACE without animation
it will ask you further down the road for both - the BEFORE and AFTER controller. So your application-logic can keep up with the PVC...
But with an animation you are always conveying - move to the previous/next space (BEFORE -
AFTER). So logically there is no need at all for the PVC to ask again about a space it already
knows about when animating page turns!!!
If you wanna see PAGE 7 when flipping back to the left after having animated from PAGE 1
to the right - well, I would say - that's definitely your very own problem!
And just in case you are looking for a better solution than the 'completion-block' hack from
the accepted answer (because with it you are doing work beforehand for something that might
possibly not even get used further down the road) use the gesture recognizer delegate:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
Set your PVC's DataViewController here (without animation) if you really intend to go back
left to PAGE 7 and the DataSource will be asked for BEFORE and AFTER and you can submit
whatever page you like! With a flag or ivar that you should have stashed away when doing your uncontrolled
jump from PAGE 1 to 8 this should be no problem...
And when people keep on complaining about a bug in the PVC - doing 2 page turns when it is
supposed to do 1 turn only - point them to this article.
Same problem - triggering an un-animated setViewControllers: method within the transition gesture
will cause exactly the same havoc. You think you set the new center - the DataSource is asked
for the new BEFORE - AFTER dataController - you reset your index count... - Well, that seems OK...
But - after all that business the PVC ends its transition/animation and wants to know about the
next (still unknown to it) dataViewController (BEFORE or AFTER) and also triggers the DataSource. That's totally justified ! It needs to know where in its small BEFORE - CENTER - AFTER
world it is and be prepared for the next turn.
But your program-logic adds another index++ count to its logic and suddenly got 2 page turns !!!
And that is one off from where you think you are.
And YOU have to account for that! Not UIPageViewController !!!
That is exactly the point of the DataSourceProtocol only having two methods! It wants to be as generic as possible - leaving you the space and freedom to define your own logic and not being stuck with somebody else's special ideas and use-cases! The logic is completely up to you. And only because you find functions like
- (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard position:(GSPositionOfDataViewController)position;
- (NSUInteger)indexOfViewController:(DataViewController *)viewController;
in all the copy/pasted sample applications in the cloud doesn't necessarily mean that you have to eat that pre-cook food! Extend them any way you like! Just look above - in my signature you will find a 'position:' argument! I extended this to know later on if a completed page turn was a right or a left turn. Because the delegate unfortunately just tells you whether your turn completed or not! It doesn't tell you about the direction! But this sometimes matters for index-counting, depending on your application's need...
Go crazy - they are your's...
HAPPY CODING !!!

Resources