Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to record other X displays #74

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 2 additions & 57 deletions aclocal.m4
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
[m4_warning([this file was generated for autoconf 2.69.
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
[m4_warning([this file was generated for autoconf 2.68.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
Expand Down Expand Up @@ -180,61 +180,6 @@ else
fi[]dnl
])# PKG_CHECK_MODULES


# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
[with_pkgconfigdir=]pkg_default)
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_INSTALLDIR


# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([noarch-pkgconfigdir],
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
[with_noarch_pkgconfigdir=]pkg_default)
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR


# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl

_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])

AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR

# Copyright (C) 2002-2013 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
Expand Down
16 changes: 14 additions & 2 deletions src/AV/Input/X11Input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ along with SimpleScreenRecorder. If not, see <http://www.gnu.org/licenses/>.

#include <X11/Xutil.h>
#include <X11/extensions/Xfixes.h>
#include <QByteArray>

/*
The code in this file is based on the MIT-SHM example code and the x11grab device in libav/ffmpeg (which is GPL):
Expand Down Expand Up @@ -167,8 +168,15 @@ static void X11ImageDrawCursor(Display* dpy, XImage* image, int recording_area_x

}

X11Input::X11Input(unsigned int x, unsigned int y, unsigned int width, unsigned int height, bool record_cursor, bool follow_cursor) {
X11Input::X11Input(const QString& display_name, unsigned int x, unsigned int y, unsigned int width, unsigned int height, bool record_cursor, bool follow_cursor) {

if(display_name=="this"){
m_x11_display_name = NULL;
} else {
m_x11_display_name = new char[display_name.length()+1];
QByteArray ba = display_name.toAscii();
strcpy(m_x11_display_name, ba.data());
}
m_x = x;
m_y = y;
m_width = width;
Expand Down Expand Up @@ -221,7 +229,7 @@ void X11Input::Init() {

// do the X11 stuff
// we need a separate display because the existing one would interfere with what Qt is doing in some cases
m_x11_display = XOpenDisplay(NULL); //QX11Info::display();
m_x11_display = XOpenDisplay(m_x11_display_name); //QX11Info::display();
if(m_x11_display == NULL) {
Logger::LogError("[X11Input::Init] " + QObject::tr("Error: Can't open X display!", "Don't translate 'display'"));
throw X11Exception();
Expand Down Expand Up @@ -301,6 +309,10 @@ void X11Input::Free() {
XCloseDisplay(m_x11_display);
m_x11_display = NULL;
}
if(m_x11_display_name != NULL) {
delete m_x11_display_name;
m_x11_display_name = NULL;
}
}

void X11Input::UpdateScreenConfiguration() {
Expand Down
3 changes: 2 additions & 1 deletion src/AV/Input/X11Input.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class X11Input : public QObject, public VideoSource {
unsigned int m_x, m_y, m_width, m_height;
bool m_record_cursor, m_follow_cursor;

char *m_x11_display_name;
Display *m_x11_display;
int m_x11_screen;
Qt::HANDLE m_x11_root;
Expand All @@ -53,7 +54,7 @@ class X11Input : public QObject, public VideoSource {
std::atomic<uint32_t> m_frame_counter;

public:
X11Input(unsigned int x, unsigned int y, unsigned int width, unsigned int height, bool record_cursor, bool follow_cursor);
X11Input(const QString& display_name, unsigned int x, unsigned int y, unsigned int width, unsigned int height, bool record_cursor, bool follow_cursor);
~X11Input();

// Returns the total number of captured frames.
Expand Down
90 changes: 66 additions & 24 deletions src/GUI/PageInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ along with SimpleScreenRecorder. If not, see <http://www.gnu.org/licenses/>.

#include "Global.h"
#include "PageInput.h"
#include "Utils.h"

#include "MainWindow.h"

Expand Down Expand Up @@ -78,13 +79,17 @@ PageInput::PageInput(MainWindow* main_window)
{
m_buttongroup_video_area = new QButtonGroup(group_video);
QRadioButton *radio_area_screen = new QRadioButton(tr("Record the entire screen"), group_video);
QRadioButton *radio_area_fixed = new QRadioButton(tr("Record a fixed rectangle"), group_video);
QRadioButton *radio_area_cursor = new QRadioButton(tr("Follow the cursor"), group_video);
QRadioButton *radio_area_fixed = new QRadioButton(tr("Record a fixed rectangle"), group_video);
QRadioButton *radio_area_cursor = new QRadioButton(tr("Follow the cursor"), group_video);
QRadioButton *radio_area_other_x = new QRadioButton(tr("Record a fixed rectangle on another X server"), group_video);
QRadioButton *radio_area_glinject = new QRadioButton(tr("Record OpenGL (experimental)"), group_video);
m_buttongroup_video_area->addButton(radio_area_screen, VIDEO_AREA_SCREEN);
m_buttongroup_video_area->addButton(radio_area_fixed, VIDEO_AREA_FIXED);
m_buttongroup_video_area->addButton(radio_area_cursor, VIDEO_AREA_CURSOR);
m_buttongroup_video_area->addButton(radio_area_fixed, VIDEO_AREA_FIXED);
m_buttongroup_video_area->addButton(radio_area_cursor, VIDEO_AREA_CURSOR);
m_buttongroup_video_area->addButton(radio_area_other_x, VIDEO_AREA_OTHER_X);
m_buttongroup_video_area->addButton(radio_area_glinject, VIDEO_AREA_GLINJECT);
m_lineedit_display_name = new QLineEdit(group_video);
m_lineedit_display_name->setToolTip(tr("X server display name."));
m_combobox_screens = new QComboBoxWithSignal(group_video);
m_combobox_screens->setToolTip(tr("Select what monitor should be recorded in a multi-monitor configuration."));
m_pushbutton_video_select_rectangle = new QPushButton(tr("Select rectangle..."), group_video);
Expand Down Expand Up @@ -140,7 +145,8 @@ PageInput::PageInput(MainWindow* main_window)
connect(m_combobox_screens, SIGNAL(activated(int)), this, SLOT(OnUpdateVideoAreaFields()));
connect(m_combobox_screens, SIGNAL(popupShown()), this, SLOT(OnIdentifyScreens()));
connect(m_combobox_screens, SIGNAL(popupHidden()), this, SLOT(OnStopIdentifyScreens()));
connect(m_spinbox_video_x, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
connect(m_lineedit_display_name, SIGNAL(textChanged(QString)), this, SLOT(OnUpdateVideoAreaFields()));
connect(m_spinbox_video_x, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
connect(m_spinbox_video_x, SIGNAL(focusOut()), this, SLOT(OnUpdateRecordingFrame()));
connect(m_spinbox_video_x, SIGNAL(valueChanged(int)), this, SLOT(OnUpdateRecordingFrame()));
connect(m_spinbox_video_y, SIGNAL(focusIn()), this, SLOT(OnUpdateRecordingFrame()));
Expand All @@ -166,7 +172,13 @@ PageInput::PageInput(MainWindow* main_window)
}
layout->addWidget(radio_area_fixed);
layout->addWidget(radio_area_cursor);
layout->addWidget(radio_area_glinject);
{
QHBoxLayout *layout2 = new QHBoxLayout();
layout->addLayout(layout2);
layout2->addWidget(radio_area_other_x);
layout2->addWidget(m_lineedit_display_name);
}
layout->addWidget(radio_area_glinject);
{
QHBoxLayout *layout2 = new QHBoxLayout();
layout->addLayout(layout2);
Expand Down Expand Up @@ -201,8 +213,8 @@ PageInput::PageInput(MainWindow* main_window)
layout2->addWidget(m_spinbox_video_scaled_w, 0, 1);
layout2->addWidget(m_label_video_scaled_h, 0, 2);
layout2->addWidget(m_spinbox_video_scaled_h, 0, 3);
}
layout->addWidget(m_checkbox_record_cursor);
}
layout->addWidget(m_checkbox_record_cursor);
}
QGroupBox *group_audio = new QGroupBox(tr("Audio input"), this);
{
Expand Down Expand Up @@ -291,6 +303,7 @@ void PageInput::LoadSettings(QSettings* settings) {
#endif

// load settings
SetDisplayNameGui(settings->value("input_display_name", ":0").toString());
SetVideoArea((enum_video_area) settings->value("input/video_area", VIDEO_AREA_SCREEN).toUInt());
SetVideoAreaScreen(settings->value("input/video_area_screen", 0).toUInt());
SetVideoX(settings->value("input/video_x", 0).toUInt());
Expand Down Expand Up @@ -324,7 +337,8 @@ void PageInput::LoadSettings(QSettings* settings) {
}

void PageInput::SaveSettings(QSettings* settings) {
settings->setValue("input/video_area", GetVideoArea());
settings->setValue("input/video_display_name", GetDisplayNameGui());
settings->setValue("input/video_area", GetVideoArea());
settings->setValue("input/video_area_screen", GetVideoAreaScreen());
settings->setValue("input/video_x", GetVideoX());
settings->setValue("input/video_y", GetVideoY());
Expand Down Expand Up @@ -606,13 +620,15 @@ void PageInput::LoadPulseAudioSources() {

void PageInput::OnUpdateRecordingFrame() {
if(m_spinbox_video_x->hasFocus() || m_spinbox_video_y->hasFocus() || m_spinbox_video_w->hasFocus() || m_spinbox_video_h->hasFocus()) {
if(m_recording_frame == NULL) {
m_recording_frame.reset(new QRubberBand(QRubberBand::Rectangle));
m_recording_frame->setGeometry(ValidateRubberBandRectangle(QRect(GetVideoX(), GetVideoY(), GetVideoW(), GetVideoH())));
m_recording_frame->show();
} else {
m_recording_frame->setGeometry(ValidateRubberBandRectangle(QRect(GetVideoX(), GetVideoY(), GetVideoW(), GetVideoH())));
}
if(GetVideoArea() != VIDEO_AREA_OTHER_X) {
if(m_recording_frame == NULL) {
m_recording_frame.reset(new QRubberBand(QRubberBand::Rectangle));
m_recording_frame->setGeometry(ValidateRubberBandRectangle(QRect(GetVideoX(), GetVideoY(), GetVideoW(), GetVideoH())));
m_recording_frame->show();
} else {
m_recording_frame->setGeometry(ValidateRubberBandRectangle(QRect(GetVideoX(), GetVideoY(), GetVideoW(), GetVideoH())));
}
}
} else {
m_recording_frame.reset();
}
Expand All @@ -623,8 +639,9 @@ void PageInput::OnUpdateVideoAreaFields() {
case VIDEO_AREA_SCREEN: {
m_combobox_screens->setEnabled(true);
m_pushbutton_video_select_rectangle->setEnabled(false);
m_pushbutton_video_select_window->setEnabled(false);
m_pushbutton_video_opengl_settings->setEnabled(false);
m_pushbutton_video_select_window->setEnabled(false);
m_pushbutton_video_opengl_settings->setEnabled(false);
m_lineedit_display_name->setEnabled(false);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y,
m_label_video_w, m_spinbox_video_w, m_label_video_h, m_spinbox_video_h}, false);
int sc = m_combobox_screens->currentIndex();
Expand All @@ -641,36 +658,61 @@ void PageInput::OnUpdateVideoAreaFields() {
SetVideoY(rect.top());
SetVideoW(rect.width());
SetVideoH(rect.height());
SetDisplayName("this");
break;
}
}

case VIDEO_AREA_OTHER_X: {
m_combobox_screens->setEnabled(false);
m_pushbutton_video_select_rectangle->setEnabled(false);
m_pushbutton_video_select_window->setEnabled(false);
m_pushbutton_video_opengl_settings->setEnabled(false);
m_lineedit_display_name->setEnabled(true);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y,
m_label_video_w, m_spinbox_video_w, m_label_video_h, m_spinbox_video_h}, true);
SetVideoX(0);
SetVideoY(0);
int w,h;
getDisplaySize(m_lineedit_display_name->text(), &w, &h); // TODO
if(w>0) SetVideoW(w);
if(h>0) SetVideoH(h);
SetDisplayName(m_lineedit_display_name->text()); //TODO
break;
}
case VIDEO_AREA_FIXED: {
m_combobox_screens->setEnabled(false);
m_pushbutton_video_select_rectangle->setEnabled(true);
m_pushbutton_video_select_window->setEnabled(true);
m_pushbutton_video_opengl_settings->setEnabled(false);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y,
m_lineedit_display_name->setEnabled(false);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y,
m_label_video_w, m_spinbox_video_w, m_label_video_h, m_spinbox_video_h}, true);
SetDisplayName("this");
break;
}
case VIDEO_AREA_CURSOR: {
m_combobox_screens->setEnabled(false);
m_pushbutton_video_select_rectangle->setEnabled(true);
m_pushbutton_video_select_window->setEnabled(true);
m_pushbutton_video_opengl_settings->setEnabled(false);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y}, false);
m_lineedit_display_name->setEnabled(false);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y}, false);
GroupEnabled({m_label_video_w, m_spinbox_video_w, m_label_video_h, m_spinbox_video_h}, true);
SetVideoX(0);
SetVideoY(0);
break;
SetDisplayName("this");
break;
}
case VIDEO_AREA_GLINJECT: {
m_combobox_screens->setEnabled(false);
m_pushbutton_video_select_rectangle->setEnabled(false);
m_pushbutton_video_select_window->setEnabled(false);
m_pushbutton_video_opengl_settings->setEnabled(true);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y,
m_lineedit_display_name->setEnabled(false);
GroupEnabled({m_label_video_x, m_spinbox_video_x, m_label_video_y, m_spinbox_video_y,
m_label_video_w, m_spinbox_video_w, m_label_video_h, m_spinbox_video_h}, false);
break;
SetDisplayName("this");
break;
}
default: break;
}
Expand Down
15 changes: 11 additions & 4 deletions src/GUI/PageInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class PageInput : public QWidget {
VIDEO_AREA_FIXED,
VIDEO_AREA_CURSOR,
VIDEO_AREA_GLINJECT,
VIDEO_AREA_OTHER_X,
VIDEO_AREA_COUNT // must be last
};
enum enum_audio_backend {
Expand All @@ -87,6 +88,7 @@ class PageInput : public QWidget {
#endif

QString m_glinject_command, m_glinject_working_directory;
QString m_display_name;
bool m_glinject_run_command, m_glinject_relax_permissions;
unsigned int m_glinject_max_megapixels;
bool m_glinject_capture_front, m_glinject_limit_fps;
Expand All @@ -97,7 +99,8 @@ class PageInput : public QWidget {
QComboBoxWithSignal *m_combobox_screens;
QPushButton *m_pushbutton_video_select_rectangle, *m_pushbutton_video_select_window, *m_pushbutton_video_opengl_settings;
QLabel *m_label_video_x, *m_label_video_y, *m_label_video_w, *m_label_video_h;
QSpinBoxWithSignal *m_spinbox_video_x, *m_spinbox_video_y, *m_spinbox_video_w, *m_spinbox_video_h;
QLineEdit *m_lineedit_display_name;
QSpinBoxWithSignal *m_spinbox_video_x, *m_spinbox_video_y, *m_spinbox_video_w, *m_spinbox_video_h;
QSpinBox *m_spinbox_video_frame_rate;
QCheckBox *m_checkbox_scale;
QLabel *m_label_video_scaled_w, *m_label_video_scaled_h;
Expand Down Expand Up @@ -150,7 +153,9 @@ class PageInput : public QWidget {
#endif
inline QString GetGLInjectCommand() { return m_glinject_command; }
inline QString GetGLInjectWorkingDirectory() { return m_glinject_working_directory; }
inline bool GetGLInjectRunCommand() { return m_glinject_run_command; }
inline QString GetDisplayName() { return m_display_name; }
inline QString GetDisplayNameGui() { return m_lineedit_display_name->text(); }
inline bool GetGLInjectRunCommand() { return m_glinject_run_command; }
inline bool GetGLInjectRelaxPermissions() { return m_glinject_relax_permissions; }
inline unsigned int GetGLInjectMaxMegaPixels() { return m_glinject_max_megapixels; }
inline bool GetGLInjectCaptureFront() { return m_glinject_capture_front; }
Expand All @@ -174,8 +179,10 @@ class PageInput : public QWidget {
inline void SetPulseAudioSource(unsigned int source) { m_combobox_pulseaudio_source->setCurrentIndex(clamp(source, 0u, (unsigned int) m_pulseaudio_sources.size() - 1)); }
#endif
inline void SetGLInjectCommand(const QString& command) { m_glinject_command = command; }
inline void SetGLInjectWorkingDirectory(const QString& glinject_working_directory) { m_glinject_working_directory = glinject_working_directory; }
inline void SetGLInjectRunCommand(bool run_command) { m_glinject_run_command = run_command; }
inline void SetGLInjectWorkingDirectory(const QString& glinject_working_directory) { m_glinject_working_directory = glinject_working_directory; }
inline void SetDisplayName(const QString& display_name) { m_display_name = display_name; }
inline void SetDisplayNameGui(const QString& display_name) { m_lineedit_display_name->setText(display_name); }
inline void SetGLInjectRunCommand(bool run_command) { m_glinject_run_command = run_command; }
inline void SetGLInjectRelaxPermissions(bool relax_permissions) { m_glinject_relax_permissions = relax_permissions; }
inline void SetGLInjectMaxMegaPixels(unsigned int max_megapixels) { m_glinject_max_megapixels = clamp(max_megapixels, 1u, 100u); }
inline void SetGLInjectCaptureFront(bool capture_front) { m_glinject_capture_front = capture_front; }
Expand Down
3 changes: 2 additions & 1 deletion src/GUI/PageRecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ void PageRecord::StartPage() {
PageOutput *page_output = m_main_window->GetPageOutput();

// get the video input settings
m_x11_display_name = page_input->GetDisplayName();
m_video_area = page_input->GetVideoArea();
m_video_x = page_input->GetVideoX();
m_video_y = page_input->GetVideoY();
Expand Down Expand Up @@ -678,7 +679,7 @@ void PageRecord::StartInput() {
}
m_gl_inject_input.reset(new GLInjectInput(m_gl_inject_launcher.get()));
} else {
m_x11_input.reset(new X11Input(m_video_x, m_video_y, m_video_in_width, m_video_in_height, m_video_record_cursor, m_video_area == PageInput::VIDEO_AREA_CURSOR));
m_x11_input.reset(new X11Input(m_x11_display_name, m_video_x, m_video_y, m_video_in_width, m_video_in_height, m_video_record_cursor, m_video_area == PageInput::VIDEO_AREA_CURSOR));
}

// start the audio input
Expand Down
1 change: 1 addition & 0 deletions src/GUI/PageRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class PageRecord : public QWidget {
bool m_recorded_something;

PageInput::enum_video_area m_video_area;
QString m_x11_display_name;
unsigned int m_video_x, m_video_y, m_video_in_width, m_video_in_height;
unsigned int m_video_frame_rate;
bool m_video_scaling;
Expand Down
Loading