1 /*
2 ** 1999-12-23 -	Hm, perhaps this is an unfortunate choice of module title. It might bloat,
3 **		or something. :) Anyway, the purpose of this module is to help handle
4 **		(toplevel) windows, specifically remembering their sizes and positions.
5 */
6 
7 #include "gentoo.h"
8 
9 #include <ctype.h>
10 #include <stdlib.h>
11 
12 #include "guiutil.h"
13 #include "graphics/icon_gentoo_small.xpm"
14 
15 #include "window.h"
16 
17 /* ----------------------------------------------------------------------------------------- */
18 
19 typedef struct
20 {
21 	guint32		id;			/* Unique identifier for this windata. */
22 	WinType		type;			/* What type of window? */
23 	gboolean	persistent;		/* Makes close() actually do a hide(). */
24 	const gchar	*title;			/* Text for window's title bar. */
25 	const gchar	*label;			/* Short descriptive label (like "main", "config" etc). */
26 	gboolean	pos_grab;
27 	gboolean	size_grab;
28 	/* Data below here is stored in configuration file. */
29 	gint		x, y;			/* Window's opening position. */
30 	gint		width, height;		/* The desired size of this window. */
31 	gboolean	pos_use;		/* Should we set use the recorded position? */
32 	gboolean	pos_update;		/* Update recorded position when window closes? */
33 	gboolean	size_use;		/* Use recorded size? */
34 	gboolean	size_update;		/* Update recorded size with current size on close? */
35 } WinDef;
36 
37 struct WinInfo
38 {
39 	MainInfo	*min;			/* The handiness of this pointer cannot be overstated. */
40 	GList		*windows;		/* List of WinDef:s as per above. There's no rush. */
41 	gint		border_width;		/* User's idea of her window manager's border size. Hackish. */
42 	gint		border_height;
43 };
44 
45 /* ----------------------------------------------------------------------------------------- */
46 
47 static WinDef * window_find(const WinInfo *wi, guint32 id);
48 
49 /* ----------------------------------------------------------------------------------------- */
50 
win_wininfo_new(MainInfo * min)51 WinInfo * win_wininfo_new(MainInfo *min)
52 {
53 	WinInfo *wi;
54 
55 	wi = g_malloc(sizeof *wi);
56 	wi->min = min;
57 	wi->windows = NULL;
58 
59 	return wi;
60 }
61 
62 /* 1999-12-23 -	Create a new WinInfo, initialized with the "default" (i.e., legacy) windows. */
win_wininfo_new_default(MainInfo * min)63 WinInfo * win_wininfo_new_default(MainInfo *min)
64 {
65 	WinInfo *wi;
66 
67 	wi = win_wininfo_new(min);
68 
69 	/* This is what seems to be right on my stock GNOME desktop.
70 	** Mileage will vary, wildly.
71 	*/
72 	win_borders_set(wi, 4, 24);
73 
74 	win_window_new(wi, WIN_MAIN, WIN_TYPE_SIMPLE_TOPLEVEL, FALSE, geteuid() == 0 ? "gentoo [root]" : "gentoo", "main");
75 	win_window_pos_grab_set(wi, WIN_MAIN, TRUE);
76 	win_window_size_set(wi, WIN_MAIN, 764, 932);
77 	win_window_size_use_set(wi, WIN_MAIN, TRUE);
78 	win_window_size_update_set(wi, WIN_MAIN, TRUE);
79 	win_window_size_grab_set(wi, WIN_MAIN, TRUE);
80 
81 	win_window_new(wi, WIN_CONFIG, WIN_TYPE_COMPLEX_DIALOG, TRUE, _("Configure gentoo"), "config");
82 	win_window_pos_use_set(wi, WIN_CONFIG, FALSE);
83 	win_window_size_set(wi, WIN_CONFIG, -1, 464);
84 	win_window_size_use_set(wi, WIN_CONFIG, TRUE);
85 	win_window_size_update_set(wi, WIN_CONFIG, TRUE);
86 
87 	win_window_new(wi, WIN_TEXTVIEW, WIN_TYPE_SIMPLE_TOPLEVEL, FALSE, _("Text Viewer"), "textview");
88 	win_window_pos_use_set(wi, WIN_TEXTVIEW, FALSE);
89 	win_window_size_set(wi, WIN_TEXTVIEW, 640, 480);
90 	win_window_size_use_set(wi, WIN_TEXTVIEW, TRUE);
91 	win_window_size_update_set(wi, WIN_TEXTVIEW, TRUE);
92 
93 	win_window_new(wi, WIN_INFO, WIN_TYPE_SIMPLE_DIALOG, FALSE, "Info", "info");
94 	win_window_size_set(wi, WIN_INFO, 320, 480);
95 	win_window_size_use_set(wi, WIN_INFO, TRUE);
96 	win_window_size_update_set(wi, WIN_INFO, TRUE);
97 
98 	return wi;
99 }
100 
101 /* 1999-12-23 -	Create a copy of <wi>, sharing no memory with it. */
win_wininfo_copy(const WinInfo * wi)102 WinInfo * win_wininfo_copy(const WinInfo *wi)
103 {
104 	WinInfo *nwi;
105 	WinDef *win;
106 	GList *iter;
107 
108 	nwi = win_wininfo_new(wi->min);
109 
110 	for(iter = wi->windows; iter != NULL; iter = g_list_next(iter))
111 	{
112 		win = iter->data;
113 
114 		win_window_new(nwi, win->id, win->type, win->persistent,
115 				win->title, win->label);
116 		win_window_pos_grab_set(nwi, win->id, win->pos_grab);
117 		win_window_pos_set(nwi, win->id, win->x, win->y);
118 		win_window_pos_use_set(nwi, win->id, win->pos_use);
119 		win_window_pos_update_set(nwi, win->id, win->pos_update);
120 		win_window_size_grab_set(nwi, win->id, win->size_grab);
121 		win_window_size_set(nwi, win->id, win->width, win->height);
122 		win_window_size_use_set(nwi, win->id, win->size_use);
123 		win_window_size_update_set(nwi, win->id, win->size_update);
124 	}
125 	nwi->border_width = wi->border_width;
126 	nwi->border_height = wi->border_height;
127 	return nwi;
128 }
129 
win_wininfo_destroy(WinInfo * wi)130 void win_wininfo_destroy(WinInfo *wi)
131 {
132 	GList *iter;
133 
134 	for(iter = wi->windows; iter != NULL; iter = g_list_next(iter))
135 		g_free(iter->data);
136 	g_list_free(wi->windows);
137 	g_free(wi);
138 }
139 
140 /* ----------------------------------------------------------------------------------------- */
141 
142 enum
143 {
144 	SUBFRAME_POSITION, SUBFRAME_SIZE
145 };
146 
evt_boolean_clicked(GtkWidget * wid,gpointer user)147 static void evt_boolean_clicked(GtkWidget *wid, gpointer user)
148 {
149 	gboolean *flag = user;
150 	gboolean *modified;
151 
152 	*flag = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wid));
153 	if((modified = g_object_get_data(G_OBJECT(wid), "modified")) != NULL)
154 		*modified = TRUE;
155 }
156 
evt_integer_changed(GtkAdjustment * adj,gpointer user)157 static void evt_integer_changed(GtkAdjustment *adj, gpointer user)
158 {
159 	gint *value = user;
160 	gboolean *modified;
161 
162 	*value = gtk_adjustment_get_value(adj);
163 	if((modified = g_object_get_data(G_OBJECT(adj), "modified")) != NULL)
164 		*modified = TRUE;
165 }
166 
167 /* Grab position. We implicitly *know* that the window in question is the main
168 ** gentoo window, and therefore access it directly through the MainInfo. We
169 ** then put the grabbed position into the editing copy of the WinDef, and update
170 ** the spin buttons to match. Of course, we don't forget setting that pesky old
171 ** modified-flag, either. :) What would people think?
172 */
evt_pos_grab_clicked(GtkWidget * wid,gpointer user)173 static void evt_pos_grab_clicked(GtkWidget *wid, gpointer user)
174 {
175 	MainInfo *min;
176 	WinDef *wd = user;
177 
178 	min = g_object_get_data(G_OBJECT(wid), "min");
179 	gdk_window_get_position(gtk_widget_get_window(min->gui->window), &wd->x, &wd->y);
180 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(wid), "spin1")), wd->x);
181 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(wid), "spin2")), wd->y);
182 	*(gboolean *) g_object_get_data(G_OBJECT(wid), "modified") = TRUE;
183 }
184 
185 /* Grab size. Works only for main gentoo window. See comment for pos_grab above. */
evt_size_grab_clicked(GtkWidget * wid,gpointer user)186 static void evt_size_grab_clicked(GtkWidget *wid, gpointer user)
187 {
188 	MainInfo *min;
189 	WinDef *wd = user;
190 
191 	min = g_object_get_data(G_OBJECT(wid), "min");
192 	wd->width  = gdk_window_get_width(gtk_widget_get_window(min->gui->window));
193 	wd->height = gdk_window_get_height(gtk_widget_get_window(min->gui->window));
194 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(wid), "spin1")), wd->width);
195 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(g_object_get_data(G_OBJECT(wid), "spin2")), wd->height);
196 	*(gboolean *) g_object_get_data(G_OBJECT(wid), "modified") = TRUE;
197 }
198 
subframe_build(const WinInfo * wi,WinDef * win,gint type,gboolean * modified)199 static GtkWidget * subframe_build(const WinInfo *wi, WinDef *win, gint type, gboolean *modified)
200 {
201 	const gchar *ltext[] =
202 	{ N_("Position"), N_("Size") }, *etext[] =
203 	{ N_("X"), N_("Y"), N_("Width"), N_("Height") };
204 	GtkWidget	*label, *frame, *cbtn, *vbox, *grid, *spin1, *spin2;
205 	GtkAdjustment	*adj;
206 	gint		val1 = 0, val2 = 0;
207 
208 	frame = gtk_frame_new(_(ltext[type]));
209 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
210 	cbtn = gtk_check_button_new_with_label(_("Set on Open?"));
211 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbtn), (type == SUBFRAME_POSITION) ? win_window_pos_use_get(wi, win->id) : win_window_size_use_get(wi, win->id));
212 	g_object_set_data(G_OBJECT(cbtn), "modified", modified);
213 	g_signal_connect(G_OBJECT(cbtn), "clicked", G_CALLBACK(evt_boolean_clicked), (type == SUBFRAME_POSITION) ? &win->pos_use : &win->size_use);
214 	gtk_box_pack_start(GTK_BOX(vbox), cbtn, FALSE, FALSE, 0);
215 
216 	cbtn = gtk_check_button_new_with_label(_("Update on Close?"));
217 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbtn), (type == SUBFRAME_POSITION) ? win_window_pos_update_get(wi, win->id) : win_window_size_update_get(wi, win->id));
218 	g_object_set_data(G_OBJECT(cbtn), "modified", modified);
219 	g_signal_connect(G_OBJECT(cbtn), "clicked", G_CALLBACK(evt_boolean_clicked), (type == SUBFRAME_POSITION) ? &win->pos_update : &win->size_update);
220 	gtk_box_pack_start(GTK_BOX(vbox), cbtn, FALSE, FALSE, 0);
221 
222 	grid = gtk_grid_new();
223 
224 	if(type == SUBFRAME_POSITION)
225 		win_window_pos_get(wi, win->id, &val1, &val2);
226 	else
227 		win_window_size_get(wi, win->id, &val1, &val2);
228 
229 	label = gtk_label_new(_(etext[2 * type]));
230 	gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
231 	adj = gtk_adjustment_new(val1, -1.0, 65535.0, 1.0, 25.0, 0.0);
232 	spin1 = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0.0);
233 	g_object_set_data(G_OBJECT(adj), "modified", modified);
234 	g_signal_connect(G_OBJECT(adj), "value_changed", G_CALLBACK(evt_integer_changed), type == SUBFRAME_POSITION ? &win->x : &win->width);
235 	gtk_widget_set_hexpand(spin1, TRUE);
236 	gtk_widget_set_halign(spin1, GTK_ALIGN_FILL);
237 	gtk_grid_attach(GTK_GRID(grid), spin1, 1, 0, 1, 1);
238 	label = gtk_label_new(_(etext[2 * type + 1]));
239 	gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
240 	adj = gtk_adjustment_new(val2, -1.0, 65535.0, 1.0, 25.0, 0.0);
241 	spin2 = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0.0);
242 	g_object_set_data(G_OBJECT(adj), "modified", modified);
243 	g_signal_connect(G_OBJECT(adj), "value_changed", G_CALLBACK(evt_integer_changed), type == SUBFRAME_POSITION ? &win->y : &win->height);
244 	gtk_grid_attach(GTK_GRID(grid), spin2, 1, 1, 1, 1);
245 	if((type == SUBFRAME_POSITION && win->pos_grab) || (type == SUBFRAME_SIZE && win->size_grab))
246 	{
247 		GtkWidget *grab;
248 
249 		grab = gtk_button_new_with_label(_("Grab"));
250 
251 		g_object_set_data(G_OBJECT(grab), "min", wi->min);
252 		g_object_set_data(G_OBJECT(grab), "spin1", spin1);
253 		g_object_set_data(G_OBJECT(grab), "spin2", spin2);
254 		g_object_set_data(G_OBJECT(grab), "modified", modified);
255 		g_signal_connect(G_OBJECT(grab), "clicked", type == SUBFRAME_POSITION ? G_CALLBACK(evt_pos_grab_clicked) : G_CALLBACK(evt_size_grab_clicked), win);
256 		gtk_grid_attach(GTK_GRID(grid), grab, 2, 0, 1, 2);
257 	}
258 	gtk_box_pack_start(GTK_BOX(vbox), grid, FALSE, FALSE, 0);
259 	gtk_container_add(GTK_CONTAINER(frame), vbox);
260 
261 	return frame;
262 }
263 
win_wininfo_build(const WinInfo * wi,gboolean * modified)264 GtkWidget * win_wininfo_build(const WinInfo *wi, gboolean *modified)
265 {
266 	GtkWidget *vbox, *frame, *hbox, *sframe;
267 	GList *iter;
268 	gchar tmp[64];
269 	WinDef *win;
270 
271 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
272 
273 	for(iter = wi->windows; iter != NULL; iter = g_list_next(iter))
274 	{
275 		win = iter->data;
276 
277 		g_snprintf(tmp, sizeof tmp, "%c%s", toupper(*win->label), win->label + 1);
278 		frame = gtk_frame_new(tmp);
279 		hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
280 		sframe = subframe_build(wi, win, SUBFRAME_POSITION, modified);
281 		gtk_box_pack_start(GTK_BOX(hbox), sframe, TRUE, TRUE, 5);
282 		sframe = subframe_build(wi, win, SUBFRAME_SIZE, modified);
283 		gtk_box_pack_start(GTK_BOX(hbox), sframe, TRUE, TRUE, 5);
284 		gtk_container_add(GTK_CONTAINER(frame), hbox);
285 		gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
286 	}
287 	return vbox;
288 }
289 
290 /* ----------------------------------------------------------------------------------------- */
291 
292 /* 2000-02-24 -	Write WinInfo out to given file <out>, at its current location. */
win_wininfo_save(const WinInfo * wi,FILE * out)293 void win_wininfo_save(const WinInfo *wi, FILE *out)
294 {
295 	GList *iter;
296 	WinDef *wd;
297 
298 	xml_put_node_open(out, "Windows");
299 	for(iter = wi->windows; iter != NULL; iter = g_list_next(iter))
300 	{
301 		wd = iter->data;
302 
303 		xml_put_node_open(out, "Window");
304 		xml_put_uinteger(out, "id", wd->id);
305 		xml_put_integer(out, "x", wd->x);
306 		xml_put_integer(out, "y", wd->y);
307 		xml_put_integer(out, "w", wd->width);
308 		xml_put_integer(out, "h", wd->height);
309 		xml_put_boolean(out, "pos_use", wd->pos_use);
310 		xml_put_boolean(out, "pos_update", wd->pos_update);
311 		xml_put_boolean(out, "size_use", wd->size_use);
312 		xml_put_boolean(out, "size_update", wd->size_update);
313 		xml_put_node_close(out, "Window");
314 	}
315 	/* This goes INSIDE <Windows>, since there is no outer structure. :| */
316 	xml_put_node_open(out, "Borders");
317 	xml_put_integer(out, "width", wi->border_width);
318 	xml_put_integer(out, "height", wi->border_height);
319 	xml_put_node_close(out, "Borders");
320 	xml_put_node_close(out, "Windows");
321 }
322 
window_load(const XmlNode * node,gpointer user)323 static void window_load(const XmlNode *node, gpointer user)
324 {
325 	WinInfo	*wi = user;
326 
327 	if(xml_node_has_name(node, "Window"))
328 	{
329 		guint32 id;
330 
331 		if(xml_get_uinteger(node, "id", &id))
332 		{
333 			WinDef *wd;
334 
335 			if((wd = window_find(wi, id)) != NULL)
336 			{
337 				xml_get_integer(node, "x", &wd->x);
338 				xml_get_integer(node, "y", &wd->y);
339 				xml_get_integer(node, "w", &wd->width);
340 				xml_get_integer(node, "h", &wd->height);
341 				xml_get_boolean(node, "pos_use", &wd->pos_use);
342 				xml_get_boolean(node, "pos_update", &wd->pos_update);
343 				xml_get_boolean(node, "size_use", &wd->size_use);
344 				xml_get_boolean(node, "size_update", &wd->size_update);
345 			}
346 		}
347 	}
348 	else if(xml_node_has_name(node, "Borders"))
349 	{
350 		xml_get_integer(node, "width", &wi->border_width);
351 		xml_get_integer(node, "height", &wi->border_height);
352 	}
353 }
354 
355 /* 2000-02-24 -	Fill in <wi> with details for windows, loaded from <node>. */
win_wininfo_load(WinInfo * wi,const XmlNode * node)356 void win_wininfo_load(WinInfo *wi, const XmlNode *node)
357 {
358 	/* Visit all children. Since the XML structure, for the usual raisins, is a bit
359 	** messed up, the Window elements are at the same level as the Borders.
360 	*/
361 	xml_node_visit_children(node, window_load, wi);
362 }
363 
364 /* ----------------------------------------------------------------------------------------- */
365 
win_borders_set(WinInfo * wi,gint width,gint height)366 void win_borders_set(WinInfo *wi, gint width, gint height)
367 {
368 	if(wi == NULL)
369 		return;
370 	wi->border_width = width;
371 	wi->border_height = height;
372 }
373 
win_borders_get(const WinInfo * wi,gint * width,gint * height)374 void win_borders_get(const WinInfo *wi, gint *width, gint *height)
375 {
376 	if(wi == NULL)
377 		return;
378 	if(width != NULL)
379 		*width = wi->border_width;
380 	if(height != NULL)
381 		*height = wi->border_height;
382 }
383 
384 /* ----------------------------------------------------------------------------------------- */
385 
win_window_new(WinInfo * wi,guint32 id,WinType type,gboolean persistent,const gchar * title,const gchar * label)386 void win_window_new(WinInfo *wi, guint32 id, WinType type, gboolean persistent, const gchar *title, const gchar *label)
387 {
388 	WinDef *wd;
389 
390 	wd = g_malloc(sizeof *wd);
391 	wd->id = id;
392 	wd->type = type;
393 	wd->persistent = persistent;
394 	wd->title = title;
395 	wd->label = label;
396 	wd->pos_grab = FALSE;
397 	wd->size_grab = FALSE;
398 
399 	wd->x = 32;
400 	wd->y = 32;
401 	wd->width = 32;
402 	wd->height = 32;
403 
404 	wd->pos_use = FALSE;
405 	wd->pos_update = FALSE;
406 	wd->size_use = FALSE;
407 	wd->size_update = TRUE;
408 
409 	wi->windows = g_list_append(wi->windows, wd);
410 }
411 
window_find(const WinInfo * wi,guint32 id)412 static WinDef * window_find(const WinInfo *wi, guint32 id)
413 {
414 	GList *iter;
415 
416 	if(wi == NULL)
417 		return NULL;
418 
419 	for(iter = wi->windows; iter != NULL; iter = g_list_next(iter))
420 	{
421 		if(((WinDef *) iter->data)->id == id)
422 			return iter->data;
423 	}
424 	return NULL;
425 }
426 
win_window_pos_grab_set(const WinInfo * wi,guint32 id,gboolean grab)427 void win_window_pos_grab_set(const WinInfo *wi, guint32 id, gboolean grab)
428 {
429 	WinDef *wd;
430 
431 	if((wd = window_find(wi, id)) != NULL)
432 		wd->pos_grab = grab;
433 }
434 
win_window_pos_set(const WinInfo * wi,guint32 id,gint x,gint y)435 void win_window_pos_set(const WinInfo *wi, guint32 id, gint x, gint y)
436 {
437 	WinDef *wd;
438 
439 	if((wd = window_find(wi, id)) != NULL)
440 	{
441 		wd->x = x;
442 		wd->y = y;
443 	}
444 }
445 
win_window_pos_get(const WinInfo * wi,guint32 id,gint * x,gint * y)446 gboolean win_window_pos_get(const WinInfo *wi, guint32 id, gint *x, gint *y)
447 {
448 	WinDef *wd;
449 
450 	if((wd = window_find(wi, id)) != NULL)
451 	{
452 		if(x)
453 			*x = wd->x;
454 		if(y)
455 			*y = wd->y;
456 		return TRUE;
457 	}
458 	return FALSE;
459 }
460 
win_window_pos_use_set(const WinInfo * wi,guint32 id,gboolean enabled)461 void win_window_pos_use_set(const WinInfo *wi, guint32 id, gboolean enabled)
462 {
463 	WinDef *wd;
464 
465 	if((wd = window_find(wi, id)) != NULL)
466 		wd->pos_use = enabled;
467 }
468 
win_window_pos_use_get(const WinInfo * wi,guint32 id)469 gboolean win_window_pos_use_get(const WinInfo *wi, guint32 id)
470 {
471 	WinDef *wd;
472 
473 	if((wd = window_find(wi, id)) != NULL)
474 		return wd->pos_use;
475 	return FALSE;
476 }
477 
win_window_pos_update_set(const WinInfo * wi,guint32 id,gboolean enabled)478 void win_window_pos_update_set(const WinInfo *wi, guint32 id, gboolean enabled)
479 {
480 	WinDef *wd;
481 
482 	if((wd = window_find(wi, id)) != NULL)
483 		wd->pos_update = enabled;
484 }
485 
win_window_pos_update_get(const WinInfo * wi,guint32 id)486 gboolean win_window_pos_update_get(const WinInfo *wi, guint32 id)
487 {
488 	WinDef *wd;
489 
490 	if((wd = window_find(wi, id)) != NULL)
491 		return wd->pos_update;
492 	return FALSE;
493 }
494 
win_window_size_grab_set(const WinInfo * wi,guint32 id,gboolean grab)495 void win_window_size_grab_set(const WinInfo *wi, guint32 id, gboolean grab)
496 {
497 	WinDef *wd;
498 
499 	if((wd = window_find(wi, id)) != NULL)
500 		wd->size_grab = grab;
501 }
502 
win_window_size_set(const WinInfo * wi,guint32 id,gint width,gint height)503 void win_window_size_set(const WinInfo *wi, guint32 id, gint width, gint height)
504 {
505 	WinDef *wd;
506 
507 	if((wd = window_find(wi, id)) != NULL)
508 	{
509 		wd->width = width;
510 		wd->height = height;
511 	}
512 }
513 
win_window_size_get(const WinInfo * wi,guint32 id,gint * width,gint * height)514 gboolean win_window_size_get(const WinInfo *wi, guint32 id, gint *width,
515 		gint *height)
516 {
517 	WinDef *wd;
518 
519 	if((wd = window_find(wi, id)) != NULL)
520 	{
521 		if(width)
522 			*width = wd->width;
523 		if(height)
524 			*height = wd->height;
525 		return TRUE;
526 	}
527 	return FALSE;
528 }
529 
win_window_size_use_set(const WinInfo * wi,guint32 id,gboolean enabled)530 void win_window_size_use_set(const WinInfo *wi, guint32 id, gboolean enabled)
531 {
532 	WinDef *wd;
533 
534 	if((wd = window_find(wi, id)) != NULL)
535 		wd->size_use = enabled;
536 }
537 
win_window_size_use_get(const WinInfo * wi,guint32 id)538 gboolean win_window_size_use_get(const WinInfo *wi, guint32 id)
539 {
540 	WinDef *wd;
541 
542 	if((wd = window_find(wi, id)) != NULL)
543 		return wd->size_use;
544 	return FALSE;
545 }
546 
win_window_size_update_set(const WinInfo * wi,guint32 id,gboolean enabled)547 void win_window_size_update_set(const WinInfo *wi, guint32 id, gboolean enabled)
548 {
549 	WinDef *wd;
550 
551 	if((wd = window_find(wi, id)) != NULL)
552 		wd->size_update = enabled;
553 }
554 
win_window_size_update_get(const WinInfo * wi,guint32 id)555 gboolean win_window_size_update_get(const WinInfo *wi, guint32 id)
556 {
557 	WinDef *wd;
558 
559 	if((wd = window_find(wi, id)) != NULL)
560 		return wd->size_update;
561 	return FALSE;
562 }
563 
564 /* ----------------------------------------------------------------------------------------- */
565 
win_window_destroy(WinInfo * wi,guint32 id)566 void win_window_destroy(WinInfo *wi, guint32 id)
567 {
568 	WinDef *wd;
569 
570 	if((wd = window_find(wi, id)) != NULL)
571 	{
572 		wi->windows = g_list_remove(wi->windows, wd);
573 		g_free(wd);
574 	}
575 }
576 
577 /* ----------------------------------------------------------------------------------------- */
578 
579 /* 2010-12-12 -	Rewritten to not use deprecated (and crazy-seeming) GDK calls. */
window_set_icon(GtkWindow * win)580 static void window_set_icon(GtkWindow *win)
581 {
582 	GdkPixbuf	*pbuf;
583 
584 	if((pbuf = gdk_pixbuf_new_from_xpm_data(icon_gentoo_small_xpm)) != NULL)
585 	{
586 		gtk_window_set_default_icon(pbuf);
587 		gtk_window_set_icon_name(win, PACKAGE);
588 		g_object_unref(G_OBJECT(pbuf));	/* I believe GTK+ owns this, now. */
589 	}
590 }
591 
592 /* 1999-12-23 -	Open the window described by <key> in <wi>. The window will not be shown yet. */
win_window_open(const WinInfo * wi,guint32 id)593 GtkWidget * win_window_open(const WinInfo *wi, guint32 id)
594 {
595 	WinDef *wd;
596 
597 	if((wd = window_find(wi, id)) != NULL)
598 	{
599 		GtkWidget *wid = NULL;
600 
601 		switch (wd->type)
602 		{
603 		case WIN_TYPE_SIMPLE_TOPLEVEL:
604 		case WIN_TYPE_SIMPLE_DIALOG:
605 			wid = gtk_window_new(GTK_WINDOW_TOPLEVEL);
606 			break;
607 		case WIN_TYPE_SIMPLE_POPUP:
608 			wid = gtk_window_new(GTK_WINDOW_POPUP);
609 			break;
610 		case WIN_TYPE_COMPLEX_DIALOG:
611 			wid = win_dialog_open(wi->min->gui->window);
612 			break;
613 		}
614 		g_object_set_data(G_OBJECT(wid), "wininfo", (gpointer) wi);
615 		g_object_set_data(G_OBJECT(wid), "windef", (gpointer) wd);
616 		if(!wd->pos_use)
617 			gtk_window_set_position(GTK_WINDOW(wid), GTK_WIN_POS_MOUSE);
618 		gtk_widget_realize(wid);
619 		if(id == WIN_MAIN)
620 			window_set_icon(GTK_WINDOW(wid));
621 		else if(id != WIN_MAIN && id != WIN_TYPE_COMPLEX_DIALOG && wi->min->gui != NULL)
622 			gtk_window_set_transient_for(GTK_WINDOW(wid), GTK_WINDOW(wi->min->gui->window));
623 		if(wd->title != NULL)
624 			win_window_set_title(wid, wd->title);
625 		if(wd->label != NULL)
626 			gtk_window_set_role(GTK_WINDOW(wid), wd->label);
627 		return wid;
628 	}
629 	return NULL;
630 }
631 
632 /* 2000-02-19 -	Refresh link between <wi> and <window>. Handy after <wi> has been replaced
633 **		while window was open, as happens in the config window case.
634 */
win_window_relink(const WinInfo * wi,guint32 id,GtkWidget * window)635 void win_window_relink(const WinInfo *wi, guint32 id, GtkWidget *window)
636 {
637 	WinDef *wd;
638 
639 	if((wd = window_find(wi, id)) != NULL)
640 	{
641 		g_object_set_data(G_OBJECT(window), "wininfo", (gpointer) wi);
642 		g_object_set_data(G_OBJECT(window), "windef", wd);
643 	}
644 }
645 
646 /* 2002-08-10 -	Set title of a window. Since it seems to break if locale is set, we simply
647 **		un-set the locale temporarily. Hopefully, noone sets window titles in inner
648 **		loops around here.
649 ** NOTE NOTE	This works for *all* windows, not just those created through this module.
650 **		That might surprise, but it felt more sensical to stick it in here anyway.
651 */
win_window_set_title(GtkWidget * win,const gchar * title)652 void win_window_set_title(GtkWidget *win, const gchar *title)
653 {
654 	gtk_widget_realize(win);
655 	gtk_window_set_title(GTK_WINDOW(win), title);
656 }
657 
658 /* 1999-12-23 -	Use this rather than gtk_widget_show() when you want to the window to appear, since
659 **		this gives us a chance to set the window's size and position according to preference.
660 */
win_window_show(GtkWidget * window)661 void win_window_show(GtkWidget *window)
662 {
663 	WinInfo	*wi;
664 	WinDef	*wd;
665 
666 	if(gtk_widget_get_visible(window))
667 		return;
668 
669 	wi = g_object_get_data(G_OBJECT(window), "wininfo");
670 	wd = g_object_get_data(G_OBJECT(window), "windef");
671 	if((wd != NULL) && wd->size_use && wd->width >= 0)
672 		gtk_window_set_default_size(GTK_WINDOW(window), wd->width, wd->height);
673 	/* For the main window, make sure to make it possible to shrink very much. */
674 	if(wd != NULL && wd->id == WIN_MAIN)
675 	{
676 		GdkGeometry	geo;
677 
678 		geo.min_width = 10;
679 		geo.min_height = 10;
680 		gtk_window_set_geometry_hints(GTK_WINDOW(window), window, &geo, GDK_HINT_MIN_SIZE);
681 	}
682 
683 	/* This causes the window to appear at some more or less random position. We then reposition
684 	** it to the configured place. This is visually distracting, unattractive, and almost s*cks,
685 	** but unfortunately I haven't been able to figure out how to fix it. If you move the show()
686 	** call to below the if, it works, but not all the time. :( Tips welcome.
687 	*/
688 	gtk_widget_show_all(window);
689 
690 	/* If user wants to set position, check where it ended up and move it home. */
691 	if((wd != NULL) && wd->pos_use && wd->x >= 0)
692 	{
693 		gint	cx, cy;
694 
695 		gtk_window_get_position(GTK_WINDOW(window), &cx, &cy);
696 		if(wi != NULL)	/* Any borders to adjust for? */
697 		{
698 			cx += wi->border_width;
699 			cy += wi->border_height;
700 		}
701 		gtk_window_move(GTK_WINDOW(window), wd->x - cx, wd->y - cy);
702 		gui_events_flush();
703 		gtk_window_get_position(GTK_WINDOW(window), &cx, &cy);
704 	}
705 }
706 
707 /* 2000-03-04 -	If <a_new> is different from *<a>, update *<a> to <a_new> and return TRUE, else
708 **		return FALSE. Likewise for <b>, whatever that would mean.
709 */
update_pair(gint * a,gint * b,gint a_new,gint b_new)710 static gboolean update_pair(gint *a, gint *b, gint a_new, gint b_new)
711 {
712 	if((*a != a_new) || (*b != b_new))
713 	{
714 		*a = a_new;
715 		*b = b_new;
716 		return TRUE;
717 	}
718 	return FALSE;
719 }
720 
721 /* 2000-03-18 -	Do an update for the given window, changing the config as needed. Returns TRUE
722 **		if the config was indeed changed.
723 */
win_window_update(GtkWidget * win)724 gboolean win_window_update(GtkWidget *win)
725 {
726 	WinDef *wd;
727 
728 	if((wd = g_object_get_data(G_OBJECT(win), "windef")) != NULL)
729 	{
730 		gboolean ret = FALSE;
731 		gint ta, tb;
732 
733 		if(wd->pos_update)
734 		{
735 			gdk_window_get_root_origin(gtk_widget_get_window(win), &ta, &tb);
736 			ret |= update_pair(&wd->x, &wd->y, ta, tb);
737 		}
738 		if(wd->size_update)
739 		{
740 			ta = gdk_window_get_width(gtk_widget_get_window(win));
741 			tb = gdk_window_get_height(gtk_widget_get_window(win));
742 			ret |= update_pair(&wd->width, &wd->height, ta, tb);
743 		}
744 		return ret;
745 	}
746 	return FALSE;
747 }
748 
749 /* 1999-12-23 -	Close the given window. Use this rather than a direct gtk_widget_destroy(), since
750 **		we need a chance to update the position and size fields if needed. Also, if the
751 **		window is classified as "persistent", we don't actually destroy it, but only hide
752 **		it. Returns TRUE if the config was changed, i.e. if one of the update flags were
753 **		set AND the relevant property actually had changed.
754 */
win_window_close(GtkWidget * win)755 gboolean win_window_close(GtkWidget *win)
756 {
757 	WinDef *wd;
758 
759 	if((wd = g_object_get_data(G_OBJECT(win), "windef")) != NULL)
760 	{
761 		gboolean ret;
762 
763 		ret = win_window_update(win);
764 		if(wd->persistent)
765 			gtk_widget_hide(win);
766 		else
767 			gtk_widget_destroy(win);
768 		return ret;
769 	}
770 	gtk_widget_destroy(win);
771 	return FALSE;
772 }
773 
774 /* ----------------------------------------------------------------------------------------- */
775 
776 /* 2010-12-12 -	New single way of opening a dialog, that tries to make sure it gets the proper
777 **		linkage to the main window. This shares the icon, among (possibly) other things.
778 */
win_dialog_open(GtkWidget * main_window)779 GtkWidget * win_dialog_open(GtkWidget *main_window)
780 {
781 	GtkWidget	*wid = gtk_dialog_new();
782 
783 	if(main_window != NULL)
784 		gtk_window_set_transient_for(GTK_WINDOW(wid), GTK_WINDOW(main_window));
785 
786 	return wid;
787 }
788