1 /****************************************************************************\
2  *  grid.c - put display grid info here
3  *****************************************************************************
4  *  Copyright (C) 2004-2007 The Regents of the University of California.
5  *  Copyright (C) 2008-2010 Lawrence Livermore National Security.
6  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7  *  Written by Danny Auble <da@llnl.gov>, et. al.
8  *  CODE-OCEC-09-009. All rights reserved.
9  *
10  *  This file is part of Slurm, a resource management program.
11  *  For details, see <https://slurm.schedmd.com/>.
12  *  Please also read the included file: DISCLAIMER.
13  *
14  *  Slurm is free software; you can redistribute it and/or modify it under
15  *  the terms of the GNU General Public License as published by the Free
16  *  Software Foundation; either version 2 of the License, or (at your option)
17  *  any later version.
18  *
19  *  In addition, as a special exception, the copyright holders give permission
20  *  to link the code of portions of this program with the OpenSSL library under
21  *  certain conditions as described in each individual source file, and
22  *  distribute linked combinations including the two. You must obey the GNU
23  *  General Public License in all respects for all of the code used other than
24  *  OpenSSL. If you modify file(s) with this exception, you may extend this
25  *  exception to your version of the file(s), but you are not obligated to do
26  *  so. If you do not wish to do so, delete this exception statement from your
27  *  version.  If you delete this exception statement from all source files in
28  *  the program, then also delete it here.
29  *
30  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
31  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
33  *  details.
34  *
35  *  You should have received a copy of the GNU General Public License along
36  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
37  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
38 \*****************************************************************************/
39 
40 #include "config.h"
41 
42 #include "sview.h"
43 
44 #define RESET_GRID -2
45 #define TOPO_DEBUG  0
46 
47 List grid_button_list = NULL;
48 List blinking_button_list = NULL;
49 List multi_button_list = NULL;
50 
51 char *sview_colors[] = {"#0000FF", "#00FF00", "#00FFFF", "#FFFF00",
52 			"#FF0000", "#4D4DC6", "#F09A09", "#BDFA19",
53 			"#715627", "#6A8CA2", "#4C7127", "#25B9B9",
54 			"#A020F0", "#8293ED", "#FFA500", "#FFC0CB",
55 			"#8B6914", "#18A24E", "#F827FC", "#B8A40C"};
56 char *blank_color = "#919191";
57 char *white_color = "#FFFFFF";
58 char *topo1_color = "honeydew"; //"seashell";DarkTurquoise
59 char *topo2_color = "gray94";//honeydew";
60 
61 int sview_colors_cnt = 20;
62 
63 typedef struct {
64 	int node_inx_id;
65 	int color_inx_id;
66 	List button_list;
67 } grid_foreach_t;
68 
69 typedef struct {
70 	List button_list;
71 	int *coord_x;
72 	int *coord_y;
73 	int default_y_offset;
74 	grid_button_t *grid_button;
75 	int *inx;
76 	GtkTable *table;
77 	int table_y;
78 	bool force_row_break;
79 } button_processor_t;
80 
_mouseover_node(GtkWidget * widget,GdkEventButton * event,grid_button_t * grid_button)81 static gboolean _mouseover_node(GtkWidget *widget, GdkEventButton *event,
82 				grid_button_t *grid_button)
83 {
84 	gboolean rc = true;
85 
86 	grid_button->last_state = gtk_widget_get_state(widget);
87 #ifdef GTK2_USE_TOOLTIP
88 	gtk_widget_set_tooltip_text(grid_button->button,
89 				    grid_button->node_name);
90 #else
91 	if (!grid_button->tip)
92 		grid_button->tip = gtk_tooltips_new();
93 	gtk_tooltips_set_tip(grid_button->tip,
94 			     grid_button->button,
95 			     grid_button->node_name,
96 			     "click for node stats");
97 #endif
98 	//g_print("on at %s\n", grid_button->node_name);
99 	gtk_widget_set_state(grid_button->button, GTK_STATE_PRELIGHT);
100 
101 	return rc;
102 }
103 
_mouseoff_node(GtkWidget * widget,GdkEventButton * event,grid_button_t * grid_button)104 static gboolean _mouseoff_node(GtkWidget *widget, GdkEventButton *event,
105 			       grid_button_t *grid_button)
106 {
107 	gboolean rc = false;
108 
109 	if (grid_button->last_state == GTK_STATE_ACTIVE) {
110 		gtk_widget_set_state(grid_button->button, GTK_STATE_ACTIVE);
111 		rc = true;
112 		//g_print("off of %s\n", grid_button->node_name);
113 	}
114 	return rc;
115 }
116 
_open_node(GtkWidget * widget,GdkEventButton * event,grid_button_t * grid_button)117 static gboolean _open_node(GtkWidget *widget, GdkEventButton *event,
118 			   grid_button_t *grid_button)
119 {
120 	if (event->button == 1) {
121 		popup_all_node_name(grid_button->node_name, INFO_PAGE, NULL);
122 	} else if (event->button == 3) {
123 		/* right click */
124 		admin_menu_node_name(grid_button->node_name, event);
125 	}
126 
127 	return false;
128 }
129 
130 /* static void _state_changed(GtkWidget *button, GtkStateType state, */
131 /* 			   grid_button_t *grid_button) */
132 /* { */
133 /* 	g_print("state of %s is now %d\n", grid_button->node_name, state); */
134 /* } */
135 
_add_button_signals(grid_button_t * grid_button)136 static void _add_button_signals(grid_button_t *grid_button)
137 {
138 	/* g_signal_connect(G_OBJECT(grid_button->button), */
139 	/* 		 "state-changed", */
140 	/* 		 G_CALLBACK(_state_changed), */
141 	/* 		 grid_button); */
142 	g_signal_connect(G_OBJECT(grid_button->button),
143 			 "button-press-event",
144 			 G_CALLBACK(_open_node),
145 			 grid_button);
146 	g_signal_connect(G_OBJECT(grid_button->button),
147 			 "enter-notify-event",
148 			 G_CALLBACK(_mouseover_node),
149 			 grid_button);
150 	g_signal_connect(G_OBJECT(grid_button->button),
151 			 "leave-notify-event",
152 			 G_CALLBACK(_mouseoff_node),
153 			 grid_button);
154 }
155 
156 /*
157  * Comparator used for sorting buttons
158  *
159  * returns: -1: button_a->inx > button_b->inx
160  *           0: rec_a == rec_b
161  *           1: rec_a < rec_b
162  *
163  */
_sort_button_inx(void * b1,void * b2)164 static int _sort_button_inx(void *b1, void *b2)
165 {
166 	grid_button_t *button_a = *(grid_button_t **)b1;
167 	grid_button_t *button_b = *(grid_button_t **)b2;
168 	int inx_a;
169 	int inx_b;
170 
171 	inx_a = button_a->inx;
172 	inx_b = button_b->inx;
173 
174 	if (inx_a < inx_b)
175 		return -1;
176 	else if (inx_a > inx_b)
177 		return 1;
178 	return 0;
179 }
180 
_put_button_as_down(grid_button_t * grid_button,int state)181 void _put_button_as_down(grid_button_t *grid_button, int state)
182 {
183 	GtkWidget *image = NULL;
184 /* 	GdkColor color; */
185 
186 	if (GTK_IS_EVENT_BOX(grid_button->button)) {
187 		//gtk_widget_set_sensitive (grid_button->button, true);
188 		return;
189 	}
190 
191 	gtk_widget_destroy(grid_button->button);
192 	grid_button->color = NULL;
193 	grid_button->color_inx = MAKE_DOWN;
194 	grid_button->button = gtk_event_box_new();
195 	gtk_widget_set_size_request(grid_button->button,
196 				    working_sview_config.button_size,
197 				    working_sview_config.button_size);
198 	gtk_event_box_set_above_child(GTK_EVENT_BOX(grid_button->button),
199 				      false);
200 	_add_button_signals(grid_button);
201 
202 /* 	if (grid_button->frame) */
203 /* 		gtk_container_add(GTK_CONTAINER(grid_button->frame), */
204 /* 				  grid_button->button); */
205 	if (grid_button->table)
206 		gtk_table_attach(grid_button->table, grid_button->button,
207 				 grid_button->table_x,
208 				 (grid_button->table_x+1),
209 				 grid_button->table_y,
210 				 (grid_button->table_y+1),
211 				 GTK_SHRINK, GTK_SHRINK,
212 				 1, 1);
213 
214 	//gdk_color_parse("black", &color);
215 	//sview_widget_modify_bg(grid_button->button, GTK_STATE_NORMAL, color);
216 	//gdk_color_parse(white_color, &color);
217 	//sview_widget_modify_bg(grid_button->button, GTK_STATE_ACTIVE, color);
218 	if (state == NODE_STATE_DRAIN)
219 		image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_ERROR,
220 						 GTK_ICON_SIZE_SMALL_TOOLBAR);
221 	else
222 		image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
223 						 GTK_ICON_SIZE_SMALL_TOOLBAR);
224 	gtk_container_add(GTK_CONTAINER(grid_button->button), image);
225 	gtk_widget_show_all(grid_button->button);
226 	return;
227 }
228 
229 
_put_button_as_up(grid_button_t * grid_button)230 void _put_button_as_up(grid_button_t *grid_button)
231 {
232 	if (GTK_IS_BUTTON(grid_button->button)) {
233 		return;
234 	}
235 	gtk_widget_destroy(grid_button->button);
236 	grid_button->button = gtk_button_new();
237 	gtk_widget_set_size_request(grid_button->button,
238 				    working_sview_config.button_size,
239 				    working_sview_config.button_size);
240 	_add_button_signals(grid_button);
241 
242 /* 	if (grid_button->frame) */
243 /* 		gtk_container_add(GTK_CONTAINER(grid_button->frame), */
244 /* 				  grid_button->button); */
245 	if (grid_button->table)
246 		gtk_table_attach(grid_button->table, grid_button->button,
247 				 grid_button->table_x,
248 				 (grid_button->table_x+1),
249 				 grid_button->table_y,
250 				 (grid_button->table_y+1),
251 				 GTK_SHRINK, GTK_SHRINK,
252 				 1, 1);
253 	gtk_widget_show_all(grid_button->button);
254 	return;
255 }
256 
_put_button_as_inactive(grid_button_t * grid_button)257 void _put_button_as_inactive(grid_button_t *grid_button)
258 {
259 	if (GTK_IS_BUTTON(grid_button->button)) {
260 		//gtk_widget_set_sensitive (grid_button->button, false);
261 		return;
262 	}
263 	gtk_widget_destroy(grid_button->button);
264 	grid_button->button = gtk_button_new();
265 	gtk_widget_set_size_request(grid_button->button,
266 				    working_sview_config.button_size,
267 				    working_sview_config.button_size);
268 	//gtk_widget_set_sensitive (grid_button->button, false);
269 
270 	_add_button_signals(grid_button);
271 
272 /* 	if (grid_button->frame) */
273 /* 		gtk_container_add(GTK_CONTAINER(grid_button->frame), */
274 /* 				  grid_button->button); */
275 	if (grid_button->table)
276 		gtk_table_attach(grid_button->table, grid_button->button,
277 				 grid_button->table_x,
278 				 (grid_button->table_x+1),
279 				 grid_button->table_y,
280 				 (grid_button->table_y+1),
281 				 GTK_SHRINK, GTK_SHRINK,
282 				 1, 1);
283 	gtk_widget_show_all(grid_button->button);
284 	return;
285 }
286 
_change_button_color(grid_button_t * grid_button,int color_inx,char * new_col,GdkColor color,bool only_change_unused,enum node_states state_override)287 static bool _change_button_color(grid_button_t *grid_button,
288 				 int color_inx, char *new_col, GdkColor color,
289 				 bool only_change_unused,
290 				 enum node_states state_override)
291 {
292 	enum node_states state;
293 	uint16_t node_base_state;
294 	bool changed = 0;
295 
296 	xassert(grid_button);
297 	if (only_change_unused && grid_button->used)
298 		return 0;
299 
300 	grid_button->used = true;
301 	if (color_inx == MAKE_BLACK) {
302 		if (grid_button->color_inx != color_inx) {
303 			_put_button_as_inactive(grid_button);
304 			grid_button->color = new_col;
305 			grid_button->color_inx = color_inx;
306 			sview_widget_modify_bg(grid_button->button,
307 					       GTK_STATE_NORMAL, color);
308 /* 				sview_widget_modify_bg(grid_button->button,  */
309 /* 						       GTK_STATE_ACTIVE, */
310 /* 						       color); */
311 			changed = 1;
312 		}
313 
314 		return changed;
315 	}
316 
317 	if (state_override != NODE_STATE_UNKNOWN)
318 		state = state_override;
319 	else
320 		state = grid_button->state;
321 
322 	node_base_state = state & NODE_STATE_BASE;
323 
324 	if (node_base_state == NODE_STATE_DOWN) {
325 		_put_button_as_down(grid_button, NODE_STATE_DOWN);
326 	} else if (state & NODE_STATE_DRAIN) {
327 		_put_button_as_down(grid_button, NODE_STATE_DRAIN);
328 	} else if (grid_button->node_name &&
329 		   !xstrcmp(grid_button->node_name, "EMPTY")) {
330 		grid_button->color_inx = MAKE_BLACK;
331 //		_put_button_as_up(grid_button);
332 	} else if (grid_button->color_inx != color_inx) {
333 		_put_button_as_up(grid_button);
334 		grid_button->color = new_col;
335 		grid_button->color_inx = color_inx;
336 		sview_widget_modify_bg(grid_button->button,
337 				       GTK_STATE_NORMAL, color);
338 /* 			sview_widget_modify_bg(grid_button->button,  */
339 /* 					       GTK_STATE_ACTIVE, color); */
340 		changed = 1;
341 	}
342 
343 	return changed;
344 }
345 
346 
_each_highlightd(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer userdata)347 static void _each_highlightd(GtkTreeModel *model,
348 			     GtkTreePath *path,
349 			     GtkTreeIter *iter,
350 			     gpointer userdata)
351 {
352 	ListIterator itr = NULL;
353 	grid_button_t *grid_button = NULL;
354 	int *node_inx = NULL;
355 	int color_inx;
356 
357 	int j=0;
358 	GdkColor color;
359 
360 	grid_foreach_t *grid_foreach = userdata;
361 
362 	gtk_tree_model_get(model, iter, grid_foreach->node_inx_id,
363 			   &node_inx, -1);
364 	gtk_tree_model_get(model, iter, grid_foreach->color_inx_id,
365 			   &color_inx, -1);
366 
367 	if (!node_inx)
368 		return;
369 
370 	if (color_inx > sview_colors_cnt) {
371 		g_print("hey the color_inx from %d was set to %d > %d\n",
372 			grid_foreach->color_inx_id, color_inx,
373 			sview_colors_cnt);
374 		color_inx %= sview_colors_cnt;
375 	}
376 	gdk_color_parse(sview_colors[color_inx], &color);
377 
378 	itr = list_iterator_create(grid_foreach->button_list);
379 	while ((grid_button = list_next(itr))) {
380 		/*For multiple selections, need to retain all selected.
381 		 *(previously this assumed only one selected).
382 		 */
383 
384 		if ((node_inx[j] < 0)
385 		    || (grid_button->inx < node_inx[j])
386 		    || (grid_button->inx > node_inx[j+1]))
387 			continue;
388 
389 		(void)_change_button_color(grid_button, color_inx,
390 				     sview_colors[color_inx],
391 				     color, 0, 0);
392 
393 		if (gtk_widget_get_state(grid_button->button) != GTK_STATE_NORMAL)
394 			gtk_widget_set_state(grid_button->button,
395 					     GTK_STATE_NORMAL);
396 
397 		if (grid_button->inx == node_inx[j+1])
398 			j+=2;
399 
400 	}
401 
402 	list_iterator_destroy(itr);
403 	return;
404 }
405 
_each_highlight_selected(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer userdata)406 static void _each_highlight_selected(GtkTreeModel *model,
407 				     GtkTreePath *path,
408 				     GtkTreeIter *iter,
409 				     gpointer userdata)
410 {
411 
412 	grid_button_t *grid_button = NULL;
413 	int node_inx = 0;
414 	bool speedup_break = true;
415 	grid_foreach_t *grid_foreach = userdata;
416 	ListIterator itr = NULL;
417 
418 	xassert(grid_foreach);
419 	if (working_sview_config.grid_topological)
420 		speedup_break = false;
421 
422 	gtk_tree_model_get(model, iter, grid_foreach->node_inx_id,
423 			   &node_inx, -1);
424 
425 	if (node_inx < 0 || !grid_foreach->button_list)
426 		return;
427 	itr = list_iterator_create(grid_foreach->button_list);
428 	while ((grid_button = list_next(itr))) {
429 		/* For multiple selections, need to retain all selected.
430 		 * (previously this assumed only one selected). */
431 		if (grid_button->inx != node_inx)
432 			continue;
433 		else if (gtk_widget_get_state(grid_button->button)
434 			 != GTK_STATE_NORMAL) {
435 			gtk_widget_set_state(grid_button->button,
436 					     GTK_STATE_NORMAL);
437 			change_grid_color(grid_button_list, grid_button->inx,
438 					  grid_button->inx,
439 					  grid_button->inx, true, 0);
440 		}
441 		if (speedup_break)
442 			break;
443 		speedup_break = true; //allow for secondary grid button
444 	}
445 	list_iterator_destroy(itr);
446 	return;
447 
448 }
449 
450 /*
451  * This is used to add an entry to the grid for a node which is not configured
452  * in the system (e.g. there is a gap in the 3-D torus for a service or login
453  * node.
454  */
_build_empty_node(int coord_x,int coord_y,button_processor_t * button_processor)455 static void _build_empty_node(int coord_x, int coord_y,
456 			      button_processor_t *button_processor)
457 {
458 	grid_button_t *grid_button;
459 
460 	(*button_processor->coord_x) = coord_x;
461 	(*button_processor->coord_y) = coord_y;
462 	grid_button = xmalloc(sizeof(grid_button_t));
463 	grid_button->color_inx = MAKE_BLACK;
464 	grid_button->inx = (*button_processor->inx);
465 	grid_button->state = NODE_STATE_FUTURE;
466 	grid_button->table = button_processor->table;
467 	grid_button->table_x = (*button_processor->coord_x);
468 	grid_button->table_y = (*button_processor->coord_y);
469 	grid_button->button = gtk_button_new();
470 	grid_button->node_name = xstrdup("EMPTY");	/* Needed by popups */
471 
472 	gtk_widget_set_state(grid_button->button, GTK_STATE_ACTIVE);
473 	list_append(button_processor->button_list, grid_button);
474 
475 	gtk_table_attach(button_processor->table, grid_button->button,
476 			 (*button_processor->coord_x),
477 			 ((*button_processor->coord_x) + 1),
478 			 (*button_processor->coord_y),
479 			 ((*button_processor->coord_y) + 1),
480 			 GTK_SHRINK, GTK_SHRINK, 1, 1);
481 }
482 
_calc_coord_3d(int x,int y,int z,int default_y_offset,int * coord_x,int * coord_y,int * dim_size)483 static void _calc_coord_3d(int x, int y, int z, int default_y_offset,
484 			   int *coord_x, int *coord_y, int *dim_size)
485 {
486 	int y_offset;
487 
488 	*coord_x = (x + (dim_size[2] - 1)) - z;
489 	y_offset = default_y_offset - (dim_size[2] * y);
490 	*coord_y = (y_offset - y) + z;
491 }
492 
_get_cluster_dims(void)493 static int *_get_cluster_dims(void)
494 {
495 	int *my_dim_size = slurmdb_setup_cluster_dim_size();
496 
497 	if ((cluster_flags & CLUSTER_FLAG_CRAY_A) && my_dim_size) {
498 		static int cray_dim_size[3] = {-1, -1, -1};
499 		/* For now, assume four nodes per coordinate all in
500 		 * the same cage. Need to refine. */
501 		cray_dim_size[0] = my_dim_size[0];
502 		cray_dim_size[1] = my_dim_size[1];
503 		cray_dim_size[2] = my_dim_size[2];
504 		return cray_dim_size;
505 	}
506 
507 	return my_dim_size;
508 }
509 
510 /* Add a button for a given node. If node_ptr == NULL then fill in any gaps
511  * in the grid just for a clean look. Always call with node_ptr == NULL for
512  * the last call in the sequence. */
_add_button_to_list(node_info_t * node_ptr,button_processor_t * button_processor)513 static int _add_button_to_list(node_info_t *node_ptr,
514 			       button_processor_t *button_processor)
515 {
516 	static bool *node_exists = NULL;
517 	static int node_exists_cnt = 1;
518 	grid_button_t *grid_button = button_processor->grid_button;
519 	int *dim_size = NULL, i, coord_x = 0, coord_y = 0;
520 	int len = 0, len_a = 0;
521 
522 	if (cluster_dims > 1) {
523 		dim_size = _get_cluster_dims();
524 		if (dim_size == NULL) {
525 			g_error("Could not read dim_size\n");
526 			return SLURM_ERROR;
527 		}
528 		if ((dim_size[0] < 1) || (cluster_dims < 1)) {
529 			g_error("Invalid dim_size %d or cluster_dims %d\n",
530 				dim_size[0], cluster_dims);
531 			return SLURM_ERROR;
532 		}
533 
534 		/* Translate a 3D or 4D space into a 2D space to the extent
535 		 * possible. */
536 		if (node_exists == NULL) {
537 			node_exists_cnt = 1;
538 			for (i = 0; i < cluster_dims; i++)
539 				node_exists_cnt *= dim_size[i];
540 			node_exists = xmalloc(sizeof(bool) * node_exists_cnt);
541 		}
542 		if (node_ptr) {
543 			len = strlen(node_ptr->name);
544 			if (len < cluster_dims) {
545 				g_error("bad node name %s\n", node_ptr->name);
546 				return SLURM_ERROR;
547 			}
548 			if (cluster_flags & CLUSTER_FLAG_CRAY_A) {
549 				len_a = strlen(node_ptr->node_addr);
550 				if (len_a < cluster_dims) {
551 					g_error("bad node addr %s\n",
552 						node_ptr->node_addr);
553 					return SLURM_ERROR;
554 				}
555 			}
556 		}
557 	}
558 
559 	if (cluster_dims == 3) {
560 		int x, y, z;
561 		if (node_ptr) {
562 			if (cluster_flags & CLUSTER_FLAG_CRAY_A) {
563 				x = select_char2coord(
564 					node_ptr->node_addr[len_a-3]);
565 				y = select_char2coord(
566 					node_ptr->node_addr[len_a-2]);
567 				z = select_char2coord(
568 					node_ptr->node_addr[len_a-1]);
569 			} else {
570 				x = select_char2coord(node_ptr->name[len-3]);
571 				y = select_char2coord(node_ptr->name[len-2]);
572 				z = select_char2coord(node_ptr->name[len-1]);
573 			}
574 			i = (x * dim_size[1] + y) * dim_size[2] + z;
575 			node_exists[i] = true;
576 			_calc_coord_3d(x, y, z,
577 				       button_processor->default_y_offset,
578 				       &coord_x, &coord_y, dim_size);
579 		} else {
580 			for (x = 0; x < dim_size[0]; x++) {
581 				for (y = 0; y < dim_size[1]; y++) {
582 					for (z = 0; z < dim_size[2]; z++) {
583 						i = (x * dim_size[1] + y) *
584 							dim_size[2] + z;
585 						if (node_exists[i])
586 							continue;
587 						_calc_coord_3d(x, y, z,
588 				      			button_processor->
589 							default_y_offset,
590 							&coord_x, &coord_y,
591 							dim_size);
592 						_build_empty_node(
593 							coord_x, coord_y,
594 							button_processor);
595 					}
596 				}
597 			}
598 			xfree(node_exists);
599 			return SLURM_SUCCESS;
600 		}
601 	}
602 	if (node_ptr == NULL)
603 		return SLURM_SUCCESS;
604 
605 	if (cluster_dims > 1) {
606 		(*button_processor->coord_x) = coord_x;
607 		(*button_processor->coord_y) = coord_y;
608 #if 0
609 		g_print("%s %d:%d\n", node_ptr->name, coord_x, coord_y);
610 #endif
611 	}
612 
613 	if (!grid_button) {
614 		grid_button = xmalloc(sizeof(grid_button_t));
615 		grid_button->color_inx = MAKE_INIT;
616 		grid_button->inx = (*button_processor->inx);
617 		grid_button->table = button_processor->table;
618 		grid_button->table_x = (*button_processor->coord_x);
619 		grid_button->table_y = (*button_processor->coord_y);
620 		grid_button->button = gtk_button_new();
621 		grid_button->node_name = xstrdup(node_ptr->name);
622 
623 		gtk_widget_set_size_request(grid_button->button,
624 					    working_sview_config.button_size,
625 					    working_sview_config.button_size);
626 		_add_button_signals(grid_button);
627 		list_append(button_processor->button_list, grid_button);
628 
629 		gtk_table_attach(button_processor->table, grid_button->button,
630 				 (*button_processor->coord_x),
631 				 ((*button_processor->coord_x)+1),
632 				 (*button_processor->coord_y),
633 				 ((*button_processor->coord_y)+1),
634 				 GTK_SHRINK, GTK_SHRINK,
635 				 1, 1);
636 	} else {
637 		grid_button->table_x = (*button_processor->coord_x);
638 		grid_button->table_y = (*button_processor->coord_y);
639 		gtk_container_child_set(
640 			GTK_CONTAINER(button_processor->table),
641 			grid_button->button,
642 			"left-attach", (*button_processor->coord_x),
643 			"right-attach", ((*button_processor->coord_x)+1),
644 			"top-attach", (*button_processor->coord_y),
645 			"bottom-attach", ((*button_processor->coord_y)+1),
646 			NULL);
647 	}
648 	/* gtk_container_add(GTK_CONTAINER(grid_button->frame),  */
649 /* 				  grid_button->button); */
650 /* 		gtk_frame_set_shadow_type(GTK_FRAME(grid_button->frame), */
651 /* 					  GTK_SHADOW_ETCHED_OUT); */
652 	if (cluster_dims < 3) {
653 		/* On linear systems we just up the x_coord until we hit the
654 		 * side of the table and then increment the coord_y.  We add
655 		 * space between each tenth row. */
656 		(*button_processor->coord_x)++;
657 
658 		if (button_processor->force_row_break) {
659 			(*button_processor->coord_x) = 0;
660 			(*button_processor->coord_y)++;
661 			gtk_table_set_row_spacing(
662 				button_processor->table,
663 				(*button_processor->coord_y)-1,
664 				working_sview_config.gap_size);
665 			return SLURM_SUCCESS;
666 		}
667 
668 		if ((*button_processor->coord_x)
669 		    == working_sview_config.grid_x_width) {
670 			(*button_processor->coord_x) = 0;
671 			(*button_processor->coord_y)++;
672 			if (!((*button_processor->coord_y)
673 			      % working_sview_config.grid_vert))
674 				gtk_table_set_row_spacing(
675 					button_processor->table,
676 					(*button_processor->coord_y)-1,
677 					working_sview_config.gap_size);
678 		}
679 
680 		if ((*button_processor->coord_y) == button_processor->table_y)
681 			return SLURM_SUCCESS;
682 
683 		if ((*button_processor->coord_x) &&
684 		    !((*button_processor->coord_x)
685 		      % working_sview_config.grid_hori))
686 			gtk_table_set_col_spacing(
687 				button_processor->table,
688 				(*button_processor->coord_x)-1,
689 				working_sview_config.gap_size);
690 	}
691 	return SLURM_SUCCESS;
692 }
693 
_grid_table_by_switch(button_processor_t * button_processor,List node_list)694 static int _grid_table_by_switch(button_processor_t *button_processor,
695 				 List node_list)
696 {
697 	int rc = SLURM_SUCCESS;
698 	int inx = 0, ii = 0;
699 	switch_record_bitmaps_t *sw_nodes_bitmaps_ptr = g_switch_nodes_maps;
700 #if TOPO_DEBUG
701 	/* engage if want original display below switched */
702 	ListIterator itr = list_iterator_create(node_list);
703 	sview_node_info_t *sview_node_info_ptr = NULL;
704 #endif
705 	button_processor->inx = &inx;
706 	for (ii=0; ii<g_topo_info_msg_ptr->record_count;
707 	     ii++, sw_nodes_bitmaps_ptr++) {
708 		int j = 0, first, last;
709 		if (g_topo_info_msg_ptr->topo_array[ii].level)
710 			continue;
711 		first = bit_ffs(sw_nodes_bitmaps_ptr->node_bitmap);
712 		if (first == -1)
713 			continue;
714 		last = bit_fls(sw_nodes_bitmaps_ptr->node_bitmap);
715 		button_processor->inx = &j;
716 		button_processor->force_row_break = false;
717 		for (j = first; j <= last; j++) {
718 			if (TOPO_DEBUG)
719 				g_print("allocated node = %s button# %d\n",
720 					g_node_info_ptr->node_array[j].name,
721 					j);
722 			if (!bit_test(sw_nodes_bitmaps_ptr->node_bitmap, j))
723 				continue;
724 			/* if (!working_sview_config.show_hidden) { */
725 			/* 	if (!check_part_includes_node(j)) */
726 			/* 		continue; */
727 			/* } */
728 			if (j == last)
729 				button_processor->force_row_break = true;
730 			if ((rc = _add_button_to_list(
731 				     &g_node_info_ptr->node_array[j],
732 				     button_processor)) != SLURM_SUCCESS)
733 				break;
734 			button_processor->force_row_break = false;
735 		}
736 		rc = _add_button_to_list(NULL, button_processor);
737 	}
738 
739 #if TOPO_DEBUG
740 	/* engage this if want original display below
741 	 * switched grid */
742 	 button_processor->inx = &inx;
743 	 while ((sview_node_info_ptr = list_next(itr))) {
744 		 if ((rc = _add_button_to_list(
745 				sview_node_info_ptr->node_ptr,
746 	 			button_processor)) != SLURM_SUCCESS)
747 			 break;
748 	 	inx++;
749 	 }
750 	 list_iterator_destroy(itr);
751 #endif
752 
753 	/* This is needed to get the correct width of the grid window.
754 	 * If it is not given then we get a really narrow window. */
755 	gtk_table_set_row_spacing(button_processor->table,
756 				  (*button_processor->coord_y)?
757 				  ((*button_processor->coord_y)-1):0, 1);
758 
759 	return rc;
760 
761 }
762 
_grid_table_by_list(button_processor_t * button_processor,List node_list)763 static int _grid_table_by_list(button_processor_t *button_processor,
764 			       List node_list)
765 {
766 	sview_node_info_t *sview_node_info_ptr = NULL;
767 	int inx = 0, rc = SLURM_SUCCESS;
768 	ListIterator itr = list_iterator_create(node_list);
769 	button_processor->inx = &inx;
770 
771 	while ((sview_node_info_ptr = list_next(itr))) {
772 		/* if (!working_sview_config.show_hidden) { */
773 		/* 	if (!check_part_includes_node(inx)) { */
774 		/* 		inx++; */
775 		/* 		continue; */
776 		/* 	} */
777 		/* } */
778 		if ((rc = _add_button_to_list(
779 			     sview_node_info_ptr->node_ptr,
780 			     button_processor)) != SLURM_SUCCESS)
781 			break;
782 		inx++;
783 	}
784 	list_iterator_destroy(itr);
785 	rc = _add_button_to_list(NULL, button_processor);
786 
787 	/* This is needed to get the correct width of the grid window.
788 	 * If it is not given then we get a really narrow window. */
789 	gtk_table_set_row_spacing(button_processor->table,
790 				  (*button_processor->coord_y)?
791 				  ((*button_processor->coord_y)-1):0, 1);
792 
793 
794 	return rc;
795 }
796 
_init_button_processor(button_processor_t * button_processor,int node_count)797 static int _init_button_processor(button_processor_t *button_processor,
798 				  int node_count)
799 {
800 	int *dim_size = NULL;
801 
802 	if (node_count == 0) {
803 		g_print("_init_button_processor: no nodes selected\n");
804 		return SLURM_ERROR;
805 	}
806 
807 	memset(button_processor, 0, sizeof(button_processor_t));
808 
809 	if (cluster_dims > 1) {
810 		dim_size = _get_cluster_dims();
811 		if (dim_size == NULL) {
812 			g_error("could not read dim_size\n");
813 			return SLURM_ERROR;
814 		}
815 	}
816 
817 	if (cluster_dims == 3) {
818 		button_processor->default_y_offset = (dim_size[2] * dim_size[1])
819 			+ (dim_size[1] - dim_size[2]);
820 		working_sview_config.grid_x_width = dim_size[0] + dim_size[2];
821 		button_processor->table_y = (dim_size[2] * dim_size[1])
822 					    + dim_size[1];
823 	} else {
824 		if (!working_sview_config.grid_x_width) {
825 			if (node_count < 50) {
826 				working_sview_config.grid_x_width = 1;
827 			} else if (node_count < 500) {
828 				working_sview_config.grid_x_width = 10;
829 			} else {
830 				working_sview_config.grid_x_width = 20;
831 			}
832 		}
833 		button_processor->table_y =
834 			(node_count / working_sview_config.grid_x_width) + 1;
835 	}
836 
837 	button_processor->force_row_break = false;
838 
839 	return SLURM_SUCCESS;
840 }
841 /* static void _destroy_grid_foreach(void *arg) */
842 /* { */
843 /* 	grid_foreach_t *grid_foreach = (grid_foreach_t *)arg; */
844 
845 /* 	if (grid_foreach) { */
846 /* 		xfree(grid_foreach); */
847 /* 	} */
848 /* } */
849 
destroy_grid_button(void * arg)850 extern void destroy_grid_button(void *arg)
851 {
852 	grid_button_t *grid_button = (grid_button_t *)arg;
853 	if (grid_button) {
854 		if (grid_button->button) {
855 			gtk_widget_destroy(grid_button->button);
856 			grid_button->button = NULL;
857 		}
858 		xfree(grid_button->node_name);
859 		xfree(grid_button);
860 	}
861 }
862 
863 /* we don't set the call back for the button here because sometimes we
864  * need to get a different call back based on what we are doing with
865  * the button, an example of this would be in
866  * add_extra_bluegene_buttons were the small block buttons do
867  * something different than they do regularly
868  * TODO - this may be simplified now that bluegene is gone.
869  */
870 
create_grid_button_from_another(grid_button_t * grid_button,char * name,int color_inx)871 extern grid_button_t *create_grid_button_from_another(
872 	grid_button_t *grid_button, char *name, int color_inx)
873 {
874 	grid_button_t *send_grid_button = NULL;
875 	GdkColor color;
876 	uint16_t node_base_state;
877 	char *new_col = NULL;
878 
879 	if (!grid_button || !name)
880 		return NULL;
881 	if (color_inx >= 0) {
882 		color_inx %= sview_colors_cnt;
883 		new_col = sview_colors[color_inx];
884 	} else if (color_inx == MAKE_BLACK)
885 		new_col = blank_color;
886 	else
887 		new_col = white_color;
888 
889 	send_grid_button = xmalloc(sizeof(grid_button_t));
890 	memcpy(send_grid_button, grid_button, sizeof(grid_button_t));
891 	node_base_state = send_grid_button->state & NODE_STATE_BASE;
892 	send_grid_button->color_inx = color_inx;
893 
894 	/* need to set the table to empty because we will want to fill
895 	   this into the new table later */
896 	send_grid_button->table = NULL;
897 	if (color_inx == MAKE_BLACK) {
898 		send_grid_button->button = gtk_button_new();
899 		//gtk_widget_set_sensitive (send_grid_button->button, false);
900 		gdk_color_parse(new_col, &color);
901 		send_grid_button->color = new_col;
902 		sview_widget_modify_bg(send_grid_button->button,
903 				       GTK_STATE_NORMAL, color);
904 /* 		sview_widget_modify_bg(send_grid_button->button,  */
905 /* 				       GTK_STATE_ACTIVE, color); */
906 	} else if ((color_inx >= 0) && node_base_state == NODE_STATE_DOWN) {
907 		GtkWidget *image = gtk_image_new_from_stock(
908 			GTK_STOCK_CANCEL,
909 			GTK_ICON_SIZE_SMALL_TOOLBAR);
910 		send_grid_button->button = gtk_event_box_new();
911 		gtk_event_box_set_above_child(
912 			GTK_EVENT_BOX(send_grid_button->button),
913 			false);
914 		gdk_color_parse("black", &color);
915 		sview_widget_modify_bg(send_grid_button->button,
916 				       GTK_STATE_NORMAL, color);
917 		//gdk_color_parse("white", &color);
918 /* 		sview_widget_modify_bg(send_grid_button->button,  */
919 /* 				     GTK_STATE_ACTIVE, color); */
920 		gtk_container_add(
921 			GTK_CONTAINER(send_grid_button->button),
922 			image);
923 	} else if ((color_inx >= 0)
924 		   && (send_grid_button->state & NODE_STATE_DRAIN)) {
925 		GtkWidget *image = gtk_image_new_from_stock(
926 			GTK_STOCK_DIALOG_ERROR,
927 			GTK_ICON_SIZE_SMALL_TOOLBAR);
928 
929 		send_grid_button->button = gtk_event_box_new();
930 		gtk_event_box_set_above_child(
931 			GTK_EVENT_BOX(send_grid_button->button),
932 			false);
933 		gdk_color_parse("black", &color);
934 /* 		sview_widget_modify_bg(send_grid_button->button,  */
935 /* 				       GTK_STATE_NORMAL, color); */
936 		//gdk_color_parse("white", &color);
937 /* 		sview_widget_modify_bg(send_grid_button->button,  */
938 /* 				       GTK_STATE_ACTIVE, color); */
939 		gtk_container_add(
940 			GTK_CONTAINER(send_grid_button->button),
941 			image);
942 	} else {
943 		send_grid_button->button = gtk_button_new();
944 		send_grid_button->color = new_col;
945 		gdk_color_parse(new_col, &color);
946 		sview_widget_modify_bg(send_grid_button->button,
947 				       GTK_STATE_NORMAL, color);
948 /* 		sview_widget_modify_bg(send_grid_button->button,  */
949 /* 				       GTK_STATE_ACTIVE, color); */
950 	}
951 	gtk_widget_set_size_request(send_grid_button->button,
952 				    working_sview_config.button_size,
953 				    working_sview_config.button_size);
954 
955 	send_grid_button->node_name = xstrdup(name);
956 
957 	return send_grid_button;
958 }
959 
960 /* start == -1 for all */
change_grid_color(List button_list,int start,int end,int color_inx,bool only_change_unused,enum node_states state_override)961 extern void change_grid_color(List button_list, int start, int end,
962 			      int color_inx, bool only_change_unused,
963 			      enum node_states state_override)
964 {
965 	ListIterator itr = NULL;
966 	grid_button_t *grid_button = NULL;
967 	GdkColor color;
968 	char *new_col = NULL;
969 
970 	if (!button_list)
971 		return;
972 
973 	if (color_inx >= 0) {
974 		color_inx %= sview_colors_cnt;
975 		new_col = sview_colors[color_inx];
976 	} else if (color_inx == MAKE_BLACK) {
977 		new_col = blank_color;
978 	} else if (color_inx == MAKE_TOPO_1) {
979 		new_col = topo1_color;
980 	} else if (color_inx == MAKE_TOPO_2) {
981 		new_col = topo2_color;
982 	} else
983 		new_col = white_color;
984 
985 	gdk_color_parse(new_col, &color);
986 
987 	itr = list_iterator_create(button_list);
988 	while ((grid_button = list_next(itr))) {
989 		if ((start != -1) &&
990 		    ((grid_button->inx < start) || (grid_button->inx > end)))
991 			continue;
992 		_change_button_color(grid_button, color_inx, new_col,
993 				     color, only_change_unused, state_override);
994 	}
995 	list_iterator_destroy(itr);
996 }
997 
998 /* This variation of change_grid_color() is faster when changing many
999  * button colors at the same time since we can issue a single call to
1000  * _change_button_color() and eliminate a nested loop. */
change_grid_color_array(List button_list,int array_len,int * color_inx,bool * color_set_flag,bool only_change_unused,enum node_states state_override)1001 extern void change_grid_color_array(List button_list, int array_len,
1002 				    int *color_inx, bool *color_set_flag,
1003 				    bool only_change_unused,
1004 				    enum node_states state_override)
1005 {
1006 	ListIterator itr = NULL;
1007 	grid_button_t *grid_button = NULL;
1008 	GdkColor color;
1009 	char *new_col = NULL;
1010 
1011 	if (!button_list)
1012 		return;
1013 
1014 	itr = list_iterator_create(button_list);
1015 	while ((grid_button = list_next(itr))) {
1016 		if ((grid_button->inx < 0) || (grid_button->inx >= array_len))
1017 			continue;
1018 		if (!color_set_flag[grid_button->inx])
1019 			continue;
1020 
1021 		if (color_inx[grid_button->inx] >= 0) {
1022 			color_inx[grid_button->inx] %= sview_colors_cnt;
1023 			new_col = sview_colors[color_inx[grid_button->inx]];
1024 		} else if (color_inx[grid_button->inx] == MAKE_BLACK) {
1025 			new_col = blank_color;
1026 		} else if (color_inx[grid_button->inx] == MAKE_TOPO_1) {
1027 			new_col = topo1_color;
1028 		} else if (color_inx[grid_button->inx] == MAKE_TOPO_2) {
1029 			new_col = topo2_color;
1030 		} else
1031 			new_col = white_color;
1032 		gdk_color_parse(new_col, &color);
1033 
1034 		_change_button_color(grid_button, color_inx[grid_button->inx],
1035 				     new_col, color, only_change_unused,
1036 				     state_override);
1037 	}
1038 	list_iterator_destroy(itr);
1039 	return;
1040 }
1041 
highlight_grid(GtkTreeView * tree_view,int node_inx_id,int color_inx_id,List button_list)1042 extern void highlight_grid(GtkTreeView *tree_view,
1043 			   int node_inx_id, int color_inx_id, List button_list)
1044 {
1045 	ListIterator itr = NULL;
1046 	grid_button_t *grid_button = NULL;
1047 	grid_foreach_t grid_foreach;
1048 
1049 	if (!button_list || !tree_view)
1050 		return;
1051 
1052 	/*first clear all grid buttons*/
1053 	itr = list_iterator_create(button_list);
1054 	while ((grid_button = list_next(itr))) {
1055 		/* clear everyone */
1056 		if ((gtk_widget_get_state(grid_button->button)
1057 		     != GTK_STATE_ACTIVE)) {
1058 			gtk_widget_set_state(grid_button->button,
1059 					     GTK_STATE_ACTIVE);
1060 		}
1061 	}
1062 	list_iterator_destroy(itr);
1063 
1064 	/* for each currently selected row,go back & ensure the
1065 	 * corresponding grid button is highlighted */
1066 	memset(&grid_foreach, 0, sizeof(grid_foreach_t));
1067 	grid_foreach.node_inx_id = node_inx_id;
1068 	grid_foreach.color_inx_id = color_inx_id;
1069 	grid_foreach.button_list = button_list;
1070 	if (grid_foreach.color_inx_id != (int)NO_VAL)
1071 		gtk_tree_selection_selected_foreach(
1072 			gtk_tree_view_get_selection(tree_view),
1073 			_each_highlightd, &grid_foreach);
1074 	else
1075 		gtk_tree_selection_selected_foreach(
1076 			gtk_tree_view_get_selection(tree_view),
1077 			_each_highlight_selected, &grid_foreach);
1078 
1079 	return;
1080 }
1081 
1082 /* start == -1 for all */
highlight_grid_range(int start,int end,List button_list)1083 extern void highlight_grid_range(int start, int end, List button_list)
1084 {
1085 	ListIterator itr = NULL;
1086 	grid_button_t *grid_button = NULL;
1087 
1088 	if (!button_list)
1089 		return;
1090 
1091 	itr = list_iterator_create(button_list);
1092 	while ((grid_button = list_next(itr))) {
1093 		if (start != -1)
1094 			if ((grid_button->inx < start)
1095 			    || (grid_button->inx > end)) {
1096 				/* clear everyone else */
1097 				if ((gtk_widget_get_state(grid_button->button)
1098 				     != GTK_STATE_ACTIVE))
1099 					gtk_widget_set_state(
1100 						grid_button->button,
1101 						GTK_STATE_ACTIVE);
1102 				continue;
1103 			}
1104 		/* highlight this one, if it is already hightlighted,
1105 		 * put it back to normal */
1106 		//g_print("highlighting %d\n", grid_button->inx);
1107 		if ((gtk_widget_get_state(grid_button->button)
1108 		     != GTK_STATE_NORMAL))
1109 			gtk_widget_set_state(grid_button->button,
1110 					     GTK_STATE_NORMAL);
1111 	}
1112 	list_iterator_destroy(itr);
1113 
1114 	return;
1115 }
1116 
set_grid_used(List button_list,int start,int end,bool used,bool reset_highlight)1117 extern void set_grid_used(List button_list, int start, int end,
1118 			  bool used, bool reset_highlight)
1119 {
1120 	ListIterator itr = NULL;
1121 	grid_button_t *grid_button = NULL;
1122 
1123 	if (!button_list)
1124 		return;
1125 
1126 	itr = list_iterator_create(button_list);
1127 	while ((grid_button = list_next(itr))) {
1128 		if (start != -1)
1129 			if ((grid_button->inx < start)
1130 			    || (grid_button->inx > end))
1131 				continue;
1132 		grid_button->used = used;
1133 		if (reset_highlight)
1134 			gtk_widget_set_state(grid_button->button,
1135 					     GTK_STATE_NORMAL);
1136 
1137 	}
1138 	list_iterator_destroy(itr);
1139 
1140 	return;
1141 }
1142 
get_button_list_from_main(List * button_list,int start,int end,int color_inx)1143 extern void get_button_list_from_main(List *button_list, int start, int end,
1144 				      int color_inx)
1145 {
1146 	ListIterator itr = NULL;
1147 	ListIterator button_itr = NULL;
1148 	grid_button_t *grid_button = NULL;
1149 	grid_button_t *send_grid_button = NULL;
1150 
1151 	if (!*button_list)
1152 		*button_list = list_create(destroy_grid_button);
1153 
1154 	color_inx %= sview_colors_cnt;
1155 	itr = list_iterator_create(grid_button_list);
1156 	while ((grid_button = list_next(itr))) {
1157 		if ((grid_button->inx < start)
1158 		    ||  (grid_button->inx > end))
1159 			continue;
1160 		button_itr = list_iterator_create(*button_list);
1161 		while ((send_grid_button = list_next(button_itr))) {
1162 			if (send_grid_button->inx == grid_button->inx)
1163 				break;
1164 		}
1165 		list_iterator_destroy(button_itr);
1166 		if (send_grid_button)
1167 			continue;
1168 
1169 		send_grid_button = create_grid_button_from_another(
1170 			grid_button, grid_button->node_name, color_inx);
1171 		if (send_grid_button) {
1172 			send_grid_button->button_list = *button_list;
1173 			_add_button_signals(send_grid_button);
1174 			list_append(*button_list, send_grid_button);
1175 		}
1176 	}
1177 	list_iterator_destroy(itr);
1178 	return;
1179 }
1180 
copy_main_button_list(int initial_color)1181 extern List copy_main_button_list(int initial_color)
1182 {
1183 	ListIterator itr = NULL;
1184 	grid_button_t *grid_button = NULL;
1185 	grid_button_t *send_grid_button = NULL;
1186 	List button_list = list_create(destroy_grid_button);
1187 
1188 	itr = list_iterator_create(grid_button_list);
1189 	while ((grid_button = list_next(itr))) {
1190 		send_grid_button = create_grid_button_from_another(
1191 			grid_button, grid_button->node_name, initial_color);
1192 		if (send_grid_button) {
1193 			send_grid_button->button_list = button_list;
1194 			_add_button_signals(send_grid_button);
1195 			send_grid_button->used = false;
1196 			list_append(button_list, send_grid_button);
1197 		}
1198 	}
1199 	list_iterator_destroy(itr);
1200 	return button_list;
1201 }
1202 
put_buttons_in_table(GtkTable * table,List button_list)1203 extern void put_buttons_in_table(GtkTable *table, List button_list)
1204 {
1205 	int coord_x=0, coord_y=0;
1206 	button_processor_t button_processor;
1207 	grid_button_t *grid_button = NULL;
1208 	ListIterator itr = NULL;
1209 	list_sort(button_list, (ListCmpF) _sort_button_inx);
1210 
1211 	if (!button_list) {
1212 		g_print("put_buttons_in_table: no node_list given\n");
1213 		return;
1214 	}
1215 
1216 	if (_init_button_processor(&button_processor, list_count(button_list))
1217 	    != SLURM_SUCCESS)
1218 		return;
1219 
1220 	button_processor.table = table;
1221 	button_processor.button_list = button_list;
1222 	button_processor.coord_x = &coord_x;
1223 	button_processor.coord_y = &coord_y;
1224 
1225 	gtk_table_resize(table, button_processor.table_y,
1226 			 working_sview_config.grid_x_width);
1227 
1228 	itr = list_iterator_create(button_list);
1229 	while ((grid_button = list_next(itr))) {
1230 		if (cluster_dims == 3) {
1231 			grid_button->table = table;
1232 			gtk_table_attach(table, grid_button->button,
1233 					 grid_button->table_x,
1234 					 (grid_button->table_x+1),
1235 					 grid_button->table_y,
1236 					 (grid_button->table_y+1),
1237 					 GTK_SHRINK, GTK_SHRINK,
1238 					 1, 1);
1239 			if (!grid_button->table_x) {
1240 				gtk_table_set_row_spacing(table,
1241 						grid_button->table_y,
1242 						working_sview_config.gap_size);
1243 			}
1244 		} else {
1245 			grid_button->table = table;
1246 			grid_button->table_x = coord_x;
1247 			grid_button->table_y = coord_y;
1248 			gtk_table_attach(table, grid_button->button,
1249 					 coord_x, (coord_x+1),
1250 					 coord_y, (coord_y+1),
1251 					 GTK_SHRINK, GTK_SHRINK,
1252 					 1, 1);
1253 			coord_x++;
1254 			if (coord_x == working_sview_config.grid_x_width) {
1255 				coord_x = 0;
1256 				coord_y++;
1257 				if (!(coord_y % working_sview_config.grid_vert))
1258 					gtk_table_set_row_spacing(
1259 						table, coord_y-1,
1260 						working_sview_config.gap_size);
1261 			}
1262 
1263 			if (coord_y == button_processor.table_y)
1264 				break;
1265 
1266 			if (coord_x
1267 			    && !(coord_x % working_sview_config.grid_hori))
1268 				gtk_table_set_col_spacing(table, coord_x-1, 5);
1269 		}
1270 	}
1271 	list_iterator_destroy(itr);
1272 
1273 	if (cluster_dims == 0) {
1274 		/* This is needed to get the correct width of the grid window.
1275 		 * If it is not given then we get a really narrow window. */
1276 		gtk_table_set_row_spacing(table, coord_y?(coord_y-1):0, 1);
1277 	}
1278 	gtk_widget_show_all(GTK_WIDGET(table));
1279 }
1280 
update_grid_table(GtkTable * table,List button_list,List node_list)1281 extern int update_grid_table(GtkTable *table, List button_list, List node_list)
1282 {
1283 	int rc = SLURM_SUCCESS;
1284 	int coord_x=0, coord_y=0, inx=0;
1285 	ListIterator itr = NULL, itr2 = NULL;
1286 	sview_node_info_t *sview_node_info_ptr = NULL;
1287 	button_processor_t button_processor;
1288 
1289 	if (!node_list) {
1290 		g_print("update_grid_table: no node_list given\n");
1291 		return SLURM_ERROR;
1292 	}
1293 
1294 	if (_init_button_processor(&button_processor, list_count(node_list))
1295 	    != SLURM_SUCCESS)
1296 		return SLURM_ERROR;
1297 
1298 	button_processor.table = table;
1299 	button_processor.button_list = button_list;
1300 	button_processor.coord_x = &coord_x;
1301 	button_processor.coord_y = &coord_y;
1302 	button_processor.inx = &inx;
1303 
1304 	gtk_table_resize(table, button_processor.table_y,
1305 			 working_sview_config.grid_x_width);
1306 	gtk_table_set_row_spacings(table, 0);
1307 	gtk_table_set_col_spacings(table, 0);
1308 	itr = list_iterator_create(node_list);
1309 	itr2 = list_iterator_create(button_list);
1310 
1311 	while ((sview_node_info_ptr = list_next(itr))) {
1312 		int found = 0;
1313 		/* if (!working_sview_config.show_hidden */
1314 		/*     && !check_part_includes_node(inx)) { */
1315 		/* 	inx++; */
1316 		/* 	continue; */
1317 		/* } */
1318 
1319 //	again:
1320 		while ((button_processor.grid_button = list_next(itr2))) {
1321 			if (button_processor.grid_button->inx != inx) {
1322 				continue;
1323 			}
1324 			found = 1;
1325 
1326 			if ((rc = _add_button_to_list(
1327 				     sview_node_info_ptr->node_ptr,
1328 				     &button_processor)) != SLURM_SUCCESS)
1329 				goto end_it;
1330 			break;
1331 		}
1332 		if (!found) {
1333 			//list_iterator_reset(itr2);
1334 			//goto again;
1335 			return RESET_GRID;
1336 		}
1337 		inx++;
1338 	}
1339 	rc = _add_button_to_list(NULL, &button_processor);
1340 
1341 	/* This is needed to get the correct width of the grid window.
1342 	 * If it is not given then we get a really narrow window. */
1343 	gtk_table_set_row_spacing(table, coord_y?(coord_y-1):0, 1);
1344 
1345 end_it:
1346 	list_iterator_destroy(itr);
1347 	list_iterator_destroy(itr2);
1348 	return rc;
1349 }
1350 
get_system_stats(GtkTable * table)1351 extern int get_system_stats(GtkTable *table)
1352 {
1353 	int rc = SLURM_SUCCESS;
1354 	node_info_msg_t *node_info_ptr = NULL;
1355 	List node_list = NULL;
1356 
1357 	if ((rc = get_new_info_node(&node_info_ptr, force_refresh))
1358 	    == SLURM_NO_CHANGE_IN_DATA) {
1359 	} else if (rc != SLURM_SUCCESS)
1360 		return SLURM_ERROR;
1361 
1362 	node_list = create_node_info_list(node_info_ptr, false);
1363 	if (grid_button_list) {
1364 		rc = update_grid_table(main_grid_table, grid_button_list,
1365 				       node_list);
1366 		if (rc == RESET_GRID) {
1367 			FREE_NULL_LIST(grid_button_list);
1368 			grid_button_list = list_create(destroy_grid_button);
1369 			setup_grid_table(main_grid_table, grid_button_list,
1370 					 node_list);
1371 		}
1372 	} else {
1373 		grid_button_list = list_create(destroy_grid_button);
1374 		setup_grid_table(main_grid_table, grid_button_list, node_list);
1375 	}
1376 
1377 	gtk_widget_show_all(GTK_WIDGET(main_grid_table));
1378 
1379 	return SLURM_SUCCESS;
1380 }
1381 
setup_grid_table(GtkTable * table,List button_list,List node_list)1382 extern int setup_grid_table(GtkTable *table, List button_list, List node_list)
1383 {
1384 	int rc = SLURM_SUCCESS;
1385 	button_processor_t button_processor;
1386 	int coord_x=0, coord_y=0;
1387 
1388 	if (!node_list) {
1389 		g_print("setup_grid_table: no node_list given\n");
1390 		return SLURM_ERROR;
1391 	}
1392 
1393 	if (_init_button_processor(&button_processor, list_count(node_list))
1394 	    != SLURM_SUCCESS)
1395 		return SLURM_ERROR;
1396 
1397 	button_processor.table = table;
1398 	button_processor.button_list = button_list;
1399 	button_processor.coord_x = &coord_x;
1400 	button_processor.coord_y = &coord_y;
1401 
1402 	gtk_table_resize(table, button_processor.table_y,
1403 			 working_sview_config.grid_x_width);
1404 
1405 	if (default_sview_config.grid_topological && g_topo_info_msg_ptr)
1406 		rc = _grid_table_by_switch(&button_processor, node_list);
1407 	else
1408 		rc = _grid_table_by_list(&button_processor, node_list);
1409 
1410 	list_sort(button_list, (ListCmpF) _sort_button_inx);
1411 
1412 	return rc;
1413 }
1414 
sview_init_grid(bool reset_highlight)1415 extern void sview_init_grid(bool reset_highlight)
1416 {
1417 	static node_info_msg_t *node_info_ptr = NULL;
1418 	int rc = SLURM_SUCCESS;
1419 	node_info_t *node_ptr = NULL;
1420 	int i = 0;
1421 	ListIterator itr = NULL;
1422 	grid_button_t *grid_button = NULL;
1423 
1424 	rc = get_new_info_node(&node_info_ptr, force_refresh);
1425 	if (rc == SLURM_NO_CHANGE_IN_DATA) {
1426 		/* need to clear out old data */
1427 		set_grid_used(grid_button_list, -1, -1, false, reset_highlight);
1428 		return;
1429 	} else if (rc != SLURM_SUCCESS) {
1430 		return;
1431 	}
1432 
1433 	if (!grid_button_list) {
1434 		g_print("you need to run get_system_stats() first\n");
1435 		exit(0);
1436 	}
1437 
1438 	itr = list_iterator_create(grid_button_list);
1439 	for (i = 0; i < node_info_ptr->record_count; i++) {
1440 		int tried_again = 0;
1441 		node_ptr = &node_info_ptr->node_array[i];
1442 	try_again:
1443 		while ((grid_button = list_next(itr))) {
1444 			if (grid_button->inx != i)
1445 				continue;
1446 			grid_button->state = node_ptr->node_state;
1447 			gtk_widget_set_state(grid_button->button,
1448 					     GTK_STATE_NORMAL);
1449 			grid_button->used = false;
1450 			break;
1451 		}
1452 		if (!grid_button && !tried_again) {
1453 			/* the order should never change but just to
1454 			 * make sure we don't miss it */
1455 			list_iterator_reset(itr);
1456 			tried_again = 1;
1457 			goto try_again;
1458 		}
1459 	}
1460 	list_iterator_destroy(itr);
1461 }
1462 
1463 /* make grid if it doesn't exist and set the buttons to unused */
setup_popup_grid_list(popup_info_t * popup_win)1464 extern void setup_popup_grid_list(popup_info_t *popup_win)
1465 {
1466 	int def_color = MAKE_BLACK;
1467 
1468 	if (popup_win->grid_button_list) {
1469 		set_grid_used(popup_win->grid_button_list,
1470 			      -1, -1, false, false);
1471 	} else {
1472 		popup_win->grid_button_list =
1473 			copy_main_button_list(def_color);
1474 		put_buttons_in_table(popup_win->grid_table,
1475 				     popup_win->grid_button_list);
1476 		popup_win->full_grid = 1;
1477 	}
1478 }
1479 
1480 /* clear extra buttons to N/A and if model then set those as white */
post_setup_popup_grid_list(popup_info_t * popup_win)1481 extern void post_setup_popup_grid_list(popup_info_t *popup_win)
1482 {
1483 	/* refresh the pointer */
1484 	if (popup_win->model
1485 	    && gtk_tree_store_iter_is_valid(GTK_TREE_STORE(popup_win->model),
1486 					    &popup_win->iter)) {
1487 		gtk_tree_model_get(popup_win->model, &popup_win->iter,
1488 				   popup_win->node_inx_id,
1489 				   &popup_win->node_inx, -1);
1490 	} else {
1491 		popup_win->node_inx = NULL;
1492 	}
1493 
1494 	if (popup_win->node_inx) {
1495 		int j=0;
1496 		while (popup_win->node_inx[j] >= 0) {
1497 			change_grid_color(
1498 				popup_win->grid_button_list,
1499 				popup_win->node_inx[j],
1500 				popup_win->node_inx[j+1], MAKE_WHITE, true, 0);
1501 			j += 2;
1502 		}
1503 	}
1504 
1505 	change_grid_color(popup_win->grid_button_list, -1, -1,
1506 			  MAKE_BLACK, true, NODE_STATE_IDLE);
1507 }
1508