Howto Maintain GtkSourceCompletion When Changing Buffers in a GtkSourceView? - gtk

All,
I have an editor that holds the open files in a treeview/treemodel on the left of the main window and displays the buffer associated with the highlighted treeview entry in the focused textview (sourceview) window on the right.
Each GtkSourceView shown is contained within an editor instance struct which also contains a pointer to its GtkSourceCompletionWords 'provider' (prov_words). The word-completion works fine for the first buffer shown in the window, but when I change files and display a different buffer in the sourceview window, word competion is not active for that buffer, even through I unregister the first buffer from the prov_words provider and register the current buffer for the words provider to use as its source.
Essentially I create the initial completion object as:
GtkSourceCompletion *completion;
GtkSourceCompletionWords *prov_words;
completion = gtk_source_view_get_completion (view);
prov_words = gtk_source_completion_words_new (NULL, NULL);
gtk_source_completion_words_register (prov_words,
gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
gtk_source_completion_add_provider (completion,
GTK_SOURCE_COMPLETION_PROVIDER (prov_words), NULL);
/* store a pointer to the completions words provider as part of
* the editor instance.
*/
einst->prov_words = prov_words;
When displaying a new buffer in the textview, I use the treeview "changed" signal to display the new buffer, update the window title, etc.. and to unregister the current buffer from the prov_words provider and then register the new buffer as the word source with:
GtkSourceCompletionWords *prov_words = einst->prov_words;
/* unregister current buffer from words completion provider */
gtk_source_completion_words_unregister (prov_words,
GTK_TEXT_BUFFER(oldbuf));
/* register new buffer with words completion provider */
gtk_source_completion_words_register (prov_words,
GTK_TEXT_BUFFER(newbuf));
This results in no completion functionality at all in the new buffer -- but when switching back to the first buffer, completion continues to work just fine. So it seems I am conceptually missing a piece of the puzzle for what is required to switch buffers associated with a sourceview window (where the completion object and provider remain unchanged) and have completion work with the new buffer in that same sourceview window.
Since the completion object is part of the sourceview, the provider part of the completion object and the words proposed by the provider are derived from the buffer, e.g.
-- GtkSourceView
|
-- GtkSourceCompletion
| |
| -- GtkSourceCompletionWords
|
-- GtkSourceBuffer
it seems the only requirement would be to unregister the words in the first buffer from the provider and then register the words in the new buffer with the provider -- but that does not seem to be the case. The documentation is silent on what is required in this instance (or it escapes me), Gtk SourceView Completion API
So how do you enable completion for a sourceview widget and then change the displayed buffer and have the completion continue to work using the words in the new bufffer?

Related

How to send events from the dap to the frontend (frame change, breakpoint changes)?

From the Debug Adapter Protocol Specification it is quite clear how to react on frontend changes. For example: when the user selects a frame so the dap backend is getting an event, the user changes a breakpoint, so a SetBreakpointsRequest() is received.
But how to send "insights" to the frontend, for example when the backend recognizes a breakpoint change or a change of active frame by the debugger?
Note: I've directly tried to add them in the backend with the following code - but as long as that was in the debugging did not start and neither output panes nor debugging pane showed any reason.
import * as vscode from "vscode";
var loc = new vscode.Location(vscode.Uri.file(file), new vscode.Position(line,0));
var bp = new vscode.SourceBreakpoint(loc);
vscode.debug.addBreakpoints([bp]);
A debugger adapter can update breakpoints with an event. See https://microsoft.github.io/debug-adapter-protocol/specification#Events_Breakpoint
The event indicates that some information about a breakpoint has changed.
interface BreakpointEvent extends Event {
event: 'breakpoint';
body: {
/**
* The reason for the event.
* Values: 'changed', 'new', 'removed', etc.
*/
reason: 'changed' | 'new' | 'removed' | string;
/**
* The `id` attribute is used to find the target breakpoint, the other
* attributes are used as the new values.
*/
breakpoint: Breakpoint;
};
}
The Breakpoint object contains an id that you can use to reference an existing breakpoint.
A typical scenario for this would be when you start debugging, the code is loaded in your runtime and a breakpoint is automatically moved from a no-code line to the next line with code. This is how the Debug Adapter would signal to the IDE that it needs to update the breakpoint location.
Generally the specification section "Requests" is something that gets initiated by the IDE (usually the user) and the section "Events" is something that gets initiated by the Debug Adapter or the Debugger Engine Backend...
Note, all this is only possible when a debug session is active. If you have some other requirements, that your extension should modify breakpoints and such while there is no active session, or perhaps do something that is not covered by the DAP specification, you will need to implement some extension code and use the vscode.debug API https://code.visualstudio.com/api/references/vscode-api#debug

Intercept X11 KeyPress event in GtkDrawingArea of GTK+3 on Linux

GTK+ version: 3.18.9
I created a drawing area (GtkWidget) with following code
content = gtk_drawing_area_new();
gtk_widget_set_can_focus(content, TRUE);
gtk_widget_add_events(content, GDK_ALL_EVENTS_MASK);
g_signal_connect(content, "draw", G_CALLBACK(&drawCallback), ctx);
gtk_widget_realize(content);
// Add a filter for interception
gdk_window_add_filter(content, gtk_widget_get_window(content),
OnXEvent, NULL);
Problem is that when I clicked the wideget, I got sequence of XEvents as follows:
LeaveNotify
FocusIn
EnterNotify
ButtonPress
FocusOut // Lost focus!
ButtonRelease
Above FocusOut indicated we lost focus right away after clicking.
It implies we can't receive any keyboard events since they are available only within focus.
Is this limitation of GTK? If not, is there any tools/methodlogy to find out which widget/widow trigger the FocusOut?
References:
gdk_window_add_filter
As of GTK+ version 3.18.9, it uses an extra X window for toplevel window and any keyboard events are captured by the window. Thus a filter need to be added as a global one, i.e.
gdk_window_add_filter(NULL, OnXEvent, NULL)
Note that the API was removed in this commit in GTK+ 4.x.

Delphi: How to restore a form's original location when monitor configuration changes?

I have a multi-form application in which a child form is positioned on the second monitor on startup, at which time its BoundsRect is saved.
When the computer's display configuration changes, Windows moves the form to the first (primary) monitor. I can catch this change with WM_DISPLAYCHANGE:
procedure WMDisplayChange(var msg: TWMDisplayChange); message WM_DISPLAYCHANGE;
What I'm interested in doing is moving the child form back to the second monitor when it reappears in the configuration (i.e. Screen.MonitorCount goes from 1 to 2), e.g.:
childForm.BoundsRect := childForm.m_WorkingBounds;
// (or)
childForm.BoundsRect := Screen.Monitors[Screen.MonitorCount-1].BoundsRect;
However this assignment is have no affect -- the child form stays on monitor 0.
I've tried other approaches, such as SetWindowPos(), with no success ...
Root of your problem is in the fact that Delphi VCL does not refresh its internal list of monitors when they actually change. You have to force that refresh yourself.
Monitors are refreshed with TScreen.GetMonitors method that is unfortunately private method so you cannot call it directly.
However, TApplication.WndProc(var Message: TMessage) processes WM_WTSSESSION_CHANGE and upon receiving that message it calls Screen.GetMonitors - this is most benign way to achieve your goal.
When you receive notifications that monitors are changed just send it to Application:
SendMessage(Application.Handle, WM_WTSSESSION_CHANGE, 0, 0);
I tested this with old version Delphi5 and it worked easy just to:
Screen.Free;
Screen := TScreen.Create(Nil);
The screen handling has changed in later versions of Delphi, however a similar approach may work.

How to change active application in progress?

In Progress 11.3.2 (Developer Studio 3.7 - Eclipse 3.8.2), not using dot net at all:
How do you switch the focus to another window/application/w file?
In windows 7/8 the order of what window that is focused acts a bit different than before and does not always show the window you want to have over all the other apps.
If you have 3 windows open, and close the 3rd one and want to focus on the second one that was minimized, the first one get focus instead.
You set it to normal with WINDOW-STATE = WINDOW-NORMAL. But how to focus on it too?
If you run the secondary windows persistent you can do something like this:
In calling window:
/* In definitions */
DEFINE VARIABLE ghSecondWindow AS HANDLE NO-UNDO.
/* In a trigger */
RUN secondWindow.w PERSISTENT SET ghSecondWindow.
/* Whenever you want to shift focus */
RUN setFocus IN ghSecondWindow.
In "SecondWindow":
PROCEDURE setFocus:
/* Replace FILL-IN-1 with any widget that can gain focus */
APPLY "ENTRY" TO FILL-IN-1 IN FRAME {&FRAME-NAME}.
END PROCEDURE.
If however you are not running persistent windows you can still achieve this by walking the widget trees, first of the current window and then of the second window (once you've localized it).
Quick and ugly code to put in the calling window wherever you want the focus to shift. This might not suit your needs exactly so it might require some rewriting. Also error checking is pretty much not here and dealing with possible eternal loops without error checking is not really best practice:
DEFINE VARIABLE hWin AS HANDLE NO-UNDO.
DEFINE VARIABLE hWidget AS HANDLE NO-UNDO.
/* Get the first child (widget) of the session */
ASSIGN
hWin = SESSION:FIRST-CHILD.
/* Loop through all widgets in the session */
loop:
DO WHILE VALID-HANDLE(hWin):
/* We've identified the correct Window! */
IF hWin:TYPE = "WINDOW" AND hWin:TITLE = "Secondary Window" THEN DO:
/* ** Very Ugly** this could use better error checking etc! */
/* Get the second field-group of the window */
/* This will depend on your layout with different frames etc */
/* What we really have is WINDOW:DEFAULT-FRAME:FIELD-GROUP:FIELD-GROUP */
/* Field groups are really only present in the widget tree - they lack visual */
/* representation */
/* Read about field-groups in the online help! */
ASSIGN
hWidget = hWin:FIRST-CHILD:FIRST-CHILD:FIRST-CHILD.
/* Loop through all widgets of the field-group */
DO WHILE VALID-HANDLE(hWidget).
/* We've found the correct fill-in, give it focus */
IF hWidget:TYPE = "FILL-IN" AND hWidget:LABEL = "Fill 1" THEN DO:
APPLY "ENTRY" TO hWidget.
LEAVE loop.
END.
/* Next window of the correct window */
hWidget = hWidget:NEXT-SIBLING.
END.
END.
/* Next widget of the session */
hWin = hWin:NEXT-SIBLING.
END.
You could also do the "widget tree walk" recursively if you feel like it!

Multiple instances of window in perl, using gtk builder

To get started, I am inexperienced scripting in perl, or using gtk, but I've been googling and researching how to for the past two or so weeks. It was difficult just figuring out where I could find the PMs for gtk on windows, and then even more so getting it to some semblance of 'working'. However, there have of course still been problems.
Skipping the above, I have two problems. For a slight bit of relevant background, I am trying to port an mirc script over to xchat, but to do that I obviously need to learn a whole 'nother language.. but anyway. The two problems are thus:
The window consists of several buttons, labels, and text areas. However, the window is.. 'frozen' in time unless one clicks on the title bar and holds. Clicking a button does nothing, not even to show it has been clicked, unless of course the title bar is clicked and held.
I have no idea how to initialize multiple instances of the same window. I have of course tried researching, but it's either not out there or I just haven't found it yet. To be specific.. My mirc script requires that multiple instances be allowed to exist, but I need the buttons for the specific instance to only affect that instance.. and so on.
In regards to problem 1, I do not know if the .xml glade file is important, so I won't post it immediately. I will however post the code that calls it:
my $glade_file = "window3.xml";
my $glade = Gtk2::Builder->new();
$glade->add_from_file($glade_file);
sub charopen {
my $window = $glade->get_object('window1');
$glade->connect_signals(undef, $window);
my $hp_cur = $glade->get_object('HP_Cur');
$window->set("title"=>$_[0][1]);
$hp_cur->set("label"=>$ini->val($_[0][1],"HPC"));
$window->show();
}
Graphical interface design relies on event processing. To work properly, it is important to reserve a thread to process user events (keyboard, mouse clicks...). That is the aim of calling Gtk2->main() when user interface is ready to accept user interaction.
To make the event thread exiting the event loop, an event callback method may invoke Gtk2->main_quit()
The Gtk2::Builder creates Gtk widget hierarchy from XML. To get multiple instance of the same window, you have to create a builder for each one.
Then your event callback methods has to get information about which window has sent the event, and the $user_data parameter may be used in that aim.
Here is a code proposal with a simple button click callback which use Perl reference to a hash so you can pass as many information as you want between window creator code and event callbacks:
sub createWindow($)
my $windowTitle = $_[0];
my $windowBuilder = Gtk2::Builder->new();
$windowBuilder->add_from_file($glade_file);
my $window = $windowBuilder->get_object('window1');
my $hp_cur = $windowBuilder->get_object('HP_Cur');
# Create hash with data (alternative: use Class::Struct for better code)
my %window_user_data = {
"title" => $windowTitle,
"window" => $window,
"hp_cur" => $hp_cur };
# Pass hash reference as user data
$windowBuilder->connect_signals(\%window_user_data);
# prepare interface: set data model into view and then...
$window->show();
}
# Click callback method defined on a button in window
sub button_click_callback($$) {
my $button = $_[0];
my $window_user_data_ref = $_[1];
# get back data model from view
print "Click received from button on "
. $window_user_data_ref->{"title"} . "\n";
}
There is another way to handle callbacks per window but it requires more Perl skills: you can design a Perl package to create an object instance for a specific window, and use $windowbuilder->connect_signals ($user_data, $windowcallbackinstance). In that case, such an object is called controller, and you have built your graphical interface based on Model-View-Controller (MVC) pattern.