2
* @file ui_shell.c UI layout handling
4
* Copyright (C) 2004-2006 Nathan J. Conrad <t98502@users.sourceforge.net>
5
* Copyright (C) 2007-2008 Lars Lindner <lars.lindner@gmail.com>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program 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
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
#include "ui/liferea_shell.h"
30
#include <gdk/gdkkeysyms.h>
31
#include <glade/glade.h>
32
#include <string.h> /* strcmp() and strsep() */
43
#include "notification/notification.h"
44
#include "ui/browser_tabs.h"
45
#include "ui/itemview.h"
46
#include "ui/liferea_dialog.h"
47
#include "ui/ui_common.h"
48
#include "ui/ui_feedlist.h"
49
#include "ui/ui_itemlist.h"
50
#include "ui/ui_prefs.h"
51
#include "ui/ui_script.h"
52
#include "ui/ui_search.h"
53
#include "ui/search_dialog.h"
54
#include "ui/ui_session.h"
55
#include "ui/ui_tray.h"
56
#include "ui/ui_update.h"
58
/* all used icons (FIXME: evil) */
59
GdkPixbuf *icons[MAX_ICONS];
61
static void liferea_shell_class_init (LifereaShellClass *klass);
62
static void liferea_shell_init (LifereaShell *ls);
64
#define LIFEREA_SHELL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), LIFEREA_SHELL_TYPE, LifereaShellPrivate))
66
struct LifereaShellPrivate {
69
GtkWindow *window; /**< Liferea main window */
72
GtkTreeView *feedlistView;
74
GtkStatusbar *statusbar; /**< main window status bar */
75
gboolean statusbarLocked; /**< flag locking important message on status bar */
76
guint statusbarLockTimer; /**< timer id for status bar lock reset timer */
78
GtkWidget *statusbar_feedsinfo;
79
GtkActionGroup *generalActions;
80
GtkActionGroup *addActions; /**< all types of "New" options */
81
GtkActionGroup *feedActions; /**< update and mark read */
82
GtkActionGroup *readWriteActions; /**< node remove and properties, node itemset items remove */
83
GtkActionGroup *itemActions; /**< item state toggline, single item remove */
90
static GObjectClass *parent_class = NULL;
91
static LifereaShell *shell = NULL;
94
liferea_shell_get_type (void)
96
static GType type = 0;
98
if (G_UNLIKELY (type == 0))
100
static const GTypeInfo our_info =
102
sizeof (LifereaShellClass),
103
NULL, /* base_init */
104
NULL, /* base_finalize */
105
(GClassInitFunc) liferea_shell_class_init,
107
NULL, /* class_data */
108
sizeof (LifereaShell),
110
(GInstanceInitFunc) liferea_shell_init
113
type = g_type_register_static (G_TYPE_OBJECT,
122
liferea_shell_finalize (GObject *object)
124
LifereaShell *ls = LIFEREA_SHELL (object);
126
g_object_unref (ls->priv->xml);
128
G_OBJECT_CLASS (parent_class)->finalize (object);
132
liferea_shell_class_init (LifereaShellClass *klass)
134
GObjectClass *object_class = G_OBJECT_CLASS (klass);
136
parent_class = g_type_class_peek_parent (klass);
138
object_class->finalize = liferea_shell_finalize;
140
g_type_class_add_private (object_class, sizeof(LifereaShellPrivate));
144
liferea_shell_lookup (const gchar *name)
146
g_return_val_if_fail (shell != NULL, NULL);
147
g_return_val_if_fail (shell->priv != NULL, NULL);
149
return glade_xml_get_widget (shell->priv->xml, name);
153
liferea_shell_init (LifereaShell *ls)
155
/* globally accessible singleton */
156
g_assert (NULL == shell);
159
shell->priv = LIFEREA_SHELL_GET_PRIVATE (ls);
160
shell->priv->xml = glade_xml_new (PACKAGE_DATA_DIR G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "liferea.glade", "mainwindow", GETTEXT_PACKAGE);
161
glade_xml_signal_autoconnect (shell->priv->xml);
165
* Restore the window position from the values saved into gconf. Note
166
* that this does not display/present/show the mainwindow.
169
liferea_shell_restore_position (void)
171
/* load window position */
174
x = conf_get_int_value (LAST_WINDOW_X);
175
y = conf_get_int_value (LAST_WINDOW_Y);
177
w = conf_get_int_value (LAST_WINDOW_WIDTH);
178
h = conf_get_int_value (LAST_WINDOW_HEIGHT);
180
debug4 (DEBUG_GUI, "Retrieved saved setting: size %dx%d position %d:%d", w, h, x, y);
182
/* Restore position only if the width and height were saved */
183
if (w != 0 && h != 0) {
185
if (x >= gdk_screen_width ())
186
x = gdk_screen_width () - 100;
190
if (y >= gdk_screen_height ())
191
y = gdk_screen_height () - 100;
195
debug4 (DEBUG_GUI, "Restoring to size %dx%d position %d:%d", w, h, x, y);
197
gtk_window_move (GTK_WINDOW (shell->priv->window), x, y);
199
/* load window size */
200
gtk_window_resize (GTK_WINDOW (shell->priv->window), w, h);
203
if (conf_get_bool_value (LAST_WINDOW_MAXIMIZED))
204
gtk_window_maximize (GTK_WINDOW (shell->priv->window));
206
gtk_window_unmaximize (GTK_WINDOW (shell->priv->window));
211
liferea_shell_save_position (void)
216
/* save pane proportions */
217
pane = liferea_shell_lookup ("leftpane");
219
x = gtk_paned_get_position (GTK_PANED (pane));
220
conf_set_int_value (LAST_VPANE_POS, x);
223
pane = liferea_shell_lookup ("normalViewPane");
225
y = gtk_paned_get_position (GTK_PANED (pane));
226
conf_set_int_value (LAST_HPANE_POS, y);
229
pane = liferea_shell_lookup ("wideViewPane");
231
y = gtk_paned_get_position (GTK_PANED (pane));
232
conf_set_int_value (LAST_WPANE_POS, y);
235
/* The following needs to be skipped when the window is not visible */
236
if (!GTK_WIDGET_VISIBLE (shell->priv->window))
239
if (conf_get_bool_value (LAST_WINDOW_MAXIMIZED))
242
gtk_window_get_position (shell->priv->window, &x, &y);
243
gtk_window_get_size (shell->priv->window, &w, &h);
245
if (x+w<0 || y+h<0 ||
246
x > gdk_screen_width () ||
247
y > gdk_screen_height ())
250
debug4 (DEBUG_GUI, "Saving window size and position: %dx%d %d:%d", w, h, x, y);
252
/* save window position */
253
conf_set_int_value (LAST_WINDOW_X, x);
254
conf_set_int_value (LAST_WINDOW_Y, y);
256
/* save window size */
257
conf_set_int_value (LAST_WINDOW_WIDTH, w);
258
conf_set_int_value (LAST_WINDOW_HEIGHT, h);
262
liferea_shell_set_toolbar_style (const gchar *toolbar_style)
264
if (!toolbar_style) /* default to icons */
265
gtk_toolbar_set_style (GTK_TOOLBAR (shell->priv->toolbar), GTK_TOOLBAR_ICONS);
266
else if (!strcmp (toolbar_style, "text"))
267
gtk_toolbar_set_style (GTK_TOOLBAR (shell->priv->toolbar), GTK_TOOLBAR_TEXT);
268
else if (!strcmp (toolbar_style, "both"))
269
gtk_toolbar_set_style (GTK_TOOLBAR (shell->priv->toolbar), GTK_TOOLBAR_BOTH);
270
else if (!strcmp (toolbar_style, "both_horiz") || !strcmp (toolbar_style, "both-horiz") )
271
gtk_toolbar_set_style (GTK_TOOLBAR (shell->priv->toolbar), GTK_TOOLBAR_BOTH_HORIZ);
272
else /* default to icons */
273
gtk_toolbar_set_style (GTK_TOOLBAR (shell->priv->toolbar), GTK_TOOLBAR_ICONS);
277
liferea_shell_update_toolbar (void)
279
if (conf_get_bool_value (DISABLE_TOOLBAR))
280
gtk_widget_hide (shell->priv->toolbar);
282
gtk_widget_show (shell->priv->toolbar);
286
liferea_shell_update_update_menu (gboolean enabled)
288
gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->feedActions, "UpdateSelected"), enabled);
292
liferea_shell_update_feed_menu (gboolean add, gboolean enabled, gboolean readWrite)
294
gtk_action_group_set_sensitive (shell->priv->addActions, add);
295
gtk_action_group_set_sensitive (shell->priv->feedActions, enabled);
296
gtk_action_group_set_sensitive (shell->priv->readWriteActions, readWrite);
300
liferea_shell_update_item_menu (gboolean enabled)
302
gtk_action_group_set_sensitive (shell->priv->itemActions, enabled);
306
liferea_shell_update_allitems_actions (gboolean isNotEmpty, gboolean isRead)
308
gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->generalActions, "RemoveAllItems"), isNotEmpty);
309
gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->feedActions, "MarkFeedAsRead"), isRead);
313
liferea_shell_update_unread_stats (void)
315
gint new_items, unread_items;
321
new_items = feedlist_get_new_item_count ();
322
unread_items = feedlist_get_unread_item_count ();
325
msg = g_strdup_printf (ngettext (" (%d new)", " (%d new)", new_items), new_items);
329
if (unread_items != 0)
330
tmp = g_strdup_printf (ngettext ("%d unread%s", "%d unread%s", unread_items), unread_items, msg);
334
gtk_label_set_text (GTK_LABEL (shell->priv->statusbar_feedsinfo), tmp);
340
Do to the unsuitable GtkStatusBar stack handling which doesn't
341
allow to keep messages on top of the stack for some time without
342
overwriting them with newly arriving messages we need some extra
345
Liferea knows two types of status messages:
347
-> low prio messages (e.g. updating status messages)
348
-> high prio messages (caused by user interaction, e.g. link hovering)
350
The ideas is to keep the high prio messages always visible no matter
351
what low prio messages arrive. To solve this we define the status bar
352
stack is always a stack of two messages at most. At the bottom of the
353
stack is always the latest low prio message and on top of the stack
354
is the latest high prio message (or none at all).
356
To enforce this using GtkStatusBar we use a lock to avoid adding
357
low prio messages on top of high priority ones. This lock is valid
358
for at most 5s which should be enough to read the high priority
359
message. Afterwards new low priority messages will overrule the
360
out-dated high priority message.
364
liferea_shell_unlock_status_bar_cb (gpointer user_data)
366
shell->priv->statusbarLocked = FALSE;
372
liferea_shell_set_status_bar_important_cb (gpointer user_data)
374
gchar *text = (gchar *)user_data;
376
GtkStatusbar *statusbar;
378
statusbar = GTK_STATUSBAR (shell->priv->statusbar);
379
id = gtk_statusbar_get_context_id (statusbar, "important");
380
gtk_statusbar_pop (statusbar, id);
381
gtk_statusbar_push (statusbar, id, text);
388
liferea_shell_set_status_bar_default_cb (gpointer user_data)
390
gchar *text = (gchar *)user_data;
392
GtkStatusbar *statusbar;
394
statusbar = GTK_STATUSBAR (shell->priv->statusbar);
395
id = gtk_statusbar_get_context_id (statusbar, "default");
396
gtk_statusbar_pop (statusbar, id);
397
gtk_statusbar_push (statusbar, id, text);
404
liferea_shell_set_status_bar (const char *format, ...)
409
if (shell->priv->statusbarLocked)
412
g_return_if_fail (format != NULL);
414
va_start (args, format);
415
text = g_strdup_vprintf (format, args);
418
g_idle_add ((GSourceFunc)liferea_shell_set_status_bar_default_cb, (gpointer)text);
422
liferea_shell_set_important_status_bar (const char *format, ...)
427
g_return_if_fail (format != NULL);
429
va_start (args, format);
430
text = g_strdup_vprintf (format, args);
433
shell->priv->statusbarLocked = FALSE;
434
if (shell->priv->statusbarLockTimer) {
435
g_source_remove (shell->priv->statusbarLockTimer);
436
shell->priv->statusbarLockTimer = 0;
439
/* URL hover messages are reset with an empty string, so
440
we must locking the status bar on empty strings! */
441
if (!g_str_equal (text, "")) {
442
/* Realize 5s locking for important messages... */
443
shell->priv->statusbarLocked = TRUE;
444
shell->priv->statusbarLockTimer = g_timeout_add_seconds (5, liferea_shell_unlock_status_bar_cb, NULL);
447
g_idle_add ((GSourceFunc)liferea_shell_set_status_bar_important_cb, (gpointer)text);
451
liferea_shell_do_zoom (gboolean in)
453
/* We must apply the zoom either to the item view
454
or to an open tab, depending on the browser tabs
455
GtkNotebook page that is active... */
456
if (!browser_tabs_get_active_htmlview ())
457
itemview_do_zoom (in);
459
browser_tabs_do_zoom (in);
463
on_key_press_event_null_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
469
on_notebook_scroll_event_null_cb (GtkWidget *widget, GdkEventScroll *event)
471
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
474
GtkWidget* originator;
476
if (!notebook->cur_page)
479
child = gtk_notebook_get_nth_page (notebook, gtk_notebook_get_current_page (notebook));
480
originator = gtk_get_event_widget ((GdkEvent *)event);
482
/* ignore scroll events from the content of the page */
483
if (!originator || gtk_widget_is_ancestor (originator, child))
490
on_close (GtkWidget *widget, GdkEvent *event, gpointer user_data)
492
if ((ui_tray_get_count() == 0) || (conf_get_bool_value (DONT_MINIMIZE_TO_TRAY))) {
497
liferea_shell_save_position ();
498
gtk_widget_hide (GTK_WIDGET (shell->priv->window));
504
on_window_state_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
506
if (event->type == GDK_WINDOW_STATE) {
507
GdkWindowState changed = ((GdkEventWindowState*)event)->changed_mask, state = ((GdkEventWindowState*)event)->new_window_state;
509
if (changed == GDK_WINDOW_STATE_MAXIMIZED && !(state & GDK_WINDOW_STATE_WITHDRAWN)) {
510
if (state & GDK_WINDOW_STATE_MAXIMIZED)
511
conf_set_bool_value (LAST_WINDOW_MAXIMIZED, TRUE);
513
conf_set_bool_value (LAST_WINDOW_MAXIMIZED, FALSE);
515
if (state & GDK_WINDOW_STATE_ICONIFIED)
516
session_set_cmd (NULL, MAINWINDOW_ICONIFIED);
517
else if(state & GDK_WINDOW_STATE_WITHDRAWN)
518
session_set_cmd (NULL, MAINWINDOW_HIDDEN);
520
session_set_cmd (NULL, MAINWINDOW_SHOWN);
526
on_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer data)
528
gboolean modifier_matches = FALSE;
529
guint default_modifiers;
533
if (event->type == GDK_KEY_PRESS) {
534
default_modifiers = gtk_accelerator_get_default_mod_mask ();
536
/* handle [<modifier>+]<Space> headline skimming hotkey */
537
switch (event->keyval) {
539
switch (conf_get_int_value (BROWSE_KEY_SETTING)) {
542
modifier_matches = ((event->state & default_modifiers) == 0);
543
/* Hack to make space handled in the module. This is necessary
544
because the HTML widget code must be able to catch spaces
547
By ignoring the space here it will be passed to the HTML
548
widget which in turn will pass it back if it is not eaten by
549
any input field currently focussed. */
552
modifier_matches = ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK);
555
modifier_matches = ((event->state & GDK_MOD1_MASK) == GDK_MOD1_MASK);
559
if (modifier_matches) {
566
/* some <Ctrl> hotkeys that overrule the HTML view */
567
if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
568
switch (event->keyval) {
572
liferea_shell_do_zoom (TRUE);
575
case GDK_KP_Subtract:
577
liferea_shell_do_zoom (FALSE);
583
/* prevent usage of navigation keys in entries */
584
focusw = gtk_window_get_focus (GTK_WINDOW (widget));
585
if (!focusw || GTK_IS_ENTRY (focusw))
588
/* prevent usage of navigation keys in HTML view */
589
type = g_type_name (GTK_WIDGET_TYPE (focusw));
590
if (type && (!strcmp (type, "WebKitWebView")))
593
/* check for treeview navigation */
594
if (0 == (event->state & default_modifiers)) {
595
switch (event->keyval) {
599
if (focusw == GTK_WIDGET (shell->priv->feedlistView))
600
return FALSE; /* to be handled in ui_feedlist_key_press_cb() */
602
on_remove_item_activate (NULL, NULL);
606
on_next_unread_item_activate (NULL, NULL);
610
itemview_move_cursor (1);
614
itemview_move_cursor (-1);
618
ui_common_treeview_move_cursor (shell->priv->feedlistView, -1);
619
itemview_move_cursor_to_first ();
623
ui_common_treeview_move_cursor (shell->priv->feedlistView, 1);
624
itemview_move_cursor_to_first ();
635
liferea_shell_save_accels (gpointer data)
637
gchar *accels_file = NULL;
639
accels_file = g_build_filename (common_get_cache_path (), "accels", NULL);
640
gtk_accel_map_save (accels_file);
641
g_free (accels_file);
646
on_accel_change (GtkAccelMap *object, gchar *accel_path,
647
guint accel_key, GdkModifierType accel_mode,
650
g_idle_add (liferea_shell_save_accels, NULL);
654
on_searchbtn_clicked (GtkButton *button, gpointer user_data)
656
simple_search_dialog_open ();
660
on_onlinebtn_clicked (GtkButton *button, gpointer user_data)
662
network_set_online (!network_is_online ());
666
on_work_offline_activate (GtkToggleAction *menuitem, gpointer user_data)
668
network_set_online (!gtk_toggle_action_get_active (menuitem));
672
on_about_activate (GtkMenuItem *menuitem, gpointer user_data)
676
dialog = liferea_dialog_new (NULL, "aboutdialog");
677
gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (dialog), VERSION);
678
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_hide), NULL);
679
gtk_widget_show (dialog);
683
on_topics_activate (GtkMenuItem *menuitem, gpointer user_data)
685
gchar *filename = g_strdup_printf ("file://" PACKAGE_DATA_DIR "/" PACKAGE "/doc/html/%s", _("topics_en.html"));
686
browser_tabs_add_new (filename, _("Help Topics"), TRUE);
691
on_quick_reference_activate (GtkMenuItem *menuitem, gpointer user_data)
693
gchar *filename = g_strdup_printf ("file://" PACKAGE_DATA_DIR "/" PACKAGE "/doc/html/%s", _("reference_en.html"));
694
browser_tabs_add_new (filename, _("Quick Reference"), TRUE);
699
on_faq_activate (GtkMenuItem *menuitem, gpointer user_data)
701
gchar *filename = g_strdup_printf ("file://" PACKAGE_DATA_DIR "/" PACKAGE "/doc/html/%s", _("faq_en.html"));
702
browser_tabs_add_new (filename, _("FAQ"), TRUE);
707
on_menu_quit (GtkMenuItem *menuitem, gpointer user_data)
713
on_menu_zoomin_selected (gpointer callback_data, guint callback_action, GtkWidget *widget)
715
liferea_shell_do_zoom (TRUE);
719
on_menu_zoomout_selected (gpointer callback_data, guint callback_action, GtkWidget *widget)
721
liferea_shell_do_zoom (FALSE);
725
on_menu_import (gpointer callback_data, guint callback_action, GtkWidget *widget)
731
on_menu_export (gpointer callback_data, guint callback_action, GtkWidget *widget)
736
// FIXME: change to signal callback
738
liferea_shell_online_status_changed (int online)
743
return; // FIXME: this check shouldn't be necessary
745
widget = liferea_shell_lookup ("onlineimage");
748
liferea_shell_set_status_bar (_("Liferea is now online"));
749
gtk_image_set_from_pixbuf (GTK_IMAGE (widget), icons[ICON_ONLINE]);
750
atk_object_set_name (gtk_widget_get_accessible (widget), _("Work Offline"));
752
liferea_shell_set_status_bar (_("Liferea is now offline"));
753
gtk_image_set_from_pixbuf (GTK_IMAGE (widget), icons[ICON_OFFLINE]);
754
atk_object_set_name (gtk_widget_get_accessible (widget), _("Work Online"));
756
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (gtk_action_group_get_action (shell->priv->generalActions, "ToggleOfflineMode")), !online);
758
/* Propagate new online status to other interested widgets */
759
// FIXME: bad design, HTML view implementation needs to register for network events itself
760
liferea_htmlview_set_online (online);
764
/* methods to receive URLs which were dropped anywhere in the main window */
766
liferea_shell_URL_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time)
768
gchar *tmp1, *tmp2, *freeme;
769
GtkWidget *mainwindow;
771
GtkTreeView *treeview;
778
g_return_if_fail (data->data != NULL);
780
mainwindow = GTK_WIDGET (liferea_shell_lookup ("mainwindow"));
781
treeview = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
782
model = gtk_tree_view_get_model (treeview);
784
/* Allow link drops only over feed list widget. This is to avoid
785
the frequent accidental text drops in the HTML view. */
787
gtk_widget_get_allocation(GTK_WIDGET(treeview), &alloc);
789
if((x > alloc.x+alloc.width) || (x < alloc.x) ||
790
(y > alloc.y+alloc.height) || (y < alloc.y)) {
791
gtk_drag_finish (context, FALSE, FALSE, time);
795
/* x and y are relative to the main window, make them relative to the treeview */
796
g_assert (gtk_widget_translate_coordinates (mainwindow, GTK_WIDGET (treeview), x, y, &tx, &ty));
798
if ((data->length >= 0) && (data->format == 8)) {
799
/* extra handling to accept multiple drops */
800
freeme = tmp1 = g_strdup (data->data);
801
while ((tmp2 = strsep (&tmp1, "\n\r"))) {
803
/* if the drop is over a node, select it so that feedlist_add_subscription()
804
* adds it in the correct folder */
805
if (gtk_tree_view_get_dest_row_at_pos (treeview, tx, ty, &path, NULL)) {
806
if (gtk_tree_model_get_iter (model, &iter, path)) {
807
gtk_tree_model_get (model, &iter, FS_PTR, &node, -1);
808
/* if node is NULL, ui_feedlist_select() will unselect the tv */
809
ui_feedlist_select (node);
811
gtk_tree_path_free (path);
813
feedlist_add_subscription (g_strdup (tmp2), NULL, NULL,
814
FEED_REQ_RESET_TITLE |
815
FEED_REQ_PRIORITY_HIGH);
819
gtk_drag_finish (context, TRUE, FALSE, time);
821
gtk_drag_finish (context, FALSE, FALSE, time);
826
liferea_shell_setup_URL_receiver (GtkWidget *widget)
828
GtkTargetEntry target_table[] = {
830
{ "text/plain", 0, 0 },
831
{ "text/uri-list", 0, 1 },
832
{ "_NETSCAPE_URL", 0, 1 },
833
{ "application/x-rootwin-drop", 0, 2 }
836
/* doesn't work with GTK_DEST_DEFAULT_DROP... */
837
gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL,
838
target_table, sizeof (target_table)/sizeof (target_table[0]),
839
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
841
g_signal_connect (G_OBJECT (widget), "drag_data_received",
842
G_CALLBACK (liferea_shell_URL_received), NULL);
845
static const GtkActionEntry ui_mainwindow_action_entries[] = {
846
{"SubscriptionsMenu", NULL, N_("_Subscriptions")},
847
{"UpdateAll", "gtk-refresh", N_("Update _All"), "<control>U", N_("Updates all subscriptions."),
848
G_CALLBACK(on_menu_update_all)},
849
{"MarkAllFeedsAsRead", "gtk-apply", N_("Mark All As _Read"), NULL, N_("Marks read every item of every subscription."),
850
G_CALLBACK(on_menu_allfeedsread)},
851
{"ImportFeedList", "gtk-open", N_("_Import Feed List..."), NULL, N_("Imports an OPML feed list."), G_CALLBACK(on_menu_import)},
852
{"ExportFeedList", "gtk-save-as", N_("_Export Feed List..."), NULL, N_("Exports the feed list as OPML."), G_CALLBACK(on_menu_export)},
853
{"Quit",GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", NULL, G_CALLBACK(on_menu_quit)},
855
{"FeedMenu", NULL, N_("_Feed")},
856
{"RemoveAllItems", "gtk-delete", N_("Remove _All Items"), NULL, N_("Removes all items of the currently selected feed."),
857
G_CALLBACK(on_remove_items_activate)},
859
{"ItemMenu", NULL, N_("_Item")},
860
{"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."),
861
G_CALLBACK(on_next_unread_item_activate)},
863
{"ViewMenu", NULL, N_("_View")},
864
{"ZoomIn", "gtk-zoom-in", N_("_Increase Text Size"), "<control>plus", N_("Increases the text size of the item view."),
865
G_CALLBACK(on_menu_zoomin_selected)},
866
{"ZoomOut", "gtk-zoom-out", N_("_Decrease Text Size"), "<control>minus", N_("Decreases the text size of the item view."),
867
G_CALLBACK(on_menu_zoomout_selected)},
869
{"ToolsMenu", NULL, N_("_Tools")},
870
{"ShowUpdateMonitor", NULL, N_("_Update Monitor"), NULL, N_("Show a list of all feeds currently in the update queue"),
871
G_CALLBACK(on_menu_show_update_monitor)},
872
{"ShowScriptManager", NULL, N_("_Script Manager"), NULL, N_("Allows to configure and edit LUA hook scripts"),
873
G_CALLBACK(on_menu_show_script_manager)},
874
{"ShowPreferences", GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, N_("Edit Preferences."),
875
G_CALLBACK(on_prefbtn_clicked)},
877
{"SearchMenu", NULL, N_("S_earch")},
878
{"SearchFeeds", "gtk-find", N_("Search All Feeds..."), "<control>F", N_("Show the search dialog."), G_CALLBACK(on_searchbtn_clicked)},
879
{"CreateEngineSearch", NULL, N_("Search With ...")},
881
{"HelpMenu", NULL, N_("_Help")},
882
{"ShowHelpContents", "gtk-help", N_("_Contents"), "F1", N_("View help for this application."), G_CALLBACK(on_topics_activate)},
883
{"ShowHelpQuickReference", NULL, N_("_Quick Reference"), NULL, N_("View a list of all Liferea shortcuts."),
884
G_CALLBACK(on_quick_reference_activate)},
885
{"ShowHelpFAQ", NULL, N_("_FAQ"), NULL, N_("View the FAQ for this application."), G_CALLBACK(on_faq_activate)},
886
{"ShowAbout", "gtk-about", N_("_About"), NULL, N_("Shows an about dialog."), G_CALLBACK(on_about_activate)}
889
static const GtkRadioActionEntry ui_mainwindow_view_radio_entries[] = {
890
{"NormalView", NULL, N_("_Normal View"), NULL, N_("Set view mode to mail client mode."),
892
{"WideView", NULL, N_("_Wide View"), NULL, N_("Set view mode to use three vertical panes."),
894
{"CombinedView", NULL, N_("_Combined View"), NULL, N_("Set view mode to two pane mode."),
898
static GtkToggleActionEntry ui_mainwindow_feedlist_toggle_entries[] = {
899
{"ReducedFeedList", NULL, N_("_Reduced Feed List"), NULL, N_("Hide feeds with no unread items."),
900
G_CALLBACK(on_feedlist_reduced_activate)}
903
static const GtkActionEntry ui_mainwindow_add_action_entries[] = {
904
{"NewSubscription", "gtk-add", N_("_New Subscription..."), NULL, N_("Adds a subscription to the feed list."),
905
G_CALLBACK(on_menu_feed_new)},
906
{"NewFolder", NULL, N_("New _Folder..."), NULL, N_("Adds a folder to the feed list."), G_CALLBACK(on_menu_folder_new)},
907
{"NewVFolder", NULL, N_("New S_earch Folder..."), NULL, N_("Adds a new search folder to the feed list."), G_CALLBACK(on_new_vfolder_activate)},
908
{"NewSource", NULL, N_("New _Source..."), NULL, N_("Adds a new feed list source."), G_CALLBACK(on_new_plugin_activate)},
909
{"NewNewsBin", NULL, N_("New _News Bin..."), NULL, N_("Adds a new news bin."), G_CALLBACK(on_new_newsbin_activate)}
912
static const GtkActionEntry ui_mainwindow_feed_action_entries[] = {
913
{"MarkFeedAsRead", "gtk-apply", N_("_Mark Items Read"), "<control>R", N_("Marks all items of the selected feed list node / in the item list as read."),
914
G_CALLBACK(on_menu_allread)},
915
{"UpdateSelected", "gtk-refresh", N_("_Update"), NULL, N_("Updates the selected subscription or all subscriptions of the selected folder."),
916
G_CALLBACK(on_menu_update)}
919
static const GtkActionEntry ui_mainwindow_read_write_action_entries[] = {
920
{"Properties", "gtk-properties", N_("_Properties"), NULL, N_("Opens the property dialog for the selected subscription."), G_CALLBACK(on_menu_properties)},
921
{"DeleteSelected", "gtk-delete", N_("_Remove"), NULL, N_("Removes the selected subscription."), G_CALLBACK(on_menu_delete)}
924
static const GtkActionEntry ui_mainwindow_item_action_entries[] = {
925
{"ToggleItemReadStatus", "gtk-apply", N_("Toggle _Read Status"), "<control>M", N_("Toggles the read status of the selected item."),
926
G_CALLBACK(on_toggle_unread_status)},
927
{"ToggleItemFlag", NULL, N_("Toggle Item _Flag"), "<control>T", N_("Toggles the flag status of the selected item."),
928
G_CALLBACK(on_toggle_item_flag)},
929
{"RemoveSelectedItem", "gtk-delete", N_("R_emove"), NULL, N_("Removes the selected item."),
930
G_CALLBACK(on_remove_item_activate)},
931
{"LaunchItemInBrowser", NULL, N_("_Launch In Browser"), NULL, N_("Launches the item's link in the configured browser."),
932
G_CALLBACK(on_popup_launchitem_selected)}
935
static const GtkToggleActionEntry ui_mainwindow_action_toggle_entries[] = {
936
{"ToggleOfflineMode", NULL, N_("_Work Offline"), NULL, N_("This option allows you to disable subscription updating."),
937
G_CALLBACK(on_work_offline_activate)}
940
static const char *ui_mainwindow_ui_desc =
942
" <menubar name='MainwindowMenubar'>"
943
" <menu action='SubscriptionsMenu'>"
944
" <menuitem action='UpdateAll'/>"
945
" <menuitem action='MarkAllFeedsAsRead'/>"
947
" <menuitem action='NewSubscription'/>"
948
" <menuitem action='NewFolder'/>"
949
" <menuitem action='NewVFolder'/>"
950
" <menuitem action='NewSource'/>"
951
" <menuitem action='NewNewsBin'/>"
953
" <menuitem action='ImportFeedList'/>"
954
" <menuitem action='ExportFeedList'/>"
956
" <menuitem action='ToggleOfflineMode'/>"
958
" <menuitem action='Quit'/>"
960
" <menu action='FeedMenu'>"
961
" <menuitem action='UpdateSelected'/>"
962
" <menuitem action='MarkFeedAsRead'/>"
964
" <menuitem action='RemoveAllItems'/>"
965
" <menuitem action='DeleteSelected'/>"
967
" <menuitem action='Properties'/>"
969
" <menu action='ItemMenu'>"
970
" <menuitem action='NextUnreadItem'/>"
972
" <menuitem action='ToggleItemReadStatus'/>"
973
" <menuitem action='ToggleItemFlag'/>"
974
" <menuitem action='RemoveSelectedItem'/>"
976
" <menuitem action='LaunchItemInBrowser'/>"
978
" <menu action='ViewMenu'>"
979
" <menuitem action='ZoomIn'/>"
980
" <menuitem action='ZoomOut'/>"
982
" <menuitem action='NormalView'/>"
983
" <menuitem action='WideView'/>"
984
" <menuitem action='CombinedView'/>"
986
" <menuitem action='ReducedFeedList'/>"
988
" <menu action='ToolsMenu'>"
989
" <menuitem action='ShowUpdateMonitor'/>"
990
" <menuitem action='ShowScriptManager'/>"
991
" <menuitem action='ShowPreferences'/>"
993
" <menu action='SearchMenu'>"
994
" <menuitem action='SearchFeeds'/>"
995
" <menu action='CreateEngineSearch'/>"
997
" <menu action='HelpMenu'>"
998
" <menuitem action='ShowHelpContents'/>"
999
" <menuitem action='ShowHelpQuickReference'/>"
1000
" <menuitem action='ShowHelpFAQ'/>"
1002
" <menuitem action='ShowAbout'/>"
1005
" <toolbar action='maintoolbar'>"
1007
" <toolitem name='newFeedButton' action='NewSubscription'/>"
1008
" <toolitem name='nextUnreadButton' action='NextUnreadItem'/>"
1009
" <toolitem name='MarkAsReadButton' action='MarkFeedAsRead'/>"
1010
" <toolitem name='UpdateAllButton' action='UpdateAll'/>"
1011
" <toolitem name='SearchButton' action='SearchFeeds'/>"
1017
liferea_shell_get_theme_icon (GtkIconTheme *icon_theme, const gchar *name, gint size)
1019
GError *error = NULL;
1022
pixbuf = gtk_icon_theme_load_icon (icon_theme,
1023
name, /* icon name */
1028
debug1(DEBUG_GUI, "Couldn't load icon: %s", error->message);
1029
g_error_free (error);
1035
liferea_shell_restore_state (void)
1037
gchar *toolbar_style, *accels_file;
1039
debug0 (DEBUG_GUI, "Setting toolbar style");
1041
toolbar_style = conf_get_toolbar_style ();
1042
liferea_shell_set_toolbar_style (toolbar_style);
1043
g_free (toolbar_style);
1045
debug0 (DEBUG_GUI, "Loading accelerators");
1047
accels_file = g_build_filename (common_get_cache_path(), "accels", NULL);
1048
gtk_accel_map_load (accels_file);
1049
g_free (accels_file);
1051
debug0 (DEBUG_GUI, "Restoring window position");
1053
liferea_shell_restore_position ();
1055
debug0 (DEBUG_GUI, "Loading pane proportions");
1057
if (0 != conf_get_int_value (LAST_VPANE_POS))
1058
gtk_paned_set_position (GTK_PANED (liferea_shell_lookup ("leftpane")), conf_get_int_value (LAST_VPANE_POS));
1059
if (0 != conf_get_int_value (LAST_HPANE_POS))
1060
gtk_paned_set_position (GTK_PANED (liferea_shell_lookup ("normalViewPane")), conf_get_int_value (LAST_HPANE_POS));
1061
if (0 != conf_get_int_value (LAST_WPANE_POS))
1062
gtk_paned_set_position (GTK_PANED (liferea_shell_lookup ("wideViewPane")), conf_get_int_value (LAST_WPANE_POS));
1066
liferea_shell_create (int initialState)
1068
GtkUIManager *ui_manager;
1069
GtkAccelGroup *accel_group;
1070
GError *error = NULL;
1074
GtkIconTheme *icon_theme;
1076
debug_enter ("liferea_shell_create");
1078
/* 1.) object setup */
1080
g_object_new (LIFEREA_SHELL_TYPE, NULL);
1082
shell->priv->window = GTK_WINDOW (liferea_shell_lookup ("mainwindow"));
1084
// FIXME: do we use this anywhere?
1085
gtk_widget_set_name (liferea_shell_lookup ("feedlist"), "feedlist");
1087
/* 2.) menu creation */
1089
debug0 (DEBUG_GUI, "Setting up menues");
1091
/* Prepare some toggle button states */
1092
ui_mainwindow_feedlist_toggle_entries[0].is_active = conf_get_bool_value (REDUCED_FEEDLIST);
1094
ui_manager = gtk_ui_manager_new ();
1096
shell->priv->generalActions = gtk_action_group_new ("GeneralActions");
1097
gtk_action_group_set_translation_domain (shell->priv->generalActions, PACKAGE);
1098
gtk_action_group_add_actions (shell->priv->generalActions, ui_mainwindow_action_entries, G_N_ELEMENTS (ui_mainwindow_action_entries), shell->priv);
1099
gtk_action_group_add_toggle_actions (shell->priv->generalActions, ui_mainwindow_action_toggle_entries, G_N_ELEMENTS (ui_mainwindow_action_toggle_entries), shell->priv);
1100
gtk_action_group_add_radio_actions (shell->priv->generalActions, ui_mainwindow_view_radio_entries, G_N_ELEMENTS (ui_mainwindow_view_radio_entries), itemlist_get_view_mode (), (GCallback)on_view_activate, (gpointer)TRUE);
1101
gtk_action_group_add_toggle_actions (shell->priv->generalActions, ui_mainwindow_feedlist_toggle_entries, G_N_ELEMENTS (ui_mainwindow_feedlist_toggle_entries), shell->priv);
1102
gtk_ui_manager_insert_action_group (ui_manager, shell->priv->generalActions, 0);
1104
shell->priv->addActions = gtk_action_group_new ("AddActions");
1105
gtk_action_group_set_translation_domain (shell->priv->addActions, PACKAGE);
1106
gtk_action_group_add_actions (shell->priv->addActions, ui_mainwindow_add_action_entries, G_N_ELEMENTS (ui_mainwindow_add_action_entries), shell->priv);
1107
gtk_ui_manager_insert_action_group (ui_manager, shell->priv->addActions, 0);
1109
shell->priv->feedActions = gtk_action_group_new ("FeedActions");
1110
gtk_action_group_set_translation_domain (shell->priv->feedActions, PACKAGE);
1111
gtk_action_group_add_actions (shell->priv->feedActions, ui_mainwindow_feed_action_entries, G_N_ELEMENTS (ui_mainwindow_feed_action_entries), shell->priv);
1112
gtk_ui_manager_insert_action_group (ui_manager, shell->priv->feedActions, 0);
1114
shell->priv->readWriteActions = gtk_action_group_new("ReadWriteActions");
1115
gtk_action_group_set_translation_domain (shell->priv->readWriteActions, PACKAGE);
1116
gtk_action_group_add_actions (shell->priv->readWriteActions, ui_mainwindow_read_write_action_entries, G_N_ELEMENTS (ui_mainwindow_read_write_action_entries), shell->priv);
1117
gtk_ui_manager_insert_action_group (ui_manager, shell->priv->readWriteActions, 0);
1119
shell->priv->itemActions = gtk_action_group_new ("ItemActions");
1120
gtk_action_group_set_translation_domain (shell->priv->itemActions, PACKAGE);
1121
gtk_action_group_add_actions (shell->priv->itemActions, ui_mainwindow_item_action_entries, G_N_ELEMENTS (ui_mainwindow_item_action_entries), shell->priv);
1122
gtk_ui_manager_insert_action_group (ui_manager, shell->priv->itemActions, 0);
1124
accel_group = gtk_ui_manager_get_accel_group (ui_manager);
1125
gtk_window_add_accel_group (GTK_WINDOW (shell->priv->window), accel_group);
1126
g_object_unref (accel_group);
1128
g_signal_connect (gtk_accel_map_get (), "changed", G_CALLBACK (on_accel_change), NULL);
1130
if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_mainwindow_ui_desc, -1, &error))
1131
g_error ("building menus failed: %s", error->message);
1133
ui_search_engines_setup_menu (ui_manager);
1135
shell->priv->menubar = gtk_ui_manager_get_widget (ui_manager, "/MainwindowMenubar");
1136
shell->priv->toolbar = gtk_ui_manager_get_widget (ui_manager, "/maintoolbar");
1138
/* what a pain, why is there no markup for this option? */
1139
g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/newFeedButton")), "is_important", TRUE, NULL);
1140
g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/nextUnreadButton")), "is_important", TRUE, NULL);
1141
g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/MarkAsReadButton")), "is_important", TRUE, NULL);
1142
g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/UpdateAllButton")), "is_important", TRUE, NULL);
1143
g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/SearchButton")), "is_important", TRUE, NULL);
1145
/* 2.) setup containers */
1147
debug0 (DEBUG_GUI, "Setting up widget containers");
1149
gtk_box_pack_start (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->toolbar, FALSE, FALSE, 0);
1150
gtk_box_reorder_child (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->toolbar, 0);
1151
gtk_box_pack_start (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->menubar, FALSE, FALSE, 0);
1152
gtk_box_reorder_child (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->menubar, 0);
1154
gtk_widget_show_all(GTK_WIDGET(shell->priv->toolbar));
1156
g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "key_press_event",
1157
G_CALLBACK (on_key_press_event_null_cb), NULL);
1159
g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "key_release_event",
1160
G_CALLBACK (on_key_press_event_null_cb), NULL);
1162
g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "scroll_event",
1163
G_CALLBACK (on_notebook_scroll_event_null_cb), NULL);
1165
g_signal_connect (G_OBJECT (shell->priv->window), "delete_event", G_CALLBACK(on_close), shell->priv);
1166
g_signal_connect (G_OBJECT (shell->priv->window), "window_state_event", G_CALLBACK(on_window_state_event), shell->priv);
1167
g_signal_connect (G_OBJECT (shell->priv->window), "key_press_event", G_CALLBACK(on_key_press_event), shell->priv);
1169
/* 3.) setup status bar */
1171
debug0 (DEBUG_GUI, "Setting up status bar");
1173
shell->priv->statusbar = GTK_STATUSBAR (liferea_shell_lookup ("statusbar"));
1174
shell->priv->statusbarLocked = FALSE;
1175
shell->priv->statusbarLockTimer = 0;
1176
shell->priv->statusbar_feedsinfo = gtk_label_new("");
1177
gtk_widget_show(shell->priv->statusbar_feedsinfo);
1178
gtk_box_pack_start (GTK_BOX (shell->priv->statusbar), shell->priv->statusbar_feedsinfo, FALSE, FALSE, 5);
1180
/* 4.) setup tabs */
1182
debug0 (DEBUG_GUI, "Setting up tabbed browsing");
1183
shell->priv->tabs = browser_tabs_create (GTK_NOTEBOOK (liferea_shell_lookup ("browsertabs")));
1185
/* 5.) setup feed list */
1187
debug0 (DEBUG_GUI, "Setting up feed list");
1188
shell->priv->feedlistView = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
1189
ui_feedlist_init (shell->priv->feedlistView);
1191
/* 6.) setup menu sensivity */
1193
debug0 (DEBUG_GUI, "Initialising menues");
1195
/* On start, no item or feed is selected, so Item menu should be insensitive: */
1196
liferea_shell_update_item_menu (FALSE);
1198
/* necessary to prevent selection signals when filling the feed list
1199
and setting the 2/3 pane mode view */
1200
gtk_widget_set_sensitive (GTK_WIDGET (shell->priv->feedlistView), FALSE);
1202
/* 7.) setup item view */
1204
debug0 (DEBUG_GUI, "Setting up item view");
1206
shell->priv->itemview = itemview_create (ui_itemlist_new (GTK_WIDGET (shell->priv->window)));
1208
/* 8.) load icons as required */
1210
debug0 (DEBUG_GUI, "Loading icons");
1212
ui_common_add_pixmap_directory (PACKAGE_DATA_DIR G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "pixmaps");
1214
/* first try to load icons from theme */
1215
static const gchar *iconThemeNames[] = {
1216
NULL, /* ICON_READ */
1217
NULL, /* ICON_UNREAD */
1218
"emblem-important", /* ICON_FLAG */
1219
NULL, /* ICON_AVAILABLE */
1220
NULL, /* ICON_AVAILABLE_OFFLINE */
1221
NULL, /* ICON_UNAVAILABLE */
1222
NULL, /* ICON_DEFAULT */
1223
NULL, /* ICON_FOLDER_EMPTY */
1224
"folder", /* ICON_FOLDER */
1225
"folder-saved-search", /* ICON_VFOLDER */
1226
NULL, /* ICON_NEWSBIN */
1227
NULL, /* ICON_EMPTY */
1228
NULL, /* ICON_EMPTY_OFFLINE */
1229
"gtk-connect", /* ICON_ONLINE */
1230
"gtk-disconnect", /* ICON_OFFLINE */
1231
NULL, /* ICON_UPDATED */
1232
"mail-attachment", /* ICON_ENCLOSURE */
1236
icon_theme = gtk_icon_theme_get_default ();
1237
for (i = 0; i < MAX_ICONS; i++)
1238
if (iconThemeNames[i])
1239
icons[i] = liferea_shell_get_theme_icon (icon_theme, iconThemeNames[i], 16);
1241
/* and then load own default icons */
1242
static const gchar *iconNames[] = {
1243
"read.xpm", /* ICON_READ */
1244
"unread.png", /* ICON_UNREAD */
1245
"flag.png", /* ICON_FLAG */
1246
"available.png", /* ICON_AVAILABLE */
1247
"available_offline.png", /* ICON_AVAILABLE_OFFLINE */
1248
NULL, /* ICON_UNAVAILABLE */
1249
"default.png", /* ICON_DEFAULT */
1250
"folder_empty.png", /* ICON_FOLDER_EMPTY */
1251
"directory.png", /* ICON_FOLDER */
1252
"vfolder.png", /* ICON_VFOLDER */
1253
"newsbin.png", /* ICON_NEWSBIN */
1254
"empty.png", /* ICON_EMPTY */
1255
"empty_offline.png", /* ICON_EMPTY_OFFLINE */
1256
"online.png", /* ICON_ONLINE */
1257
"offline.png", /* ICON_OFFLINE */
1258
"edit.png", /* ICON_UPDATED */
1259
"attachment.png", /* ICON_ENCLOSURE */
1263
for (i = 0; i < MAX_ICONS; i++)
1265
icons[i] = ui_common_create_pixbuf (iconNames[i]);
1267
/* set up icons that are build from stock */
1268
widget = gtk_button_new ();
1269
icons[ICON_UNAVAILABLE] = gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_MENU, "");
1270
gtk_widget_destroy (widget);
1272
liferea_shell_update_toolbar ();
1273
liferea_shell_online_status_changed (network_is_online ());
1275
liferea_shell_setup_URL_receiver (GTK_WIDGET (shell->priv->window)); /* setup URL dropping support */
1277
shell->priv->feedlist = feedlist_create ();
1279
ui_tray_enable (conf_get_bool_value (SHOW_TRAY_ICON)); /* init tray icon */
1281
liferea_shell_restore_state ();
1283
if (initialState == MAINWINDOW_ICONIFIED ||
1284
(initialState == MAINWINDOW_HIDDEN && ui_tray_get_count () == 0)) {
1285
gtk_window_iconify (shell->priv->window);
1286
gtk_widget_show (GTK_WIDGET (shell->priv->window));
1287
} else if (initialState == MAINWINDOW_SHOWN) {
1288
gtk_widget_show (GTK_WIDGET (shell->priv->window));
1290
/* Needed so that the window structure can be
1291
accessed... otherwise will GTK warning when window is
1292
shown by clicking on notification icon. */
1293
// gtk_widget_realize (GTK_WIDGET (shell->priv->window));
1294
// Does not work with gtkmozembed...
1296
gtk_widget_show (GTK_WIDGET (shell->priv->window));
1297
gtk_widget_hide (GTK_WIDGET (shell->priv->window));
1300
gtk_widget_set_sensitive (GTK_WIDGET (shell->priv->feedlistView), TRUE);
1302
/* 9. Create welcome text */
1304
/* force two pane mode */
1305
/* For some reason, this causes the first item to be selected and then
1306
unselected... strange. */
1307
ui_feedlist_select (NULL);
1309
itemview_set_layout (NODE_VIEW_MODE_COMBINED);
1311
buffer = g_string_new (NULL);
1312
htmlview_start_output (buffer, NULL, TRUE, FALSE);
1313
g_string_append (buffer, "<div style=\"padding:8px\">"
1314
"<table class=\"headmeta\" style=\"border:solid 1px #aaa;font-size:120%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5px\"><tr><td>"
1315
// Display application icon
1317
PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "icons" G_DIR_SEPARATOR_S
1318
"hicolor" G_DIR_SEPARATOR_S "48x48" G_DIR_SEPARATOR_S "apps"
1319
G_DIR_SEPARATOR_S "liferea.png\" />"
1321
g_string_append (buffer, _("Liferea - Linux Feed Reader"));
1322
g_string_append (buffer, "</h3></td></tr><tr><td colspan=\"2\">");
1323
g_string_append (buffer, _("<p>Welcome to <b>Liferea</b>, a desktop news aggregator for online news "
1325
"<p>The left pane contains the list of your subscriptions. To add a "
1326
"subscription select Feeds -> New Subscription. To browse the headlines "
1327
"of a feed select it in the feed list and the headlines will be loaded "
1328
"into the right pane.</p>"));
1329
g_string_append (buffer, "</td></tr></table>");
1331
g_string_append (buffer, "</div>");
1333
htmlview_finish_output (buffer);
1334
itemview_display_info (buffer->str);
1335
g_string_free (buffer, TRUE);
1337
debug_exit ("liferea_shell_create");
1341
liferea_shell_destroy (void)
1343
ui_feedlist_select (NULL);
1344
liferea_shell_save_position ();
1345
ui_tray_enable (FALSE);
1346
notification_enable (FALSE);
1347
g_object_unref (shell->priv->tabs);
1348
g_object_unref (shell->priv->feedlist);
1350
gtk_widget_destroy (GTK_WIDGET (shell->priv->window));
1354
liferea_shell_present (void)
1356
GtkWidget *mainwindow = GTK_WIDGET (shell->priv->window);
1358
if ((gdk_window_get_state (mainwindow->window) & GDK_WINDOW_STATE_ICONIFIED) || !GTK_WIDGET_VISIBLE (mainwindow))
1359
liferea_shell_restore_position ();
1361
gtk_window_present (shell->priv->window);
1365
liferea_shell_toggle_visibility (void)
1367
GtkWidget *mainwindow = GTK_WIDGET (shell->priv->window);
1369
if(gdk_window_get_state(GTK_WIDGET(mainwindow)->window) & GDK_WINDOW_STATE_ICONIFIED) {
1370
/* The window is either iconified, or on another workspace */
1371
/* Raise it in one click */
1372
if (GTK_WIDGET_VISIBLE(mainwindow)) {
1373
liferea_shell_save_position ();
1374
gtk_widget_hide(mainwindow);
1376
liferea_shell_restore_position();
1377
gtk_window_present(GTK_WINDOW(mainwindow));
1379
else if(!GTK_WIDGET_VISIBLE(mainwindow)) {
1380
/* The window is neither iconified nor on another workspace, but is not visible */
1381
liferea_shell_restore_position ();
1382
gtk_window_present (shell->priv->window);
1384
liferea_shell_save_position ();
1385
gtk_widget_hide (mainwindow);
1390
liferea_shell_get_window (void)
1392
return GTK_WIDGET (shell->priv->window);
1395
void liferea_shell_set_view_mode (nodeViewType newMode)
1397
GtkRadioAction *action;
1399
action = GTK_RADIO_ACTION (gtk_action_group_get_action (shell->priv->generalActions, "NormalView"));
1400
gtk_radio_action_set_current_value (action, newMode);