gnome: add share screen

add ability to share part of screen via right click menu

Refs #66538

Change-Id: I2e31e9fa5b2b3f888be2501a6d2fb435c7fe85e2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d98ae83..5f79ab2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -160,6 +160,8 @@
    src/models/activeitemproxymodel.h
    src/models/activeitemproxymodel.cpp
    src/defines.h
+   src/video/xrectsel.h
+   src/video/xrectsel.c
 )
 
 # compile glib resource files to c code
diff --git a/src/video/video_widget.cpp b/src/video/video_widget.cpp
index e525107..981b989 100644
--- a/src/video/video_widget.cpp
+++ b/src/video/video_widget.cpp
@@ -38,6 +38,8 @@
 #include <video/devicemodel.h>
 #include <QtCore/QUrl>
 #include "../defines.h"
+#include <stdlib.h>
+#include "xrectsel.h"
 
 #define VIDEO_LOCAL_SIZE            150
 #define VIDEO_LOCAL_OPACITY_DEFAULT 150 /* out of 255 */
@@ -279,6 +281,38 @@
     Video::SourcesModel::instance()->switchTo(device);
 }
 
+static void
+switch_video_input_screen(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer user_data)
+{
+    unsigned x, y;
+    unsigned width, height;
+
+    /* try to get the dispaly or default to 0 */
+    QString display_env{getenv("DISPLAY")};
+    int display = 0;
+
+    if (!display_env.isEmpty()) {
+        auto list = display_env.split(":", QString::SkipEmptyParts);
+        /* should only be one display, so get the first one */
+        if (list.size() > 0) {
+            display = list.at(0).toInt();
+            g_debug("sharing screen from DISPLAY %d", display);
+        }
+    }
+
+    x = y = width = height = 0;
+
+    xrectsel(&x, &y, &width, &height);
+
+    if (!width || !height) {
+        x = y = 0;
+        width = gdk_screen_width();
+        height = gdk_screen_height();
+    }
+
+    Video::SourcesModel::instance()->setDisplay(display, QRect(x,y,width,height));
+}
+
 /*
  * on_button_press_in_screen_event()
  *
@@ -306,6 +340,11 @@
         g_signal_connect(item, "activate", G_CALLBACK(switch_video_input), device);
     }
 
+    /* add screen area as an input */
+    GtkWidget *item = gtk_check_menu_item_new_with_mnemonic("Share screen area");
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+    g_signal_connect(item, "activate", G_CALLBACK(switch_video_input_screen), NULL);
+
     /* show menu */
     gtk_widget_show_all(menu);
     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
diff --git a/src/video/xrectsel.c b/src/video/xrectsel.c
new file mode 100644
index 0000000..e629eb4
--- /dev/null
+++ b/src/video/xrectsel.c
@@ -0,0 +1,116 @@
+/*
+ * This code is based and adapted from:
+ * https://github.com/lolilolicon/FFcast2/blob/master/xrectsel.c
+ *
+ * now located at:
+ * https://github.com/lolilolicon/xrectsel/blob/master/xrectsel.c
+ *
+ * xrectsel.c -- print the geometry of a rectangular screen region.
+ * Copyright (C) 2011-2014 lolilolicon <lolilolicon@gmail.com>
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+xrectsel(unsigned *x_sel, unsigned *y_sel, unsigned *w_sel, unsigned *h_sel)
+{
+    Display *dpy = XOpenDisplay(NULL);
+    if (!dpy)
+        return;
+
+    Window root = DefaultRootWindow(dpy);
+
+    XEvent ev;
+
+    GC sel_gc;
+    XGCValues sel_gv;
+
+    int btn_pressed = 0;
+    int x = 0, y = 0;
+    unsigned int width = 0, height = 0;
+    int start_x = 0, start_y = 0;
+
+    Cursor cursor;
+    cursor = XCreateFontCursor(dpy, XC_crosshair);
+
+    /* Grab pointer for these events */
+    XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+            GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
+
+    sel_gv.function = GXinvert;
+    sel_gv.subwindow_mode = IncludeInferiors;
+    sel_gv.line_width = 1;
+    sel_gc = XCreateGC(dpy, root, GCFunction | GCSubwindowMode | GCLineWidth, &sel_gv);
+
+    for (;;) {
+        XNextEvent(dpy, &ev);
+
+        if (ev.type == ButtonPress) {
+            btn_pressed = 1;
+            x = start_x = ev.xbutton.x_root;
+            y = start_y = ev.xbutton.y_root;
+            width = height = 0;
+
+        } else if (ev.type == MotionNotify) {
+            if (!btn_pressed)
+                continue; /* Draw only if button is pressed */
+
+            /* Re-draw last Rectangle to clear it */
+            XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
+
+            x = ev.xbutton.x_root;
+            y = ev.xbutton.y_root;
+
+            if (x > start_x) {
+                width = x - start_x;
+                x = start_x;
+            } else {
+                width = start_x - x;
+            }
+
+            if (y > start_y) {
+                height = y - start_y;
+                y = start_y;
+            } else {
+                height = start_y - y;
+            }
+
+            /* Draw Rectangle */
+            XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
+            XFlush(dpy);
+
+        } else if (ev.type == ButtonRelease)
+            break;
+    }
+
+    /* Re-draw last Rectangle to clear it */
+    XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
+    XFlush(dpy);
+
+    XUngrabPointer(dpy, CurrentTime);
+    XFreeCursor(dpy, cursor);
+    XFreeGC(dpy, sel_gc);
+    XSync(dpy, 1);
+
+    *x_sel = x;
+    *y_sel = y;
+    *w_sel = width;
+    *h_sel = height;
+
+    XCloseDisplay(dpy);
+}
diff --git a/src/video/xrectsel.h b/src/video/xrectsel.h
new file mode 100644
index 0000000..5965fb5
--- /dev/null
+++ b/src/video/xrectsel.h
@@ -0,0 +1,31 @@
+/*
+ * This code is based and adapted from:
+ * https://github.com/lolilolicon/FFcast2/blob/master/xrectsel.c
+ *
+ * now located at:
+ * https://github.com/lolilolicon/xrectsel/blob/master/xrectsel.c
+ *
+ * xrectsel.c -- print the geometry of a rectangular screen region.
+ * Copyright (C) 2011-2014 lolilolicon <lolilolicon@gmail.com>
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XRECTSEL_H__
+#define __XRECTSEL_H__
+
+G_BEGIN_DECLS
+
+void xrectsel(unsigned *x_sel, unsigned *y_sel, unsigned *w_sel, unsigned *h_sel);
+
+G_END_DECLS
+
+#endif /* __XRECTSEL_H__ */
\ No newline at end of file