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,6 +72,10 @@
72 gboolean pw3270_settings_set_int(const gchar *key, gint value); 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 // Actions 79 // Actions
76 void pw3270_application_print_copy_activated(GAction *action, GVariant *parameter, GtkWidget *terminal); 80 void pw3270_application_print_copy_activated(GAction *action, GVariant *parameter, GtkWidget *terminal);
77 void pw3270_application_save_copy_activated(GAction *action, GVariant *parameter, GtkWidget *terminal); 81 void pw3270_application_save_copy_activated(GAction *action, GVariant *parameter, GtkWidget *terminal);
src/main/tools.c
@@ -38,4 +38,28 @@ @@ -38,4 +38,28 @@
38 38
39 /*---[ Implement ]----------------------------------------------------------------------------------*/ 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,7 +91,6 @@
91 PROP_ACTION_NAMES, 91 PROP_ACTION_NAMES,
92 }; 92 };
93 93
94 -  
95 struct _pw3270ToolBar { 94 struct _pw3270ToolBar {
96 GtkToolbar parent; 95 GtkToolbar parent;
97 96
@@ -375,24 +374,12 @@ @@ -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 void pw3270_toolbar_set_actions(GtkWidget *toolbar, const gchar *action_names) { 377 void pw3270_toolbar_set_actions(GtkWidget *toolbar, const gchar *action_names) {
391 378
392 gchar ** actions = g_strsplit(action_names,",",-1); 379 gchar ** actions = g_strsplit(action_names,",",-1);
393 size_t ix; 380 size_t ix;
394 381
395 - pw3270_toolbar_clear(toolbar); 382 + gtk_container_remove_all(GTK_CONTAINER(toolbar));
396 383
397 for(ix = 0; actions[ix]; ix++) { 384 for(ix = 0; actions[ix]; ix++) {
398 pw3270_toolbar_insert_action(toolbar,actions[ix],-1); 385 pw3270_toolbar_insert_action(toolbar,actions[ix],-1);
@@ -426,6 +413,5 @@ @@ -426,6 +413,5 @@
426 413
427 g_list_free(children); 414 g_list_free(children);
428 415
429 -  
430 return g_string_free(str,FALSE); 416 return g_string_free(str,FALSE);
431 } 417 }
src/objects/window/header.c
@@ -33,6 +33,53 @@ @@ -33,6 +33,53 @@
33 #include <pw3270/application.h> 33 #include <pw3270/application.h>
34 #include <pw3270/actions.h> 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 static void on_sensitive(GtkWidget *button, GParamSpec *spec, GtkWidget *widget) { 83 static void on_sensitive(GtkWidget *button, GParamSpec *spec, GtkWidget *widget) {
37 84
38 gboolean sensitive; 85 gboolean sensitive;
@@ -73,8 +120,53 @@ @@ -73,8 +120,53 @@
73 gtk_widget_set_focus_on_click(button,FALSE); 120 gtk_widget_set_focus_on_click(button,FALSE);
74 gtk_widget_set_can_focus(button,FALSE); 121 gtk_widget_set_can_focus(button,FALSE);
75 gtk_widget_set_can_default(button,FALSE); 122 gtk_widget_set_can_default(button,FALSE);
  123 + gtk_widget_set_name(button,action_name);
76 124
77 } 125 }
78 126
79 return button; 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,14 +77,18 @@
77 G_GNUC_INTERNAL GtkWidget * pw3270_setup_image_button(GtkWidget *button, const gchar *image_name); 77 G_GNUC_INTERNAL GtkWidget * pw3270_setup_image_button(GtkWidget *button, const gchar *image_name);
78 78
79 // Actions 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 GAction * pw3270_action_session_properties_new(void); 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 // Terminal actions. 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 G_GNUC_INTERNAL void pw3270_window_open_activated(GSimpleAction * action, GVariant *parameter, gpointer window); 93 G_GNUC_INTERNAL void pw3270_window_open_activated(GSimpleAction * action, GVariant *parameter, gpointer window);
90 G_GNUC_INTERNAL void pw3270_window_close_activated(GSimpleAction * action, GVariant *parameter, gpointer window); 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,8 +33,16 @@
33 #include <pw3270/application.h> 33 #include <pw3270/application.h>
34 #include <pw3270/actions.h> 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 G_DEFINE_TYPE(pw3270ApplicationWindow, pw3270ApplicationWindow, GTK_TYPE_APPLICATION_WINDOW); 39 G_DEFINE_TYPE(pw3270ApplicationWindow, pw3270ApplicationWindow, GTK_TYPE_APPLICATION_WINDOW);
37 40
  41 + enum {
  42 + PROP_NONE,
  43 + PROP_ACTION_NAMES,
  44 + };
  45 +
38 static void destroy(GtkWidget *widget) { 46 static void destroy(GtkWidget *widget) {
39 47
40 size_t ix; 48 size_t ix;
@@ -70,9 +78,39 @@ @@ -70,9 +78,39 @@
70 78
71 static void pw3270ApplicationWindow_class_init(pw3270ApplicationWindowClass *klass) { 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,8 +216,11 @@
178 216
179 GtkWidget * pw3270_application_window_new(GtkApplication * application) { 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 size_t ix; 223 size_t ix;
182 - const gchar * title = _( "IBM 3270 Terminal emulator" );  
183 224
184 g_autoptr(GSettings) settings = pw3270_application_get_settings(G_APPLICATION(application)); 225 g_autoptr(GSettings) settings = pw3270_application_get_settings(G_APPLICATION(application));
185 226
@@ -190,138 +231,69 @@ @@ -190,138 +231,69 @@
190 "application", application, 231 "application", application,
191 NULL); 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