Showing preview only (330K chars total). Download the full file or copy to clipboard to get everything.
Repository: CrimsonAS/gtkplatform
Branch: master
Commit: 1149f4f77523
Files: 60
Total size: 311.8 KB
Directory structure:
gitextract_lr58kn4j/
├── .gitignore
├── LICENSE
├── README.md
├── examples/
│ ├── examples.pro
│ └── gtkextras/
│ ├── gtkextras.pro
│ └── headerbar/
│ ├── headerbar.pro
│ └── main.cpp
├── gtkplatform.pro
├── src/
│ ├── gtkextras/
│ │ ├── gtkextras.pro
│ │ ├── qgtkextrasglobal.h
│ │ ├── qgtkheaderbar.cpp
│ │ ├── qgtkheaderbar.h
│ │ └── qgtkrefptr.h
│ ├── platform-plugin/
│ │ ├── CSystrace.cpp
│ │ ├── CSystrace.h
│ │ ├── CTraceMessages.h
│ │ ├── gtk.json
│ │ ├── main.cpp
│ │ ├── platform-plugin.pro
│ │ ├── qgtk3dialoghelpers.cpp
│ │ ├── qgtk3dialoghelpers.h
│ │ ├── qgtkbackingstore.cpp
│ │ ├── qgtkbackingstore.h
│ │ ├── qgtkclipboard.cpp
│ │ ├── qgtkclipboard.h
│ │ ├── qgtkcursor.cpp
│ │ ├── qgtkcursor.h
│ │ ├── qgtkeventdispatcher.cpp
│ │ ├── qgtkeventdispatcher.h
│ │ ├── qgtkhelpers.cpp
│ │ ├── qgtkhelpers.h
│ │ ├── qgtkintegration.cpp
│ │ ├── qgtkintegration.h
│ │ ├── qgtkmenu.cpp
│ │ ├── qgtkmenu.h
│ │ ├── qgtkmenubar.cpp
│ │ ├── qgtkmenubar.h
│ │ ├── qgtkmenuitem.cpp
│ │ ├── qgtkmenuitem.h
│ │ ├── qgtkopenglcontext.cpp
│ │ ├── qgtkopenglcontext.h
│ │ ├── qgtkopenglcontext_wayland.cpp
│ │ ├── qgtkopenglcontext_x11.cpp
│ │ ├── qgtkscreen.cpp
│ │ ├── qgtkscreen.h
│ │ ├── qgtkservices.cpp
│ │ ├── qgtkservices.h
│ │ ├── qgtksystemtrayicon.cpp
│ │ ├── qgtksystemtrayicon.h
│ │ ├── qgtktheme.cpp
│ │ ├── qgtktheme.h
│ │ ├── qgtkwindow.cpp
│ │ ├── qgtkwindow.h
│ │ ├── qgtkwindow_gesture.cpp
│ │ ├── qgtkwindow_keyboard.cpp
│ │ ├── qgtkwindow_mouse.cpp
│ │ ├── qgtkwindow_render.cpp
│ │ └── qgtkwindow_touch.cpp
│ └── src.pro
└── sync.profile
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.qmake.*
*.o
Makefile
moc_*.cpp
moc_*.h
*.moc
================================================
FILE: LICENSE
================================================
The source code in this repository is available under the same terms as that of
the open source licenses Qt itself is available under: LGPL v3 or GPL 2+.
If these license terms are not suitable, please contact us: info@crimson.no.
================================================
FILE: README.md
================================================
# introduction
gtkplatform is a Qt Platform Abstraction plugin providing Qt applications with
the capability to use gtk+ as a host toolkit, primarily intended for use on
Linux desktops.
That is: it lets Qt applications render with native gtk+ menus, and use gtk+ for
input (mouse, keyboard, touch), and getting window content on screen, the same
as it uses e.g. cocoa on macOS for instance.
Thanks to:
* Robin Burchell (@rburchell, initial idea & heavy lifting)
* John Brooks (@special, rendering work and OpenGL implementation)
* Gunnar Sletta (@sletta, all sorts of assistance and brainstorming)
* Donald Carr (@sirspudd, Arch Linux packaging)
If you'd like to have a chat with us, feel free to
[drop in on Telegram](https://t.me/joinchat/FlwGHw366p2Z9tBZ_f1yTA).
## what this is
It's a way to get better integrated, consistent application behaviour on the
Linux desktop.
## what this is **not**
It's not the most performant way to run applications, and as a result, not well
suited for the embedded environment. This is particularly noticable with QtQuick
applications, as they make use of OpenGL. This goes through a copy step: the
scene is drawn offscreen, copied, and uploaded to the gtk+ window, which is
rather inefficient. Hopefully, gtk+ will grow API to allow this to be done
better in the future.
## current state
What works:
* Showing, resizing, and hiding windows windows (all hopefully flicker-free)
* Rendering in those windows
* Using QPainter
* Using QOpenGLContext
* A mix of OpenGL and software rendering in those windows (QOpenGLWidget, etc)
* QtWebEngine (if patched, tracked at [#9](https://github.com/CrimsonAS/gtkplatform/issues/9))
* Simple clipboard interaction (text/image copying)
* Native gtk+ dialogs (taken from Qt)
* Native gtk+ menubar
* Notifications using libnotify
* Input events
* Touch
* Keyboard
* Mouse, including smooth scroll events
Not everything does work, though. See the known issues section.
# screenshots
Here's Qt Creator running with the gtk+ platform plugin:

If you'd like to see more, [go take a look at the wiki](https://github.com/CrimsonAS/gtkplatform/wiki).
# building
These are the versions I test with.
* Qt 5.10.1
* gtk+ 3.22.30
* libnotify 0.7.7
These are all available in Fedora 28, which is where I do testing/development.
Good support is also available on Arch Linux, using [the package generously
maintained by @sirspudd](https://aur.archlinux.org/packages/qt-gtk-platform-plugin/).
Note that on Fedora, you need qt5-qtbase-static and redhat-rpm-config installed
to build from source.
Other distributions may, or may not work, but I don't have any involvement with them.
With dependencies installed:
* `qmake`
* `make`
* `make install` (as root)
Then try launch something after setting `QT_QPA_PLATFORM=gtk` (or `-platform gtk`
as a command line option)
# history
Qt is pretty portable. I don't think there's any doubt to this statement; just
take a look at the vast myriad of platform ports out there. It runs on macOS,
Windows, even Haiku. It's everywhere.
There's a bit of a fly in the ointment, though: on the Linux desktop, things
aren't quite so well defined. There isn't a "sanctioned" platform toolkit.
As a result, Qt has to do quite a lot of heavy lifting itself, and this doesn't
always result in something that is too well integrated with the host desktop
system.
As an additional problem, the Linux desktop world is changing. The stability
(which some may consider stagnation) of xcb has been giving way to the rise of
Wayland. In many ways, this change has been beneficial: it's a lot harder to
introduce some bad graphical glitches like flicker on resize. On the other hand,
it introduces a host of its own brand new problems.
Even discounting all of these as solvable problems on top of the usual
things like reasonably performant flicker-free graphics that we ought to have
and ought to be able to take for granted, there's the root issue
that there is a significant amount of duplicate work going on here: any new
development has to be solved in (at least) two major toolkits.
So with this background, we get to the situation that lead to this project. A
while ago, I moved from macOS back to Linux as my day to day desktop system, and
quickly experienced frustration with a myriad of bad, very user-visible bugs
on Linux like variances in how high DPI is dealt with, font sizing and selection
that wasn't identical, black flicker on resizing, bad trackpad scroll behaviour,
the reliance of Qt applications on xwayland rather than being first class
Wayland citizens, etc.
This project aims to help mitigate those issues.
# Known Issues
* Popup positioning (like combo box dropdowns) will often be wrong.
When running on Wayland, this platform plugin will not allow absolute
positioning of a window in global coordinate space. Instead, popups are
positioned relative to their parent window. This usually manifests as windows
appearing very far away from where they ought to have triggered because they
failed to set a parent.
* Notifications don't work right.
Right now, we're using libnotify, because using `GtkApplication` without using
`g_application_run` doesn't seem trivial. This means that we're not using the
latest and greatest stuff, unfortunately. I'd like to fix this somehow.
* Accessibility doesn't work
* Drag and drop doesn't work
It isn't written yet. There's rather a lot of features like that, actually.
I'm sure it will improve with time.
* My menu shortcuts have funny things in them
The mapping of GTK+ keys to Qt keys is incomplete. See [#8](https://github.com/CrimsonAS/gtkplatform/issues/8).
* QtWebEngine doesn't work out of the box
Correct. Currently there's a hardcoded "whitelist" of platform plugins that
will work. The patch to make it work is quite trivial, see `src/core/content_browser_client_qt.cpp`,
and make it request "eglcontext" unconditionally (or when using the "gtk"
plugin). See [#9](https://github.com/CrimsonAS/gtkplatform/issues/9).
# FAQ
* **Q:** But my desktop works just fine. I don't want to use this.
**A:** That's fine. Keep using what you are using today, and pretend this
doesn't exist.
* **Q:** Why is this any better than a theme for Qt which looks like a gtk+ theme?
**A:** These are separate, but related concerns. If I was just interested in
getting the contents of a window to look like the contents of a Qt window,
then sure, a theme/style plugin alone would be more than sufficient.
More importantly than the contents of the window, though, I want consistency
on the level of things underneath theming too. For instance, using this, you
get transparent Wayland support that looks and works good *right now* without
having to fix the numerous desktop-related pieces that are missing from QtWayland.
You get consistent high DPI support. You get window resizing that doesn't
flicker, unlike that of the xcb platform plugin.
Longer term, I have even bigger goals than this. I want to be able to use
platform-native features like GNotification, GtkHeaderBar, app menus, and more.
I'd also like to look into mapping GtkGesture into something that Qt applications
can make use of, so pinch/rotate/etc all work in the same way across all desktop
applications.
Most of this isn't realised yet, as for the time being I'm focusing on the
"basics", but in the longer term I expect it will come. In the short term,
this is about a more consistent, more usable out-of-the-box desktop
experience.
* **Q:** Are you changing Qt's API?
**A:** No. Your existing Qt applications of today will work with this with the
same amount of tweaking they might need to make when running on a new platform
like macOS or Wayland. We may provide some helpers to allow using some gtk+
specific features in future, like GtkHeaderBar, though.
* **Q:** Why are you doing this? Qt supports _my pet feature_ better.
**A:** That might be true. The main problem here is inconsistencies between
different applications on my desktop. I want everything to look, and act the
same. And maybe once I have that, we can focus on improving everything at once
rather than fighting over who has the better toolkit.
* **Q:** Why isn't this part of Qt?
**A:** Firstly, it's easier to develop something that is rapidly changing
out-of-tree. Secondly, I want this to be usable on my desktop _now_, not
in 6-12 months time.
* **Q:** There's no system tray icon support
**A:** [Correct](https://bugzilla.gnome.org/show_bug.cgi?id=785956).
Given that GtkStatusIcon is deprecated, and the system tray is a dead concept inside GNOME, I don't think this warrants supporting.
* **Q:** How does high DPI support work?
**A:** We're using gtk+, so, it works the same way it does there. Window size
etc is reported in units that aren't real pixels. The window content is drawn
by scaling those sizes by the appropriate amount into a larger buffer, which
is then drawn by gtk+.
* **Q:** How do multiple monitors work?
**A:** They probably don't.
More seriously, I haven't tested them much yet. There's probably going to
be a lot of bugs there. When all that stabilizes, though, it should work the
same as it does with gtk+ applications.
* **Q:** My application doesn't work!
**A:** Not exactly a question, but: many applications rely on features of the
underlying platform at build time. This of course won't work out of the box in
many cases, sometimes due to missing mapping of a feature, and sometimes
because it's outright not possible.
It might be a bug in gtkplatform, or it might be that the application requires
adaptation.
* **Q:** Does this render using gtk+?
**A:** Sort of. With the exception of menu bars on windows, the content of the
window is entirely rendered by Qt right now. Once Qt is done with that, it
passes over to our code, and we use gtk+ to get that content on screen as
well as to provide some of the desktop's settings, like font settings.
So the reason that widgets look "native" is for the most part not down to the
work that we've done, but rather the work of the people who wrote the Adwaita
theme plugin. This having been said, it might be an area of interest to look
at the possibility of using Pango to render text in the future, rather than
fontconfig/freetype.
* **Q:** What technologies does this build on?
**A:** The "glib" event dispatcher, originally written by [Bradley Hughes](https://blog.qt.io/blog/2006/02/24/qt-and-glib/)
during his time working on Qt has proven very useful. Without that, this
would have been a more difficult task.
The ["adwaita" QStyle plugin](https://github.com/MartinBriza/adwaita-qt) is
also great in that it helps the contents of windows blend in very well.
Of course, none of this would be possible without the work of everyone in the
greater Linux desktop community, too, particularly the gtk+ and Qt contributors.
================================================
FILE: examples/examples.pro
================================================
TEMPLATE = subdirs
SUBDIRS += gtkextras
================================================
FILE: examples/gtkextras/gtkextras.pro
================================================
TEMPLATE = subdirs
SUBDIRS += \
headerbar
================================================
FILE: examples/gtkextras/headerbar/headerbar.pro
================================================
QT += widgets gui-private gtkextras
TEMPLATE = app
TARGET = testheaderbar
INCLUDEPATH += ../src
# Input
SOURCES += main.cpp
CONFIG += link_pkgconfig
PKGCONFIG += gtk+-3.0
CONFIG += no_keywords
target.path = $$[QT_INSTALL_EXAMPLES]/gtkextras/headerbar
INSTALLS += target
================================================
FILE: examples/gtkextras/headerbar/main.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include <QApplication>
#include <QWidget>
#include <QWindow>
#include <QLabel>
#include <QDebug>
#include <QtGtkExtras/QGtkHeaderBar>
#include <QtGtkExtras/QGtkRefPtr>
#include <gtk/gtk.h>
class TestWindow : public QWidget
{
public:
TestWindow()
{
QGtkHeaderBar *qhb = new QGtkHeaderBar(this);
GtkWidget *hb = qhb->headerBarWidget();
gtk_header_bar_set_title(GTK_HEADER_BAR(hb), "A magical Qt test");
gtk_header_bar_set_subtitle(GTK_HEADER_BAR(hb), "Featuring a real GtkHeaderBar");
gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(hb), TRUE);
openMenuButton = gtk_button_new_from_icon_name("open-menu-symbolic", GTK_ICON_SIZE_BUTTON);
gtk_header_bar_pack_end(GTK_HEADER_BAR(hb), openMenuButton.get());
}
private:
QGtkRefPtr<GtkWidget> openMenuButton;
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
TestWindow w;
QLabel l(&w);
l.setText("I'm a QLabel");
w.resize(200, 200);
w.show();
return app.exec();
}
================================================
FILE: gtkplatform.pro
================================================
load(qt_parts)
================================================
FILE: src/gtkextras/gtkextras.pro
================================================
TARGET = QtGtkExtras
QT -= gui
QT += widgets gui-private
HEADERS += \
qgtkrefptr.h \
qgtkheaderbar.h
SOURCES += \
qgtkheaderbar.cpp
CONFIG += link_pkgconfig
PKGCONFIG_PRIVATE += gdk-3.0 gtk+-3.0
CONFIG += no_keywords
load(qt_module)
CONFIG -= create_cmake # should be fixed, but ...
================================================
FILE: src/gtkextras/qgtkextrasglobal.h
================================================
/****************************************************************************
**
** Copyright (C) 2018 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QTGTKEXTRASGLOBAL_H
#define QTGTKEXTRASGLOBAL_H
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
#ifndef QT_STATIC
# if defined(QT_BUILD_GTKEXTRAS_LIB)
# define Q_GTKEXTRAS_EXPORT Q_DECL_EXPORT
# else
# define Q_GTKEXTRAS_EXPORT Q_DECL_IMPORT
# endif
#else
# define Q_GTKEXTRAS_EXPORT
#endif
QT_END_NAMESPACE
#endif // QTGTKEXTRASGLOBAL_H
================================================
FILE: src/gtkextras/qgtkheaderbar.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2018 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include <QWindow>
#include <QWidget>
#include <QGuiApplication>
#include <QDebug>
#include <qpa/qplatformnativeinterface.h>
#include "qgtkheaderbar.h"
#include "qgtkrefptr.h"
class QGtkHeaderBar::QGtkHeaderBarPrivate
{
public:
QGtkRefPtr<GtkWidget> headerBar;
};
QGtkHeaderBar::QGtkHeaderBar(QObject *parent)
: d(new QGtkHeaderBarPrivate)
{
QWindow *win = 0;
win = qobject_cast<QWindow*>(parent);
if (!win) {
QWidget *w = qobject_cast<QWidget*>(parent);
if (!w->isVisible()) {
w->show(); // ensure pwin creation
w->hide();
}
qWarning() << "widget w" << w;
if (w) {
// ### this stuff all feels super sketchy
//w = w->window();
//if (!w) {
// qFatal("Created a QGtkHeaderBar on a widget with no parent window...");
//}
win = w->windowHandle();
qWarning() << "widget win" << win;
if (!win) {
qWarning() << "widget npw" << w->nativeParentWidget();
qWarning() << "widget npw win" << w->nativeParentWidget()->windowHandle();
win = w->nativeParentWidget()->windowHandle();
if (!win) {
qFatal("QGtkHeaderBar couldn't get window handle of widget...");
}
}
}
}
// ensure that QPA resources are created
win->create();
d->headerBar = gtk_header_bar_new();
QPlatformNativeInterface *platformNativeInterface = QGuiApplication::platformNativeInterface();
GtkWidget *w = static_cast<GtkWidget*>(platformNativeInterface->nativeResourceForWindow("gtkwindow", win));
if (!w) {
qFatal("no GtkWidget! (not using the right QPA?)");
}
gtk_window_set_titlebar(GTK_WINDOW(w), d->headerBar.get());
}
QGtkHeaderBar::~QGtkHeaderBar()
{
delete d;
}
GtkWidget *QGtkHeaderBar::headerBarWidget() const
{
return d->headerBar.get();
}
================================================
FILE: src/gtkextras/qgtkheaderbar.h
================================================
/****************************************************************************
**
** Copyright (C) 2018 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QGTKHEADERBAR_H
#define QGTKHEADERBAR_H
#include <QtCore/qglobal.h>
#include <QtCore/qobject.h>
#include <gtk/gtk.h>
#include "qgtkextrasglobal.h"
QT_BEGIN_NAMESPACE
class Q_GTKEXTRAS_EXPORT QGtkHeaderBar : public QObject
{
public:
QGtkHeaderBar(QObject *parent);
~QGtkHeaderBar();
GtkWidget *headerBarWidget() const;
private:
class QGtkHeaderBarPrivate;
QGtkHeaderBarPrivate *d;
};
QT_END_NAMESPACE
#endif // QGTKHEADERBAR_H
================================================
FILE: src/gtkextras/qgtkrefptr.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QGTKREFPTR_H
#define QGTKREFPTR_H
#include <QtCore/qglobal.h>
#include <gtk/gtk.h>
QT_BEGIN_NAMESPACE
template<typename T>
class QGtkRefPtr
{
public:
QGtkRefPtr()
: m_obj(0)
{
}
QGtkRefPtr(gpointer obj)
: m_obj(obj)
{
if (m_obj)
g_object_ref_sink(m_obj);
}
QGtkRefPtr(const QGtkRefPtr& other)
: m_obj(other.m_obj)
{
if (m_obj)
g_object_ref(m_obj);
}
~QGtkRefPtr()
{
if (m_obj)
g_object_unref(m_obj);
}
QGtkRefPtr<T>& operator=(const QGtkRefPtr &other)
{
reset(other.get());
return *this;
}
bool operator==(const QGtkRefPtr &other)
{
return this->m_obj == other.m_obj;
}
bool operator!=(const QGtkRefPtr &other)
{
return !(*this == other);
}
bool operator==(gpointer other)
{
return this->m_obj == other;
}
bool operator!=(gpointer other)
{
return !(*this == other);
}
// ### consider moves
T* get() const { return static_cast<T*>(m_obj); }
operator bool() const { return m_obj != nullptr; }
void reset(T* newObj)
{
if (m_obj)
g_object_unref(m_obj);
m_obj = newObj;
if (m_obj)
g_object_ref_sink(m_obj);
}
private:
gpointer m_obj;
};
QT_END_NAMESPACE
#endif // QGTKREFPTR_H
================================================
FILE: src/platform-plugin/CSystrace.cpp
================================================
/*
* Copyright (c) 2017 Crimson AS <info@crimson.no>
* Author: Robin Burchell <robin.burchell@crimson.no>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
// MAC
#include <unistd.h> // syscall()
#include <sys/syscall.h> // SYS_thread_selfid
// ENDMAC
#include <unordered_map>
#include "CSystrace.h"
#include "CTraceMessages.h"
#include <atomic>
// Information about SHM chunks
const int ShmChunkSize = 1024 * 10;
// Data about the process of tracing itself.
// This is held thread-local.
struct CTracerThreadData
{
// The FD for the open SHM chunk
int m_shm_fd = -1;
// The pointer to the start of the SHM chunk
char *m_shmInitialPtr = 0;
// The pointer to the current location in the SHM chunk (so written len
// would be m_shmPtr - m_shmInitialPtr).
char *m_shmPtr = 0;
// The name of the current SHM chunk
char *m_currentChunkName = 0;
// How much of the SHM chunk for this thread is left, in bytes?
int m_remainingChunkSize = 0;
// A map of string -> ID for this thread. Each thread registers strings
// independently (as it has its own chunks, its own code, and we don't want
// to lock as much as possible).
std::unordered_map<const char *, uint64_t> m_registeredStrings;
};
static thread_local CTracerThreadData tracerThreadData;
// Global data. There are no locks in place, so don't be dumb when using this.
struct CTracerGlobalData
{
// FD to communicate with traced
int m_traced_fd = -1;
// Each thread registers unique strings as it comes across them here and sends a
// registration message to traced.
std::atomic<uint64_t> m_currentStringId;
// When the trace started (when systrace_init was called).
// Do not modify this outside of systrace_init! It is read from multiple
// threads.
struct timespec m_originalTp;
};
static CTracerGlobalData tracerGlobalData;
//gettid(); except that mac sucks
static int gettid()
{
#ifdef __APPLE__
return syscall(SYS_thread_selfid);
#else
return syscall(SYS_gettid);
#endif
}
/*! Update the book keeping for the current position in the chunk.
*/
static void advance_chunk(int len)
{
tracerThreadData.m_shmPtr += len;
tracerThreadData.m_remainingChunkSize -= len;
assert(tracerThreadData.m_remainingChunkSize >= 0);
}
/*!
* Send the current chunk to traced for processing.
*
* ### right now, this will not be called if a thread terminates abruptly.
* we should somehow monitor old, stale chunks and force-submit them.
*/
static void submit_chunk()
{
if (tracerThreadData.m_shm_fd == -1)
return;
munmap(tracerThreadData.m_shmInitialPtr, ShmChunkSize);
close(tracerThreadData.m_shm_fd);
tracerThreadData.m_shm_fd = -1;
tracerThreadData.m_shmPtr = 0;
char buf[1024];
int blen = sprintf(buf, "%s\n", tracerThreadData.m_currentChunkName);
if (0) // left for debug purposes
printf("TID %d sending %s", gettid(), buf);
int ret = write(tracerGlobalData.m_traced_fd, buf, blen);
if (ret == -1) {
// ### we also need to ignore SIGPIPE or clients will die if traced does.
perror("Can't write to traced! Giving up!");
shm_unlink(tracerThreadData.m_currentChunkName);
close(tracerGlobalData.m_traced_fd);
tracerGlobalData.m_traced_fd = -1;
}
}
static uint64_t getMicroseconds()
{
struct timespec tp;
if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
perror("Can't get time");
abort();
}
return (tp.tv_sec - tracerGlobalData.m_originalTp.tv_sec) * 1000000 +
(tp.tv_nsec / 1000) - (tracerGlobalData.m_originalTp.tv_nsec / 1000);
}
static void systrace_debug()
{
#if 0
static thread_local bool debugging = false;
if (debugging)
return;
debugging = true;
// These vars are to try avoid spurious reporting.
static thread_local int lastm_remainingChunkSize = 0;
if (m_remainingChunkSize != lastm_remainingChunkSize) {
lastm_remainingChunkSize = m_remainingChunkSize;
systrace_record_counter("systrace", "m_remainingChunkSize", m_remainingChunkSize, gettid());
}
static uint64_t lastStringCount = 0;
if (lastStringCount != tracerGlobalData.m_currentStringId.load()) {
lastStringCount = tracerGlobalData.m_currentStringId.load();
systrace_record_counter("systrace", "registeredStringCount", lastStringCount); // not thread-specific
}
debugging = false;
#endif
}
/*!
* Make sure we have a valid SHM chunk to write events to, or abort if not.
*/
static void ensure_chunk(int mlen)
{
if (tracerThreadData.m_shm_fd != -1 && tracerThreadData.m_remainingChunkSize >= mlen)
return;
if (tracerThreadData.m_shm_fd != -1) {
submit_chunk();
}
// ### linux via /dev/shm or memfd_create?
int nextShmId = 0;
while (tracerThreadData.m_shm_fd == -1 && nextShmId < TRACED_MAX_SHM_CHUNKS) {
if (!tracerThreadData.m_currentChunkName)
asprintf(&tracerThreadData.m_currentChunkName, "tracechunk-%d", nextShmId++);
tracerThreadData.m_shm_fd = shm_open(tracerThreadData.m_currentChunkName, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
if (tracerThreadData.m_shm_fd != -1) {
break; // we won!
} else {
// try again. either something is using that chunk name, or traced
// hasn't released it for us to reuse yet.
free(tracerThreadData.m_currentChunkName);
tracerThreadData.m_currentChunkName = 0;
}
}
if (tracerThreadData.m_shm_fd == -1) {
fprintf(stderr, "Something is seriously screwed. Can't find any free SHM chunk, tried all %d\n", TRACED_MAX_SHM_CHUNKS);
abort();
}
if (ftruncate(tracerThreadData.m_shm_fd, ShmChunkSize) == -1) {
perror("Can't ftruncate SHM!");
abort();
}
tracerThreadData.m_shmPtr = (char*)mmap(0, ShmChunkSize, PROT_READ | PROT_WRITE, MAP_SHARED, tracerThreadData.m_shm_fd, 0);
if (tracerThreadData.m_shmPtr == MAP_FAILED) {
perror("Can't map SHM!");
abort();
}
tracerThreadData.m_remainingChunkSize = ShmChunkSize;
ChunkHeader *h = (ChunkHeader*)tracerThreadData.m_shmPtr;
h->magic = TRACED_PROTOCOL_MAGIC;
h->version = TRACED_PROTOCOL_VERSION;
h->pid = getpid();
h->tid = gettid();
h->epoch = (tracerGlobalData.m_originalTp.tv_sec * 1000000) +
(tracerGlobalData.m_originalTp.tv_nsec / 1000);
advance_chunk(sizeof(ChunkHeader));
}
__attribute__((constructor)) void systrace_init()
{
if (clock_gettime(CLOCK_MONOTONIC, &tracerGlobalData.m_originalTp) == -1) {
perror("Can't get time");
abort();
}
if (getenv("TRACED") == NULL) {
tracerGlobalData.m_traced_fd = open("/tmp/traced", O_WRONLY);
if ((tracerGlobalData.m_traced_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("Can't create socket for traced!");
}
struct sockaddr_un remote;
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, "/tmp/traced");
int len = strlen(remote.sun_path) + sizeof(remote.sun_family) + 1;
if (connect(tracerGlobalData.m_traced_fd, (struct sockaddr *)&remote, len) == -1) {
perror("Can't connect to traced!");
}
} else {
fprintf(stderr, "Running trace daemon. Not tracing.\n");
}
}
__attribute__((destructor)) void systrace_deinit()
{
if (tracerGlobalData.m_traced_fd == -1)
return;
submit_chunk();
close(tracerGlobalData.m_traced_fd);
tracerGlobalData.m_traced_fd = -1;
}
int systrace_should_trace(const char *module)
{
if (tracerGlobalData.m_traced_fd == -1)
return 0;
// hack this if you want to temporarily omit some traces.
return 1;
}
static uint64_t getStringId(const char *string)
{
auto it = tracerThreadData.m_registeredStrings.find(string);
if (it == tracerThreadData.m_registeredStrings.end()) {
uint64_t nid = tracerGlobalData.m_currentStringId.fetch_add(1);
tracerThreadData.m_registeredStrings[string] = nid;
int slen = strlen(string);
assert(slen < ShmChunkSize / 100); // 102 characters, assuming 10kb
ensure_chunk(sizeof(RegisterStringMessage) + slen);
RegisterStringMessage *m = (RegisterStringMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::RegisterStringMessage;
m->id = nid;
m->length = slen;
strncpy(&m->stringData, string, slen);
advance_chunk(sizeof(RegisterStringMessage) + slen);
systrace_debug();
return nid;
}
return it->second;
}
void systrace_duration_begin(const char *module, const char *tracepoint)
{
if (!systrace_should_trace(module))
return;
uint64_t modid = getStringId(module);
uint64_t tpid = getStringId(tracepoint);
ensure_chunk(sizeof(BeginMessage));
BeginMessage *m = (BeginMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::BeginMessage;
m->microseconds = getMicroseconds();
m->categoryId = modid;
m->tracepointId = tpid;
advance_chunk(sizeof(BeginMessage));
systrace_debug();
}
void systrace_duration_end(const char *module, const char *tracepoint)
{
if (!systrace_should_trace(module))
return;
uint64_t modid = getStringId(module);
uint64_t tpid = getStringId(tracepoint);
ensure_chunk(sizeof(EndMessage));
EndMessage *m = (EndMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::EndMessage;
m->microseconds = getMicroseconds();
m->categoryId = modid;
m->tracepointId = tpid;
advance_chunk(sizeof(EndMessage));
systrace_debug();
}
void systrace_duration_begin(CSystraceEvent &event)
{
if (!systrace_should_trace(event.m_module))
return;
event.m_begin = getMicroseconds();
// Do nothing We will write the event on end.
}
void systrace_duration_end(CSystraceEvent &event)
{
if (!systrace_should_trace(event.m_module))
return;
uint64_t modid = getStringId(event.m_module);
uint64_t tpid = getStringId(event.m_tracepoint);
ensure_chunk(sizeof(DurationMessage));
DurationMessage *m = (DurationMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::DurationMessage;
m->microseconds = event.m_begin;
m->duration = getMicroseconds() - event.m_begin;
m->categoryId = modid;
m->tracepointId = tpid;
advance_chunk(sizeof(DurationMessage));
systrace_debug();
}
void systrace_record_counter(const char *module, const char *tracepoint, int value, int id)
{
if (!systrace_should_trace(module))
return;
uint64_t modid = getStringId(module);
uint64_t tpid = getStringId(tracepoint);
if (id == -1) {
ensure_chunk(sizeof(CounterMessage));
CounterMessage *m = (CounterMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::CounterMessage;
m->microseconds = getMicroseconds();
m->categoryId = modid;
m->tracepointId = tpid;
m->value = value;
advance_chunk(sizeof(CounterMessage));
} else {
ensure_chunk(sizeof(CounterMessageWithId));
CounterMessageWithId *m = (CounterMessageWithId*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::CounterMessageWithId;
m->microseconds = getMicroseconds();
m->categoryId = modid;
m->tracepointId = tpid;
m->value = value;
m->id = id;
advance_chunk(sizeof(CounterMessageWithId));
}
systrace_debug();
}
void systrace_async_begin(const char *module, const char *tracepoint, const void *cookie)
{
if (!systrace_should_trace(module))
return;
uint64_t modid = getStringId(module);
uint64_t tpid = getStringId(tracepoint);
ensure_chunk(sizeof(AsyncBeginMessage));
AsyncBeginMessage *m = (AsyncBeginMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::AsyncBeginMessage;
m->microseconds = getMicroseconds();
m->categoryId = modid;
m->tracepointId = tpid;
m->cookie = (intptr_t)cookie;
advance_chunk(sizeof(AsyncBeginMessage));
systrace_debug();
}
void systrace_async_end(const char *module, const char *tracepoint, const void *cookie)
{
if (!systrace_should_trace(module))
return;
uint64_t modid = getStringId(module);
uint64_t tpid = getStringId(tracepoint);
ensure_chunk(sizeof(AsyncEndMessage));
AsyncEndMessage *m = (AsyncEndMessage*)tracerThreadData.m_shmPtr;
m->messageType = MessageType::AsyncEndMessage;
m->microseconds = getMicroseconds();
m->categoryId = modid;
m->tracepointId = tpid;
m->cookie = (intptr_t)cookie;
advance_chunk(sizeof(AsyncEndMessage));
systrace_debug();
}
================================================
FILE: src/platform-plugin/CSystrace.h
================================================
/*
* Copyright (c) 2017 Crimson AS <info@crimson.no>
* Author: Robin Burchell <robin.burchell@crimson.no>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef SYSTRACE_H
#define SYSTRACE_H
#if defined(DISABLE_TRACE_CODE)
struct CSystraceEvent;
inline void systrace_init() {}
inline void systrace_deinit() {}
inline int systrace_should_trace(const char *) { return 0; }
inline void systrace_duration_begin(const char *, const char *) {}
inline void systrace_duration_end(const char *, const char *) {}
inline void systrace_duration_begin(CSystraceEvent &) {}
inline void systrace_duration_end(CSystraceEvent &) {}
inline void systrace_record_counter(const char *, const char *, int , int = -1) {}
inline void systrace_async_begin(const char *, const char *, const void *) {}
inline void systrace_async_end(const char *, const char *, const void *) {}
struct CSystraceEvent
{
public:
CSystraceEvent(const char *, const char *)
{
}
~CSystraceEvent()
{
}
};
struct CSystraceAsyncEvent
{
public:
CSystraceAsyncEvent(const char *, const char *, const void *)
{
}
~CSystraceAsyncEvent()
{
}
};
#else
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_WIN32) || defined(__CYGWIN__)
# if defined(BUILDING_DLL)
# if defined(__GNUC__)
# define SYSTRACE_EXPORT __attribute__ ((dllexport))
# else
# define SYSTRACE_EXPORT __declspec(dllexport)
# endif
# else
# if defined(__GNUC__)
# define SYSTRACE_EXPORT __attribute__ ((dllimport))
# else
# define SYSTRACE_EXPORT __declspec(dllimport)
# endif
# endif
#else
# define SYSTRACE_EXPORT __attribute__ ((visibility ("default")))
#endif
/*!
* Perform necessary set up. Should be called before any other functions.
*
* \note If your compiler supports the `constructor` attribute (gcc does),
* then this method will be called for you. Calling it multiple times will not
* cause trouble, however, so feel free to call it yourself.
*
* \sa systrace_deinit()
*/
SYSTRACE_EXPORT void systrace_init();
/*!
* Perform necessary tear down. Should be called before termination, and no systrace
* methods should be called after it.
*
* \note If your compiler supports the `destructor` attribute (gcc does),
* then this method will be called for you. Calling it multiple times will not
* cause trouble, however, so feel free to call it yourself.
*
* \sa systrace_init()
*/
SYSTRACE_EXPORT void systrace_deinit();
/*!
* Determine whether or not a given \a module should be traced.
* This can be used to avoid expensive setup (such as allocation of data for the
* trace event).
*
* Returns 1 if the event should be traced, 0 otherwise.
*/
SYSTRACE_EXPORT int systrace_should_trace(const char *module);
struct CSystraceEvent;
SYSTRACE_EXPORT void systrace_duration_begin(const char *module, const char *tracepoint);
SYSTRACE_EXPORT void systrace_duration_end(const char *module, const char *tracepoint);
SYSTRACE_EXPORT void systrace_duration_begin(CSystraceEvent &event);
SYSTRACE_EXPORT void systrace_duration_end(CSystraceEvent &event);
SYSTRACE_EXPORT void systrace_record_counter(const char *module, const char *tracepoint, int value, int id = -1);
SYSTRACE_EXPORT void systrace_async_begin(const char *module, const char *tracepoint, const void *cookie);
SYSTRACE_EXPORT void systrace_async_end(const char *module, const char *tracepoint, const void *cookie);
struct SYSTRACE_EXPORT CSystraceEvent
{
public:
CSystraceEvent(const char *module, const char *tracepoint)
: m_module(module)
, m_tracepoint(tracepoint)
{
systrace_duration_begin(*this);
}
~CSystraceEvent()
{
systrace_duration_end(*this);
}
const char *m_module;
const char *m_tracepoint;
uint64_t m_begin;
};
struct SYSTRACE_EXPORT CSystraceAsyncEvent
{
public:
CSystraceAsyncEvent(const char *module, const char *tracepoint, const void *cookie)
: m_module(module)
, m_tracepoint(tracepoint)
, m_cookie(cookie)
{
systrace_async_begin(m_module, m_tracepoint, m_cookie);
}
~CSystraceAsyncEvent()
{
systrace_async_end(m_module, m_tracepoint, m_cookie);
}
private:
const char *m_module;
const char *m_tracepoint;
const void *m_cookie;
};
#endif // DISABLE_TRACE_CODE
#define COMBINE1(X,Y) X##Y // helper macros
#define COMBINE(X,Y) COMBINE1(X,Y)
// ### TRACE_STR_COPY
// ### TRACE_EVENT_COPY_XXX
// Records a pair of begin and end events called "name" for the current
// scope, with 0, 1 or 2 associated arguments. If the category is not
// enabled, then this does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_EVENT0(module, tracepoint) \
CSystraceEvent COMBINE(ev, __LINE__) (module, tracepoint);
// ### EVENT1, EVENT2
// ### TRACE_EVENT_INSTANT0?
#define TRACE_EVENT_BEGIN0(module, tracepoint) \
systrace_duration_begin(module, tracepoint);
#define TRACE_EVENT_END0(module, tracepoint) \
systrace_duration_end(module, tracepoint);
// ### BEGIN & END 1, 2
// ###:
// Pointers can be used for the ID parameter, and they will be mangled
// internally so that the same pointer on two different processes will not
// match.
#define TRACE_EVENT_ASYNC_BEGIN0(module, tracepoint, cookie) \
systrace_async_begin(module, tracepoint, cookie);
#define TRACE_EVENT_ASYNC_END0(module, tracepoint, cookie) \
systrace_async_end(module, tracepoint, cookie);
// ### 1 & 2
#define TRACE_COUNTER1(module, tracepoint, value) \
systrace_record_counter(module, tracepoint, value);
// ### TRACE_COUNTER2
#define TRACE_COUNTER_ID1(module, tracepoint, value, id) \
systrace_record_counter(module, tracepoint, value, id);
#endif // SYSTRACE_H
================================================
FILE: src/platform-plugin/CTraceMessages.h
================================================
/*
* Copyright (c) 2017 Crimson AS <info@crimson.no>
* Author: Robin Burchell <robin.burchell@crimson.no>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CTRACEMESSAGES_H
#define CTRACEMESSAGES_H
// Used by traced to clean up at startup time. Used client side to figure out
// what to allocate.
#define TRACED_MAX_SHM_CHUNKS 99999
// Used to mark a SHM chunk for some measure of safety.
#define TRACED_PROTOCOL_MAGIC 0xDEADBEEFBAAD
// Used to mark a SHM chunk as being written/read by a given version, for
// safety's sake. Bump this if the protocol changes.
#define TRACED_PROTOCOL_VERSION 256
enum class MessageType : uint8_t
{
NoMessage = 0,
RegisterStringMessage = 1,
BeginMessage = 2,
EndMessage = 3,
DurationMessage = 4,
AsyncBeginMessage = 5,
AsyncEndMessage = 6,
CounterMessage = 7,
CounterMessageWithId = 8
};
// ### consider splitting ChunkHeader to a ProcessHeaderMessage and
// ChunkHeaderMessage. pid & epoch should never change, so that's 16 bytes of
// each chunk wasted at present.
struct ChunkHeader
{
uint64_t magic;
uint16_t version;
uint64_t pid;
uint64_t tid;
// when the process under trace started. traced uses this against its own start
// time to calculate relative times.
uint64_t epoch;
};
struct BaseMessage
{
MessageType messageType;
};
struct RegisterStringMessage : public BaseMessage
{
uint64_t id;
uint8_t length;
char stringData; // and it follows on for length bytes
};
struct RegularMessage : public BaseMessage
{
uint64_t microseconds;
uint16_t categoryId;
uint64_t tracepointId;
};
struct BeginMessage : public RegularMessage
{
};
struct EndMessage : public RegularMessage
{
};
struct DurationMessage : public RegularMessage
{
uint64_t duration;
};
struct AsyncBeginMessage : public RegularMessage
{
uint64_t cookie;
};
struct AsyncEndMessage : public RegularMessage
{
uint64_t cookie;
};
struct CounterMessage : public RegularMessage
{
uint64_t value;
};
struct CounterMessageWithId : public CounterMessage
{
uint64_t id;
};
#endif // CTRACEMESSAGES_H
================================================
FILE: src/platform-plugin/gtk.json
================================================
{ "Keys": [ "gtk" ] }
================================================
FILE: src/platform-plugin/main.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include <qpa/qplatformintegrationplugin.h>
#include "qgtkintegration.h"
QT_BEGIN_NAMESPACE
class QGtkIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "gtk.json")
public:
QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE;
};
QPlatformIntegration *QGtkIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
if (!system.compare(QLatin1String("gtk"), Qt::CaseInsensitive))
return new QGtkIntegration(paramList);
return 0;
}
QT_END_NAMESPACE
#include "main.moc"
================================================
FILE: src/platform-plugin/platform-plugin.pro
================================================
TARGET = qgtk
!gtkplatform-release {
CONFIG -= release
CONFIG += debug
}
QT += core-private gui-private widgets
equals(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 8): {
QT += platformsupport-private
} else {
QT += fontdatabase_support_private glx_support_private egl_support_private service_support_private theme_support_private
}
equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 7): {
# qhighdpi has some bugs with this in at least 5.7.
DEFINES += QT_NO_FOREACH
}
SOURCES = main.cpp \
qgtkintegration.cpp \
qgtkbackingstore.cpp \
qgtkscreen.cpp \
qgtkwindow.cpp \
qgtkwindow_keyboard.cpp \
qgtkwindow_mouse.cpp \
qgtkwindow_touch.cpp \
qgtkwindow_render.cpp \
qgtkwindow_gesture.cpp \
qgtktheme.cpp \
qgtksystemtrayicon.cpp \
qgtkmenubar.cpp \
qgtkmenu.cpp \
qgtkmenuitem.cpp \
qgtkhelpers.cpp \
qgtk3dialoghelpers.cpp \
qgtkopenglcontext.cpp \
qgtkopenglcontext_wayland.cpp \
qgtkopenglcontext_x11.cpp \
qgtkcursor.cpp \
qgtkeventdispatcher.cpp \
qgtkclipboard.cpp \
qgtkservices.cpp
HEADERS = qgtkintegration.h \
qgtkbackingstore.h \
qgtkscreen.h \
qgtkwindow.h \
qgtktheme.h \
qgtksystemtrayicon.h \
qgtkmenubar.h \
qgtkmenu.h \
qgtkmenuitem.h \
qgtkhelpers.h \
qgtk3dialoghelpers.h \
qgtkopenglcontext.h \
qgtkcursor.h \
qgtkeventdispatcher.h \
qgtkclipboard.h \
qgtkservices.h
# CSystrace
DEFINES += DISABLE_TRACE_CODE
#LIBS += -lrt
#SOURCES += CSystrace.cpp
HEADERS += CSystrace.h \
CTraceMessages.h
QT += gtkextras
#INCLUDEPATH += ../gtkextras
CONFIG += qpa/genericunixfontdatabase
LIBS += -lX11-xcb -lxcb
CONFIG += link_pkgconfig
PKGCONFIG_PRIVATE += gdk-3.0 gtk+-3.0 libnotify
# for GL
PKGCONFIG_PRIVATE += egl
CONFIG += no_keywords
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QGtkIntegrationPlugin
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
load(qt_plugin)
================================================
FILE: src/platform-plugin/qgtk3dialoghelpers.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qgtk3dialoghelpers.h"
#include "qgtktheme.h"
#include "qgtkwindow.h"
#include <qeventloop.h>
#include <qwindow.h>
#include <qcolor.h>
#include <qdebug.h>
#include <qfont.h>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformfontdatabase.h>
#undef signals
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <pango/pango.h>
QT_BEGIN_NAMESPACE
static const char *standardButtonText(int button)
{
return QGtkTheme::defaultStandardButtonText(button).toUtf8();
}
QGtk3Dialog::QGtk3Dialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget)
{
g_signal_connect_swapped(G_OBJECT(gtkWidget), "response", G_CALLBACK(onResponse), this);
g_signal_connect(G_OBJECT(gtkWidget), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
}
QGtk3Dialog::~QGtk3Dialog()
{
gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
gtk_widget_destroy(gtkWidget);
}
GtkDialog *QGtk3Dialog::gtkDialog() const
{
return GTK_DIALOG(gtkWidget);
}
void QGtk3Dialog::exec()
{
if (modality() == Qt::ApplicationModal) {
// transient to the active window (best we can do really).
QWindow *focusWin = QGuiApplication::focusWindow();
if (focusWin) {
QGtkWindow *parentWin = static_cast<QGtkWindow*>(focusWin->handle());
gtk_window_set_transient_for(GTK_WINDOW(gtkWidget), GTK_WINDOW(parentWin->gtkWindow().get()));
}
// block input to the whole app, including other GTK dialogs
//
gtk_dialog_run(gtkDialog());
} else {
// block input to the window, allow input to other GTK dialogs
QEventLoop loop;
connect(this, SIGNAL(accept()), &loop, SLOT(quit()));
connect(this, SIGNAL(reject()), &loop, SLOT(quit()));
loop.exec();
}
}
bool QGtk3Dialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
{
if (parent) {
connect(parent, &QWindow::destroyed, this, &QGtk3Dialog::onParentWindowDestroyed,
Qt::UniqueConnection);
}
setParent(parent);
setFlags(flags);
setModality(modality);
gtk_widget_realize(gtkWidget); // creates X window
GdkWindow *gdkWindow = gtk_widget_get_window(gtkWidget);
if (parent) {
QGtkWindow *parentWin = static_cast<QGtkWindow*>(parent->handle());
gtk_window_set_transient_for(GTK_WINDOW(gtkWidget), GTK_WINDOW(parentWin->gtkWindow().get()));
}
if (modality != Qt::NonModal) {
gdk_window_set_modal_hint(gdkWindow, true);
QGuiApplicationPrivate::showModalWindow(this);
}
gtk_widget_show(gtkWidget);
gdk_window_focus(gdkWindow, GDK_CURRENT_TIME);
return true;
}
void QGtk3Dialog::hide()
{
QGuiApplicationPrivate::hideModalWindow(this);
gtk_widget_hide(gtkWidget);
}
void QGtk3Dialog::onResponse(QGtk3Dialog *dialog, int response)
{
if (response == GTK_RESPONSE_OK)
Q_EMIT dialog->accept();
else
Q_EMIT dialog->reject();
}
void QGtk3Dialog::onParentWindowDestroyed()
{
// The QGtk3*DialogHelper classes own this object. Make sure the parent doesn't delete it.
setParent(0);
}
QGtk3ColorDialogHelper::QGtk3ColorDialogHelper()
{
d.reset(new QGtk3Dialog(gtk_color_chooser_dialog_new("", 0)));
connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
g_signal_connect_swapped(d->gtkDialog(), "notify::rgba", G_CALLBACK(onColorChanged), this);
}
QGtk3ColorDialogHelper::~QGtk3ColorDialogHelper()
{
}
bool QGtk3ColorDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
{
applyOptions();
return d->show(flags, modality, parent);
}
void QGtk3ColorDialogHelper::exec()
{
d->exec();
}
void QGtk3ColorDialogHelper::hide()
{
d->hide();
}
void QGtk3ColorDialogHelper::setCurrentColor(const QColor &color)
{
GtkDialog *gtkDialog = d->gtkDialog();
if (color.alpha() < 255)
gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(gtkDialog), true);
GdkRGBA gdkColor;
gdkColor.red = color.redF();
gdkColor.green = color.greenF();
gdkColor.blue = color.blueF();
gdkColor.alpha = color.alphaF();
gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(gtkDialog), &gdkColor);
}
QColor QGtk3ColorDialogHelper::currentColor() const
{
GtkDialog *gtkDialog = d->gtkDialog();
GdkRGBA gdkColor;
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(gtkDialog), &gdkColor);
return QColor::fromRgbF(gdkColor.red, gdkColor.green, gdkColor.blue, gdkColor.alpha);
}
void QGtk3ColorDialogHelper::onAccepted()
{
Q_EMIT accept();
}
void QGtk3ColorDialogHelper::onColorChanged(QGtk3ColorDialogHelper *dialog)
{
Q_EMIT dialog->currentColorChanged(dialog->currentColor());
}
void QGtk3ColorDialogHelper::applyOptions()
{
GtkDialog *gtkDialog = d->gtkDialog();
gtk_window_set_title(GTK_WINDOW(gtkDialog), options()->windowTitle().toUtf8());
gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(gtkDialog), options()->testOption(QColorDialogOptions::ShowAlphaChannel));
}
QGtk3FileDialogHelper::QGtk3FileDialogHelper()
{
d.reset(new QGtk3Dialog(gtk_file_chooser_dialog_new("", 0,
GTK_FILE_CHOOSER_ACTION_OPEN,
standardButtonText(QPlatformDialogHelper::Cancel), GTK_RESPONSE_CANCEL,
standardButtonText(QPlatformDialogHelper::Ok), GTK_RESPONSE_OK,
NULL)));
connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
g_signal_connect(GTK_FILE_CHOOSER(d->gtkDialog()), "selection-changed", G_CALLBACK(onSelectionChanged), this);
g_signal_connect_swapped(GTK_FILE_CHOOSER(d->gtkDialog()), "current-folder-changed", G_CALLBACK(onCurrentFolderChanged), this);
g_signal_connect_swapped(GTK_FILE_CHOOSER(d->gtkDialog()), "notify::filter", G_CALLBACK(onFilterChanged), this);
}
QGtk3FileDialogHelper::~QGtk3FileDialogHelper()
{
}
bool QGtk3FileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
{
_dir.clear();
_selection.clear();
applyOptions();
return d->show(flags, modality, parent);
}
void QGtk3FileDialogHelper::exec()
{
d->exec();
}
void QGtk3FileDialogHelper::hide()
{
// After GtkFileChooserDialog has been hidden, gtk_file_chooser_get_current_folder()
// & gtk_file_chooser_get_filenames() will return bogus values -> cache the actual
// values before hiding the dialog
_dir = directory();
_selection = selectedFiles();
d->hide();
}
bool QGtk3FileDialogHelper::defaultNameFilterDisables() const
{
return false;
}
void QGtk3FileDialogHelper::setDirectory(const QUrl &directory)
{
GtkDialog *gtkDialog = d->gtkDialog();
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toLocalFile().toUtf8());
}
QUrl QGtk3FileDialogHelper::directory() const
{
// While GtkFileChooserDialog is hidden, gtk_file_chooser_get_current_folder()
// returns a bogus value -> return the cached value before hiding
if (!_dir.isEmpty())
return _dir;
QString ret;
GtkDialog *gtkDialog = d->gtkDialog();
gchar *folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(gtkDialog));
if (folder) {
ret = QString::fromUtf8(folder);
g_free(folder);
}
return QUrl::fromLocalFile(ret);
}
void QGtk3FileDialogHelper::selectFile(const QUrl &filename)
{
GtkDialog *gtkDialog = d->gtkDialog();
if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
QFileInfo fi(filename.toLocalFile());
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), fi.path().toUtf8());
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(gtkDialog), fi.fileName().toUtf8());
} else {
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toLocalFile().toUtf8());
}
}
QList<QUrl> QGtk3FileDialogHelper::selectedFiles() const
{
// While GtkFileChooserDialog is hidden, gtk_file_chooser_get_filenames()
// returns a bogus value -> return the cached value before hiding
if (!_selection.isEmpty())
return _selection;
QList<QUrl> selection;
GtkDialog *gtkDialog = d->gtkDialog();
GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(gtkDialog));
for (GSList *it = filenames; it; it = it->next)
selection += QUrl::fromLocalFile(QString::fromUtf8((const char*)it->data));
g_slist_free(filenames);
return selection;
}
void QGtk3FileDialogHelper::setFilter()
{
applyOptions();
}
void QGtk3FileDialogHelper::selectNameFilter(const QString &filter)
{
GtkFileFilter *gtkFilter = _filters.value(filter);
if (gtkFilter) {
GtkDialog *gtkDialog = d->gtkDialog();
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
}
}
QString QGtk3FileDialogHelper::selectedNameFilter() const
{
GtkDialog *gtkDialog = d->gtkDialog();
GtkFileFilter *gtkFilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(gtkDialog));
return _filterNames.value(gtkFilter);
}
void QGtk3FileDialogHelper::onAccepted()
{
Q_EMIT accept();
}
void QGtk3FileDialogHelper::onSelectionChanged(GtkDialog *gtkDialog, QGtk3FileDialogHelper *helper)
{
QString selection;
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(gtkDialog));
if (filename) {
selection = QString::fromUtf8(filename);
g_free(filename);
}
Q_EMIT helper->currentChanged(QUrl::fromLocalFile(selection));
}
void QGtk3FileDialogHelper::onCurrentFolderChanged(QGtk3FileDialogHelper *dialog)
{
Q_EMIT dialog->directoryEntered(dialog->directory());
}
void QGtk3FileDialogHelper::onFilterChanged(QGtk3FileDialogHelper *dialog)
{
Q_EMIT dialog->filterSelected(dialog->selectedNameFilter());
}
static GtkFileChooserAction gtkFileChooserAction(const QSharedPointer<QFileDialogOptions> &options)
{
switch (options->fileMode()) {
case QFileDialogOptions::AnyFile:
case QFileDialogOptions::ExistingFile:
case QFileDialogOptions::ExistingFiles:
if (options->acceptMode() == QFileDialogOptions::AcceptOpen)
return GTK_FILE_CHOOSER_ACTION_OPEN;
else
return GTK_FILE_CHOOSER_ACTION_SAVE;
case QFileDialogOptions::Directory:
case QFileDialogOptions::DirectoryOnly:
default:
if (options->acceptMode() == QFileDialogOptions::AcceptOpen)
return GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
else
return GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
}
}
void QGtk3FileDialogHelper::applyOptions()
{
GtkDialog *gtkDialog = d->gtkDialog();
const QSharedPointer<QFileDialogOptions> &opts = options();
gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(gtkDialog), true);
const GtkFileChooserAction action = gtkFileChooserAction(opts);
gtk_file_chooser_set_action(GTK_FILE_CHOOSER(gtkDialog), action);
const bool selectMultiple = opts->fileMode() == QFileDialogOptions::ExistingFiles;
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(gtkDialog), selectMultiple);
const bool confirmOverwrite = !opts->testOption(QFileDialogOptions::DontConfirmOverwrite);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(gtkDialog), confirmOverwrite);
const QStringList nameFilters = opts->nameFilters();
if (!nameFilters.isEmpty())
setNameFilters(nameFilters);
if (opts->initialDirectory().isLocalFile())
setDirectory(opts->initialDirectory());
for (const QUrl &filename : opts->initiallySelectedFiles())
selectFile(filename);
const QString initialNameFilter = opts->initiallySelectedNameFilter();
if (!initialNameFilter.isEmpty())
selectNameFilter(initialNameFilter);
GtkWidget *acceptButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_OK);
if (acceptButton) {
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
gtk_button_set_label(GTK_BUTTON(acceptButton), opts->labelText(QFileDialogOptions::Accept).toUtf8());
else if (opts->acceptMode() == QFileDialogOptions::AcceptOpen)
gtk_button_set_label(GTK_BUTTON(acceptButton), standardButtonText(QPlatformDialogHelper::Open));
else
gtk_button_set_label(GTK_BUTTON(acceptButton), standardButtonText(QPlatformDialogHelper::Save));
}
GtkWidget *rejectButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_CANCEL);
if (rejectButton) {
if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject))
gtk_button_set_label(GTK_BUTTON(rejectButton), opts->labelText(QFileDialogOptions::Reject).toUtf8());
else
gtk_button_set_label(GTK_BUTTON(rejectButton), standardButtonText(QPlatformDialogHelper::Cancel));
}
}
void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters)
{
GtkDialog *gtkDialog = d->gtkDialog();
for (GtkFileFilter *filter : _filters)
gtk_file_chooser_remove_filter(GTK_FILE_CHOOSER(gtkDialog), filter);
_filters.clear();
_filterNames.clear();
for (const QString &filter : filters) {
GtkFileFilter *gtkFilter = gtk_file_filter_new();
const QString name = filter.left(filter.indexOf(QLatin1Char('(')));
const QStringList extensions = cleanFilterList(filter);
gtk_file_filter_set_name(gtkFilter, name.isEmpty() ? extensions.join(QStringLiteral(", ")).toUtf8() : name.toUtf8());
for (const QString &ext : extensions)
gtk_file_filter_add_pattern(gtkFilter, ext.toUtf8());
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
_filters.insert(filter, gtkFilter);
_filterNames.insert(gtkFilter, filter);
}
}
QGtk3FontDialogHelper::QGtk3FontDialogHelper()
{
d.reset(new QGtk3Dialog(gtk_font_chooser_dialog_new("", 0)));
connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
g_signal_connect_swapped(d->gtkDialog(), "notify::font", G_CALLBACK(onFontChanged), this);
}
QGtk3FontDialogHelper::~QGtk3FontDialogHelper()
{
}
bool QGtk3FontDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
{
applyOptions();
return d->show(flags, modality, parent);
}
void QGtk3FontDialogHelper::exec()
{
d->exec();
}
void QGtk3FontDialogHelper::hide()
{
d->hide();
}
static QString qt_fontToString(const QFont &font)
{
PangoFontDescription *desc = pango_font_description_new();
pango_font_description_set_size(desc, (font.pointSizeF() > 0.0 ? font.pointSizeF() : QFontInfo(font).pointSizeF()) * PANGO_SCALE);
pango_font_description_set_family(desc, QFontInfo(font).family().toUtf8());
int weight = font.weight();
if (weight >= QFont::Black)
pango_font_description_set_weight(desc, PANGO_WEIGHT_HEAVY);
else if (weight >= QFont::ExtraBold)
pango_font_description_set_weight(desc, PANGO_WEIGHT_ULTRABOLD);
else if (weight >= QFont::Bold)
pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
else if (weight >= QFont::DemiBold)
pango_font_description_set_weight(desc, PANGO_WEIGHT_SEMIBOLD);
else if (weight >= QFont::Medium)
pango_font_description_set_weight(desc, PANGO_WEIGHT_MEDIUM);
else if (weight >= QFont::Normal)
pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL);
else if (weight >= QFont::Light)
pango_font_description_set_weight(desc, PANGO_WEIGHT_LIGHT);
else if (weight >= QFont::ExtraLight)
pango_font_description_set_weight(desc, PANGO_WEIGHT_ULTRALIGHT);
else
pango_font_description_set_weight(desc, PANGO_WEIGHT_THIN);
int style = font.style();
if (style == QFont::StyleItalic)
pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
else if (style == QFont::StyleOblique)
pango_font_description_set_style(desc, PANGO_STYLE_OBLIQUE);
else
pango_font_description_set_style(desc, PANGO_STYLE_NORMAL);
char *str = pango_font_description_to_string(desc);
QString name = QString::fromUtf8(str);
pango_font_description_free(desc);
g_free(str);
return name;
}
static QFont qt_fontFromString(const QString &name)
{
QFont font;
PangoFontDescription *desc = pango_font_description_from_string(name.toUtf8());
font.setPointSizeF(static_cast<float>(pango_font_description_get_size(desc)) / PANGO_SCALE);
QString family = QString::fromUtf8(pango_font_description_get_family(desc));
if (!family.isEmpty())
font.setFamily(family);
const int weight = pango_font_description_get_weight(desc);
font.setWeight(QPlatformFontDatabase::weightFromInteger(weight));
PangoStyle style = pango_font_description_get_style(desc);
if (style == PANGO_STYLE_ITALIC)
font.setStyle(QFont::StyleItalic);
else if (style == PANGO_STYLE_OBLIQUE)
font.setStyle(QFont::StyleOblique);
else
font.setStyle(QFont::StyleNormal);
pango_font_description_free(desc);
return font;
}
void QGtk3FontDialogHelper::setCurrentFont(const QFont &font)
{
GtkFontChooser *gtkDialog = GTK_FONT_CHOOSER(d->gtkDialog());
gtk_font_chooser_set_font(gtkDialog, qt_fontToString(font).toUtf8());
}
QFont QGtk3FontDialogHelper::currentFont() const
{
GtkFontChooser *gtkDialog = GTK_FONT_CHOOSER(d->gtkDialog());
gchar *name = gtk_font_chooser_get_font(gtkDialog);
QFont font = qt_fontFromString(QString::fromUtf8(name));
g_free(name);
return font;
}
void QGtk3FontDialogHelper::onAccepted()
{
Q_EMIT accept();
}
void QGtk3FontDialogHelper::onFontChanged(QGtk3FontDialogHelper *dialog)
{
Q_EMIT dialog->currentFontChanged(dialog->currentFont());
}
void QGtk3FontDialogHelper::applyOptions()
{
GtkDialog *gtkDialog = d->gtkDialog();
const QSharedPointer<QFontDialogOptions> &opts = options();
gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
}
QT_END_NAMESPACE
================================================
FILE: src/platform-plugin/qgtk3dialoghelpers.h
================================================
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGTK3DIALOGHELPERS_H
#define QGTK3DIALOGHELPERS_H
#include <QtCore/qhash.h>
#include <QtCore/qlist.h>
#include <QtCore/qurl.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qstring.h>
#include <QtGui/qwindow.h>
#include <qpa/qplatformdialoghelper.h>
#include <gtk/gtk.h>
QT_BEGIN_NAMESPACE
class QColor;
class QGtk3Dialog : public QWindow
{
Q_OBJECT
public:
QGtk3Dialog(GtkWidget *gtkWidget);
~QGtk3Dialog();
GtkDialog *gtkDialog() const;
void exec();
bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
void hide();
Q_SIGNALS:
void accept();
void reject();
protected:
static void onResponse(QGtk3Dialog *dialog, int response);
private Q_SLOTS:
void onParentWindowDestroyed();
private:
GtkWidget *gtkWidget;
};
class QGtk3ColorDialogHelper : public QPlatformColorDialogHelper
{
Q_OBJECT
public:
QGtk3ColorDialogHelper();
~QGtk3ColorDialogHelper();
bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) Q_DECL_OVERRIDE;
void exec() Q_DECL_OVERRIDE;
void hide() Q_DECL_OVERRIDE;
void setCurrentColor(const QColor &color) Q_DECL_OVERRIDE;
QColor currentColor() const Q_DECL_OVERRIDE;
private Q_SLOTS:
void onAccepted();
private:
static void onColorChanged(QGtk3ColorDialogHelper *helper);
void applyOptions();
QScopedPointer<QGtk3Dialog> d;
};
class QGtk3FileDialogHelper : public QPlatformFileDialogHelper
{
Q_OBJECT
public:
QGtk3FileDialogHelper();
~QGtk3FileDialogHelper();
bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) Q_DECL_OVERRIDE;
void exec() Q_DECL_OVERRIDE;
void hide() Q_DECL_OVERRIDE;
bool defaultNameFilterDisables() const Q_DECL_OVERRIDE;
void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE;
QUrl directory() const Q_DECL_OVERRIDE;
void selectFile(const QUrl &filename) Q_DECL_OVERRIDE;
QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
void setFilter() Q_DECL_OVERRIDE;
void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE;
QString selectedNameFilter() const Q_DECL_OVERRIDE;
private Q_SLOTS:
void onAccepted();
private:
static void onSelectionChanged(GtkDialog *dialog, QGtk3FileDialogHelper *helper);
static void onCurrentFolderChanged(QGtk3FileDialogHelper *helper);
static void onFilterChanged(QGtk3FileDialogHelper *helper);
void applyOptions();
void setNameFilters(const QStringList &filters);
QUrl _dir;
QList<QUrl> _selection;
QHash<QString, GtkFileFilter*> _filters;
QHash<GtkFileFilter*, QString> _filterNames;
QScopedPointer<QGtk3Dialog> d;
};
class QGtk3FontDialogHelper : public QPlatformFontDialogHelper
{
Q_OBJECT
public:
QGtk3FontDialogHelper();
~QGtk3FontDialogHelper();
bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) Q_DECL_OVERRIDE;
void exec() Q_DECL_OVERRIDE;
void hide() Q_DECL_OVERRIDE;
void setCurrentFont(const QFont &font) Q_DECL_OVERRIDE;
QFont currentFont() const Q_DECL_OVERRIDE;
private Q_SLOTS:
void onAccepted();
private:
static void onFontChanged(QGtk3FontDialogHelper *helper);
void applyOptions();
QScopedPointer<QGtk3Dialog> d;
};
QT_END_NAMESPACE
#endif // QGTK3DIALOGHELPERS_H
================================================
FILE: src/platform-plugin/qgtkbackingstore.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkbackingstore.h"
#include "qgtkintegration.h"
#include "qgtkwindow.h"
#include "qscreen.h"
#include <QtCore/qdebug.h>
#include <qpa/qplatformscreen.h>
#include <private/qguiapplication_p.h>
#include "CSystrace.h"
// we have no_keywords, but this header uses one.
#define foreach Q_FOREACH
#include <private/qhighdpiscaling_p.h>
#undef foreach
QGtkBackingStore::QGtkBackingStore(QWindow *window)
: QPlatformBackingStore(window)
, m_paintImage(nullptr)
{
}
QGtkBackingStore::~QGtkBackingStore()
{
}
QPaintDevice *QGtkBackingStore::paintDevice()
{
return m_paintImage;
}
QImage QGtkBackingStore::toImage() const
{
return static_cast<QGtkWindow*>(window()->handle())->currentFrameImage();
}
void QGtkBackingStore::beginPaint(const QRegion ®ion)
{
TRACE_EVENT_ASYNC_BEGIN0("gfx", "QGtkBackingStore::paint", this);
Q_UNUSED(region);
if (!m_paintImage)
m_paintImage = static_cast<QGtkWindow*>(window()->handle())->beginUpdateFrame("beginPaint");
}
void QGtkBackingStore::endPaint()
{
Q_ASSERT(m_paintImage);
static_cast<QGtkWindow*>(window()->handle())->endUpdateFrame("endPaint");
m_paintImage = nullptr;
TRACE_EVENT_ASYNC_END0("gfx", "QGtkBackingStore::paint", this);
}
void QGtkBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
#if QT_VERSION >= QT_VERSION_CHECK(5,10,0)
QPlatformTextureList *textures, bool translucentBackground)
#else
QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground)
#endif
{
TRACE_EVENT0("gfx", "QGtkBackingStore::composeAndFlush");
#if QT_VERSION >= QT_VERSION_CHECK(5,10,0)
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
#else
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, context, translucentBackground);
#endif
}
void QGtkBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
{
TRACE_EVENT0("gfx", "QGtkBackingStore::flush");
static_cast<QGtkWindow*>(window->handle())->invalidateRegion(region.translated(offset));
}
void QGtkBackingStore::resize(const QSize &size, const QRegion &)
{
TRACE_EVENT0("gfx", "QGtkBackingStore::resize");
QGtkWindow *qgwin = static_cast<QGtkWindow*>(window()->handle());
QImage *image = qgwin->beginUpdateFrame("resize");
qreal dpr = window()->devicePixelRatio() / QHighDpiScaling::factor(window());
QSize realSize = size * dpr;
QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
if (image->size() != realSize) {
*image = QImage(realSize, format);
image->setDevicePixelRatio(dpr);
}
qgwin->endUpdateFrame("resize");
}
bool QGtkBackingStore::scroll(const QRegion ®ion, int dx, int dy)
{
// ### temporarily disabled
//
// this helps to accelerate widget scrolling by copying a region of the
// backing store rather than re-rendering them from scratch. however, it's
// currently not working quite right because of bad event ordering.
//
// the way this is supposed to work:
// QWidget::scroll()
// -> backingStore->scroll()
// -> QPABackingStore->scroll()
// -> QWidget::update()
// QPABackingStore::beginPaint
// QWidget::paintEvent
// ...
// gtk_render_stuff
//
// But events are arriving out of order at the moment (perhaps due to event
// dispatcher? perhaps due to something else?) and as a result we get:
// QWidget::scroll
// -> backingStore->scroll
// -> QPABackingStore->scroll
// -> QWidget::update
// gtk_render_stuff <--- OOPS! didn't render the area that we couldn't // scroll yet!
// QPABackingStore::beginPaint
// QWidget::paintEvent
// gtk_render_stuff <- eventually consistent, but looks bad.
return false;
TRACE_EVENT0("gfx", "QGtkBackingStore::scroll");
extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
QGtkWindow *qgwin = static_cast<QGtkWindow*>(window()->handle());
const qreal dpr = qgwin->devicePixelRatio();
const QPoint delta = QPoint(dx * dpr, dy * dpr);
QImage *image = qgwin->beginUpdateFrame("scroll");
for (const QRect &rect : region.rects()) {
qt_scrollRectInImage(*image, QRect(rect.topLeft() * dpr, rect.size() * dpr), delta);
}
qgwin->endUpdateFrame("scroll");
QRegion uregion = region.united(region.translated(delta));
qgwin->invalidateRegion(uregion);
return true;
}
================================================
FILE: src/platform-plugin/qgtkbackingstore.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QBACKINGSTORE_GTK_H
#define QBACKINGSTORE_GTK_H
#include <qpa/qplatformbackingstore.h>
#include <qpa/qplatformwindow.h>
#include <QtGui/QImage>
QT_BEGIN_NAMESPACE
class QGtkBackingStore : public QPlatformBackingStore
{
public:
QGtkBackingStore(QWindow *window);
~QGtkBackingStore();
QPaintDevice *paintDevice() override;
void beginPaint(const QRegion ®ion) override;
void endPaint() override;
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
#if QT_VERSION >= QT_VERSION_CHECK(5,10,0)
QPlatformTextureList *textures, bool translucentBackground) override;
#else
QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground) override;
#endif
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override;
void resize(const QSize &size, const QRegion &staticContents) override;
QImage toImage() const override;
bool scroll(const QRegion ®ion, int dx, int dy) override;
private:
QImage *m_paintImage;
};
QT_END_NAMESPACE
#endif
================================================
FILE: src/platform-plugin/qgtkclipboard.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkclipboard.h"
#include "qgtkhelpers.h"
#include <gtk/gtk.h>
#include <QtCore/qloggingcategory.h>
Q_LOGGING_CATEGORY(lcClipboard, "qt.qpa.gtk.clipboard");
enum TargetTypes {
TargetTypeText = 1,
TargetTypeImage = 2
};
QGtkClipboard::QGtkClipboard(QObject *parent)
: QObject(parent)
, m_clipData(QClipboard::Clipboard)
, m_selData(QClipboard::Selection)
{
QObject::connect(&m_clipData, &QGtkClipboardData::changed, this, [=](){ emitChanged(QClipboard::Clipboard); qCDebug(lcClipboard) << "Clipboard changed"; });
QObject::connect(&m_selData, &QGtkClipboardData::changed, this, [=](){ emitChanged(QClipboard::Selection); qCDebug(lcClipboard) << "Selection changed"; });
}
QGtkClipboard::~QGtkClipboard()
{
}
QGtkClipboardData *QGtkClipboard::mimeForMode(QClipboard::Mode mode) const
{
switch (mode) {
case QClipboard::Clipboard:
return const_cast<QGtkClipboardData*>(&m_clipData);
case QClipboard::Selection:
return const_cast<QGtkClipboardData*>(&m_selData);
default:
Q_UNREACHABLE();
}
}
QMimeData *QGtkClipboard::mimeData(QClipboard::Mode mode)
{
if (!supportsMode(mode))
return 0;
QGtkClipboardData *m = mimeForMode(mode);
return m->mimeData();
}
void QGtkClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
if (!supportsMode(mode))
return;
QGtkClipboardData *m = mimeForMode(mode);
m->setData(data);
qCDebug(lcClipboard) << "setMimeData changed to " << data;
emitChanged(mode);
}
bool QGtkClipboard::supportsMode(QClipboard::Mode mode) const
{
switch (mode) {
case QClipboard::Clipboard:
case QClipboard::Selection:
return true;
default:
return false;
}
}
bool QGtkClipboard::ownsMode(QClipboard::Mode mode) const
{
if (!supportsMode(mode))
return false;
QGtkClipboardData *m = mimeForMode(mode);
return m->ownsMode();
}
QGtkClipboardData::QGtkClipboardData(QClipboard::Mode clipboardMode)
: m_mode(clipboardMode)
{
switch (clipboardMode) {
case QClipboard::Clipboard:
m_clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", TRUE));
break;
case QClipboard::Selection:
m_clipboard = gtk_clipboard_get(gdk_atom_intern("PRIMARY", TRUE));
break;
default:
Q_UNREACHABLE();
}
}
QGtkClipboardData::~QGtkClipboardData()
{
gtk_clipboard_set_can_store(m_clipboard, NULL, 0);
delete m_localData;
delete m_systemData;
}
bool QGtkClipboardData::ownsMode() const
{
return gtk_clipboard_get_owner(m_clipboard) != NULL;
}
static void getFun(GtkClipboard *, GtkSelectionData *selection_data, guint info, gpointer gtkClipboardData)
{
QGtkClipboardData *gdata = static_cast<QGtkClipboardData*>(gtkClipboardData);
gdata->onLocalGet(selection_data, info);
}
static void clearFun(GtkClipboard*, gpointer gtkClipboardData)
{
QGtkClipboardData *gdata = static_cast<QGtkClipboardData*>(gtkClipboardData);
gdata->onLocalClear();
}
void QGtkClipboardData::onLocalClear()
{
qCDebug(lcClipboard) << "Clear func" << m_mode;
delete m_localData;
m_localData = nullptr;
}
// Request for the data from our set clipboard to give to a remote client
void QGtkClipboardData::onLocalGet(GtkSelectionData *selection_data, guint info)
{
qCDebug(lcClipboard) << "Local get for " << m_localData;
if (!m_localData) {
return;
}
if (info == TargetTypeText) {
gtk_selection_data_set_text(selection_data, m_localData->text().toUtf8().constData(), -1);
} else if (info == TargetTypeImage) {
QImage imageData = qvariant_cast<QImage>(m_localData->imageData());
gtk_selection_data_set_pixbuf(selection_data, qt_pixmapToPixbuf(QPixmap::fromImage(imageData)).get());
}
}
// Set our local clipboard, and inform the system about it
void QGtkClipboardData::setData(QMimeData *data)
{
qCDebug(lcClipboard) << "Setting mime data " << data << m_mode << (data ? data->formats() : QStringList());
if (!data || data->formats().isEmpty()) {
qCDebug(lcClipboard) << "Clearing mime data" << data;
gtk_clipboard_clear(m_clipboard);
return;
}
GtkTargetList *targetList = gtk_target_list_new(nullptr, 0);
if (data->hasText()) {
gtk_target_list_add_text_targets(targetList, TargetTypeText);
}
if (data->hasImage()) {
QImage imageData = qvariant_cast<QImage>(data->imageData());
gtk_target_list_add_image_targets(targetList, TargetTypeImage, TRUE);
}
// ### rich text? html? what else should we handle...
int targetCount = 0;
GtkTargetEntry *table = gtk_target_table_new_from_list(targetList, &targetCount);
if (targetCount > 0 && table) {
if (gtk_clipboard_set_with_data(
m_clipboard,
table,
targetCount,
getFun,
clearFun,
this
) == TRUE) {
gtk_clipboard_set_can_store(m_clipboard, nullptr, 0);
} else {
qCWarning(lcClipboard) << "Store FAILED";
}
} else {
qCWarning(lcClipboard) << "No targets";
}
if (table) {
gtk_target_table_free(table, targetCount);
}
gtk_target_list_unref(targetList);
m_localData = data;
}
QMimeData *QGtkClipboardData::mimeData() const
{
qCDebug(lcClipboard) << "Getting data" << m_mode << m_localData << m_systemData;
if (ownsMode()) {
qCDebug(lcClipboard) << "Getting local data";
return m_localData;
}
if (m_systemData) {
qCDebug(lcClipboard) << "Clearing system data";
m_systemData->clear();
} else {
qCDebug(lcClipboard) << "Creating system data";
const_cast<QGtkClipboardData*>(this)->m_systemData = new QMimeData();
}
GtkSelectionData *gsel = gtk_clipboard_wait_for_contents(m_clipboard, gdk_atom_intern("TARGETS", TRUE));
if (gsel) {
if (gtk_selection_data_targets_include_image(gsel, FALSE)) {
qCDebug(lcClipboard) << "Reading image data";
QGtkRefPtr<GdkPixbuf> img = gtk_clipboard_wait_for_image(m_clipboard);
if (img.get()) {
QImage data = qt_pixbufToImage(img);
if (!data.isNull()) {
m_systemData->setImageData(QVariant::fromValue(data));
qCDebug(lcClipboard) << "Read image " << data;
}
}
}
if (gtk_selection_data_targets_include_text(gsel)) {
qCDebug(lcClipboard) << "Reading text data";
const gchar *rdata = gtk_clipboard_wait_for_text(m_clipboard);
if (rdata) {
QString data = QString::fromUtf8((rdata), strlen(rdata));
g_free((void*)rdata);
if (!data.isNull()) {
m_systemData->setText(data);
qCDebug(lcClipboard) << "Read text " << data;
}
}
}
gtk_selection_data_free(gsel);
}
return m_systemData;
}
================================================
FILE: src/platform-plugin/qgtkclipboard.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QGTKCLIPBOARD_H
#define QGTKCLIPBOARD_H
#include <qpa/qplatformclipboard.h>
#include <private/qdnd_p.h>
#include <gtk/gtk.h>
QT_BEGIN_NAMESPACE
class QGtkClipboardData : public QObject
{
Q_OBJECT
public:
QGtkClipboardData(QClipboard::Mode clipboardMode);
~QGtkClipboardData();
void setData(QMimeData *data);
QMimeData *mimeData() const;
bool ownsMode() const;
void onLocalClear();
void onLocalGet(GtkSelectionData *selection_data, guint info);
Q_SIGNALS:
void changed();
private:
QStringList formats() const;
GtkClipboard *m_clipboard = nullptr;
QMimeData *m_localData = nullptr; // app-local
QMimeData *m_systemData = nullptr; // system-global, remote
QClipboard::Mode m_mode;
};
class QGtkClipboard : public QPlatformClipboard, QObject
{
public:
QGtkClipboard(QObject *parent = 0);
~QGtkClipboard();
QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
bool supportsMode(QClipboard::Mode mode) const override;
bool ownsMode(QClipboard::Mode mode) const override;
private:
QGtkClipboardData m_clipData;
QGtkClipboardData m_selData;
QGtkClipboardData *mimeForMode(QClipboard::Mode mode) const;
};
QT_END_NAMESPACE
#endif // QGTKCLIPBOARD_H
================================================
FILE: src/platform-plugin/qgtkcursor.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkcursor.h"
#include "qgtkhelpers.h"
#include "qgtkwindow.h"
QGtkCursor::QGtkCursor()
: QPlatformCursor()
{
}
void QGtkCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Qt::CursorShape shape = Qt::BlankCursor;
if (windowCursor) {
shape = windowCursor->shape();
}
QByteArray gtkCursorName;
bool bitmapCursor = false;
switch (shape) {
case Qt::BlankCursor:
case Qt::CustomCursor:
case Qt::ArrowCursor:
gtkCursorName = "default";
break;
case Qt::UpArrowCursor:
gtkCursorName = "default";
break;
case Qt::CrossCursor:
gtkCursorName = "crosshair";
break;
case Qt::WaitCursor:
gtkCursorName = "wait";
break;
case Qt::IBeamCursor:
gtkCursorName = "text";
break;
case Qt::SizeVerCursor:
gtkCursorName = "row-resize";
break;
case Qt::SizeHorCursor:
gtkCursorName = "col-resize";
break;
case Qt::SizeBDiagCursor:
gtkCursorName = "nesw-resize";
break;
case Qt::SizeFDiagCursor:
gtkCursorName = "nwse-resize";
break;
case Qt::SizeAllCursor:
gtkCursorName = "all-scroll";
break;
case Qt::SplitVCursor:
gtkCursorName = "ns-resize";
break;
case Qt::SplitHCursor:
gtkCursorName = "ew-resize";
break;
case Qt::PointingHandCursor:
gtkCursorName = "pointer";
break;
case Qt::ForbiddenCursor:
gtkCursorName = "not-allowed";
break;
case Qt::OpenHandCursor:
gtkCursorName = "grab";
break;
case Qt::ClosedHandCursor:
gtkCursorName = "grabbing";
break;
case Qt::WhatsThisCursor:
gtkCursorName = "help";
break;
case Qt::BusyCursor:
gtkCursorName = "progress";
break;
case Qt::DragMoveCursor:
gtkCursorName = "grabbing";
break;
case Qt::DragCopyCursor:
gtkCursorName = "copy";
break;
case Qt::DragLinkCursor:
gtkCursorName = "alias";
break;
case Qt::BitmapCursor:
bitmapCursor = true;
break;
}
QGtkRefPtr<GdkCursor> c;
if (bitmapCursor == false) {
c = gdk_cursor_new_from_name(gdk_display_get_default(), gtkCursorName.constData());
} else {
c = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), qt_pixmapToPixbuf(windowCursor->pixmap()).get(), 0, 0);
}
QGtkWindow *pw = static_cast<QGtkWindow*>(window->handle());
// ### are we called before being realized, sometimes? why does this happen?
if (gtk_widget_get_window(pw->gtkWindow().get()) != nullptr) {
gdk_window_set_cursor(gtk_widget_get_window(pw->gtkWindow().get()), c.get());
}
}
QPoint QGtkCursor::pos() const
{
// not supported.
return m_pos;
}
void QGtkCursor::setPos(const QPoint &pos)
{
// not supported.
m_pos = pos;
}
================================================
FILE: src/platform-plugin/qgtkcursor.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QGTKCURSOR_H
#define QGTKCURSOR_H
#include <qpa/qplatformcursor.h>
#include <gdk/gdk.h>
QT_BEGIN_NAMESPACE
class QGtkCursor;
class QGtkCursor : public QPlatformCursor
{
public:
QGtkCursor();
void changeCursor(QCursor *windowCursor, QWindow *window) override;
QPoint pos() const override;
void setPos(const QPoint &pos) override;
private:
QPoint m_pos;
};
QT_END_NAMESPACE
#endif // QGTKCURSOR_H
================================================
FILE: src/platform-plugin/qgtkeventdispatcher.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qgtkeventdispatcher.h"
#include <private/qeventdispatcher_unix_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <private/qthread_p.h>
#include "qcoreapplication.h"
#include "qsocketnotifier.h"
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <glib.h>
#include "CSystrace.h"
QT_BEGIN_NAMESPACE
struct GPollFDWithQSocketNotifier
{
GPollFD pollfd;
QSocketNotifier *socketNotifier;
};
struct GSocketNotifierSource
{
GSource source;
QList<GPollFDWithQSocketNotifier *> pollfds;
};
static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
{
if (timeout)
*timeout = -1;
return false;
}
static gboolean socketNotifierSourceCheck(GSource *source)
{
GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
bool pending = false;
for (int i = 0; !pending && i < src->pollfds.count(); ++i) {
GPollFDWithQSocketNotifier *p = src->pollfds.at(i);
if (p->pollfd.revents & G_IO_NVAL) {
// disable the invalid socket notifier
static const char *t[] = { "Read", "Write", "Exception" };
qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...",
p->pollfd.fd, t[int(p->socketNotifier->type())]);
// ### note, modifies src->pollfds!
p->socketNotifier->setEnabled(false);
}
pending = ((p->pollfd.revents & p->pollfd.events) != 0);
}
return pending;
}
static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer)
{
QEvent event(QEvent::SockAct);
GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
for (int i = 0; i < src->pollfds.count(); ++i) {
GPollFDWithQSocketNotifier *p = src->pollfds.at(i);
if ((p->pollfd.revents & p->pollfd.events) != 0) {
TRACE_EVENT0("gfx", "QGtkEventDispatcher::socketNotifierSourceDispatch");
QCoreApplication::sendEvent(p->socketNotifier, &event);
}
}
return true; // ??? don't remove, right?
}
static GSourceFuncs socketNotifierSourceFuncs = {
socketNotifierSourcePrepare,
socketNotifierSourceCheck,
socketNotifierSourceDispatch,
NULL,
NULL,
NULL
};
struct GTimerSource
{
GSource source;
QTimerInfoList timerList;
QEventLoop::ProcessEventsFlags processEventsFlags;
bool runWithIdlePriority;
};
static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
{
timespec tv = { 0l, 0l };
if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv))
*timeout = (tv.tv_sec * 1000) + ((tv.tv_nsec + 999999) / 1000 / 1000);
else
*timeout = -1;
return (*timeout == 0);
}
static gboolean timerSourceCheckHelper(GTimerSource *src)
{
if (src->timerList.isEmpty()
|| (src->processEventsFlags & QEventLoop::X11ExcludeTimers))
return false;
if (src->timerList.updateCurrentTime() < src->timerList.constFirst()->timeout)
return false;
return true;
}
static gboolean timerSourcePrepare(GSource *source, gint *timeout)
{
gint dummy;
if (!timeout)
timeout = &dummy;
GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
if (src->runWithIdlePriority) {
if (timeout)
*timeout = -1;
return false;
}
return timerSourcePrepareHelper(src, timeout);
}
static gboolean timerSourceCheck(GSource *source)
{
GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
if (src->runWithIdlePriority)
return false;
return timerSourceCheckHelper(src);
}
static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
{
GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source);
if (timerSource->processEventsFlags & QEventLoop::X11ExcludeTimers)
return true;
timerSource->runWithIdlePriority = true;
(void) timerSource->timerList.activateTimers();
return true; // ??? don't remove, right again?
}
static GSourceFuncs timerSourceFuncs = {
timerSourcePrepare,
timerSourceCheck,
timerSourceDispatch,
NULL,
NULL,
NULL
};
struct GIdleTimerSource
{
GSource source;
GTimerSource *timerSource;
};
static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
{
GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
GTimerSource *timerSource = idleTimerSource->timerSource;
if (!timerSource->runWithIdlePriority) {
// Yield to the normal priority timer source
if (timeout)
*timeout = -1;
return false;
}
return timerSourcePrepareHelper(timerSource, timeout);
}
static gboolean idleTimerSourceCheck(GSource *source)
{
GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
GTimerSource *timerSource = idleTimerSource->timerSource;
if (!timerSource->runWithIdlePriority) {
// Yield to the normal priority timer source
return false;
}
return timerSourceCheckHelper(timerSource);
}
static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
{
GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource;
(void) timerSourceDispatch(&timerSource->source, 0, 0);
return true;
}
static GSourceFuncs idleTimerSourceFuncs = {
idleTimerSourcePrepare,
idleTimerSourceCheck,
idleTimerSourceDispatch,
NULL,
NULL,
NULL
};
struct GPostEventSource
{
GSource source;
QAtomicInt serialNumber;
int lastSerialNumber;
QGtkEventDispatcherPrivate *d;
};
static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
{
QThreadData *data = reinterpret_cast<QThreadPrivate*>(QObjectPrivate::get(QThread::currentThread()))->data;
if (!data)
return false;
gint dummy;
if (!timeout)
timeout = &dummy;
const bool canWait = data->canWaitLocked();
*timeout = canWait ? -1 : 0;
GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
return (!canWait
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
|| (source->serialNumber.loadRelaxed() != source->lastSerialNumber));
#else
|| (source->serialNumber.load() != source->lastSerialNumber));
#endif
}
static gboolean postEventSourceCheck(GSource *source)
{
return postEventSourcePrepare(source, 0);
}
static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
{
TRACE_EVENT0("gfx", "QGtkEventDispatcher::postEventSourceDispatch");
GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
source->lastSerialNumber = source->serialNumber.loadRelaxed();
#else
source->lastSerialNumber = source->serialNumber.load();
#endif
QCoreApplication::sendPostedEvents();
source->d->runTimersOnceWithNormalPriority();
return true; // i dunno, george...
}
static GSourceFuncs postEventSourceFuncs = {
postEventSourcePrepare,
postEventSourceCheck,
postEventSourceDispatch,
NULL,
NULL,
NULL
};
struct GUserEventSource
{
GSource source;
QGtkEventDispatcherPrivate *d;
};
static gboolean userEventSourcePrepare(GSource *s, gint *timeout)
{
Q_UNUSED(s);
Q_UNUSED(timeout);
return QWindowSystemInterface::windowSystemEventsQueued() > 0;
}
static gboolean userEventSourceCheck(GSource *source)
{
return userEventSourcePrepare(source, 0);
}
static gboolean userEventSourceDispatch(GSource *source, GSourceFunc, gpointer)
{
TRACE_EVENT0("gfx", "QGtkEventDispatcher::userEventSourceDispatch");
GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource*>(source);
QGtkEventDispatcherPrivate *dispatcher = userEventSource->d;
QWindowSystemInterface::sendWindowSystemEvents(dispatcher->m_flags);
return true;
}
static GSourceFuncs userEventSourceFuncs = {
userEventSourcePrepare,
userEventSourceCheck,
userEventSourceDispatch,
NULL,
NULL,
NULL
};
QGtkEventDispatcherPrivate::QGtkEventDispatcherPrivate(GMainContext *context)
: mainContext(context)
{
#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32
if (qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB")) {
static QBasicMutex mutex;
QMutexLocker locker(&mutex);
if (!g_thread_supported())
g_thread_init(NULL);
}
#endif
if (mainContext) {
g_main_context_ref(mainContext);
} else {
QCoreApplication *app = QCoreApplication::instance();
if (app && QThread::currentThread() == app->thread()) {
mainContext = g_main_context_default();
g_main_context_ref(mainContext);
} else {
mainContext = g_main_context_new();
}
}
#if GLIB_CHECK_VERSION (2, 22, 0)
g_main_context_push_thread_default (mainContext);
#endif
// ### RB: modified from upstream
// We must ensure that gtk's priority settings are above us, otherwise we
// might exhaust gtk, meaning that windows won't show etc.
int QT_BASE_PRIORITY = G_PRIORITY_LOW - 1;
// user event source
userEventSource = reinterpret_cast<GUserEventSource *>(g_source_new(&userEventSourceFuncs,
sizeof(GUserEventSource)));
userEventSource->d = this;
// must be above QT_BASE_PRIORITY, and similar to gtk's base priorities, otherwise we will have window flicker on show/resize.
g_source_set_priority(&userEventSource->source, G_PRIORITY_DEFAULT);
g_source_set_can_recurse(&userEventSource->source, true);
g_source_attach(&userEventSource->source, mainContext);
// setup post event source
postEventSource = reinterpret_cast<GPostEventSource *>(g_source_new(&postEventSourceFuncs,
sizeof(GPostEventSource)));
g_source_set_priority(&postEventSource->source, QT_BASE_PRIORITY - 1);
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
postEventSource->serialNumber.storeRelaxed(1);
#else
postEventSource->serialNumber.store(1);
#endif
postEventSource->d = this;
g_source_set_can_recurse(&postEventSource->source, true);
g_source_attach(&postEventSource->source, mainContext);
// setup socketNotifierSource
socketNotifierSource =
reinterpret_cast<GSocketNotifierSource *>(g_source_new(&socketNotifierSourceFuncs,
sizeof(GSocketNotifierSource)));
g_source_set_priority(&socketNotifierSource->source, QT_BASE_PRIORITY - 3);
(void) new (&socketNotifierSource->pollfds) QList<GPollFDWithQSocketNotifier *>();
g_source_set_can_recurse(&socketNotifierSource->source, true);
g_source_attach(&socketNotifierSource->source, mainContext);
// setup normal and idle timer sources
timerSource = reinterpret_cast<GTimerSource *>(g_source_new(&timerSourceFuncs,
sizeof(GTimerSource)));
g_source_set_priority(&timerSource->source, QT_BASE_PRIORITY - 3);
(void) new (&timerSource->timerList) QTimerInfoList();
timerSource->processEventsFlags = QEventLoop::AllEvents;
timerSource->runWithIdlePriority = false;
g_source_set_can_recurse(&timerSource->source, true);
g_source_attach(&timerSource->source, mainContext);
idleTimerSource = reinterpret_cast<GIdleTimerSource *>(g_source_new(&idleTimerSourceFuncs,
sizeof(GIdleTimerSource)));
g_source_set_priority(&idleTimerSource->source, QT_BASE_PRIORITY - 4);
idleTimerSource->timerSource = timerSource;
g_source_set_can_recurse(&idleTimerSource->source, true);
g_source_attach(&idleTimerSource->source, mainContext);
}
void QGtkEventDispatcherPrivate::runTimersOnceWithNormalPriority()
{
timerSource->runWithIdlePriority = false;
}
QGtkEventDispatcher::QGtkEventDispatcher(QObject *parent)
: QAbstractEventDispatcher(*(new QGtkEventDispatcherPrivate), parent)
{
}
QGtkEventDispatcher::QGtkEventDispatcher(GMainContext *mainContext, QObject *parent)
: QAbstractEventDispatcher(*(new QGtkEventDispatcherPrivate(mainContext)), parent)
{ }
QGtkEventDispatcher::~QGtkEventDispatcher()
{
Q_D(QGtkEventDispatcher);
// destroy user event source
g_source_destroy(&d->userEventSource->source);
g_source_unref(&d->userEventSource->source);
d->userEventSource = 0;
// destroy all timer sources
qDeleteAll(d->timerSource->timerList);
d->timerSource->timerList.~QTimerInfoList();
g_source_destroy(&d->timerSource->source);
g_source_unref(&d->timerSource->source);
d->timerSource = 0;
g_source_destroy(&d->idleTimerSource->source);
g_source_unref(&d->idleTimerSource->source);
d->idleTimerSource = 0;
// destroy socket notifier source
for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) {
GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds[i];
g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
delete p;
}
d->socketNotifierSource->pollfds.~QList<GPollFDWithQSocketNotifier *>();
g_source_destroy(&d->socketNotifierSource->source);
g_source_unref(&d->socketNotifierSource->source);
d->socketNotifierSource = 0;
// destroy post event source
g_source_destroy(&d->postEventSource->source);
g_source_unref(&d->postEventSource->source);
d->postEventSource = 0;
Q_ASSERT(d->mainContext != 0);
#if GLIB_CHECK_VERSION (2, 22, 0)
g_main_context_pop_thread_default (d->mainContext);
#endif
g_main_context_unref(d->mainContext);
d->mainContext = 0;
}
bool QGtkEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
{
TRACE_EVENT0("gfx", "QGtkEventDispatcher::processEvents");
Q_D(QGtkEventDispatcher);
d->m_flags = flags;
const bool canWait = (flags & QEventLoop::WaitForMoreEvents);
if (canWait)
Q_EMIT aboutToBlock();
else
Q_EMIT awake();
// tell postEventSourcePrepare() and timerSource about any new flags
QEventLoop::ProcessEventsFlags savedFlags = d->timerSource->processEventsFlags;
d->timerSource->processEventsFlags = flags;
if (!(flags & QEventLoop::EventLoopExec)) {
// force timers to be sent at normal priority
d->timerSource->runWithIdlePriority = false;
}
bool result = g_main_context_iteration(d->mainContext, canWait);
while (!result && canWait)
result = g_main_context_iteration(d->mainContext, canWait);
d->timerSource->processEventsFlags = savedFlags;
if (canWait)
Q_EMIT awake();
return result;
}
bool QGtkEventDispatcher::hasPendingEvents()
{
Q_D(QGtkEventDispatcher);
return g_main_context_pending(d->mainContext);
}
void QGtkEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
int sockfd = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (sockfd < 0) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != thread()
|| thread() != QThread::currentThread()) {
qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
return;
}
#endif
Q_D(QGtkEventDispatcher);
TRACE_COUNTER1("core", "registeredSockets", ++d->m_sockets);
GPollFDWithQSocketNotifier *p = new GPollFDWithQSocketNotifier;
p->pollfd.fd = sockfd;
switch (type) {
case QSocketNotifier::Read:
p->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
break;
case QSocketNotifier::Write:
p->pollfd.events = G_IO_OUT | G_IO_ERR;
break;
case QSocketNotifier::Exception:
p->pollfd.events = G_IO_PRI | G_IO_ERR;
break;
}
p->socketNotifier = notifier;
d->socketNotifierSource->pollfds.append(p);
g_source_add_poll(&d->socketNotifierSource->source, &p->pollfd);
}
void QGtkEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
#ifndef QT_NO_DEBUG
int sockfd = notifier->socket();
if (sockfd < 0) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != thread()
|| thread() != QThread::currentThread()) {
qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
return;
}
#endif
Q_D(QGtkEventDispatcher);
TRACE_COUNTER1("core", "registeredSockets", --d->m_sockets);
for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) {
GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds.at(i);
if (p->socketNotifier == notifier) {
// found it
g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
d->socketNotifierSource->pollfds.removeAt(i);
delete p;
return;
}
}
}
void QGtkEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
{
#ifndef QT_NO_DEBUG
if (timerId < 1 || interval < 0 || !object) {
qWarning("QGtkEventDispatcher::registerTimer: invalid arguments");
return;
} else if (object->thread() != thread() || thread() != QThread::currentThread()) {
qWarning("QGtkEventDispatcher::registerTimer: timers cannot be started from another thread");
return;
}
#endif
Q_D(QGtkEventDispatcher);
TRACE_COUNTER1("core", "registeredTimers", ++d->m_timers);
d->timerSource->timerList.registerTimer(timerId, interval, timerType, object);
}
bool QGtkEventDispatcher::unregisterTimer(int timerId)
{
#ifndef QT_NO_DEBUG
if (timerId < 1) {
qWarning("QGtkEventDispatcher::unregisterTimer: invalid argument");
return false;
} else if (thread() != QThread::currentThread()) {
qWarning("QGtkEventDispatcher::unregisterTimer: timers cannot be stopped from another thread");
return false;
}
#endif
Q_D(QGtkEventDispatcher);
TRACE_COUNTER1("core", "registeredTimers", --d->m_timers);
return d->timerSource->timerList.unregisterTimer(timerId);
}
bool QGtkEventDispatcher::unregisterTimers(QObject *object)
{
#ifndef QT_NO_DEBUG
if (!object) {
qWarning("QGtkEventDispatcher::unregisterTimers: invalid argument");
return false;
} else if (object->thread() != thread() || thread() != QThread::currentThread()) {
qWarning("QGtkEventDispatcher::unregisterTimers: timers cannot be stopped from another thread");
return false;
}
#endif
Q_D(QGtkEventDispatcher);
return d->timerSource->timerList.unregisterTimers(object);
}
QList<QGtkEventDispatcher::TimerInfo> QGtkEventDispatcher::registeredTimers(QObject *object) const
{
if (!object) {
qWarning("QGtkEventDispatcher:registeredTimers: invalid argument");
return QList<TimerInfo>();
}
Q_D(const QGtkEventDispatcher);
return d->timerSource->timerList.registeredTimers(object);
}
int QGtkEventDispatcher::remainingTime(int timerId)
{
#ifndef QT_NO_DEBUG
if (timerId < 1) {
qWarning("QGtkEventDispatcher::remainingTimeTime: invalid argument");
return -1;
}
#endif
Q_D(QGtkEventDispatcher);
return d->timerSource->timerList.timerRemainingTime(timerId);
}
void QGtkEventDispatcher::interrupt()
{
wakeUp();
}
void QGtkEventDispatcher::wakeUp()
{
Q_D(QGtkEventDispatcher);
d->postEventSource->serialNumber.ref();
g_main_context_wakeup(d->mainContext);
}
void QGtkEventDispatcher::flush()
{
}
bool QGtkEventDispatcher::versionSupported()
{
#if !defined(GLIB_MAJOR_VERSION) || !defined(GLIB_MINOR_VERSION) || !defined(GLIB_MICRO_VERSION)
return false;
#else
return ((GLIB_MAJOR_VERSION << 16) + (GLIB_MINOR_VERSION << 8) + GLIB_MICRO_VERSION) >= 0x020301;
#endif
}
QGtkEventDispatcher::QGtkEventDispatcher(QGtkEventDispatcherPrivate &dd, QObject *parent)
: QAbstractEventDispatcher(dd, parent)
{
}
QT_END_NAMESPACE
================================================
FILE: src/platform-plugin/qgtkeventdispatcher.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QEVENTDISPATCHER_GLIB_P_H
#define QEVENTDISPATCHER_GLIB_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qabstracteventdispatcher.h>
#include <private/qabstracteventdispatcher_p.h>
typedef struct _GMainContext GMainContext;
QT_BEGIN_NAMESPACE
class QGtkEventDispatcherPrivate;
class Q_CORE_EXPORT QGtkEventDispatcher : public QAbstractEventDispatcher
{
Q_OBJECT
Q_DECLARE_PRIVATE(QGtkEventDispatcher)
public:
explicit QGtkEventDispatcher(QObject *parent = 0);
explicit QGtkEventDispatcher(GMainContext *context, QObject *parent = 0);
~QGtkEventDispatcher();
bool processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE;
bool hasPendingEvents() Q_DECL_OVERRIDE;
void registerSocketNotifier(QSocketNotifier *socketNotifier) Q_DECL_FINAL;
void unregisterSocketNotifier(QSocketNotifier *socketNotifier) Q_DECL_FINAL;
void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) Q_DECL_FINAL;
bool unregisterTimer(int timerId) Q_DECL_FINAL;
bool unregisterTimers(QObject *object) Q_DECL_FINAL;
QList<TimerInfo> registeredTimers(QObject *object) const Q_DECL_FINAL;
int remainingTime(int timerId) Q_DECL_FINAL;
void wakeUp() Q_DECL_FINAL;
void interrupt() Q_DECL_FINAL;
void flush() Q_DECL_FINAL;
static bool versionSupported();
protected:
QGtkEventDispatcher(QGtkEventDispatcherPrivate &dd, QObject *parent);
};
struct GPostEventSource;
struct GSocketNotifierSource;
struct GTimerSource;
struct GIdleTimerSource;
struct GUserEventSource;
class Q_CORE_EXPORT QGtkEventDispatcherPrivate : public QAbstractEventDispatcherPrivate
{
public:
QGtkEventDispatcherPrivate(GMainContext *context = 0);
GMainContext *mainContext;
GPostEventSource *postEventSource;
GSocketNotifierSource *socketNotifierSource;
GTimerSource *timerSource;
GIdleTimerSource *idleTimerSource;
GUserEventSource *userEventSource;
void runTimersOnceWithNormalPriority();
QEventLoop::ProcessEventsFlags m_flags = QEventLoop::AllEvents;
uint m_timers = 0;
uint m_sockets = 0;
};
QT_END_NAMESPACE
#endif // QEVENTDISPATCHER_GLIB_P_H
================================================
FILE: src/platform-plugin/qgtkhelpers.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkhelpers.h"
QGtkRefPtr<GdkPixbuf> qt_imageToPixbuf(const QImage &cimage)
{
if (cimage.isNull())
return 0;
QImage image = cimage;
if (image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGBA8888) {
image = image.convertToFormat(QImage::Format_RGBA8888);
}
} else {
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
}
}
guchar *buf = (guchar*)malloc(image.byteCount());
memcpy(buf, image.constBits(), image.byteCount());
QGtkRefPtr<GdkPixbuf> gpb = gdk_pixbuf_new_from_data(
buf,
GDK_COLORSPACE_RGB,
image.hasAlphaChannel(),
8,
image.width(),
image.height(),
image.bytesPerLine(),
(GdkPixbufDestroyNotify)free,
NULL
);
return gpb;
}
QGtkRefPtr<GdkPixbuf> qt_pixmapToPixbuf(const QPixmap &pixmap)
{
QImage i = pixmap.toImage();
return qt_imageToPixbuf(i);
}
QImage qt_pixbufToImage(const QGtkRefPtr<GdkPixbuf> &pixbuf)
{
QImage data;
if (gdk_pixbuf_get_has_alpha(pixbuf.get())) {
data = QImage(gdk_pixbuf_get_pixels(pixbuf.get()),
gdk_pixbuf_get_width(pixbuf.get()), gdk_pixbuf_get_height(pixbuf.get()),
gdk_pixbuf_get_rowstride(pixbuf.get()),
QImage::Format_RGBA8888).copy();
} else {
data = QImage(gdk_pixbuf_get_pixels(pixbuf.get()),
gdk_pixbuf_get_width(pixbuf.get()), gdk_pixbuf_get_height(pixbuf.get()),
gdk_pixbuf_get_rowstride(pixbuf.get()),
QImage::Format_RGB888).copy();
}
return data;
}
// Returns the largest image for this icon, in RGBA format.
QImage qt_getBiggestImageForIcon(const QIcon &icon)
{
QIcon::State st = QIcon::On;
QList<QSize> sizes = icon.availableSizes(QIcon::Normal, st);
if (!sizes.length()) {
st = QIcon::Off;
sizes = icon.availableSizes(QIcon::Normal, st);
if (!sizes.length()) {
qWarning() << "No available icons for icon?" << icon;
return QImage();
}
}
// Find the largest size, hopefully it's the best looking.
QSize sz;
for (int i = 0; i < sizes.length(); ++i) {
const QSize &nsz = sizes.at(i);
if (nsz.width() * nsz.height() >= sz.width() * sz.height()) {
sz = nsz;
}
}
QPixmap p = icon.pixmap(sz, QIcon::Normal, st);
QImage i = p.toImage().convertToFormat(QImage::Format_RGBA8888);
return i;
}
// Convert a QIcon to a GdkPixbuf for use elsewhere.
QGtkRefPtr<GdkPixbuf> qt_iconToPixbuf(const QIcon &icon)
{
QImage i = qt_getBiggestImageForIcon(icon);
return qt_imageToPixbuf(i);
}
// Convert a QIcon to a GIcon for use elsewhere.
QGtkRefPtr<GIcon> qt_iconToIcon(const QIcon &icon)
{
QImage i = qt_getBiggestImageForIcon(icon);
QGtkRefPtr<GBytes> bytes = g_bytes_new_take(const_cast<uchar*>(i.constBits()), i.byteCount());
QGtkRefPtr<GIcon> ico = g_bytes_icon_new(bytes.get());
return ico;
}
// Qt uses &, gtk uses _.
QString qt_convertToGtkMnemonics(const QString &text)
{
QString cpy = text;
return cpy.replace("&", "_"); // ### too simple! need to leave &&.
}
Qt::KeyboardModifiers qt_convertToQtKeyboardMods(guint mask)
{
Qt::KeyboardModifiers mods = Qt::NoModifier;
if (mask & GDK_SHIFT_MASK)
mods |= Qt::ShiftModifier;
if (mask & GDK_CONTROL_MASK)
mods |= Qt::ControlModifier;
if (mask & GDK_MOD1_MASK)
mods |= Qt::AltModifier;
if (mask & GDK_META_MASK)
mods |= Qt::MetaModifier;
#if 0
if (mask & GDK_SUPER_MASK)
qDebug() << "Super";
if (mask & GDK_HYPER_MASK)
qDebug() << "Hyper";
if (mask & GDK_MOD2_MASK)
qDebug() << "Mod2";
if (mask & GDK_MOD3_MASK)
qDebug() << "Mod3";
if (mask & GDK_MOD4_MASK)
qDebug() << "Mod4";
if (mask & GDK_MOD5_MASK)
qDebug() << "Mod5";
#endif
return mods;
}
Qt::Key qt_convertToQtKey(int keyval)
{
switch (keyval) {
case GDK_KEY_BackSpace:
return Qt::Key_Backspace;
case GDK_KEY_KP_Tab:
case GDK_KEY_Tab:
return Qt::Key_Tab;
case GDK_KEY_Clear:
return Qt::Key_Clear;
case GDK_KEY_Return:
return Qt::Key_Return;
case GDK_KEY_KP_Enter:
return Qt::Key_Enter;
case GDK_KEY_Pause:
return Qt::Key_Pause;
case GDK_KEY_Scroll_Lock:
return Qt::Key_ScrollLock;
case GDK_KEY_Sys_Req:
return Qt::Key_SysReq;
case GDK_KEY_Escape:
return Qt::Key_Escape;
case GDK_KEY_KP_Delete:
case GDK_KEY_Delete:
return Qt::Key_Delete;
case GDK_KEY_Multi_key:
return Qt::Key_Multi_key;
case GDK_KEY_Codeinput:
return Qt::Key_Codeinput;
case GDK_KEY_SingleCandidate:
return Qt::Key_SingleCandidate;
case GDK_KEY_MultipleCandidate:
return Qt::Key_MultipleCandidate;
case GDK_KEY_PreviousCandidate:
return Qt::Key_PreviousCandidate;
case GDK_KEY_Kanji:
return Qt::Key_Kanji;
case GDK_KEY_Muhenkan:
return Qt::Key_Muhenkan;
case GDK_KEY_Henkan:
return Qt::Key_Henkan;
case GDK_KEY_Romaji:
return Qt::Key_Romaji;
case GDK_KEY_Hiragana:
return Qt::Key_Hiragana;
case GDK_KEY_Katakana:
return Qt::Key_Katakana;
case GDK_KEY_Hiragana_Katakana:
return Qt::Key_Hiragana_Katakana;
case GDK_KEY_Zenkaku:
return Qt::Key_Zenkaku;
case GDK_KEY_Hankaku:
return Qt::Key_Hankaku;
case GDK_KEY_Zenkaku_Hankaku:
return Qt::Key_Zenkaku_Hankaku;
case GDK_KEY_Touroku:
return Qt::Key_Touroku;
case GDK_KEY_Massyo:
return Qt::Key_Massyo;
case GDK_KEY_Kana_Lock:
return Qt::Key_Kana_Lock;
case GDK_KEY_Kana_Shift:
return Qt::Key_Kana_Shift;
case GDK_KEY_Eisu_Shift:
return Qt::Key_Eisu_Shift;
case GDK_KEY_Eisu_toggle:
return Qt::Key_Eisu_toggle;
case GDK_KEY_KP_Home:
case GDK_KEY_Home:
return Qt::Key_Home;
case GDK_KEY_KP_Left:
case GDK_KEY_Left:
return Qt::Key_Left;
case GDK_KEY_KP_Up:
case GDK_KEY_Up:
return Qt::Key_Up;
case GDK_KEY_KP_Right:
case GDK_KEY_Right:
return Qt::Key_Right;
case GDK_KEY_KP_Down:
case GDK_KEY_Down:
return Qt::Key_Down;
case GDK_KEY_KP_Page_Up:
case GDK_KEY_Page_Up:
return Qt::Key_PageUp;
case GDK_KEY_KP_Page_Down:
case GDK_KEY_Page_Down:
return Qt::Key_PageDown;
case GDK_KEY_KP_End:
case GDK_KEY_End:
return Qt::Key_End;
case GDK_KEY_KP_Begin:
case GDK_KEY_Begin:
return Qt::Key_Home;
case GDK_KEY_Select:
return Qt::Key_Select;
case GDK_KEY_Print:
return Qt::Key_Print;
case GDK_KEY_Execute:
return Qt::Key_Execute;
case GDK_KEY_KP_Insert:
case GDK_KEY_Insert:
return Qt::Key_Insert;
case GDK_KEY_Menu:
return Qt::Key_Menu;
case GDK_KEY_Cancel:
return Qt::Key_Cancel;
case GDK_KEY_Help:
return Qt::Key_Help;
case GDK_KEY_Mode_switch:
return Qt::Key_Mode_switch;
case GDK_KEY_Num_Lock:
return Qt::Key_NumLock;
case GDK_KEY_F1:
case GDK_KEY_KP_F1:
return Qt::Key_F1;
case GDK_KEY_F2:
case GDK_KEY_KP_F2:
return Qt::Key_F2;
case GDK_KEY_F3:
case GDK_KEY_KP_F3:
return Qt::Key_F3;
case GDK_KEY_F4:
case GDK_KEY_KP_F4:
return Qt::Key_F4;
case GDK_KEY_F5:
return Qt::Key_F5;
case GDK_KEY_F6:
return Qt::Key_F6;
case GDK_KEY_F7:
return Qt::Key_F7;
case GDK_KEY_F8:
return Qt::Key_F8;
case GDK_KEY_F9:
return Qt::Key_F9;
case GDK_KEY_F10:
return Qt::Key_F10;
case GDK_KEY_F11:
return Qt::Key_F11;
case GDK_KEY_F12:
return Qt::Key_F12;
case GDK_KEY_F13:
return Qt::Key_F13;
case GDK_KEY_F14:
return Qt::Key_F14;
case GDK_KEY_F15:
return Qt::Key_F15;
case GDK_KEY_F16:
return Qt::Key_F16;
case GDK_KEY_F17:
return Qt::Key_F17;
case GDK_KEY_F18:
return Qt::Key_F18;
case GDK_KEY_F19:
return Qt::Key_F19;
case GDK_KEY_F20:
return Qt::Key_F20;
case GDK_KEY_F21:
return Qt::Key_F21;
case GDK_KEY_F22:
return Qt::Key_F22;
case GDK_KEY_F23:
return Qt::Key_F23;
case GDK_KEY_F24:
return Qt::Key_F24;
case GDK_KEY_F25:
return Qt::Key_F25;
case GDK_KEY_F26:
return Qt::Key_F26;
case GDK_KEY_F27:
return Qt::Key_F27;
case GDK_KEY_F28:
return Qt::Key_F28;
case GDK_KEY_F29:
return Qt::Key_F29;
case GDK_KEY_F30:
return Qt::Key_F30;
case GDK_KEY_F31:
return Qt::Key_F31;
case GDK_KEY_F32:
return Qt::Key_F32;
case GDK_KEY_F33:
return Qt::Key_F33;
case GDK_KEY_F34:
return Qt::Key_F34;
case GDK_KEY_F35:
return Qt::Key_F35;
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
return Qt::Key_Shift;
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
return Qt::Key_Control;
case GDK_KEY_Caps_Lock:
return Qt::Key_CapsLock;
case GDK_KEY_Meta_L:
case GDK_KEY_Meta_R:
return Qt::Key_Meta;
case GDK_KEY_Alt_L:
case GDK_KEY_Alt_R:
return Qt::Key_Alt;
case GDK_KEY_Super_L:
return Qt::Key_Super_L;
case GDK_KEY_Super_R:
return Qt::Key_Super_R;
case GDK_KEY_Hyper_L:
return Qt::Key_Hyper_R;
case GDK_KEY_Hyper_R:
return Qt::Key_Hyper_R;
case GDK_KEY_MonBrightnessUp:
return Qt::Key_MonBrightnessUp;
case GDK_KEY_MonBrightnessDown:
return Qt::Key_MonBrightnessDown;
case GDK_KEY_KbdLightOnOff:
return Qt::Key_KeyboardLightOnOff;
case GDK_KEY_KbdBrightnessUp:
return Qt::Key_KeyboardBrightnessUp;
case GDK_KEY_KbdBrightnessDown:
return Qt::Key_KeyboardBrightnessDown;
case GDK_KEY_Standby:
return Qt::Key_Standby;
case GDK_KEY_AudioLowerVolume:
return Qt::Key_VolumeDown;
case GDK_KEY_AudioMute:
return Qt::Key_VolumeMute;
case GDK_KEY_AudioRaiseVolume:
return Qt::Key_VolumeUp;
case GDK_KEY_AudioPlay:
return Qt::Key_MediaPlay;
case GDK_KEY_AudioStop:
return Qt::Key_MediaStop;
case GDK_KEY_AudioPrev:
return Qt::Key_MediaPrevious;
case GDK_KEY_AudioNext:
return Qt::Key_MediaNext;
case GDK_KEY_HomePage:
return Qt::Key_HomePage;
case GDK_KEY_Mail:
return Qt::Key_LaunchMail;
case GDK_KEY_Start:
return Qt::Key_Standby;
case GDK_KEY_Find:
case GDK_KEY_Search:
return Qt::Key_Search;
case GDK_KEY_AudioRecord:
case GDK_KEY_Calculator:
return Qt::Key_Calculator;
case GDK_KEY_Memo:
return Qt::Key_Memo;
case GDK_KEY_ToDoList:
return Qt::Key_ToDoList;
case GDK_KEY_Calendar:
return Qt::Key_Calendar;
case GDK_KEY_PowerDown:
return Qt::Key_PowerDown;
case GDK_KEY_ContrastAdjust:
return Qt::Key_ContrastAdjust;
case GDK_KEY_Back:
return Qt::Key_Back;
case GDK_KEY_Forward:
return Qt::Key_Forward;
case GDK_KEY_Stop:
return Qt::Key_Stop;
case GDK_KEY_Refresh:
return Qt::Key_Refresh;
case GDK_KEY_PowerOff:
return Qt::Key_PowerOff;
case GDK_KEY_WakeUp:
return Qt::Key_WakeUp;
case GDK_KEY_Eject:
return Qt::Key_Eject;
case GDK_KEY_ScreenSaver:
return Qt::Key_ScreenSaver;
case GDK_KEY_WWW:
return Qt::Key_WWW;
case GDK_KEY_Sleep:
return Qt::Key_Sleep;
case GDK_KEY_Favorites:
return Qt::Key_Favorites;
case GDK_KEY_AudioPause:
return Qt::Key_MediaPause;
case GDK_KEY_AudioMedia:
return Qt::Key_LaunchMedia;
case GDK_KEY_MyComputer:
return Qt::Key_Launch0;
case GDK_KEY_VendorHome:
return Qt::Key_OfficeHome;
case GDK_KEY_LightBulb:
return Qt::Key_LightBulb;
case GDK_KEY_Shop:
return Qt::Key_Shop;
case GDK_KEY_History:
return Qt::Key_History;
case GDK_KEY_OpenURL:
return Qt::Key_OpenUrl;
case GDK_KEY_AddFavorite:
return Qt::Key_AddFavorite;
case GDK_KEY_HotLinks:
return Qt::Key_HotLinks;
case GDK_KEY_BrightnessAdjust:
return Qt::Key_BrightnessAdjust;
case GDK_KEY_Finance:
return Qt::Key_Finance;
case GDK_KEY_Community:
return Qt::Key_Community;
case GDK_KEY_AudioRewind:
return Qt::Key_AudioRewind;
case GDK_KEY_BackForward:
return Qt::Key_BackForward;
case GDK_KEY_Launch0:
return Qt::Key_Launch0;
case GDK_KEY_Launch1:
return Qt::Key_Launch1;
case GDK_KEY_Launch2:
return Qt::Key_Launch2;
case GDK_KEY_Launch3:
return Qt::Key_Launch3;
case GDK_KEY_Launch4:
return Qt::Key_Launch4;
case GDK_KEY_Launch5:
return Qt::Key_Launch5;
case GDK_KEY_Launch6:
return Qt::Key_Launch6;
case GDK_KEY_Launch7:
return Qt::Key_Launch7;
case GDK_KEY_Launch8:
return Qt::Key_Launch8;
case GDK_KEY_Launch9:
return Qt::Key_Launch9;
case GDK_KEY_LaunchA:
return Qt::Key_LaunchA;
case GDK_KEY_LaunchB:
return Qt::Key_LaunchB;
case GDK_KEY_LaunchC:
return Qt::Key_LaunchC;
case GDK_KEY_LaunchD:
return Qt::Key_LaunchD;
case GDK_KEY_LaunchE:
return Qt::Key_LaunchE;
case GDK_KEY_LaunchF:
return Qt::Key_LaunchF;
case GDK_KEY_ApplicationLeft:
return Qt::Key_ApplicationLeft;
case GDK_KEY_ApplicationRight:
return Qt::Key_ApplicationRight;
case GDK_KEY_Book:
return Qt::Key_Book;
case GDK_KEY_CD:
return Qt::Key_CD;
case GDK_KEY_Close:
return Qt::Key_Close;
case GDK_KEY_Copy:
return Qt::Key_Copy;
case GDK_KEY_Cut:
return Qt::Key_Cut;
case GDK_KEY_Display:
return Qt::Key_Display;
case GDK_KEY_DOS:
return Qt::Key_DOS;
case GDK_KEY_Documents:
return Qt::Key_Documents;
case GDK_KEY_Excel:
return Qt::Key_Excel;
case GDK_KEY_Explorer:
return Qt::Key_Explorer;
case GDK_KEY_Game:
return Qt::Key_Game;
case GDK_KEY_Go:
return Qt::Key_Go;
case GDK_KEY_iTouch:
return Qt::Key_iTouch;
case GDK_KEY_LogOff:
return Qt::Key_LogOff;
case GDK_KEY_Market:
return Qt::Key_Market;
case GDK_KEY_Meeting:
return Qt::Key_Meeting;
case GDK_KEY_MenuKB:
return Qt::Key_MenuKB;
case GDK_KEY_MenuPB:
return Qt::Key_MenuPB;
case GDK_KEY_MySites:
return Qt::Key_MySites;
case GDK_KEY_News:
return Qt::Key_News;
case GDK_KEY_OfficeHome:
return Qt::Key_OfficeHome;
case GDK_KEY_Option:
return Qt::Key_Option;
case GDK_KEY_Paste:
return Qt::Key_Paste;
case GDK_KEY_Phone:
return Qt::Key_Phone;
case GDK_KEY_Reply:
return Qt::Key_Reply;
case GDK_KEY_Reload:
return Qt::Key_Reload;
case GDK_KEY_RotateWindows:
return Qt::Key_RotateWindows;
case GDK_KEY_RotationPB:
return Qt::Key_RotationPB;
case GDK_KEY_RotationKB:
return Qt::Key_RotationKB;
case GDK_KEY_Save:
return Qt::Key_Save;
case GDK_KEY_Send:
return Qt::Key_Send;
case GDK_KEY_Spell:
return Qt::Key_Spell;
case GDK_KEY_SplitScreen:
return Qt::Key_SplitScreen;
case GDK_KEY_Support:
return Qt::Key_Support;
case GDK_KEY_TaskPane:
return Qt::Key_TaskPane;
case GDK_KEY_Terminal:
return Qt::Key_Terminal;
case GDK_KEY_Tools:
return Qt::Key_Tools;
case GDK_KEY_Travel:
return Qt::Key_Travel;
case GDK_KEY_Video:
return Qt::Key_Video;
case GDK_KEY_Word:
return Qt::Key_Word;
case GDK_KEY_Xfer:
return Qt::Key_Xfer;
case GDK_KEY_ZoomIn:
return Qt::Key_ZoomIn;
case GDK_KEY_ZoomOut:
return Qt::Key_ZoomOut;
case GDK_KEY_Away:
return Qt::Key_Away;
case GDK_KEY_Messenger:
return Qt::Key_Messenger;
case GDK_KEY_WebCam:
return Qt::Key_WebCam;
case GDK_KEY_MailForward:
return Qt::Key_MailForward;
case GDK_KEY_Pictures:
return Qt::Key_Pictures;
case GDK_KEY_Music:
return Qt::Key_Music;
case GDK_KEY_Battery:
return Qt::Key_Battery;
case GDK_KEY_Bluetooth:
return Qt::Key_Bluetooth;
case GDK_KEY_WLAN:
return Qt::Key_WLAN;
case GDK_KEY_UWB:
return Qt::Key_UWB;
case GDK_KEY_AudioForward:
return Qt::Key_AudioForward;
case GDK_KEY_AudioRepeat:
return Qt::Key_AudioRepeat;
case GDK_KEY_AudioRandomPlay:
return Qt::Key_AudioRandomPlay;
case GDK_KEY_Subtitle:
return Qt::Key_Subtitle;
case GDK_KEY_AudioCycleTrack:
return Qt::Key_AudioCycleTrack;
case GDK_KEY_Time:
return Qt::Key_Time;
case GDK_KEY_View:
return Qt::Key_View;
case GDK_KEY_TopMenu:
return Qt::Key_TopMenu;
case GDK_KEY_Suspend:
return Qt::Key_Suspend;
case GDK_KEY_Hibernate:
return Qt::Key_Hibernate;
case GDK_KEY_ClearGrab:
return Qt::Key_ClearGrab;
}
if (keyval < 256) {
if (isprint(keyval))
keyval = toupper(keyval);
}
return Qt::Key(keyval);
}
// ### keyvalToQtKey in reverse, ugh
// ### finish
guint qt_convertToGdkKeyval(Qt::Key qKey)
{
switch (qKey) {
case Qt::Key_Insert:
return GDK_KEY_Insert;
case Qt::Key_Delete:
return GDK_KEY_Delete;
case Qt::Key_Left:
return GDK_KEY_Left;
case Qt::Key_Right:
return GDK_KEY_Right;
case Qt::Key_Up:
return GDK_KEY_Up;
case Qt::Key_Down:
return GDK_KEY_Down;
case Qt::Key_Tab:
return GDK_KEY_Tab;
case Qt::Key_F1:
return GDK_KEY_F1;
case Qt::Key_F2:
return GDK_KEY_F2;
case Qt::Key_F3:
return GDK_KEY_F3;
case Qt::Key_F4:
return GDK_KEY_F4;
case Qt::Key_F5:
return GDK_KEY_F5;
case Qt::Key_F6:
return GDK_KEY_F6;
case Qt::Key_F7:
return GDK_KEY_F7;
case Qt::Key_F8:
return GDK_KEY_F8;
case Qt::Key_F9:
return GDK_KEY_F9;
case Qt::Key_F10:
return GDK_KEY_F10;
case Qt::Key_F11:
return GDK_KEY_F11;
case Qt::Key_F12:
return GDK_KEY_F12;
case Qt::Key_F13:
return GDK_KEY_F13;
case Qt::Key_F14:
return GDK_KEY_F14;
case Qt::Key_F15:
return GDK_KEY_F15;
case Qt::Key_F16:
return GDK_KEY_F16;
case Qt::Key_F17:
return GDK_KEY_F17;
case Qt::Key_F18:
return GDK_KEY_F18;
case Qt::Key_F19:
return GDK_KEY_F19;
case Qt::Key_F20:
return GDK_KEY_F20;
case Qt::Key_F21:
return GDK_KEY_F21;
}
return (guint)qKey;
}
Qt::MouseButton qt_convertGButtonToQButton(guint button)
{
Qt::MouseButton b = Qt::NoButton;
switch (button) {
case 1:
b = Qt::LeftButton;
break;
case 2:
b = Qt::MiddleButton;
break;
case 3:
b = Qt::RightButton;
break;
case 4:
b = Qt::ExtraButton1;
break;
case 5:
b = Qt::ExtraButton2;
break;
case 6:
b = Qt::ExtraButton3;
break;
case 7:
b = Qt::ExtraButton4;
break;
case 8:
b = Qt::ExtraButton5;
break;
case 9:
b = Qt::ExtraButton6;
break;
case 10:
b = Qt::ExtraButton7;
break;
case 11:
b = Qt::ExtraButton8;
break;
case 12:
b = Qt::ExtraButton9;
break;
case 13:
b = Qt::ExtraButton10;
break;
case 14:
b = Qt::ExtraButton11;
break;
case 15:
b = Qt::ExtraButton12;
break;
case 16:
b = Qt::ExtraButton13;
break;
case 17:
b = Qt::ExtraButton14;
break;
case 18:
b = Qt::ExtraButton15;
break;
case 19:
b = Qt::ExtraButton16;
break;
case 20:
b = Qt::ExtraButton17;
break;
case 21:
b = Qt::ExtraButton18;
break;
case 22:
b = Qt::ExtraButton19;
break;
case 23:
b = Qt::ExtraButton20;
break;
case 24:
b = Qt::ExtraButton21;
break;
case 25:
b = Qt::ExtraButton22;
break;
case 26:
b = Qt::ExtraButton23;
break;
case 27:
b = Qt::ExtraButton24;
break;
default:
qWarning() << "Unrecognized button" << button;
}
return b;
}
Qt::TouchPointState qt_convertToQtTouchPointState(GdkEventType type)
{
switch (type) {
case GDK_TOUCH_BEGIN:
return Qt::TouchPointPressed;
case GDK_TOUCH_UPDATE:
return Qt::TouchPointMoved;
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
return Qt::TouchPointReleased;
default:
Q_UNREACHABLE();
}
}
cairo_region_t *qt_convertToCairoRegion(const QRegion ®ion)
{
cairo_region_t *r = cairo_region_create();
for (const QRect &qrect : region.rects()) {
cairo_rectangle_int_t rect = { qrect.x(), qrect.y(), qrect.width(), qrect.height() };
cairo_region_union_rectangle(r, &rect);
}
return r;
}
================================================
FILE: src/platform-plugin/qgtkhelpers.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkmenuitem.h"
#include "qgtkrefptr.h"
#include <QtCore/qdebug.h>
#ifndef QGTKHELPERS_H
#define QGTKHELPERS_H
QT_BEGIN_NAMESPACE
QGtkRefPtr<GdkPixbuf> qt_imageToPixbuf(const QImage &image);
QGtkRefPtr<GdkPixbuf> qt_pixmapToPixbuf(const QPixmap &pixmap);
QImage qt_pixbufToImage(const QGtkRefPtr<GdkPixbuf> &pixbuf);
QGtkRefPtr<GdkPixbuf> qt_iconToPixbuf(const QIcon &icon);
QGtkRefPtr<GIcon> qt_iconToIcon(const QIcon &icon);
QString qt_convertToGtkMnemonics(const QString &text);
Qt::KeyboardModifiers qt_convertToQtKeyboardMods(guint mask);
Qt::Key qt_convertToQtKey(int keyval);
guint qt_convertToGdkKeyval(Qt::Key qKey);
Qt::MouseButton qt_convertGButtonToQButton(guint button);
Qt::TouchPointState qt_convertToQtTouchPointState(GdkEventType type);
cairo_region_t *qt_convertToCairoRegion(const QRegion ®ion);
QT_END_NAMESPACE
#endif
================================================
FILE: src/platform-plugin/qgtkintegration.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkintegration.h"
#include "qgtkbackingstore.h"
#include "qgtkwindow.h"
#include "qgtkscreen.h"
#include "qgtktheme.h"
#include "qgtkopenglcontext.h"
#include "qgtkeventdispatcher.h"
#include "qgtkclipboard.h"
#include <QtWidgets/qapplication.h>
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qguiapplication_p.h>
#if QT_VERSION >= QT_VERSION_CHECK(5,8,0)
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#include <QtServiceSupport/private/qgenericunixservices_p.h>
#else
#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
#include <QtPlatformSupport/private/qgenericunixservices_p.h>
#endif
#include <gtk/gtk.h>
#include <libnotify/notify.h>
#ifdef GDK_WINDOWING_WAYLAND
#include <EGL/egl.h>
#include <gdk/gdkwayland.h>
static EGLDisplay createWaylandEGLDisplay(wl_display *display);
#endif
#ifdef GDK_WINDOWING_X11
# include <gdk/gdkx.h>
# include <X11/Xlib-xcb.h>
#endif
#include "CSystrace.h"
QT_BEGIN_NAMESPACE
class QCoreTextFontEngine;
void monitor_added(GdkDisplay *, GdkMonitor *monitor, gpointer integration)
{
QGtkIntegration *ig = static_cast<QGtkIntegration*>(integration);
ig->onMonitorAdded(monitor);
}
void monitor_removed(GdkDisplay *, GdkMonitor *monitor, gpointer integration)
{
QGtkIntegration *ig = static_cast<QGtkIntegration*>(integration);
ig->onMonitorRemoved(monitor);
}
QGtkIntegration::QGtkIntegration(const QStringList &)
: m_services(new QGtkServices)
, m_fontDatabase(new QGenericUnixFontDatabase)
, m_eglDisplay(nullptr)
{
systrace_init();
gtk_init(NULL, NULL);
notify_init(qApp->applicationName().toUtf8().constData());
// Set up screens
m_display = gdk_display_get_default();
g_signal_connect(m_display, "monitor-added", G_CALLBACK(monitor_added), this);
g_signal_connect(m_display, "monitor-removed", G_CALLBACK(monitor_removed), this);
int num_monitors = gdk_display_get_n_monitors(m_display);
for (int i = 0; i < num_monitors; i++) {
GdkMonitor *monitor = gdk_display_get_monitor(m_display, i);
monitor_added(m_display, monitor, this);
}
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY(m_display)) {
wl_display *wldisplay = gdk_wayland_display_get_wl_display(GDK_WAYLAND_DISPLAY(m_display));
m_eglDisplay = createWaylandEGLDisplay(wldisplay);
Q_ASSERT(m_eglDisplay);
}
else
#endif
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY(m_display)) {
qWarning() << "Application is running under X11. While this may work, it is experimental.";
qWarning() << "Run under Wayland for best results.";
}
else
#endif
qWarning("GTK platform does not support this display backend; GL contexts will fail");
}
QGtkIntegration::~QGtkIntegration()
{
notify_uninit();
#ifdef GDK_WINDOWING_WAYLAND
if (m_eglDisplay) {
eglTerminate(m_eglDisplay);
}
#endif
systrace_deinit();
}
void QGtkIntegration::onMonitorAdded(GdkMonitor *monitor)
{
bool isPrimary = gdk_monitor_is_primary(monitor) || m_screens.count() == 0;
qDebug() << "Added " << monitor << " isPrimary " << isPrimary;
QGtkScreen *screen = new QGtkScreen(monitor);
screen->setPrimary(isPrimary);
m_screens.append(screen);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
#else
screenAdded(screen, isPrimary);
#endif
if (isPrimary) {
qDebug() << "Changed primary screen on add";
// clear old screens
for (int i = 0; i < m_screens.count(); i++) {
QGtkScreen *os = m_screens.at(i);
screen->setPrimary(os == screen);
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
QWindowSystemInterface::handlePrimaryScreenChanged(screen);
#else
setPrimaryScreen(screen);
#endif
}
}
void QGtkIntegration::onMonitorRemoved(GdkMonitor *monitor)
{
qDebug() << "Removed " << monitor;
for (int i = 0; i < m_screens.count(); ++i) {
QGtkScreen *screen = m_screens.at(i);
if (screen->monitor() == monitor) {
qDebug() << "Removing QGtkScreen " << screen << screen->isPrimary();
bool wasPrimary = screen->isPrimary();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
QWindowSystemInterface::handleScreenRemoved(screen);
#else
removeScreen(screen->screen());
#endif
m_screens.removeAt(i);
if (wasPrimary) {
qDebug() << "Changed primary screen on remove";
GdkMonitor *primaryScreen = gdk_display_get_primary_monitor(m_display);
QGtkScreen *newPrimary = nullptr;
for (int i = 0; i < m_screens.count(); ++i) {
QGtkScreen *screen = m_screens.at(i);
screen->setPrimary(false);
if (screen->monitor() == primaryScreen || primaryScreen == nullptr) {
qDebug() << "Changed primary screen to index " << i << " ptr " << screen;
newPrimary = screen;
}
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary);
#else
setPrimaryScreen(newPrimary);
#endif
newPrimary->setPrimary(true);
}
return;
}
}
}
QPlatformOpenGLContext *QGtkIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY(m_display)) {
return new QGtkWaylandContext(context->format(), static_cast<QGtkOpenGLContext*>(context->shareHandle()));
}
#endif
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY(m_display)) {
return new QGtkX11Context(context->format(), static_cast<QGtkOpenGLContext*>(context->shareHandle()));
}
#endif
return nullptr;
}
bool QGtkIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
case ThreadedPixmaps:
case MultipleWindows:
case OpenGL:
case ThreadedOpenGL:
case RasterGLSurface:
case WindowManagement:
return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
}
QPlatformClipboard *QGtkIntegration::clipboard() const
{
if (m_clipboard == nullptr) {
QGtkIntegration *that = const_cast<QGtkIntegration*>(this);
that->m_clipboard = new QGtkClipboard(that);
}
return this->m_clipboard;
}
QPlatformFontDatabase *QGtkIntegration::fontDatabase() const
{
return m_fontDatabase.data();
}
QStringList QGtkIntegration::themeNames() const
{
return QStringList(QLatin1String(QGtkTheme::name));
}
QPlatformTheme *QGtkIntegration::createPlatformTheme(const QString &name) const
{
if (name == QLatin1String(QGtkTheme::name))
return new QGtkTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
QPlatformServices *QGtkIntegration::services() const
{
return m_services.data();
}
QPlatformNativeInterface *QGtkIntegration::nativeInterface() const
{
return const_cast<QGtkIntegration*>(this);
}
void *QGtkIntegration::nativeResourceForIntegration(const QByteArray &resource)
{
void *result = 0;
if (resource == "egldisplay") {
result = reinterpret_cast<void*>(m_eglDisplay);
} else if (resource == "connection") {
#ifdef GDK_WINDOWING_X11
static bool xcb_warned = false;
if (!xcb_warned) {
qWarning() << "XCB connection requested; this is experimental, and may not work well.";
xcb_warned = true;
}
Display *dpy = nullptr;
if (GDK_IS_X11_DISPLAY(m_display)) {
dpy = gdk_x11_display_get_xdisplay(m_display);
} else {
qWarning() << "Can't get XCB connection, GDK_BACKEND is not X11.";
}
xcb_connection_t *conn = XGetXCBConnection(dpy);
result = reinterpret_cast<void*>(conn);
#endif
} else if (resource == "display") {
#ifdef GDK_WINDOWING_X11
static bool x11_warned = false;
if (!x11_warned) {
qWarning() << "X11 display handle; this is experimental, and may not work well.";
x11_warned = true;
}
Display *dpy = nullptr;
if (GDK_IS_X11_DISPLAY(m_display)) {
dpy = gdk_x11_display_get_xdisplay(m_display);
} else {
qWarning() << "Can't get XCB connection, GDK_BACKEND is not X11.";
}
result = reinterpret_cast<void*>(dpy);
#endif
} else {
qWarning() << "Unimplemented request for " << resource;
}
return result;
}
void *QGtkIntegration::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
{
void *result = 0;
QByteArray res = resource.toLower();
// ### notify on change
if (res == "antialiasingenabled") {
int aa = -1;
g_object_get(gtk_settings_get_default(), "gtk-xft-antialias", &aa, NULL);
result = reinterpret_cast<void*>(aa + 1);
} else if (res == "subpixeltype") {
GtkSettings *s = gtk_settings_get_default();
gchararray value;
g_object_get(s, "gtk-xft-rgba", &value, NULL);
QString qtVal = QString::fromUtf8(value);
g_free(value);
QFontEngine::SubpixelAntialiasingType type = QFontEngine::SubpixelAntialiasingType(-1);
if (qtVal == "none") {
type = QFontEngine::Subpixel_None;
} else if (qtVal == "rgb") {
type = QFontEngine::Subpixel_RGB;
} else if (qtVal == "bgr") {
type = QFontEngine::Subpixel_BGR;
} else if (qtVal == "vrgb") {
type = QFontEngine::Subpixel_VRGB;
} else if (qtVal == "vbgr") {
type = QFontEngine::Subpixel_VBGR;
}
result = reinterpret_cast<void*>(type + 1);
} else if (resource == "rootwindow") {
#ifdef GDK_WINDOWING_X11
static bool rootwin_warned = false;
if (!rootwin_warned) {
qWarning() << "X root window requested; this is experimental, and may not work well.";
rootwin_warned = true;
}
Display *dpy = nullptr;
xcb_screen_t *screen = nullptr;
if (GDK_IS_X11_DISPLAY(m_display)) {
dpy = gdk_x11_display_get_xdisplay(m_display);
xcb_connection_t *conn = XGetXCBConnection(dpy);
// use the first screen... hopefully this is okay? sigh...
screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
} else {
qWarning() << "Can't get root X window, GDK_BACKEND is not X11.";
}
result = reinterpret_cast<void*>(screen ? screen->root : 0);
#endif
} else {
qWarning() << "Unimplemented request for " << resource << " on " << screen;
}
return result;
}
void *QGtkIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
{
void *result = 0;
if (resource == "gtkwindow") {
return static_cast<QGtkWindow*>(window->handle())->gtkWindow().get();
}
qWarning() << "Unimplemented request for " << resource << " on " << window;
return result;
}
void *QGtkIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
{
void *result = 0;
if (!context->handle()) {
return result;
}
result = static_cast<QGtkOpenGLContext*>(context->handle())->nativeResource(resource);
if (!result) {
qWarning() << "Unimplemented request for " << resource << " on " << context;
}
return result;
}
QPlatformNativeInterface::NativeResourceForContextFunction QGtkIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
{
qWarning() << "Unimplemented request for " << resource;
return 0;
}
QPlatformWindow *QGtkIntegration::createPlatformWindow(QWindow *window) const
{
Q_UNUSED(window);
QGtkWindow *w = new QGtkWindow(window);
return w;
}
QPlatformBackingStore *QGtkIntegration::createPlatformBackingStore(QWindow *window) const
{
return new QGtkBackingStore(window);
}
QAbstractEventDispatcher *QGtkIntegration::createEventDispatcher() const
{
return new QGtkEventDispatcher;
}
QGtkIntegration *QGtkIntegration::instance()
{
return static_cast<QGtkIntegration *>(QGuiApplicationPrivate::platformIntegration());
}
#ifdef GDK_WINDOWING_WAYLAND
static EGLDisplay createWaylandEGLDisplay(wl_display *display)
{
eglBindAPI(EGL_OPENGL_API);
EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)display);
if (dpy == EGL_NO_DISPLAY) {
qWarning() << "eglGetDisplay failed";
return dpy;
}
if (!eglInitialize(dpy, NULL, NULL)) {
qWarning() << "eglInitialize failed";
return EGL_NO_DISPLAY;
}
return dpy;
}
#endif
EGLDisplay QGtkIntegration::eglDisplay() const
{
return m_eglDisplay;
}
QT_END_NAMESPACE
================================================
FILE: src/platform-plugin/qgtkintegration.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QPLATFORMINTEGRATION_GTK_H
#define QPLATFORMINTEGRATION_GTK_H
#include "qgtkservices.h"
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformscreen.h>
#include <QtCore/qscopedpointer.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
typedef void *EGLDisplay;
QT_BEGIN_NAMESPACE
class QTouchDevice;
class QGtkScreen;
class QGtkClipboard;
class QGtkIntegration : public QPlatformIntegration, public QPlatformNativeInterface
{
public:
explicit QGtkIntegration(const QStringList ¶meters);
~QGtkIntegration();
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
bool hasCapability(QPlatformIntegration::Capability cap) const override;
QPlatformFontDatabase *fontDatabase() const override;
QPlatformClipboard *clipboard() const override;
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
QPlatformServices *services() const override;
QPlatformNativeInterface *nativeInterface() const override;
// QPlatformNativeInterface
void *nativeResourceForIntegration(const QByteArray &resource) override;
void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
static QGtkIntegration *instance();
void onMonitorAdded(GdkMonitor *monitor);
void onMonitorRemoved(GdkMonitor *monitor);
GtkApplication *application() const;
EGLDisplay eglDisplay() const;
private:
QScopedPointer<QGtkServices> m_services;
QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
GdkDisplay *m_display;
QVector<const char*> m_arguments; /* must remain allocated for gdk's sake */
QVector<QGtkScreen*> m_screens;
QGtkClipboard *m_clipboard = nullptr;
EGLDisplay m_eglDisplay; // non-null for wayland platforms
};
QT_END_NAMESPACE
#endif
================================================
FILE: src/platform-plugin/qgtkmenu.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkwindow.h"
#include "qgtkmenu.h"
#include "qgtkmenuitem.h"
#include "qgtkhelpers.h"
#include <QtGui/qguiapplication.h>
#include <QtGui/qwindow.h>
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
Q_LOGGING_CATEGORY(lcMenu, "qt.qpa.gtk.menu");
QGtkMenu::QGtkMenu()
: m_tag((qintptr)this)
{
}
QGtkMenu::~QGtkMenu()
{
}
void QGtkMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
{
QGtkMenuItem *mi = static_cast<QGtkMenuItem*>(menuItem);
QGtkMenuItem *bi = static_cast<QGtkMenuItem*>(before);
int idx = m_items.indexOf(bi);
if (idx < 0) {
m_items.append(mi);
} else {
m_items.insert(idx, mi);
}
if (mi->menu()) {
connect(mi->menu(), &QGtkMenu::updated, this, &QGtkMenu::updated, Qt::UniqueConnection);
}
qCDebug(lcMenu) << "Added menu item " << mi << " before " << bi << " at " << idx;
Q_EMIT updated();
}
void QGtkMenu::removeMenuItem(QPlatformMenuItem *menuItem)
{
QGtkMenuItem *mi = static_cast<QGtkMenuItem*>(menuItem);
int idx = m_items.indexOf(mi);
m_items.removeAt(idx);
m_items.removeAll(0); // if it was deleted, remove those too.
if (mi->menu()) {
disconnect(mi->menu(), &QGtkMenu::updated, this, &QGtkMenu::updated);
}
Q_EMIT updated();
}
void QGtkMenu::syncMenuItem(QPlatformMenuItem *menuItem)
{
QGtkMenu *m = static_cast<QGtkMenuItem*>(menuItem)->menu();
if (m) {
connect(m, &QGtkMenu::updated, this, &QGtkMenu::updated, Qt::UniqueConnection);
}
Q_EMIT updated();
}
void QGtkMenu::syncSeparatorsCollapsible(bool enable)
{
Q_UNUSED(enable);
}
void QGtkMenu::setTag(quintptr tag)
{
m_tag = tag;
Q_EMIT updated();
}
quintptr QGtkMenu::tag()const
{
return m_tag;
}
void QGtkMenu::setText(const QString &text)
{
m_text = text;
Q_EMIT updated();
}
void QGtkMenu::setIcon(const QIcon &icon)
{
Q_UNUSED(icon);
}
void QGtkMenu::setEnabled(bool enabled)
{
m_enabled = enabled;
Q_EMIT updated();
}
bool QGtkMenu::isEnabled() const
{
return m_enabled;
}
void QGtkMenu::setVisible(bool visible)
{
//aboutToShow, aboutToHide signals
Q_UNUSED(visible);
m_visible = visible;
Q_EMIT updated();
}
void QGtkMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
{
Q_UNUSED(item);
if (m_popup) {
dismiss();
}
Q_EMIT aboutToShow();
QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height());
if (parentWindow)
pos = parentWindow->mapToGlobal(pos);
m_popup = gtkMenu();
GdkRectangle gRect { pos.x(), pos.y(), targetRect.width(), targetRect.height() };
gtk_menu_popup_at_rect(
m_popup.get(),
gtk_widget_get_window(static_cast<QGtkWindow*>(parentWindow->handle())->gtkWindow().get()),
&gRect,
GdkGravity(GDK_GRAVITY_NORTH_WEST),
GdkGravity(GDK_GRAVITY_NORTH_WEST),
NULL
);
connect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QGtkMenu::dismiss);
}
void QGtkMenu::dismiss()
{
Q_EMIT aboutToHide();
if (m_popup) {
gtk_menu_popdown(m_popup.get());
gtk_widget_destroy(GTK_WIDGET(m_popup.get()));
m_popup = nullptr;
}
disconnect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QGtkMenu::dismiss);
}
QPlatformMenuItem *QGtkMenu::menuItemAt(int position) const
{
int idx = 0;
while (position >= 0 && idx < m_items.size()) {
if (m_items.at(idx)) {
position--;
}
idx++;
}
if (idx >= 0 && idx < m_items.size())
return m_items.at(idx);
return nullptr;
}
QPlatformMenuItem *QGtkMenu::menuItemForTag(quintptr tag) const
{
for (QGtkMenuItem *item : qAsConst(m_items)) {
if (item && item->tag() == tag) {
return item;
}
}
return nullptr;
}
QGtkRefPtr<GtkMenuItem> QGtkMenu::gtkMenuItem() const
{
QGtkRefPtr<GtkMenuItem> mi = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(qt_convertToGtkMnemonics(m_text).toUtf8().constData()));
gtk_menu_item_set_submenu(mi.get(), GTK_WIDGET(gtkMenu().get()));
gtk_widget_set_sensitive(GTK_WIDGET(mi.get()), m_enabled);
gtk_widget_set_visible(GTK_WIDGET(mi.get()), m_visible);
return mi;
}
QGtkRefPtr<GtkMenu> QGtkMenu::gtkMenu() const
{
QGtkRefPtr<GtkMenu> menu = GTK_MENU(gtk_menu_new());
for (QGtkMenuItem *i : m_items) {
if (i)
gtk_menu_shell_append(GTK_MENU_SHELL(menu.get()), i->gtkMenuItem().get());
}
return menu;
}
QVector<QPointer<QGtkMenuItem>> QGtkMenu::items() const
{
return m_items;
}
================================================
FILE: src/platform-plugin/qgtkmenu.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QGTKMENU_H
#define QGTKMENU_H
#include "qgtkrefptr.h"
#include <qpa/qplatformmenu.h>
#include <gtk/gtk.h>
QT_BEGIN_NAMESPACE
class QGtkMenuItem;
class QGtkMenu : public QPlatformMenu
{
Q_OBJECT
public:
QGtkMenu();
~QGtkMenu();
void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override;
void removeMenuItem(QPlatformMenuItem *menuItem) override;
void syncMenuItem(QPlatformMenuItem *menuItem) override;
void syncSeparatorsCollapsible(bool enable) override;
void setTag(quintptr tag) override;
quintptr tag()const override;
void setText(const QString &text) override;
void setIcon(const QIcon &icon) override;
void setEnabled(bool enabled) override;
bool isEnabled() const override;
void setVisible(bool visible) override;
void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override;
void dismiss() override;
QPlatformMenuItem *menuItemAt(int position) const override;
QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
QGtkRefPtr<GtkMenu> gtkMenu() const;
QGtkRefPtr<GtkMenuItem> gtkMenuItem() const;
QVector<QPointer<QGtkMenuItem>> items() const;
Q_SIGNALS:
void updated();
private:
QVector<QPointer<QGtkMenuItem>> m_items;
QGtkRefPtr<GtkMenu> m_popup = nullptr;
bool m_enabled = true;
bool m_visible = true;
QString m_text;
qintptr m_tag;
};
QT_END_NAMESPACE
#endif // QGTKMENU_H
================================================
FILE: src/platform-plugin/qgtkmenubar.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkmenubar.h"
#include "qgtkmenu.h"
#include "qgtkmenuitem.h"
#include "qgtkwindow.h"
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
Q_LOGGING_CATEGORY(lcMenuBar, "qt.qpa.gtk.menubar");
QGtkMenuBar::QGtkMenuBar()
{
connect(this, &QGtkMenuBar::updated, this, &QGtkMenuBar::queueRegenerate);
}
QGtkMenuBar::~QGtkMenuBar()
{
}
void QGtkMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
{
QGtkMenu *m = static_cast<QGtkMenu*>(menu);
QGtkMenu *b = static_cast<QGtkMenu*>(before);
Q_ASSERT(m && !m_items.contains(m));
Q_ASSERT(!b || m_items.contains(b));
int idx = m_items.indexOf(b);
qCDebug(lcMenuBar) << "Inserting menu " << m << idx;
if (idx < 0) {
m_items.append(m);
} else {
m_items.insert(idx, m);
}
connect(m, &QGtkMenu::updated, this, &QGtkMenuBar::queueRegenerate);
syncMenu(menu);
Q_EMIT updated();
}
void QGtkMenuBar::removeMenu(QPlatformMenu *menu)
{
QGtkMenu *m = static_cast<QGtkMenu*>(menu);
int idx = m_items.indexOf(m);
Q_ASSERT(idx >= 0);
qCDebug(lcMenuBar) << "Removing menu " << m_items.at(idx) << idx;
m_items.removeAt(idx);
m_items.removeAll(0); // if it was deleted, remove nulls too.
disconnect(m, &QGtkMenu::updated, this, &QGtkMenuBar::queueRegenerate);
Q_EMIT updated();
}
void QGtkMenuBar::syncMenu(QPlatformMenu *menuItem)
{
QGtkMenu *menu = static_cast<QGtkMenu*>(menuItem);
for (QGtkMenuItem *item : menu->items()) {
if (item)
menu->syncMenuItem(item);
}
}
void QGtkMenuBar::queueRegenerate()
{
if (m_regenerateQueued) {
return;
}
QMetaObject::invokeMethod(this, "regenerate", Qt::QueuedConnection);
m_regenerateQueued = true;
}
void QGtkMenuBar::regenerate()
{
m_regenerateQueued = false;
GtkContainer *omb = GTK_CONTAINER(m_menubar.get());
GList *children = gtk_container_get_children(omb);
for (GList *iter = children; iter != NULL; iter = g_list_next(iter)) {
GtkWidget *menuChild = (GtkWidget*)iter->data;
gtk_container_remove(omb, menuChild);
}
g_list_free(children);
for (QGtkMenu *menu : m_items) {
if (menu)
gtk_menu_shell_append(GTK_MENU_SHELL(m_menubar.get()), GTK_WIDGET(menu->gtkMenuItem().get()));
}
}
void QGtkMenuBar::handleReparent(QWindow *newParentWindow)
{
QGtkRefPtr<GtkMenuBar> oldMenuBar = m_menubar;
if (!newParentWindow) {
m_menubar.reset(nullptr);
} else {
QGtkWindow *w = static_cast<QGtkWindow*>(newParentWindow->handle());
if (!w) {
// force creation of pwin
newParentWindow->create();
}
w = static_cast<QGtkWindow*>(newParentWindow->handle());
m_menubar = w->gtkMenuBar();
}
if (oldMenuBar) {
GtkContainer *omb = GTK_CONTAINER(oldMenuBar.get());
GtkContainer *nmb = GTK_CONTAINER(m_menubar.get());
GList *children = gtk_container_get_children(omb);
for (GList *iter = children; iter != NULL; iter = g_list_next(iter)) {
GtkWidget *menuChild = (GtkWidget*)iter->data;
g_object_ref(menuChild); // temporaray ref, to save it past remove()
gtk_container_remove(omb, menuChild);
if (m_menubar.get()) {
gtk_container_add(nmb, menuChild);
}
g_object_unref(menuChild);
}
g_list_free(children);
}
}
QPlatformMenu *QGtkMenuBar::menuForTag(quintptr tag) const
{
for (QGtkMenu *menu : qAsConst(m_items)) {
if (menu && menu->tag() == tag) {
return menu;
}
}
return nullptr;
}
QPlatformMenu *QGtkMenuBar::createMenu() const
{
return new QGtkMenu;
}
================================================
FILE: src/platform-plugin/qgtkmenubar.h
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef QGTKMENUBAR_H
#define QGTKMENUBAR_H
#include "qgtkrefptr.h"
#include <qpa/qplatformmenu.h>
#include <gtk/gtk.h>
QT_BEGIN_NAMESPACE
class QGtkMenu;
class QGtkMenuBar : public QPlatformMenuBar
{
Q_OBJECT
public:
QGtkMenuBar();
~QGtkMenuBar();
void insertMenu(QPlatformMenu *menu, QPlatformMenu *before) override;
void removeMenu(QPlatformMenu *menu) override;
void syncMenu(QPlatformMenu *menuItem) override;
void handleReparent(QWindow *newParentWindow) override;
QPlatformMenu *menuForTag(quintptr tag) const override;
QPlatformMenu *createMenu() const override;
Q_SIGNALS:
void updated();
private Q_SLOTS:
void queueRegenerate();
void regenerate();
private:
QGtkRefPtr<GtkMenuBar> m_menubar;
QVector<QPointer<QGtkMenu>> m_items;
bool m_regenerateQueued = false;
};
QT_END_NAMESPACE
#endif // QGTKMENUBAR
================================================
FILE: src/platform-plugin/qgtkmenuitem.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Contact: https://www.crimson.no
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qgtkmenuitem.h"
#include "qgtkhelpers.h"
#include "qgtkmenu.h"
#include <QtCore/qdebug.h>
static void select_cb(GtkMenuItem *, gpointer qgtkMenuItem)
{
QGtkMenuItem *gm = static_cast<QGtkMenuItem*>(qgtkMenuItem);
gm->emitSelect();
}
static void activate_cb(GtkMenuItem *, gpointer qgtkMenuItem)
{
QGtkMenuItem *gm = static_cast<QGtkMenuItem*>(qgtkMenuItem);
gm->emitActivate();
}
QGtkMenuItem::QGtkMenuItem()
: m_tag((qintptr)this)
{
}
QGtkMenuItem::~QGtkMenuItem()
{
}
void QGtkMenuItem::setTag(quintptr tag)
{
m_tag = tag;
Q_EMIT updated();
}
quintptr QGtkMenuItem::tag()const
{
return m_tag;
}
void QGtkMenuItem::setText(const QString &text)
{
m_text = qt_convertToGtkMnemonics(text);
Q_EMIT updated();
}
void QGtkMenuItem::setIcon(const QIcon &icon)
{
Q_UNUSED(icon);
}
void QGtkMenuItem::setMenu(QPlatformMenu *pmenu)
{
QGtkMenu *childMenu = static_cast<QGtkMenu*>(pmenu);
m_childMenu = childMenu;
Q_EMIT updated();
}
void QGtkMenuItem::setVisible(bool isVisible)
{
m_visible = isVisible;
Q_EMIT updated();
}
void QGtkMenuItem::setIsSeparator(bool isSeparator)
{
m_isSeparator = isSeparator;
Q_EMIT updated();
}
void QGtkMenuItem::setFont(const QFont &font)
{
Q_UNUSED(font);
}
void QGtkMenuItem::setRole(MenuRole role)
{
Q_UNUSED(role);
}
void QGtkMenuItem::setCheckable(bool checkable)
{
m_checkable = checkable;
Q_EMIT updated();
}
void QGtkMenuItem::setChecked(bool isChecked)
{
m_checked = isChecked;
Q_EMIT updated();
}
void QGtkMenuItem::setShortcut(const QKeySequence& shortcut)
{
m_shortcut = shortcut;
Q_EMIT updated();
}
void QGtkMenuItem::setEnabled(bool enabled)
{
m_enabled = enabled;
Q_EMIT updated();
}
void QGtkMenuItem::setIconSize(int size)
{
Q_UNUSED(size);
}
void QGtkMenuItem::setNativeContents(WId item)
{
Q_UNUSED(item);
}
void QGtkMenuItem::setHasExclusiveGroup(bool hasExclusiveGroup)
{
m_hasExclusiveGroup = hasExclusiveGroup;
Q_EMIT updated();
}
QGtkRefPtr<GtkWidget> QGtkMenuItem::gtkMenuItem() const
{
QGtkRefPtr<GtkWidget> ret;
if (m_isSeparator) {
ret = gtk_separator_menu_item_new();
} else if (m_childMenu) {
QGtkRefPtr<GtkMenuItem> mi = m_childMenu->gtkMenuItem();
//g_signal_connect(mi, "select", G_CALLBACK(select_cb), const_cast<QGtkMenuItem*>(this));
//g_signal_connect(mi, "activate", G_CALLBACK(activate_cb), const_cast<QGtkMenuItem*>(this));
// stick our title on it
GtkWidget *child = gtk_bin_get_child(GTK_BIN(mi.get()));
gtk_label_set_markup_with_mnemonic(GTK_LABEL(child), m_text.toUtf8().constData());
gtk_widget_set_sensitive(GTK_WIDGET(mi.get()), m_enabled);
ret = GTK_WIDGET(mi.get());
} else {
GtkWidget *mi = nullptr;
if (m_checkable) {
mi = gtk_check_menu_item_new_with_mnemonic(m_text.toUtf8().constData());
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), m_checked);
} else {
mi = gtk_menu_item_new_with_mnemonic(m_text.toUtf8().constData());
}
if (GTK_IS_CHECK_MENU_ITEM(mi)) {
g_object_set(mi, "draw-as-radio", m_hasExclusiveGroup, NULL);
}
gtk_widget_set_sensitive(mi, m_enabled);
g_signal_connect(mi, "select", G_CALLBACK(select_cb), const_cast<QGtkMenuItem*>(this));
g_signal_connect(mi, "activate", G_CALLBACK(activate_cb), const_cast<QGtkMenuItem*>(this));
GtkWidget *label = gtk_bin_get_child(GTK_BIN(mi));
Qt::KeyboardModifiers qtMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
// Only attempt to map top level shortcuts. GTK+ accels only take a
// single key, but QKeySequence can take multiple-- to overcome this
// mismatch, we map the simple key sequences (and their modifiers), but
// don't even attempt to try map more complex sequences.
if (m_shortcut[1] == 0 && m_shortcut[2] == 0 && m_shortcut[3] == 0) {
guint gKey = qt_convertToGdkKeyval(Qt::Key(m_shortcut[0] & ~qtMods));
guint gModifiers = 0;
if (m_shortcut[0] & Qt::ShiftModifier) {
gModifiers |= GDK_SHIFT_MASK;
}
if (m_shortcut
gitextract_lr58kn4j/ ├── .gitignore ├── LICENSE ├── README.md ├── examples/ │ ├── examples.pro │ └── gtkextras/ │ ├── gtkextras.pro │ └── headerbar/ │ ├── headerbar.pro │ └── main.cpp ├── gtkplatform.pro ├── src/ │ ├── gtkextras/ │ │ ├── gtkextras.pro │ │ ├── qgtkextrasglobal.h │ │ ├── qgtkheaderbar.cpp │ │ ├── qgtkheaderbar.h │ │ └── qgtkrefptr.h │ ├── platform-plugin/ │ │ ├── CSystrace.cpp │ │ ├── CSystrace.h │ │ ├── CTraceMessages.h │ │ ├── gtk.json │ │ ├── main.cpp │ │ ├── platform-plugin.pro │ │ ├── qgtk3dialoghelpers.cpp │ │ ├── qgtk3dialoghelpers.h │ │ ├── qgtkbackingstore.cpp │ │ ├── qgtkbackingstore.h │ │ ├── qgtkclipboard.cpp │ │ ├── qgtkclipboard.h │ │ ├── qgtkcursor.cpp │ │ ├── qgtkcursor.h │ │ ├── qgtkeventdispatcher.cpp │ │ ├── qgtkeventdispatcher.h │ │ ├── qgtkhelpers.cpp │ │ ├── qgtkhelpers.h │ │ ├── qgtkintegration.cpp │ │ ├── qgtkintegration.h │ │ ├── qgtkmenu.cpp │ │ ├── qgtkmenu.h │ │ ├── qgtkmenubar.cpp │ │ ├── qgtkmenubar.h │ │ ├── qgtkmenuitem.cpp │ │ ├── qgtkmenuitem.h │ │ ├── qgtkopenglcontext.cpp │ │ ├── qgtkopenglcontext.h │ │ ├── qgtkopenglcontext_wayland.cpp │ │ ├── qgtkopenglcontext_x11.cpp │ │ ├── qgtkscreen.cpp │ │ ├── qgtkscreen.h │ │ ├── qgtkservices.cpp │ │ ├── qgtkservices.h │ │ ├── qgtksystemtrayicon.cpp │ │ ├── qgtksystemtrayicon.h │ │ ├── qgtktheme.cpp │ │ ├── qgtktheme.h │ │ ├── qgtkwindow.cpp │ │ ├── qgtkwindow.h │ │ ├── qgtkwindow_gesture.cpp │ │ ├── qgtkwindow_keyboard.cpp │ │ ├── qgtkwindow_mouse.cpp │ │ ├── qgtkwindow_render.cpp │ │ └── qgtkwindow_touch.cpp │ └── src.pro └── sync.profile
SYMBOL INDEX (197 symbols across 37 files)
FILE: examples/gtkextras/headerbar/main.cpp
class TestWindow (line 38) | class TestWindow : public QWidget
method TestWindow (line 41) | TestWindow()
function main (line 58) | int main(int argc, char **argv)
FILE: src/gtkextras/qgtkheaderbar.cpp
class QGtkHeaderBar::QGtkHeaderBarPrivate (line 36) | class QGtkHeaderBar::QGtkHeaderBarPrivate
function GtkWidget (line 94) | GtkWidget *QGtkHeaderBar::headerBarWidget() const
FILE: src/gtkextras/qgtkheaderbar.h
function Q_GTKEXTRAS_EXPORT (line 38) | Q_GTKEXTRAS_EXPORT QGtkHeaderBar : public QObject
FILE: src/gtkextras/qgtkrefptr.h
function QT_BEGIN_NAMESPACE (line 33) | QT_BEGIN_NAMESPACE
FILE: src/platform-plugin/CSystrace.cpp
type CTracerThreadData (line 56) | struct CTracerThreadData
type CTracerGlobalData (line 83) | struct CTracerGlobalData
type timespec (line 95) | struct timespec
function gettid (line 101) | static int gettid()
function advance_chunk (line 112) | static void advance_chunk(int len)
function submit_chunk (line 125) | static void submit_chunk()
function getMicroseconds (line 149) | static uint64_t getMicroseconds()
function systrace_debug (line 162) | static void systrace_debug()
function ensure_chunk (line 188) | static void ensure_chunk(int mlen)
function systrace_init (line 240) | __attribute__((constructor)) void systrace_init()
function systrace_deinit (line 266) | __attribute__((destructor)) void systrace_deinit()
function systrace_should_trace (line 275) | int systrace_should_trace(const char *module)
function getStringId (line 283) | static uint64_t getStringId(const char *string)
function systrace_duration_begin (line 306) | void systrace_duration_begin(const char *module, const char *tracepoint)
function systrace_duration_end (line 325) | void systrace_duration_end(const char *module, const char *tracepoint)
function systrace_duration_begin (line 344) | void systrace_duration_begin(CSystraceEvent &event)
function systrace_duration_end (line 353) | void systrace_duration_end(CSystraceEvent &event)
function systrace_record_counter (line 373) | void systrace_record_counter(const char *module, const char *tracepoint,...
function systrace_async_begin (line 405) | void systrace_async_begin(const char *module, const char *tracepoint, co...
function systrace_async_end (line 425) | void systrace_async_end(const char *module, const char *tracepoint, cons...
FILE: src/platform-plugin/CSystrace.h
type CSystraceEvent (line 28) | struct CSystraceEvent
function systrace_init (line 30) | inline void systrace_init() {}
function systrace_deinit (line 31) | inline void systrace_deinit() {}
function systrace_should_trace (line 32) | inline int systrace_should_trace(const char *) { return 0; }
function systrace_duration_begin (line 33) | inline void systrace_duration_begin(const char *, const char *) {}
function systrace_duration_end (line 34) | inline void systrace_duration_end(const char *, const char *) {}
function systrace_duration_begin (line 35) | inline void systrace_duration_begin(CSystraceEvent &) {}
function systrace_duration_end (line 36) | inline void systrace_duration_end(CSystraceEvent &) {}
function systrace_async_begin (line 38) | inline void systrace_async_begin(const char *, const char *, const void ...
function systrace_async_end (line 39) | inline void systrace_async_end(const char *, const char *, const void *) {}
type CSystraceEvent (line 41) | struct CSystraceEvent
function CSystraceAsyncEvent (line 153) | struct SYSTRACE_EXPORT CSystraceAsyncEvent
FILE: src/platform-plugin/CTraceMessages.h
type class (line 38) | enum class
type ChunkHeader (line 54) | struct ChunkHeader
type BaseMessage (line 66) | struct BaseMessage
function BaseMessage (line 71) | struct RegisterStringMessage : public BaseMessage
function BaseMessage (line 78) | struct RegularMessage : public BaseMessage
function RegularMessage (line 85) | struct BeginMessage : public RegularMessage
function RegularMessage (line 89) | struct EndMessage : public RegularMessage
function RegularMessage (line 93) | struct DurationMessage : public RegularMessage
function RegularMessage (line 98) | struct AsyncBeginMessage : public RegularMessage
function RegularMessage (line 103) | struct AsyncEndMessage : public RegularMessage
function RegularMessage (line 108) | struct CounterMessage : public RegularMessage
function CounterMessage (line 113) | struct CounterMessageWithId : public CounterMessage
FILE: src/platform-plugin/main.cpp
function QT_BEGIN_NAMESPACE (line 30) | QT_BEGIN_NAMESPACE
function QPlatformIntegration (line 40) | QPlatformIntegration *QGtkIntegrationPlugin::create(const QString& syste...
FILE: src/platform-plugin/qgtk3dialoghelpers.cpp
function QT_BEGIN_NAMESPACE (line 59) | QT_BEGIN_NAMESPACE
function GtkDialog (line 78) | GtkDialog *QGtk3Dialog::gtkDialog() const
function QColor (line 194) | QColor QGtk3ColorDialogHelper::currentColor() const
function QUrl (line 276) | QUrl QGtk3FileDialogHelper::directory() const
function QString (line 335) | QString QGtk3FileDialogHelper::selectedNameFilter() const
function GtkFileChooserAction (line 368) | static GtkFileChooserAction gtkFileChooserAction(const QSharedPointer<QF...
function QString (line 492) | static QString qt_fontToString(const QFont &font)
function QFont (line 533) | static QFont qt_fontFromString(const QString &name)
function QFont (line 564) | QFont QGtk3FontDialogHelper::currentFont() const
FILE: src/platform-plugin/qgtk3dialoghelpers.h
function class (line 57) | class QGtk3Dialog : public QWindow
FILE: src/platform-plugin/qgtkbackingstore.cpp
function QPaintDevice (line 52) | QPaintDevice *QGtkBackingStore::paintDevice()
function QImage (line 57) | QImage QGtkBackingStore::toImage() const
FILE: src/platform-plugin/qgtkclipboard.cpp
type TargetTypes (line 36) | enum TargetTypes {
function QGtkClipboardData (line 54) | QGtkClipboardData *QGtkClipboard::mimeForMode(QClipboard::Mode mode) const
function QMimeData (line 66) | QMimeData *QGtkClipboard::mimeData(QClipboard::Mode mode)
function getFun (line 131) | static void getFun(GtkClipboard *, GtkSelectionData *selection_data, gui...
function clearFun (line 137) | static void clearFun(GtkClipboard*, gpointer gtkClipboardData)
function QMimeData (line 217) | QMimeData *QGtkClipboardData::mimeData() const
FILE: src/platform-plugin/qgtkclipboard.h
function ownsMode (line 46) | bool ownsMode() const;
FILE: src/platform-plugin/qgtkcursor.cpp
function QPoint (line 132) | QPoint QGtkCursor::pos() const
FILE: src/platform-plugin/qgtkcursor.h
function class (line 38) | class QGtkCursor : public QPlatformCursor
FILE: src/platform-plugin/qgtkeventdispatcher.cpp
function QT_BEGIN_NAMESPACE (line 56) | QT_BEGIN_NAMESPACE
type GSocketNotifierSource (line 64) | struct GSocketNotifierSource
function gboolean (line 70) | static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
function gboolean (line 77) | static gboolean socketNotifierSourceCheck(GSource *source)
function gboolean (line 100) | static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFun...
type GTimerSource (line 126) | struct GTimerSource
function gboolean (line 134) | static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
function gboolean (line 145) | static gboolean timerSourceCheckHelper(GTimerSource *src)
function gboolean (line 157) | static gboolean timerSourcePrepare(GSource *source, gint *timeout)
function gboolean (line 173) | static gboolean timerSourceCheck(GSource *source)
function gboolean (line 181) | static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
type GIdleTimerSource (line 200) | struct GIdleTimerSource
function gboolean (line 206) | static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
function gboolean (line 220) | static gboolean idleTimerSourceCheck(GSource *source)
function gboolean (line 231) | static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gp...
type GPostEventSource (line 247) | struct GPostEventSource
function gboolean (line 255) | static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
function gboolean (line 276) | static gboolean postEventSourceCheck(GSource *source)
function gboolean (line 281) | static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
type GUserEventSource (line 304) | struct GUserEventSource
function gboolean (line 310) | static gboolean userEventSourcePrepare(GSource *s, gint *timeout)
function gboolean (line 318) | static gboolean userEventSourceCheck(GSource *source)
function gboolean (line 323) | static gboolean userEventSourceDispatch(GSource *source, GSourceFunc, gp...
FILE: src/platform-plugin/qgtkeventdispatcher.h
type GMainContext (line 44) | typedef struct _GMainContext GMainContext;
function Q_OBJECT (line 52) | Q_OBJECT
FILE: src/platform-plugin/qgtkhelpers.cpp
function qt_imageToPixbuf (line 29) | QGtkRefPtr<GdkPixbuf> qt_imageToPixbuf(const QImage &cimage)
function qt_pixmapToPixbuf (line 59) | QGtkRefPtr<GdkPixbuf> qt_pixmapToPixbuf(const QPixmap &pixmap)
function QImage (line 65) | QImage qt_pixbufToImage(const QGtkRefPtr<GdkPixbuf> &pixbuf)
function QImage (line 83) | QImage qt_getBiggestImageForIcon(const QIcon &icon)
function qt_iconToPixbuf (line 112) | QGtkRefPtr<GdkPixbuf> qt_iconToPixbuf(const QIcon &icon)
function qt_iconToIcon (line 119) | QGtkRefPtr<GIcon> qt_iconToIcon(const QIcon &icon)
function QString (line 128) | QString qt_convertToGtkMnemonics(const QString &text)
function qt_convertToQtKeyboardMods (line 134) | Qt::KeyboardModifiers qt_convertToQtKeyboardMods(guint mask)
function qt_convertToQtKey (line 163) | Qt::Key qt_convertToQtKey(int keyval)
function guint (line 647) | guint qt_convertToGdkKeyval(Qt::Key qKey)
function qt_convertGButtonToQButton (line 711) | Qt::MouseButton qt_convertGButtonToQButton(guint button)
function qt_convertToQtTouchPointState (line 803) | Qt::TouchPointState qt_convertToQtTouchPointState(GdkEventType type)
function cairo_region_t (line 818) | cairo_region_t *qt_convertToCairoRegion(const QRegion ®ion)
FILE: src/platform-plugin/qgtkintegration.cpp
function monitor_added (line 68) | void monitor_added(GdkDisplay *, GdkMonitor *monitor, gpointer integration)
function monitor_removed (line 74) | void monitor_removed(GdkDisplay *, GdkMonitor *monitor, gpointer integra...
function QPlatformOpenGLContext (line 200) | QPlatformOpenGLContext *QGtkIntegration::createPlatformOpenGLContext(QOp...
function QPlatformClipboard (line 230) | QPlatformClipboard *QGtkIntegration::clipboard() const
function QPlatformFontDatabase (line 239) | QPlatformFontDatabase *QGtkIntegration::fontDatabase() const
function QStringList (line 244) | QStringList QGtkIntegration::themeNames() const
function QPlatformTheme (line 249) | QPlatformTheme *QGtkIntegration::createPlatformTheme(const QString &name...
function QPlatformServices (line 256) | QPlatformServices *QGtkIntegration::services() const
function QPlatformNativeInterface (line 261) | QPlatformNativeInterface *QGtkIntegration::nativeInterface() const
function QPlatformWindow (line 398) | QPlatformWindow *QGtkIntegration::createPlatformWindow(QWindow *window) ...
function QPlatformBackingStore (line 405) | QPlatformBackingStore *QGtkIntegration::createPlatformBackingStore(QWind...
function QAbstractEventDispatcher (line 410) | QAbstractEventDispatcher *QGtkIntegration::createEventDispatcher() const
function QGtkIntegration (line 415) | QGtkIntegration *QGtkIntegration::instance()
function EGLDisplay (line 421) | static EGLDisplay createWaylandEGLDisplay(wl_display *display)
function EGLDisplay (line 440) | EGLDisplay QGtkIntegration::eglDisplay() const
FILE: src/platform-plugin/qgtkmenu.cpp
function quintptr (line 99) | quintptr QGtkMenu::tag()const
function QPlatformMenuItem (line 173) | QPlatformMenuItem *QGtkMenu::menuItemAt(int position) const
function QPlatformMenuItem (line 187) | QPlatformMenuItem *QGtkMenu::menuItemForTag(quintptr tag) const
FILE: src/platform-plugin/qgtkmenubar.cpp
function QPlatformMenu (line 150) | QPlatformMenu *QGtkMenuBar::menuForTag(quintptr tag) const
function QPlatformMenu (line 161) | QPlatformMenu *QGtkMenuBar::createMenu() const
FILE: src/platform-plugin/qgtkmenubar.h
function class (line 40) | class QGtkMenuBar : public QPlatformMenuBar
FILE: src/platform-plugin/qgtkmenuitem.cpp
function select_cb (line 33) | static void select_cb(GtkMenuItem *, gpointer qgtkMenuItem)
function activate_cb (line 39) | static void activate_cb(GtkMenuItem *, gpointer qgtkMenuItem)
function quintptr (line 61) | quintptr QGtkMenuItem::tag()const
FILE: src/platform-plugin/qgtkmenuitem.h
function class (line 37) | class QGtkMenuItem : public QPlatformMenuItem
FILE: src/platform-plugin/qgtkopenglcontext.cpp
function QSurfaceFormat (line 94) | QSurfaceFormat QGtkOpenGLContext::format() const
function GLuint (line 99) | GLuint QGtkOpenGLContext::defaultFramebufferObject(QPlatformSurface *sur...
FILE: src/platform-plugin/qgtkopenglcontext_wayland.cpp
function QSurfaceFormat (line 104) | static QSurfaceFormat qgtk_wayland_update_format(const QSurfaceFormat &r...
function QFunctionPointer (line 197) | QFunctionPointer QGtkWaylandContext::getProcAddress(const char *procName)
function EGLContext (line 220) | EGLContext QGtkWaylandContext::eglContext() const
function EGLDisplay (line 225) | EGLDisplay QGtkWaylandContext::eglDisplay() const
function EGLConfig (line 230) | EGLConfig QGtkWaylandContext::eglConfig() const
FILE: src/platform-plugin/qgtkopenglcontext_x11.cpp
function updateFormatFromContext (line 46) | static void updateFormatFromContext(QSurfaceFormat &format)
function QFunctionPointer (line 206) | QFunctionPointer QGtkX11Context::getProcAddress(const char *procName)
FILE: src/platform-plugin/qgtkscreen.cpp
function QRect (line 47) | QRect QGtkScreen::availableGeometry() const
function QRect (line 62) | QRect QGtkScreen::geometry() const
function QSizeF (line 87) | QSizeF QGtkScreen::physicalSize() const
function QDpi (line 92) | QDpi QGtkScreen::logicalDpi() const
function qreal (line 105) | qreal QGtkScreen::devicePixelRatio() const
function qreal (line 110) | qreal QGtkScreen::refreshRate() const
function QPlatformCursor (line 116) | QPlatformCursor *QGtkScreen::cursor() const
FILE: src/platform-plugin/qgtkscreen.h
function class (line 40) | class QGtkScreen : public QPlatformScreen
FILE: src/platform-plugin/qgtkservices.cpp
function QByteArray (line 69) | QByteArray QGtkServices::desktopEnvironment() const
FILE: src/platform-plugin/qgtksystemtrayicon.cpp
function QRect (line 63) | QRect QGtkSystemTrayIcon::geometry() const
function action_cb (line 68) | void action_cb(NotifyNotification*, gchar *, gpointer gtkSystemTrayIcon)
FILE: src/platform-plugin/qgtktheme.cpp
function QPlatformMenuItem (line 58) | QPlatformMenuItem* QGtkTheme::createPlatformMenuItem() const
function QPlatformMenu (line 63) | QPlatformMenu* QGtkTheme::createPlatformMenu() const
function QPlatformMenuBar (line 68) | QPlatformMenuBar* QGtkTheme::createPlatformMenuBar() const
function QPlatformSystemTrayIcon (line 74) | QPlatformSystemTrayIcon *QGtkTheme::createPlatformSystemTrayIcon() const
function QPlatformDialogHelper (line 93) | QPlatformDialogHelper *QGtkTheme::createPlatformDialogHelper(DialogType ...
function QPalette (line 108) | const QPalette *QGtkTheme::palette(Palette type) const
function QFont (line 113) | const QFont *QGtkTheme::font(Font type) const
function QPixmap (line 143) | QPixmap QGtkTheme::standardPixmap(StandardPixmap sp, const QSizeF &size)...
function QIcon (line 148) | static QIcon fileIconForFile(const QFileInfo &fi)
function QIcon (line 169) | QIcon QGtkTheme::fileIcon(const QFileInfo &fileInfo,
function QPixmap (line 175) | QPixmap QGtkTheme::fileIconPixmap(const QFileInfo &fileInfo,
function QVariant (line 186) | QVariant QGtkTheme::themeHint(ThemeHint hint) const
function QString (line 208) | QString QGtkTheme::standardButtonText(int button) const
FILE: src/platform-plugin/qgtktheme.h
function class (line 33) | class QGtkTheme : public QPlatformTheme
FILE: src/platform-plugin/qgtkwindow.cpp
function gboolean (line 41) | static gboolean map_cb(GtkWidget *, gpointer platformWindow)
function gboolean (line 49) | static gboolean unmap_cb(GtkWidget *, gpointer platformWindow)
function gboolean (line 57) | static gboolean configure_cb(GtkWidget *, GdkEvent *, gpointer platformW...
function gboolean (line 65) | static gboolean size_allocate_cb(GtkWidget *, GdkRectangle *, gpointer p...
function gboolean (line 73) | static gboolean delete_cb(GtkWidget *, GdkEvent *, gpointer platformWindow)
function gboolean (line 80) | static gboolean key_press_cb(GtkWidget *, GdkEvent *event, gpointer plat...
function gboolean (line 87) | static gboolean key_release_cb(GtkWidget *, GdkEvent *event, gpointer pl...
function gboolean (line 94) | static gboolean button_press_cb(GtkWidget *, GdkEvent *event, gpointer p...
function gboolean (line 101) | static gboolean button_release_cb(GtkWidget *, GdkEvent *event, gpointer...
function gboolean (line 108) | static gboolean touch_event_cb(GtkWidget *, GdkEvent *event, gpointer pl...
function gboolean (line 115) | static gboolean motion_notify_cb(GtkWidget *, GdkEvent *event, gpointer ...
function gboolean (line 122) | static gboolean scroll_cb(GtkWidget *, GdkEvent *event, gpointer platfor...
function gboolean (line 129) | static gboolean window_state_event_cb(GtkWidget *, GdkEvent *event, gpoi...
function gboolean (line 137) | static gboolean enter_leave_window_notify_cb(GtkWidget *, GdkEvent *even...
function gboolean (line 146) | static gboolean leave_content_notify_cb(GtkWidget *, GdkEvent *, gpointe...
function QSurfaceFormat (line 399) | QSurfaceFormat QGtkWindow::format() const
function QRect (line 437) | QRect QGtkWindow::geometry() const
function QRect (line 442) | QRect QGtkWindow::normalGeometry() const
function qreal (line 447) | qreal QGtkWindow::devicePixelRatio() const
function QMargins (line 453) | QMargins QGtkWindow::frameMargins() const
function WId (line 674) | WId QGtkWindow::winId() const
FILE: src/platform-plugin/qgtkwindow.h
function qreal (line 55) | qreal devicePixelRatio() const;
FILE: src/platform-plugin/qgtkwindow_gesture.cpp
function populateTsAndPoint (line 36) | static void populateTsAndPoint(GtkGesture *gesture, guint32 &ts, QPointF...
FILE: src/platform-plugin/qgtkwindow_render.cpp
function gboolean (line 110) | gboolean QGtkWindow::windowTickCallback(GtkWidget*, GdkFrameClock *, gpo...
function QImage (line 198) | QImage *QGtkWindow::beginUpdateFrame(const QString &reason)
function QImage (line 217) | QImage QGtkWindow::currentFrameImage() const
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (334K chars).
[
{
"path": ".gitignore",
"chars": 46,
"preview": ".qmake.*\n*.o\nMakefile\nmoc_*.cpp\nmoc_*.h\n*.moc\n"
},
{
"path": "LICENSE",
"chars": 232,
"preview": "The source code in this repository is available under the same terms as that of\nthe open source licenses Qt itself is av"
},
{
"path": "README.md",
"chars": 11120,
"preview": "# introduction\n\ngtkplatform is a Qt Platform Abstraction plugin providing Qt applications with\nthe capability to use gtk"
},
{
"path": "examples/examples.pro",
"chars": 40,
"preview": "TEMPLATE = subdirs\nSUBDIRS += gtkextras\n"
},
{
"path": "examples/gtkextras/gtkextras.pro",
"chars": 46,
"preview": "TEMPLATE = subdirs\nSUBDIRS += \\\n headerbar\n"
},
{
"path": "examples/gtkextras/headerbar/headerbar.pro",
"chars": 275,
"preview": "QT += widgets gui-private gtkextras\n\nTEMPLATE = app\nTARGET = testheaderbar\nINCLUDEPATH += ../src\n\n# Input\nSOURCES += mai"
},
{
"path": "examples/gtkextras/headerbar/main.cpp",
"chars": 2376,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "gtkplatform.pro",
"chars": 15,
"preview": "load(qt_parts)\n"
},
{
"path": "src/gtkextras/gtkextras.pro",
"chars": 300,
"preview": "TARGET = QtGtkExtras\nQT -= gui\nQT += widgets gui-private\n\nHEADERS += \\\n qgtkrefptr.h \\\n qgtkheaderbar.h\n\nSOURCES +"
},
{
"path": "src/gtkextras/qgtkextrasglobal.h",
"chars": 1697,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2018 Crimson AS <info@"
},
{
"path": "src/gtkextras/qgtkheaderbar.cpp",
"chars": 3305,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2018 Crimson AS <info@"
},
{
"path": "src/gtkextras/qgtkheaderbar.h",
"chars": 1798,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2018 Crimson AS <info@"
},
{
"path": "src/gtkextras/qgtkrefptr.h",
"chars": 2751,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/CSystrace.cpp",
"chars": 14158,
"preview": "/*\n * Copyright (c) 2017 Crimson AS <info@crimson.no>\n * Author: Robin Burchell <robin.burchell@crimson.no>\n *\n * Permis"
},
{
"path": "src/platform-plugin/CSystrace.h",
"chars": 6904,
"preview": "/*\n * Copyright (c) 2017 Crimson AS <info@crimson.no>\n * Author: Robin Burchell <robin.burchell@crimson.no>\n *\n * Permis"
},
{
"path": "src/platform-plugin/CTraceMessages.h",
"chars": 3163,
"preview": "/*\n * Copyright (c) 2017 Crimson AS <info@crimson.no>\n * Author: Robin Burchell <robin.burchell@crimson.no>\n *\n * Permis"
},
{
"path": "src/platform-plugin/gtk.json",
"chars": 22,
"preview": "{ \"Keys\": [ \"gtk\" ] }\n"
},
{
"path": "src/platform-plugin/main.cpp",
"chars": 1969,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/platform-plugin.pro",
"chars": 2310,
"preview": "TARGET = qgtk\n\n!gtkplatform-release {\n CONFIG -= release\n CONFIG += debug\n}\nQT += core-private gui-private widgets"
},
{
"path": "src/platform-plugin/qgtk3dialoghelpers.cpp",
"chars": 20304,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2016 The Qt Company Lt"
},
{
"path": "src/platform-plugin/qgtk3dialoghelpers.h",
"chars": 5269,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2016 The Qt Company Lt"
},
{
"path": "src/platform-plugin/qgtkbackingstore.cpp",
"chars": 5972,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkbackingstore.h",
"chars": 2452,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkclipboard.cpp",
"chars": 8423,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkclipboard.h",
"chars": 2706,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkcursor.cpp",
"chars": 4290,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkcursor.h",
"chars": 1770,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkeventdispatcher.cpp",
"chars": 22141,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2016 The Qt Company Lt"
},
{
"path": "src/platform-plugin/qgtkeventdispatcher.h",
"chars": 3738,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkhelpers.cpp",
"chars": 23126,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkhelpers.h",
"chars": 2194,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkintegration.cpp",
"chars": 14240,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkintegration.h",
"chars": 3767,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkmenu.cpp",
"chars": 6003,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkmenu.h",
"chars": 2845,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkmenubar.cpp",
"chars": 5092,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkmenubar.h",
"chars": 2223,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkmenuitem.cpp",
"chars": 6307,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkmenuitem.h",
"chars": 2857,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkopenglcontext.cpp",
"chars": 8150,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkopenglcontext.h",
"chars": 3651,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkopenglcontext_wayland.cpp",
"chars": 9032,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkopenglcontext_x11.cpp",
"chars": 8011,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkscreen.cpp",
"chars": 3590,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkscreen.h",
"chars": 2262,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkservices.cpp",
"chars": 2292,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkservices.h",
"chars": 1780,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtksystemtrayicon.cpp",
"chars": 3456,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtksystemtrayicon.h",
"chars": 2388,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtktheme.cpp",
"chars": 6143,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtktheme.h",
"chars": 2802,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow.cpp",
"chars": 29293,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow.h",
"chars": 7189,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow_gesture.cpp",
"chars": 8634,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow_keyboard.cpp",
"chars": 2834,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow_mouse.cpp",
"chars": 6316,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow_render.cpp",
"chars": 7836,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/platform-plugin/qgtkwindow_touch.cpp",
"chars": 5185,
"preview": "/****************************************************************************\n**\n** Copyright (C) 2017 Crimson AS <info@"
},
{
"path": "src/src.pro",
"chars": 146,
"preview": "TEMPLATE = subdirs\nSUBDIRS += \\\n gtkextras \\\n platform_plugin\n\nplatform_plugin.subdir = platform-plugin\nplatform_p"
},
{
"path": "sync.profile",
"chars": 86,
"preview": "%modules = (\n \"QtGtkExtras\" => \"$basedir/src/gtkextras\",\n);\n\n%moduleheaders = (\n);\n"
}
]
About this extraction
This page contains the full source code of the CrimsonAS/gtkplatform GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (311.8 KB), approximately 79.9k tokens, and a symbol index with 197 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.