/* * Simple program to demonstrate 2 bugs with Compiz 0.8.2 and programs that use * _NET_WM_FULLSCREEN_MONITORS. This program will present a simple window with a * button and a label. The label will display a textual explanation of what * topology the window should be covering. The button allows the user to click * it and cycle through the 6 topologies over 2 monitors. * * The bugs this demonstrates are as follows: * 1) When an application requests a topology change via * _NET_WM_FULLSCREEN_MONITORS, Compiz does honor the topology change, but it * does not refresh any monitor that has changed since the last * _NET_WM_FULLSCREEN_MONITORS topology. If the application requests to * change from fullscreening monitor 1 to cover both monitors 1 and 2, the * window is resized and can still be interacted with, but the display still * shows a frozen image of what was previously on the second monitor, for * example. * * 2) When a window has fullscreened and used _NET_WM_FULLSCREEN_MONITORS, if * any tooltips are used in that window (as this simple application does), * Compiz will cause the screen to flash repeatedly until the user stops * hovering over the originating widget and the tooltip goes away. This can * be demonstrated in this simple application by hovering over the button in * the window. As an interesting aside, when Compiz causes the screen to * flash, it will refresh the monitors that were previously stale from #1 * above. * * This program can be compiled like this: * * gcc -Wall -g test_NET_WM_FULLSCREEN_MONITORS-wtf.c -o \ * test_NET_WM_FULLSCREEN_MONITORS `pkg-config --cflags gtk+-2.0` `pkg-config \ * --libs gtk+-2.0` */#include <gtk/gtk.h>#include <gdk/gdkx.h>#include <string.h>static GtkWidget* window;static GtkWidget* button;static GtkWidget* label;static guint topology;static gboolean fullscreen(){ gtk_window_fullscreen(GTK_WINDOW(window)); return FALSE;}static gboolean unfullscreen(){ gtk_window_unfullscreen(GTK_WINDOW(window)); return FALSE;}static gboolean switch_monitors(gpointer data){ static const long monitors[6][4] = { {0, 0, 0, 0}, {1, 1, 1, 1}, {0, 1, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 1}, {0, 1, 0, 1} }; static const char* desc[6] = { "Window should be covering just the first head, height: top/bottom of first head\n", "Window should be covering just the second head, height: top/bottom of second head\n", "Window should be covering just the first head, height: top of first head, bottom of second head\n", "Window should be covering just the first head, height: top of second head, bottom of second head\n", "Window should be covering both heads 1 and 2, height: top and bottom of first head\n", "Window should be covering both heads 1 and 2, height: top of first head, bottom of second head\n", }; guint index = GPOINTER_TO_UINT(data); g_debug("index: %d\n", index); if (index > 5) { unfullscreen(); gtk_label_set_text(GTK_LABEL(label), "Unfullscreened."); topology = 0; return FALSE; } else { fullscreen(); gtk_label_set_text(GTK_LABEL(label), desc[index]); } g_debug(desc[index]); GdkDisplay *display = gdk_display_get_default(); XClientMessageEvent xclient; memset(&xclient, 0, sizeof(xclient)); xclient.type = ClientMessage; xclient.window = GDK_WINDOW_XID(window->window); xclient.message_type = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WM_FULLSCREEN_MONITORS"); xclient.format = 32; xclient.data.l[0] = monitors[index][0]; xclient.data.l[1] = monitors[index][1]; xclient.data.l[2] = monitors[index][2]; xclient.data.l[3] = monitors[index][3]; xclient.data.l[4] = 1; XSendEvent(GDK_WINDOW_XDISPLAY(window->window), GDK_WINDOW_XWINDOW(gdk_get_default_root_window()), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *) &xclient); return FALSE;}static void close(GtkWidget *widget, gpointer data ){ gtk_main_quit ();}static void clicked(GtkWidget *widget, gpointer data ){ switch_monitors(GUINT_TO_POINTER(topology++));}int main(int argc, char** argv){ gtk_init(&argc, &argv); GtkWidget* box; topology = 0; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(close), NULL); g_signal_connect(G_OBJECT (window), "destroy", G_CALLBACK (close), NULL); gtk_container_set_border_width (GTK_CONTAINER (window), 10); button = gtk_button_new_with_label ("Push Me to change topologies!"); gtk_widget_show(button); g_signal_connect(G_OBJECT (button), "clicked", G_CALLBACK (clicked), NULL); label = gtk_label_new("I'll tell you what topology you're in here."); gtk_widget_show(label); box = gtk_vbox_new(FALSE, 10); gtk_widget_show(box); gtk_container_add(GTK_CONTAINER(window), box); gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(GTK_WIDGET(button), "This is a tooltip!"); gtk_widget_show(window); gtk_main(); return 0;}