attachment:ui_mainwindow.c of UMEGuide/ApplicationDevelopment/PortingCAppsToUME


Attachment 'ui_mainwindow.c'

Download

Toggle line numbers
   1 /**
   2  * @file ui_mainwindow.c some functions concerning the main window 
   3  *
   4  * Copyright (C) 2004-2006 Nathan J. Conrad <t98502@users.sourceforge.net>
   5  * Copyright (C) 2004-2007 Lars Lindner <lars.lindner@gmail.com>
   6  *
   7  * This library is free software; you can redistribute it and/or
   8  * modify it under the terms of the GNU Library General Public
   9  * License as published by the Free Software Foundation; either
  10  * version 2 of the License, or (at your option) any later version.
  11  * 
  12  * This library is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15  * Library General Public License for more details.
  16  * 
  17  * You should have received a copy of the GNU Library General Public License
  18  * along with this library; see the file COPYING.LIB.  If not, write to
  19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20  * Boston, MA 02111-1307, USA.
  21  */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #  include <config.h>
  25 #endif
  26 
  27 #include <gtk/gtk.h>
  28 #include <gdk/gdk.h>
  29 #include <gdk/gdkkeysyms.h>
  30 
  31 #ifdef MAEMO_CHANGES
  32 #  include <hildon/hildon-program.h>
  33 #endif
  34 
  35 #include <string.h>
  36 #include <libintl.h>
  37 
  38 #include "common.h"
  39 #include "conf.h"
  40 #include "debug.h"
  41 #include "export.h"
  42 #include "feedlist.h"
  43 #include "itemlist.h"
  44 #include "itemview.h"
  45 #include "script.h"
  46 #include "update.h"
  47 #include "ui/ui_script.h"
  48 #include "ui/ui_dialog.h"
  49 #include "ui/ui_dnd.h"
  50 #include "ui/ui_enclosure.h"
  51 #include "ui/ui_feedlist.h"
  52 #include "ui/ui_htmlview.h"
  53 #include "ui/ui_itemlist.h"
  54 #include "ui/ui_mainwindow.h"
  55 #include "ui/ui_node.h"
  56 #include "ui/ui_popup.h"
  57 #include "ui/ui_prefs.h"
  58 #include "ui/ui_search.h"
  59 #include "ui/ui_session.h"
  60 #include "ui/ui_shell.h"
  61 #include "ui/ui_tabs.h"
  62 #include "ui/ui_tray.h"
  63 #include "ui/ui_update.h"
  64 
  65 static struct mainwindow {
  66 #ifdef MAEMO_CHANGES
  67 	HildonProgram	*program;
  68 	GtkWidget	*container;
  69 	GtkWidget	*window;
  70 #else
  71 	GtkWindow	*window;
  72 #endif
  73 	GtkWidget	*menubar;
  74 	GtkWidget	*toolbar;
  75 	GtkWidget	*itemlistContainer;	/**< scrolled window holding item list tree view */
  76 	GtkWidget	*itemlist;		/**< item list tree view */
  77 	GtkWidget	*statusbar_feedsinfo;
  78 	GtkActionGroup	*generalActions;
  79 	GtkActionGroup	*addActions;		/**< all types of "New" options */
  80 	GtkActionGroup	*feedActions;		/**< update and mark read */
  81 	GtkActionGroup	*readWriteActions;	/**< remove and properties */
  82 	
  83 	LifereaHtmlView	*htmlview;		/**< HTML rendering widget */
  84 	gfloat		zoom;			/**< HTML rendering widget zoom level */
  85 } *mainwindow_priv;
  86 
  87 /* all used icons */
  88 GdkPixbuf *icons[MAX_ICONS];
  89 
  90 /* icon from theme names */
  91 static const gchar *iconThemeNames[] = {
  92 	NULL,			/* ICON_READ */
  93 	NULL,			/* ICON_UNREAD */
  94 	"emblem-important",	/* ICON_FLAG */
  95 	NULL,			/* ICON_AVAILABLE */
  96 	NULL,			/* ICON_AVAILABLE_OFFLINE */
  97 	NULL,			/* ICON_UNAVAILABLE */
  98 	NULL,			/* ICON_DEFAULT */
  99 	NULL,			/* ICON_OCS */
 100 	"folder",		/* ICON_FOLDER */
 101 	"folder-saved-search",	/* ICON_VFOLDER */
 102 	NULL,			/* ICON_NEWSBIN */
 103 	NULL,			/* ICON_EMPTY */
 104 	NULL,			/* ICON_EMPTY_OFFLINE */
 105 	NULL,			/* ICON_ONLINE */
 106 	NULL,			/* ICON_OFFLINE */
 107 	NULL,			/* ICON_UPDATED */
 108 	"mail-attachment",	/* ICON_ENCLOSURE */
 109 	NULL
 110 };
 111 
 112 /* icon names */
 113 static const gchar *iconNames[] = {
 114 	"read.xpm",		/* ICON_READ */
 115 	"unread.png",		/* ICON_UNREAD */
 116 	"flag.png",		/* ICON_FLAG */
 117 	"available.png",	/* ICON_AVAILABLE */
 118 	"available_offline.png",	/* ICON_AVAILABLE_OFFLINE */
 119 	NULL,			/* ICON_UNAVAILABLE */
 120 	"default.png",		/* ICON_DEFAULT */
 121 	"ocs.png",		/* ICON_OCS */
 122 	"directory.png",	/* ICON_FOLDER */
 123 	"vfolder.png",		/* ICON_VFOLDER */
 124 	"newsbin.png",		/* ICON_NEWSBIN */
 125 	"empty.png",		/* ICON_EMPTY */
 126 	"empty_offline.png",	/* ICON_EMPTY_OFFLINE */
 127 	"online.png",		/* ICON_ONLINE */
 128 	"offline.png",		/* ICON_OFFLINE */
 129 	"edit.png",		/* ICON_UPDATED */
 130 	"attachment.png",	/* ICON_ENCLOSURE */
 131 	NULL
 132 };
 133 
 134 GtkWidget 	*mainwindow;
 135 
 136 /* some prototypes */
 137 static void ui_mainwindow_restore_position(GtkWidget *window);
 138 static gboolean on_close(GtkWidget *widget, GdkEvent *event, struct mainwindow *user_data);
 139 static void ui_mainwindow_create_menus(struct mainwindow *mw);
 140 static gboolean on_mainwindow_window_state_event(GtkWidget *widget, GdkEvent *event, gpointer user_data);
 141 
 142 LifereaHtmlView *
 143 ui_mainwindow_get_active_htmlview (void)
 144 {
 145 	return mainwindow_priv->htmlview;
 146 }
 147 
 148 extern htmlviewPluginPtr htmlviewPlugin;
 149 
 150 /* simple dialogs */
 151 
 152 void ui_show_error_box(const char *format, ...) {
 153 	GtkWidget	*dialog;
 154 	va_list		args;
 155 	gchar		*msg;
 156 
 157 	g_return_if_fail(format != NULL);
 158 
 159 	va_start(args, format);
 160 	msg = g_strdup_vprintf(format, args);
 161 	va_end(args);
 162 	
 163 	dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow),
 164                   GTK_DIALOG_DESTROY_WITH_PARENT,
 165                   GTK_MESSAGE_ERROR,
 166                   GTK_BUTTONS_CLOSE,
 167                   "%s", msg);
 168 	(void)gtk_dialog_run(GTK_DIALOG (dialog));
 169 	gtk_widget_destroy(dialog);
 170 	g_free(msg);
 171 }
 172 
 173 void ui_show_info_box(const char *format, ...) { 
 174 	GtkWidget	*dialog;
 175 	va_list		args;
 176 	gchar		*msg;
 177 
 178 	g_return_if_fail(format != NULL);
 179 
 180 	va_start(args, format);
 181 	msg = g_strdup_vprintf(format, args);
 182 	va_end(args);
 183 		
 184 	dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow),
 185                   GTK_DIALOG_DESTROY_WITH_PARENT,
 186                   GTK_MESSAGE_INFO,
 187                   GTK_BUTTONS_CLOSE,
 188                   "%s", msg);
 189 	(void)gtk_dialog_run(GTK_DIALOG (dialog));
 190 	gtk_widget_destroy(dialog);
 191 	g_free(msg);
 192 }
 193 
 194 /*------------------------------------------------------------------------------*/
 195 /* exit handler	and menu callbacks						*/
 196 /*------------------------------------------------------------------------------*/
 197 
 198 void on_popup_quit(gpointer callback_data, guint callback_action, GtkWidget *widget) {
 199 
 200 	(void)on_quit(NULL, NULL, NULL);
 201 }
 202 
 203 void on_about_activate(GtkMenuItem *menuitem, gpointer user_data) {
 204 	GtkWidget *dialog;
 205 	GtkLabel *versionLabel;
 206 	gchar *text;
 207 
 208 	dialog = liferea_dialog_new (NULL, "aboutdialog");
 209 	versionLabel = GTK_LABEL(liferea_dialog_lookup(dialog, "version_label"));
 210 	text = g_strdup_printf("%s %s", PACKAGE, VERSION);;
 211 	gtk_label_set_text(versionLabel,text);
 212 	g_free(text);
 213 	gtk_widget_show(dialog);
 214 }
 215 
 216 void
 217 on_homepagebtn_clicked (GtkButton *button, gpointer user_data)
 218 {
 219 	/* launch the homepage when button in about dialog is pressed */
 220 	liferea_htmlview_launch_in_external_browser(_("http://liferea.sf.net"));
 221 }
 222 
 223 void on_topics_activate(GtkMenuItem *menuitem, gpointer user_data) {
 224 	gchar *filename = g_strdup_printf("file://" PACKAGE_DATA_DIR "/" PACKAGE "/doc/html/%s", _("topics_en.html"));
 225 	ui_tabs_new(filename, _("Help Topics"), TRUE);
 226 	g_free(filename);
 227 }
 228 
 229 
 230 void on_quick_reference_activate(GtkMenuItem *menuitem, gpointer user_data) {
 231 	gchar *filename = g_strdup_printf("file://" PACKAGE_DATA_DIR "/" PACKAGE "/doc/html/%s", _("reference_en.html"));
 232 	ui_tabs_new(filename, _("Quick Reference"), TRUE);
 233 	g_free(filename);
 234 }
 235 
 236 void on_faq_activate(GtkMenuItem *menuitem, gpointer user_data) {
 237 	gchar *filename = g_strdup_printf("file://" PACKAGE_DATA_DIR "/" PACKAGE "/doc/html/%s", _("faq_en.html"));
 238 	ui_tabs_new(filename, _("FAQ"), TRUE);
 239 	g_free(filename);
 240 }
 241 
 242 /*------------------------------------------------------------------------------*/
 243 /* keyboard navigation	 							*/
 244 /*------------------------------------------------------------------------------*/
 245 
 246 /* Set cursor to the first item on a treeview. */
 247 static void
 248 on_treeview_set_first (GtkWidget *treeview)
 249 {
 250 	GtkTreePath	*path;
 251 
 252 	path = gtk_tree_path_new_first ();
 253 	gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, NULL, FALSE);
 254 	gtk_tree_path_free(path);
 255 }
 256 
 257 /* Move treeview cursor up and down. */
 258 void
 259 on_treeview_move (GtkWidget *treeview, gint step)
 260 {
 261 	gboolean	ret;
 262 
 263 	gtk_widget_grab_focus(treeview);
 264 	g_signal_emit_by_name(GTK_TREE_VIEW (treeview), "move-cursor", GTK_MOVEMENT_DISPLAY_LINES, step, &ret);
 265 }
 266 
 267 static void
 268 on_treeview_prev (GtkWidget *treeview)
 269 {
 270 	on_treeview_move (treeview, -1);
 271 }
 272 
 273 static void
 274 on_treeview_next (GtkWidget *treeview)
 275 {
 276 	on_treeview_move (treeview, 1);
 277 }
 278 
 279 gboolean
 280 on_mainwindow_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer data)
 281 {
 282 	gboolean	modifier_matches = FALSE;
 283 	guint		default_modifiers;
 284 	const gchar	*type;
 285 	GtkWidget	*focusw;
 286 
 287 	if (event->type == GDK_KEY_PRESS) {
 288 		default_modifiers = gtk_accelerator_get_default_mod_mask ();
 289 
 290 		/* handle headline skimming hotkey */
 291 		switch (event->keyval) {
 292 			case GDK_space:
 293 				switch (conf_get_int_value (BROWSE_KEY_SETTING)) {
 294 					default:
 295 					case 0:
 296 						modifier_matches = ((event->state & default_modifiers) == 0);
 297 						/* Hack to make space handled in the module. This is necessary
 298 						   because the GtkMozEmbed code must be able to catch spaces
 299 						   for input fields.
 300 						   
 301 						   By ignoring the space here it will be passed to the GtkMozEmbed
 302 						   widget which in turn will pass it back if it is not eaten by
 303 						   any input field currently focussed. */
 304 						if (!strcmp (htmlviewPlugin->name, "Mozilla") ||
 305 						    !strcmp (htmlviewPlugin->name, "XulRunner"))
 306 							return FALSE;
 307 
 308 						/* GtkHTML2 does handle <Space> correctly */
 309 						break;
 310 					case 1:
 311 						modifier_matches = ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK);
 312 						break;
 313 					case 2:
 314 						modifier_matches = ((event->state & GDK_MOD1_MASK) == GDK_MOD1_MASK);
 315 						break;
 316 				}
 317 				
 318 				if (modifier_matches) {
 319 					/* Note that this code is duplicated in mozilla/mozilla.cpp! */
 320 					if (liferea_htmlview_scroll () == FALSE)
 321 						on_next_unread_item_activate (NULL, NULL);
 322 					return TRUE;
 323 				}
 324 				break;
 325 		}
 326 
 327 		/* menu hotkeys (duplicated so they work with hidden menu */
 328 		if (GDK_CONTROL_MASK == (event->state & default_modifiers)) {
 329 			switch (event->keyval) {
 330 				case GDK_KP_Add:
 331 					on_popup_zoomin_selected (NULL, 0, NULL);
 332 					return TRUE;
 333 					break;
 334 				case GDK_KP_Subtract:
 335 					on_popup_zoomout_selected (NULL, 0, NULL);
 336 					return TRUE;
 337 					break;
 338 				case GDK_period:
 339 				case GDK_n:
 340 					on_next_unread_item_activate (NULL, NULL);
 341 					return TRUE;
 342 					break;
 343 				case GDK_r:
 344 					on_menu_allread (NULL, NULL);
 345 					return TRUE;
 346 					break;
 347 				case GDK_t:
 348 					on_toggle_item_flag (NULL, NULL);
 349 					return TRUE;
 350 					break;
 351 				case GDK_u:
 352 					on_toggle_unread_status (NULL, NULL);
 353 					return TRUE;
 354 					break;
 355 				case GDK_a:
 356 					on_menu_update_all (NULL, NULL);
 357 					return TRUE;
 358 					break;
 359 				case GDK_f:
 360 					on_searchbtn_clicked (NULL, NULL);
 361 					return TRUE;
 362 					break;
 363 			}
 364 		}
 365 
 366 		/* prevent usage of navigation keys in entries */
 367 		focusw = gtk_window_get_focus (GTK_WINDOW (widget));
 368 		if (GTK_IS_ENTRY (focusw))
 369 			return FALSE;
 370 
 371 		/* prevent usage of navigation keys in HTML view */
 372 		type = g_type_name (GTK_WIDGET_TYPE (focusw));
 373 		if (type && (!strcmp (type, "MozContainer")))
 374 			return FALSE;
 375 
 376 		/* somehow we don't need to check for GtkHTML2... */
 377 
 378 		/* check for treeview navigation */
 379 		if (0 == (event->state & default_modifiers)) {
 380 			switch (event->keyval) {
 381 				case GDK_KP_Delete:
 382 				case GDK_Delete:
 383 					on_remove_item_activate (NULL, NULL);
 384 					return TRUE;
 385 					break;
 386 				case GDK_n: 
 387 					on_next_unread_item_activate (NULL, NULL);
 388 					return TRUE;
 389 					break;
 390 				case GDK_f:
 391 					on_treeview_next (mainwindow_priv->itemlist);
 392 					return TRUE;
 393 					break;
 394 				case GDK_b:
 395 					on_treeview_prev (mainwindow_priv->itemlist);
 396 					return TRUE;
 397 					break;
 398 				case GDK_u:
 399 					on_treeview_prev (liferea_shell_lookup ("feedlist"));
 400 					on_treeview_set_first (mainwindow_priv->itemlist);
 401 					return TRUE;
 402 					break;
 403 				case GDK_d:
 404 					on_treeview_next (liferea_shell_lookup ("feedlist"));
 405 					on_treeview_set_first (mainwindow_priv->itemlist);
 406 					return TRUE;
 407 					break;
 408 			}
 409 		}
 410 	}
 411 	
 412 	return FALSE;
 413 }
 414 
 415 static void radio_action_set_current_value(GtkRadioAction *action, gint current_value)
 416 {
 417 	GSList* group;
 418 	gint value;
 419 
 420 	/*gtk_radio_action_set_current_value(action, current_value);*/
 421 
 422 	group = gtk_radio_action_get_group(action);
 423 
 424 	for(; group; group = g_slist_next(group)) {
 425 		action = GTK_RADIO_ACTION(group->data);
 426 		g_object_get(G_OBJECT(action), "value", &value, NULL);
 427 		if (value == current_value) {
 428 			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
 429 			break;
 430 		}
 431 	}
 432 }
 433 
 434 static void
 435 ui_mainwindow_htmlview_statusbar_changed (gpointer obj, gchar *url)
 436 {
 437 	ui_mainwindow_set_status_bar (url);
 438 }
 439 
 440 void
 441 ui_mainwindow_set_layout (guint newMode)
 442 {
 443 	gchar	*htmlWidgetName, *ilWidgetName;
 444 	GtkRadioAction *action;
 445 
 446 	action = GTK_RADIO_ACTION (gtk_action_group_get_action (mainwindow_priv->generalActions, "NormalView"));
 447 	radio_action_set_current_value (action, newMode);
 448 	
 449 	if (!mainwindow_priv->htmlview) {
 450 		GtkWidget *renderWidget;
 451 		mainwindow_priv->htmlview = liferea_htmlview_new (FALSE);		
 452 		g_signal_connect (mainwindow_priv->htmlview, "statusbar-changed", 
 453 		                  G_CALLBACK (ui_mainwindow_htmlview_statusbar_changed), 
 454 		                  mainwindow_priv);
 455 		renderWidget = liferea_htmlview_get_widget (mainwindow_priv->htmlview);
 456 		gtk_container_add (GTK_CONTAINER (liferea_shell_lookup ("normalViewHtml")), renderWidget);
 457 		gtk_widget_show (renderWidget);
 458 	}
 459 	
 460 	liferea_htmlview_clear (mainwindow_priv->htmlview);
 461 
 462 	debug1 (DEBUG_GUI, "Setting item list visibility mode: %d", newMode);
 463 	
 464 	switch (newMode) {
 465 		case NODE_VIEW_MODE_NORMAL:
 466 			htmlWidgetName = "normalViewHtml";
 467 			ilWidgetName = "normalViewItems";
 468 			break;
 469 		case NODE_VIEW_MODE_WIDE:
 470 			htmlWidgetName = "wideViewHtml";
 471 			ilWidgetName = "wideViewItems";
 472 			break;
 473 		case NODE_VIEW_MODE_COMBINED:
 474 			htmlWidgetName = "combinedViewHtml";
 475 			ilWidgetName = "normalViewItems";
 476 			break;
 477 		default:
 478 			g_warning("fatal: illegal viewing mode!");
 479 			return;
 480 			break;
 481 	}
 482 
 483 	/* reparenting HTML view */
 484 	gtk_notebook_set_current_page (GTK_NOTEBOOK (liferea_shell_lookup ("itemtabs")), newMode);
 485 	gtk_widget_reparent (liferea_htmlview_get_widget (mainwindow_priv->htmlview), liferea_shell_lookup (htmlWidgetName));
 486 	gtk_widget_reparent (GTK_WIDGET (mainwindow_priv->itemlistContainer), liferea_shell_lookup (ilWidgetName));
 487  
 488 	/* grab necessary to force HTML widget update (display must
 489 	   change from feed description to list of items and vica 
 490 	   versa */
 491 	gtk_widget_grab_focus (liferea_shell_lookup ("feedlist"));
 492 }
 493 
 494 void
 495 ui_mainwindow_set_toolbar_style (const gchar *toolbar_style)
 496 {	
 497 	if (toolbar_style == NULL) /* default to icons */
 498 		gtk_toolbar_set_style (GTK_TOOLBAR(mainwindow_priv->toolbar), GTK_TOOLBAR_ICONS);
 499 	else if (!strcmp (toolbar_style, "text"))
 500 		gtk_toolbar_set_style (GTK_TOOLBAR(mainwindow_priv->toolbar), GTK_TOOLBAR_TEXT);
 501 	else if (!strcmp (toolbar_style, "both"))
 502 		gtk_toolbar_set_style (GTK_TOOLBAR(mainwindow_priv->toolbar), GTK_TOOLBAR_BOTH);
 503 	else if (!strcmp (toolbar_style, "both_horiz") || !strcmp (toolbar_style, "both-horiz") )
 504 		gtk_toolbar_set_style (GTK_TOOLBAR (mainwindow_priv->toolbar), GTK_TOOLBAR_BOTH_HORIZ);
 505 	else /* default to icons */
 506 		gtk_toolbar_set_style (GTK_TOOLBAR (mainwindow_priv->toolbar), GTK_TOOLBAR_ICONS);
 507 }
 508 
 509 static gboolean
 510 on_key_press_event_null_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
 511 {
 512 	return TRUE;
 513 }
 514 
 515 static gboolean
 516 on_notebook_scroll_event_null_cb (GtkWidget *widget, GdkEventScroll *event)
 517 {
 518 	GtkNotebook *notebook = GTK_NOTEBOOK (widget);
 519 
 520 	GtkWidget* child;
 521 	GtkWidget* originator;
 522 
 523 	if (!notebook->cur_page)
 524 		return FALSE;
 525 
 526 	child = gtk_notebook_get_nth_page (notebook, gtk_notebook_get_current_page (notebook));
 527 	originator = gtk_get_event_widget ((GdkEvent *)event);
 528 
 529 	/* ignore scroll events from the content of the page */
 530 	if (!originator || gtk_widget_is_ancestor (originator, child))
 531 		return FALSE;
 532 
 533 	return TRUE;
 534 }
 535 
 536 static struct mainwindow *ui_mainwindow_new(void) {
 537 	GtkWidget		*window;
 538 	GtkWidget		*statusbar;
 539 	gchar			*toolbar_style;
 540 	struct mainwindow	*mw;
 541 
 542 	window = liferea_shell_lookup ("mainwindow");
 543 	mw = mainwindow_priv = g_new0 (struct mainwindow, 1);
 544 
 545 #ifdef MAEMO_CHANGES
 546 	mw->program = HILDON_PROGRAM(hildon_program_get_instance());
 547 	mw->container = window;
 548 	mw->window = hildon_window_new();
 549 	gtk_container_add(GTK_CONTAINER(mw->window), GTK_WIDGET(mw->container));
 550 	hildon_program_add_window(mw->program, HILDON_WINDOW(mw->window));
 551 #else
 552 	mw->window = GTK_WINDOW (window);
 553 #endif
 554 	
 555 	toolbar_style = conf_get_toolbar_style ();
 556 
 557 	gtk_widget_set_name (window, "lifereaMainwindow");
 558 	gtk_widget_set_name (liferea_shell_lookup ("feedlist"), "feedlist");
 559 	
 560 	ui_mainwindow_create_menus(mw);
 561 	gtk_box_pack_start (GTK_BOX (liferea_shell_lookup ("vbox1")), mw->toolbar, FALSE, FALSE, 0);
 562 	gtk_box_reorder_child(GTK_BOX (liferea_shell_lookup ("vbox1")), mw->toolbar, 0);
 563 	gtk_box_pack_start (GTK_BOX (liferea_shell_lookup ("vbox1")), mw->menubar, FALSE, FALSE, 0);
 564 	gtk_box_reorder_child(GTK_BOX (liferea_shell_lookup ("vbox1")), mw->menubar, 0);
 565 	ui_mainwindow_set_toolbar_style(toolbar_style);
 566 	g_free(toolbar_style);
 567 	gtk_widget_show_all(GTK_WIDGET(mw->toolbar));
 568 
 569 	g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "key_press_event",
 570 	                  G_CALLBACK (on_key_press_event_null_cb), NULL);
 571 
 572 	g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "key_release_event",
 573 	                  G_CALLBACK (on_key_press_event_null_cb), NULL);
 574 	
 575 	g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "scroll_event",
 576 	                  G_CALLBACK (on_notebook_scroll_event_null_cb), NULL);
 577 	
 578 	g_signal_connect(mw->window, "delete_event", G_CALLBACK(on_close), mw);
 579 	g_signal_connect(mw->window, "window_state_event", G_CALLBACK(on_mainwindow_window_state_event), mw);
 580 	g_signal_connect(mw->window, "key_press_event", G_CALLBACK(on_mainwindow_key_press_event), mw);
 581 	
 582 	statusbar = liferea_shell_lookup ("statusbar");
 583 	mw->statusbar_feedsinfo = gtk_label_new("");
 584 	gtk_widget_show(mw->statusbar_feedsinfo);
 585 	gtk_box_pack_start(GTK_BOX(statusbar), mw->statusbar_feedsinfo, FALSE, FALSE, 5);
 586 
 587 	ui_mainwindow_restore_position(window);
 588 	
 589 	return mw;
 590 }
 591 
 592 static GdkPixbuf* ui_mainwindow_get_theme_icon(GtkIconTheme *icon_theme, const gchar *name, gint size) {
 593 	GError *error = NULL;
 594 	GdkPixbuf *pixbuf;
 595 
 596 	pixbuf = gtk_icon_theme_load_icon(icon_theme,
 597 	                                  name, /* icon name */
 598 	                                  size, /* size */
 599 	                                  0,  /* flags */
 600 	                                  &error);
 601 	if(!pixbuf) {
 602 		debug1(DEBUG_GUI, "Couldn't load icon: %s", error->message);
 603 		g_error_free(error);
 604 	}
 605 	return pixbuf;
 606 }
 607 
 608 static void
 609 ui_mainwindow_destroy_cb (gpointer user_data)
 610 {
 611 	liferea_htmlview_plugin_deregister ();
 612 	ui_tray_enable (FALSE);
 613 	notification_enable (FALSE);
 614 }
 615 
 616 void
 617 ui_mainwindow_init (int mainwindowState)
 618 {
 619 	GtkWidget	*widget;
 620 	int		i;
 621 	GString		*buffer;
 622 	struct mainwindow *mw;
 623 	GtkIconTheme	*icon_theme;
 624 	
 625 	debug_enter("ui_mainwindow_init");
 626 	
 627 	liferea_shell_create ();
 628 	
 629 	ui_search_init();
 630 
 631 	mw = ui_mainwindow_new();
 632 	mainwindow = GTK_WIDGET(mw->window);
 633 	ui_tabs_init();
 634 	
 635 	g_signal_connect (G_OBJECT (mainwindow), "destroy", G_CALLBACK (ui_mainwindow_destroy_cb), NULL);
 636  
 637 	/* load pane proportions */
 638 	if(0 != getNumericConfValue(LAST_VPANE_POS))
 639 		gtk_paned_set_position(GTK_PANED(liferea_shell_lookup("leftpane")), getNumericConfValue(LAST_VPANE_POS));
 640 	if(0 != getNumericConfValue(LAST_HPANE_POS))
 641 		gtk_paned_set_position(GTK_PANED(liferea_shell_lookup("normalViewPane")), getNumericConfValue(LAST_HPANE_POS));
 642 	if(0 != getNumericConfValue(LAST_WPANE_POS))
 643 		gtk_paned_set_position(GTK_PANED(liferea_shell_lookup("wideViewPane")), getNumericConfValue(LAST_WPANE_POS));
 644 
 645 	/* order important !!! */
 646 	ui_feedlist_init(liferea_shell_lookup("feedlist"));
 647 	
 648 	mw->itemlistContainer = ui_itemlist_new();
 649 	mw->itemlist = gtk_bin_get_child (GTK_BIN (mw->itemlistContainer));
 650 	/* initially we pack the item list in the normal view pane,
 651 	   which is later changed in ui_mainwindow_set_layout() */
 652 	gtk_container_add(GTK_CONTAINER(liferea_shell_lookup("normalViewItems")), mw->itemlistContainer);
 653 	
 654 	itemview_init();
 655 	
 656 	/* necessary to prevent selection signals when filling the feed list
 657 	   and setting the 2/3 pane mode view */
 658 	gtk_widget_set_sensitive(GTK_WIDGET(liferea_shell_lookup("feedlist")), FALSE);
 659 
 660 	/* first try to load icons from theme */
 661 	icon_theme = gtk_icon_theme_get_default();
 662 	for(i = 0; i < MAX_ICONS; i++)
 663 		if(iconThemeNames[i] != NULL)
 664 			icons[i] = ui_mainwindow_get_theme_icon(icon_theme, iconThemeNames[i], 16);
 665 
 666 	/* and then load own default icons */
 667 	for(i = 0; i < MAX_ICONS; i++)
 668 		if(NULL == icons[i])
 669 			icons[i] = create_pixbuf(iconNames[i]);
 670 
 671 	/* set up icons that are build from stock */
 672 	widget = gtk_button_new();
 673 	icons[ICON_UNAVAILABLE] = gtk_widget_render_icon(widget, GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_MENU, "");
 674 	gtk_widget_destroy(widget);
 675 
 676 	ui_mainwindow_update_toolbar();
 677 	ui_mainwindow_update_menubar();
 678 	ui_mainwindow_online_status_changed(update_is_online());
 679 	
 680 	ui_tray_enable(getBooleanConfValue(SHOW_TRAY_ICON));			/* init tray icon */
 681 	ui_dnd_setup_URL_receiver(mainwindow);	/* setup URL dropping support */
 682 	ui_enclosure_init();
 683 
 684 	feedlist_init();
 685 	
 686 	ui_popup_update_menues();		/* create popup menues */
 687 			
 688 	if(mainwindowState == MAINWINDOW_ICONIFIED || 
 689 	   (mainwindowState == MAINWINDOW_HIDDEN && ui_tray_get_count() == 0)) {
 690 		gtk_window_iconify(GTK_WINDOW(mainwindow));
 691 		gtk_widget_show(mainwindow);
 692 	} else if(mainwindowState == MAINWINDOW_SHOWN) {
 693 		gtk_widget_show(mainwindow);
 694 	} else {
 695 		/* Needed so that the window structure can be
 696 		   accessed... otherwise will GTK warning when window is
 697 		   shown by clicking on notification icon. */
 698 		// gtk_widget_realize(GTK_WIDGET(mainwindow)); 
 699 		// Does not work with gtkmozembed...
 700 		
 701 		gtk_widget_show(mainwindow);
 702 		gtk_widget_hide(mainwindow);
 703 	}
 704 
 705 	/* force two pane mode */
 706 	/*   For some reason, this causes the first item to be selected and then
 707 	     unselected... strange. */
 708 	ui_feedlist_select(NULL);
 709 	/* Initialize the UI with respect to the viewing mode */
 710 	ui_mainwindow_set_layout(2);	/* FIXME: set user defined default viewing mode */
 711 	
 712 	/* set zooming properties */	
 713 	mainwindow_priv->zoom = getNumericConfValue(LAST_ZOOMLEVEL);
 714 
 715 	if(0 == mainwindow_priv->zoom) {	/* workaround for scheme problem with the last releases */
 716 		mainwindow_priv->zoom = 100;
 717 		setNumericConfValue(LAST_ZOOMLEVEL, 100);
 718 	}
 719 	liferea_htmlview_set_zoom (mainwindow_priv->htmlview, mainwindow_priv->zoom/100.);
 720 	
 721 	/* create welcome text */
 722 	buffer = g_string_new(NULL);
 723 	htmlview_start_output(buffer, NULL, TRUE, FALSE);
 724 	g_string_append(buffer,    "<div style=\"padding:8px\">"
 725 				   "<table class=\"headmeta\" style=\"border:solid 1px #aaa;font-size:120%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5px\"><tr><td>"
 726 				   // add application icon
 727 				   "<img src=\""
 728 				   PACKAGE_DATA_DIR G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "pixmaps" G_DIR_SEPARATOR_S
 729 				   "liferea.png\" />"
 730 				   "</td><td><h3>");
 731 	g_string_append(buffer,    _("Liferea - Linux Feed Reader"));
 732 	g_string_append(buffer,    "</h3></td></tr><tr><td colspan=\"2\">");
 733 	g_string_append(buffer,    _("<p>Welcome to <b>Liferea</b>, a desktop news aggregator for online news "
 734 				   "feeds.</p>"
 735 				   "<p>The left pane contains the list of your subscriptions. To add a "
 736 				   "subscription select Feeds -&gt; New Subscription. To browse the headlines "
 737 				   "of a feed select it in the feed list and the headlines will be loaded "
 738 				   "into the right pane.</p>"));
 739 	g_string_append(buffer,    "</td></tr></table>");
 740 
 741 	g_string_append(buffer,    "</div>");
 742 				   
 743 	htmlview_finish_output(buffer);
 744 	liferea_htmlview_write (ui_mainwindow_get_active_htmlview(), buffer->str, NULL);
 745 	g_string_free(buffer, TRUE);
 746 
 747 	gtk_widget_set_sensitive(GTK_WIDGET(liferea_shell_lookup("feedlist")), TRUE);
 748 	
 749 	script_run_for_hook(SCRIPT_HOOK_STARTUP);
 750 
 751 	debug_exit("ui_mainwindow_init");
 752 }
 753 
 754 void ui_mainwindow_update_toolbar(void) {
 755 	
 756 	/* to avoid "locking out" the user */
 757 	if(getBooleanConfValue(DISABLE_MENUBAR) && getBooleanConfValue(DISABLE_TOOLBAR))
 758 		setBooleanConfValue(DISABLE_TOOLBAR, FALSE);
 759 	
 760 	if(getBooleanConfValue(DISABLE_TOOLBAR))
 761 		gtk_widget_hide(mainwindow_priv->toolbar);
 762 	else
 763 		gtk_widget_show(mainwindow_priv->toolbar);
 764 }
 765 
 766 void ui_mainwindow_update_feed_menu(gboolean feedActions, gboolean readWrite) {
 767 	
 768 	gtk_action_group_set_sensitive(mainwindow_priv->addActions, readWrite);
 769 	gtk_action_group_set_sensitive(mainwindow_priv->feedActions, feedActions);
 770 	gtk_action_group_set_sensitive(mainwindow_priv->readWriteActions, readWrite);
 771 }
 772 
 773 void ui_mainwindow_update_menubar(void) {
 774 
 775 	if(getBooleanConfValue(DISABLE_MENUBAR))
 776 		gtk_widget_hide(mainwindow_priv->menubar);
 777 	else
 778 		gtk_widget_show(mainwindow_priv->menubar);
 779 }
 780 
 781 void ui_mainwindow_online_status_changed (int online) {
 782 	GtkWidget	*widget;
 783 
 784 	widget = liferea_shell_lookup("onlineimage");
 785 	
 786 	if(online) {
 787 		ui_mainwindow_set_status_bar(_("Liferea is now online"));
 788 		gtk_image_set_from_pixbuf(GTK_IMAGE(widget), icons[ICON_ONLINE]);
 789 		atk_object_set_name(gtk_widget_get_accessible(widget), _("Work Offline"));		
 790 	} else {
 791 		ui_mainwindow_set_status_bar(_("Liferea is now offline"));
 792 		gtk_image_set_from_pixbuf(GTK_IMAGE(widget), icons[ICON_OFFLINE]);
 793 		atk_object_set_name(gtk_widget_get_accessible(widget), _("Work Online"));	
 794 	}
 795 	gtk_toggle_action_set_active(
 796 	    GTK_TOGGLE_ACTION(gtk_action_group_get_action(mainwindow_priv->generalActions,"ToggleOfflineMode")),
 797 	    !online);
 798 }
 799 
 800 void on_onlinebtn_clicked(GtkButton *button, gpointer user_data) {
 801 	
 802 	update_set_online(!update_is_online());
 803 }
 804 
 805 static void on_work_offline_activate(GtkToggleAction *menuitem, gpointer user_data) {
 806 	
 807 	update_set_online(!gtk_toggle_action_get_active(menuitem));
 808 }
 809 
 810 gboolean
 811 ui_mainwindow_set_status_bar_idle_cb (gpointer user_data)
 812 {
 813 	gchar	*text = (gchar *)user_data;
 814 	
 815 	gtk_label_set_text (GTK_LABEL (GTK_STATUSBAR (liferea_shell_lookup ("statusbar"))->label), text);
 816 	g_free(text);
 817 	
 818 	return FALSE;
 819 }
 820 
 821 void
 822 ui_mainwindow_set_status_bar (const char *format, ...)
 823 {
 824 	va_list		args;
 825 	gchar 		*text;
 826 
 827 	g_return_if_fail (format != NULL);
 828 
 829 	va_start (args, format);
 830 	text = g_strdup_vprintf (format, args);
 831 	va_end (args);
 832 
 833 	g_idle_add ((GSourceFunc)ui_mainwindow_set_status_bar_idle_cb, (gpointer)text);
 834 }
 835 
 836 void
 837 ui_mainwindow_save_position (void)
 838 {
 839 	GtkWidget	*pane;
 840 	gint		x, y, w, h;
 841 
 842 	if (!GTK_WIDGET_VISIBLE (mainwindow))
 843 		return;
 844 	
 845 	if (getBooleanConfValue (LAST_WINDOW_MAXIMIZED))
 846 		return;
 847 
 848 	gtk_window_get_position (GTK_WINDOW (mainwindow), &x, &y);
 849 	gtk_window_get_size (GTK_WINDOW (mainwindow), &w, &h);
 850 
 851 	if (x+w<0 || y+h<0 ||
 852 	    x > gdk_screen_width () ||
 853 	    y > gdk_screen_height ())
 854 		return;
 855 	
 856 	/* save window position */
 857 	setNumericConfValue (LAST_WINDOW_X, x);
 858 	setNumericConfValue (LAST_WINDOW_Y, y);	
 859 
 860 	/* save window size */
 861 	setNumericConfValue (LAST_WINDOW_WIDTH, w);
 862 	setNumericConfValue (LAST_WINDOW_HEIGHT, h);
 863 	
 864 	/* save pane proportions */
 865 	if (NULL != (pane = liferea_shell_lookup ("leftpane"))) {
 866 		x = gtk_paned_get_position (GTK_PANED (pane));
 867 		setNumericConfValue (LAST_VPANE_POS, x);
 868 	}
 869 	
 870 	if (NULL != (pane = liferea_shell_lookup ("normalViewPane"))) {
 871 		y = gtk_paned_get_position (GTK_PANED (pane));
 872 		setNumericConfValue (LAST_HPANE_POS, y);
 873 	}
 874 	
 875 	if (NULL != (pane = liferea_shell_lookup ("wideViewPane"))) {
 876 		y = gtk_paned_get_position (GTK_PANED (pane));
 877 		setNumericConfValue (LAST_WPANE_POS, y);
 878 	}
 879 	
 880 	/* save itemlist properties */
 881 	setNumericConfValue (LAST_ZOOMLEVEL, (gint)(100.* liferea_htmlview_get_zoom (ui_mainwindow_get_active_htmlview ())));
 882 }
 883 
 884 void ui_mainwindow_tray_add() {
 885 
 886 }
 887 
 888 void ui_mainwindow_tray_remove() {
 889 	
 890 	if (ui_tray_get_count() == 0)
 891 		if (!GTK_WIDGET_VISIBLE(mainwindow)) {
 892 			ui_mainwindow_restore_position(mainwindow);
 893 			gtk_window_present(GTK_WINDOW(mainwindow));
 894 		}
 895 }
 896 
 897 /**
 898  * Restore the window position from the values saved into gconf. Note
 899  * that this does not display/present/show the mainwindow.
 900  */
 901 static void ui_mainwindow_restore_position(GtkWidget *window) {
 902 	/* load window position */
 903 	int x, y, w, h;
 904 	
 905 	x = getNumericConfValue(LAST_WINDOW_X);
 906 	y = getNumericConfValue(LAST_WINDOW_Y);
 907 	
 908 	w = getNumericConfValue(LAST_WINDOW_WIDTH);
 909 	h = getNumericConfValue(LAST_WINDOW_HEIGHT);
 910 	
 911 	/* Restore position only if the width and height were saved */
 912 	if(w != 0 && h != 0) {
 913 	
 914 		if(x >= gdk_screen_width())
 915 			x = gdk_screen_width() - 100;
 916 		else if(x + w < 0)
 917 			x  = 100;
 918 
 919 		if(y >= gdk_screen_height())
 920 			y = gdk_screen_height() - 100;
 921 		else if(y + w < 0)
 922 			y  = 100;
 923 	
 924 		gtk_window_move(GTK_WINDOW(window), x, y);
 925 
 926 		/* load window size */
 927 		gtk_window_resize(GTK_WINDOW(window), w, h);
 928 	}
 929 
 930 	if(getBooleanConfValue(LAST_WINDOW_MAXIMIZED))
 931 		gtk_window_maximize(GTK_WINDOW(window));
 932 	else
 933 		gtk_window_unmaximize(GTK_WINDOW(window));
 934 
 935 }
 936 
 937 /**
 938  * Function to present the main window
 939  */
 940 void ui_mainwindow_show() {
 941 
 942 	if((gdk_window_get_state(GTK_WIDGET(mainwindow)->window) & GDK_WINDOW_STATE_ICONIFIED) || !GTK_WIDGET_VISIBLE(mainwindow)) {
 943 		ui_mainwindow_restore_position(mainwindow);
 944 	}
 945 	gtk_window_present(GTK_WINDOW(mainwindow));
 946 }
 947 
 948 /*
 949  * Main menu and tray icon callbacks
 950  */
 951 
 952 static gboolean on_close(GtkWidget *widget, GdkEvent *event, struct mainwindow *mw) {
 953 	
 954 	if((ui_tray_get_count() == 0) || (getBooleanConfValue(DONT_MINIMIZE_TO_TRAY)))
 955 		return on_quit(widget, event, mw);
 956 	ui_mainwindow_save_position();
 957 	gtk_widget_hide(GTK_WIDGET(mw->window));
 958 	return TRUE;
 959 }
 960 
 961 void ui_mainwindow_toggle_visibility(GtkMenuItem *menuitem, gpointer data) {
 962 	
 963 	if((gdk_window_get_state(GTK_WIDGET(mainwindow)->window) & GDK_WINDOW_STATE_ICONIFIED) || !GTK_WIDGET_VISIBLE(mainwindow)) {
 964 		ui_mainwindow_restore_position(mainwindow);
 965 		gtk_window_present(GTK_WINDOW(mainwindow));
 966 	} else {
 967 		ui_mainwindow_save_position();
 968 		gtk_widget_hide(mainwindow);
 969 	}
 970 }
 971 
 972 gboolean on_mainwindow_window_state_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
 973 	if((event->type) == (GDK_WINDOW_STATE)) {
 974 		GdkWindowState changed = ((GdkEventWindowState*)event)->changed_mask, state = ((GdkEventWindowState*)event)->new_window_state;
 975 		
 976 		if (changed == GDK_WINDOW_STATE_MAXIMIZED && !(state & GDK_WINDOW_STATE_WITHDRAWN)) {
 977 			if(state & GDK_WINDOW_STATE_MAXIMIZED)
 978 				setBooleanConfValue(LAST_WINDOW_MAXIMIZED, TRUE);
 979 			else
 980 				setBooleanConfValue(LAST_WINDOW_MAXIMIZED, FALSE);
 981 		}
 982 		if(state & GDK_WINDOW_STATE_ICONIFIED)
 983 			session_set_cmd(NULL, MAINWINDOW_ICONIFIED);
 984 		else if(state & GDK_WINDOW_STATE_WITHDRAWN)
 985 			session_set_cmd(NULL, MAINWINDOW_HIDDEN);
 986 		else
 987 			session_set_cmd(NULL, MAINWINDOW_SHOWN);
 988 	}
 989 	return FALSE;
 990 }
 991 
 992 struct file_chooser_tuple {
 993 	GtkWidget *dialog;
 994 	fileChoosenCallback func;
 995 	gpointer user_data;
 996 };
 997 
 998 static void ui_choose_file_save_cb(GtkDialog *dialog, gint response_id, gpointer user_data) {
 999 	struct file_chooser_tuple *tuple = (struct file_chooser_tuple*)user_data;
1000 	gchar *filename;
1001 
1002 	if(response_id == GTK_RESPONSE_ACCEPT) {
1003 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1004 		tuple->func(filename, tuple->user_data);
1005 		g_free(filename);
1006 	} else {
1007 		tuple->func(NULL, tuple->user_data);
1008 	}
1009 	
1010 	gtk_widget_destroy(GTK_WIDGET(dialog));
1011 	g_free(tuple);
1012 }
1013 
1014 static void ui_choose_file_or_dir(gchar *title, gchar *buttonName, gboolean saving, gboolean directory, fileChoosenCallback callback, const gchar *currentPath, const gchar *defaultFilename, gpointer user_data) {
1015 	GtkWidget			*dialog;
1016 	struct file_chooser_tuple	*tuple;
1017 	GtkWidget			*button;
1018 
1019 	g_assert(!(saving & directory));
1020 	g_assert(!(defaultFilename && !saving));
1021 	
1022 	dialog = gtk_file_chooser_dialog_new(title, GTK_WINDOW (mainwindow),
1023 	                                     (directory?GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
1024 					      (saving ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN)),
1025 	                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1026 	                                     NULL);
1027 	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1028 	tuple = g_new0(struct file_chooser_tuple, 1);
1029 	tuple->dialog = dialog;
1030 	tuple->func = callback;
1031 	tuple->user_data = user_data;
1032 	
1033 	button = gtk_dialog_add_button(GTK_DIALOG(dialog), buttonName, GTK_RESPONSE_ACCEPT);
1034 	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1035 	gtk_widget_grab_default(button);
1036 	
1037 	g_signal_connect(G_OBJECT(dialog), "response",
1038 	                 G_CALLBACK(ui_choose_file_save_cb), tuple);
1039 	if(currentPath != NULL && g_file_test(currentPath, G_FILE_TEST_EXISTS)) {
1040 		if (directory)
1041 			gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), currentPath);
1042 		else 
1043 			gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), currentPath);
1044 	}
1045 	if(defaultFilename)
1046 		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), defaultFilename);
1047 	
1048 	gtk_widget_show_all(dialog);
1049 }
1050 
1051 void ui_choose_file(gchar *title, gchar *buttonName, gboolean saving, fileChoosenCallback callback, const gchar *currentPath, const gchar *defaultFilename, gpointer user_data) {
1052 
1053 	ui_choose_file_or_dir(title, buttonName, saving, FALSE, callback, currentPath, defaultFilename, user_data);
1054 }
1055 
1056 void ui_choose_directory(gchar *title, gchar *buttonName, fileChoosenCallback callback, const gchar *currentPath, gpointer user_data) {
1057 
1058 	ui_choose_file_or_dir(title, buttonName, FALSE, TRUE, callback, currentPath, NULL, user_data);
1059 }
1060 
1061 static const GtkActionEntry ui_mainwindow_action_entries[] = {
1062 	{"SubscriptionsMenu", NULL, N_("_Subscriptions")},
1063 	{"UpdateAll", "gtk-refresh", N_("Update _All"), "<control>A", N_("Updates all subscriptions. This does not update OCS directories."),
1064 	 G_CALLBACK(on_menu_update_all)},
1065 	{"MarkAllFeedsAsRead", "gtk-apply", N_("Mark All As _Read"), NULL, N_("Marks read every item of every subscription."),
1066 	 G_CALLBACK(on_menu_allfeedsread)},
1067 	{"ImportFeedList", "gtk-open", N_("_Import Feed List..."), NULL, N_("Imports an OPML feed list."), G_CALLBACK(on_import_activate)},
1068 	{"ExportFeedList", "gtk-save-as", N_("_Export Feed List..."), NULL, N_("Exports the feed list as OPML."), G_CALLBACK(on_export_activate)},
1069 	{"Quit",GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", NULL, G_CALLBACK(on_quit)},
1070 
1071 	{"FeedMenu", NULL, N_("_Feed")},
1072 	{"RemoveAllItems", "gtk-delete", N_("Remove _All Items"), NULL, N_("Removes all items of the currently selected feed."),
1073 	 G_CALLBACK(on_remove_items_activate)},
1074 
1075 	{"ItemMenu", NULL, N_("_Item")},
1076 	{"NextUnreadItem", GTK_STOCK_GO_FORWARD, N_("_Next Unread Item"), "<control>N", N_("Jumps to the next unread item. If necessary selects the next feed with unread items."),
1077 	 G_CALLBACK(on_next_unread_item_activate)},
1078 	{"ToggleItemReadStatus", "gtk-apply", N_("Toggle _Read Status"), "<control>U", N_("Toggles the read status of the selected item."),
1079 	 G_CALLBACK(on_toggle_unread_status)},
1080 	{"ToggleItemFlag", NULL, N_("Toggle Item _Flag"), "<control>T", N_("Toggles the flag status of the selected item."),
1081 	 G_CALLBACK(on_toggle_item_flag)},
1082 	{"RemoveSelectedItem", "gtk-delete", N_("R_emove"), NULL, N_("Removes the selected item."),
1083 	 G_CALLBACK(on_remove_item_activate)},
1084 	{"LaunchItemInBrowser", NULL, N_("_Launch In Browser"), NULL, N_("Launches the item's link in the configured browser."),
1085 	 G_CALLBACK(on_popup_launchitem_selected)},
1086 
1087 	{"ViewMenu", NULL, N_("_View")},
1088 	{"ZoomIn", "gtk-zoom-in", N_("_Increase Text Size"), "<control>plus", N_("Increases the text size of the item view."),
1089 	 G_CALLBACK(on_popup_zoomin_selected)},
1090 	{"ZoomOut", "gtk-zoom-out", N_("_Decrease Text Size"), "<control>minus", N_("Decreases the text size of the item view."),
1091 	 G_CALLBACK(on_popup_zoomout_selected)},
1092 
1093 	{"ToolsMenu", NULL, N_("_Tools")},
1094 	{"ShowUpdateMonitor", NULL, N_("_Update Monitor"), NULL, N_("Show a list of all feeds currently in the update queue"),
1095 	 G_CALLBACK(on_menu_show_update_monitor)},
1096 	{"ShowScriptManager", NULL, N_("_Script Manager"), NULL, N_("Allows to configure and edit LUA hook scripts"),
1097 	 G_CALLBACK(on_menu_show_script_manager)},
1098 	{"ShowPreferences", GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, N_("Edit Preferences."),
1099 	 G_CALLBACK(on_prefbtn_clicked)},
1100 	 
1101 	{"SearchMenu", NULL, N_("_Search")},
1102 	{"SearchFeeds", "gtk-find", N_("Search All Feeds..."), "<control>F", N_("Show the search dialog."), G_CALLBACK(on_searchbtn_clicked)},
1103 	{"CreateEngineSearch", NULL, N_("Search With ...")},
1104 	
1105 	{"HelpMenu", NULL, N_("_Help")},
1106 	{"ShowHelpContents", "gtk-help", N_("_Contents"), "F1", N_("View help for this application."), G_CALLBACK(on_topics_activate)},
1107 	{"ShowHelpQuickReference", NULL, N_("_Quick Reference"), NULL, N_("View a list of all Liferea shortcuts."),
1108 	 G_CALLBACK(on_quick_reference_activate)},
1109 	{"ShowHelpFAQ", NULL, N_("_FAQ"), NULL, N_("View the FAQ for this application."), G_CALLBACK(on_faq_activate)},
1110 	{"ShowAbout", "gtk-about", N_("_About"), NULL, N_("Shows an about dialog."), G_CALLBACK(on_about_activate)}
1111 };
1112 
1113 static const GtkRadioActionEntry ui_mainwindow_view_radio_entries[] = {
1114 	{"NormalView", NULL, N_("_Normal View"), NULL, N_("Set view mode to mail client mode."),
1115 	 0},
1116 	{"WideView", NULL, N_("_Wide View"), NULL, N_("Set view mode to use three vertical panes."),
1117 	 1},
1118 	{"CombinedView", NULL, N_("_Combined View"), NULL, N_("Set view mode to two pane mode."),
1119 	 2}
1120 };
1121 
1122 static const GtkActionEntry ui_mainwindow_add_action_entries[] = {
1123 	{"NewSubscription", "gtk-add", N_("_New Subscription..."), NULL, N_("Adds a subscription to the feed list."),
1124 	 G_CALLBACK(on_menu_feed_new)},
1125 	{"NewFolder", NULL, N_("New _Folder..."), NULL, N_("Adds a folder to the feed list."), G_CALLBACK(on_menu_folder_new)},
1126 	{"NewVFolder", NULL, N_("New S_earch Folder..."), NULL, N_("Adds a new search folder to the feed list."), G_CALLBACK(on_new_vfolder_activate)},
1127 	{"NewPlugin", NULL, N_("New _Source..."), NULL, N_("Adds a new feed list source."), G_CALLBACK(on_new_plugin_activate)},
1128 	{"NewNewsBin", NULL, N_("New _News Bin..."), NULL, N_("Adds a new news bin."), G_CALLBACK(on_new_newsbin_activate)}
1129 };
1130 
1131 static const GtkActionEntry ui_mainwindow_feed_action_entries[] = {
1132 	{"MarkFeedAsRead", "gtk-apply", N_("_Mark As Read"), "<control>R", N_("Marks all items of the selected subscription or of all subscriptions of the selected folder as read."), 
1133 	 G_CALLBACK(on_menu_allread)},
1134 	{"UpdateSelected", "gtk-refresh", N_("_Update"), NULL, N_("Updates the selected subscription or all subscriptions of the selected folder."),
1135 	 G_CALLBACK(on_menu_update)}
1136 };
1137 
1138 static const GtkActionEntry ui_mainwindow_read_write_action_entries[] = {
1139 	{"Properties", "gtk-properties", N_("_Properties..."), NULL, N_("Opens the property dialog for the selected subscription."), G_CALLBACK(on_menu_properties)},
1140 	{"DeleteSelected", "gtk-delete", N_("_Remove"), NULL, N_("Removes the selected subscription."), G_CALLBACK(on_menu_delete)}
1141 };
1142 
1143 static const GtkToggleActionEntry ui_mainwindow_action_toggle_entries[] = {
1144 	{"ToggleOfflineMode", NULL, N_("_Work Offline"), NULL, N_("This option allows you to disable subscription updating."),
1145 	 G_CALLBACK(on_work_offline_activate)}
1146 };
1147 
1148 static const char *ui_mainwindow_ui_desc =
1149 "<ui>"
1150 "  <menubar name='MainwindowMenubar'>"
1151 "    <menu action='SubscriptionsMenu'>"
1152 "      <menuitem action='UpdateAll'/>"
1153 "      <menuitem action='MarkAllFeedsAsRead'/>"
1154 "      <separator/>"
1155 "      <menuitem action='NewSubscription'/>"
1156 "      <menuitem action='NewFolder'/>"
1157 "      <menuitem action='NewVFolder'/>"
1158 "      <menuitem action='NewPlugin'/>"
1159 "      <menuitem action='NewNewsBin'/>"
1160 "      <separator/>"
1161 "      <menuitem action='ImportFeedList'/>"
1162 "      <menuitem action='ExportFeedList'/>"
1163 "      <separator/>"
1164 "      <menuitem action='ToggleOfflineMode'/>"
1165 "      <separator/>"
1166 "      <menuitem action='Quit'/>"
1167 "    </menu>"
1168 "    <menu action='FeedMenu'>"
1169 "      <menuitem action='UpdateSelected'/>"
1170 "      <menuitem action='MarkFeedAsRead'/>"
1171 "      <separator/>"
1172 "      <menuitem action='RemoveAllItems'/>"
1173 "      <menuitem action='DeleteSelected'/>"
1174 "      <separator/>"
1175 "      <menuitem action='Properties'/>"
1176 "    </menu>"
1177 "    <menu action='ItemMenu'>"
1178 "      <menuitem action='NextUnreadItem'/>"
1179 "      <separator/>"
1180 "      <menuitem action='ToggleItemReadStatus'/>"
1181 "      <menuitem action='ToggleItemFlag'/>"
1182 "      <menuitem action='RemoveSelectedItem'/>"
1183 "      <separator/>"
1184 "      <menuitem action='LaunchItemInBrowser'/>"
1185 "    </menu>"
1186 "    <menu action='ViewMenu'>"
1187 "      <menuitem action='ZoomIn'/>"
1188 "      <menuitem action='ZoomOut'/>"
1189 "      <separator/>"
1190 "      <menuitem action='NormalView'/>"
1191 "      <menuitem action='WideView'/>"
1192 "      <menuitem action='CombinedView'/>"
1193 "    </menu>"
1194 "    <menu action='ToolsMenu'>"
1195 "      <menuitem action='ShowUpdateMonitor'/>"
1196 "      <menuitem action='ShowScriptManager'/>"
1197 "      <menuitem action='ShowPreferences'/>"
1198 "    </menu>"
1199 "    <menu action='SearchMenu'>"
1200 "      <menuitem action='SearchFeeds'/>"
1201 "      <menu action='CreateEngineSearch'/>"
1202 "    </menu>"
1203 "    <menu action='HelpMenu'>"
1204 "      <menuitem action='ShowHelpContents'/>"
1205 "      <menuitem action='ShowHelpQuickReference'/>"
1206 "      <menuitem action='ShowHelpFAQ'/>"
1207 "      <separator/>"
1208 "      <menuitem action='ShowAbout'/>"
1209 "    </menu>"
1210 "  </menubar>"
1211 "  <toolbar action='maintoolbar'>"
1212 "    <separator/>"
1213 "    <toolitem name='newFeedButton' action='NewSubscription'/>"
1214 "    <toolitem name='nextUnreadButton' action='NextUnreadItem'/>"
1215 "    <toolitem name='MarkAsReadButton' action='MarkFeedAsRead'/>"
1216 "    <toolitem name='UpdateAllButton' action='UpdateAll'/>"
1217 "    <toolitem name='SearchButton' action='SearchFeeds'/>"
1218 //"    <toolitem name='ViewingModeButton' action='ToggleCondensedMode'/>"
1219 "    <toolitem name='PreferencesButton' action='ShowPreferences'/>"
1220 "    <separator/>"
1221 "  </toolbar>"
1222 "</ui>";
1223 
1224 static void ui_mainwindow_create_menus(struct mainwindow *mw) {
1225 	GtkUIManager	*ui_manager;
1226 	GtkAccelGroup	*accel_group;
1227 	GError		*error = NULL;
1228 	
1229 	//register_my_stock_icons ();
1230 	//gtk_container_add (GTK_CONTAINER (window), vbox);
1231 	ui_manager = gtk_ui_manager_new ();
1232 
1233 	mw->generalActions = gtk_action_group_new ("GeneralActions");
1234 	gtk_action_group_set_translation_domain (mw->generalActions, PACKAGE);
1235 	gtk_action_group_add_actions (mw->generalActions, ui_mainwindow_action_entries, G_N_ELEMENTS (ui_mainwindow_action_entries), mw);
1236 	gtk_action_group_add_toggle_actions (mw->generalActions, ui_mainwindow_action_toggle_entries, G_N_ELEMENTS (ui_mainwindow_action_toggle_entries), mw);
1237 	gtk_action_group_add_radio_actions (mw->generalActions, ui_mainwindow_view_radio_entries, G_N_ELEMENTS (ui_mainwindow_view_radio_entries), itemlist_get_view_mode (), (GCallback)on_view_activate, (gpointer)TRUE);
1238 	gtk_ui_manager_insert_action_group (ui_manager, mw->generalActions, 0);
1239 
1240 	mw->addActions = gtk_action_group_new ("AddActions");
1241 	gtk_action_group_set_translation_domain (mw->addActions, PACKAGE);
1242 	gtk_action_group_add_actions (mw->addActions, ui_mainwindow_add_action_entries, G_N_ELEMENTS (ui_mainwindow_add_action_entries), mw);
1243 	gtk_ui_manager_insert_action_group (ui_manager, mw->addActions, 0);
1244 	
1245 	mw->feedActions = gtk_action_group_new ("FeedActions");
1246 	gtk_action_group_set_translation_domain (mw->feedActions, PACKAGE);
1247 	gtk_action_group_add_actions (mw->feedActions, ui_mainwindow_feed_action_entries, G_N_ELEMENTS (ui_mainwindow_feed_action_entries), mw);
1248 	gtk_ui_manager_insert_action_group (ui_manager, mw->feedActions, 0);
1249 	
1250 	mw->readWriteActions = gtk_action_group_new("ReadWriteActions");
1251 	gtk_action_group_set_translation_domain (mw->readWriteActions, PACKAGE);
1252 	gtk_action_group_add_actions (mw->readWriteActions, ui_mainwindow_read_write_action_entries, G_N_ELEMENTS (ui_mainwindow_read_write_action_entries), mw);
1253 	gtk_ui_manager_insert_action_group (ui_manager, mw->readWriteActions, 0);
1254 
1255 #ifndef MAEMO_CHANGES	
1256 	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
1257 	gtk_window_add_accel_group (mw->window, accel_group);
1258 #endif
1259 
1260 	if(!gtk_ui_manager_add_ui_from_string(ui_manager, ui_mainwindow_ui_desc, -1, &error))
1261 		g_error("building menus failed: %s", error->message);
1262 	
1263 	ui_search_engines_setup_menu(ui_manager);
1264 
1265 	mw->menubar = gtk_ui_manager_get_widget (ui_manager, "/MainwindowMenubar");
1266 	mw->toolbar = gtk_ui_manager_get_widget (ui_manager, "/maintoolbar");
1267 
1268 
1269 #ifdef MAEMO_CHANGES
1270 	GtkWidget *main_menu;
1271 	GList *iter;
1272 
1273 	/* Create new main menu */
1274 	main_menu = gtk_menu_new();
1275 
1276 	iter = gtk_container_get_children (GTK_CONTAINER (mw->menubar));
1277 	while (iter) {
1278 		GtkWidget *menu;
1279 
1280 		menu = GTK_WIDGET (iter->data);
1281 		gtk_widget_reparent(menu, main_menu);
1282 
1283 		iter = g_list_next (iter);
1284 	}
1285 
1286 	hildon_window_set_menu(HILDON_WINDOW(mw->window), GTK_MENU(main_menu));
1287 #endif
1288 	
1289 	/* what a pain, why is there no markup for this option? */
1290 	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/newFeedButton")), "is_important", TRUE, NULL);
1291 	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/nextUnreadButton")), "is_important", TRUE, NULL);
1292 	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/MarkAsReadButton")), "is_important", TRUE, NULL);
1293 	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/UpdateAllButton")), "is_important", TRUE, NULL);
1294 	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/SearchButton")), "is_important", TRUE, NULL);
1295 	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/PreferencesButton")), "is_important", TRUE, NULL);
1296 }
1297 
1298 void ui_mainwindow_update_feedsinfo(void) {
1299 	gint	new_items, unread_items;
1300 	gchar	*msg, *tmp;
1301 
1302 	if(mainwindow == NULL)
1303 		return;
1304 	
1305 	new_items = feedlist_get_new_item_count();
1306 	unread_items = feedlist_get_unread_item_count();
1307 	
1308 	if(new_items != 0) {
1309 		msg = g_strdup_printf(ngettext(" (%d new)", " (%d new)", new_items), new_items);
1310 	} else {
1311 		msg = g_strdup("");
1312 	}
1313 		
1314 	if(unread_items != 0) {
1315 		tmp = g_strdup_printf(ngettext("%d unread%s", "%d unread%s", unread_items), unread_items, msg);
1316 	} else {
1317 		tmp = g_strdup("");
1318 	}
1319 
1320 	gtk_label_set_text(GTK_LABEL(mainwindow_priv->statusbar_feedsinfo), tmp);
1321 	g_free(tmp);
1322 	g_free(msg);
1323 }

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2007-09-29 18:23:59, 2.0 KB) [[attachment:Makefile.am]]
  • [get | view] (2007-09-29 18:27:09, 0.9 KB) [[attachment:Makefile.am from ui directory]]
  • [get | view] (2007-09-29 18:19:25, 16.5 KB) [[attachment:configure.ac]]
  • [get | view] (2007-09-29 18:46:32, 110.7 KB) [[attachment:hildonized.png]]
  • [get | view] (2007-09-29 19:02:18, 6630.1 KB) [[attachment:liferea-1.4.2b.tar.gz]]
  • [get | view] (2007-09-29 18:31:43, 286.9 KB) [[attachment:liferea.glade]]
  • [get | view] (2007-09-29 18:43:07, 91.2 KB) [[attachment:liferea.png]]
  • [get | view] (2007-09-29 18:32:30, 286.8 KB) [[attachment:liferea_hildon.glade]]
  • [get | view] (2007-09-29 18:47:27, 62.2 KB) [[attachment:liferea_maemo.png]]
  • [get | view] (2007-09-29 18:28:40, 0.9 KB) [[attachment:ui makefile]]
  • [get | view] (2007-09-29 18:30:47, 0.9 KB) [[attachment:ui_Makefile.am]]
  • [get | view] (2007-09-29 18:36:26, 4.1 KB) [[attachment:ui_dialog.c]]
  • [get | view] (2007-09-29 18:53:17, 44.9 KB) [[attachment:ui_mainwindow.c]]
  • [get | view] (2007-09-29 18:35:59, 3.2 KB) [[attachment:ui_shell.c]]
 All files | Selected Files: delete move to page

You are not allowed to attach a file to this page.