| 1701 gtk_widget_show(dirsel); |
1704 gtk_widget_show(dirsel); |
| 1702 |
1705 |
| 1703 return (void *)data; |
1706 return (void *)data; |
| 1704 } |
1707 } |
| 1705 |
1708 |
| |
1709 #ifdef USE_VV |
| |
1710 static GstElement *create_screensrc_cb(PurpleMedia *media, const gchar *session_id, |
| |
1711 const gchar *participant); |
| |
1712 |
| |
1713 #ifdef HAVE_X11 |
| |
1714 static gboolean |
| |
1715 grab_event (GtkWidget *child, GdkEvent *event, PidginRequestData *data) |
| |
1716 { |
| |
1717 GdkScreen *screen = gdk_screen_get_default(); |
| |
1718 GObject *info; |
| |
1719 GdkWindow *gdkroot = gdk_get_default_root_window(); |
| |
1720 Window xroot = GDK_WINDOW_XID(gdkroot), xwindow, parent, *children; |
| |
1721 unsigned int nchildren, xmask; |
| |
1722 Display *xdisplay = GDK_SCREEN_XDISPLAY(screen); |
| |
1723 int rootx, rooty, winx, winy; |
| |
1724 |
| |
1725 if (event->type != GDK_BUTTON_PRESS) |
| |
1726 return FALSE; |
| |
1727 |
| |
1728 XQueryPointer(xdisplay, xroot, &xroot, &xwindow, &rootx, &rooty, &winx, &winy, &xmask); |
| |
1729 |
| |
1730 gdk_pointer_ungrab(GDK_CURRENT_TIME); |
| |
1731 |
| |
1732 /* Find WM window (direct child of root) */ |
| |
1733 while (1) { |
| |
1734 if (!XQueryTree(xdisplay, xwindow, &xroot, &parent, &children, &nchildren)) |
| |
1735 break; |
| |
1736 |
| |
1737 if (nchildren) |
| |
1738 XFree(children); |
| |
1739 |
| |
1740 if (xroot == parent) |
| |
1741 break; |
| |
1742 |
| |
1743 xwindow = parent; |
| |
1744 } |
| |
1745 |
| |
1746 generic_response_start(data); |
| |
1747 |
| |
1748 if (data->cbs[0] != NULL) { |
| |
1749 info = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO, |
| |
1750 "id", "screenshare-window", |
| |
1751 "name", "Screen share single window", |
| |
1752 "type", PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC | |
| |
1753 PURPLE_MEDIA_ELEMENT_ONE_SRC, |
| |
1754 "create-cb", create_screensrc_cb, NULL); |
| |
1755 g_object_set_data(info, "window-id", GUINT_TO_POINTER(xwindow)); |
| |
1756 ((PurpleRequestScreenshareCb)data->cbs[0])(data->user_data, info); |
| |
1757 } |
| |
1758 |
| |
1759 purple_request_close(PURPLE_REQUEST_SCREENSHARE, data); |
| |
1760 |
| |
1761 return FALSE; |
| |
1762 } |
| |
1763 |
| |
1764 static void |
| |
1765 screenshare_window_cb(GtkWidget *button, PidginRequestData *data) |
| |
1766 { |
| |
1767 GdkCursor *cursor; |
| |
1768 GdkWindow *gdkwin = gtk_widget_get_window(GTK_WIDGET(data->dialog)); |
| |
1769 |
| |
1770 if (!GTK_WIDGET_HAS_FOCUS(button)) |
| |
1771 gtk_widget_grab_focus(button); |
| |
1772 |
| |
1773 gtk_widget_add_events(GTK_WIDGET(data->dialog), |
| |
1774 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); |
| |
1775 g_signal_connect(data->dialog, "event", G_CALLBACK(grab_event), data); |
| |
1776 |
| |
1777 cursor = gdk_cursor_new(GDK_CROSSHAIR); |
| |
1778 gdk_pointer_grab(gdkwin, FALSE, |
| |
1779 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK, |
| |
1780 NULL, cursor, GDK_CURRENT_TIME); |
| |
1781 } |
| |
1782 |
| |
1783 static GstElement *create_screensrc_cb(PurpleMedia *media, const gchar *session_id, |
| |
1784 const gchar *participant) |
| |
1785 { |
| |
1786 GObject *info; |
| |
1787 GstElement *ret; |
| |
1788 |
| |
1789 ret = gst_element_factory_make("ximagesrc", NULL); |
| |
1790 g_object_set(ret, "use-damage", 0, NULL); |
| |
1791 |
| |
1792 info = g_object_get_data(G_OBJECT(media), "src-element"); |
| |
1793 if (info) { |
| |
1794 Window xid = GPOINTER_TO_UINT(g_object_get_data(info, "window-id")); |
| |
1795 int monitor_no = GPOINTER_TO_INT(g_object_get_data(info, "monitor-no")); |
| |
1796 if (xid) { |
| |
1797 g_object_set(ret, "xid", xid, NULL); |
| |
1798 } else if (monitor_no >= 0) { |
| |
1799 GdkScreen *screen = gdk_screen_get_default(); |
| |
1800 GdkRectangle geom; |
| |
1801 |
| |
1802 gdk_screen_get_monitor_geometry(screen, monitor_no, &geom); |
| |
1803 g_object_set(ret, "startx", geom.x, "starty", geom.y, |
| |
1804 "endx", geom.x + geom.width - 1, |
| |
1805 "endy", geom.y + geom.height - 1, NULL); |
| |
1806 } |
| |
1807 } |
| |
1808 |
| |
1809 return ret; |
| |
1810 } |
| |
1811 #elif defined (_WIN32) |
| |
1812 static GstElement *create_screensrc_cb(PPurpleMedia *media, const gchar *session_id, |
| |
1813 const gchar *participant) |
| |
1814 { |
| |
1815 GObject *info; |
| |
1816 GstElement *ret; |
| |
1817 |
| |
1818 ret = gst_element_factory_make("gdiscreencapsrc", NULL); |
| |
1819 g_object_set(ret, "cursor", TRUE); |
| |
1820 |
| |
1821 info = g_object_get_data(G_OBJECT(media), "src-element"); |
| |
1822 if (info) { |
| |
1823 int monitor_no = GPOINTER_TO_INT(g_object_get_data(info, "monitor-no")); |
| |
1824 if (monitor_no >= 0) |
| |
1825 g_object_set(ret, "monitor", monitor_no); |
| |
1826 } |
| |
1827 |
| |
1828 return ret; |
| |
1829 } |
| |
1830 #else |
| |
1831 /* We don't actually need to break the build just because we can't do |
| |
1832 * screencap, but gtkmedia.c is going to break the USE_VV build if it |
| |
1833 * isn't WIN32 or X11 anyway, so we might as well. */ |
| |
1834 #error "Unsupported windowing system" |
| |
1835 #endif |
| |
1836 |
| |
1837 static void |
| |
1838 screenshare_monitor_cb(GtkWidget *button, PidginRequestData *data) |
| |
1839 { |
| |
1840 GtkWidget *radio; |
| |
1841 GObject *info; |
| |
1842 int monitor_no = -1; |
| |
1843 |
| |
1844 generic_response_start(data); |
| |
1845 |
| |
1846 if (!GTK_WIDGET_HAS_FOCUS(button)) |
| |
1847 gtk_widget_grab_focus(button); |
| |
1848 |
| |
1849 radio = g_object_get_data(G_OBJECT(data->dialog), "radio"); |
| |
1850 if (radio) { |
| |
1851 GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); |
| |
1852 |
| |
1853 while (group) { |
| |
1854 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group->data))) { |
| |
1855 monitor_no = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(group->data), |
| |
1856 "monitor-no")); |
| |
1857 break; |
| |
1858 } |
| |
1859 group = group->next; |
| |
1860 } |
| |
1861 } |
| |
1862 if (data->cbs[0] != NULL) { |
| |
1863 info = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO, |
| |
1864 "id", "screenshare-monitor", |
| |
1865 "name", "Screen share monitor", |
| |
1866 "type", PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC | |
| |
1867 PURPLE_MEDIA_ELEMENT_ONE_SRC, |
| |
1868 "create-cb", create_screensrc_cb, NULL); |
| |
1869 g_object_set_data(info, "monitor-no", GINT_TO_POINTER(monitor_no)); |
| |
1870 ((PurpleRequestScreenshareCb)data->cbs[0])(data->user_data, info); |
| |
1871 } |
| |
1872 |
| |
1873 purple_request_close(PURPLE_REQUEST_SCREENSHARE, data); |
| |
1874 } |
| |
1875 |
| |
1876 static GstElement *create_videotest_cb(PurpleMedia *media, const gchar *session_id, |
| |
1877 const gchar *participant) |
| |
1878 { |
| |
1879 return gst_element_factory_make("videotestsrc", NULL); |
| |
1880 } |
| |
1881 |
| |
1882 static void |
| |
1883 screenshare_videotest_cb(GtkWidget *button, PidginRequestData *data) |
| |
1884 { |
| |
1885 GObject *info; |
| |
1886 |
| |
1887 generic_response_start(data); |
| |
1888 |
| |
1889 if (!GTK_WIDGET_HAS_FOCUS(button)) |
| |
1890 gtk_widget_grab_focus(button); |
| |
1891 |
| |
1892 if (data->cbs[0] != NULL) { |
| |
1893 info = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO, |
| |
1894 "id", "screenshare-videotestsrc", |
| |
1895 "name", "Screen share test source", |
| |
1896 "type", PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC | |
| |
1897 PURPLE_MEDIA_ELEMENT_ONE_SRC, |
| |
1898 "create-cb", create_videotest_cb, NULL); |
| |
1899 ((PurpleRequestScreenshareCb)data->cbs[0])(data->user_data, info); |
| |
1900 } |
| |
1901 |
| |
1902 purple_request_close(PURPLE_REQUEST_SCREENSHARE, data); |
| |
1903 } |
| |
1904 |
| |
1905 static void |
| |
1906 screenshare_cancel_cb(GtkWidget *button, PidginRequestData *data) |
| |
1907 { |
| |
1908 generic_response_start(data); |
| |
1909 |
| |
1910 if (data->cbs[0] != NULL) |
| |
1911 ((PurpleRequestScreenshareCb)data->cbs[0])(data->user_data, NULL); |
| |
1912 |
| |
1913 purple_request_close(PURPLE_REQUEST_SCREENSHARE, data); |
| |
1914 } |
| |
1915 |
| |
1916 static gboolean |
| |
1917 destroy_screenshare_cb(GtkWidget *dialog, GdkEvent *event, |
| |
1918 PidginRequestData *data) |
| |
1919 { |
| |
1920 screenshare_cancel_cb(NULL, data); |
| |
1921 return FALSE; |
| |
1922 } |
| |
1923 |
| |
1924 static void *pidgin_request_screenshare_media(const char *title, const char *primary, |
| |
1925 const char *secondary, PurpleAccount *account, |
| |
1926 GCallback cb, void *user_data) |
| |
1927 { |
| |
1928 PidginRequestData *data; |
| |
1929 GtkWidget *dialog; |
| |
1930 GtkWidget *vbox; |
| |
1931 GtkWidget *hbox; |
| |
1932 GtkWidget *label; |
| |
1933 GtkWidget *button; |
| |
1934 GtkWidget *radio = NULL; |
| |
1935 GdkScreen *screen; |
| |
1936 char *label_text; |
| |
1937 char *primary_esc, *secondary_esc; |
| |
1938 |
| |
1939 data = g_new0(PidginRequestData, 1); |
| |
1940 data->type = PURPLE_REQUEST_SCREENSHARE; |
| |
1941 data->user_data = user_data; |
| |
1942 |
| |
1943 data->cb_count = 1; |
| |
1944 data->cbs = g_new0(GCallback, 1); |
| |
1945 data->cbs[0] = cb; |
| |
1946 |
| |
1947 /* Create the dialog. */ |
| |
1948 data->dialog = dialog = gtk_dialog_new(); |
| |
1949 |
| |
1950 if (title != NULL) |
| |
1951 gtk_window_set_title(GTK_WINDOW(dialog), title); |
| |
1952 #ifdef _WIN32 |
| |
1953 else |
| |
1954 gtk_window_set_title(GTK_WINDOW(dialog), PIDGIN_ALERT_TITLE); |
| |
1955 #endif |
| |
1956 |
| |
1957 button = pidgin_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, |
| |
1958 G_CALLBACK(screenshare_cancel_cb), data); |
| |
1959 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); |
| |
1960 |
| |
1961 if (g_getenv("PIDGIN_SHARE_VIDEOTEST") != NULL) { |
| |
1962 button = pidgin_dialog_add_button(GTK_DIALOG(dialog), _("Test image"), |
| |
1963 G_CALLBACK(screenshare_videotest_cb), data); |
| |
1964 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); |
| |
1965 gtk_window_set_default(GTK_WINDOW(dialog), button); |
| |
1966 } |
| |
1967 |
| |
1968 #ifdef HAVE_X11 |
| |
1969 button = pidgin_dialog_add_button(GTK_DIALOG(dialog), _("Select window"), |
| |
1970 G_CALLBACK(screenshare_window_cb), data); |
| |
1971 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); |
| |
1972 gtk_window_set_default(GTK_WINDOW(dialog), button); |
| |
1973 #endif |
| |
1974 |
| |
1975 button = pidgin_dialog_add_button(GTK_DIALOG(dialog), _("Use monitor"), |
| |
1976 G_CALLBACK(screenshare_monitor_cb), data); |
| |
1977 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); |
| |
1978 gtk_window_set_default(GTK_WINDOW(dialog), button); |
| |
1979 |
| |
1980 g_signal_connect(G_OBJECT(dialog), "delete_event", |
| |
1981 G_CALLBACK(destroy_screenshare_cb), data); |
| |
1982 |
| |
1983 /* Setup the dialog */ |
| |
1984 gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2); |
| |
1985 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2); |
| |
1986 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
| |
1987 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); |
| |
1988 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER); |
| |
1989 |
| |
1990 /* Setup the main horizontal box */ |
| |
1991 hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); |
| |
1992 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); |
| |
1993 |
| |
1994 |
| |
1995 /* Vertical box */ |
| |
1996 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); |
| |
1997 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); |
| |
1998 |
| |
1999 pidgin_widget_decorate_account(hbox, account); |
| |
2000 |
| |
2001 /* Descriptive label */ |
| |
2002 primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; |
| |
2003 secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL; |
| |
2004 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" |
| |
2005 "%s</span>%s%s" : "%s%s%s"), |
| |
2006 (primary ? primary_esc : ""), |
| |
2007 ((primary && secondary) ? "\n\n" : ""), |
| |
2008 (secondary ? secondary_esc : "")); |
| |
2009 g_free(primary_esc); |
| |
2010 g_free(secondary_esc); |
| |
2011 |
| |
2012 label = gtk_label_new(NULL); |
| |
2013 |
| |
2014 gtk_label_set_markup(GTK_LABEL(label), label_text); |
| |
2015 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
| |
2016 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); |
| |
2017 gtk_label_set_selectable(GTK_LABEL(label), TRUE); |
| |
2018 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); |
| |
2019 |
| |
2020 g_free(label_text); |
| |
2021 |
| |
2022 screen = gdk_screen_get_default(); |
| |
2023 if (screen) { |
| |
2024 int nr_monitors = gdk_screen_get_n_monitors(screen); |
| |
2025 int primary = gdk_screen_get_primary_monitor(screen); |
| |
2026 int i; |
| |
2027 |
| |
2028 for (i = 0; i < nr_monitors; i++) { |
| |
2029 GdkRectangle geom; |
| |
2030 gchar *name; |
| |
2031 gchar *label; |
| |
2032 |
| |
2033 name = gdk_screen_get_monitor_plug_name(screen, i); |
| |
2034 gdk_screen_get_monitor_geometry(screen, i, &geom); |
| |
2035 |
| |
2036 label = g_strdup_printf(_("%s (%d✕%d @ %d,%d)"), |
| |
2037 name ? name : _("Unknown output"), |
| |
2038 geom.width, geom.height, |
| |
2039 geom.x, geom.y); |
| |
2040 radio = gtk_radio_button_new_with_label_from_widget((GtkRadioButton *)radio, label); |
| |
2041 g_object_set_data(G_OBJECT(radio), "monitor-no", GINT_TO_POINTER(i)); |
| |
2042 gtk_box_pack_start(GTK_BOX(vbox), radio, FALSE, FALSE, 0); |
| |
2043 if (i == primary) |
| |
2044 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE); |
| |
2045 |
| |
2046 g_free(label); |
| |
2047 g_free(name); |
| |
2048 } |
| |
2049 g_object_set_data(G_OBJECT(dialog), "radio", radio); |
| |
2050 } |
| |
2051 |
| |
2052 /* Show everything. */ |
| |
2053 pidgin_auto_parent_window(dialog); |
| |
2054 |
| |
2055 gtk_widget_show_all(dialog); |
| |
2056 |
| |
2057 return data; |
| |
2058 |
| |
2059 } |
| |
2060 #endif /* USE_VV */ |
| |
2061 |
| 1706 static void |
2062 static void |
| 1707 pidgin_close_request(PurpleRequestType type, void *ui_handle) |
2063 pidgin_close_request(PurpleRequestType type, void *ui_handle) |
| 1708 { |
2064 { |
| 1709 PidginRequestData *data = (PidginRequestData *)ui_handle; |
2065 PidginRequestData *data = (PidginRequestData *)ui_handle; |
| 1710 |
2066 |