I ran into troubles trying to create a gnome-panel applet with gtkmm. I dealt with most of them, but I'm now kind of blocked.
Quick summary : I tried libpanelappletmm, but every program (even the examples supplied in the source code) segfaults when I try to add the applet in my panel.
So I now use the C library (libpanel-applet). First I looked for a way to wrap the PanelApplet Gobject in a gtkmm C++-object, for example a Gtk::EventBox (PanelApplet inherits from GtkEventBox). I tried to cast it, but Glibmm kept throwing a warning ("Failed to wrap object 'PanelApplet'").
So I created a class "Info", inheriting from Gtk::HBox. In my main.cpp file I declare an instance of it, get the underlying GTK object (gobj method), and use the GTK+ functions to add it into the PanelApplet.
Here's my main.cpp.
#include <iostream>
#include <gtkmm.h>
#include <panel-applet.h>
#include "Info.hpp"
static void manage_timeboxes(BonoboUIComponent *uic, void *applet, const char* data) {
std::cout << "manage" << std::endl;
}
static gboolean getApplet(PanelApplet *applet, const gchar *iid, gpointer data) {
/*
if(iid != "OAFIID:TimeboxingApplet")
return false;
*/
Glib::init();
Gtk::Widget* content = new Info();
gtk_container_add(GTK_CONTAINER(applet), content->gobj());
static const char menu_xml[] =
"<popup name=\"button3\">\n"
" <menuitem name=\"Manage\" "
" verb=\"manage_timeboxes\" "
" _label=\"_Gérer l'emploi du temps\"\n"
" pixtype=\"stock\" "
" pixname=\"gtk-properties\"/>\n"
"</popup>\n";
static const BonoboUIVerb linked_verbs[] = {
BONOBO_UI_VERB ("manage_timeboxes", manage_timeboxes),
BONOBO_UI_VERB_END
};
panel_applet_setup_menu(applet, menu_xml, linked_verbs, data);
gtk_widget_show_all(GTK_WIDGET(applet));
return true;
}
PANEL_APPLET_BONOBO_FACTORY (
"OAFIID:TimeboxingApplet_Factory",
PANEL_TYPE_APPLET,
"Timeboxing",
"0.0",
getApplet,
NULL)
It works fine if I add labels or buttons in my Info object.
But then I tried to add an icon.
My first try was adding a Gtk::Image as a property of Info.
Info.hpp
#ifndef TIMEBOXING_INFO_H
#define TIMEBOXING_INFO_H
#include <gtkmm/box.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
class Info : public Gtk::HBox {
public:
Info();
virtual ~Info(){};
protected:
Gtk::Image icon;
Gtk::Label info;
};
#endif
Info.cpp
#include "Info.hpp"
#include <gtkmm/image.h>
#include <gtkmm/label.h>
Info::Info() : icon("/home/bastien/programmation/timeboxing-applet/icons/clock-24.png"), info("<b>En cours</b>") {
info.set_use_markup();
pack_start(icon);
pack_start(info);
show_all_children();
}
When I try to add the applet, I get this error and the program aborts :
glibmm:ERROR:objectbase.cc:78:void Glib::ObjectBase::initialize(GObject*): assertion failed: (gobject_ == castitem)
I commented "Gtk::Image icon" from Info.hpp, and I modified my constructor like this :
Info::Info() : info("<b>En cours</b>") {
info.set_use_markup();
Gtk::Image icon("/home/bastien/programmation/timeboxing-applet/icons/clock-24.png");
pack_start(icon);
pack_start(info);
show_all_children();
}
I'm not getting the Glibmm error anymore, but the image isn't displayed. I tried with another file, with an icon from the stock, and even with a Gdk::Pixbuf.
Thank you in advance !
Well, strangely enough, it works if I create a pointer to Gtk::Image.
If anyone has an explanation, it would be great !
Edit : apparently, I had to call Gtk::Main::init_gtkmm_internals. My wrapping troubles went away. I can wrap PanelApplet too, but if I use the resulting Gtk::EventBox* it doesn't display anything.
Related
I am seeing a problem while restoring QMainWindow state having QCombobox in floating toolbar. After restoring floating toolbar, my QCombobox is not able to get focus until i click on toolbar handle and move it.
Following is gif showing problem, Using QT 5.13.
File floating_toolbar.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = floating_toolbar
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
File : main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
File : mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
void closeEvent(QCloseEvent *event);
void readSettings();
bool eventFilter(QObject* xObj, QEvent* xEvent);
~MainWindow();
public slots:
void mCheck();
};
#endif // MAINWINDOW_H
File : mainwindow.cpp
#include "mainwindow.h"
#include <QToolBar>
#include <QComboBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLayout>
#include <QSettings>
#include <QEvent>
#include <QDebug>
#include <QMouseEvent>
#include <QApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QToolBar* lToolbar = new QToolBar(this);
QComboBox* lComobox = new QComboBox(this);
lComobox->setEditable(true);
lToolbar->setWindowTitle("MyToolBar");
lToolbar->setObjectName("NiceBaby");
lToolbar->addWidget(lComobox);
//lToolbar->addAction("check", lComobox, SLOT(clearEditText()));
addToolBar(lToolbar);
lToolbar->installEventFilter(this);
readSettings();
}
void MainWindow::mCheck()
{
}
void MainWindow::closeEvent(QCloseEvent *event)
{
QSettings settings("MyCompany", "MyApp");
settings.setValue("windowState", saveState());
QMainWindow::closeEvent(event);
}
void MainWindow::readSettings()
{
QSettings settings("MyCompany", "MyApp");
restoreState(settings.value("windowState").toByteArray());
}
MainWindow::~MainWindow()
{
}
bool MainWindow::eventFilter(QObject* xObj, QEvent* xEvent)
{
//qDebug()<<xEvent->type();
return QMainWindow::eventFilter(xObj, xEvent);
}
OK, a workaround is to reset the window flags on the toolbar when it is first shown and is floating. I tracked this down by seeing what happens once a toolbar is dropped after being dragged (but not plugged into main window). (It calls setWindowState() and all that does in this situation is hide the toolbar, call updateWindowFlags(), and show it again).
This could be handled from the QMainWindow::showEvent() or from the eventFilter installed onto the QToolBar. I think it's simpler from the former.
UPDATE: This problem actually happens whenever the toolbar is first shown even if not at app startup, e.g. from the toggle view menu by the user once app starts. I updated the code below to fix that issue as well. And see notes below about another issue with minimizing the main window.
I added this to the MainWindow class from the MCVE:
protected:
void showEvent(QShowEvent *e) override {
QMainWindow::showEvent(e);
#ifdef Q_OS_LINUX
if (lToolbar->isFloating()
// remove the next condition and the toolsbar will get hidden the 2nd time main window is minimized.
&& lToolbar->windowFlags().testFlag(Qt::X11BypassWindowManagerHint)
) {
const bool vis = !lToolbar->isHidden();
qDebug() << lToolbar->isFloating() << vis << lToolbar->windowFlags();
lToolbar->hide();
lToolbar->setWindowFlag(Qt::X11BypassWindowManagerHint, false);
if (vis)
lToolbar->show();
#endif
}
QToolBar* lToolbar; // Use this in MainWindow constructor to save the instance pointer.
I also noticed another issue with the initially-floating toolbar. When the main window is minimized, the toolbar doesn't get hidden but stays where it was on the screen. Regardless of what is in the toolbar (eg. no combo box, just QActions). This workaround could also sort-of address that issue (see code comment), but only the 2nd time the window is minimized. Needs a better workaround for the first minimize.
Can others confirm this? Potentially a larger issue than the editable combo and I'd be surprised if no one noticed before.
I guess this should be filed as a Qt bug either way.
UPDATE2: This version also fixes the minimize issue. I guess something happens after the QMainWindow::showEvent() that changes how the toolbar behaves. Which explains why the above workaround works only after the 1st minimize. So scheduling the toolbar "fix" for later works around that also.
class MainWindow : public QMainWindow
{
...
#ifdef Q_OS_LINUX
protected:
void showEvent(QShowEvent *e) override
{
QMainWindow::showEvent(e);
if (lToolbar->isFloating() && lToolbar->windowFlags().testFlag(Qt::X11BypassWindowManagerHint) ) {
// QMainWindow::show() after QMainWindow::restoreState() will break the minimizing again so we should delay calling adjustToolbar().
QMetaObject::invokeMethod(this, "adjustToolbar", Qt::QueuedConnection);
// If we're sure restoreState() is only called after show() then adjustToolbar() could be called here directly instead.
//adjustToolbar();
}
}
private slots:
void adjustToolbar() const
{
const bool vis = !lToolbar->isHidden();
qDebug() << lToolbar->isFloating() << vis << lToolbar->windowFlags();
lToolbar->hide();
lToolbar->setWindowFlag(Qt::X11BypassWindowManagerHint, false);
if (vis)
lToolbar->show();
}
#endif
private:
QToolBar* lToolbar;
};
ADDED: A QToolBar subclass which applies the workaround on its own, nothing special needed in the QMainWindow. The minimize fix still only works when the adjustToolbar() function is queued or if restoreState() is only called after show() (see code comments).
class ToolBar : public QToolBar
{
Q_OBJECT
public:
using QToolBar::QToolBar;
#ifdef Q_OS_LINUX
protected:
void showEvent(QShowEvent *e) override
{
QToolBar::showEvent(e);
if (isFloating() && windowFlags().testFlag(Qt::X11BypassWindowManagerHint) ) {
// QMainWindow::show() after QMainWindow::restoreState() will break the minimizing again so we should delay calling adjustToolbar().
QMetaObject::invokeMethod(this, "adjustToolbar", Qt::QueuedConnection);
// If we're sure restoreState() is only called after show() then adjustToolbar() could be called here directly instead.
//adjustToolbar();
}
}
private slots:
void adjustToolbar()
{
const bool vis = !isHidden();
hide();
setWindowFlag(Qt::X11BypassWindowManagerHint, false);
if (vis)
show();
}
#endif
};
UPDATE3: The minimizing issue also exists with floating QDockWidget if the QMainWindow state is restored before it is shown. In fact with "older" Qt versions the floating widget doesn't show up at all (doesn't with <= 5.9.5 but does with >= 5.12.4, don't have anything in between to try ATM). So the proper approach is to show() the main window first and then restoreState(). Unfortunately this doesn't seem to work for QToolBar.
UPDATE4: Filed as QTBUG-78293
It seems to work normally on macOS:
My code :
main.cpp
#include <iostream>
namespace file {
#include "file.cpp"
}
namespace file2 {
#include "file1.cpp"
}
int main() {
file::hello();
return 0;
}
file.cpp
#include <iostream>
void hello() {
std::cout << "hello";
}
file1.cpp
#include <iostream>
void hello() {
std::cout << "hello world";
}
My problem:
I use virtual studio, and i don't know why this does not work.I try it allready on CodeBlock and it was fine. But in VS i have error with at least one repeatedly defined symbol has been found.
Sorry for my english.
Since VS still builds and links file.cpp and file1.cpp to the executable you get the errors. You can exclude them from the project by changing its properties or make them regular header files and include them as such.
The include will literally just copy the content of the file into the name space declaration of main.cpp.
so somewhere along the lines of putting this app together I've started to get a runtime check failure stack corruption when the destructor for a cstring class member is called.
I've gotten to the point of trying to debug this by throwing bricks at the issue but still havent root caused it. At the current moment the class that the cstring resides in does nothing but initialize its private string members and set a pointer to another class to NULL.
Interestingly if I do not set the class pointer to NULL and comment out that line the corruption goes away. I think this is somewhat of a red herring, and that something is changing in the way the compiler is putting the code together when it pulls in the .h file that contains theCLog definitions and that would be used since I'm declaring a pointer to that object.
int _tmain(int argc, _TCHAR* argv[])
{
DWORD a = 0xBABA; //just to help catch the corrupter
DWORD b = 0xDFDF;
CStringW startat = L"\\\\anetworkshare\\fre";
CStringW lookfor = L".inf";
DirEnum myEnum(startat,lookfor);
ULONG en = a + b;
en = a - b;
return 0;
}
DirEnum.cpp
DirEnum::DirEnum(CString startingdir,CString fileFilter)
{
m_plogfile = NULL; //If you comment out this line corruption goes away
m_startingdir = L"";
m_extfilter = L"";
if(startingdir.GetLength() > 0)
m_startingdir = startingdir;
if(fileFilter.GetLength() > 0)
m_extfilter = fileFilter;
//following commented out to tshoot
//CLogBase& ref = ref.GetInstance();
//logBase = &ref;
//m_plogfile = new CLog(L"DirEnumerator",L"logfile.txt",logINFO);
}
Now I suspect that something in the log.h file is causing a change to occuur in the ATL or CString libraries but I dont know what. Heres the log.h file
#pragma once
//#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
using namespace std;
#ifndef TYPEDEF_H
#define TYPEDEF_H
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <tchar.h>
#include <time.h>
//simple defines to allow the TCHAR library to be used
typedef std::basic_string<TCHAR> tstring;
typedef std::basic_ostream<TCHAR> tostream;
typedef std::basic_istream<TCHAR> tistream;
typedef std::basic_ostringstream<TCHAR> tostringstream;
typedef std::basic_istringstream<TCHAR> tistringstream;
typedef std::basic_ofstream<TCHAR> tofstream;
#if defined(UNICODE) || defined(_UNICODE)
#define tcout std::wcout
#define tcin std::wcin
#else
#define tcout std::cout
#define tcin std::cin;
#endif
#endif
#if defined DEBUG || defined (_DEBUG)
#define TOCONSOLE
#endif
typedef enum LOGLVL{logERROR =0,logWARN,logINFO,logDEBUG};
//CLogBase os a singleton log class. Intent is that you can establish a reference from anywhere in the project and write to the same file
// without having locking issues or threading issues
class CLogBase
{
public:
static CLogBase& GetInstance(CString logname = L"log.txt",LOGLVL lvl = logWARN);
~CLogBase(void);
tostringstream& GetLog(LOGLVL level);
tostringstream& GetStream(LOGLVL);
void Forceflush();
private:
CLogBase(CString file,LOGLVL lvl);
//our outstream
tostringstream m_os;
tostringstream m_dummy;
tofstream m_filestream;
CString m_filename;
LOGLVL m_reportlvl;
//Private declarations to prevent copy constructors from being invoked; these are do nothig implimentations
CLogBase(CLogBase const&);
void operator=(CLogBase const&);
};
class CLog
{
public:
CLog(CString component);
CLog(CString component,CString logname,LOGLVL lvl);
~CLog();
void Log(LOGLVL,CString message);
void CLog::Flush();
tostringstream& CLog::GetStream(LOGLVL lvl);
private:
CString m_componentname;
CLogBase* m_logBase;
};
I thought I would answer this as I found the issue. this was not a coding problem per se but a visual studio issue.
What happened was that I was storing the direnum.h file and .cpp file in a different directory than the one used for the main project. referencing the header with #include "..\somedir\direnum.h"
at one point in time visual studio reported the file as locked and did I want to overwrite \ cancel etc. I choose overwrite but what seemed to happen was that this caused VS to COPY the files to the current project. All my troubleshooting attempts were being edited in the local somename.h file whtne opened in the editor but the compiler was doing the correct thing and pulling down the .h file from the location above.
removing switching to the now local copy of direnum.h and recompiling fixed this as it was compiling part of the code as ANSI and the other part as WCHAR
I´m trying to add a signal to my qthread, but I get an some errors:
error: undefined reference to `vtable for RFDongleCommunication'
error: undefined reference to `RFDongleCommunication::newLogger(unsigned char, unsigned char)'
This is my header file:
#ifndef RFDONGLECOMMUNICATION_H
#define RFDONGLECOMMUNICATION_H
#include <QThread>
#include "qextserialport.h"
#include <QtGui>
class RFDongleCommunication: public QThread
{
Q_OBJECT
public:
explicit RFDongleCommunication(QextSerialPort * port);
QextSerialPort * rfport;
QByteArray data;
signals:
void newLogger(uchar,uchar);
private:
void run();
};
#endif // RFDONGLECOMMUNICATION_H
And the cpp file
#include "rfdonglecommunication.h"
#include "QDebug"
RFDongleCommunication::RFDongleCommunication(QextSerialPort * port)
{
rfport=port;
}
void RFDongleCommunication::run()
{
while(!(rfport->bytesAvailable()));
data = rfport->readAll();
uchar id = data[1];
uchar type = data[2];
emit newLogger(id,type);
}
Does anybody see what I´m doing wrong?
Make shure your class is in a different .cpp and .h file that are included in the MOC process generation
Click on: File - New File or Project - Files and classes - C++ - New
class
undefined reference to `vtable means that the moc cpp file is not generated.
I see that this is a very old post, but it seems people still keep asking very similar or even exactly the same question. I would elaborate the answer given by Rudolfs Bundulis above a little, and hope it would be helpful.
In case you are using Qt Creator and when you compiled your project for the first time, you did not put "Q_OBJECT" in your header file, then the moc cpp file for your (qthread) cpp file was not generated. In this case, simply running "Clean All" and "Rebuild All" after putting "Q_OBJECT" in your header file will not work. You need to go to your build folder to manually delete the Qt generated "Makefile" and run "Rebuild All" or "Build All" again, your error message will be gone.
I want to call Java class methods from a cpp file that receives call backs from another executable.
To achieve this, I have retrieved a JavaVM pointer using the android::AndroidRuntime::getJavaVM() method in the .cpp file that directly receives JNI method calls. I am sharing this JavaVM pointer via the constructor to the eventual .cpp file where I call required Java methods as follows:
/* All the required objects(JNIEnv*,jclass,jmethodID,etc) are appropriately declared. */
**JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL);
clazz = env->FindClass("com/skype/ref/NativeCodeCaller");
readFromAudioRecord = env->GetStaticMethodID(clazz, "readFromAudioRecord", "([B)I");
writeToAudioTrack = env->GetStaticMethodID(clazz, "writeToAudioTrack", "([B)I");**
However, I get a SIGSEGV fault running this code.
According to the JNI documentation this seems to be the appropriate way to obtain JNIEnv in arbitary contexts: http://java.sun.com/docs/books/jni/html/other.html#26206
Any help in this regard will be appreciated.
Regards,
Neeraj
Global references will NOT prevent a segmentation fault in a new thread if you try to use a JNIEnv or JavaVM reference without attaching the thread to the VM. You were doing it properly the first time around, Mārtiņš Možeiko is mistaken in implying that there was something wrong with what you were doing.
Don't remove it, just learn how to use it. That guy doesn't know what he's talking about, if it's in jni.h you can be pretty sure it's not going anywhere. The reason it's not documented is probably because it's ridiculously self explanatory. You don't need to create GlobalReference objects or anything either, just do something like this:
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#include <linux/threads.h>
#include <pthread.h>
#define LOG_TAG "[NDK]"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static pthread_mutex_t thread_mutex;
static pthread_t thread;
static JNIEnv* jniENV;
void *threadLoop()
{
int exiting;
JavaVM* jvm;
int gotVM = (*jniENV)->GetJavaVM(jniENV,&jvm);
LOGI("Got JVM: %s", (gotVM ? "false" : "true") );
jclass javaClass;
jmethodID javaMethodId;
int attached = (*jvm)->AttachCurrentThread(jvm, &jniENV,NULL);
if(attached>0)
{
LOGE("Failed to attach thread to JavaVM");
exiting = 1;
}
else{
javaClass= (*jniENV)->FindClass(jniENV, "com/justinbuser/nativecore/NativeThread");
javaMethodId= (*jniENV)->GetStaticMethodID(jniENV, javaClass, "javaMethodName", "()V");
}
while(!exiting)
{
pthread_mutex_lock(&thread_mutex);
(*jniENV)->CallStaticVoidMethod(jniENV, javaClass, javaMethodId);
pthread_mutex_unlock(&thread_mutex);
}
LOGE("Thread Loop Exiting");
void* retval;
pthread_exit(retval);
return retval;
}
void start_thread(){
if(thread < 1)
{
if(pthread_mutex_init(&thread_mutex, NULL) != 0)
{
LOGE( "Error initing mutex" );
}
if(pthread_create(&thread, NULL, threadLoop, NULL) == 0)
{
LOGI( "Started thread#: %d", thread);
if(pthread_detach(thread)!=0)
{
LOGE( "Error detaching thread" );
}
}
else
{
LOGE( "Error starting thread" );
}
}
}
JNIEXPORT void JNICALL
Java_com_justinbuser_nativecore_NativeMethods_startThread(JNIEnv * env, jobject this){
jniENV = env;
start_thread();
}
Solved the problem. The segmentation fault was because I could not retrieve a jclass object from the JNIEnv object retrieved from the shared jvm pointer.
I propogated a Global reference jclass object alongwith the jvm and the problem was solved.
Thanks for your help Mārtiņš Možeiko!..
Regards,
Neeraj