Commit 34dc0b375065d839dea1e24f8e0f18cdfe34b48d

Authored by Perry Werneck
1 parent 8eb32755

Buttons on the header bar are now configurable.

src/include/pw3270/application.h
... ... @@ -72,6 +72,10 @@
72 72 gboolean pw3270_settings_set_int(const gchar *key, gint value);
73 73  
74 74  
  75 + // Tools
  76 + GtkBuilder * pw3270_application_get_builder(const gchar *name);
  77 + void gtk_container_remove_all(GtkContainer *container);
  78 +
75 79 // Actions
76 80 void pw3270_application_print_copy_activated(GAction *action, GVariant *parameter, GtkWidget *terminal);
77 81 void pw3270_application_save_copy_activated(GAction *action, GVariant *parameter, GtkWidget *terminal);
... ...
src/main/tools.c
... ... @@ -38,4 +38,28 @@
38 38  
39 39 /*---[ Implement ]----------------------------------------------------------------------------------*/
40 40  
  41 + GtkBuilder * pw3270_application_get_builder(const gchar *name) {
  42 +
  43 +#ifdef DEBUG
  44 + g_autofree gchar * filename = g_build_filename("ui",name,NULL);
  45 +#else
  46 + lib3270_autoptr(char) filename = lib3270_build_data_filename("ui",name,NULL);
  47 +#endif // DEBUG
  48 +
  49 + return gtk_builder_new_from_file(filename);
  50 + }
  51 +
  52 + void gtk_container_remove_all(GtkContainer *container) {
  53 +
  54 + GList * children = gtk_container_get_children(container);
  55 + GList * item;
  56 +
  57 + for(item = children;item;item = g_list_next(item)) {
  58 + gtk_container_remove(container,GTK_WIDGET(item->data));
  59 + }
  60 +
  61 + g_list_free(children);
  62 +
  63 + }
  64 +
41 65  
... ...
src/objects/toolbar/toolbar.c
... ... @@ -91,7 +91,6 @@
91 91 PROP_ACTION_NAMES,
92 92 };
93 93  
94   -
95 94 struct _pw3270ToolBar {
96 95 GtkToolbar parent;
97 96  
... ... @@ -375,24 +374,12 @@
375 374  
376 375 }
377 376  
378   - void pw3270_toolbar_clear(GtkWidget *toolbar) {
379   -
380   - GList * children = gtk_container_get_children(GTK_CONTAINER(toolbar));
381   - GList * item;
382   -
383   - for(item = children;item;item = g_list_next(item)) {
384   - gtk_container_remove(GTK_CONTAINER(toolbar),GTK_WIDGET(item->data));
385   - }
386   -
387   - g_list_free(children);
388   - }
389   -
390 377 void pw3270_toolbar_set_actions(GtkWidget *toolbar, const gchar *action_names) {
391 378  
392 379 gchar ** actions = g_strsplit(action_names,",",-1);
393 380 size_t ix;
394 381  
395   - pw3270_toolbar_clear(toolbar);
  382 + gtk_container_remove_all(GTK_CONTAINER(toolbar));
396 383  
397 384 for(ix = 0; actions[ix]; ix++) {
398 385 pw3270_toolbar_insert_action(toolbar,actions[ix],-1);
... ... @@ -426,6 +413,5 @@
426 413  
427 414 g_list_free(children);
428 415  
429   -
430 416 return g_string_free(str,FALSE);
431 417 }
... ...
src/objects/window/header.c
... ... @@ -33,6 +33,53 @@
33 33 #include <pw3270/application.h>
34 34 #include <pw3270/actions.h>
35 35  
  36 + void pw3270_window_set_header_action_names(GtkWidget *window, const gchar *action_names) {
  37 +
  38 + GtkWidget * header = gtk_window_get_titlebar(GTK_WINDOW(window));
  39 +
  40 + if(!(header && GTK_IS_HEADER_BAR(header)))
  41 + return;
  42 +
  43 + gtk_container_remove_all(GTK_CONTAINER(header));
  44 +
  45 + if(action_names && *action_names) {
  46 +
  47 + size_t ix;
  48 + gchar ** header_blocks = g_strsplit(action_names,":",-1);
  49 +
  50 + g_autoptr(GtkBuilder) builder = pw3270_application_get_builder("window.xml");
  51 +
  52 + if(g_strv_length(header_blocks) >= 2) {
  53 +
  54 + gchar ** elements;
  55 + GtkWidget * button;
  56 +
  57 + // First the left side actions.
  58 + elements = g_strsplit(header_blocks[0],",",-1);
  59 + for(ix=0;elements[ix];ix++) {
  60 + button = pw3270_header_button_new_from_builder(GTK_WIDGET(window),builder,elements[ix]);
  61 + g_object_set_data(G_OBJECT(button),"header-position-id",GINT_TO_POINTER(0));
  62 + gtk_header_bar_pack_start(GTK_HEADER_BAR(header), button);
  63 + }
  64 + g_strfreev(elements);
  65 +
  66 + // And then, the right side actions;
  67 + elements = g_strsplit(header_blocks[1],",",-1);
  68 + for(ix=0;elements[ix];ix++) {
  69 + button = pw3270_header_button_new_from_builder(GTK_WIDGET(window),builder,elements[ix]);
  70 + g_object_set_data(G_OBJECT(button),"header-position-id",GINT_TO_POINTER(1));
  71 + gtk_header_bar_pack_end(GTK_HEADER_BAR(header), button);
  72 + }
  73 + g_strfreev(elements);
  74 +
  75 + }
  76 +
  77 + g_strfreev(header_blocks);
  78 +
  79 + }
  80 +
  81 + }
  82 +
36 83 static void on_sensitive(GtkWidget *button, GParamSpec *spec, GtkWidget *widget) {
37 84  
38 85 gboolean sensitive;
... ... @@ -73,8 +120,53 @@
73 120 gtk_widget_set_focus_on_click(button,FALSE);
74 121 gtk_widget_set_can_focus(button,FALSE);
75 122 gtk_widget_set_can_default(button,FALSE);
  123 + gtk_widget_set_name(button,action_name);
76 124  
77 125 }
78 126  
79 127 return button;
80 128 }
  129 +
  130 + gchar * pw3270_window_get_action_names(GtkWidget *window) {
  131 +
  132 + GtkWidget * header = gtk_window_get_titlebar(GTK_WINDOW(window));
  133 +
  134 + if(!(header && GTK_IS_HEADER_BAR(header)))
  135 + return g_strdup("win.disconnect,win.reconnect,win.file.transfer,win.print:menu.open-menu");
  136 +
  137 + GString * str = g_string_new("");
  138 +
  139 + GList * children = gtk_container_get_children(GTK_CONTAINER(header));
  140 + GList * item;
  141 +
  142 + int id;
  143 + for(id = 0; id < 2; id++) {
  144 +
  145 + gboolean sep = FALSE;
  146 +
  147 + for(item = children;item;item = g_list_next(item)) {
  148 +
  149 + if(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item->data),"header-position-id") != id))
  150 + continue;
  151 +
  152 + if(sep)
  153 + g_string_append(str,",");
  154 +
  155 + if(GTK_IS_MENU_BUTTON(item->data)) {
  156 + g_string_append(str,gtk_widget_get_name(GTK_WIDGET(item->data)));
  157 + } else if(GTK_IS_ACTIONABLE(item->data)) {
  158 + g_string_append(str,gtk_actionable_get_action_name(GTK_ACTIONABLE(item->data)));
  159 + }
  160 +
  161 + sep = TRUE;
  162 + }
  163 +
  164 + if(!id)
  165 + g_string_append(str,":");
  166 +
  167 + }
  168 +
  169 + g_list_free(children);
  170 +
  171 + return g_string_free(str,FALSE);
  172 + }
... ...
src/objects/window/private.h
... ... @@ -77,14 +77,18 @@
77 77 G_GNUC_INTERNAL GtkWidget * pw3270_setup_image_button(GtkWidget *button, const gchar *image_name);
78 78  
79 79 // Actions
80   - GAction * pw3270_action_host_properties_new(void);
81   - GAction * pw3270_set_color_action_new(void);
82   - GAction * pw3270_file_transfer_action_new(void);
  80 + G_GNUC_INTERNAL GAction * pw3270_action_host_properties_new(void);
  81 + G_GNUC_INTERNAL GAction * pw3270_set_color_action_new(void);
  82 + G_GNUC_INTERNAL GAction * pw3270_file_transfer_action_new(void);
83 83  
84 84 GAction * pw3270_action_session_properties_new(void);
85 85  
  86 + // Header bar
  87 + G_GNUC_INTERNAL void pw3270_window_set_header_action_names(GtkWidget *window, const gchar *action_names);
  88 + G_GNUC_INTERNAL gchar * pw3270_window_get_action_names(GtkWidget *window);
  89 +
86 90 // Terminal actions.
87   - GAction * pw3270_model_number_action_new(GtkWidget *terminal);
  91 + G_GNUC_INTERNAL GAction * pw3270_model_number_action_new(GtkWidget *terminal);
88 92  
89 93 G_GNUC_INTERNAL void pw3270_window_open_activated(GSimpleAction * action, GVariant *parameter, gpointer window);
90 94 G_GNUC_INTERNAL void pw3270_window_close_activated(GSimpleAction * action, GVariant *parameter, gpointer window);
... ...
src/objects/window/window.c
... ... @@ -33,8 +33,16 @@
33 33 #include <pw3270/application.h>
34 34 #include <pw3270/actions.h>
35 35  
  36 + static void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
  37 + static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
  38 +
36 39 G_DEFINE_TYPE(pw3270ApplicationWindow, pw3270ApplicationWindow, GTK_TYPE_APPLICATION_WINDOW);
37 40  
  41 + enum {
  42 + PROP_NONE,
  43 + PROP_ACTION_NAMES,
  44 + };
  45 +
38 46 static void destroy(GtkWidget *widget) {
39 47  
40 48 size_t ix;
... ... @@ -70,9 +78,39 @@
70 78  
71 79 static void pw3270ApplicationWindow_class_init(pw3270ApplicationWindowClass *klass) {
72 80  
73   - GtkWidgetClass * widget = GTK_WIDGET_CLASS(klass);
74   - widget->destroy = destroy;
  81 + GTK_WIDGET_CLASS(klass)->destroy = destroy;
  82 +
  83 + GObjectClass *object_class = G_OBJECT_CLASS(klass);
  84 +
  85 + object_class->set_property = set_property;
  86 + object_class->get_property = get_property;
  87 +
  88 + g_object_class_install_property(
  89 + object_class,
  90 + PROP_ACTION_NAMES,
  91 + g_param_spec_string ("action-names",
  92 + N_("Action Names"),
  93 + N_("The name of the actions in the header bar"),
  94 + NULL,
  95 + G_PARAM_WRITABLE|G_PARAM_READABLE)
  96 + );
  97 +
  98 +
  99 + }
  100 +
  101 + void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec G_GNUC_UNUSED(*pspec)) {
  102 +
  103 + if(prop_id == PROP_ACTION_NAMES) {
  104 + pw3270_window_set_header_action_names(GTK_WIDGET(object), g_value_get_string(value));
  105 + }
  106 +
  107 + }
  108 +
  109 + void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
75 110  
  111 + if(prop_id == PROP_ACTION_NAMES) {
  112 + g_value_take_string(value,pw3270_window_get_action_names(GTK_WIDGET(object)));
  113 + }
76 114  
77 115 }
78 116  
... ... @@ -178,8 +216,11 @@
178 216  
179 217 GtkWidget * pw3270_application_window_new(GtkApplication * application) {
180 218  
  219 + gchar *title = _( "IBM 3270 Terminal emulator" );
  220 +
  221 + g_return_val_if_fail(PW3270_IS_APPLICATION(application),NULL);
  222 +
181 223 size_t ix;
182   - const gchar * title = _( "IBM 3270 Terminal emulator" );
183 224  
184 225 g_autoptr(GSettings) settings = pw3270_application_get_settings(G_APPLICATION(application));
185 226  
... ... @@ -190,138 +231,69 @@
190 231 "application", application,
191 232 NULL);
192 233  
193   - if(PW3270_IS_APPLICATION(gtk_window_get_application(GTK_WINDOW(window)))) {
194   -
195   - GtkBuilder * builder;
196   -#ifdef DEBUG
197   - builder = gtk_builder_new_from_file("ui/window.xml");
198   -#else
199   - {
200   - lib3270_autoptr(char) build_file = lib3270_build_data_filename("ui","window.xml",NULL);
201   - builder = gtk_builder_new_from_file(build_file);
202   - }
203   -#endif // DEBUG
204   -
205   - switch(pw3270_application_get_ui_style(G_APPLICATION(application))) {
206   - case PW3270_UI_STYLE_CLASSICAL:
207   - {
208   - gtk_window_set_title(GTK_WINDOW(window), title);
209   -
210   - }
211   - break;
212   -
213   - case PW3270_UI_STYLE_GNOME:
214   - {
215   - // Create header bar
216   - GtkHeaderBar * header = GTK_HEADER_BAR(gtk_header_bar_new());
217   - gtk_window_set_titlebar(GTK_WINDOW(window), GTK_WIDGET(header));
218   - gtk_header_bar_set_show_close_button(header,TRUE);
219   -
220   - gtk_header_bar_set_title(header,title);
221   - if(settings)
222   - g_settings_bind(settings, "has-subtitle", header, "has-subtitle", G_SETTINGS_BIND_DEFAULT);
223   - else
224   - gtk_header_bar_set_has_subtitle(header,TRUE);
225   -
226   - // Show the new header
227   - gtk_widget_show_all(GTK_WIDGET(header));
228   -
229   - // Create header's action buttons
230   - // https://wiki.gnome.org/Initiatives/GnomeGoals/GearIcons
231   - {
232   - g_autofree gchar * header_actions = g_settings_get_string(settings, "header-action-names");
233   - gchar ** header_blocks = g_strsplit(header_actions,":",-1);
234   -
235   - if(g_strv_length(header_blocks) >= 2) {
236   -
237   - gchar ** elements;
238   -
239   - // First the left side actions.
240   - elements = g_strsplit(header_blocks[0],",",-1);
241   - for(ix=0;elements[ix];ix++) {
242   - gtk_header_bar_pack_start(header, pw3270_header_button_new_from_builder(GTK_WIDGET(window),builder,elements[ix]));
243   - }
244   - g_strfreev(elements);
245   -
246   - // And then, the right side actions;
247   - elements = g_strsplit(header_blocks[1],",",-1);
248   - for(ix=0;elements[ix];ix++) {
249   - gtk_header_bar_pack_end(header, pw3270_header_button_new_from_builder(GTK_WIDGET(window),builder,elements[ix]));
250   - }
251   - g_strfreev(elements);
252   -
253   - }
254   -
255   - g_strfreev(header_blocks);
256   -
257   - }
  234 + //
  235 + // Get builder
  236 + //
  237 + g_autoptr(GtkBuilder) builder = pw3270_application_get_builder("window.xml");
258 238  
259   - /*
260   - {
261   - g_autofree gchar * left = g_settings_get_string(settings, "header-start-action-names");
262   - g_autofree gchar * right = g_settings_get_string(settings, "header-end-action-names");
  239 + // Load popup menus.
  240 + const gchar * popup_menus[G_N_ELEMENTS(window->popups)] = {
  241 + "popup-over-selected-area",
  242 + "popup-over-unselected-area",
  243 + "popup-when-offline"
  244 + };
263 245  
  246 + for(ix = 0; ix < G_N_ELEMENTS(popup_menus); ix++) {
264 247  
265   - }
266   - */
  248 + GObject * model = gtk_builder_get_object(builder, popup_menus[ix]);
  249 + if(model) {
  250 + window->popups[ix] = gtk_menu_new_from_model(G_MENU_MODEL(model));
  251 + gtk_menu_attach_to_widget(GTK_MENU(window->popups[ix]),GTK_WIDGET(window),NULL);
  252 + }
267 253  
268   - /*
269   - static const gchar * end_actions[] = {
270   - "menu.open-menu",
271   - };
  254 + }
272 255  
273   - for(ix = 0; ix < G_N_ELEMENTS(end_actions); ix++) {
274   - gtk_header_bar_pack_end(header, pw3270_header_button_new_from_builder(GTK_WIDGET(window),builder,end_actions[ix]));
275   - }
  256 + if(pw3270_application_get_ui_style(G_APPLICATION(application)) == PW3270_UI_STYLE_GNOME) {
276 257  
  258 + // Create header bar
277 259  
278   - static const gchar * start_actions[] = {
279   - "win.disconnect",
280   - "win.reconnect",
281   - "win.file.transfer",
282   - "win.print"
283   - };
  260 + GtkHeaderBar * header = GTK_HEADER_BAR(gtk_header_bar_new());
  261 + gtk_window_set_titlebar(GTK_WINDOW(window), GTK_WIDGET(header));
  262 + gtk_header_bar_set_show_close_button(header,TRUE);
284 263  
285   - for(ix = 0; ix < G_N_ELEMENTS(start_actions); ix++) {
286   - gtk_header_bar_pack_start(header, pw3270_header_button_new_from_builder(GTK_WIDGET(window),builder,start_actions[ix]));
287   - }
288   - */
  264 + gtk_header_bar_set_title(header,title);
  265 + g_settings_bind(
  266 + settings,
  267 + "has-subtitle",
  268 + header,
  269 + "has-subtitle",
  270 + G_SETTINGS_BIND_DEFAULT
  271 + );
289 272  
  273 + // Show the new header
  274 + gtk_widget_show_all(GTK_WIDGET(header));
290 275  
291   - /*
292   - // Create "new tab" bar
293   - GtkWidget * new_tab_button = pw3270_setup_image_button(gtk_button_new(),"tab-new-symbolic");
294   - gtk_actionable_set_action_name(GTK_ACTIONABLE(new_tab_button),"app.new.tab");
295   - gtk_header_bar_pack_start(header, new_tab_button);
296   - gtk_widget_show(new_tab_button);
297   - */
  276 + // g_autofree gchar * header_actions = g_settings_get_string(settings, "header-action-names");
  277 + // pw3270_window_set_header_action_names(GTK_WIDGET(window), header_actions);
298 278  
299   - }
300   - break;
  279 + g_settings_bind(
  280 + settings,
  281 + "header-action-names",
  282 + window,
  283 + "action-names",
  284 + G_SETTINGS_BIND_DEFAULT
  285 + );
301 286  
302   - default:
303   - g_warning("Unexpected UI");
  287 +#ifdef DEBUG
  288 + {
  289 + g_autofree gchar * an = pw3270_window_get_action_names(window);
304 290  
305 291 }
  292 +#endif // DEBUG
306 293  
307   - // Load popup menus.
308   - const gchar * popup_menus[G_N_ELEMENTS(window->popups)] = {
309   - "popup-over-selected-area",
310   - "popup-over-unselected-area",
311   - "popup-when-offline"
312   - };
313   -
314   - for(ix = 0; ix < G_N_ELEMENTS(popup_menus); ix++) {
315   -
316   - GObject * model = gtk_builder_get_object(builder, popup_menus[ix]);
317   - if(model) {
318   - window->popups[ix] = gtk_menu_new_from_model(G_MENU_MODEL(model));
319   - gtk_menu_attach_to_widget(GTK_MENU(window->popups[ix]),GTK_WIDGET(window),NULL);
320   - }
321   -
322   - }
  294 + } else {
323 295  
324   - g_object_unref(builder);
  296 + gtk_window_set_title(GTK_WINDOW(window), title);
325 297  
326 298 }
327 299  
... ...