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