1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include "main.h"
23 #include "fullscreen.h"
24 
25 #include "image.h"
26 #include "misc.h"
27 #include "ui_fileops.h"
28 #include "ui_menu.h"
29 #include "ui_misc.h"
30 #include "window.h"
31 #include "image-load.h"
32 
33 enum {
34 	FULLSCREEN_CURSOR_HIDDEN = 1 << 0,
35 	FULLSCREEN_CURSOR_NORMAL = 1 << 1,
36 	FULLSCREEN_CURSOR_BUSY   = 1 << 2
37 };
38 
39 
40 /*
41  *----------------------------------------------------------------------------
42  * full screen functions
43  *----------------------------------------------------------------------------
44  */
45 
clear_mouse_cursor(GtkWidget * widget,gint state)46 static void clear_mouse_cursor(GtkWidget *widget, gint state)
47 {
48 	GdkWindow *window = gtk_widget_get_window(widget);
49 	if (!window) return;
50 
51 	if (state & FULLSCREEN_CURSOR_BUSY)
52 		{
53 		GdkCursor *cursor;
54 
55 		cursor = gdk_cursor_new(GDK_WATCH);
56 		gdk_window_set_cursor(window, cursor);
57 		gdk_cursor_unref(cursor);
58 		}
59 	else if (state & FULLSCREEN_CURSOR_NORMAL)
60 		{
61 		gdk_window_set_cursor(window, NULL);
62 		}
63 	else
64 		{
65 		GdkCursor *cursor;
66 
67 		cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
68 		gdk_window_set_cursor(window, cursor);
69 		gdk_cursor_unref(cursor);
70 		}
71 }
72 
fullscreen_hide_mouse_cb(gpointer data)73 static gboolean fullscreen_hide_mouse_cb(gpointer data)
74 {
75 	FullScreenData *fs = data;
76 
77 	if (!fs->hide_mouse_id) return FALSE;
78 
79 	fs->cursor_state &= ~FULLSCREEN_CURSOR_NORMAL;
80 	if (!(fs->cursor_state & FULLSCREEN_CURSOR_BUSY)) clear_mouse_cursor(fs->window, fs->cursor_state);
81 
82 	g_source_remove(fs->hide_mouse_id);
83 	fs->hide_mouse_id = 0;
84 	return FALSE;
85 }
86 
fullscreen_hide_mouse_disable(FullScreenData * fs)87 static void fullscreen_hide_mouse_disable(FullScreenData *fs)
88 {
89 	if (fs->hide_mouse_id)
90 		{
91 		g_source_remove(fs->hide_mouse_id);
92 		fs->hide_mouse_id = 0;
93 		}
94 }
95 
fullscreen_hide_mouse_reset(FullScreenData * fs)96 static void fullscreen_hide_mouse_reset(FullScreenData *fs)
97 {
98 	fullscreen_hide_mouse_disable(fs);
99 	fs->hide_mouse_id = g_timeout_add(FULL_SCREEN_HIDE_MOUSE_DELAY, fullscreen_hide_mouse_cb, fs);
100 }
101 
fullscreen_mouse_moved(GtkWidget * widget,GdkEventMotion * event,gpointer data)102 static gboolean fullscreen_mouse_moved(GtkWidget *widget, GdkEventMotion *event, gpointer data)
103 {
104 	FullScreenData *fs = data;
105 
106 	if (!(fs->cursor_state & FULLSCREEN_CURSOR_NORMAL))
107 		{
108 		fs->cursor_state |= FULLSCREEN_CURSOR_NORMAL;
109 		if (!(fs->cursor_state & FULLSCREEN_CURSOR_BUSY)) clear_mouse_cursor(fs->window, fs->cursor_state);
110 		}
111 	fullscreen_hide_mouse_reset(fs);
112 
113 	return FALSE;
114 }
115 
fullscreen_busy_mouse_disable(FullScreenData * fs)116 static void fullscreen_busy_mouse_disable(FullScreenData *fs)
117 {
118 	if (fs->busy_mouse_id)
119 		{
120 		g_source_remove(fs->busy_mouse_id);
121 		fs->busy_mouse_id = 0;
122 		}
123 }
124 
fullscreen_mouse_set_busy(FullScreenData * fs,gboolean busy)125 static void fullscreen_mouse_set_busy(FullScreenData *fs, gboolean busy)
126 {
127 	fullscreen_busy_mouse_disable(fs);
128 
129 	if (!!(fs->cursor_state & FULLSCREEN_CURSOR_BUSY) == (busy)) return;
130 
131 	if (busy)
132 		{
133 		fs->cursor_state |= FULLSCREEN_CURSOR_BUSY;
134 		}
135 	else
136 		{
137 		fs->cursor_state &= ~FULLSCREEN_CURSOR_BUSY;
138 		}
139 
140 	clear_mouse_cursor(fs->window, fs->cursor_state);
141 }
142 
fullscreen_mouse_set_busy_cb(gpointer data)143 static gboolean fullscreen_mouse_set_busy_cb(gpointer data)
144 {
145 	FullScreenData *fs = data;
146 
147 	fs->busy_mouse_id = 0;
148 	fullscreen_mouse_set_busy(fs, TRUE);
149 	return FALSE;
150 }
151 
fullscreen_mouse_set_busy_idle(FullScreenData * fs)152 static void fullscreen_mouse_set_busy_idle(FullScreenData *fs)
153 {
154 	if (!fs->busy_mouse_id)
155 		{
156 		fs->busy_mouse_id = g_timeout_add(FULL_SCREEN_BUSY_MOUSE_DELAY,
157 						  fullscreen_mouse_set_busy_cb, fs);
158 		}
159 }
160 
fullscreen_image_update_cb(ImageWindow * imd,gpointer data)161 static void fullscreen_image_update_cb(ImageWindow *imd, gpointer data)
162 {
163 	FullScreenData *fs = data;
164 
165 	if (fs->imd->il &&
166 	    image_loader_get_pixbuf(fs->imd->il) != image_get_pixbuf(fs->imd))
167 		{
168 		fullscreen_mouse_set_busy_idle(fs);
169 		}
170 }
171 
fullscreen_image_complete_cb(ImageWindow * imd,gboolean preload,gpointer data)172 static void fullscreen_image_complete_cb(ImageWindow *imd, gboolean preload, gpointer data)
173 {
174 	FullScreenData *fs = data;
175 
176 	if (!preload) fullscreen_mouse_set_busy(fs, FALSE);
177 }
178 
179 #define XSCREENSAVER_BINARY	"xscreensaver-command"
180 #define XSCREENSAVER_COMMAND	"xscreensaver-command -deactivate >&- 2>&- &"
181 
fullscreen_saver_deactivate(void)182 static void fullscreen_saver_deactivate(void)
183 {
184 	static gboolean checked = FALSE;
185 	static gboolean found = FALSE;
186 
187 	if (!checked)
188 		{
189 		checked = TRUE;
190 		found = file_in_path(XSCREENSAVER_BINARY);
191 		}
192 
193 	if (found)
194 		{
195 		runcmd(XSCREENSAVER_COMMAND);
196 		}
197 }
198 
fullscreen_saver_block_cb(gpointer data)199 static gboolean fullscreen_saver_block_cb(gpointer data)
200 {
201 	if (options->fullscreen.disable_saver)
202 		{
203 		fullscreen_saver_deactivate();
204 		}
205 
206 	return TRUE;
207 }
208 
fullscreen_delete_cb(GtkWidget * widget,GdkEventAny * event,gpointer data)209 static gboolean fullscreen_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
210 {
211 	FullScreenData *fs = data;
212 
213 	fullscreen_stop(fs);
214 	return TRUE;
215 }
216 
fullscreen_start(GtkWidget * window,ImageWindow * imd,void (* stop_func)(FullScreenData *,gpointer),gpointer stop_data)217 FullScreenData *fullscreen_start(GtkWidget *window, ImageWindow *imd,
218 				 void (*stop_func)(FullScreenData *, gpointer), gpointer stop_data)
219 {
220 	FullScreenData *fs;
221 	GdkScreen *screen;
222 	gint x, y;
223 	gint w, h;
224 	GdkGeometry geometry;
225 
226 	if (!window || !imd) return NULL;
227 
228 	fs = g_new0(FullScreenData, 1);
229 
230 	fs->cursor_state = FULLSCREEN_CURSOR_HIDDEN;
231 
232 	fs->normal_window = window;
233 	fs->normal_imd = imd;
234 
235 	fs->stop_func = stop_func;
236 	fs->stop_data = stop_data;
237 
238 	DEBUG_1("full screen requests screen %d", options->fullscreen.screen);
239 	fullscreen_prefs_get_geometry(options->fullscreen.screen, window, &x, &y, &w, &h,
240 				      &screen, &fs->same_region);
241 
242 	fs->window = window_new(GTK_WINDOW_TOPLEVEL, "fullscreen", NULL, NULL, _("Full screen"));
243 	DEBUG_NAME(fs->window);
244 
245 	g_signal_connect(G_OBJECT(fs->window), "delete_event",
246 			 G_CALLBACK(fullscreen_delete_cb), fs);
247 
248 	/* few cosmetic details */
249 	gtk_window_set_decorated(GTK_WINDOW(fs->window), FALSE);
250 	gtk_container_set_border_width(GTK_CONTAINER(fs->window), 0);
251 
252 	/* keep window above others, if requested */
253 	if (options->fullscreen.above) {
254 		gtk_window_set_keep_above(GTK_WINDOW(fs->window), TRUE);
255 	}
256 
257 	/* set default size and position, so the window appears where it was before */
258 	gtk_window_set_default_size(GTK_WINDOW(fs->window), w, h);
259 	gtk_window_move(GTK_WINDOW(fs->window), x, y);
260 
261 	/* By setting USER_POS and USER_SIZE, most window managers will
262 	 * not request positioning of the full screen window (for example twm).
263 	 *
264 	 * In addition, setting gravity to STATIC will result in the
265 	 * decorations of twm to not effect the requested window position,
266 	 * the decorations will simply be off screen, except in multi monitor setups :-/
267 	 */
268 	geometry.min_width = 1;
269 	geometry.min_height = 1;
270 	geometry.base_width = w;
271 	geometry.base_height = h;
272 	geometry.win_gravity = GDK_GRAVITY_STATIC;
273 	gtk_window_set_geometry_hints(GTK_WINDOW(fs->window), fs->window, &geometry,
274 			GDK_HINT_WIN_GRAVITY | GDK_HINT_USER_POS | GDK_HINT_USER_SIZE);
275 
276 	gtk_widget_realize(fs->window);
277 #if GTK_CHECK_VERSION(3,8,0)
278 	if ((options->fullscreen.screen % 100) == 0)
279 		{
280 		GdkWindow *gdkwin;
281 		gdkwin = gtk_widget_get_window(fs->window);
282 		if (gdkwin != NULL)
283 			gdk_window_set_fullscreen_mode(gdkwin, GDK_FULLSCREEN_ON_ALL_MONITORS);
284 		}
285 #endif
286 	/* make window fullscreen -- let Gtk do it's job, don't screw it in any way */
287 	gtk_window_fullscreen(GTK_WINDOW(fs->window));
288 
289 	/* move it to requested screen */
290 	if (options->fullscreen.screen >= 0)
291 		{
292 		gtk_window_set_screen(GTK_WINDOW(fs->window), screen);
293 		}
294 
295 	fs->imd = image_new(FALSE);
296 
297 	gtk_container_add(GTK_CONTAINER(fs->window), fs->imd->widget);
298 
299 	image_background_set_color_from_options(fs->imd, TRUE);
300 	image_set_delay_flip(fs->imd, options->fullscreen.clean_flip);
301 	image_auto_refresh_enable(fs->imd, fs->normal_imd->auto_refresh);
302 
303 	if (options->fullscreen.clean_flip)
304 		{
305 		image_set_update_func(fs->imd, fullscreen_image_update_cb, fs);
306 		image_set_complete_func(fs->imd, fullscreen_image_complete_cb, fs);
307 		}
308 
309 	gtk_widget_show(fs->imd->widget);
310 
311 	if (fs->same_region)
312 		{
313 		DEBUG_2("Original window is not visible, enabling std. fullscreen mode");
314 		image_move_from_image(fs->imd, fs->normal_imd);
315 		}
316 	else
317 		{
318 		DEBUG_2("Original window is still visible, enabling presentation fullscreen mode");
319 		image_copy_from_image(fs->imd, fs->normal_imd);
320 		}
321 
322 	if (options->stereo.enable_fsmode) {
323 		image_stereo_set(fs->imd, options->stereo.fsmode);
324 	}
325 
326 	gtk_widget_show(fs->window);
327 
328 	/* for hiding the mouse */
329 	g_signal_connect(G_OBJECT(fs->imd->pr), "motion_notify_event",
330 			   G_CALLBACK(fullscreen_mouse_moved), fs);
331 	clear_mouse_cursor(fs->window, fs->cursor_state);
332 
333 	/* set timer to block screen saver */
334 	fs->saver_block_id = g_timeout_add(60 * 1000, fullscreen_saver_block_cb, fs);
335 
336 	/* hide normal window
337 	 * FIXME: properly restore this window on show
338 	 */
339 	if (fs->same_region)
340 		{
341 		if (options->hide_window_in_fullscreen)
342 			{
343 			gtk_widget_hide(fs->normal_window);
344 			}
345 		image_change_fd(fs->normal_imd, NULL, image_zoom_get(fs->normal_imd));
346 		}
347 
348 	return fs;
349 }
350 
fullscreen_stop(FullScreenData * fs)351 void fullscreen_stop(FullScreenData *fs)
352 {
353 	if (!fs) return;
354 
355 	if (fs->saver_block_id) g_source_remove(fs->saver_block_id);
356 
357 	fullscreen_hide_mouse_disable(fs);
358 	fullscreen_busy_mouse_disable(fs);
359 	gdk_keyboard_ungrab(GDK_CURRENT_TIME);
360 
361 	if (fs->same_region)
362 		{
363 		image_move_from_image(fs->normal_imd, fs->imd);
364 		if (options->hide_window_in_fullscreen)
365 			{
366 			gtk_widget_show(fs->normal_window);
367 			}
368 		if (options->stereo.enable_fsmode)
369 			{
370 			image_stereo_set(fs->normal_imd, options->stereo.mode);
371 			}
372 		}
373 
374 
375 	if (fs->stop_func) fs->stop_func(fs, fs->stop_data);
376 
377 	gtk_widget_destroy(fs->window);
378 
379 	gtk_window_present(GTK_WINDOW(fs->normal_window));
380 
381 	g_free(fs);
382 }
383 
384 
385 /*
386  *----------------------------------------------------------------------------
387  * full screen preferences and utils
388  *----------------------------------------------------------------------------
389  */
390 
fullscreen_prefs_list(void)391 GList *fullscreen_prefs_list(void)
392 {
393 	GList *list = NULL;
394 	GdkDisplay *display;
395 	gint number;
396 	gint i;
397 
398 	display = gdk_display_get_default();
399 	number = gdk_display_get_n_screens(display);
400 
401 	for (i = 0; i < number; i++)
402 		{
403 		GdkScreen *screen;
404 		gint monitors;
405 		gint j;
406 
407 		screen = gdk_display_get_screen(display, i);
408 		monitors = gdk_screen_get_n_monitors(screen);
409 
410 		for (j = -1; j < monitors; j++)
411 			{
412 			ScreenData *sd;
413 			GdkRectangle rect;
414 			gchar *name;
415 			gchar *subname;
416 
417 			name = gdk_screen_make_display_name(screen);
418 
419 			if (j < 0)
420 				{
421 				rect.x = 0;
422 				rect.y = 0;
423 				rect.width = gdk_screen_get_width(screen);
424 				rect.height = gdk_screen_get_height(screen);
425 				subname = g_strdup(_("Full size"));
426 				}
427 			else
428 				{
429 				gdk_screen_get_monitor_geometry(screen, j, &rect);
430 				subname = gdk_screen_get_monitor_plug_name(screen, j);
431 				if (subname == NULL)
432 					{
433 					subname = g_strdup_printf("%s %d", _("Monitor"), j + 1);
434 					}
435 				}
436 
437 			sd = g_new0(ScreenData, 1);
438 			sd->number = (i+1) * 100 + j + 1;
439 			sd->description = g_strdup_printf("%s %s, %s", _("Screen"), name, subname);
440 			sd->x = rect.x;
441 			sd->y = rect.y;
442 			sd->width = rect.width;
443 			sd->height = rect.height;
444 
445 			DEBUG_1("Screen %d %30s %4d,%4d (%4dx%4d)",
446 					  sd->number, sd->description, sd->x, sd->y, sd->width, sd->height);
447 
448 			list = g_list_append(list, sd);
449 
450 			g_free(name);
451 			g_free(subname);
452 			}
453 		}
454 
455 	return list;
456 }
457 
fullscreen_prefs_list_free(GList * list)458 void fullscreen_prefs_list_free(GList *list)
459 {
460 	GList *work;
461 
462 	work = list;
463 	while (work)
464 		{
465 		ScreenData *sd = work->data;
466 		work = work->next;
467 
468 		g_free(sd->description);
469 		g_free(sd);
470 		}
471 
472 	g_list_free(list);
473 }
474 
fullscreen_prefs_list_find(GList * list,gint screen)475 ScreenData *fullscreen_prefs_list_find(GList *list, gint screen)
476 {
477 	GList *work;
478 
479 	work = list;
480 	while (work)
481 		{
482 		ScreenData *sd = work->data;
483 		work = work->next;
484 
485 		if (sd->number == screen) return sd;
486 		}
487 
488 	return NULL;
489 }
490 
491 /* screen is interpreted as such:
492  *  -1  window manager determines size and position, fallback is (1) active monitor
493  *   0  full size of screen containing widget
494  *   1  size of monitor containing widget
495  * 100  full size of screen 1 (screen, monitor counts start at 1)
496  * 101  size of monitor 1 on screen 1
497  * 203  size of monitor 3 on screen 2
498  * returns:
499  * dest_screen: screen to place widget [use gtk_window_set_screen()]
500  * same_region: the returned region will overlap the current location of widget.
501  */
fullscreen_prefs_get_geometry(gint screen,GtkWidget * widget,gint * x,gint * y,gint * width,gint * height,GdkScreen ** dest_screen,gboolean * same_region)502 void fullscreen_prefs_get_geometry(gint screen, GtkWidget *widget, gint *x, gint *y, gint *width, gint *height,
503 				   GdkScreen **dest_screen, gboolean *same_region)
504 {
505 	GList *list;
506 	ScreenData *sd;
507 
508 	list = fullscreen_prefs_list();
509 	if (screen >= 100)
510 		{
511 		sd = fullscreen_prefs_list_find(list, screen);
512 		}
513 	else
514 		{
515 		sd = NULL;
516 		if (screen < 0) screen = 1;
517 		}
518 
519 	if (sd)
520 		{
521 		GdkDisplay *display;
522 		GdkScreen *screen;
523 		gint n;
524 
525 		display = gdk_display_get_default();
526 		n = sd->number / 100 - 1;
527 		if (n >= 0 && n < gdk_display_get_n_screens(display))
528 			{
529 			screen = gdk_display_get_screen(display, n);
530 			}
531 		else
532 			{
533 			screen = gdk_display_get_default_screen(display);
534 			}
535 
536 		if (x) *x = sd->x;
537 		if (y) *y = sd->y;
538 		if (width) *width = sd->width;
539 		if (height) *height = sd->height;
540 
541 		if (dest_screen) *dest_screen = screen;
542 		if (same_region) *same_region = (!widget || !gtk_widget_get_window(widget) ||
543 					(screen == gtk_widget_get_screen(widget) &&
544 					(sd->number%100 == 0 ||
545 					 sd->number%100 == gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(widget))+1)));
546 
547 		}
548 	else if (screen != 1 || !widget || !gtk_widget_get_window(widget))
549 		{
550 		GdkScreen *screen;
551 
552 		if (widget)
553 			{
554 			screen = gtk_widget_get_screen(widget);
555 			}
556 		else
557 			{
558 			screen = gdk_screen_get_default();
559 			}
560 
561 		if (x) *x = 0;
562 		if (y) *y = 0;
563 		if (width) *width = gdk_screen_get_width(screen);
564 		if (height) *height = gdk_screen_get_height(screen);
565 
566 		if (dest_screen) *dest_screen = screen;
567 		if (same_region) *same_region = TRUE;
568 		}
569 	else
570 		{
571 		GdkScreen *screen;
572 		gint monitor;
573 		GdkRectangle rect;
574 
575 		screen = gtk_widget_get_screen(widget);
576 		monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(widget));
577 
578 		gdk_screen_get_monitor_geometry(screen, monitor, &rect);
579 
580 		if (x) *x = rect.x;
581 		if (y) *y = rect.y;
582 		if (width) *width = rect.width;
583 		if (height) *height = rect.height;
584 
585 		if (dest_screen) *dest_screen = screen;
586 		if (same_region) *same_region = TRUE;
587 		}
588 
589 	fullscreen_prefs_list_free(list);
590 }
591 
fullscreen_prefs_find_screen_for_widget(GtkWidget * widget)592 gint fullscreen_prefs_find_screen_for_widget(GtkWidget *widget)
593 {
594 	GdkScreen *screen;
595 	gint monitor;
596 	gint n;
597 
598 	if (!widget || !gtk_widget_get_window(widget)) return 0;
599 
600 	screen = gtk_widget_get_screen(widget);
601 	monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(widget));
602 
603 	n = (gdk_screen_get_number(screen)+1) * 100 + monitor + 1;
604 
605 	DEBUG_1("Screen appears to be %d", n);
606 
607 	return n;
608 }
609 
610 enum {
611 	FS_MENU_COLUMN_NAME = 0,
612 	FS_MENU_COLUMN_VALUE
613 };
614 
615 #define BUTTON_ABOVE_KEY  "button_above"
616 
fullscreen_prefs_selection_cb(GtkWidget * combo,gpointer data)617 static void fullscreen_prefs_selection_cb(GtkWidget *combo, gpointer data)
618 {
619 	gint *value = data;
620 	GtkTreeModel *store;
621 	GtkTreeIter iter;
622 	GtkWidget *button;
623 
624 	if (!value) return;
625 
626 	store = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
627 	if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) return;
628 	gtk_tree_model_get(store, &iter, FS_MENU_COLUMN_VALUE, value, -1);
629 
630 	button = g_object_get_data(G_OBJECT(combo), BUTTON_ABOVE_KEY);
631 	if (button)
632 		{
633 		gtk_widget_set_sensitive(button, *value != -1);
634 		}
635 }
636 
fullscreen_prefs_selection_add(GtkListStore * store,const gchar * text,gint value)637 static void fullscreen_prefs_selection_add(GtkListStore *store, const gchar *text, gint value)
638 {
639 	GtkTreeIter iter;
640 
641 	gtk_list_store_append(store, &iter);
642 	gtk_list_store_set(store, &iter, FS_MENU_COLUMN_NAME, text,
643 					 FS_MENU_COLUMN_VALUE, value, -1);
644 }
645 
fullscreen_prefs_selection_new(const gchar * text,gint * screen_value,gboolean * above_value)646 GtkWidget *fullscreen_prefs_selection_new(const gchar *text, gint *screen_value, gboolean *above_value)
647 {
648 	GtkWidget *vbox;
649 	GtkWidget *hbox;
650 	GtkWidget *combo;
651 	GtkListStore *store;
652 	GtkCellRenderer *renderer;
653 	GList *list;
654 	GList *work;
655 	gint current = 0;
656 	gint n;
657 
658 	if (!screen_value) return NULL;
659 
660 	vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
661 	DEBUG_NAME(vbox);
662 	hbox = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
663 	if (text) pref_label_new(hbox, text);
664 
665 	store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
666 	combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
667 	g_object_unref(store);
668 
669 	renderer = gtk_cell_renderer_text_new();
670 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
671 	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer,
672 				       "text", FS_MENU_COLUMN_NAME, NULL);
673 
674 	fullscreen_prefs_selection_add(store, _("Determined by Window Manager"), -1);
675 	fullscreen_prefs_selection_add(store, _("Active screen"), 0);
676 	if (*screen_value == 0) current = 1;
677 	fullscreen_prefs_selection_add(store, _("Active monitor"), 1);
678 	if (*screen_value == 1) current = 2;
679 
680 	n = 3;
681 	list = fullscreen_prefs_list();
682 	work = list;
683 	while (work)
684 		{
685 		ScreenData *sd = work->data;
686 
687 		fullscreen_prefs_selection_add(store, sd->description, sd->number);
688 		if (*screen_value == sd->number) current = n;
689 
690 		work = work->next;
691 		n++;
692 		}
693 	fullscreen_prefs_list_free(list);
694 
695 	gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
696 
697 	gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
698 	gtk_widget_show(combo);
699 
700 	g_signal_connect(G_OBJECT(combo), "changed",
701 			 G_CALLBACK(fullscreen_prefs_selection_cb), screen_value);
702 
703 	return vbox;
704 }
705 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
706