1 
2 #include <config.h>
3 
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include <gdk/gdkx.h>
9 #include <gtk/gtk.h>
10 
11 #include <glib/gi18n-lib.h>
12 
13 #include "xapp-monitor-blanker.h"
14 
15 /**
16  * SECTION:xapp-monitor-blanker
17  * @Short_description: Blank and unblank unused monitors
18  * @Title: XAppMonitorBlanker
19  *
20  * The XAppMonitorBlanker widget that creates one or more
21  * POPUP type GtkWindows that are used to blank unused
22  * monitors in multiple monitor setups.
23  */
24 
25 struct _XAppMonitorBlanker
26 {
27     GObject parent_instance;
28 
29     int num_outputs;
30     gboolean blanked;
31     GtkWidget **windows;
32 };
33 
34 G_DEFINE_TYPE (XAppMonitorBlanker, xapp_monitor_blanker, G_TYPE_OBJECT);
35 
36 static void
xapp_monitor_blanker_init(XAppMonitorBlanker * self)37 xapp_monitor_blanker_init (XAppMonitorBlanker *self)
38 {
39     self->num_outputs = 0;
40     self->blanked = FALSE;
41     self->windows = NULL;
42 }
43 
44 static void
xapp_monitor_blanker_finalize(GObject * object)45 xapp_monitor_blanker_finalize (GObject *object)
46 {
47     XAppMonitorBlanker *self = XAPP_MONITOR_BLANKER (object);
48 
49     if (self->windows != NULL)
50     {
51         xapp_monitor_blanker_unblank_monitors (XAPP_MONITOR_BLANKER (self));
52         g_free (self->windows);
53     }
54 
55     G_OBJECT_CLASS (xapp_monitor_blanker_parent_class)->finalize (object);
56 }
57 
58 static void
xapp_monitor_blanker_class_init(XAppMonitorBlankerClass * klass)59 xapp_monitor_blanker_class_init (XAppMonitorBlankerClass *klass)
60 {
61     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
62 
63     gobject_class->finalize = xapp_monitor_blanker_finalize;
64 
65 }
66 
67 /**
68  * xapp_monitor_blanker_new:
69  *
70  * Creates a new #XAppMonitorBlanker.
71  *
72  * Returns: a newly created #XAppMonitorBlanker
73  */
74 
75 XAppMonitorBlanker *
xapp_monitor_blanker_new(void)76 xapp_monitor_blanker_new (void)
77 {
78     return g_object_new (XAPP_TYPE_MONITOR_BLANKER, NULL);
79 }
80 
81 GtkWidget *
create_blanking_window(GdkScreen * screen,int monitor)82 create_blanking_window (GdkScreen *screen,
83                         int        monitor)
84 {
85     GdkRectangle fullscreen;
86     GtkWidget *window;
87     GtkStyleContext *context;
88     GtkCssProvider *provider;
89 
90     gdk_screen_get_monitor_geometry (screen, monitor, &fullscreen);
91 
92     window = gtk_window_new (GTK_WINDOW_POPUP);
93     gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
94     gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
95     gtk_window_resize (GTK_WINDOW (window), fullscreen.width, fullscreen.height);
96     gtk_window_move (GTK_WINDOW (window), fullscreen.x, fullscreen.y);
97     gtk_widget_set_visible (window, TRUE);
98 
99     context = gtk_widget_get_style_context (GTK_WIDGET (window));
100     gtk_style_context_add_class (context, "xapp-blanking-window");
101     provider = gtk_css_provider_new ();
102     gtk_css_provider_load_from_data (provider,
103                                      ".xapp-blanking-window { background-color: rgb(0, 0, 0); }",
104                                      -1, NULL);
105     gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
106 
107     return window;
108 }
109 
110 /**
111  * xapp_monitor_blanker_blank_other_monitors:
112  * @self: a #XAppMonitorBlanker
113  * @window: a #GtkWindow
114  *
115  * Blanks monitors besides the one where the @window is.
116  */
117 
118 void
xapp_monitor_blanker_blank_other_monitors(XAppMonitorBlanker * self,GtkWindow * window)119 xapp_monitor_blanker_blank_other_monitors (XAppMonitorBlanker *self,
120                                            GtkWindow          *window)
121 {
122     GdkScreen *screen;
123     int active_monitor;
124     int i;
125 
126     g_return_if_fail (XAPP_IS_MONITOR_BLANKER (self));
127 
128     if (self->windows != NULL)
129         return;
130 
131     screen = gtk_window_get_screen (window);
132     active_monitor = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET (window)));
133     self->num_outputs = gdk_screen_get_n_monitors (screen);
134     self->windows = g_new (GtkWidget *, self->num_outputs);
135 
136     for (i = 0; i < self->num_outputs; i++)
137     {
138         if (i != active_monitor)
139         {
140             self->windows[i] = create_blanking_window (screen, i);
141         }
142         else
143         {
144             // initialize at NULL so it gets properly skipped when windows get destroyed
145             self->windows[i] = NULL;
146         }
147     }
148 
149     self->blanked = TRUE;
150 }
151 
152 /**
153  * xapp_monitor_blanker_unblank_monitors:
154  * @self: a #XAppMonitorBlanker
155  *
156  * Unblanks monitors that were blanked by
157  * xapp_monitor_blanker_blank_other_monitors();
158  */
159 
160 void
xapp_monitor_blanker_unblank_monitors(XAppMonitorBlanker * self)161 xapp_monitor_blanker_unblank_monitors (XAppMonitorBlanker *self)
162 {
163     int i;
164     g_return_if_fail (XAPP_IS_MONITOR_BLANKER (self));
165 
166     if (self->windows == NULL)
167         return;
168 
169     for (i = 0; i < self->num_outputs; i++)
170     {
171         if (self->windows[i] != NULL)
172         {
173             gtk_widget_destroy (self->windows[i]);
174             self->windows[i] = NULL;
175         }
176     }
177     g_free (self->windows);
178     self->windows = NULL;
179     self->blanked = FALSE;
180 }
181 
182 /**
183  * xapp_monitor_blanker_are_monitors_blanked:
184  * @self: a #XAppMonitorBlanker
185  *
186  * Returns whether monitors are currently blanked.
187  * See xapp_monitor_blanker_blank_other_monitors().
188  *
189  * Returns: %TRUE if monitors are blanked.
190  */
191 
192 gboolean
xapp_monitor_blanker_are_monitors_blanked(XAppMonitorBlanker * self)193 xapp_monitor_blanker_are_monitors_blanked (XAppMonitorBlanker *self)
194 {
195     return self->blanked;
196 }
197