~ubuntu-installer/ubiquity/trunk

4836 by Evan Dandrea
Add copyright headers
1
/* «panel» - Installer session panel
4123.1.39 by Evan Dandrea
Add an installer session panel.
2
 *
3
 * Copyright (C) 2010 Canonical Ltd.
4
 *
5
 * Authors:
6
 *
7
 * - Evan Dandrea <ev@ubuntu.com>
8
 *
9
 * This file is part of Ubiquity.
10
 *
11
 * Ubiquity is free software; you can redistribute it and/or modify it under
12
 * the terms of the GNU General Public License as published by the Free
13
 * Software Foundation; either version 2 of the License, or at your option)
14
 * any later version.
15
 *
16
 * Ubiquity is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19
 * more details.
20
 *
21
 * You should have received a copy of the GNU General Public License along
22
 * with Ubiquity; if not, write to the Free Software Foundation, Inc., 51
23
 * Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24
 */
4123.1.41 by Evan Dandrea
Actually run the panel in the installer session.
25
/* Mostly stolen from gnome-panel and unity. */
4123.1.39 by Evan Dandrea
Add an installer session panel.
26
#include <gtk/gtk.h>
27
#include <gdk/gdkx.h>
4949 by Evan Dandrea
Port the panel to GTK3.
28
#include <cairo/cairo.h>
4123.1.39 by Evan Dandrea
Add an installer session panel.
29
#include <X11/Xatom.h>
30
#include <X11/Xlib.h>
31
#include <X11/Xutil.h>
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
32
#include <libindicator/indicator-ng.h>
33
#include <libido/libido.h>
4123.1.39 by Evan Dandrea
Add an installer session panel.
34
35
#define ENTRY_DATA_NAME "indicator-custom-entry-data"
36
37
enum {
38
	STRUT_LEFT = 0,
39
	STRUT_RIGHT = 1,
40
	STRUT_TOP = 2,
41
	STRUT_BOTTOM = 3,
42
	STRUT_LEFT_START = 4,
43
	STRUT_LEFT_END = 5,
44
	STRUT_RIGHT_START = 6,
45
	STRUT_RIGHT_END = 7,
46
	STRUT_TOP_START = 8,
47
	STRUT_TOP_END = 9,
48
	STRUT_BOTTOM_START = 10,
49
	STRUT_BOTTOM_END = 11
50
};
51
52
static Atom net_wm_strut              = 0;
53
static Atom net_wm_strut_partial      = 0;
54
55
void
56
set_strut (GtkWindow *gtk_window,
57
                 guint32    left_size,
58
                 guint32    left_start,
59
                 guint32    left_end,
60
                 guint32    top_size,
61
                 guint32    top_start,
62
                 guint32    top_end)
63
{
64
  Display   *display;
65
  Window     window;
66
  GdkWindow *gdk_window;
67
  gulong     struts [12] = { 0, };
68
69
  g_return_if_fail (GTK_IS_WINDOW (gtk_window));
70
71
  if (!left_size)
72
    return;
73
74
  gdk_window = gtk_widget_get_window (GTK_WIDGET (gtk_window));
75
  display = GDK_WINDOW_XDISPLAY (gdk_window);
4949 by Evan Dandrea
Port the panel to GTK3.
76
  window  = GDK_WINDOW_XID (gdk_window);
4123.1.39 by Evan Dandrea
Add an installer session panel.
77
78
  if (net_wm_strut == None)
79
    net_wm_strut = XInternAtom (display, "_NET_WM_STRUT", False);
80
  if (net_wm_strut_partial == None)
81
    net_wm_strut_partial = XInternAtom (display, "_NET_WM_STRUT_PARTIAL",False);
82
83
  struts [STRUT_LEFT] = left_size;
84
  struts [STRUT_LEFT_START] = left_start;
85
  struts [STRUT_LEFT_END] = left_end;
86
87
  struts [STRUT_TOP] = top_size;
88
  struts [STRUT_TOP_START] = top_start;
89
  struts [STRUT_TOP_END] = top_end;
90
91
  gdk_error_trap_push ();
92
  XChangeProperty (display, window, net_wm_strut,
93
                   XA_CARDINAL, 32, PropModeReplace,
94
                   (guchar *) &struts, 4);
95
  XChangeProperty (display, window, net_wm_strut_partial,
96
                   XA_CARDINAL, 32, PropModeReplace,
97
                   (guchar *) &struts, 12);
5178 by Colin Watson
Use gdk_error_trap_pop_ignored rather than gdk_error_trap_pop when
98
  gdk_error_trap_pop_ignored ();
4123.1.39 by Evan Dandrea
Add an installer session panel.
99
}
100
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
101
/* like gtk_menu_shell_insert, but appends/prepends if @position is out
102
 * of range */
103
static void
104
menu_shell_insert (GtkMenuShell *shell,
105
                   GtkWidget    *item,
106
                   gint          position)
107
{
108
    if (position <= 0) {
109
        gtk_menu_shell_prepend (shell, item);
110
    }
111
    else {
112
        GList *children = gtk_container_get_children (GTK_CONTAINER (shell));
113
        if (children) {
114
            if (position < g_list_length (children))
115
                gtk_menu_shell_insert (shell, item, position);
116
            else
117
                gtk_menu_shell_append (shell, item);
118
            g_list_free (children);
119
        }
120
        else
121
            gtk_menu_shell_prepend (shell, item);
122
    }
123
}
124
4123.1.39 by Evan Dandrea
Add an installer session panel.
125
/* Stolen from indicator-loader.c in unity. */
126
static void
127
entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, gpointer user_data)
128
{
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
129
    GtkMenuShell *menubar = user_data;
130
4123.1.39 by Evan Dandrea
Add an installer session panel.
131
    g_debug("Signal: Entry Added");
132
133
    GtkWidget * menuitem = gtk_menu_item_new();
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
134
    g_object_set_data_full (G_OBJECT (menuitem), "indicator object", g_object_ref (io), g_object_unref);
135
5176 by Colin Watson
Convert from deprecated GtkHBox/GtkVBox to GtkBox, and from
136
    GtkWidget * hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
4123.1.39 by Evan Dandrea
Add an installer session panel.
137
138
    if (entry->image != NULL) {
139
        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry->image), FALSE, FALSE, 0);
140
    }
141
    gtk_container_add(GTK_CONTAINER(menuitem), hbox);
142
    gtk_widget_show(hbox);
143
144
    if (entry->menu != NULL) {
145
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), GTK_WIDGET(entry->menu));
146
    }
147
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
148
    gint position = indicator_object_get_position (io);
149
    gint i = -1;
150
151
    if (position > 0) {
152
        i = 0;
153
        GList *items = gtk_container_get_children (GTK_CONTAINER (menubar));
154
        if (items) {
155
            GList *it;
156
            for (it = items; it != NULL; it = it->next, i++) {
157
                IndicatorObject *item_io = g_object_get_data (it->data, "indicator object");
158
                gint item_position = indicator_object_get_position (item_io);
159
                if (position > item_position)
160
                    break;
5312 by Stéphane Graber
Add a indicator_order list to the panel to lock the position of the known ones.
161
            }
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
162
            g_list_free (items);
163
        }
164
    }
165
    menu_shell_insert (menubar, menuitem, i);
5312 by Stéphane Graber
Add a indicator_order list to the panel to lock the position of the known ones.
166
4123.1.39 by Evan Dandrea
Add an installer session panel.
167
    gtk_widget_show(menuitem);
168
169
    g_object_set_data(G_OBJECT(menuitem), ENTRY_DATA_NAME, entry);
170
171
    return;
172
}
173
174
static void
175
entry_removed_cb (GtkWidget * widget, gpointer userdata)
176
{
177
    gpointer data = g_object_get_data(G_OBJECT(widget), ENTRY_DATA_NAME);
178
179
    if (data != userdata) {
180
        return;
181
    }
182
183
    gtk_widget_destroy(widget);
184
    return;
185
}
186
187
static void
188
entry_removed (IndicatorObject * io, IndicatorObjectEntry * entry, gpointer user_data)
189
{
190
    g_debug("Signal: Entry Removed");
191
192
    gtk_container_foreach(GTK_CONTAINER(user_data), entry_removed_cb, entry);
193
194
    return;
195
}
196
197
static gboolean
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
198
load_indicator (IndicatorObject *io, GtkWidget * menu)
4123.1.39 by Evan Dandrea
Add an installer session panel.
199
{
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
200
    g_return_val_if_fail(io != NULL, FALSE);
4123.1.39 by Evan Dandrea
Add an installer session panel.
201
5166 by Colin Watson
typo
202
    /* Connect to its signals */
4123.1.39 by Evan Dandrea
Add an installer session panel.
203
    g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,   G_CALLBACK(entry_added),    menu);
204
    g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(entry_removed),  menu);
205
    /* Work on the entries */
206
    GList * entries = indicator_object_get_entries(io);
207
    GList * entry = NULL;
208
209
    for (entry = entries; entry != NULL; entry = g_list_next(entry)) {
210
        IndicatorObjectEntry * entrydata = (IndicatorObjectEntry *)entry->data;
211
        entry_added(io, entrydata, menu);
212
    }
213
214
    g_list_free(entries);
215
216
    return TRUE;
217
}
218
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
219
static void
220
load_indicator_files (const gchar *directory, GtkWidget *menu)
221
{
222
	GDir *dir;
223
	GError *error = NULL;
224
	const gchar *name;
225
	
226
	dir = g_dir_open (INDICATOR_DIR, 0, &error);
227
	if (dir == NULL) {
228
		g_warning ("unable to open indicator directory: %s", error->message);
229
		g_error_free (error);
230
		return;
231
	}
232
233
	while ((name = g_dir_read_name (dir))) {
234
		gchar *path = g_build_filename (directory, name, NULL);
235
		IndicatorNg *io = indicator_ng_new_for_profile (path, "ubiquity", &error);
236
		if (io) {
237
			load_indicator (INDICATOR_OBJECT (io), menu);
238
		}
239
		else {
240
			g_warning ("unable to load indicator '%s': %s", name, error->message);
241
			g_clear_error (&error);
242
		}
243
		g_free (path);
244
	}
245
246
	g_dir_close (dir);
247
}
248
4123.1.39 by Evan Dandrea
Add an installer session panel.
249
/* At some point subclass GtkWindow instead. */
250
static void
251
on_realize(GtkWidget *win, gpointer data) {
252
	guint width;
253
	GtkAllocation allocation;
254
	gtk_widget_get_allocation(win, &allocation);
255
	width = gdk_screen_width();
256
	gtk_window_set_decorated (GTK_WINDOW (win), FALSE);
257
	set_strut(GTK_WINDOW(win), width, 0, allocation.height, allocation.height, 0, width);
5777.1.2 by Dmitrijs Ledkovs
Make panel screen-wide in compiz with decor plugin.
258
	gtk_widget_set_size_request(GTK_WIDGET (win), width, -1);
4123.1.39 by Evan Dandrea
Add an installer session panel.
259
	// We don't care about showing the panel on all desktops just yet.
4949 by Evan Dandrea
Port the panel to GTK3.
260
	gtk_window_stick (GTK_WINDOW (win));
4123.1.39 by Evan Dandrea
Add an installer session panel.
261
	gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
4949 by Evan Dandrea
Port the panel to GTK3.
262
	gdk_window_set_geometry_hints (gtk_widget_get_window(win), NULL, GDK_HINT_POS);
263
	gdk_window_move_resize(gtk_widget_get_window(win), 0, 0, width, allocation.height);
4497 by Evan Dandrea
Don't show a resize grip on the panel.
264
	gtk_window_set_has_resize_grip(GTK_WINDOW(win), FALSE);
4123.1.39 by Evan Dandrea
Add an installer session panel.
265
}
266
5828 by Dmitrijs Ledkovs
Make panel.c aware of screen & display changes, prevents visual
267
static void
268
on_screen_change (GdkScreen *screen, GtkWidget *win) {
269
	on_realize(win, NULL);
270
}
271
4123.1.55 by Evan Dandrea
Make the panel 22px tall.
272
static void
4949 by Evan Dandrea
Port the panel to GTK3.
273
draw_child (GtkWidget *child, gpointer client_data) {
274
	struct {
275
		GtkWidget *container;
276
		cairo_t *cr;
277
	} *data = client_data;
278
	
279
	gtk_container_propagate_draw (GTK_CONTAINER (data->container), child, data->cr);
280
}
281
282
static gint
283
on_draw(GtkWidget *widget, cairo_t *cr, gpointer userdata) {
4123.1.55 by Evan Dandrea
Make the panel 22px tall.
284
	GdkPixbuf *pixbuf;
4285 by Evan Dandrea
Update the panel to use the new location for the panel background,
285
	pixbuf = gdk_pixbuf_new_from_file("/usr/share/themes/Ambiance/gtk-2.0/apps/img/panel.png", NULL);
4449.1.4 by Julien Lavergne
Merge upstream.
286
	if (!pixbuf) {
4449.1.3 by Julien Lavergne
Merge upstream.
287
		pixbuf = gdk_pixbuf_new_from_file("/usr/share/lxpanel/images/lubuntu-background.png", NULL);
288
	}
5381 by Colin Watson
Copy the panel gradient from light-themes 0.1.8.25 (Ubuntu 11.10) and
289
	if (!pixbuf) {
6243.2.1 by Simon Steinbeiß
Add support for Xubuntu's panel background
290
		pixbuf = gdk_pixbuf_new_from_file("/usr/share/themes/Greybird/ubiquity-panel-bg.png", NULL);
291
	}
292
	if (!pixbuf) {
6513.2.1 by David Mohammed
fix window decorations and background for Ubuntu Budgie, switch to ubiquity-panel
293
		pixbuf = gdk_pixbuf_new_from_file("/usr/share/budgie-desktop/ubiquity-panel-bg.png", NULL);
294
	}
295
	if (!pixbuf) {
5381 by Colin Watson
Copy the panel gradient from light-themes 0.1.8.25 (Ubuntu 11.10) and
296
		pixbuf = gdk_pixbuf_new_from_file("/usr/share/ubiquity/pixmaps/panel.png", NULL);
297
	}
4449.1.3 by Julien Lavergne
Merge upstream.
298
	if (pixbuf) {
4949 by Evan Dandrea
Port the panel to GTK3.
299
		gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
6509 by Mathieu Trudel-Lapierre
Set extend property for the panel to CAIRO_EXTEND_PAD rather than REPEAT,
300
		cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD);
4949 by Evan Dandrea
Port the panel to GTK3.
301
		cairo_paint(cr);
5177 by Colin Watson
Use g_object_unref instead of deprecated gdk_pixbuf_unref.
302
		g_object_unref(pixbuf);
4123.1.55 by Evan Dandrea
Make the panel 22px tall.
303
	} else {
304
		g_warning("Could not find background image.");
305
	}
4949 by Evan Dandrea
Port the panel to GTK3.
306
	struct {
307
		GtkWidget *container;
308
		cairo_t *cr;
309
	} data;
310
	data.container = widget;
311
	data.cr = cr;
312
	gtk_container_forall (GTK_CONTAINER(widget), draw_child, &data);
4123.1.55 by Evan Dandrea
Make the panel 22px tall.
313
	return FALSE;
314
}
4123.1.39 by Evan Dandrea
Add an installer session panel.
315
316
int
317
main(int argc, char* argv[]) {
318
	GtkWidget *win;
5289 by Stéphane Graber
panel: Fix the gtk3 css code so that it actually applies and remove .menuitem's padding.
319
	GtkCssProvider *cssprovider;
5828 by Dmitrijs Ledkovs
Make panel.c aware of screen & display changes, prevents visual
320
	GdkScreen *screen;
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
321
	GError *error;
5289 by Stéphane Graber
panel: Fix the gtk3 css code so that it actually applies and remove .menuitem's padding.
322
4948 by Evan Dandrea
Unset UBUNTU_MENUPROXY so our custom panel doesn't lose its
323
	/* Disable global menus */
324
	g_unsetenv ("UBUNTU_MENUPROXY");
4123.1.39 by Evan Dandrea
Add an installer session panel.
325
	gtk_init(&argc, &argv);
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
326
	ido_init ();
5828 by Dmitrijs Ledkovs
Make panel.c aware of screen & display changes, prevents visual
327
	screen = gdk_screen_get_default();
4123.1.39 by Evan Dandrea
Add an installer session panel.
328
	win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6002.2.1 by Lars Uebernickel
Force panel to 28 pixels height
329
	gtk_window_set_default_size (GTK_WINDOW (win), -1, 28);
4123.1.39 by Evan Dandrea
Add an installer session panel.
330
	g_signal_connect(win, "realize", G_CALLBACK(on_realize), NULL);
5828 by Dmitrijs Ledkovs
Make panel.c aware of screen & display changes, prevents visual
331
	g_signal_connect(screen, "monitors-changed", G_CALLBACK(on_screen_change), win);
332
	g_signal_connect(screen, "size-changed", G_CALLBACK(on_screen_change), win);
4123.1.39 by Evan Dandrea
Add an installer session panel.
333
5289 by Stéphane Graber
panel: Fix the gtk3 css code so that it actually applies and remove .menuitem's padding.
334
	cssprovider = gtk_css_provider_new ();
335
	gtk_css_provider_load_from_data(cssprovider,
4949 by Evan Dandrea
Port the panel to GTK3.
336
			"GtkMenuBar {\n"
5289 by Stéphane Graber
panel: Fix the gtk3 css code so that it actually applies and remove .menuitem's padding.
337
			"    -GtkMenuBar-internal-padding: 0;\n"
338
			"    -GtkMenuBar-shadow-type: none;\n"
339
			"}\n"
340
			"GtkWidget {\n"
341
			"    -GtkWidget-focus-line-width: 0;\n"
342
			"    -GtkWidget-focus-padding: 0;\n"
343
			"}\n", -1, NULL);
344
5828 by Dmitrijs Ledkovs
Make panel.c aware of screen & display changes, prevents visual
345
	gtk_style_context_add_provider_for_screen(screen,
5289 by Stéphane Graber
panel: Fix the gtk3 css code so that it actually applies and remove .menuitem's padding.
346
		GTK_STYLE_PROVIDER (cssprovider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
4123.1.55 by Evan Dandrea
Make the panel 22px tall.
347
4123.1.39 by Evan Dandrea
Add an installer session panel.
348
	GtkWidget* menubar = gtk_menu_bar_new();
5966.1.1 by Lars Uebernickel
panel.c: port to new indicator architecture
349
350
	load_indicator_files (INDICATOR_DIR, menubar);
351
	IndicatorObject * io = indicator_object_new_from_file("/usr/lib/indicators3/7/libapplication.so");
352
	load_indicator(io, menubar);
353
5176 by Colin Watson
Convert from deprecated GtkHBox/GtkVBox to GtkBox, and from
354
	GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
4298 by Evan Dandrea
Add notification area support in the panel.
355
	gtk_container_add(GTK_CONTAINER(win), hbox);
4949 by Evan Dandrea
Port the panel to GTK3.
356
	gtk_box_pack_end(GTK_BOX(hbox), menubar, FALSE, FALSE, 0);
357
	g_signal_connect_after(menubar, "draw", G_CALLBACK(on_draw), NULL);
358
	g_signal_connect(win, "draw", G_CALLBACK(on_draw), NULL);
359
	gtk_widget_show_all(win);
360
	gdk_window_process_updates(gtk_widget_get_window(win), TRUE);
4298 by Evan Dandrea
Add notification area support in the panel.
361
	gtk_widget_set_app_paintable(win, TRUE);
4123.1.39 by Evan Dandrea
Add an installer session panel.
362
	gtk_main();
363
	return 0;
364
}