| /****************************************************************************\ |
| * grid.c - put display grid info here |
| ***************************************************************************** |
| * Copyright (C) 2004-2007 The Regents of the University of California. |
| * Copyright (C) 2008-2010 Lawrence Livermore National Security. |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). |
| * Written by Danny Auble <da@llnl.gov>, et. al. |
| * CODE-OCEC-09-009. All rights reserved. |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include "config.h" |
| |
| #include "sview.h" |
| |
| #define RESET_GRID -2 |
| #define TOPO_DEBUG 0 |
| |
| list_t *grid_button_list = NULL; |
| list_t *blinking_button_list = NULL; |
| list_t *multi_button_list = NULL; |
| |
| char *sview_colors[] = {"#0000FF", "#00FF00", "#00FFFF", "#FFFF00", |
| "#FF0000", "#4D4DC6", "#F09A09", "#BDFA19", |
| "#715627", "#6A8CA2", "#4C7127", "#25B9B9", |
| "#A020F0", "#8293ED", "#FFA500", "#FFC0CB", |
| "#8B6914", "#18A24E", "#F827FC", "#B8A40C"}; |
| char *blank_color = "#919191"; |
| char *white_color = "#FFFFFF"; |
| char *topo1_color = "honeydew"; //"seashell";DarkTurquoise |
| char *topo2_color = "gray94";//honeydew"; |
| |
| int sview_colors_cnt = 20; |
| |
| typedef struct { |
| int node_inx_id; |
| int color_inx_id; |
| list_t *button_list; |
| } grid_foreach_t; |
| |
| typedef struct { |
| list_t *button_list; |
| int *coord_x; |
| int *coord_y; |
| int default_y_offset; |
| grid_button_t *grid_button; |
| int *inx; |
| GtkTable *table; |
| int table_y; |
| bool force_row_break; |
| } button_processor_t; |
| |
| static gboolean _mouseover_node(GtkWidget *widget, GdkEventButton *event, |
| grid_button_t *grid_button) |
| { |
| gboolean rc = true; |
| |
| grid_button->last_state = gtk_widget_get_state(widget); |
| #ifdef GTK2_USE_TOOLTIP |
| gtk_widget_set_tooltip_text(grid_button->button, |
| grid_button->node_name); |
| #else |
| if (!grid_button->tip) |
| grid_button->tip = gtk_tooltips_new(); |
| gtk_tooltips_set_tip(grid_button->tip, |
| grid_button->button, |
| grid_button->node_name, |
| "click for node stats"); |
| #endif |
| //g_print("on at %s\n", grid_button->node_name); |
| gtk_widget_set_state(grid_button->button, GTK_STATE_PRELIGHT); |
| |
| return rc; |
| } |
| |
| static gboolean _mouseoff_node(GtkWidget *widget, GdkEventButton *event, |
| grid_button_t *grid_button) |
| { |
| gboolean rc = false; |
| |
| if (grid_button->last_state == GTK_STATE_ACTIVE) { |
| gtk_widget_set_state(grid_button->button, GTK_STATE_ACTIVE); |
| rc = true; |
| //g_print("off of %s\n", grid_button->node_name); |
| } |
| return rc; |
| } |
| |
| static gboolean _open_node(GtkWidget *widget, GdkEventButton *event, |
| grid_button_t *grid_button) |
| { |
| if (event->button == 1) { |
| popup_all_node_name(grid_button->node_name, INFO_PAGE, NULL); |
| } else if (event->button == 3) { |
| /* right click */ |
| admin_menu_node_name(grid_button->node_name, event); |
| } |
| |
| return false; |
| } |
| |
| /* static void _state_changed(GtkWidget *button, GtkStateType state, */ |
| /* grid_button_t *grid_button) */ |
| /* { */ |
| /* g_print("state of %s is now %d\n", grid_button->node_name, state); */ |
| /* } */ |
| |
| static void _add_button_signals(grid_button_t *grid_button) |
| { |
| /* g_signal_connect(G_OBJECT(grid_button->button), */ |
| /* "state-changed", */ |
| /* G_CALLBACK(_state_changed), */ |
| /* grid_button); */ |
| g_signal_connect(G_OBJECT(grid_button->button), |
| "button-press-event", |
| G_CALLBACK(_open_node), |
| grid_button); |
| g_signal_connect(G_OBJECT(grid_button->button), |
| "enter-notify-event", |
| G_CALLBACK(_mouseover_node), |
| grid_button); |
| g_signal_connect(G_OBJECT(grid_button->button), |
| "leave-notify-event", |
| G_CALLBACK(_mouseoff_node), |
| grid_button); |
| } |
| |
| /* |
| * Comparator used for sorting buttons |
| * |
| * returns: -1: button_a->inx > button_b->inx |
| * 0: rec_a == rec_b |
| * 1: rec_a < rec_b |
| * |
| */ |
| static int _sort_button_inx(void *b1, void *b2) |
| { |
| grid_button_t *button_a = *(grid_button_t **)b1; |
| grid_button_t *button_b = *(grid_button_t **)b2; |
| int inx_a; |
| int inx_b; |
| |
| inx_a = button_a->inx; |
| inx_b = button_b->inx; |
| |
| if (inx_a < inx_b) |
| return -1; |
| else if (inx_a > inx_b) |
| return 1; |
| return 0; |
| } |
| |
| void _put_button_as_down(grid_button_t *grid_button, int state) |
| { |
| GtkWidget *image = NULL; |
| /* GdkColor color; */ |
| |
| if (GTK_IS_EVENT_BOX(grid_button->button)) { |
| //gtk_widget_set_sensitive (grid_button->button, true); |
| return; |
| } |
| |
| gtk_widget_destroy(grid_button->button); |
| grid_button->color = NULL; |
| grid_button->color_inx = MAKE_DOWN; |
| grid_button->button = gtk_event_box_new(); |
| gtk_widget_set_size_request(grid_button->button, |
| working_sview_config.button_size, |
| working_sview_config.button_size); |
| gtk_event_box_set_above_child(GTK_EVENT_BOX(grid_button->button), |
| false); |
| _add_button_signals(grid_button); |
| |
| /* if (grid_button->frame) */ |
| /* gtk_container_add(GTK_CONTAINER(grid_button->frame), */ |
| /* grid_button->button); */ |
| if (grid_button->table) |
| gtk_table_attach(grid_button->table, grid_button->button, |
| grid_button->table_x, |
| (grid_button->table_x+1), |
| grid_button->table_y, |
| (grid_button->table_y+1), |
| GTK_SHRINK, GTK_SHRINK, |
| 1, 1); |
| |
| //gdk_color_parse("black", &color); |
| //sview_widget_modify_bg(grid_button->button, GTK_STATE_NORMAL, color); |
| //gdk_color_parse(white_color, &color); |
| //sview_widget_modify_bg(grid_button->button, GTK_STATE_ACTIVE, color); |
| if (state == NODE_STATE_DRAIN) |
| image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_ERROR, |
| GTK_ICON_SIZE_SMALL_TOOLBAR); |
| else |
| image = gtk_image_new_from_stock(GTK_STOCK_CANCEL, |
| GTK_ICON_SIZE_SMALL_TOOLBAR); |
| gtk_container_add(GTK_CONTAINER(grid_button->button), image); |
| gtk_widget_show_all(grid_button->button); |
| return; |
| } |
| |
| |
| void _put_button_as_up(grid_button_t *grid_button) |
| { |
| if (GTK_IS_BUTTON(grid_button->button)) { |
| return; |
| } |
| gtk_widget_destroy(grid_button->button); |
| grid_button->button = gtk_button_new(); |
| gtk_widget_set_size_request(grid_button->button, |
| working_sview_config.button_size, |
| working_sview_config.button_size); |
| _add_button_signals(grid_button); |
| |
| /* if (grid_button->frame) */ |
| /* gtk_container_add(GTK_CONTAINER(grid_button->frame), */ |
| /* grid_button->button); */ |
| if (grid_button->table) |
| gtk_table_attach(grid_button->table, grid_button->button, |
| grid_button->table_x, |
| (grid_button->table_x+1), |
| grid_button->table_y, |
| (grid_button->table_y+1), |
| GTK_SHRINK, GTK_SHRINK, |
| 1, 1); |
| gtk_widget_show_all(grid_button->button); |
| return; |
| } |
| |
| void _put_button_as_inactive(grid_button_t *grid_button) |
| { |
| if (GTK_IS_BUTTON(grid_button->button)) { |
| //gtk_widget_set_sensitive (grid_button->button, false); |
| return; |
| } |
| gtk_widget_destroy(grid_button->button); |
| grid_button->button = gtk_button_new(); |
| gtk_widget_set_size_request(grid_button->button, |
| working_sview_config.button_size, |
| working_sview_config.button_size); |
| //gtk_widget_set_sensitive (grid_button->button, false); |
| |
| _add_button_signals(grid_button); |
| |
| /* if (grid_button->frame) */ |
| /* gtk_container_add(GTK_CONTAINER(grid_button->frame), */ |
| /* grid_button->button); */ |
| if (grid_button->table) |
| gtk_table_attach(grid_button->table, grid_button->button, |
| grid_button->table_x, |
| (grid_button->table_x+1), |
| grid_button->table_y, |
| (grid_button->table_y+1), |
| GTK_SHRINK, GTK_SHRINK, |
| 1, 1); |
| gtk_widget_show_all(grid_button->button); |
| return; |
| } |
| |
| static bool _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) |
| { |
| enum node_states state; |
| uint16_t node_base_state; |
| bool changed = 0; |
| |
| xassert(grid_button); |
| if (only_change_unused && grid_button->used) |
| return 0; |
| |
| grid_button->used = true; |
| if (color_inx == MAKE_BLACK) { |
| if (grid_button->color_inx != color_inx) { |
| _put_button_as_inactive(grid_button); |
| grid_button->color = new_col; |
| grid_button->color_inx = color_inx; |
| sview_widget_modify_bg(grid_button->button, |
| GTK_STATE_NORMAL, color); |
| /* sview_widget_modify_bg(grid_button->button, */ |
| /* GTK_STATE_ACTIVE, */ |
| /* color); */ |
| changed = 1; |
| } |
| |
| return changed; |
| } |
| |
| if (state_override != NODE_STATE_UNKNOWN) |
| state = state_override; |
| else |
| state = grid_button->state; |
| |
| node_base_state = state & NODE_STATE_BASE; |
| |
| if (node_base_state == NODE_STATE_DOWN) { |
| _put_button_as_down(grid_button, NODE_STATE_DOWN); |
| } else if (state & NODE_STATE_DRAIN) { |
| _put_button_as_down(grid_button, NODE_STATE_DRAIN); |
| } else if (grid_button->node_name && |
| !xstrcmp(grid_button->node_name, "EMPTY")) { |
| grid_button->color_inx = MAKE_BLACK; |
| // _put_button_as_up(grid_button); |
| } else if (grid_button->color_inx != color_inx) { |
| _put_button_as_up(grid_button); |
| grid_button->color = new_col; |
| grid_button->color_inx = color_inx; |
| sview_widget_modify_bg(grid_button->button, |
| GTK_STATE_NORMAL, color); |
| /* sview_widget_modify_bg(grid_button->button, */ |
| /* GTK_STATE_ACTIVE, color); */ |
| changed = 1; |
| } |
| |
| return changed; |
| } |
| |
| |
| static void _each_highlightd(GtkTreeModel *model, |
| GtkTreePath *path, |
| GtkTreeIter *iter, |
| gpointer userdata) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| int *node_inx = NULL; |
| int color_inx; |
| |
| int j=0; |
| GdkColor color; |
| |
| grid_foreach_t *grid_foreach = userdata; |
| |
| gtk_tree_model_get(model, iter, grid_foreach->node_inx_id, |
| &node_inx, -1); |
| gtk_tree_model_get(model, iter, grid_foreach->color_inx_id, |
| &color_inx, -1); |
| |
| if (!node_inx) |
| return; |
| |
| if (color_inx > sview_colors_cnt) { |
| g_print("hey the color_inx from %d was set to %d > %d\n", |
| grid_foreach->color_inx_id, color_inx, |
| sview_colors_cnt); |
| color_inx %= sview_colors_cnt; |
| } |
| gdk_color_parse(sview_colors[color_inx], &color); |
| |
| itr = list_iterator_create(grid_foreach->button_list); |
| while ((grid_button = list_next(itr))) { |
| /*For multiple selections, need to retain all selected. |
| *(previously this assumed only one selected). |
| */ |
| |
| if ((node_inx[j] < 0) |
| || (grid_button->inx < node_inx[j]) |
| || (grid_button->inx > node_inx[j+1])) |
| continue; |
| |
| (void)_change_button_color(grid_button, color_inx, |
| sview_colors[color_inx], |
| color, 0, 0); |
| |
| if (gtk_widget_get_state(grid_button->button) != GTK_STATE_NORMAL) |
| gtk_widget_set_state(grid_button->button, |
| GTK_STATE_NORMAL); |
| |
| if (grid_button->inx == node_inx[j+1]) |
| j+=2; |
| |
| } |
| |
| list_iterator_destroy(itr); |
| return; |
| } |
| |
| static void _each_highlight_selected(GtkTreeModel *model, |
| GtkTreePath *path, |
| GtkTreeIter *iter, |
| gpointer userdata) |
| { |
| |
| grid_button_t *grid_button = NULL; |
| int node_inx = 0; |
| bool speedup_break = true; |
| grid_foreach_t *grid_foreach = userdata; |
| list_itr_t *itr = NULL; |
| |
| xassert(grid_foreach); |
| if (working_sview_config.grid_topological) |
| speedup_break = false; |
| |
| gtk_tree_model_get(model, iter, grid_foreach->node_inx_id, |
| &node_inx, -1); |
| |
| if (node_inx < 0 || !grid_foreach->button_list) |
| return; |
| itr = list_iterator_create(grid_foreach->button_list); |
| while ((grid_button = list_next(itr))) { |
| /* For multiple selections, need to retain all selected. |
| * (previously this assumed only one selected). */ |
| if (grid_button->inx != node_inx) |
| continue; |
| else if (gtk_widget_get_state(grid_button->button) |
| != GTK_STATE_NORMAL) { |
| gtk_widget_set_state(grid_button->button, |
| GTK_STATE_NORMAL); |
| change_grid_color(grid_button_list, grid_button->inx, |
| grid_button->inx, |
| grid_button->inx, true, 0); |
| } |
| if (speedup_break) |
| break; |
| speedup_break = true; //allow for secondary grid button |
| } |
| list_iterator_destroy(itr); |
| return; |
| |
| } |
| |
| /* Add a button for a given node. If node_ptr == NULL then fill in any gaps |
| * in the grid just for a clean look. Always call with node_ptr == NULL for |
| * the last call in the sequence. */ |
| static int _add_button_to_list(node_info_t *node_ptr, |
| button_processor_t *button_processor) |
| { |
| grid_button_t *grid_button = button_processor->grid_button; |
| |
| if (node_ptr == NULL) |
| return SLURM_SUCCESS; |
| |
| if (!grid_button) { |
| grid_button = xmalloc(sizeof(grid_button_t)); |
| grid_button->color_inx = MAKE_INIT; |
| grid_button->inx = (*button_processor->inx); |
| grid_button->table = button_processor->table; |
| grid_button->table_x = (*button_processor->coord_x); |
| grid_button->table_y = (*button_processor->coord_y); |
| grid_button->button = gtk_button_new(); |
| grid_button->node_name = xstrdup(node_ptr->name); |
| |
| gtk_widget_set_size_request(grid_button->button, |
| working_sview_config.button_size, |
| working_sview_config.button_size); |
| _add_button_signals(grid_button); |
| list_append(button_processor->button_list, grid_button); |
| |
| gtk_table_attach(button_processor->table, grid_button->button, |
| (*button_processor->coord_x), |
| ((*button_processor->coord_x)+1), |
| (*button_processor->coord_y), |
| ((*button_processor->coord_y)+1), |
| GTK_SHRINK, GTK_SHRINK, |
| 1, 1); |
| } else { |
| grid_button->table_x = (*button_processor->coord_x); |
| grid_button->table_y = (*button_processor->coord_y); |
| gtk_container_child_set( |
| GTK_CONTAINER(button_processor->table), |
| grid_button->button, |
| "left-attach", (*button_processor->coord_x), |
| "right-attach", ((*button_processor->coord_x)+1), |
| "top-attach", (*button_processor->coord_y), |
| "bottom-attach", ((*button_processor->coord_y)+1), |
| NULL); |
| } |
| /* gtk_container_add(GTK_CONTAINER(grid_button->frame), */ |
| /* grid_button->button); */ |
| /* gtk_frame_set_shadow_type(GTK_FRAME(grid_button->frame), */ |
| /* GTK_SHADOW_ETCHED_OUT); */ |
| |
| /* On linear systems we just up the x_coord until we hit the |
| * side of the table and then increment the coord_y. We add |
| * space between each tenth row. */ |
| (*button_processor->coord_x)++; |
| |
| if (button_processor->force_row_break) { |
| (*button_processor->coord_x) = 0; |
| (*button_processor->coord_y)++; |
| gtk_table_set_row_spacing( |
| button_processor->table, |
| (*button_processor->coord_y)-1, |
| working_sview_config.gap_size); |
| return SLURM_SUCCESS; |
| } |
| |
| if ((*button_processor->coord_x) |
| == working_sview_config.grid_x_width) { |
| (*button_processor->coord_x) = 0; |
| (*button_processor->coord_y)++; |
| if (!((*button_processor->coord_y) |
| % working_sview_config.grid_vert)) |
| gtk_table_set_row_spacing( |
| button_processor->table, |
| (*button_processor->coord_y)-1, |
| working_sview_config.gap_size); |
| } |
| |
| if ((*button_processor->coord_y) == button_processor->table_y) |
| return SLURM_SUCCESS; |
| |
| if ((*button_processor->coord_x) && |
| !((*button_processor->coord_x) |
| % working_sview_config.grid_hori)) |
| gtk_table_set_col_spacing( |
| button_processor->table, |
| (*button_processor->coord_x)-1, |
| working_sview_config.gap_size); |
| |
| return SLURM_SUCCESS; |
| } |
| |
| static int _grid_table_by_switch(button_processor_t *button_processor, |
| list_t *node_list) |
| { |
| int rc = SLURM_SUCCESS; |
| int inx = 0, ii = 0; |
| switch_record_bitmaps_t *sw_nodes_bitmaps_ptr = g_switch_nodes_maps; |
| #if TOPO_DEBUG |
| /* engage if want original display below switched */ |
| list_itr_t *itr = list_iterator_create(node_list); |
| sview_node_info_t *sview_node_info_ptr = NULL; |
| #endif |
| button_processor->inx = &inx; |
| for (ii = 0; ii < g_switch_nodes_maps_count; |
| ii++, sw_nodes_bitmaps_ptr++) { |
| int j = 0, first, last; |
| first = bit_ffs(sw_nodes_bitmaps_ptr->node_bitmap); |
| if (first == -1) |
| continue; |
| last = bit_fls(sw_nodes_bitmaps_ptr->node_bitmap); |
| button_processor->inx = &j; |
| button_processor->force_row_break = false; |
| for (j = first; j <= last; j++) { |
| if (TOPO_DEBUG) |
| g_print("allocated node = %s button# %d\n", |
| g_node_info_ptr->node_array[j].name, |
| j); |
| if (!bit_test(sw_nodes_bitmaps_ptr->node_bitmap, j)) |
| continue; |
| /* if (!working_sview_config.show_hidden) { */ |
| /* if (!check_part_includes_node(j)) */ |
| /* continue; */ |
| /* } */ |
| if (j == last) |
| button_processor->force_row_break = true; |
| if ((rc = _add_button_to_list( |
| &g_node_info_ptr->node_array[j], |
| button_processor)) != SLURM_SUCCESS) |
| break; |
| button_processor->force_row_break = false; |
| } |
| rc = _add_button_to_list(NULL, button_processor); |
| } |
| |
| #if TOPO_DEBUG |
| /* engage this if want original display below |
| * switched grid */ |
| button_processor->inx = &inx; |
| while ((sview_node_info_ptr = list_next(itr))) { |
| if ((rc = _add_button_to_list( |
| sview_node_info_ptr->node_ptr, |
| button_processor)) != SLURM_SUCCESS) |
| break; |
| inx++; |
| } |
| list_iterator_destroy(itr); |
| #endif |
| |
| /* This is needed to get the correct width of the grid window. |
| * If it is not given then we get a really narrow window. */ |
| gtk_table_set_row_spacing(button_processor->table, |
| (*button_processor->coord_y)? |
| ((*button_processor->coord_y)-1):0, 1); |
| |
| return rc; |
| |
| } |
| |
| static int _grid_table_by_list(button_processor_t *button_processor, |
| list_t *node_list) |
| { |
| sview_node_info_t *sview_node_info_ptr = NULL; |
| int inx = 0, rc = SLURM_SUCCESS; |
| list_itr_t *itr = list_iterator_create(node_list); |
| button_processor->inx = &inx; |
| |
| while ((sview_node_info_ptr = list_next(itr))) { |
| /* if (!working_sview_config.show_hidden) { */ |
| /* if (!check_part_includes_node(inx)) { */ |
| /* inx++; */ |
| /* continue; */ |
| /* } */ |
| /* } */ |
| if ((rc = _add_button_to_list( |
| sview_node_info_ptr->node_ptr, |
| button_processor)) != SLURM_SUCCESS) |
| break; |
| inx++; |
| } |
| list_iterator_destroy(itr); |
| rc = _add_button_to_list(NULL, button_processor); |
| |
| /* This is needed to get the correct width of the grid window. |
| * If it is not given then we get a really narrow window. */ |
| gtk_table_set_row_spacing(button_processor->table, |
| (*button_processor->coord_y)? |
| ((*button_processor->coord_y)-1):0, 1); |
| |
| |
| return rc; |
| } |
| |
| static int _init_button_processor(button_processor_t *button_processor, |
| int node_count) |
| { |
| if (node_count == 0) { |
| g_print("_init_button_processor: no nodes selected\n"); |
| return SLURM_ERROR; |
| } |
| |
| memset(button_processor, 0, sizeof(button_processor_t)); |
| |
| if (!working_sview_config.grid_x_width) { |
| if (node_count < 50) { |
| working_sview_config.grid_x_width = 1; |
| } else if (node_count < 500) { |
| working_sview_config.grid_x_width = 10; |
| } else { |
| working_sview_config.grid_x_width = 20; |
| } |
| } |
| button_processor->table_y = |
| (node_count / working_sview_config.grid_x_width) + 1; |
| |
| button_processor->force_row_break = false; |
| |
| return SLURM_SUCCESS; |
| } |
| /* static void _destroy_grid_foreach(void *arg) */ |
| /* { */ |
| /* grid_foreach_t *grid_foreach = (grid_foreach_t *)arg; */ |
| |
| /* if (grid_foreach) { */ |
| /* xfree(grid_foreach); */ |
| /* } */ |
| /* } */ |
| |
| extern void destroy_grid_button(void *arg) |
| { |
| grid_button_t *grid_button = (grid_button_t *)arg; |
| if (grid_button) { |
| if (grid_button->button) { |
| gtk_widget_destroy(grid_button->button); |
| grid_button->button = NULL; |
| } |
| xfree(grid_button->node_name); |
| xfree(grid_button); |
| } |
| } |
| |
| /* we don't set the call back for the button here because sometimes we |
| * need to get a different call back based on what we are doing with |
| * the button, an example of this would be in |
| * add_extra_bluegene_buttons were the small block buttons do |
| * something different than they do regularly |
| * TODO - this may be simplified now that bluegene is gone. |
| */ |
| |
| extern grid_button_t *create_grid_button_from_another( |
| grid_button_t *grid_button, char *name, int color_inx) |
| { |
| grid_button_t *send_grid_button = NULL; |
| GdkColor color; |
| uint16_t node_base_state; |
| char *new_col = NULL; |
| |
| if (!grid_button || !name) |
| return NULL; |
| if (color_inx >= 0) { |
| color_inx %= sview_colors_cnt; |
| new_col = sview_colors[color_inx]; |
| } else if (color_inx == MAKE_BLACK) |
| new_col = blank_color; |
| else |
| new_col = white_color; |
| |
| send_grid_button = xmalloc(sizeof(grid_button_t)); |
| memcpy(send_grid_button, grid_button, sizeof(grid_button_t)); |
| node_base_state = send_grid_button->state & NODE_STATE_BASE; |
| send_grid_button->color_inx = color_inx; |
| |
| /* need to set the table to empty because we will want to fill |
| this into the new table later */ |
| send_grid_button->table = NULL; |
| if (color_inx == MAKE_BLACK) { |
| send_grid_button->button = gtk_button_new(); |
| //gtk_widget_set_sensitive (send_grid_button->button, false); |
| gdk_color_parse(new_col, &color); |
| send_grid_button->color = new_col; |
| sview_widget_modify_bg(send_grid_button->button, |
| GTK_STATE_NORMAL, color); |
| /* sview_widget_modify_bg(send_grid_button->button, */ |
| /* GTK_STATE_ACTIVE, color); */ |
| } else if ((color_inx >= 0) && node_base_state == NODE_STATE_DOWN) { |
| GtkWidget *image = gtk_image_new_from_stock( |
| GTK_STOCK_CANCEL, |
| GTK_ICON_SIZE_SMALL_TOOLBAR); |
| send_grid_button->button = gtk_event_box_new(); |
| gtk_event_box_set_above_child( |
| GTK_EVENT_BOX(send_grid_button->button), |
| false); |
| gdk_color_parse("black", &color); |
| sview_widget_modify_bg(send_grid_button->button, |
| GTK_STATE_NORMAL, color); |
| //gdk_color_parse("white", &color); |
| /* sview_widget_modify_bg(send_grid_button->button, */ |
| /* GTK_STATE_ACTIVE, color); */ |
| gtk_container_add( |
| GTK_CONTAINER(send_grid_button->button), |
| image); |
| } else if ((color_inx >= 0) |
| && (send_grid_button->state & NODE_STATE_DRAIN)) { |
| GtkWidget *image = gtk_image_new_from_stock( |
| GTK_STOCK_DIALOG_ERROR, |
| GTK_ICON_SIZE_SMALL_TOOLBAR); |
| |
| send_grid_button->button = gtk_event_box_new(); |
| gtk_event_box_set_above_child( |
| GTK_EVENT_BOX(send_grid_button->button), |
| false); |
| gdk_color_parse("black", &color); |
| /* sview_widget_modify_bg(send_grid_button->button, */ |
| /* GTK_STATE_NORMAL, color); */ |
| //gdk_color_parse("white", &color); |
| /* sview_widget_modify_bg(send_grid_button->button, */ |
| /* GTK_STATE_ACTIVE, color); */ |
| gtk_container_add( |
| GTK_CONTAINER(send_grid_button->button), |
| image); |
| } else { |
| send_grid_button->button = gtk_button_new(); |
| send_grid_button->color = new_col; |
| gdk_color_parse(new_col, &color); |
| sview_widget_modify_bg(send_grid_button->button, |
| GTK_STATE_NORMAL, color); |
| /* sview_widget_modify_bg(send_grid_button->button, */ |
| /* GTK_STATE_ACTIVE, color); */ |
| } |
| gtk_widget_set_size_request(send_grid_button->button, |
| working_sview_config.button_size, |
| working_sview_config.button_size); |
| |
| send_grid_button->node_name = xstrdup(name); |
| |
| return send_grid_button; |
| } |
| |
| /* start == -1 for all */ |
| extern void change_grid_color(list_t *button_list, int start, int end, |
| int color_inx, bool only_change_unused, |
| enum node_states state_override) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| GdkColor color; |
| char *new_col = NULL; |
| |
| if (!button_list) |
| return; |
| |
| if (color_inx >= 0) { |
| color_inx %= sview_colors_cnt; |
| new_col = sview_colors[color_inx]; |
| } else if (color_inx == MAKE_BLACK) { |
| new_col = blank_color; |
| } else if (color_inx == MAKE_TOPO_1) { |
| new_col = topo1_color; |
| } else if (color_inx == MAKE_TOPO_2) { |
| new_col = topo2_color; |
| } else |
| new_col = white_color; |
| |
| gdk_color_parse(new_col, &color); |
| |
| itr = list_iterator_create(button_list); |
| while ((grid_button = list_next(itr))) { |
| if ((start != -1) && |
| ((grid_button->inx < start) || (grid_button->inx > end))) |
| continue; |
| _change_button_color(grid_button, color_inx, new_col, |
| color, only_change_unused, state_override); |
| } |
| list_iterator_destroy(itr); |
| } |
| |
| /* This variation of change_grid_color() is faster when changing many |
| * button colors at the same time since we can issue a single call to |
| * _change_button_color() and eliminate a nested loop. */ |
| extern void change_grid_color_array(list_t *button_list, int array_len, |
| int *color_inx, bool *color_set_flag, |
| bool only_change_unused, |
| enum node_states state_override) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| GdkColor color; |
| char *new_col = NULL; |
| |
| if (!button_list) |
| return; |
| |
| itr = list_iterator_create(button_list); |
| while ((grid_button = list_next(itr))) { |
| if ((grid_button->inx < 0) || (grid_button->inx >= array_len)) |
| continue; |
| if (!color_set_flag[grid_button->inx]) |
| continue; |
| |
| if (color_inx[grid_button->inx] >= 0) { |
| color_inx[grid_button->inx] %= sview_colors_cnt; |
| new_col = sview_colors[color_inx[grid_button->inx]]; |
| } else if (color_inx[grid_button->inx] == MAKE_BLACK) { |
| new_col = blank_color; |
| } else if (color_inx[grid_button->inx] == MAKE_TOPO_1) { |
| new_col = topo1_color; |
| } else if (color_inx[grid_button->inx] == MAKE_TOPO_2) { |
| new_col = topo2_color; |
| } else |
| new_col = white_color; |
| gdk_color_parse(new_col, &color); |
| |
| _change_button_color(grid_button, color_inx[grid_button->inx], |
| new_col, color, only_change_unused, |
| state_override); |
| } |
| list_iterator_destroy(itr); |
| return; |
| } |
| |
| extern void highlight_grid(GtkTreeView *tree_view, int node_inx_id, |
| int color_inx_id, list_t *button_list) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| grid_foreach_t grid_foreach; |
| |
| if (!button_list || !tree_view) |
| return; |
| |
| /*first clear all grid buttons*/ |
| itr = list_iterator_create(button_list); |
| while ((grid_button = list_next(itr))) { |
| /* clear everyone */ |
| if ((gtk_widget_get_state(grid_button->button) |
| != GTK_STATE_ACTIVE)) { |
| gtk_widget_set_state(grid_button->button, |
| GTK_STATE_ACTIVE); |
| } |
| } |
| list_iterator_destroy(itr); |
| |
| /* for each currently selected row,go back & ensure the |
| * corresponding grid button is highlighted */ |
| memset(&grid_foreach, 0, sizeof(grid_foreach_t)); |
| grid_foreach.node_inx_id = node_inx_id; |
| grid_foreach.color_inx_id = color_inx_id; |
| grid_foreach.button_list = button_list; |
| if (grid_foreach.color_inx_id != (int)NO_VAL) |
| gtk_tree_selection_selected_foreach( |
| gtk_tree_view_get_selection(tree_view), |
| _each_highlightd, &grid_foreach); |
| else |
| gtk_tree_selection_selected_foreach( |
| gtk_tree_view_get_selection(tree_view), |
| _each_highlight_selected, &grid_foreach); |
| |
| return; |
| } |
| |
| /* start == -1 for all */ |
| extern void highlight_grid_range(int start, int end, list_t *button_list) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| |
| if (!button_list) |
| return; |
| |
| itr = list_iterator_create(button_list); |
| while ((grid_button = list_next(itr))) { |
| if (start != -1) |
| if ((grid_button->inx < start) |
| || (grid_button->inx > end)) { |
| /* clear everyone else */ |
| if ((gtk_widget_get_state(grid_button->button) |
| != GTK_STATE_ACTIVE)) |
| gtk_widget_set_state( |
| grid_button->button, |
| GTK_STATE_ACTIVE); |
| continue; |
| } |
| /* highlight this one, if it is already highlighted, |
| * put it back to normal */ |
| //g_print("highlighting %d\n", grid_button->inx); |
| if ((gtk_widget_get_state(grid_button->button) |
| != GTK_STATE_NORMAL)) |
| gtk_widget_set_state(grid_button->button, |
| GTK_STATE_NORMAL); |
| } |
| list_iterator_destroy(itr); |
| |
| return; |
| } |
| |
| extern void set_grid_used(list_t *button_list, int start, int end, |
| bool used, bool reset_highlight) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| |
| if (!button_list) |
| return; |
| |
| itr = list_iterator_create(button_list); |
| while ((grid_button = list_next(itr))) { |
| if (start != -1) |
| if ((grid_button->inx < start) |
| || (grid_button->inx > end)) |
| continue; |
| grid_button->used = used; |
| if (reset_highlight) |
| gtk_widget_set_state(grid_button->button, |
| GTK_STATE_NORMAL); |
| |
| } |
| list_iterator_destroy(itr); |
| |
| return; |
| } |
| |
| extern void get_button_list_from_main(list_t **button_list, int start, int end, |
| int color_inx) |
| { |
| list_itr_t *itr = NULL; |
| list_itr_t *button_itr = NULL; |
| grid_button_t *grid_button = NULL; |
| grid_button_t *send_grid_button = NULL; |
| |
| if (!*button_list) |
| *button_list = list_create(destroy_grid_button); |
| |
| color_inx %= sview_colors_cnt; |
| itr = list_iterator_create(grid_button_list); |
| while ((grid_button = list_next(itr))) { |
| if ((grid_button->inx < start) |
| || (grid_button->inx > end)) |
| continue; |
| button_itr = list_iterator_create(*button_list); |
| while ((send_grid_button = list_next(button_itr))) { |
| if (send_grid_button->inx == grid_button->inx) |
| break; |
| } |
| list_iterator_destroy(button_itr); |
| if (send_grid_button) |
| continue; |
| |
| send_grid_button = create_grid_button_from_another( |
| grid_button, grid_button->node_name, color_inx); |
| if (send_grid_button) { |
| send_grid_button->button_list = *button_list; |
| _add_button_signals(send_grid_button); |
| list_append(*button_list, send_grid_button); |
| } |
| } |
| list_iterator_destroy(itr); |
| return; |
| } |
| |
| extern list_t *copy_main_button_list(int initial_color) |
| { |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| grid_button_t *send_grid_button = NULL; |
| list_t *button_list = list_create(destroy_grid_button); |
| |
| itr = list_iterator_create(grid_button_list); |
| while ((grid_button = list_next(itr))) { |
| send_grid_button = create_grid_button_from_another( |
| grid_button, grid_button->node_name, initial_color); |
| if (send_grid_button) { |
| send_grid_button->button_list = button_list; |
| _add_button_signals(send_grid_button); |
| send_grid_button->used = false; |
| list_append(button_list, send_grid_button); |
| } |
| } |
| list_iterator_destroy(itr); |
| return button_list; |
| } |
| |
| extern void put_buttons_in_table(GtkTable *table, list_t *button_list) |
| { |
| int coord_x=0, coord_y=0; |
| button_processor_t button_processor; |
| grid_button_t *grid_button = NULL; |
| list_itr_t *itr = NULL; |
| list_sort(button_list, (ListCmpF) _sort_button_inx); |
| |
| if (!button_list) { |
| g_print("put_buttons_in_table: no node_list given\n"); |
| return; |
| } |
| |
| if (_init_button_processor(&button_processor, list_count(button_list)) |
| != SLURM_SUCCESS) |
| return; |
| |
| button_processor.table = table; |
| button_processor.button_list = button_list; |
| button_processor.coord_x = &coord_x; |
| button_processor.coord_y = &coord_y; |
| |
| gtk_table_resize(table, button_processor.table_y, |
| working_sview_config.grid_x_width); |
| |
| itr = list_iterator_create(button_list); |
| while ((grid_button = list_next(itr))) { |
| grid_button->table = table; |
| grid_button->table_x = coord_x; |
| grid_button->table_y = coord_y; |
| gtk_table_attach(table, grid_button->button, |
| coord_x, (coord_x+1), |
| coord_y, (coord_y+1), |
| GTK_SHRINK, GTK_SHRINK, |
| 1, 1); |
| coord_x++; |
| if (coord_x == working_sview_config.grid_x_width) { |
| coord_x = 0; |
| coord_y++; |
| if (!(coord_y % working_sview_config.grid_vert)) |
| gtk_table_set_row_spacing( |
| table, coord_y-1, |
| working_sview_config.gap_size); |
| } |
| |
| if (coord_y == button_processor.table_y) |
| break; |
| |
| if (coord_x |
| && !(coord_x % working_sview_config.grid_hori)) |
| gtk_table_set_col_spacing(table, coord_x-1, 5); |
| } |
| list_iterator_destroy(itr); |
| |
| gtk_widget_show_all(GTK_WIDGET(table)); |
| } |
| |
| extern int update_grid_table(GtkTable *table, list_t *button_list, |
| list_t *node_list) |
| { |
| int rc = SLURM_SUCCESS; |
| int coord_x=0, coord_y=0, inx=0; |
| list_itr_t *itr = NULL, *itr2 = NULL; |
| sview_node_info_t *sview_node_info_ptr = NULL; |
| button_processor_t button_processor; |
| |
| if (!node_list) { |
| g_print("update_grid_table: no node_list given\n"); |
| return SLURM_ERROR; |
| } |
| |
| if (_init_button_processor(&button_processor, list_count(node_list)) |
| != SLURM_SUCCESS) |
| return SLURM_ERROR; |
| |
| button_processor.table = table; |
| button_processor.button_list = button_list; |
| button_processor.coord_x = &coord_x; |
| button_processor.coord_y = &coord_y; |
| button_processor.inx = &inx; |
| |
| gtk_table_resize(table, button_processor.table_y, |
| working_sview_config.grid_x_width); |
| gtk_table_set_row_spacings(table, 0); |
| gtk_table_set_col_spacings(table, 0); |
| itr = list_iterator_create(node_list); |
| itr2 = list_iterator_create(button_list); |
| |
| while ((sview_node_info_ptr = list_next(itr))) { |
| int found = 0; |
| /* if (!working_sview_config.show_hidden */ |
| /* && !check_part_includes_node(inx)) { */ |
| /* inx++; */ |
| /* continue; */ |
| /* } */ |
| |
| // again: |
| while ((button_processor.grid_button = list_next(itr2))) { |
| if (button_processor.grid_button->inx != inx) { |
| continue; |
| } |
| found = 1; |
| |
| if ((rc = _add_button_to_list( |
| sview_node_info_ptr->node_ptr, |
| &button_processor)) != SLURM_SUCCESS) |
| goto end_it; |
| break; |
| } |
| if (!found) { |
| //list_iterator_reset(itr2); |
| //goto again; |
| return RESET_GRID; |
| } |
| inx++; |
| } |
| rc = _add_button_to_list(NULL, &button_processor); |
| |
| /* This is needed to get the correct width of the grid window. |
| * If it is not given then we get a really narrow window. */ |
| gtk_table_set_row_spacing(table, coord_y?(coord_y-1):0, 1); |
| |
| end_it: |
| list_iterator_destroy(itr); |
| list_iterator_destroy(itr2); |
| return rc; |
| } |
| |
| extern int get_system_stats(GtkTable *table) |
| { |
| int rc = SLURM_SUCCESS; |
| node_info_msg_t *node_info_ptr = NULL; |
| list_t *node_list = NULL; |
| |
| if ((rc = get_new_info_node(&node_info_ptr, force_refresh)) |
| == SLURM_NO_CHANGE_IN_DATA) { |
| } else if (rc != SLURM_SUCCESS) |
| return SLURM_ERROR; |
| |
| node_list = create_node_info_list(node_info_ptr, false); |
| if (grid_button_list) { |
| rc = update_grid_table(main_grid_table, grid_button_list, |
| node_list); |
| if (rc == RESET_GRID) { |
| FREE_NULL_LIST(grid_button_list); |
| grid_button_list = list_create(destroy_grid_button); |
| setup_grid_table(main_grid_table, grid_button_list, |
| node_list); |
| } |
| } else { |
| grid_button_list = list_create(destroy_grid_button); |
| setup_grid_table(main_grid_table, grid_button_list, node_list); |
| } |
| |
| gtk_widget_show_all(GTK_WIDGET(main_grid_table)); |
| |
| return SLURM_SUCCESS; |
| } |
| |
| extern int setup_grid_table(GtkTable *table, list_t *button_list, |
| list_t *node_list) |
| { |
| int rc = SLURM_SUCCESS; |
| button_processor_t button_processor; |
| int coord_x=0, coord_y=0; |
| |
| if (!node_list) { |
| g_print("setup_grid_table: no node_list given\n"); |
| return SLURM_ERROR; |
| } |
| |
| if (_init_button_processor(&button_processor, list_count(node_list)) |
| != SLURM_SUCCESS) |
| return SLURM_ERROR; |
| |
| button_processor.table = table; |
| button_processor.button_list = button_list; |
| button_processor.coord_x = &coord_x; |
| button_processor.coord_y = &coord_y; |
| |
| gtk_table_resize(table, button_processor.table_y, |
| working_sview_config.grid_x_width); |
| |
| if (default_sview_config.grid_topological && g_topo_info_msg_ptr) |
| rc = _grid_table_by_switch(&button_processor, node_list); |
| else |
| rc = _grid_table_by_list(&button_processor, node_list); |
| |
| list_sort(button_list, (ListCmpF) _sort_button_inx); |
| |
| return rc; |
| } |
| |
| extern void sview_init_grid(bool reset_highlight) |
| { |
| static node_info_msg_t *node_info_ptr = NULL; |
| int rc = SLURM_SUCCESS; |
| node_info_t *node_ptr = NULL; |
| int i = 0; |
| list_itr_t *itr = NULL; |
| grid_button_t *grid_button = NULL; |
| |
| rc = get_new_info_node(&node_info_ptr, force_refresh); |
| if (rc == SLURM_NO_CHANGE_IN_DATA) { |
| /* need to clear out old data */ |
| set_grid_used(grid_button_list, -1, -1, false, reset_highlight); |
| return; |
| } else if (rc != SLURM_SUCCESS) { |
| return; |
| } |
| |
| if (!grid_button_list) { |
| g_print("you need to run get_system_stats() first\n"); |
| exit(0); |
| } |
| |
| itr = list_iterator_create(grid_button_list); |
| for (i = 0; i < node_info_ptr->record_count; i++) { |
| int tried_again = 0; |
| node_ptr = &node_info_ptr->node_array[i]; |
| try_again: |
| while ((grid_button = list_next(itr))) { |
| if (grid_button->inx != i) |
| continue; |
| grid_button->state = node_ptr->node_state; |
| gtk_widget_set_state(grid_button->button, |
| GTK_STATE_NORMAL); |
| grid_button->used = false; |
| break; |
| } |
| if (!grid_button && !tried_again) { |
| /* the order should never change but just to |
| * make sure we don't miss it */ |
| list_iterator_reset(itr); |
| tried_again = 1; |
| goto try_again; |
| } |
| } |
| list_iterator_destroy(itr); |
| } |
| |
| /* make grid if it doesn't exist and set the buttons to unused */ |
| extern void setup_popup_grid_list(popup_info_t *popup_win) |
| { |
| int def_color = MAKE_BLACK; |
| |
| if (popup_win->grid_button_list) { |
| set_grid_used(popup_win->grid_button_list, |
| -1, -1, false, false); |
| } else { |
| popup_win->grid_button_list = |
| copy_main_button_list(def_color); |
| put_buttons_in_table(popup_win->grid_table, |
| popup_win->grid_button_list); |
| popup_win->full_grid = 1; |
| } |
| } |
| |
| /* clear extra buttons to N/A and if model then set those as white */ |
| extern void post_setup_popup_grid_list(popup_info_t *popup_win) |
| { |
| /* refresh the pointer */ |
| if (popup_win->model |
| && gtk_tree_store_iter_is_valid(GTK_TREE_STORE(popup_win->model), |
| &popup_win->iter)) { |
| gtk_tree_model_get(popup_win->model, &popup_win->iter, |
| popup_win->node_inx_id, |
| &popup_win->node_inx, -1); |
| } else { |
| popup_win->node_inx = NULL; |
| } |
| |
| if (popup_win->node_inx) { |
| int j=0; |
| while (popup_win->node_inx[j] >= 0) { |
| change_grid_color( |
| popup_win->grid_button_list, |
| popup_win->node_inx[j], |
| popup_win->node_inx[j+1], MAKE_WHITE, true, 0); |
| j += 2; |
| } |
| } |
| |
| change_grid_color(popup_win->grid_button_list, -1, -1, |
| MAKE_BLACK, true, NODE_STATE_IDLE); |
| } |