I have an app, running on Linux, which is comprised of a VkMainWindow and several VkWindows. The desired behavior is to keep the VkMainWindow always on the bottom (and hence, all the VkWindows always on top of the VkMainWindow). The existing code works as advertised on KDE, but the customer decided it needs to run under MWM. Running under MWM, the VkMainWindow raises above the VkWindows. Any ideas?
VkMainWindow:
MainWindow::MainWindow(MyContainer const &container, ArgList args, Cardinal argc)
:
BaseWindow("My Base Window", args, argc,
_statusWindow(new StatusWindow(container)),
m_helpDialog(new MainHelpDialog),
m_container(container),
m_frame(nullptr),
m_form(nullptr),
_button1(nullptr),
_widget1(nullptr),
m_button2(nullptr),
m_widget2(nullptr),
m_button2(nullptr),
m_widget3(nullptr),
m_button3(nullptr),
m_button4(nullptr),
m_button5(nullptr),
m_widget4(nullptr),
_label1(nullptr),
_label2(nullptr),
_label3(nullptr),
_label4(nullptr),
_label5(nullptr),
_label6(nullptr),
_label7(nullptr)
{
Display *mainDisplay;
mainDisplay = XOpenDisplay(0);
if (mainDisplay)
{
m_width = m_mainWindowWidth = 1280;
m_height = m_mainWindowHeight = 1024;
XCloseDisplay(mainDisplay);
}
XtVaSetValues(m_shellWidget, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE, XmNx, 0, XmNy, 0, NULL);
m_configFile = currentWorkspace;
}
VkWindows:
BaseWindow::BaseWindow(string const &name, ArgList args, Cardinal argc,
unsigned int createOptions, bool createTabStack, bool removeCornerFunctions, bool scrollable, bool workspaceConfigurable)
:
VkWindow(name.c_str(), args, argc), _mainForm(0), _mainOffset(
MAIN_OFFSET), _buttonSpacing(BUTTON_SPACING), _createOptions(createOptions),
_createTabStack(createTabStack), _statusText(0), m_buttonBoxForm(0), m_helpForm(0),
m_okButton(0), m_cancelButton(0), m_applyButton(0), m_applyCb(0), m_okCb(0), m_cancelCb(0),
m_screenId(INVALID_SCREEN_ID), m_previousTab(0), _tabStack(0), _tabForm(0), m_initialized(false),
m_shellWidget(0), m_clipWindow(0), _isScrollable(scrollable), m_isValid(true), m_statusOnly(false),
m_validateOnOk(true), m_validateOnApply(true), m_widgetsMapped(false), m_fooLocked(false), m_isLocked(false),
m_currentSize(FULL), m_lastSize(0)
{
Widget parent = mainWindowWidget();
XtSetValues(parent, args, argc);
m_shellWidget = parent;
while (m_shellWidget && !XtIsShell(m_shellWidget))
{
m_shellWidget = XtParent(m_shellWidget);
}
if (removeCornerFunctions)
{
if (m_shellWidget)
{
XtVaSetValues(m_shellWidget,
XmNmwmFunctions, 22,
// MWM_FUNC_RESIZE | MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE | MWM_FUNC_CLOSE,
NULL);
XtAddEventHandler(m_shellWidget, StructureNotifyMask, false, resizeCb, this);
}
}
...
}
Main:
int main(int argc, char **argv)
{
...
Cardinal ac;
Arg args[20];
std::string title("My Client");
XrmOptionDescRec *optionList = NULL;
int numOptions = 0;
app = new VkApp(const_cast<char*>(title.c_str()), &argc, argv, optionList, numOptions);
...
app->run();
...
return (0);
}
The solution is to call VkWindow:lower() in the event loop for the main window.
Related
Good afternoon,
I'm trying to integrate a popover context menu to a treeview widget in GTKmm 4.
I've been successful in getting the menu to be displayed and for the respective actions to be called when clicking on the context menu options, however, I'm finding that the menu items are not being highlighted when the mouse hovers over them.
A GIF showing what I'm seeing is here:
If however, using the same code, I attach the menu and action group to another widget (such as a button or the window itself), all works as expected and the options are highlighted correctly.
Below is code for a minimal reproducible example.
Could someone help as I'm going round in circles with this??
#include <gtkmm.h>
class Window : public Gtk::Window {
public:
Window() {
list_store_ = Gtk::ListStore::create(model_);
auto row = *(list_store_->append());
row[model_.id] = 1;
row[model_.name] = "Example 1";
row = *(list_store_->append());
row[model_.id] = 2;
row[model_.name] = "Example 2";
treeview_.set_hexpand(true);
treeview_.set_vexpand(true);
treeview_.set_model(list_store_);
treeview_.append_column("ID", model_.id);
treeview_.append_column("Name", model_.name);
Glib::RefPtr<Gio::Menu> gmenu = Gio::Menu::create();
gmenu->append("_Edit", "popup.edit");
gmenu->append("_Remove", "popup.remove");
menu_.set_parent(treeview_);
menu_.set_menu_model(gmenu);
menu_.set_has_arrow(false);
Glib::RefPtr<Gio::SimpleActionGroup> action_group = Gio::SimpleActionGroup::create();
action_group->add_action("edit", sigc::mem_fun(*this, &Window::on_popup_edit));
action_group->add_action("remove", sigc::mem_fun(*this, &Window::on_popup_remove));
treeview_.insert_action_group("popup", action_group);
Glib::RefPtr<Gtk::GestureClick> gesture = Gtk::GestureClick::create();
gesture->set_button(GDK_BUTTON_SECONDARY);
gesture->signal_pressed().connect(sigc::mem_fun(*this, &Window::on_popup_button_pressed));
treeview_.add_controller(gesture);
set_child(treeview_);
}
~Window() override {
}
private:
class ExampleModel : public Gtk::TreeModel::ColumnRecord {
public:
ExampleModel() {
add(id);
add(name);
}
Gtk::TreeModelColumn<int> id;
Gtk::TreeModelColumn<Glib::ustring> name;
};
void on_popup_button_pressed(int, double x, double y) {
int cx, cy;
treeview_.convert_widget_to_bin_window_coords(x, y, cx, cy);
Gtk::TreeModel::Path path;
treeview_.get_path_at_pos(cx, cy, path);
if (!path) {
return;
}
const Gdk::Rectangle rect(x, y, 1, 1);
menu_.set_pointing_to(rect);
menu_.popup();
}
void on_popup_edit() { /* Implementation here */ }
void on_popup_remove() { /* Implementation here */ }
Gtk::TreeView treeview_;
ExampleModel model_;
Glib::RefPtr<Gtk::ListStore> list_store_;
Gtk::PopoverMenu menu_;
};
int main(int argc, char** argv) {
auto app = Gtk::Application::create("com.example.treeview");
return app->make_window_and_run<Window>(argc, argv);
}
Okay, so I recently had time to come back to this project.
This time I thought I'd attempt to re-write it in Rust using the gtk4-rs crate and see if the same happens and it does!
I've managed to work around this issue by wrapping the TreeView inside of a ScrolledWindow and then setting up the menu against the ScrolledView instead of the TreeView.
Inside the on_popup_button_pressed function, I'm still able to determine the path/item that was clicked.
Updated code (untested though - as the project is now written in Rust instead) is below:
#include <gtkmm.h>
class Window : public Gtk::Window {
public:
Window() {
list_store_ = Gtk::ListStore::create(model_);
auto row = *(list_store_->append());
row[model_.id] = 1;
row[model_.name] = "Example 1";
row = *(list_store_->append());
row[model_.id] = 2;
row[model_.name] = "Example 2";
treeview_.set_hexpand(true);
treeview_.set_vexpand(true);
treeview_.set_model(list_store_);
treeview_.append_column("ID", model_.id);
treeview_.append_column("Name", model_.name);
scrolled_window_.set_child(treeview_);
Glib::RefPtr<Gio::Menu> gmenu = Gio::Menu::create();
gmenu->append("_Edit", "popup.edit");
gmenu->append("_Remove", "popup.remove");
menu_.set_parent(scrolled_window_);
menu_.set_menu_model(gmenu);
menu_.set_has_arrow(false);
Glib::RefPtr<Gio::SimpleActionGroup> action_group = Gio::SimpleActionGroup::create();
action_group->add_action("edit", sigc::mem_fun(*this, &Window::on_popup_edit));
action_group->add_action("remove", sigc::mem_fun(*this, &Window::on_popup_remove));
scrolled_window.insert_action_group("popup", action_group);
Glib::RefPtr<Gtk::GestureClick> gesture = Gtk::GestureClick::create();
gesture->set_button(GDK_BUTTON_SECONDARY);
gesture->signal_pressed().connect(sigc::mem_fun(*this, &Window::on_popup_button_pressed));
scrolled_window_.add_controller(gesture);
set_child(scrolled_window_);
}
~Window() override {
}
private:
class ExampleModel : public Gtk::TreeModel::ColumnRecord {
public:
ExampleModel() {
add(id);
add(name);
}
Gtk::TreeModelColumn<int> id;
Gtk::TreeModelColumn<Glib::ustring> name;
};
void on_popup_button_pressed(int, double x, double y) {
int cx, cy;
treeview_.convert_widget_to_bin_window_coords(x, y, cx, cy);
Gtk::TreeModel::Path path;
treeview_.get_path_at_pos(cx, cy, path);
if (!path) {
return;
}
const Gdk::Rectangle rect(x, y, 1, 1);
menu_.set_pointing_to(rect);
menu_.popup();
}
void on_popup_edit() { /* Implementation here */ }
void on_popup_remove() { /* Implementation here */ }
Gtk::TreeView treeview_;
Gtk::ScrolledWindow scrolled_window_;
ExampleModel model_;
Glib::RefPtr<Gtk::ListStore> list_store_;
Gtk::PopoverMenu menu_;
};
int main(int argc, char** argv) {
auto app = Gtk::Application::create("com.example.treeview");
return app->make_window_and_run<Window>(argc, argv);
}
As titled above, i'm trying to get an extremely simple FLTK 1.3.3 application working.
But, even with only a simple Fl_Window and 1 Fl_Button, nothing seems to work. Can anyone help?
class MainEditorWindow : public Fl_Window
{
public:
MainEditorWindow(int _width, int _height, std::string _title);
~MainEditorWindow();
virtual void draw();
virtual int handle(int _event);
private:
Fl_Button* m_btnExit;
};
And here is the Implementation
MainEditorWindow::~MainEditorWindow()
{
}
int MainEditorWindow::handle(int _event)
{
return 1;
}
void MainEditorWindow::draw()
{
m_btnExit->redraw();
}
MainEditorWindow::MainEditorWindow(int _width, int _height, std::string _title) : Fl_Window(_width, _height, _title.c_str())
{
this->begin();
m_btnExit = new Fl_Button(0, 0, 40, 40, "EXIT");
m_btnExit->color(FL_RED);
this->color(FL_WHITE);
this->end();
}
But when simply running the application like this:
int main(int argc, char** argv)
{
MainEditorWindow* mw = new MainEditorWindow(800, 600, "SHIP Editor");
mw->show(argc,argv);
return Fl::run();
}
The window shows up fine, its resizable movable etc, the draw() - function is being called and all that. But the window itself is just blank. It simply shows nothing, especially not the Fl_Button. Can anybody tell me why this occurs? As far as i can tell, there should be nothing particularily wrong with my code.
You need to call Fl_Window::draw()
void MainEditorWindow::draw()
{
m_btnExit->redraw();
Fl_Window::draw();
}
And maybe you want the button is clickable too
int MainEditorWindow::handle(int _event)
{
//return 1;
return(Fl_Window::handle(_event));
}
Try this in your MainEditorWindow constructor:
MainEditorWindow(int _width, int _height, const std::string& _title)
: Fl_Window(_width, _height, _title.c_str()) {
// begin grouped GUI object creation
Fl_Group::begin();
// alter x,y coords of button as necessary
m_btnExit = new Fl_Button(0,0,40,40,"EXIT");
m_btnExit->color(FL_RED);
// end grouped GUI object creation
Fl_Group::end();
// defines resizable widget for group
Fl_Group::resizable(this);
this->color(FL_WHITE);
// display window
Fl_Window::show();
}
Then in main:
int main(int argc, char** argv) {
MainEditorWindow mw(800, 600, "SHIP Editor");
return Fl::run();
}
Here we have added the button to a group and then invoked Fl_Window::show() inside the constructor to display it.
Note there is no need to make mw a pointer to MainEditorWindow in main.
I'm trying to get frames from video stream and use them as OpenCV Mat, but I have encountered a problem.
I don't know the resolution my video stream will have so I use
libvlc_video_set_format_callbacks
but then, after video starts playing, I hear audio, but I'm not getting an image, instead I get errors:
Bad dst image pointers.
Here's my code:
struct ctx
{
unsigned char *pixeldata;
std::mutex imagemutex;
};
static void *lock(void *data, void **p_pixels)
{
struct ctx *ctx = reinterpret_cast<struct ctx *>(data);
ctx->imagemutex.lock();
*p_pixels = ctx->pixeldata;
return NULL;
}
static void unlock(void *data, void *id, void *const *p_pixels)
{
struct ctx *ctx = reinterpret_cast<struct ctx *>(data);
ctx->imagemutex.unlock();
assert(id == NULL);
}
unsigned setup(void **opaque, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines)
{
struct ctx *callback = reinterpret_cast<struct ctx *>(*opaque);
unsigned nWidth = (*width);
unsigned nHeight = (*height);
(*pitches) = nWidth * 3;
(*lines) = nHeight;
chroma = (char *)"RV24";
callback->pixeldata = new unsigned char[nWidth*nHeight*3];
return 1;
}
int main(int argc, char *argv[])
{
libvlc_instance_t *vlcInstance;
libvlc_media_player_t *_player;
libvlc_media_t *_media;
const char * const vlc_args[] = {
"-I", "dummy", // Don't use any interface
"--ignore-config", // Don't use VLC's config
"--extraintf=logger", // Log anything
"--verbose=2", // Be much more verbose then normal for debugging purpose
};
vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
_media = libvlc_media_new_location(vlcInstance , "rtsp://address");
_player = libvlc_media_player_new_from_media(_media);
struct ctx *callback = new struct ctx;
libvlc_video_set_callbacks(_player, lock, unlock, 0, callback);
libvlc_video_set_format_callbacks(_player, setup, 0);
libvlc_media_player_play(_player);
}
If I won't use libvlc_video_set_format_callbacks(_player, setup, 0); but instead set fixed parameters, eg. libvlc_video_set_format(_player, "RV24", 720, 404, 720 * 3); it works fine. Any idea what might be a problem?
Actually it was simple and stupid mistake.
Line:
chroma = (char *)"RV24";
needs to be replaced by:
memcpy(chroma, "RV24", 4);
I have the following application.
#include <FWWindow.h>
#include <FWApplication.h>
int main(int /*argc*/, char */*argv*/[])
{
FWApplication::Initialize();
FWWindow *win = new FWWindow(800, 600);
win->Show();
FWApplication::Run();
delete win;
}
When I run it it gets stuck on the XNextEvent() because it blocks until it gets the next event from the XServer. What I would like to know, is based on the code below, why is the XNextEvent not getting the ConfigureNotify or Expose events after I am calling XMapWindow(); I have checked to make sure my application provides the right Display based on the address in the watch window of my IDE. What am I missing to get the window to appear?
Initialize() does the following
-
FWApplication *FWApplication::Initialize()
{
if (!_instance)
{
_xDisplay = XOpenDisplay(NULL);
if (_xDisplay == NULL)
throw "Failed to get XDisplay";
_initialized = true;
_instance = new FWApplication(); // Calls an empty ctor
}
return _instance;
}
FWWindow *win = new FWWindow(800, 600); does the following
-
FWWindow::FWWindow(int width, int height) :
clientWidth(width),
clientHeight(height)
{
// These are all member variables
xDisplay = FWApplication::GetMainDisplay();
xScreen = DefaultScreen(xDisplay);
xDepth = DefaultDepth(xDisplay, xScreen);
xVisual = DefaultVisual(xDisplay,xScreen);
xAttributes.background_pixel = XWhitePixel(xDisplay, xScreen);
xAttributes.border_pixel = XBlackPixel(xDisplay, xScreen);
xAttributes.override_redirect = 0;
xWindow = XCreateWindow(
xDisplay,
RootWindow(xDisplay, xScreen),
0, 0,
width, height,
0,
xDepth,
InputOutput,
xVisual,
CWBorderPixel | CWColormap | CWEventMask,
&xAttributes
);
XSetStandardProperties(
xDisplay,
xWindow,
"glxsimple",
"glxsimple",
None,
NULL,
0,
NULL
);
}
win->Show(); does the following
-
void FWWindow::Show()
{
XMapWindow(xDisplay, xWindow); // xWindow and xDisplay defined in ctor above
}
And finaly FWApplication::Run(); does the following
-
int FWApplication::Run()
{
if (!_initialized)
return -1;
static bool run = true;
static Display *lDisplay = _xDisplay;
XEvent xEvent;
while (run)
{
do
{
XNextEvent(lDisplay, &xEvent);
switch (xEvent.type)
{
case ConfigureNotify:
{
unsigned int w = xEvent.xconfigure.width;
unsigned int h = xEvent.xconfigure.height;
// Do something to main widget
}
case Expose:
break;
}
} while (XPending(GetMainDisplay()));
}
return EXIT_SUCCESS;
}
You're not specifying an event mask in your window's attributes, so XNextEvent() won't report any event. You should write something like:
xAttributes.background_pixel = XWhitePixel(xDisplay, xScreen);
xAttributes.border_pixel = XBlackPixel(xDisplay, xScreen);
xAttributes.override_redirect = 0;
xAttributes.event_mask = StructureNotifyMask // for ConfigureNotify
| ExposureMask; // for Expose
Here is my code:
#include <gtk/gtk.h>
G_MODULE_EXPORT void waka(GtkWidget *button, GtkWidget* entry1)
{
printf("%s",gtk_entry_get_text(GTK_ENTRY(entry1)));
}
int main(int argc, char * argv[])
{
GtkWidget *window, *button, *entry;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("hha");
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(waka),entry);
entry = gtk_entry_new();
GtkWidget *vbox;
vbox = gtk_vbox_new(FALSE,2);
gtk_box_pack_start_defaults(GTK_BOX(vbox),button);
gtk_box_pack_start_defaults(GTK_BOX(vbox),entry);
gtk_container_add(GTK_CONTAINER(window),vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
When I launch it, and try to fill in some string in the entry box, and then click the button, it said 'segmentation fault'. What is going on?
Also, the callback only works with one user data argument. How about if I want two or more arguments, what must I do in the callback function, and in the call to g_signal_connect()?
the problem is that you're trying to use pointer to entry before initializing it. I've changed a bit your code to fix this, see if it will work for you:
#include <gtk/gtk.h>
void waka(GtkWidget *button, GtkWidget* entry1)
{
g_print("entry: %s\n", gtk_entry_get_text(GTK_ENTRY(entry1)));
}
int main(int argc, char * argv[])
{
GtkWidget *window, *button, *entry, *vbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("hha");
entry = gtk_entry_new();
vbox = gtk_vbox_new(FALSE, 2);
gtk_box_pack_start_defaults(GTK_BOX(vbox),button);
gtk_box_pack_start_defaults(GTK_BOX(vbox),entry);
gtk_container_add(GTK_CONTAINER(window),vbox);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(waka), entry);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
hope this helps, regards