From c51ef797a707f4e2c6f9688d4378f2b0e9898a66 Mon Sep 17 00:00:00 2001 From: Perberos Date: Thu, 1 Dec 2011 22:56:10 -0300 Subject: moving from https://github.com/perberos/mate-desktop-environment --- mate-panel/Makefile.am | 290 ++ mate-panel/Makefile.in | 2222 ++++++++ mate-panel/applet.c | 1449 ++++++ mate-panel/applet.h | 119 + mate-panel/button-widget.c | 902 ++++ mate-panel/button-widget.h | 60 + mate-panel/drawer.c | 806 +++ mate-panel/drawer.h | 52 + mate-panel/launcher.c | 1114 ++++ mate-panel/launcher.h | 80 + mate-panel/libegg/Makefile.am | 25 + mate-panel/libegg/Makefile.in | 622 +++ mate-panel/libegg/eggdesktopfile.c | 1510 ++++++ mate-panel/libegg/eggdesktopfile.h | 164 + mate-panel/libegg/eggsmclient-private.h | 57 + mate-panel/libegg/eggsmclient-xsmp.c | 1370 +++++ mate-panel/libegg/eggsmclient.c | 604 +++ mate-panel/libegg/eggsmclient.h | 121 + .../libmate-panel-applet-private/Makefile.am | 34 + .../libmate-panel-applet-private/Makefile.in | 644 +++ .../mate-panel-applet-container.c | 790 +++ .../mate-panel-applet-container.h | 118 + .../mate-panel-applet-frame-dbus.c | 468 ++ .../mate-panel-applet-frame-dbus.h | 65 + .../mate-panel-applet-mini.c | 5 + .../mate-panel-applets-manager-dbus.c | 604 +++ .../mate-panel-applets-manager-dbus.h | 60 + mate-panel/libpanel-util/Makefile.am | 39 + mate-panel/libpanel-util/Makefile.in | 647 +++ mate-panel/libpanel-util/panel-cleanup.c | 110 + mate-panel/libpanel-util/panel-cleanup.h | 51 + mate-panel/libpanel-util/panel-dbus-service.c | 307 ++ mate-panel/libpanel-util/panel-dbus-service.h | 78 + mate-panel/libpanel-util/panel-error.c | 96 + mate-panel/libpanel-util/panel-error.h | 49 + mate-panel/libpanel-util/panel-glib.c | 164 + mate-panel/libpanel-util/panel-glib.h | 46 + mate-panel/libpanel-util/panel-gtk.c | 83 + mate-panel/libpanel-util/panel-gtk.h | 42 + mate-panel/libpanel-util/panel-icon-chooser.c | 555 ++ mate-panel/libpanel-util/panel-icon-chooser.h | 79 + mate-panel/libpanel-util/panel-keyfile.c | 363 ++ mate-panel/libpanel-util/panel-keyfile.h | 79 + mate-panel/libpanel-util/panel-launch.c | 234 + mate-panel/libpanel-util/panel-launch.h | 65 + mate-panel/libpanel-util/panel-list.c | 212 + mate-panel/libpanel-util/panel-list.h | 56 + mate-panel/libpanel-util/panel-session-manager.c | 192 + mate-panel/libpanel-util/panel-session-manager.h | 75 + mate-panel/libpanel-util/panel-show.c | 283 ++ mate-panel/libpanel-util/panel-show.h | 54 + mate-panel/libpanel-util/panel-xdg.c | 152 + mate-panel/libpanel-util/panel-xdg.h | 43 + mate-panel/main.c | 153 + mate-panel/mate-desktop-item-edit.c | 225 + mate-panel/mate-panel-add.in | 325 ++ mate-panel/mate-panel-applet-frame.c | 1002 ++++ mate-panel/mate-panel-applet-frame.h | 146 + mate-panel/mate-panel-applet-info.c | 113 + mate-panel/mate-panel-applet-info.h | 51 + mate-panel/mate-panel-applets-manager.c | 201 + mate-panel/mate-panel-applets-manager.h | 94 + mate-panel/mate-panel.desktop.in.in | 19 + mate-panel/mate-panelrc | 4 + mate-panel/menu.c | 1914 +++++++ mate-panel/menu.h | 80 + mate-panel/nothing.cP | 1568 ++++++ mate-panel/nothing.h | 22 + mate-panel/panel-a11y.c | 135 + mate-panel/panel-a11y.h | 43 + mate-panel/panel-action-button.c | 907 ++++ mate-panel/panel-action-button.h | 103 + mate-panel/panel-action-protocol.c | 158 + mate-panel/panel-action-protocol.h | 40 + mate-panel/panel-addto.c | 1428 ++++++ mate-panel/panel-addto.h | 39 + mate-panel/panel-background-monitor.c | 440 ++ mate-panel/panel-background-monitor.h | 60 + mate-panel/panel-background.c | 1156 +++++ mate-panel/panel-background.h | 133 + mate-panel/panel-bindings.c | 303 ++ mate-panel/panel-bindings.h | 42 + mate-panel/panel-compatibility.c | 1167 +++++ mate-panel/panel-compatibility.h | 48 + mate-panel/panel-compatibility.schemas | 546 ++ mate-panel/panel-config-global.c | 153 + mate-panel/panel-config-global.h | 47 + mate-panel/panel-context-menu.c | 307 ++ mate-panel/panel-context-menu.h | 33 + mate-panel/panel-default-setup.entries | 657 +++ mate-panel/panel-ditem-editor.c | 1804 +++++++ mate-panel/panel-ditem-editor.h | 115 + mate-panel/panel-enums.h | 110 + mate-panel/panel-force-quit.c | 316 ++ mate-panel/panel-force-quit.h | 41 + mate-panel/panel-frame.c | 328 ++ mate-panel/panel-frame.h | 69 + mate-panel/panel-general.schemas.in | 127 + mate-panel/panel-global.schemas.in | 276 + mate-panel/panel-globals.h | 41 + mate-panel/panel-icon-names.h | 40 + mate-panel/panel-lockdown.c | 442 ++ mate-panel/panel-lockdown.h | 55 + mate-panel/panel-marshal.list | 3 + mate-panel/panel-mateconf.c | 351 ++ mate-panel/panel-mateconf.h | 76 + mate-panel/panel-menu-bar.c | 474 ++ mate-panel/panel-menu-bar.h | 83 + mate-panel/panel-menu-button.c | 1194 +++++ mate-panel/panel-menu-button.h | 98 + mate-panel/panel-menu-items.c | 1618 ++++++ mate-panel/panel-menu-items.h | 99 + mate-panel/panel-modules.c | 86 + mate-panel/panel-modules.h | 30 + mate-panel/panel-multiscreen.c | 784 +++ mate-panel/panel-multiscreen.h | 58 + mate-panel/panel-object.schemas.in | 247 + mate-panel/panel-profile.c | 2647 ++++++++++ mate-panel/panel-profile.h | 188 + mate-panel/panel-properties-dialog.c | 999 ++++ mate-panel/panel-properties-dialog.h | 40 + mate-panel/panel-properties-dialog.ui | 769 +++ mate-panel/panel-recent.c | 243 + mate-panel/panel-recent.h | 41 + mate-panel/panel-reset.c | 46 + mate-panel/panel-reset.h | 37 + mate-panel/panel-run-dialog.c | 2041 ++++++++ mate-panel/panel-run-dialog.h | 41 + mate-panel/panel-run-dialog.ui | 270 + mate-panel/panel-separator.c | 250 + mate-panel/panel-separator.h | 71 + mate-panel/panel-session.c | 80 + mate-panel/panel-session.h | 39 + mate-panel/panel-shell.c | 164 + mate-panel/panel-shell.h | 37 + mate-panel/panel-stock-icons.c | 141 + mate-panel/panel-stock-icons.h | 60 + mate-panel/panel-struts.c | 516 ++ mate-panel/panel-struts.h | 56 + mate-panel/panel-test-applets.c | 388 ++ mate-panel/panel-test-applets.ui | 203 + mate-panel/panel-toplevel.c | 5298 ++++++++++++++++++++ mate-panel/panel-toplevel.h | 179 + mate-panel/panel-toplevel.schemas.in | 434 ++ mate-panel/panel-types.h | 19 + mate-panel/panel-util.c | 1210 +++++ mate-panel/panel-util.h | 72 + mate-panel/panel-widget.c | 3010 +++++++++++ mate-panel/panel-widget.h | 242 + mate-panel/panel-xutils.c | 258 + mate-panel/panel-xutils.h | 64 + mate-panel/panel.c | 1403 ++++++ mate-panel/panel.h | 57 + mate-panel/xstuff.c | 736 +++ mate-panel/xstuff.h | 39 + 155 files changed, 63724 insertions(+) create mode 100644 mate-panel/Makefile.am create mode 100644 mate-panel/Makefile.in create mode 100644 mate-panel/applet.c create mode 100644 mate-panel/applet.h create mode 100644 mate-panel/button-widget.c create mode 100644 mate-panel/button-widget.h create mode 100644 mate-panel/drawer.c create mode 100644 mate-panel/drawer.h create mode 100644 mate-panel/launcher.c create mode 100644 mate-panel/launcher.h create mode 100644 mate-panel/libegg/Makefile.am create mode 100644 mate-panel/libegg/Makefile.in create mode 100644 mate-panel/libegg/eggdesktopfile.c create mode 100644 mate-panel/libegg/eggdesktopfile.h create mode 100644 mate-panel/libegg/eggsmclient-private.h create mode 100644 mate-panel/libegg/eggsmclient-xsmp.c create mode 100644 mate-panel/libegg/eggsmclient.c create mode 100644 mate-panel/libegg/eggsmclient.h create mode 100644 mate-panel/libmate-panel-applet-private/Makefile.am create mode 100644 mate-panel/libmate-panel-applet-private/Makefile.in create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applet-container.c create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applet-container.h create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.c create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.h create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applet-mini.c create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.c create mode 100644 mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.h create mode 100644 mate-panel/libpanel-util/Makefile.am create mode 100644 mate-panel/libpanel-util/Makefile.in create mode 100644 mate-panel/libpanel-util/panel-cleanup.c create mode 100644 mate-panel/libpanel-util/panel-cleanup.h create mode 100644 mate-panel/libpanel-util/panel-dbus-service.c create mode 100644 mate-panel/libpanel-util/panel-dbus-service.h create mode 100644 mate-panel/libpanel-util/panel-error.c create mode 100644 mate-panel/libpanel-util/panel-error.h create mode 100644 mate-panel/libpanel-util/panel-glib.c create mode 100644 mate-panel/libpanel-util/panel-glib.h create mode 100644 mate-panel/libpanel-util/panel-gtk.c create mode 100644 mate-panel/libpanel-util/panel-gtk.h create mode 100644 mate-panel/libpanel-util/panel-icon-chooser.c create mode 100644 mate-panel/libpanel-util/panel-icon-chooser.h create mode 100644 mate-panel/libpanel-util/panel-keyfile.c create mode 100644 mate-panel/libpanel-util/panel-keyfile.h create mode 100644 mate-panel/libpanel-util/panel-launch.c create mode 100644 mate-panel/libpanel-util/panel-launch.h create mode 100644 mate-panel/libpanel-util/panel-list.c create mode 100644 mate-panel/libpanel-util/panel-list.h create mode 100644 mate-panel/libpanel-util/panel-session-manager.c create mode 100644 mate-panel/libpanel-util/panel-session-manager.h create mode 100644 mate-panel/libpanel-util/panel-show.c create mode 100644 mate-panel/libpanel-util/panel-show.h create mode 100644 mate-panel/libpanel-util/panel-xdg.c create mode 100644 mate-panel/libpanel-util/panel-xdg.h create mode 100644 mate-panel/main.c create mode 100644 mate-panel/mate-desktop-item-edit.c create mode 100644 mate-panel/mate-panel-add.in create mode 100644 mate-panel/mate-panel-applet-frame.c create mode 100644 mate-panel/mate-panel-applet-frame.h create mode 100644 mate-panel/mate-panel-applet-info.c create mode 100644 mate-panel/mate-panel-applet-info.h create mode 100644 mate-panel/mate-panel-applets-manager.c create mode 100644 mate-panel/mate-panel-applets-manager.h create mode 100644 mate-panel/mate-panel.desktop.in.in create mode 100644 mate-panel/mate-panelrc create mode 100644 mate-panel/menu.c create mode 100644 mate-panel/menu.h create mode 100644 mate-panel/nothing.cP create mode 100644 mate-panel/nothing.h create mode 100644 mate-panel/panel-a11y.c create mode 100644 mate-panel/panel-a11y.h create mode 100644 mate-panel/panel-action-button.c create mode 100644 mate-panel/panel-action-button.h create mode 100644 mate-panel/panel-action-protocol.c create mode 100644 mate-panel/panel-action-protocol.h create mode 100644 mate-panel/panel-addto.c create mode 100644 mate-panel/panel-addto.h create mode 100644 mate-panel/panel-background-monitor.c create mode 100644 mate-panel/panel-background-monitor.h create mode 100644 mate-panel/panel-background.c create mode 100644 mate-panel/panel-background.h create mode 100644 mate-panel/panel-bindings.c create mode 100644 mate-panel/panel-bindings.h create mode 100644 mate-panel/panel-compatibility.c create mode 100644 mate-panel/panel-compatibility.h create mode 100644 mate-panel/panel-compatibility.schemas create mode 100644 mate-panel/panel-config-global.c create mode 100644 mate-panel/panel-config-global.h create mode 100644 mate-panel/panel-context-menu.c create mode 100644 mate-panel/panel-context-menu.h create mode 100644 mate-panel/panel-default-setup.entries create mode 100644 mate-panel/panel-ditem-editor.c create mode 100644 mate-panel/panel-ditem-editor.h create mode 100644 mate-panel/panel-enums.h create mode 100644 mate-panel/panel-force-quit.c create mode 100644 mate-panel/panel-force-quit.h create mode 100644 mate-panel/panel-frame.c create mode 100644 mate-panel/panel-frame.h create mode 100644 mate-panel/panel-general.schemas.in create mode 100644 mate-panel/panel-global.schemas.in create mode 100644 mate-panel/panel-globals.h create mode 100644 mate-panel/panel-icon-names.h create mode 100644 mate-panel/panel-lockdown.c create mode 100644 mate-panel/panel-lockdown.h create mode 100644 mate-panel/panel-marshal.list create mode 100644 mate-panel/panel-mateconf.c create mode 100644 mate-panel/panel-mateconf.h create mode 100644 mate-panel/panel-menu-bar.c create mode 100644 mate-panel/panel-menu-bar.h create mode 100644 mate-panel/panel-menu-button.c create mode 100644 mate-panel/panel-menu-button.h create mode 100644 mate-panel/panel-menu-items.c create mode 100644 mate-panel/panel-menu-items.h create mode 100644 mate-panel/panel-modules.c create mode 100644 mate-panel/panel-modules.h create mode 100644 mate-panel/panel-multiscreen.c create mode 100644 mate-panel/panel-multiscreen.h create mode 100644 mate-panel/panel-object.schemas.in create mode 100644 mate-panel/panel-profile.c create mode 100644 mate-panel/panel-profile.h create mode 100644 mate-panel/panel-properties-dialog.c create mode 100644 mate-panel/panel-properties-dialog.h create mode 100644 mate-panel/panel-properties-dialog.ui create mode 100644 mate-panel/panel-recent.c create mode 100644 mate-panel/panel-recent.h create mode 100644 mate-panel/panel-reset.c create mode 100644 mate-panel/panel-reset.h create mode 100644 mate-panel/panel-run-dialog.c create mode 100644 mate-panel/panel-run-dialog.h create mode 100644 mate-panel/panel-run-dialog.ui create mode 100644 mate-panel/panel-separator.c create mode 100644 mate-panel/panel-separator.h create mode 100644 mate-panel/panel-session.c create mode 100644 mate-panel/panel-session.h create mode 100644 mate-panel/panel-shell.c create mode 100644 mate-panel/panel-shell.h create mode 100644 mate-panel/panel-stock-icons.c create mode 100644 mate-panel/panel-stock-icons.h create mode 100644 mate-panel/panel-struts.c create mode 100644 mate-panel/panel-struts.h create mode 100644 mate-panel/panel-test-applets.c create mode 100644 mate-panel/panel-test-applets.ui create mode 100644 mate-panel/panel-toplevel.c create mode 100644 mate-panel/panel-toplevel.h create mode 100644 mate-panel/panel-toplevel.schemas.in create mode 100644 mate-panel/panel-types.h create mode 100644 mate-panel/panel-util.c create mode 100644 mate-panel/panel-util.h create mode 100644 mate-panel/panel-widget.c create mode 100644 mate-panel/panel-widget.h create mode 100644 mate-panel/panel-xutils.c create mode 100644 mate-panel/panel-xutils.h create mode 100644 mate-panel/panel.c create mode 100644 mate-panel/panel.h create mode 100644 mate-panel/xstuff.c create mode 100644 mate-panel/xstuff.h (limited to 'mate-panel') diff --git a/mate-panel/Makefile.am b/mate-panel/Makefile.am new file mode 100644 index 00000000..e72925ad --- /dev/null +++ b/mate-panel/Makefile.am @@ -0,0 +1,290 @@ +SUBDIRS = libegg libmate-panel-applet-private libpanel-util + +bin_PROGRAMS = \ + mate-panel \ + mate-desktop-item-edit \ + mate-panel-test-applets +libexec_SCRIPTS = mate-panel-add + +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + -I. \ + -I$(srcdir) \ + -I$(top_builddir)/mate-panel \ + -I$(top_builddir)/mate-panel/libpanel-util \ + -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DBUILDERDIR=\""$(uidir)"\" \ + -DICONDIR=\""$(datadir)/mate-panel/pixmaps"\" \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) + +panel_sources = \ + panel-typebuiltins.c \ + panel-typebuiltins.h \ + panel-marshal.c \ + panel-marshal.h \ + main.c \ + panel-widget.c \ + button-widget.c \ + xstuff.c \ + panel-session.c \ + panel-compatibility.c \ + panel.c \ + applet.c \ + drawer.c \ + panel-config-global.c \ + panel-util.c \ + panel-mateconf.c \ + panel-properties-dialog.c \ + panel-run-dialog.c \ + menu.c \ + panel-context-menu.c \ + launcher.c \ + mate-panel-applet-frame.c \ + mate-panel-applets-manager.c \ + panel-shell.c \ + panel-background.c \ + panel-background-monitor.c \ + panel-stock-icons.c \ + panel-action-button.c \ + panel-menu-bar.c \ + panel-menu-button.c \ + panel-menu-items.c \ + panel-separator.c \ + panel-recent.c \ + panel-action-protocol.c \ + panel-toplevel.c \ + panel-struts.c \ + panel-frame.c \ + panel-xutils.c \ + panel-multiscreen.c \ + panel-a11y.c \ + panel-bindings.c \ + panel-profile.c \ + panel-force-quit.c \ + panel-lockdown.c \ + panel-addto.c \ + panel-ditem-editor.c \ + panel-modules.c \ + mate-panel-applet-info.c \ + panel-reset.c + +panel_headers = \ + panel-types.h \ + panel-widget.h \ + panel-globals.h \ + button-widget.h \ + xstuff.h \ + panel-session.h \ + panel-compatibility.h \ + panel.h \ + applet.h \ + drawer.h \ + panel-util.h \ + panel-properties-dialog.h \ + panel-config-global.h \ + panel-mateconf.h \ + panel-run-dialog.h \ + menu.h \ + panel-context-menu.h \ + launcher.h \ + mate-panel-applet-frame.h \ + mate-panel-applets-manager.h \ + panel-shell.h \ + panel-background.h \ + panel-background-monitor.h \ + panel-stock-icons.h \ + panel-action-button.h \ + panel-menu-bar.h \ + panel-menu-button.h \ + panel-menu-items.h \ + panel-separator.h \ + panel-recent.h \ + panel-action-protocol.h \ + panel-toplevel.h \ + panel-struts.h \ + panel-frame.h \ + panel-xutils.h \ + panel-multiscreen.h \ + panel-a11y.h \ + panel-bindings.h \ + panel-profile.h \ + panel-enums.h \ + panel-force-quit.h \ + panel-lockdown.h \ + panel-addto.h \ + panel-ditem-editor.h \ + panel-icon-names.h \ + panel-modules.h \ + mate-panel-applet-info.h \ + panel-reset.h + +mate_panel_SOURCES = \ + $(panel_sources) \ + $(panel_headers) + +mate_panel_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(XRANDR_CFLAGS) \ + -DPANEL_MODULES_DIR=\"$(modulesdir)\" \ + -DMATEMENU_I_KNOW_THIS_IS_UNSTABLE + +mate_panel_LDADD = \ + $(top_builddir)/mate-panel/libegg/libegg.la \ + $(top_builddir)/mate-panel/libmate-panel-applet-private/libmate-panel-applet-private.la \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(PANEL_LIBS) \ + $(XRANDR_LIBS) \ + $(X_LIBS) + +mate_panel_LDFLAGS = -export-dynamic + +mate_desktop_item_edit_SOURCES = \ + mate-desktop-item-edit.c \ + panel-ditem-editor.c \ + panel-marshal.c \ + panel-util.c \ + xstuff.c + +mate_desktop_item_edit_LDADD = \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(PANEL_LIBS) + +mate_panel_test_applets_SOURCES = \ + panel-modules.c \ + mate-panel-applet-info.c \ + mate-panel-applets-manager.c \ + panel-marshal.c \ + panel-test-applets.c + +mate_panel_test_applets_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DPANEL_MODULES_DIR=\"$(modulesdir)\" \ + -DMATE_PANEL_APPLETS_DIR=\"$(appletsdir)\" + +mate_panel_test_applets_LDADD = \ + $(top_builddir)/mate-panel/libmate-panel-applet-private/libmate-panel-applet-private-mini.la \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(PANEL_LIBS) + +mate_panel_test_applets_LDFLAGS = -export-dynamic + +mate-panel-add: mate-panel-add.in Makefile + $(AM_V_GEN)sed \ + -e s!\@PYTHON\@!@PYTHON@! \ + -e s!\@MATE_PANEL_APPLETS_DIR\@!$(appletsdir)! \ + < $< > $@ + $(AM_V_at)chmod a+x $@ + +panel_enum_headers = \ + $(top_srcdir)/mate-panel/panel-enums.h \ + $(top_srcdir)/mate-panel/panel-types.h + +panel-marshal.h: panel-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --header --prefix=panel_marshal > $@ + +panel-marshal.c: panel-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN)echo "#include \"panel-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=panel_marshal >> $@ + +panel-typebuiltins.c: @REBUILD@ $(panel_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#include \n" \ + --fhead "#include \"panel-typebuiltins.h\"\n\n" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --fprod "\n#include \"@filename@\"\n" \ + --vhead "static const GEnumValue _@enum_name@_values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n};\n\n" \ + --vtail "GType\n@enum_name@_get_type (void)\n{\n" \ + --vtail " static GType type = 0;\n\n" \ + --vtail " if (!type)\n" \ + --vtail " type = g_enum_register_static (\"@EnumName@\", _@enum_name@_values);\n\n" \ + --vtail " return type;\n}\n\n" \ + $(panel_enum_headers) > $@ + +panel-typebuiltins.h: @REBUILD@ $(panel_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#ifndef __PANEL_TYPEBUILTINS_H__\n" \ + --fhead "#define __PANEL_TYPEBUILTINS_H__ 1\n\n" \ + --fhead "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" \ + --ftail "#ifdef __cplusplus\n}\n#endif\n\n" \ + --ftail "#endif /* __PANEL_TYPEBUILTINS_H__ */\n" \ + --fprod "\n/* --- @filename@ --- */" \ + --eprod "#define PANEL_TYPE_@ENUMSHORT@ @enum_name@_get_type()\n" \ + --eprod "GType @enum_name@_get_type (void);\n" \ + $(panel_enum_headers) > $@ + +BUILT_SOURCES = \ + panel-typebuiltins.c \ + panel-typebuiltins.h \ + panel-marshal.c \ + panel-marshal.h + +rcdir = $(datadir) +rc_DATA = mate-panelrc + +uidir = $(datadir)/mate-panel/ui +ui_DATA = \ + panel-properties-dialog.ui \ + panel-run-dialog.ui \ + panel-test-applets.ui + +desktopdir = $(datadir)/applications +desktop_in_files = mate-panel.desktop.in +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) + +@INTLTOOL_DESKTOP_RULE@ + +entriesdir = $(MATECONF_SCHEMA_FILE_DIR) +entries_DATA = panel-default-setup.entries + +schemasdir = $(MATECONF_SCHEMA_FILE_DIR) +schemas_in_files = \ + panel-global.schemas.in \ + panel-general.schemas.in \ + panel-toplevel.schemas.in \ + panel-object.schemas.in +schemas_DATA = panel-compatibility.schemas $(schemas_in_files:.schemas.in=.schemas) + +@INTLTOOL_SCHEMAS_RULE@ + +if MATECONF_SCHEMAS_INSTALL +install-data-local: + if test -z "$(DESTDIR)" ; then \ + for p in $(schemas_DATA) ; do \ + MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $(top_builddir)/mate-panel/$$p ; \ + done ; \ + $(MATECONFTOOL) --direct --config-source=$(MATECONF_SCHEMA_CONFIG_SOURCE) --load $(srcdir)/panel-default-setup.entries ; \ + $(MATECONFTOOL) --direct --config-source=$(MATECONF_SCHEMA_CONFIG_SOURCE) --load $(srcdir)/panel-default-setup.entries /apps/panel ; \ + fi +uninstall-local: + for p in $(schema_DATA) ; do \ + MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-uninstall-rule $(top_builddir)/applets/ngome-panel/$$p ; \ + done +endif + +EXTRA_DIST = \ + $(ui_DATA) \ + nothing.cP \ + nothing.h \ + $(schemas_in_files) \ + panel-compatibility.schemas \ + panel-marshal.list \ + mate-panelrc \ + $(entries_DATA) \ + $(desktop_in_files) \ + mate-panel-add.in + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(schemas_in_files:.schemas.in=.schemas) \ + $(sys_DATA) \ + $(desktop_DATA) \ + mate-panel-add + +dist-hook: + cd $(distdir) ; rm -f $(CLEANFILES) + +-include $(top_srcdir)/git.mk diff --git a/mate-panel/Makefile.in b/mate-panel/Makefile.in new file mode 100644 index 00000000..1226b501 --- /dev/null +++ b/mate-panel/Makefile.in @@ -0,0 +1,2222 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = mate-panel$(EXEEXT) mate-desktop-item-edit$(EXEEXT) \ + mate-panel-test-applets$(EXEEXT) +subdir = mate-panel +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/mate-panel.desktop.in.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/d-type.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = mate-panel.desktop.in +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \ + "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(entriesdir)" \ + "$(DESTDIR)$(rcdir)" "$(DESTDIR)$(schemasdir)" \ + "$(DESTDIR)$(uidir)" +PROGRAMS = $(bin_PROGRAMS) +am_mate_desktop_item_edit_OBJECTS = mate-desktop-item-edit.$(OBJEXT) \ + panel-ditem-editor.$(OBJEXT) panel-marshal.$(OBJEXT) \ + panel-util.$(OBJEXT) xstuff.$(OBJEXT) +mate_desktop_item_edit_OBJECTS = $(am_mate_desktop_item_edit_OBJECTS) +am__DEPENDENCIES_1 = +mate_desktop_item_edit_DEPENDENCIES = \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am__objects_1 = mate_panel-panel-typebuiltins.$(OBJEXT) \ + mate_panel-panel-marshal.$(OBJEXT) mate_panel-main.$(OBJEXT) \ + mate_panel-panel-widget.$(OBJEXT) \ + mate_panel-button-widget.$(OBJEXT) mate_panel-xstuff.$(OBJEXT) \ + mate_panel-panel-session.$(OBJEXT) \ + mate_panel-panel-compatibility.$(OBJEXT) \ + mate_panel-panel.$(OBJEXT) mate_panel-applet.$(OBJEXT) \ + mate_panel-drawer.$(OBJEXT) \ + mate_panel-panel-config-global.$(OBJEXT) \ + mate_panel-panel-util.$(OBJEXT) \ + mate_panel-panel-mateconf.$(OBJEXT) \ + mate_panel-panel-properties-dialog.$(OBJEXT) \ + mate_panel-panel-run-dialog.$(OBJEXT) \ + mate_panel-menu.$(OBJEXT) \ + mate_panel-panel-context-menu.$(OBJEXT) \ + mate_panel-launcher.$(OBJEXT) \ + mate_panel-mate-panel-applet-frame.$(OBJEXT) \ + mate_panel-mate-panel-applets-manager.$(OBJEXT) \ + mate_panel-panel-shell.$(OBJEXT) \ + mate_panel-panel-background.$(OBJEXT) \ + mate_panel-panel-background-monitor.$(OBJEXT) \ + mate_panel-panel-stock-icons.$(OBJEXT) \ + mate_panel-panel-action-button.$(OBJEXT) \ + mate_panel-panel-menu-bar.$(OBJEXT) \ + mate_panel-panel-menu-button.$(OBJEXT) \ + mate_panel-panel-menu-items.$(OBJEXT) \ + mate_panel-panel-separator.$(OBJEXT) \ + mate_panel-panel-recent.$(OBJEXT) \ + mate_panel-panel-action-protocol.$(OBJEXT) \ + mate_panel-panel-toplevel.$(OBJEXT) \ + mate_panel-panel-struts.$(OBJEXT) \ + mate_panel-panel-frame.$(OBJEXT) \ + mate_panel-panel-xutils.$(OBJEXT) \ + mate_panel-panel-multiscreen.$(OBJEXT) \ + mate_panel-panel-a11y.$(OBJEXT) \ + mate_panel-panel-bindings.$(OBJEXT) \ + mate_panel-panel-profile.$(OBJEXT) \ + mate_panel-panel-force-quit.$(OBJEXT) \ + mate_panel-panel-lockdown.$(OBJEXT) \ + mate_panel-panel-addto.$(OBJEXT) \ + mate_panel-panel-ditem-editor.$(OBJEXT) \ + mate_panel-panel-modules.$(OBJEXT) \ + mate_panel-mate-panel-applet-info.$(OBJEXT) \ + mate_panel-panel-reset.$(OBJEXT) +am__objects_2 = +am_mate_panel_OBJECTS = $(am__objects_1) $(am__objects_2) +mate_panel_OBJECTS = $(am_mate_panel_OBJECTS) +mate_panel_DEPENDENCIES = $(top_builddir)/mate-panel/libegg/libegg.la \ + $(top_builddir)/mate-panel/libmate-panel-applet-private/libmate-panel-applet-private.la \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +mate_panel_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(mate_panel_LDFLAGS) $(LDFLAGS) -o $@ +am_mate_panel_test_applets_OBJECTS = \ + mate_panel_test_applets-panel-modules.$(OBJEXT) \ + mate_panel_test_applets-mate-panel-applet-info.$(OBJEXT) \ + mate_panel_test_applets-mate-panel-applets-manager.$(OBJEXT) \ + mate_panel_test_applets-panel-marshal.$(OBJEXT) \ + mate_panel_test_applets-panel-test-applets.$(OBJEXT) +mate_panel_test_applets_OBJECTS = \ + $(am_mate_panel_test_applets_OBJECTS) +mate_panel_test_applets_DEPENDENCIES = $(top_builddir)/mate-panel/libmate-panel-applet-private/libmate-panel-applet-private-mini.la \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(am__DEPENDENCIES_1) +mate_panel_test_applets_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(mate_panel_test_applets_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +SCRIPTS = $(libexec_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(mate_desktop_item_edit_SOURCES) $(mate_panel_SOURCES) \ + $(mate_panel_test_applets_SOURCES) +DIST_SOURCES = $(mate_desktop_item_edit_SOURCES) $(mate_panel_SOURCES) \ + $(mate_panel_test_applets_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +DATA = $(desktop_DATA) $(entries_DATA) $(rc_DATA) $(schemas_DATA) \ + $(ui_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLOCK_CFLAGS = @CLOCK_CFLAGS@ +CLOCK_EDS_ICONDIR = @CLOCK_EDS_ICONDIR@ +CLOCK_LIBS = @CLOCK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DISABLE_DEPRECATED_CFLAGS = @DISABLE_DEPRECATED_CFLAGS@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOC_USER_FORMATS = @DOC_USER_FORMATS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGG_SMCLIENT_CFLAGS = @EGG_SMCLIENT_CFLAGS@ +EGG_SMCLIENT_LIBS = @EGG_SMCLIENT_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FISH_CFLAGS = @FISH_CFLAGS@ +FISH_LIBS = @FISH_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_QUERYMODULES = @GIO_QUERYMODULES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HELP_DIR = @HELP_DIR@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBMATE_PANEL_APPLET_CFLAGS = @LIBMATE_PANEL_APPLET_CFLAGS@ +LIBMATE_PANEL_APPLET_LIBS = @LIBMATE_PANEL_APPLET_LIBS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MATE_PANEL_APPLET_LT_VERSION = @LIB_MATE_PANEL_APPLET_LT_VERSION@ +LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION = @LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECOMPONENT_ACT_IDLDIR = @MATECOMPONENT_ACT_IDLDIR@ +MATECOMPONENT_CFLAGS = @MATECOMPONENT_CFLAGS@ +MATECOMPONENT_IDLDIR = @MATECOMPONENT_IDLDIR@ +MATECOMPONENT_LIBS = @MATECOMPONENT_LIBS@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATECORBA_IDL = @MATECORBA_IDL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NETWORK_MANAGER_CFLAGS = @NETWORK_MANAGER_CFLAGS@ +NETWORK_MANAGER_LIBS = @NETWORK_MANAGER_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOTIFICATION_AREA_CFLAGS = @NOTIFICATION_AREA_CFLAGS@ +NOTIFICATION_AREA_LIBS = @NOTIFICATION_AREA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OMF_DIR = @OMF_DIR@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANEL_CFLAGS = @PANEL_CFLAGS@ +PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE = @PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ +PANEL_LIBS = @PANEL_LIBS@ +PANEL_MODULE_MATECOMPONENT_CFLAGS = @PANEL_MODULE_MATECOMPONENT_CFLAGS@ +PANEL_MODULE_MATECOMPONENT_LIBS = @PANEL_MODULE_MATECOMPONENT_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POFILES = @POFILES@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REBUILD = @REBUILD@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TZ_CFLAGS = @TZ_CFLAGS@ +TZ_LIBS = @TZ_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WNCKLET_CFLAGS = @WNCKLET_CFLAGS@ +WNCKLET_LIBS = @WNCKLET_LIBS@ +XGETTEXT = @XGETTEXT@ +XMKMF = @XMKMF@ +XRANDR_CFLAGS = @XRANDR_CFLAGS@ +XRANDR_LIBS = @XRANDR_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +appletsdir = @appletsdir@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +modulesdir = @modulesdir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = libegg libmate-panel-applet-private libpanel-util +libexec_SCRIPTS = mate-panel-add +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + -I. \ + -I$(srcdir) \ + -I$(top_builddir)/mate-panel \ + -I$(top_builddir)/mate-panel/libpanel-util \ + -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DBUILDERDIR=\""$(uidir)"\" \ + -DICONDIR=\""$(datadir)/mate-panel/pixmaps"\" \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) +panel_sources = \ + panel-typebuiltins.c \ + panel-typebuiltins.h \ + panel-marshal.c \ + panel-marshal.h \ + main.c \ + panel-widget.c \ + button-widget.c \ + xstuff.c \ + panel-session.c \ + panel-compatibility.c \ + panel.c \ + applet.c \ + drawer.c \ + panel-config-global.c \ + panel-util.c \ + panel-mateconf.c \ + panel-properties-dialog.c \ + panel-run-dialog.c \ + menu.c \ + panel-context-menu.c \ + launcher.c \ + mate-panel-applet-frame.c \ + mate-panel-applets-manager.c \ + panel-shell.c \ + panel-background.c \ + panel-background-monitor.c \ + panel-stock-icons.c \ + panel-action-button.c \ + panel-menu-bar.c \ + panel-menu-button.c \ + panel-menu-items.c \ + panel-separator.c \ + panel-recent.c \ + panel-action-protocol.c \ + panel-toplevel.c \ + panel-struts.c \ + panel-frame.c \ + panel-xutils.c \ + panel-multiscreen.c \ + panel-a11y.c \ + panel-bindings.c \ + panel-profile.c \ + panel-force-quit.c \ + panel-lockdown.c \ + panel-addto.c \ + panel-ditem-editor.c \ + panel-modules.c \ + mate-panel-applet-info.c \ + panel-reset.c + +panel_headers = \ + panel-types.h \ + panel-widget.h \ + panel-globals.h \ + button-widget.h \ + xstuff.h \ + panel-session.h \ + panel-compatibility.h \ + panel.h \ + applet.h \ + drawer.h \ + panel-util.h \ + panel-properties-dialog.h \ + panel-config-global.h \ + panel-mateconf.h \ + panel-run-dialog.h \ + menu.h \ + panel-context-menu.h \ + launcher.h \ + mate-panel-applet-frame.h \ + mate-panel-applets-manager.h \ + panel-shell.h \ + panel-background.h \ + panel-background-monitor.h \ + panel-stock-icons.h \ + panel-action-button.h \ + panel-menu-bar.h \ + panel-menu-button.h \ + panel-menu-items.h \ + panel-separator.h \ + panel-recent.h \ + panel-action-protocol.h \ + panel-toplevel.h \ + panel-struts.h \ + panel-frame.h \ + panel-xutils.h \ + panel-multiscreen.h \ + panel-a11y.h \ + panel-bindings.h \ + panel-profile.h \ + panel-enums.h \ + panel-force-quit.h \ + panel-lockdown.h \ + panel-addto.h \ + panel-ditem-editor.h \ + panel-icon-names.h \ + panel-modules.h \ + mate-panel-applet-info.h \ + panel-reset.h + +mate_panel_SOURCES = \ + $(panel_sources) \ + $(panel_headers) + +mate_panel_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(XRANDR_CFLAGS) \ + -DPANEL_MODULES_DIR=\"$(modulesdir)\" \ + -DMATEMENU_I_KNOW_THIS_IS_UNSTABLE + +mate_panel_LDADD = \ + $(top_builddir)/mate-panel/libegg/libegg.la \ + $(top_builddir)/mate-panel/libmate-panel-applet-private/libmate-panel-applet-private.la \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(PANEL_LIBS) \ + $(XRANDR_LIBS) \ + $(X_LIBS) + +mate_panel_LDFLAGS = -export-dynamic +mate_desktop_item_edit_SOURCES = \ + mate-desktop-item-edit.c \ + panel-ditem-editor.c \ + panel-marshal.c \ + panel-util.c \ + xstuff.c + +mate_desktop_item_edit_LDADD = \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(PANEL_LIBS) + +mate_panel_test_applets_SOURCES = \ + panel-modules.c \ + mate-panel-applet-info.c \ + mate-panel-applets-manager.c \ + panel-marshal.c \ + panel-test-applets.c + +mate_panel_test_applets_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DPANEL_MODULES_DIR=\"$(modulesdir)\" \ + -DMATE_PANEL_APPLETS_DIR=\"$(appletsdir)\" + +mate_panel_test_applets_LDADD = \ + $(top_builddir)/mate-panel/libmate-panel-applet-private/libmate-panel-applet-private-mini.la \ + $(top_builddir)/mate-panel/libpanel-util/libpanel-util.la \ + $(PANEL_LIBS) + +mate_panel_test_applets_LDFLAGS = -export-dynamic +panel_enum_headers = \ + $(top_srcdir)/mate-panel/panel-enums.h \ + $(top_srcdir)/mate-panel/panel-types.h + +BUILT_SOURCES = \ + panel-typebuiltins.c \ + panel-typebuiltins.h \ + panel-marshal.c \ + panel-marshal.h + +rcdir = $(datadir) +rc_DATA = mate-panelrc +uidir = $(datadir)/mate-panel/ui +ui_DATA = \ + panel-properties-dialog.ui \ + panel-run-dialog.ui \ + panel-test-applets.ui + +desktopdir = $(datadir)/applications +desktop_in_files = mate-panel.desktop.in +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) +entriesdir = $(MATECONF_SCHEMA_FILE_DIR) +entries_DATA = panel-default-setup.entries +schemasdir = $(MATECONF_SCHEMA_FILE_DIR) +schemas_in_files = \ + panel-global.schemas.in \ + panel-general.schemas.in \ + panel-toplevel.schemas.in \ + panel-object.schemas.in + +schemas_DATA = panel-compatibility.schemas $(schemas_in_files:.schemas.in=.schemas) +EXTRA_DIST = \ + $(ui_DATA) \ + nothing.cP \ + nothing.h \ + $(schemas_in_files) \ + panel-compatibility.schemas \ + panel-marshal.list \ + mate-panelrc \ + $(entries_DATA) \ + $(desktop_in_files) \ + mate-panel-add.in + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(schemas_in_files:.schemas.in=.schemas) \ + $(sys_DATA) \ + $(desktop_DATA) \ + mate-panel-add + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu mate-panel/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu mate-panel/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +mate-panel.desktop.in: $(top_builddir)/config.status $(srcdir)/mate-panel.desktop.in.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +mate-desktop-item-edit$(EXEEXT): $(mate_desktop_item_edit_OBJECTS) $(mate_desktop_item_edit_DEPENDENCIES) + @rm -f mate-desktop-item-edit$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(mate_desktop_item_edit_OBJECTS) $(mate_desktop_item_edit_LDADD) $(LIBS) +mate-panel$(EXEEXT): $(mate_panel_OBJECTS) $(mate_panel_DEPENDENCIES) + @rm -f mate-panel$(EXEEXT) + $(AM_V_CCLD)$(mate_panel_LINK) $(mate_panel_OBJECTS) $(mate_panel_LDADD) $(LIBS) +mate-panel-test-applets$(EXEEXT): $(mate_panel_test_applets_OBJECTS) $(mate_panel_test_applets_DEPENDENCIES) + @rm -f mate-panel-test-applets$(EXEEXT) + $(AM_V_CCLD)$(mate_panel_test_applets_LINK) $(mate_panel_test_applets_OBJECTS) $(mate_panel_test_applets_LDADD) $(LIBS) +install-libexecSCRIPTS: $(libexec_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" + @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate-desktop-item-edit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-applet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-button-widget.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-drawer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-launcher.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-mate-panel-applet-frame.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-mate-panel-applet-info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-mate-panel-applets-manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-menu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-a11y.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-action-button.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-action-protocol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-addto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-background-monitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-background.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-bindings.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-compatibility.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-config-global.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-context-menu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-ditem-editor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-force-quit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-frame.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-lockdown.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-marshal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-mateconf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-menu-bar.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-menu-button.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-menu-items.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-modules.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-multiscreen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-profile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-properties-dialog.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-recent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-reset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-run-dialog.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-separator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-session.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-shell.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-stock-icons.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-struts.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-toplevel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-typebuiltins.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-widget.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel-xutils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-panel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel-xstuff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel_test_applets-panel-marshal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel_test_applets-panel-modules.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_panel_test_applets-panel-test-applets.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-ditem-editor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-marshal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xstuff.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mate_panel-panel-typebuiltins.o: panel-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-typebuiltins.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-typebuiltins.Tpo -c -o mate_panel-panel-typebuiltins.o `test -f 'panel-typebuiltins.c' || echo '$(srcdir)/'`panel-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-typebuiltins.Tpo $(DEPDIR)/mate_panel-panel-typebuiltins.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-typebuiltins.c' object='mate_panel-panel-typebuiltins.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-typebuiltins.o `test -f 'panel-typebuiltins.c' || echo '$(srcdir)/'`panel-typebuiltins.c + +mate_panel-panel-typebuiltins.obj: panel-typebuiltins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-typebuiltins.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-typebuiltins.Tpo -c -o mate_panel-panel-typebuiltins.obj `if test -f 'panel-typebuiltins.c'; then $(CYGPATH_W) 'panel-typebuiltins.c'; else $(CYGPATH_W) '$(srcdir)/panel-typebuiltins.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-typebuiltins.Tpo $(DEPDIR)/mate_panel-panel-typebuiltins.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-typebuiltins.c' object='mate_panel-panel-typebuiltins.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-typebuiltins.obj `if test -f 'panel-typebuiltins.c'; then $(CYGPATH_W) 'panel-typebuiltins.c'; else $(CYGPATH_W) '$(srcdir)/panel-typebuiltins.c'; fi` + +mate_panel-panel-marshal.o: panel-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-marshal.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-marshal.Tpo -c -o mate_panel-panel-marshal.o `test -f 'panel-marshal.c' || echo '$(srcdir)/'`panel-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-marshal.Tpo $(DEPDIR)/mate_panel-panel-marshal.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-marshal.c' object='mate_panel-panel-marshal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-marshal.o `test -f 'panel-marshal.c' || echo '$(srcdir)/'`panel-marshal.c + +mate_panel-panel-marshal.obj: panel-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-marshal.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-marshal.Tpo -c -o mate_panel-panel-marshal.obj `if test -f 'panel-marshal.c'; then $(CYGPATH_W) 'panel-marshal.c'; else $(CYGPATH_W) '$(srcdir)/panel-marshal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-marshal.Tpo $(DEPDIR)/mate_panel-panel-marshal.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-marshal.c' object='mate_panel-panel-marshal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-marshal.obj `if test -f 'panel-marshal.c'; then $(CYGPATH_W) 'panel-marshal.c'; else $(CYGPATH_W) '$(srcdir)/panel-marshal.c'; fi` + +mate_panel-main.o: main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-main.o -MD -MP -MF $(DEPDIR)/mate_panel-main.Tpo -c -o mate_panel-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-main.Tpo $(DEPDIR)/mate_panel-main.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='main.c' object='mate_panel-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c + +mate_panel-main.obj: main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-main.obj -MD -MP -MF $(DEPDIR)/mate_panel-main.Tpo -c -o mate_panel-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-main.Tpo $(DEPDIR)/mate_panel-main.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='main.c' object='mate_panel-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` + +mate_panel-panel-widget.o: panel-widget.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-widget.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-widget.Tpo -c -o mate_panel-panel-widget.o `test -f 'panel-widget.c' || echo '$(srcdir)/'`panel-widget.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-widget.Tpo $(DEPDIR)/mate_panel-panel-widget.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-widget.c' object='mate_panel-panel-widget.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-widget.o `test -f 'panel-widget.c' || echo '$(srcdir)/'`panel-widget.c + +mate_panel-panel-widget.obj: panel-widget.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-widget.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-widget.Tpo -c -o mate_panel-panel-widget.obj `if test -f 'panel-widget.c'; then $(CYGPATH_W) 'panel-widget.c'; else $(CYGPATH_W) '$(srcdir)/panel-widget.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-widget.Tpo $(DEPDIR)/mate_panel-panel-widget.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-widget.c' object='mate_panel-panel-widget.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-widget.obj `if test -f 'panel-widget.c'; then $(CYGPATH_W) 'panel-widget.c'; else $(CYGPATH_W) '$(srcdir)/panel-widget.c'; fi` + +mate_panel-button-widget.o: button-widget.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-button-widget.o -MD -MP -MF $(DEPDIR)/mate_panel-button-widget.Tpo -c -o mate_panel-button-widget.o `test -f 'button-widget.c' || echo '$(srcdir)/'`button-widget.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-button-widget.Tpo $(DEPDIR)/mate_panel-button-widget.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='button-widget.c' object='mate_panel-button-widget.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-button-widget.o `test -f 'button-widget.c' || echo '$(srcdir)/'`button-widget.c + +mate_panel-button-widget.obj: button-widget.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-button-widget.obj -MD -MP -MF $(DEPDIR)/mate_panel-button-widget.Tpo -c -o mate_panel-button-widget.obj `if test -f 'button-widget.c'; then $(CYGPATH_W) 'button-widget.c'; else $(CYGPATH_W) '$(srcdir)/button-widget.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-button-widget.Tpo $(DEPDIR)/mate_panel-button-widget.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='button-widget.c' object='mate_panel-button-widget.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-button-widget.obj `if test -f 'button-widget.c'; then $(CYGPATH_W) 'button-widget.c'; else $(CYGPATH_W) '$(srcdir)/button-widget.c'; fi` + +mate_panel-xstuff.o: xstuff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-xstuff.o -MD -MP -MF $(DEPDIR)/mate_panel-xstuff.Tpo -c -o mate_panel-xstuff.o `test -f 'xstuff.c' || echo '$(srcdir)/'`xstuff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-xstuff.Tpo $(DEPDIR)/mate_panel-xstuff.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xstuff.c' object='mate_panel-xstuff.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-xstuff.o `test -f 'xstuff.c' || echo '$(srcdir)/'`xstuff.c + +mate_panel-xstuff.obj: xstuff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-xstuff.obj -MD -MP -MF $(DEPDIR)/mate_panel-xstuff.Tpo -c -o mate_panel-xstuff.obj `if test -f 'xstuff.c'; then $(CYGPATH_W) 'xstuff.c'; else $(CYGPATH_W) '$(srcdir)/xstuff.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-xstuff.Tpo $(DEPDIR)/mate_panel-xstuff.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xstuff.c' object='mate_panel-xstuff.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-xstuff.obj `if test -f 'xstuff.c'; then $(CYGPATH_W) 'xstuff.c'; else $(CYGPATH_W) '$(srcdir)/xstuff.c'; fi` + +mate_panel-panel-session.o: panel-session.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-session.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-session.Tpo -c -o mate_panel-panel-session.o `test -f 'panel-session.c' || echo '$(srcdir)/'`panel-session.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-session.Tpo $(DEPDIR)/mate_panel-panel-session.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-session.c' object='mate_panel-panel-session.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-session.o `test -f 'panel-session.c' || echo '$(srcdir)/'`panel-session.c + +mate_panel-panel-session.obj: panel-session.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-session.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-session.Tpo -c -o mate_panel-panel-session.obj `if test -f 'panel-session.c'; then $(CYGPATH_W) 'panel-session.c'; else $(CYGPATH_W) '$(srcdir)/panel-session.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-session.Tpo $(DEPDIR)/mate_panel-panel-session.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-session.c' object='mate_panel-panel-session.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-session.obj `if test -f 'panel-session.c'; then $(CYGPATH_W) 'panel-session.c'; else $(CYGPATH_W) '$(srcdir)/panel-session.c'; fi` + +mate_panel-panel-compatibility.o: panel-compatibility.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-compatibility.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-compatibility.Tpo -c -o mate_panel-panel-compatibility.o `test -f 'panel-compatibility.c' || echo '$(srcdir)/'`panel-compatibility.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-compatibility.Tpo $(DEPDIR)/mate_panel-panel-compatibility.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-compatibility.c' object='mate_panel-panel-compatibility.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-compatibility.o `test -f 'panel-compatibility.c' || echo '$(srcdir)/'`panel-compatibility.c + +mate_panel-panel-compatibility.obj: panel-compatibility.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-compatibility.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-compatibility.Tpo -c -o mate_panel-panel-compatibility.obj `if test -f 'panel-compatibility.c'; then $(CYGPATH_W) 'panel-compatibility.c'; else $(CYGPATH_W) '$(srcdir)/panel-compatibility.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-compatibility.Tpo $(DEPDIR)/mate_panel-panel-compatibility.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-compatibility.c' object='mate_panel-panel-compatibility.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-compatibility.obj `if test -f 'panel-compatibility.c'; then $(CYGPATH_W) 'panel-compatibility.c'; else $(CYGPATH_W) '$(srcdir)/panel-compatibility.c'; fi` + +mate_panel-panel.o: panel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel.o -MD -MP -MF $(DEPDIR)/mate_panel-panel.Tpo -c -o mate_panel-panel.o `test -f 'panel.c' || echo '$(srcdir)/'`panel.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel.Tpo $(DEPDIR)/mate_panel-panel.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel.c' object='mate_panel-panel.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel.o `test -f 'panel.c' || echo '$(srcdir)/'`panel.c + +mate_panel-panel.obj: panel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel.Tpo -c -o mate_panel-panel.obj `if test -f 'panel.c'; then $(CYGPATH_W) 'panel.c'; else $(CYGPATH_W) '$(srcdir)/panel.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel.Tpo $(DEPDIR)/mate_panel-panel.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel.c' object='mate_panel-panel.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel.obj `if test -f 'panel.c'; then $(CYGPATH_W) 'panel.c'; else $(CYGPATH_W) '$(srcdir)/panel.c'; fi` + +mate_panel-applet.o: applet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-applet.o -MD -MP -MF $(DEPDIR)/mate_panel-applet.Tpo -c -o mate_panel-applet.o `test -f 'applet.c' || echo '$(srcdir)/'`applet.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-applet.Tpo $(DEPDIR)/mate_panel-applet.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='applet.c' object='mate_panel-applet.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-applet.o `test -f 'applet.c' || echo '$(srcdir)/'`applet.c + +mate_panel-applet.obj: applet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-applet.obj -MD -MP -MF $(DEPDIR)/mate_panel-applet.Tpo -c -o mate_panel-applet.obj `if test -f 'applet.c'; then $(CYGPATH_W) 'applet.c'; else $(CYGPATH_W) '$(srcdir)/applet.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-applet.Tpo $(DEPDIR)/mate_panel-applet.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='applet.c' object='mate_panel-applet.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-applet.obj `if test -f 'applet.c'; then $(CYGPATH_W) 'applet.c'; else $(CYGPATH_W) '$(srcdir)/applet.c'; fi` + +mate_panel-drawer.o: drawer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-drawer.o -MD -MP -MF $(DEPDIR)/mate_panel-drawer.Tpo -c -o mate_panel-drawer.o `test -f 'drawer.c' || echo '$(srcdir)/'`drawer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-drawer.Tpo $(DEPDIR)/mate_panel-drawer.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='drawer.c' object='mate_panel-drawer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-drawer.o `test -f 'drawer.c' || echo '$(srcdir)/'`drawer.c + +mate_panel-drawer.obj: drawer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-drawer.obj -MD -MP -MF $(DEPDIR)/mate_panel-drawer.Tpo -c -o mate_panel-drawer.obj `if test -f 'drawer.c'; then $(CYGPATH_W) 'drawer.c'; else $(CYGPATH_W) '$(srcdir)/drawer.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-drawer.Tpo $(DEPDIR)/mate_panel-drawer.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='drawer.c' object='mate_panel-drawer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-drawer.obj `if test -f 'drawer.c'; then $(CYGPATH_W) 'drawer.c'; else $(CYGPATH_W) '$(srcdir)/drawer.c'; fi` + +mate_panel-panel-config-global.o: panel-config-global.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-config-global.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-config-global.Tpo -c -o mate_panel-panel-config-global.o `test -f 'panel-config-global.c' || echo '$(srcdir)/'`panel-config-global.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-config-global.Tpo $(DEPDIR)/mate_panel-panel-config-global.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-config-global.c' object='mate_panel-panel-config-global.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-config-global.o `test -f 'panel-config-global.c' || echo '$(srcdir)/'`panel-config-global.c + +mate_panel-panel-config-global.obj: panel-config-global.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-config-global.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-config-global.Tpo -c -o mate_panel-panel-config-global.obj `if test -f 'panel-config-global.c'; then $(CYGPATH_W) 'panel-config-global.c'; else $(CYGPATH_W) '$(srcdir)/panel-config-global.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-config-global.Tpo $(DEPDIR)/mate_panel-panel-config-global.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-config-global.c' object='mate_panel-panel-config-global.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-config-global.obj `if test -f 'panel-config-global.c'; then $(CYGPATH_W) 'panel-config-global.c'; else $(CYGPATH_W) '$(srcdir)/panel-config-global.c'; fi` + +mate_panel-panel-util.o: panel-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-util.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-util.Tpo -c -o mate_panel-panel-util.o `test -f 'panel-util.c' || echo '$(srcdir)/'`panel-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-util.Tpo $(DEPDIR)/mate_panel-panel-util.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-util.c' object='mate_panel-panel-util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-util.o `test -f 'panel-util.c' || echo '$(srcdir)/'`panel-util.c + +mate_panel-panel-util.obj: panel-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-util.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-util.Tpo -c -o mate_panel-panel-util.obj `if test -f 'panel-util.c'; then $(CYGPATH_W) 'panel-util.c'; else $(CYGPATH_W) '$(srcdir)/panel-util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-util.Tpo $(DEPDIR)/mate_panel-panel-util.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-util.c' object='mate_panel-panel-util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-util.obj `if test -f 'panel-util.c'; then $(CYGPATH_W) 'panel-util.c'; else $(CYGPATH_W) '$(srcdir)/panel-util.c'; fi` + +mate_panel-panel-mateconf.o: panel-mateconf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-mateconf.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-mateconf.Tpo -c -o mate_panel-panel-mateconf.o `test -f 'panel-mateconf.c' || echo '$(srcdir)/'`panel-mateconf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-mateconf.Tpo $(DEPDIR)/mate_panel-panel-mateconf.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-mateconf.c' object='mate_panel-panel-mateconf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-mateconf.o `test -f 'panel-mateconf.c' || echo '$(srcdir)/'`panel-mateconf.c + +mate_panel-panel-mateconf.obj: panel-mateconf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-mateconf.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-mateconf.Tpo -c -o mate_panel-panel-mateconf.obj `if test -f 'panel-mateconf.c'; then $(CYGPATH_W) 'panel-mateconf.c'; else $(CYGPATH_W) '$(srcdir)/panel-mateconf.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-mateconf.Tpo $(DEPDIR)/mate_panel-panel-mateconf.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-mateconf.c' object='mate_panel-panel-mateconf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-mateconf.obj `if test -f 'panel-mateconf.c'; then $(CYGPATH_W) 'panel-mateconf.c'; else $(CYGPATH_W) '$(srcdir)/panel-mateconf.c'; fi` + +mate_panel-panel-properties-dialog.o: panel-properties-dialog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-properties-dialog.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-properties-dialog.Tpo -c -o mate_panel-panel-properties-dialog.o `test -f 'panel-properties-dialog.c' || echo '$(srcdir)/'`panel-properties-dialog.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-properties-dialog.Tpo $(DEPDIR)/mate_panel-panel-properties-dialog.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-properties-dialog.c' object='mate_panel-panel-properties-dialog.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-properties-dialog.o `test -f 'panel-properties-dialog.c' || echo '$(srcdir)/'`panel-properties-dialog.c + +mate_panel-panel-properties-dialog.obj: panel-properties-dialog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-properties-dialog.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-properties-dialog.Tpo -c -o mate_panel-panel-properties-dialog.obj `if test -f 'panel-properties-dialog.c'; then $(CYGPATH_W) 'panel-properties-dialog.c'; else $(CYGPATH_W) '$(srcdir)/panel-properties-dialog.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-properties-dialog.Tpo $(DEPDIR)/mate_panel-panel-properties-dialog.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-properties-dialog.c' object='mate_panel-panel-properties-dialog.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-properties-dialog.obj `if test -f 'panel-properties-dialog.c'; then $(CYGPATH_W) 'panel-properties-dialog.c'; else $(CYGPATH_W) '$(srcdir)/panel-properties-dialog.c'; fi` + +mate_panel-panel-run-dialog.o: panel-run-dialog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-run-dialog.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-run-dialog.Tpo -c -o mate_panel-panel-run-dialog.o `test -f 'panel-run-dialog.c' || echo '$(srcdir)/'`panel-run-dialog.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-run-dialog.Tpo $(DEPDIR)/mate_panel-panel-run-dialog.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-run-dialog.c' object='mate_panel-panel-run-dialog.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-run-dialog.o `test -f 'panel-run-dialog.c' || echo '$(srcdir)/'`panel-run-dialog.c + +mate_panel-panel-run-dialog.obj: panel-run-dialog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-run-dialog.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-run-dialog.Tpo -c -o mate_panel-panel-run-dialog.obj `if test -f 'panel-run-dialog.c'; then $(CYGPATH_W) 'panel-run-dialog.c'; else $(CYGPATH_W) '$(srcdir)/panel-run-dialog.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-run-dialog.Tpo $(DEPDIR)/mate_panel-panel-run-dialog.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-run-dialog.c' object='mate_panel-panel-run-dialog.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-run-dialog.obj `if test -f 'panel-run-dialog.c'; then $(CYGPATH_W) 'panel-run-dialog.c'; else $(CYGPATH_W) '$(srcdir)/panel-run-dialog.c'; fi` + +mate_panel-menu.o: menu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-menu.o -MD -MP -MF $(DEPDIR)/mate_panel-menu.Tpo -c -o mate_panel-menu.o `test -f 'menu.c' || echo '$(srcdir)/'`menu.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-menu.Tpo $(DEPDIR)/mate_panel-menu.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='menu.c' object='mate_panel-menu.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-menu.o `test -f 'menu.c' || echo '$(srcdir)/'`menu.c + +mate_panel-menu.obj: menu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-menu.obj -MD -MP -MF $(DEPDIR)/mate_panel-menu.Tpo -c -o mate_panel-menu.obj `if test -f 'menu.c'; then $(CYGPATH_W) 'menu.c'; else $(CYGPATH_W) '$(srcdir)/menu.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-menu.Tpo $(DEPDIR)/mate_panel-menu.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='menu.c' object='mate_panel-menu.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-menu.obj `if test -f 'menu.c'; then $(CYGPATH_W) 'menu.c'; else $(CYGPATH_W) '$(srcdir)/menu.c'; fi` + +mate_panel-panel-context-menu.o: panel-context-menu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-context-menu.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-context-menu.Tpo -c -o mate_panel-panel-context-menu.o `test -f 'panel-context-menu.c' || echo '$(srcdir)/'`panel-context-menu.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-context-menu.Tpo $(DEPDIR)/mate_panel-panel-context-menu.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-context-menu.c' object='mate_panel-panel-context-menu.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-context-menu.o `test -f 'panel-context-menu.c' || echo '$(srcdir)/'`panel-context-menu.c + +mate_panel-panel-context-menu.obj: panel-context-menu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-context-menu.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-context-menu.Tpo -c -o mate_panel-panel-context-menu.obj `if test -f 'panel-context-menu.c'; then $(CYGPATH_W) 'panel-context-menu.c'; else $(CYGPATH_W) '$(srcdir)/panel-context-menu.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-context-menu.Tpo $(DEPDIR)/mate_panel-panel-context-menu.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-context-menu.c' object='mate_panel-panel-context-menu.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-context-menu.obj `if test -f 'panel-context-menu.c'; then $(CYGPATH_W) 'panel-context-menu.c'; else $(CYGPATH_W) '$(srcdir)/panel-context-menu.c'; fi` + +mate_panel-launcher.o: launcher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-launcher.o -MD -MP -MF $(DEPDIR)/mate_panel-launcher.Tpo -c -o mate_panel-launcher.o `test -f 'launcher.c' || echo '$(srcdir)/'`launcher.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-launcher.Tpo $(DEPDIR)/mate_panel-launcher.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launcher.c' object='mate_panel-launcher.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-launcher.o `test -f 'launcher.c' || echo '$(srcdir)/'`launcher.c + +mate_panel-launcher.obj: launcher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-launcher.obj -MD -MP -MF $(DEPDIR)/mate_panel-launcher.Tpo -c -o mate_panel-launcher.obj `if test -f 'launcher.c'; then $(CYGPATH_W) 'launcher.c'; else $(CYGPATH_W) '$(srcdir)/launcher.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-launcher.Tpo $(DEPDIR)/mate_panel-launcher.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='launcher.c' object='mate_panel-launcher.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-launcher.obj `if test -f 'launcher.c'; then $(CYGPATH_W) 'launcher.c'; else $(CYGPATH_W) '$(srcdir)/launcher.c'; fi` + +mate_panel-mate-panel-applet-frame.o: mate-panel-applet-frame.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-mate-panel-applet-frame.o -MD -MP -MF $(DEPDIR)/mate_panel-mate-panel-applet-frame.Tpo -c -o mate_panel-mate-panel-applet-frame.o `test -f 'mate-panel-applet-frame.c' || echo '$(srcdir)/'`mate-panel-applet-frame.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-mate-panel-applet-frame.Tpo $(DEPDIR)/mate_panel-mate-panel-applet-frame.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applet-frame.c' object='mate_panel-mate-panel-applet-frame.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-mate-panel-applet-frame.o `test -f 'mate-panel-applet-frame.c' || echo '$(srcdir)/'`mate-panel-applet-frame.c + +mate_panel-mate-panel-applet-frame.obj: mate-panel-applet-frame.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-mate-panel-applet-frame.obj -MD -MP -MF $(DEPDIR)/mate_panel-mate-panel-applet-frame.Tpo -c -o mate_panel-mate-panel-applet-frame.obj `if test -f 'mate-panel-applet-frame.c'; then $(CYGPATH_W) 'mate-panel-applet-frame.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applet-frame.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-mate-panel-applet-frame.Tpo $(DEPDIR)/mate_panel-mate-panel-applet-frame.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applet-frame.c' object='mate_panel-mate-panel-applet-frame.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-mate-panel-applet-frame.obj `if test -f 'mate-panel-applet-frame.c'; then $(CYGPATH_W) 'mate-panel-applet-frame.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applet-frame.c'; fi` + +mate_panel-mate-panel-applets-manager.o: mate-panel-applets-manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-mate-panel-applets-manager.o -MD -MP -MF $(DEPDIR)/mate_panel-mate-panel-applets-manager.Tpo -c -o mate_panel-mate-panel-applets-manager.o `test -f 'mate-panel-applets-manager.c' || echo '$(srcdir)/'`mate-panel-applets-manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-mate-panel-applets-manager.Tpo $(DEPDIR)/mate_panel-mate-panel-applets-manager.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applets-manager.c' object='mate_panel-mate-panel-applets-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-mate-panel-applets-manager.o `test -f 'mate-panel-applets-manager.c' || echo '$(srcdir)/'`mate-panel-applets-manager.c + +mate_panel-mate-panel-applets-manager.obj: mate-panel-applets-manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-mate-panel-applets-manager.obj -MD -MP -MF $(DEPDIR)/mate_panel-mate-panel-applets-manager.Tpo -c -o mate_panel-mate-panel-applets-manager.obj `if test -f 'mate-panel-applets-manager.c'; then $(CYGPATH_W) 'mate-panel-applets-manager.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applets-manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-mate-panel-applets-manager.Tpo $(DEPDIR)/mate_panel-mate-panel-applets-manager.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applets-manager.c' object='mate_panel-mate-panel-applets-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-mate-panel-applets-manager.obj `if test -f 'mate-panel-applets-manager.c'; then $(CYGPATH_W) 'mate-panel-applets-manager.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applets-manager.c'; fi` + +mate_panel-panel-shell.o: panel-shell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-shell.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-shell.Tpo -c -o mate_panel-panel-shell.o `test -f 'panel-shell.c' || echo '$(srcdir)/'`panel-shell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-shell.Tpo $(DEPDIR)/mate_panel-panel-shell.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-shell.c' object='mate_panel-panel-shell.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-shell.o `test -f 'panel-shell.c' || echo '$(srcdir)/'`panel-shell.c + +mate_panel-panel-shell.obj: panel-shell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-shell.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-shell.Tpo -c -o mate_panel-panel-shell.obj `if test -f 'panel-shell.c'; then $(CYGPATH_W) 'panel-shell.c'; else $(CYGPATH_W) '$(srcdir)/panel-shell.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-shell.Tpo $(DEPDIR)/mate_panel-panel-shell.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-shell.c' object='mate_panel-panel-shell.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-shell.obj `if test -f 'panel-shell.c'; then $(CYGPATH_W) 'panel-shell.c'; else $(CYGPATH_W) '$(srcdir)/panel-shell.c'; fi` + +mate_panel-panel-background.o: panel-background.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-background.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-background.Tpo -c -o mate_panel-panel-background.o `test -f 'panel-background.c' || echo '$(srcdir)/'`panel-background.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-background.Tpo $(DEPDIR)/mate_panel-panel-background.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-background.c' object='mate_panel-panel-background.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-background.o `test -f 'panel-background.c' || echo '$(srcdir)/'`panel-background.c + +mate_panel-panel-background.obj: panel-background.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-background.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-background.Tpo -c -o mate_panel-panel-background.obj `if test -f 'panel-background.c'; then $(CYGPATH_W) 'panel-background.c'; else $(CYGPATH_W) '$(srcdir)/panel-background.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-background.Tpo $(DEPDIR)/mate_panel-panel-background.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-background.c' object='mate_panel-panel-background.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-background.obj `if test -f 'panel-background.c'; then $(CYGPATH_W) 'panel-background.c'; else $(CYGPATH_W) '$(srcdir)/panel-background.c'; fi` + +mate_panel-panel-background-monitor.o: panel-background-monitor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-background-monitor.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-background-monitor.Tpo -c -o mate_panel-panel-background-monitor.o `test -f 'panel-background-monitor.c' || echo '$(srcdir)/'`panel-background-monitor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-background-monitor.Tpo $(DEPDIR)/mate_panel-panel-background-monitor.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-background-monitor.c' object='mate_panel-panel-background-monitor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-background-monitor.o `test -f 'panel-background-monitor.c' || echo '$(srcdir)/'`panel-background-monitor.c + +mate_panel-panel-background-monitor.obj: panel-background-monitor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-background-monitor.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-background-monitor.Tpo -c -o mate_panel-panel-background-monitor.obj `if test -f 'panel-background-monitor.c'; then $(CYGPATH_W) 'panel-background-monitor.c'; else $(CYGPATH_W) '$(srcdir)/panel-background-monitor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-background-monitor.Tpo $(DEPDIR)/mate_panel-panel-background-monitor.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-background-monitor.c' object='mate_panel-panel-background-monitor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-background-monitor.obj `if test -f 'panel-background-monitor.c'; then $(CYGPATH_W) 'panel-background-monitor.c'; else $(CYGPATH_W) '$(srcdir)/panel-background-monitor.c'; fi` + +mate_panel-panel-stock-icons.o: panel-stock-icons.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-stock-icons.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-stock-icons.Tpo -c -o mate_panel-panel-stock-icons.o `test -f 'panel-stock-icons.c' || echo '$(srcdir)/'`panel-stock-icons.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-stock-icons.Tpo $(DEPDIR)/mate_panel-panel-stock-icons.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-stock-icons.c' object='mate_panel-panel-stock-icons.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-stock-icons.o `test -f 'panel-stock-icons.c' || echo '$(srcdir)/'`panel-stock-icons.c + +mate_panel-panel-stock-icons.obj: panel-stock-icons.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-stock-icons.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-stock-icons.Tpo -c -o mate_panel-panel-stock-icons.obj `if test -f 'panel-stock-icons.c'; then $(CYGPATH_W) 'panel-stock-icons.c'; else $(CYGPATH_W) '$(srcdir)/panel-stock-icons.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-stock-icons.Tpo $(DEPDIR)/mate_panel-panel-stock-icons.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-stock-icons.c' object='mate_panel-panel-stock-icons.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-stock-icons.obj `if test -f 'panel-stock-icons.c'; then $(CYGPATH_W) 'panel-stock-icons.c'; else $(CYGPATH_W) '$(srcdir)/panel-stock-icons.c'; fi` + +mate_panel-panel-action-button.o: panel-action-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-action-button.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-action-button.Tpo -c -o mate_panel-panel-action-button.o `test -f 'panel-action-button.c' || echo '$(srcdir)/'`panel-action-button.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-action-button.Tpo $(DEPDIR)/mate_panel-panel-action-button.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-action-button.c' object='mate_panel-panel-action-button.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-action-button.o `test -f 'panel-action-button.c' || echo '$(srcdir)/'`panel-action-button.c + +mate_panel-panel-action-button.obj: panel-action-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-action-button.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-action-button.Tpo -c -o mate_panel-panel-action-button.obj `if test -f 'panel-action-button.c'; then $(CYGPATH_W) 'panel-action-button.c'; else $(CYGPATH_W) '$(srcdir)/panel-action-button.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-action-button.Tpo $(DEPDIR)/mate_panel-panel-action-button.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-action-button.c' object='mate_panel-panel-action-button.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-action-button.obj `if test -f 'panel-action-button.c'; then $(CYGPATH_W) 'panel-action-button.c'; else $(CYGPATH_W) '$(srcdir)/panel-action-button.c'; fi` + +mate_panel-panel-menu-bar.o: panel-menu-bar.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-menu-bar.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-menu-bar.Tpo -c -o mate_panel-panel-menu-bar.o `test -f 'panel-menu-bar.c' || echo '$(srcdir)/'`panel-menu-bar.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-menu-bar.Tpo $(DEPDIR)/mate_panel-panel-menu-bar.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-menu-bar.c' object='mate_panel-panel-menu-bar.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-menu-bar.o `test -f 'panel-menu-bar.c' || echo '$(srcdir)/'`panel-menu-bar.c + +mate_panel-panel-menu-bar.obj: panel-menu-bar.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-menu-bar.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-menu-bar.Tpo -c -o mate_panel-panel-menu-bar.obj `if test -f 'panel-menu-bar.c'; then $(CYGPATH_W) 'panel-menu-bar.c'; else $(CYGPATH_W) '$(srcdir)/panel-menu-bar.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-menu-bar.Tpo $(DEPDIR)/mate_panel-panel-menu-bar.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-menu-bar.c' object='mate_panel-panel-menu-bar.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-menu-bar.obj `if test -f 'panel-menu-bar.c'; then $(CYGPATH_W) 'panel-menu-bar.c'; else $(CYGPATH_W) '$(srcdir)/panel-menu-bar.c'; fi` + +mate_panel-panel-menu-button.o: panel-menu-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-menu-button.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-menu-button.Tpo -c -o mate_panel-panel-menu-button.o `test -f 'panel-menu-button.c' || echo '$(srcdir)/'`panel-menu-button.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-menu-button.Tpo $(DEPDIR)/mate_panel-panel-menu-button.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-menu-button.c' object='mate_panel-panel-menu-button.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-menu-button.o `test -f 'panel-menu-button.c' || echo '$(srcdir)/'`panel-menu-button.c + +mate_panel-panel-menu-button.obj: panel-menu-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-menu-button.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-menu-button.Tpo -c -o mate_panel-panel-menu-button.obj `if test -f 'panel-menu-button.c'; then $(CYGPATH_W) 'panel-menu-button.c'; else $(CYGPATH_W) '$(srcdir)/panel-menu-button.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-menu-button.Tpo $(DEPDIR)/mate_panel-panel-menu-button.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-menu-button.c' object='mate_panel-panel-menu-button.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-menu-button.obj `if test -f 'panel-menu-button.c'; then $(CYGPATH_W) 'panel-menu-button.c'; else $(CYGPATH_W) '$(srcdir)/panel-menu-button.c'; fi` + +mate_panel-panel-menu-items.o: panel-menu-items.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-menu-items.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-menu-items.Tpo -c -o mate_panel-panel-menu-items.o `test -f 'panel-menu-items.c' || echo '$(srcdir)/'`panel-menu-items.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-menu-items.Tpo $(DEPDIR)/mate_panel-panel-menu-items.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-menu-items.c' object='mate_panel-panel-menu-items.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-menu-items.o `test -f 'panel-menu-items.c' || echo '$(srcdir)/'`panel-menu-items.c + +mate_panel-panel-menu-items.obj: panel-menu-items.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-menu-items.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-menu-items.Tpo -c -o mate_panel-panel-menu-items.obj `if test -f 'panel-menu-items.c'; then $(CYGPATH_W) 'panel-menu-items.c'; else $(CYGPATH_W) '$(srcdir)/panel-menu-items.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-menu-items.Tpo $(DEPDIR)/mate_panel-panel-menu-items.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-menu-items.c' object='mate_panel-panel-menu-items.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-menu-items.obj `if test -f 'panel-menu-items.c'; then $(CYGPATH_W) 'panel-menu-items.c'; else $(CYGPATH_W) '$(srcdir)/panel-menu-items.c'; fi` + +mate_panel-panel-separator.o: panel-separator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-separator.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-separator.Tpo -c -o mate_panel-panel-separator.o `test -f 'panel-separator.c' || echo '$(srcdir)/'`panel-separator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-separator.Tpo $(DEPDIR)/mate_panel-panel-separator.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-separator.c' object='mate_panel-panel-separator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-separator.o `test -f 'panel-separator.c' || echo '$(srcdir)/'`panel-separator.c + +mate_panel-panel-separator.obj: panel-separator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-separator.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-separator.Tpo -c -o mate_panel-panel-separator.obj `if test -f 'panel-separator.c'; then $(CYGPATH_W) 'panel-separator.c'; else $(CYGPATH_W) '$(srcdir)/panel-separator.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-separator.Tpo $(DEPDIR)/mate_panel-panel-separator.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-separator.c' object='mate_panel-panel-separator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-separator.obj `if test -f 'panel-separator.c'; then $(CYGPATH_W) 'panel-separator.c'; else $(CYGPATH_W) '$(srcdir)/panel-separator.c'; fi` + +mate_panel-panel-recent.o: panel-recent.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-recent.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-recent.Tpo -c -o mate_panel-panel-recent.o `test -f 'panel-recent.c' || echo '$(srcdir)/'`panel-recent.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-recent.Tpo $(DEPDIR)/mate_panel-panel-recent.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-recent.c' object='mate_panel-panel-recent.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-recent.o `test -f 'panel-recent.c' || echo '$(srcdir)/'`panel-recent.c + +mate_panel-panel-recent.obj: panel-recent.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-recent.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-recent.Tpo -c -o mate_panel-panel-recent.obj `if test -f 'panel-recent.c'; then $(CYGPATH_W) 'panel-recent.c'; else $(CYGPATH_W) '$(srcdir)/panel-recent.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-recent.Tpo $(DEPDIR)/mate_panel-panel-recent.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-recent.c' object='mate_panel-panel-recent.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-recent.obj `if test -f 'panel-recent.c'; then $(CYGPATH_W) 'panel-recent.c'; else $(CYGPATH_W) '$(srcdir)/panel-recent.c'; fi` + +mate_panel-panel-action-protocol.o: panel-action-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-action-protocol.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-action-protocol.Tpo -c -o mate_panel-panel-action-protocol.o `test -f 'panel-action-protocol.c' || echo '$(srcdir)/'`panel-action-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-action-protocol.Tpo $(DEPDIR)/mate_panel-panel-action-protocol.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-action-protocol.c' object='mate_panel-panel-action-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-action-protocol.o `test -f 'panel-action-protocol.c' || echo '$(srcdir)/'`panel-action-protocol.c + +mate_panel-panel-action-protocol.obj: panel-action-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-action-protocol.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-action-protocol.Tpo -c -o mate_panel-panel-action-protocol.obj `if test -f 'panel-action-protocol.c'; then $(CYGPATH_W) 'panel-action-protocol.c'; else $(CYGPATH_W) '$(srcdir)/panel-action-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-action-protocol.Tpo $(DEPDIR)/mate_panel-panel-action-protocol.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-action-protocol.c' object='mate_panel-panel-action-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-action-protocol.obj `if test -f 'panel-action-protocol.c'; then $(CYGPATH_W) 'panel-action-protocol.c'; else $(CYGPATH_W) '$(srcdir)/panel-action-protocol.c'; fi` + +mate_panel-panel-toplevel.o: panel-toplevel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-toplevel.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-toplevel.Tpo -c -o mate_panel-panel-toplevel.o `test -f 'panel-toplevel.c' || echo '$(srcdir)/'`panel-toplevel.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-toplevel.Tpo $(DEPDIR)/mate_panel-panel-toplevel.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-toplevel.c' object='mate_panel-panel-toplevel.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-toplevel.o `test -f 'panel-toplevel.c' || echo '$(srcdir)/'`panel-toplevel.c + +mate_panel-panel-toplevel.obj: panel-toplevel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-toplevel.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-toplevel.Tpo -c -o mate_panel-panel-toplevel.obj `if test -f 'panel-toplevel.c'; then $(CYGPATH_W) 'panel-toplevel.c'; else $(CYGPATH_W) '$(srcdir)/panel-toplevel.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-toplevel.Tpo $(DEPDIR)/mate_panel-panel-toplevel.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-toplevel.c' object='mate_panel-panel-toplevel.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-toplevel.obj `if test -f 'panel-toplevel.c'; then $(CYGPATH_W) 'panel-toplevel.c'; else $(CYGPATH_W) '$(srcdir)/panel-toplevel.c'; fi` + +mate_panel-panel-struts.o: panel-struts.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-struts.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-struts.Tpo -c -o mate_panel-panel-struts.o `test -f 'panel-struts.c' || echo '$(srcdir)/'`panel-struts.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-struts.Tpo $(DEPDIR)/mate_panel-panel-struts.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-struts.c' object='mate_panel-panel-struts.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-struts.o `test -f 'panel-struts.c' || echo '$(srcdir)/'`panel-struts.c + +mate_panel-panel-struts.obj: panel-struts.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-struts.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-struts.Tpo -c -o mate_panel-panel-struts.obj `if test -f 'panel-struts.c'; then $(CYGPATH_W) 'panel-struts.c'; else $(CYGPATH_W) '$(srcdir)/panel-struts.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-struts.Tpo $(DEPDIR)/mate_panel-panel-struts.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-struts.c' object='mate_panel-panel-struts.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-struts.obj `if test -f 'panel-struts.c'; then $(CYGPATH_W) 'panel-struts.c'; else $(CYGPATH_W) '$(srcdir)/panel-struts.c'; fi` + +mate_panel-panel-frame.o: panel-frame.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-frame.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-frame.Tpo -c -o mate_panel-panel-frame.o `test -f 'panel-frame.c' || echo '$(srcdir)/'`panel-frame.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-frame.Tpo $(DEPDIR)/mate_panel-panel-frame.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-frame.c' object='mate_panel-panel-frame.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-frame.o `test -f 'panel-frame.c' || echo '$(srcdir)/'`panel-frame.c + +mate_panel-panel-frame.obj: panel-frame.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-frame.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-frame.Tpo -c -o mate_panel-panel-frame.obj `if test -f 'panel-frame.c'; then $(CYGPATH_W) 'panel-frame.c'; else $(CYGPATH_W) '$(srcdir)/panel-frame.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-frame.Tpo $(DEPDIR)/mate_panel-panel-frame.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-frame.c' object='mate_panel-panel-frame.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-frame.obj `if test -f 'panel-frame.c'; then $(CYGPATH_W) 'panel-frame.c'; else $(CYGPATH_W) '$(srcdir)/panel-frame.c'; fi` + +mate_panel-panel-xutils.o: panel-xutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-xutils.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-xutils.Tpo -c -o mate_panel-panel-xutils.o `test -f 'panel-xutils.c' || echo '$(srcdir)/'`panel-xutils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-xutils.Tpo $(DEPDIR)/mate_panel-panel-xutils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-xutils.c' object='mate_panel-panel-xutils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-xutils.o `test -f 'panel-xutils.c' || echo '$(srcdir)/'`panel-xutils.c + +mate_panel-panel-xutils.obj: panel-xutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-xutils.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-xutils.Tpo -c -o mate_panel-panel-xutils.obj `if test -f 'panel-xutils.c'; then $(CYGPATH_W) 'panel-xutils.c'; else $(CYGPATH_W) '$(srcdir)/panel-xutils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-xutils.Tpo $(DEPDIR)/mate_panel-panel-xutils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-xutils.c' object='mate_panel-panel-xutils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-xutils.obj `if test -f 'panel-xutils.c'; then $(CYGPATH_W) 'panel-xutils.c'; else $(CYGPATH_W) '$(srcdir)/panel-xutils.c'; fi` + +mate_panel-panel-multiscreen.o: panel-multiscreen.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-multiscreen.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-multiscreen.Tpo -c -o mate_panel-panel-multiscreen.o `test -f 'panel-multiscreen.c' || echo '$(srcdir)/'`panel-multiscreen.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-multiscreen.Tpo $(DEPDIR)/mate_panel-panel-multiscreen.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-multiscreen.c' object='mate_panel-panel-multiscreen.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-multiscreen.o `test -f 'panel-multiscreen.c' || echo '$(srcdir)/'`panel-multiscreen.c + +mate_panel-panel-multiscreen.obj: panel-multiscreen.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-multiscreen.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-multiscreen.Tpo -c -o mate_panel-panel-multiscreen.obj `if test -f 'panel-multiscreen.c'; then $(CYGPATH_W) 'panel-multiscreen.c'; else $(CYGPATH_W) '$(srcdir)/panel-multiscreen.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-multiscreen.Tpo $(DEPDIR)/mate_panel-panel-multiscreen.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-multiscreen.c' object='mate_panel-panel-multiscreen.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-multiscreen.obj `if test -f 'panel-multiscreen.c'; then $(CYGPATH_W) 'panel-multiscreen.c'; else $(CYGPATH_W) '$(srcdir)/panel-multiscreen.c'; fi` + +mate_panel-panel-a11y.o: panel-a11y.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-a11y.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-a11y.Tpo -c -o mate_panel-panel-a11y.o `test -f 'panel-a11y.c' || echo '$(srcdir)/'`panel-a11y.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-a11y.Tpo $(DEPDIR)/mate_panel-panel-a11y.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-a11y.c' object='mate_panel-panel-a11y.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-a11y.o `test -f 'panel-a11y.c' || echo '$(srcdir)/'`panel-a11y.c + +mate_panel-panel-a11y.obj: panel-a11y.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-a11y.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-a11y.Tpo -c -o mate_panel-panel-a11y.obj `if test -f 'panel-a11y.c'; then $(CYGPATH_W) 'panel-a11y.c'; else $(CYGPATH_W) '$(srcdir)/panel-a11y.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-a11y.Tpo $(DEPDIR)/mate_panel-panel-a11y.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-a11y.c' object='mate_panel-panel-a11y.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-a11y.obj `if test -f 'panel-a11y.c'; then $(CYGPATH_W) 'panel-a11y.c'; else $(CYGPATH_W) '$(srcdir)/panel-a11y.c'; fi` + +mate_panel-panel-bindings.o: panel-bindings.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-bindings.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-bindings.Tpo -c -o mate_panel-panel-bindings.o `test -f 'panel-bindings.c' || echo '$(srcdir)/'`panel-bindings.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-bindings.Tpo $(DEPDIR)/mate_panel-panel-bindings.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-bindings.c' object='mate_panel-panel-bindings.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-bindings.o `test -f 'panel-bindings.c' || echo '$(srcdir)/'`panel-bindings.c + +mate_panel-panel-bindings.obj: panel-bindings.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-bindings.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-bindings.Tpo -c -o mate_panel-panel-bindings.obj `if test -f 'panel-bindings.c'; then $(CYGPATH_W) 'panel-bindings.c'; else $(CYGPATH_W) '$(srcdir)/panel-bindings.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-bindings.Tpo $(DEPDIR)/mate_panel-panel-bindings.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-bindings.c' object='mate_panel-panel-bindings.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-bindings.obj `if test -f 'panel-bindings.c'; then $(CYGPATH_W) 'panel-bindings.c'; else $(CYGPATH_W) '$(srcdir)/panel-bindings.c'; fi` + +mate_panel-panel-profile.o: panel-profile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-profile.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-profile.Tpo -c -o mate_panel-panel-profile.o `test -f 'panel-profile.c' || echo '$(srcdir)/'`panel-profile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-profile.Tpo $(DEPDIR)/mate_panel-panel-profile.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-profile.c' object='mate_panel-panel-profile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-profile.o `test -f 'panel-profile.c' || echo '$(srcdir)/'`panel-profile.c + +mate_panel-panel-profile.obj: panel-profile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-profile.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-profile.Tpo -c -o mate_panel-panel-profile.obj `if test -f 'panel-profile.c'; then $(CYGPATH_W) 'panel-profile.c'; else $(CYGPATH_W) '$(srcdir)/panel-profile.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-profile.Tpo $(DEPDIR)/mate_panel-panel-profile.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-profile.c' object='mate_panel-panel-profile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-profile.obj `if test -f 'panel-profile.c'; then $(CYGPATH_W) 'panel-profile.c'; else $(CYGPATH_W) '$(srcdir)/panel-profile.c'; fi` + +mate_panel-panel-force-quit.o: panel-force-quit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-force-quit.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-force-quit.Tpo -c -o mate_panel-panel-force-quit.o `test -f 'panel-force-quit.c' || echo '$(srcdir)/'`panel-force-quit.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-force-quit.Tpo $(DEPDIR)/mate_panel-panel-force-quit.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-force-quit.c' object='mate_panel-panel-force-quit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-force-quit.o `test -f 'panel-force-quit.c' || echo '$(srcdir)/'`panel-force-quit.c + +mate_panel-panel-force-quit.obj: panel-force-quit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-force-quit.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-force-quit.Tpo -c -o mate_panel-panel-force-quit.obj `if test -f 'panel-force-quit.c'; then $(CYGPATH_W) 'panel-force-quit.c'; else $(CYGPATH_W) '$(srcdir)/panel-force-quit.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-force-quit.Tpo $(DEPDIR)/mate_panel-panel-force-quit.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-force-quit.c' object='mate_panel-panel-force-quit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-force-quit.obj `if test -f 'panel-force-quit.c'; then $(CYGPATH_W) 'panel-force-quit.c'; else $(CYGPATH_W) '$(srcdir)/panel-force-quit.c'; fi` + +mate_panel-panel-lockdown.o: panel-lockdown.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-lockdown.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-lockdown.Tpo -c -o mate_panel-panel-lockdown.o `test -f 'panel-lockdown.c' || echo '$(srcdir)/'`panel-lockdown.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-lockdown.Tpo $(DEPDIR)/mate_panel-panel-lockdown.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-lockdown.c' object='mate_panel-panel-lockdown.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-lockdown.o `test -f 'panel-lockdown.c' || echo '$(srcdir)/'`panel-lockdown.c + +mate_panel-panel-lockdown.obj: panel-lockdown.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-lockdown.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-lockdown.Tpo -c -o mate_panel-panel-lockdown.obj `if test -f 'panel-lockdown.c'; then $(CYGPATH_W) 'panel-lockdown.c'; else $(CYGPATH_W) '$(srcdir)/panel-lockdown.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-lockdown.Tpo $(DEPDIR)/mate_panel-panel-lockdown.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-lockdown.c' object='mate_panel-panel-lockdown.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-lockdown.obj `if test -f 'panel-lockdown.c'; then $(CYGPATH_W) 'panel-lockdown.c'; else $(CYGPATH_W) '$(srcdir)/panel-lockdown.c'; fi` + +mate_panel-panel-addto.o: panel-addto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-addto.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-addto.Tpo -c -o mate_panel-panel-addto.o `test -f 'panel-addto.c' || echo '$(srcdir)/'`panel-addto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-addto.Tpo $(DEPDIR)/mate_panel-panel-addto.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-addto.c' object='mate_panel-panel-addto.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-addto.o `test -f 'panel-addto.c' || echo '$(srcdir)/'`panel-addto.c + +mate_panel-panel-addto.obj: panel-addto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-addto.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-addto.Tpo -c -o mate_panel-panel-addto.obj `if test -f 'panel-addto.c'; then $(CYGPATH_W) 'panel-addto.c'; else $(CYGPATH_W) '$(srcdir)/panel-addto.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-addto.Tpo $(DEPDIR)/mate_panel-panel-addto.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-addto.c' object='mate_panel-panel-addto.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-addto.obj `if test -f 'panel-addto.c'; then $(CYGPATH_W) 'panel-addto.c'; else $(CYGPATH_W) '$(srcdir)/panel-addto.c'; fi` + +mate_panel-panel-ditem-editor.o: panel-ditem-editor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-ditem-editor.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-ditem-editor.Tpo -c -o mate_panel-panel-ditem-editor.o `test -f 'panel-ditem-editor.c' || echo '$(srcdir)/'`panel-ditem-editor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-ditem-editor.Tpo $(DEPDIR)/mate_panel-panel-ditem-editor.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-ditem-editor.c' object='mate_panel-panel-ditem-editor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-ditem-editor.o `test -f 'panel-ditem-editor.c' || echo '$(srcdir)/'`panel-ditem-editor.c + +mate_panel-panel-ditem-editor.obj: panel-ditem-editor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-ditem-editor.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-ditem-editor.Tpo -c -o mate_panel-panel-ditem-editor.obj `if test -f 'panel-ditem-editor.c'; then $(CYGPATH_W) 'panel-ditem-editor.c'; else $(CYGPATH_W) '$(srcdir)/panel-ditem-editor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-ditem-editor.Tpo $(DEPDIR)/mate_panel-panel-ditem-editor.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-ditem-editor.c' object='mate_panel-panel-ditem-editor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-ditem-editor.obj `if test -f 'panel-ditem-editor.c'; then $(CYGPATH_W) 'panel-ditem-editor.c'; else $(CYGPATH_W) '$(srcdir)/panel-ditem-editor.c'; fi` + +mate_panel-panel-modules.o: panel-modules.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-modules.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-modules.Tpo -c -o mate_panel-panel-modules.o `test -f 'panel-modules.c' || echo '$(srcdir)/'`panel-modules.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-modules.Tpo $(DEPDIR)/mate_panel-panel-modules.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-modules.c' object='mate_panel-panel-modules.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-modules.o `test -f 'panel-modules.c' || echo '$(srcdir)/'`panel-modules.c + +mate_panel-panel-modules.obj: panel-modules.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-modules.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-modules.Tpo -c -o mate_panel-panel-modules.obj `if test -f 'panel-modules.c'; then $(CYGPATH_W) 'panel-modules.c'; else $(CYGPATH_W) '$(srcdir)/panel-modules.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-modules.Tpo $(DEPDIR)/mate_panel-panel-modules.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-modules.c' object='mate_panel-panel-modules.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-modules.obj `if test -f 'panel-modules.c'; then $(CYGPATH_W) 'panel-modules.c'; else $(CYGPATH_W) '$(srcdir)/panel-modules.c'; fi` + +mate_panel-mate-panel-applet-info.o: mate-panel-applet-info.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-mate-panel-applet-info.o -MD -MP -MF $(DEPDIR)/mate_panel-mate-panel-applet-info.Tpo -c -o mate_panel-mate-panel-applet-info.o `test -f 'mate-panel-applet-info.c' || echo '$(srcdir)/'`mate-panel-applet-info.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-mate-panel-applet-info.Tpo $(DEPDIR)/mate_panel-mate-panel-applet-info.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applet-info.c' object='mate_panel-mate-panel-applet-info.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-mate-panel-applet-info.o `test -f 'mate-panel-applet-info.c' || echo '$(srcdir)/'`mate-panel-applet-info.c + +mate_panel-mate-panel-applet-info.obj: mate-panel-applet-info.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-mate-panel-applet-info.obj -MD -MP -MF $(DEPDIR)/mate_panel-mate-panel-applet-info.Tpo -c -o mate_panel-mate-panel-applet-info.obj `if test -f 'mate-panel-applet-info.c'; then $(CYGPATH_W) 'mate-panel-applet-info.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applet-info.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-mate-panel-applet-info.Tpo $(DEPDIR)/mate_panel-mate-panel-applet-info.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applet-info.c' object='mate_panel-mate-panel-applet-info.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-mate-panel-applet-info.obj `if test -f 'mate-panel-applet-info.c'; then $(CYGPATH_W) 'mate-panel-applet-info.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applet-info.c'; fi` + +mate_panel-panel-reset.o: panel-reset.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-reset.o -MD -MP -MF $(DEPDIR)/mate_panel-panel-reset.Tpo -c -o mate_panel-panel-reset.o `test -f 'panel-reset.c' || echo '$(srcdir)/'`panel-reset.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-reset.Tpo $(DEPDIR)/mate_panel-panel-reset.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-reset.c' object='mate_panel-panel-reset.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-reset.o `test -f 'panel-reset.c' || echo '$(srcdir)/'`panel-reset.c + +mate_panel-panel-reset.obj: panel-reset.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel-panel-reset.obj -MD -MP -MF $(DEPDIR)/mate_panel-panel-reset.Tpo -c -o mate_panel-panel-reset.obj `if test -f 'panel-reset.c'; then $(CYGPATH_W) 'panel-reset.c'; else $(CYGPATH_W) '$(srcdir)/panel-reset.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel-panel-reset.Tpo $(DEPDIR)/mate_panel-panel-reset.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-reset.c' object='mate_panel-panel-reset.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel-panel-reset.obj `if test -f 'panel-reset.c'; then $(CYGPATH_W) 'panel-reset.c'; else $(CYGPATH_W) '$(srcdir)/panel-reset.c'; fi` + +mate_panel_test_applets-panel-modules.o: panel-modules.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-panel-modules.o -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-panel-modules.Tpo -c -o mate_panel_test_applets-panel-modules.o `test -f 'panel-modules.c' || echo '$(srcdir)/'`panel-modules.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-panel-modules.Tpo $(DEPDIR)/mate_panel_test_applets-panel-modules.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-modules.c' object='mate_panel_test_applets-panel-modules.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-panel-modules.o `test -f 'panel-modules.c' || echo '$(srcdir)/'`panel-modules.c + +mate_panel_test_applets-panel-modules.obj: panel-modules.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-panel-modules.obj -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-panel-modules.Tpo -c -o mate_panel_test_applets-panel-modules.obj `if test -f 'panel-modules.c'; then $(CYGPATH_W) 'panel-modules.c'; else $(CYGPATH_W) '$(srcdir)/panel-modules.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-panel-modules.Tpo $(DEPDIR)/mate_panel_test_applets-panel-modules.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-modules.c' object='mate_panel_test_applets-panel-modules.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-panel-modules.obj `if test -f 'panel-modules.c'; then $(CYGPATH_W) 'panel-modules.c'; else $(CYGPATH_W) '$(srcdir)/panel-modules.c'; fi` + +mate_panel_test_applets-mate-panel-applet-info.o: mate-panel-applet-info.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-mate-panel-applet-info.o -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Tpo -c -o mate_panel_test_applets-mate-panel-applet-info.o `test -f 'mate-panel-applet-info.c' || echo '$(srcdir)/'`mate-panel-applet-info.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Tpo $(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applet-info.c' object='mate_panel_test_applets-mate-panel-applet-info.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-mate-panel-applet-info.o `test -f 'mate-panel-applet-info.c' || echo '$(srcdir)/'`mate-panel-applet-info.c + +mate_panel_test_applets-mate-panel-applet-info.obj: mate-panel-applet-info.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-mate-panel-applet-info.obj -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Tpo -c -o mate_panel_test_applets-mate-panel-applet-info.obj `if test -f 'mate-panel-applet-info.c'; then $(CYGPATH_W) 'mate-panel-applet-info.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applet-info.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Tpo $(DEPDIR)/mate_panel_test_applets-mate-panel-applet-info.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applet-info.c' object='mate_panel_test_applets-mate-panel-applet-info.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-mate-panel-applet-info.obj `if test -f 'mate-panel-applet-info.c'; then $(CYGPATH_W) 'mate-panel-applet-info.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applet-info.c'; fi` + +mate_panel_test_applets-mate-panel-applets-manager.o: mate-panel-applets-manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-mate-panel-applets-manager.o -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Tpo -c -o mate_panel_test_applets-mate-panel-applets-manager.o `test -f 'mate-panel-applets-manager.c' || echo '$(srcdir)/'`mate-panel-applets-manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Tpo $(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applets-manager.c' object='mate_panel_test_applets-mate-panel-applets-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-mate-panel-applets-manager.o `test -f 'mate-panel-applets-manager.c' || echo '$(srcdir)/'`mate-panel-applets-manager.c + +mate_panel_test_applets-mate-panel-applets-manager.obj: mate-panel-applets-manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-mate-panel-applets-manager.obj -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Tpo -c -o mate_panel_test_applets-mate-panel-applets-manager.obj `if test -f 'mate-panel-applets-manager.c'; then $(CYGPATH_W) 'mate-panel-applets-manager.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applets-manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Tpo $(DEPDIR)/mate_panel_test_applets-mate-panel-applets-manager.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mate-panel-applets-manager.c' object='mate_panel_test_applets-mate-panel-applets-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-mate-panel-applets-manager.obj `if test -f 'mate-panel-applets-manager.c'; then $(CYGPATH_W) 'mate-panel-applets-manager.c'; else $(CYGPATH_W) '$(srcdir)/mate-panel-applets-manager.c'; fi` + +mate_panel_test_applets-panel-marshal.o: panel-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-panel-marshal.o -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-panel-marshal.Tpo -c -o mate_panel_test_applets-panel-marshal.o `test -f 'panel-marshal.c' || echo '$(srcdir)/'`panel-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-panel-marshal.Tpo $(DEPDIR)/mate_panel_test_applets-panel-marshal.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-marshal.c' object='mate_panel_test_applets-panel-marshal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-panel-marshal.o `test -f 'panel-marshal.c' || echo '$(srcdir)/'`panel-marshal.c + +mate_panel_test_applets-panel-marshal.obj: panel-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-panel-marshal.obj -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-panel-marshal.Tpo -c -o mate_panel_test_applets-panel-marshal.obj `if test -f 'panel-marshal.c'; then $(CYGPATH_W) 'panel-marshal.c'; else $(CYGPATH_W) '$(srcdir)/panel-marshal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-panel-marshal.Tpo $(DEPDIR)/mate_panel_test_applets-panel-marshal.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-marshal.c' object='mate_panel_test_applets-panel-marshal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-panel-marshal.obj `if test -f 'panel-marshal.c'; then $(CYGPATH_W) 'panel-marshal.c'; else $(CYGPATH_W) '$(srcdir)/panel-marshal.c'; fi` + +mate_panel_test_applets-panel-test-applets.o: panel-test-applets.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-panel-test-applets.o -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-panel-test-applets.Tpo -c -o mate_panel_test_applets-panel-test-applets.o `test -f 'panel-test-applets.c' || echo '$(srcdir)/'`panel-test-applets.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-panel-test-applets.Tpo $(DEPDIR)/mate_panel_test_applets-panel-test-applets.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-test-applets.c' object='mate_panel_test_applets-panel-test-applets.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-panel-test-applets.o `test -f 'panel-test-applets.c' || echo '$(srcdir)/'`panel-test-applets.c + +mate_panel_test_applets-panel-test-applets.obj: panel-test-applets.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_panel_test_applets-panel-test-applets.obj -MD -MP -MF $(DEPDIR)/mate_panel_test_applets-panel-test-applets.Tpo -c -o mate_panel_test_applets-panel-test-applets.obj `if test -f 'panel-test-applets.c'; then $(CYGPATH_W) 'panel-test-applets.c'; else $(CYGPATH_W) '$(srcdir)/panel-test-applets.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_panel_test_applets-panel-test-applets.Tpo $(DEPDIR)/mate_panel_test_applets-panel-test-applets.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='panel-test-applets.c' object='mate_panel_test_applets-panel-test-applets.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_panel_test_applets_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_panel_test_applets-panel-test-applets.obj `if test -f 'panel-test-applets.c'; then $(CYGPATH_W) 'panel-test-applets.c'; else $(CYGPATH_W) '$(srcdir)/panel-test-applets.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-desktopDATA: $(desktop_DATA) + @$(NORMAL_INSTALL) + test -z "$(desktopdir)" || $(MKDIR_P) "$(DESTDIR)$(desktopdir)" + @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(desktopdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(desktopdir)" || exit $$?; \ + done + +uninstall-desktopDATA: + @$(NORMAL_UNINSTALL) + @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(desktopdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(desktopdir)" && rm -f $$files +install-entriesDATA: $(entries_DATA) + @$(NORMAL_INSTALL) + test -z "$(entriesdir)" || $(MKDIR_P) "$(DESTDIR)$(entriesdir)" + @list='$(entries_DATA)'; test -n "$(entriesdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(entriesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(entriesdir)" || exit $$?; \ + done + +uninstall-entriesDATA: + @$(NORMAL_UNINSTALL) + @list='$(entries_DATA)'; test -n "$(entriesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(entriesdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(entriesdir)" && rm -f $$files +install-rcDATA: $(rc_DATA) + @$(NORMAL_INSTALL) + test -z "$(rcdir)" || $(MKDIR_P) "$(DESTDIR)$(rcdir)" + @list='$(rc_DATA)'; test -n "$(rcdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(rcdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(rcdir)" || exit $$?; \ + done + +uninstall-rcDATA: + @$(NORMAL_UNINSTALL) + @list='$(rc_DATA)'; test -n "$(rcdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(rcdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(rcdir)" && rm -f $$files +install-schemasDATA: $(schemas_DATA) + @$(NORMAL_INSTALL) + test -z "$(schemasdir)" || $(MKDIR_P) "$(DESTDIR)$(schemasdir)" + @list='$(schemas_DATA)'; test -n "$(schemasdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(schemasdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(schemasdir)" || exit $$?; \ + done + +uninstall-schemasDATA: + @$(NORMAL_UNINSTALL) + @list='$(schemas_DATA)'; test -n "$(schemasdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(schemasdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(schemasdir)" && rm -f $$files +install-uiDATA: $(ui_DATA) + @$(NORMAL_INSTALL) + test -z "$(uidir)" || $(MKDIR_P) "$(DESTDIR)$(uidir)" + @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(uidir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(uidir)" || exit $$?; \ + done + +uninstall-uiDATA: + @$(NORMAL_UNINSTALL) + @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(uidir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(uidir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(entriesdir)" "$(DESTDIR)$(rcdir)" "$(DESTDIR)$(schemasdir)" "$(DESTDIR)$(uidir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +@MATECONF_SCHEMAS_INSTALL_FALSE@uninstall-local: +@MATECONF_SCHEMAS_INSTALL_FALSE@install-data-local: +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-data-local install-desktopDATA \ + install-entriesDATA install-rcDATA install-schemasDATA \ + install-uiDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libexecSCRIPTS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-desktopDATA \ + uninstall-entriesDATA uninstall-libexecSCRIPTS uninstall-local \ + uninstall-rcDATA uninstall-schemasDATA uninstall-uiDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \ + ctags-recursive install install-am install-strip \ + tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags ctags-recursive dist-hook \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-data-local \ + install-desktopDATA install-dvi install-dvi-am \ + install-entriesDATA install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libexecSCRIPTS install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-rcDATA install-schemasDATA \ + install-strip install-uiDATA installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-desktopDATA \ + uninstall-entriesDATA uninstall-libexecSCRIPTS uninstall-local \ + uninstall-rcDATA uninstall-schemasDATA uninstall-uiDATA + + +mate-panel-add: mate-panel-add.in Makefile + $(AM_V_GEN)sed \ + -e s!\@PYTHON\@!@PYTHON@! \ + -e s!\@MATE_PANEL_APPLETS_DIR\@!$(appletsdir)! \ + < $< > $@ + $(AM_V_at)chmod a+x $@ + +panel-marshal.h: panel-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --header --prefix=panel_marshal > $@ + +panel-marshal.c: panel-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN)echo "#include \"panel-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=panel_marshal >> $@ + +panel-typebuiltins.c: @REBUILD@ $(panel_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#include \n" \ + --fhead "#include \"panel-typebuiltins.h\"\n\n" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --fprod "\n#include \"@filename@\"\n" \ + --vhead "static const GEnumValue _@enum_name@_values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n};\n\n" \ + --vtail "GType\n@enum_name@_get_type (void)\n{\n" \ + --vtail " static GType type = 0;\n\n" \ + --vtail " if (!type)\n" \ + --vtail " type = g_enum_register_static (\"@EnumName@\", _@enum_name@_values);\n\n" \ + --vtail " return type;\n}\n\n" \ + $(panel_enum_headers) > $@ + +panel-typebuiltins.h: @REBUILD@ $(panel_enum_headers) + $(AM_V_GEN)glib-mkenums \ + --fhead "#ifndef __PANEL_TYPEBUILTINS_H__\n" \ + --fhead "#define __PANEL_TYPEBUILTINS_H__ 1\n\n" \ + --fhead "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n" \ + --ftail "#ifdef __cplusplus\n}\n#endif\n\n" \ + --ftail "#endif /* __PANEL_TYPEBUILTINS_H__ */\n" \ + --fprod "\n/* --- @filename@ --- */" \ + --eprod "#define PANEL_TYPE_@ENUMSHORT@ @enum_name@_get_type()\n" \ + --eprod "GType @enum_name@_get_type (void);\n" \ + $(panel_enum_headers) > $@ + +@INTLTOOL_DESKTOP_RULE@ + +@INTLTOOL_SCHEMAS_RULE@ + +@MATECONF_SCHEMAS_INSTALL_TRUE@install-data-local: +@MATECONF_SCHEMAS_INSTALL_TRUE@ if test -z "$(DESTDIR)" ; then \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ for p in $(schemas_DATA) ; do \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $(top_builddir)/mate-panel/$$p ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ done ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ $(MATECONFTOOL) --direct --config-source=$(MATECONF_SCHEMA_CONFIG_SOURCE) --load $(srcdir)/panel-default-setup.entries ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ $(MATECONFTOOL) --direct --config-source=$(MATECONF_SCHEMA_CONFIG_SOURCE) --load $(srcdir)/panel-default-setup.entries /apps/panel ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ fi +@MATECONF_SCHEMAS_INSTALL_TRUE@uninstall-local: +@MATECONF_SCHEMAS_INSTALL_TRUE@ for p in $(schema_DATA) ; do \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-uninstall-rule $(top_builddir)/applets/ngome-panel/$$p ; \ +@MATECONF_SCHEMAS_INSTALL_TRUE@ done + +dist-hook: + cd $(distdir) ; rm -f $(CLEANFILES) + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mate-panel/applet.c b/mate-panel/applet.c new file mode 100644 index 00000000..e20e1faa --- /dev/null +++ b/mate-panel/applet.c @@ -0,0 +1,1449 @@ +/* Mate panel: general applet functionality + * (C) 1997 the Free Software Foundation + * + * Authors: George Lebl + * Federico Mena + * Miguel de Icaza + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "button-widget.h" +#include "drawer.h" +#include "launcher.h" +#include "panel-addto.h" +#include "panel-mateconf.h" +#include "panel-config-global.h" +#include "mate-panel-applet-frame.h" +#include "panel-action-button.h" +#include "panel-menu-bar.h" +#include "panel-separator.h" +#include "panel-compatibility.h" +#include "panel-toplevel.h" +#include "panel-util.h" +#include "panel-profile.h" +#include "panel-menu-button.h" +#include "panel-globals.h" +#include "panel-properties-dialog.h" +#include "panel-lockdown.h" + +#define SMALL_ICON_SIZE 20 + +static GSList *registered_applets = NULL; +static GSList *queued_position_saves = NULL; +static guint queued_position_source = 0; + + +static inline PanelWidget * +mate_panel_applet_get_panel_widget (AppletInfo *info) +{ + return PANEL_WIDGET (gtk_widget_get_parent (info->widget)); +} + +static void +mate_panel_applet_set_dnd_enabled (AppletInfo *info, + gboolean dnd_enabled) +{ + switch (info->type) { + case PANEL_OBJECT_DRAWER: + panel_drawer_set_dnd_enabled (info->data, dnd_enabled); + break; + case PANEL_OBJECT_MENU: + panel_menu_button_set_dnd_enabled (PANEL_MENU_BUTTON (info->widget), + dnd_enabled); + break; + case PANEL_OBJECT_LAUNCHER: + panel_launcher_set_dnd_enabled (info->data, dnd_enabled); + break; + case PANEL_OBJECT_APPLET: + break; + case PANEL_OBJECT_LOGOUT: + case PANEL_OBJECT_LOCK: + case PANEL_OBJECT_ACTION: + panel_action_button_set_dnd_enabled (PANEL_ACTION_BUTTON (info->widget), + dnd_enabled); + break; + case PANEL_OBJECT_MENU_BAR: + case PANEL_OBJECT_SEPARATOR: + break; + default: + g_assert_not_reached (); + break; + } + +} + +gboolean +mate_panel_applet_toggle_locked (AppletInfo *info) +{ + PanelWidget *panel_widget; + gboolean locked; + + panel_widget = mate_panel_applet_get_panel_widget (info); + + locked = panel_widget_toggle_applet_locked (panel_widget, info->widget); + + mate_panel_applet_save_position (info, info->id, TRUE); + mate_panel_applet_set_dnd_enabled (info, !locked); + + return locked; +} + +static void +mate_panel_applet_lock (GtkCheckMenuItem *menuitem, + AppletInfo *info) +{ + gboolean locked; + + locked = mate_panel_applet_toggle_locked (info); + + gtk_check_menu_item_set_active (menuitem, locked); + + if (info->move_item) + gtk_widget_set_sensitive (info->move_item, !locked); +} + +static void +move_applet_callback (GtkWidget *widget, AppletInfo *info) +{ + GtkWidget *parent; + PanelWidget *panel; + + g_return_if_fail (info != NULL); + g_return_if_fail (info->widget != NULL); + + parent = gtk_widget_get_parent (info->widget); + + g_return_if_fail (parent != NULL); + g_return_if_fail (PANEL_IS_WIDGET (parent)); + + panel = PANEL_WIDGET (parent); + + panel_widget_applet_drag_start (panel, info->widget, + PW_DRAG_OFF_CENTER, + GDK_CURRENT_TIME); +} + +/* permanently remove an applet - all non-permanent + * cleanups should go in mate_panel_applet_destroy() + */ +void +mate_panel_applet_clean (AppletInfo *info) +{ + g_return_if_fail (info != NULL); + + if (info->type == PANEL_OBJECT_LAUNCHER) + panel_launcher_delete (info->data); + + if (info->widget) { + GtkWidget *widget = info->widget; + + info->widget = NULL; + gtk_widget_destroy (widget); + } +} + +static void +mate_panel_applet_recreate_menu (AppletInfo *info) +{ + GList *l; + + if (!info->menu) + return; + + for (l = info->user_menu; l; l = l->next) { + AppletUserMenu *menu = l->data; + + menu->menuitem =NULL; + menu->submenu =NULL; + } + + g_object_unref (info->menu); + info->menu = mate_panel_applet_create_menu (info); +} + +static void +mate_panel_applet_locked_change_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + GtkWidget *applet) +{ + MateConfValue *value; + gboolean locked; + gboolean applet_locked; + AppletInfo *info; + PanelWidget *panel_widget; + + g_assert (applet != NULL); + + info = (AppletInfo *) g_object_get_data (G_OBJECT (applet), + "applet_info"); + if (info == NULL) + return; + + value = mateconf_entry_get_value (entry); + if (value == NULL || value->type != MATECONF_VALUE_BOOL) + return; + + locked = mateconf_value_get_bool (value); + + panel_widget = mate_panel_applet_get_panel_widget (info); + applet_locked = panel_widget_get_applet_locked (panel_widget, + info->widget); + + if ((locked && applet_locked) || !(locked || applet_locked)) + return; + + mate_panel_applet_toggle_locked (info); + + if (info->type == PANEL_OBJECT_APPLET) + mate_panel_applet_frame_sync_menu_state (MATE_PANEL_APPLET_FRAME (info->widget)); + else + mate_panel_applet_recreate_menu (info); +} + +static void +applet_remove_callback (GtkWidget *widget, + AppletInfo *info) +{ + + if (info->type == PANEL_OBJECT_DRAWER) + drawer_query_deletion (info->data); + else + panel_profile_delete_object (info); +} + +static inline GdkScreen * +applet_user_menu_get_screen (AppletUserMenu *menu) +{ + PanelWidget *panel_widget; + + panel_widget = mate_panel_applet_get_panel_widget (menu->info); + + return gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel)); +} + +static void +applet_callback_callback (GtkWidget *widget, + AppletUserMenu *menu) +{ + GdkScreen *screen; + + g_return_if_fail (menu->info != NULL); + + screen = applet_user_menu_get_screen (menu); + + switch (menu->info->type) { + case PANEL_OBJECT_LAUNCHER: + if (!strcmp (menu->name, "launch")) + launcher_launch (menu->info->data, widget); + else if (!strcmp (menu->name, "properties")) + launcher_properties (menu->info->data); + break; + case PANEL_OBJECT_DRAWER: + if (strcmp (menu->name, "add") == 0) { + Drawer *drawer = menu->info->data; + + panel_addto_present (GTK_MENU_ITEM (widget), + panel_toplevel_get_panel_widget (drawer->toplevel)); + } else if (strcmp (menu->name, "properties") == 0) { + Drawer *drawer = menu->info->data; + + panel_properties_dialog_present (drawer->toplevel); + } else if (strcmp (menu->name, "help") == 0) { + panel_show_help (screen, + "user-guide", "gospanel-18", NULL); + } + break; + case PANEL_OBJECT_MENU: + panel_menu_button_invoke_menu ( + PANEL_MENU_BUTTON (menu->info->widget), menu->name); + break; + case PANEL_OBJECT_ACTION: + case PANEL_OBJECT_LOGOUT: + case PANEL_OBJECT_LOCK: + panel_action_button_invoke_menu ( + PANEL_ACTION_BUTTON (menu->info->widget), menu->name); + break; + case PANEL_OBJECT_MENU_BAR: + panel_menu_bar_invoke_menu ( + PANEL_MENU_BAR (menu->info->widget), menu->name); + break; + + case PANEL_OBJECT_APPLET: + /* + * Applet's menu's are handled differently + */ + break; + case PANEL_OBJECT_SEPARATOR: + break; + default: + g_assert_not_reached (); + break; + } +} + +static void +applet_menu_show (GtkWidget *w, + AppletInfo *info) +{ + PanelWidget *panel_widget; + + panel_widget = mate_panel_applet_get_panel_widget (info); + + panel_toplevel_push_autohide_disabler (panel_widget->toplevel); +} + + +static void +applet_menu_deactivate (GtkWidget *w, + AppletInfo *info) +{ + PanelWidget *panel_widget; + + panel_widget = mate_panel_applet_get_panel_widget (info); + + panel_toplevel_pop_autohide_disabler (panel_widget->toplevel); +} + +AppletUserMenu * +mate_panel_applet_get_callback (GList *user_menu, + const char *name) +{ + GList *l; + + for (l = user_menu; l; l = l->next) { + AppletUserMenu *menu = l->data; + + if (strcmp (menu->name, name) == 0) + return menu; + } + + return NULL; +} + +void +mate_panel_applet_add_callback (AppletInfo *info, + const char *callback_name, + const char *stock_item, + const char *menuitem_text, + CallbackEnabledFunc is_enabled_func) +{ + AppletUserMenu *menu; + + g_return_if_fail (info != NULL); + g_return_if_fail (mate_panel_applet_get_callback (info->user_menu, + callback_name) == NULL); + + menu = g_new0 (AppletUserMenu, 1); + menu->name = g_strdup (callback_name); + menu->stock_item = g_strdup (stock_item); + menu->text = g_strdup (menuitem_text); + menu->is_enabled_func = is_enabled_func; + menu->sensitive = TRUE; + menu->info = info; + menu->menuitem = NULL; + menu->submenu = NULL; + + info->user_menu = g_list_append (info->user_menu, menu); + + mate_panel_applet_recreate_menu (info); +} + +static void +setup_an_item (AppletUserMenu *menu, + GtkWidget *submenu, + int is_submenu) +{ + GtkWidget *image = NULL; + + menu->menuitem = gtk_image_menu_item_new_with_mnemonic (menu->text); + if (menu->stock_item && menu->stock_item [0]) { + image = gtk_image_new_from_stock (menu->stock_item, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->menuitem), + image); + } + gtk_widget_show (menu->menuitem); + + g_signal_connect (G_OBJECT (menu->menuitem), "destroy", + G_CALLBACK (gtk_widget_destroyed), + &menu->menuitem); + + if(submenu) + gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu->menuitem); + + /*if an item not a submenu*/ + if (!is_submenu) { + g_signal_connect (menu->menuitem, "activate", + G_CALLBACK (applet_callback_callback), + menu); + g_signal_connect (submenu, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &menu->submenu); + /* if the item is a submenu and doesn't have it's menu + created yet*/ + } else if (!menu->submenu) { + menu->submenu = gtk_menu_new (); + } + + if(menu->submenu) { + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->menuitem), + menu->submenu); + g_signal_connect (G_OBJECT (menu->submenu), "destroy", + G_CALLBACK (gtk_widget_destroyed), + &menu->submenu); + } + + gtk_widget_set_sensitive(menu->menuitem,menu->sensitive); +} + +static void +add_to_submenus (AppletInfo *info, + const char *path, + const char *name, + AppletUserMenu *menu, + GtkWidget *submenu, + GList *user_menu) +{ + char *n = g_strdup (name); + char *p = strchr (n, '/'); + char *t; + AppletUserMenu *s_menu; + + /*this is the last one*/ + if (p == NULL) { + g_free (n); + setup_an_item (menu, submenu, FALSE); + return; + } + + /*this is the last one and we are a submenu, we have already been + set up*/ + if(p==(n + strlen(n) - 1)) { + g_free(n); + return; + } + + *p = '\0'; + p++; + + t = g_strconcat (path, n, "/", NULL); + s_menu = mate_panel_applet_get_callback (user_menu, t); + /*the user did not give us this sub menu, whoops, will create an empty + one then*/ + if (s_menu == NULL) { + s_menu = g_new0 (AppletUserMenu,1); + s_menu->name = g_strdup (t); + s_menu->stock_item = NULL; + s_menu->text = g_strdup (_("???")); + s_menu->sensitive = TRUE; + s_menu->info = info; + s_menu->menuitem = NULL; + s_menu->submenu = NULL; + info->user_menu = g_list_append (info->user_menu,s_menu); + user_menu = info->user_menu; + } + + if (s_menu->submenu == NULL) { + s_menu->submenu = gtk_menu_new (); + /*a more elegant way to do this should be done + when I don't want to go to sleep */ + if (s_menu->menuitem != NULL) { + gtk_widget_destroy (s_menu->menuitem); + s_menu->menuitem = NULL; + } + } + if (s_menu->menuitem == NULL) + setup_an_item (s_menu, submenu, TRUE); + + add_to_submenus (info, t, p, menu, s_menu->submenu, user_menu); + + g_free(t); + g_free(n); +} + +GtkWidget * +mate_panel_applet_create_menu (AppletInfo *info) +{ + GtkWidget *menu; + GtkWidget *menuitem; + GList *l; + PanelWidget *panel_widget; + gboolean added_anything = FALSE; + + panel_widget = mate_panel_applet_get_panel_widget (info); + + menu = g_object_ref_sink (gtk_menu_new ()); + + /* connect the show & deactivate signal, so that we can "disallow" and + * "re-allow" autohide when the menu is shown/deactivated. + */ + g_signal_connect (menu, "show", + G_CALLBACK (applet_menu_show), info); + g_signal_connect (menu, "deactivate", + G_CALLBACK (applet_menu_deactivate), info); + + for (l = info->user_menu; l; l = l->next) { + AppletUserMenu *user_menu = l->data; + + if (user_menu->is_enabled_func && !user_menu->is_enabled_func ()) + continue; + + add_to_submenus (info, "", user_menu->name, user_menu, + menu, info->user_menu); + + added_anything = TRUE; + } + + if (!panel_lockdown_get_locked_down ()) { + GtkWidget *image; + gboolean locked; + gboolean lockable; + gboolean movable; + gboolean removable; + + lockable = mate_panel_applet_lockable (info); + movable = mate_panel_applet_can_freely_move (info); + removable = panel_profile_id_lists_are_writable (); + + locked = panel_widget_get_applet_locked (panel_widget, info->widget); + + if (added_anything) { + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + } + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Remove From Panel")); + image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), + image); + g_signal_connect (menuitem, "activate", + G_CALLBACK (applet_remove_callback), info); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_set_sensitive (menuitem, (!locked || lockable) && removable); + + menuitem = gtk_menu_item_new_with_mnemonic (_("_Move")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (move_applet_callback), info); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_set_sensitive (menuitem, !locked && movable); + + g_assert (info->move_item == NULL); + + info->move_item = menuitem; + g_object_add_weak_pointer (G_OBJECT (menuitem), + (gpointer *) &info->move_item); + + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_check_menu_item_new_with_mnemonic (_("Loc_k To Panel")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), + locked); + g_signal_connect (menuitem, "toggled", + G_CALLBACK (mate_panel_applet_lock), info); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_set_sensitive (menuitem, lockable); + + added_anything = TRUE; + } + + if ( ! added_anything) { + g_object_unref (menu); + return NULL; + } + + return menu; +} + +void +mate_panel_applet_menu_set_recurse (GtkMenu *menu, + const gchar *key, + gpointer data) +{ + GList *children; + GList *l; + + g_object_set_data (G_OBJECT (menu), key, data); + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + + for (l = children; l; l = l->next) { + GtkWidget *submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (l->data)); + + if (submenu) + mate_panel_applet_menu_set_recurse ( + GTK_MENU (submenu), key, data); + } + + g_list_free (children); +} + +void +mate_panel_applet_position_menu (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + GtkWidget *applet) +{ + GtkAllocation allocation; + GtkRequisition requisition; + GdkScreen *screen; + GtkWidget *parent; + int menu_x = 0; + int menu_y = 0; + int pointer_x; + int pointer_y; + + parent = gtk_widget_get_parent (applet); + + g_return_if_fail (PANEL_IS_WIDGET (parent)); + + screen = gtk_widget_get_screen (applet); + + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + + gdk_window_get_origin (gtk_widget_get_window (applet), &menu_x, &menu_y); + gtk_widget_get_pointer (applet, &pointer_x, &pointer_y); + + gtk_widget_get_allocation (applet, &allocation); + + if (!gtk_widget_get_has_window (applet)) { + menu_x += allocation.x; + menu_y += allocation.y; + } + + if (PANEL_WIDGET (parent)->orient == GTK_ORIENTATION_HORIZONTAL) { + if (gtk_widget_get_direction (GTK_WIDGET (menu)) != GTK_TEXT_DIR_RTL) { + if (pointer_x < allocation.width && + requisition.width < pointer_x) + menu_x += MIN (pointer_x, + allocation.width - requisition.width); + } else { + menu_x += allocation.width - requisition.width; + if (pointer_x > 0 && pointer_x < allocation.width && + pointer_x < allocation.width - requisition.width) { + menu_x -= MIN (allocation.width - pointer_x, + allocation.width - requisition.width); + } + } + menu_x = MIN (menu_x, gdk_screen_get_width (screen) - requisition.width); + + if (menu_y > gdk_screen_get_height (screen) / 2) + menu_y -= requisition.height; + else + menu_y += allocation.height; + } else { + if (pointer_y < allocation.height && + requisition.height < pointer_y) + menu_y += MIN (pointer_y, allocation.height - requisition.height); + menu_y = MIN (menu_y, gdk_screen_get_height (screen) - requisition.height); + + if (menu_x > gdk_screen_get_width (screen) / 2) + menu_x -= requisition.width; + else + menu_x += allocation.width; + } + + *x = menu_x; + *y = menu_y; + *push_in = TRUE; +} + +static void +applet_show_menu (AppletInfo *info, + GdkEventButton *event) +{ + PanelWidget *panel_widget; + + g_return_if_fail (info != NULL); + + panel_widget = mate_panel_applet_get_panel_widget (info); + + if (info->menu == NULL) + info->menu = mate_panel_applet_create_menu (info); + + if (info->menu == NULL) + return; + + mate_panel_applet_menu_set_recurse (GTK_MENU (info->menu), + "menu_panel", + panel_widget); + + gtk_menu_set_screen (GTK_MENU (info->menu), + gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel))); + + if (!gtk_widget_get_realized (info->menu)) + gtk_widget_show (info->menu); + + gtk_menu_popup (GTK_MENU (info->menu), + NULL, + NULL, + (GtkMenuPositionFunc) mate_panel_applet_position_menu, + info->widget, + event->button, + event->time); +} + +static gboolean +applet_do_popup_menu (GtkWidget *widget, + GdkEventButton *event, + AppletInfo *info) +{ + if (mate_panel_applet_is_in_drag ()) + return FALSE; + + if (info->type == PANEL_OBJECT_APPLET) + return FALSE; + + applet_show_menu (info, event); + + return TRUE; +} + +static gboolean +applet_popup_menu (GtkWidget *widget, + AppletInfo *info) +{ + GdkEventButton event; + + event.button = 3; + event.time = GDK_CURRENT_TIME; + + return applet_do_popup_menu (widget, &event, info); +} + +static gboolean +applet_button_press (GtkWidget *widget, + GdkEventButton *event, + AppletInfo *info) +{ + if (event->button == 3) + return applet_do_popup_menu (widget, event, info); + + return FALSE; +} + +static void +mate_panel_applet_destroy (GtkWidget *widget, + AppletInfo *info) +{ + GList *l; + + g_return_if_fail (info != NULL); + + info->widget = NULL; + + registered_applets = g_slist_remove (registered_applets, info); + + queued_position_saves = + g_slist_remove (queued_position_saves, info); + + if (info->type == PANEL_OBJECT_DRAWER) { + Drawer *drawer = info->data; + + if (drawer->toplevel) { + PanelWidget *panel_widget; + + panel_widget = panel_toplevel_get_panel_widget ( + drawer->toplevel); + panel_widget->master_widget = NULL; + + gtk_widget_destroy (GTK_WIDGET (drawer->toplevel)); + drawer->toplevel = NULL; + } + } + + if (info->type != PANEL_OBJECT_APPLET) + panel_lockdown_notify_remove (G_CALLBACK (mate_panel_applet_recreate_menu), + info); + + if (info->menu) + g_object_unref (info->menu); + info->menu = NULL; + + if (info->data_destroy) + info->data_destroy (info->data); + info->data = NULL; + + for (l = info->user_menu; l != NULL; l = l->next) { + AppletUserMenu *umenu = l->data; + + g_free (umenu->name); + g_free (umenu->stock_item); + g_free (umenu->text); + + g_free (umenu); + } + + g_list_free (info->user_menu); + info->user_menu = NULL; + + g_free (info->id); + info->id = NULL; + + g_free (info); +} + +typedef struct { + char *id; + PanelObjectType type; + char *toplevel_id; + int position; + guint right_stick : 1; + guint locked : 1; +} MatePanelAppletToLoad; + +/* Each time those lists get both empty, + * mate_panel_applet_queue_initial_unhide_toplevels() should be called */ +static GSList *mate_panel_applets_to_load = NULL; +static GSList *mate_panel_applets_loading = NULL; +/* We have a timeout to always unhide toplevels after a delay, in case of some + * blocking applet */ +#define UNHIDE_TOPLEVELS_TIMEOUT_SECONDS 5 +static guint mate_panel_applet_unhide_toplevels_timeout = 0; + +static gboolean mate_panel_applet_have_load_idle = FALSE; + +static void +free_applet_to_load (MatePanelAppletToLoad *applet) +{ + g_free (applet->id); + applet->id = NULL; + + g_free (applet->toplevel_id); + applet->toplevel_id = NULL; + + g_free (applet); +} + +gboolean +mate_panel_applet_on_load_queue (const char *id) +{ + GSList *li; + for (li = mate_panel_applets_to_load; li != NULL; li = li->next) { + MatePanelAppletToLoad *applet = li->data; + if (strcmp (applet->id, id) == 0) + return TRUE; + } + for (li = mate_panel_applets_loading; li != NULL; li = li->next) { + MatePanelAppletToLoad *applet = li->data; + if (strcmp (applet->id, id) == 0) + return TRUE; + } + return FALSE; +} + +/* This doesn't do anything if the initial unhide already happened */ +static gboolean +mate_panel_applet_queue_initial_unhide_toplevels (gpointer user_data) +{ + GSList *l; + + if (mate_panel_applet_unhide_toplevels_timeout != 0) { + g_source_remove (mate_panel_applet_unhide_toplevels_timeout); + mate_panel_applet_unhide_toplevels_timeout = 0; + } + + for (l = panel_toplevel_list_toplevels (); l != NULL; l = l->next) + panel_toplevel_queue_initial_unhide ((PanelToplevel *) l->data); + + return FALSE; +} + +void +mate_panel_applet_stop_loading (const char *id) +{ + MatePanelAppletToLoad *applet; + GSList *l; + + for (l = mate_panel_applets_loading; l; l = l->next) { + applet = l->data; + + if (strcmp (applet->id, id) == 0) + break; + } + + /* this can happen if we reload an applet after it crashed, + * for example */ + if (l != NULL) { + mate_panel_applets_loading = g_slist_delete_link (mate_panel_applets_loading, l); + free_applet_to_load (applet); + } + + if (mate_panel_applets_loading == NULL && mate_panel_applets_to_load == NULL) + mate_panel_applet_queue_initial_unhide_toplevels (NULL); +} + +static gboolean +mate_panel_applet_load_idle_handler (gpointer dummy) +{ + PanelObjectType applet_type; + MatePanelAppletToLoad *applet = NULL; + PanelToplevel *toplevel = NULL; + PanelWidget *panel_widget; + GSList *l; + + if (!mate_panel_applets_to_load) { + mate_panel_applet_have_load_idle = FALSE; + return FALSE; + } + + for (l = mate_panel_applets_to_load; l; l = l->next) { + applet = l->data; + + toplevel = panel_profile_get_toplevel_by_id (applet->toplevel_id); + if (toplevel) + break; + } + + if (!l) { + /* All the remaining applets don't have a panel */ + for (l = mate_panel_applets_to_load; l; l = l->next) + free_applet_to_load (l->data); + g_slist_free (mate_panel_applets_to_load); + mate_panel_applets_to_load = NULL; + mate_panel_applet_have_load_idle = FALSE; + + if (mate_panel_applets_loading == NULL) { + /* unhide any potential initially hidden toplevel */ + mate_panel_applet_queue_initial_unhide_toplevels (NULL); + } + + return FALSE; + } + + mate_panel_applets_to_load = g_slist_delete_link (mate_panel_applets_to_load, l); + mate_panel_applets_loading = g_slist_append (mate_panel_applets_loading, applet); + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + + if (applet->right_stick) { + if (!panel_widget->packed) + applet->position = panel_widget->size - applet->position; + else + applet->position = -1; + } + + /* We load applets asynchronously, so we specifically don't call + * mate_panel_applet_stop_loading() for this type. However, in case of + * failure during the load, we might call mate_panel_applet_stop_loading() + * synchronously, which will make us lose the content of the applet + * variable. So we save the type to be sure we always ignore the + * applets. */ + applet_type = applet->type; + + switch (applet_type) { + case PANEL_OBJECT_APPLET: + mate_panel_applet_frame_load_from_mateconf ( + panel_widget, + applet->locked, + applet->position, + applet->id); + break; + case PANEL_OBJECT_DRAWER: + drawer_load_from_mateconf (panel_widget, + applet->locked, + applet->position, + applet->id); + break; + case PANEL_OBJECT_MENU: + panel_menu_button_load_from_mateconf (panel_widget, + applet->locked, + applet->position, + TRUE, + applet->id); + break; + case PANEL_OBJECT_LAUNCHER: + launcher_load_from_mateconf (panel_widget, + applet->locked, + applet->position, + applet->id); + break; + case PANEL_OBJECT_LOGOUT: + case PANEL_OBJECT_LOCK: + panel_action_button_load_compatible ( + applet->type, + panel_widget, + applet->locked, + applet->position, + TRUE, + applet->id); + break; + case PANEL_OBJECT_ACTION: + panel_action_button_load_from_mateconf ( + panel_widget, + applet->locked, + applet->position, + TRUE, + applet->id); + break; + case PANEL_OBJECT_MENU_BAR: + panel_menu_bar_load_from_mateconf ( + panel_widget, + applet->locked, + applet->position, + TRUE, + applet->id); + break; + case PANEL_OBJECT_SEPARATOR: + panel_separator_load_from_mateconf (panel_widget, + applet->locked, + applet->position, + applet->id); + break; + default: + g_assert_not_reached (); + break; + } + + /* Only the real applets will do a late stop_loading */ + if (applet_type != PANEL_OBJECT_APPLET) + mate_panel_applet_stop_loading (applet->id); + + return TRUE; +} + +void +mate_panel_applet_queue_applet_to_load (const char *id, + PanelObjectType type, + const char *toplevel_id, + int position, + gboolean right_stick, + gboolean locked) +{ + MatePanelAppletToLoad *applet; + + if (!toplevel_id) { + g_warning ("No toplevel on which to load object '%s'\n", id); + return; + } + + applet = g_new0 (MatePanelAppletToLoad, 1); + + applet->id = g_strdup (id); + applet->type = type; + applet->toplevel_id = g_strdup (toplevel_id); + applet->position = position; + applet->right_stick = right_stick != FALSE; + applet->locked = locked != FALSE; + + mate_panel_applets_to_load = g_slist_prepend (mate_panel_applets_to_load, applet); +} + +static int +mate_panel_applet_compare (const MatePanelAppletToLoad *a, + const MatePanelAppletToLoad *b) +{ + int c; + + if ((c = strcmp (a->toplevel_id, b->toplevel_id))) + return c; + else if (a->right_stick != b->right_stick) + return b->right_stick ? -1 : 1; + else + return a->position - b->position; +} + +void +mate_panel_applet_load_queued_applets (gboolean initial_load) +{ + if (!mate_panel_applets_to_load) { + mate_panel_applet_queue_initial_unhide_toplevels (NULL); + return; + } + + if (mate_panel_applets_to_load && mate_panel_applet_unhide_toplevels_timeout == 0) { + /* Install a timeout to make sure we don't block the + * unhiding because of an applet that doesn't load */ + mate_panel_applet_unhide_toplevels_timeout = + g_timeout_add_seconds (UNHIDE_TOPLEVELS_TIMEOUT_SECONDS, + mate_panel_applet_queue_initial_unhide_toplevels, + NULL); + } + + mate_panel_applets_to_load = g_slist_sort (mate_panel_applets_to_load, + (GCompareFunc) mate_panel_applet_compare); + + if ( ! mate_panel_applet_have_load_idle) { + /* on panel startup, we don't care about redraws of the + * toplevels since they are hidden, so we give a higher + * priority to loading of applets */ + if (initial_load) + g_idle_add_full (G_PRIORITY_HIGH_IDLE, + mate_panel_applet_load_idle_handler, + NULL, NULL); + else + g_idle_add (mate_panel_applet_load_idle_handler, NULL); + + mate_panel_applet_have_load_idle = TRUE; + } +} + +static const char* mate_panel_applet_get_toplevel_id(AppletInfo* applet) +{ + PanelWidget* panel_widget; + + g_return_val_if_fail(applet != NULL, NULL); + g_return_val_if_fail(GTK_IS_WIDGET(applet->widget), NULL); + + panel_widget = mate_panel_applet_get_panel_widget(applet); + + if (!panel_widget) + { + return NULL; + } + + return panel_profile_get_toplevel_id(panel_widget->toplevel); +} + +static gboolean +mate_panel_applet_position_save_timeout (gpointer dummy) +{ + GSList *l; + + queued_position_source = 0; + + for (l = queued_position_saves; l; l = l->next) { + AppletInfo *info = l->data; + + mate_panel_applet_save_position (info, info->id, TRUE); + } + + g_slist_free (queued_position_saves); + queued_position_saves = NULL; + + return FALSE; +} + +void +mate_panel_applet_save_position (AppletInfo *applet_info, + const char *id, + gboolean immediate) +{ + PanelMateConfKeyType key_type; + MateConfClient *client; + PanelWidget *panel_widget; + const char *key; + const char *toplevel_id; + char *old_toplevel_id; + gboolean right_stick; + gboolean locked; + int position; + + g_return_if_fail (applet_info != NULL); + + if (!immediate) { + if (!queued_position_source) + queued_position_source = + g_timeout_add_seconds (1, + (GSourceFunc) mate_panel_applet_position_save_timeout, + NULL); + + if (!g_slist_find (queued_position_saves, applet_info)) + queued_position_saves = + g_slist_prepend (queued_position_saves, applet_info); + + return; + } + + if (!(toplevel_id = mate_panel_applet_get_toplevel_id (applet_info))) + return; + + client = panel_mateconf_get_client (); + + key_type = applet_info->type == PANEL_OBJECT_APPLET ? PANEL_MATECONF_APPLETS : PANEL_MATECONF_OBJECTS; + + panel_widget = mate_panel_applet_get_panel_widget (applet_info); + + /* FIXME: Instead of getting keys, comparing and setting, there + should be a dirty flag */ + + key = panel_mateconf_full_key (key_type, id, "toplevel_id"); + old_toplevel_id = mateconf_client_get_string (client, key, NULL); + if (old_toplevel_id == NULL || strcmp (old_toplevel_id, toplevel_id) != 0) + mateconf_client_set_string (client, key, toplevel_id, NULL); + g_free (old_toplevel_id); + + /* Note: changing some properties of the panel that may not be locked down + (e.g. background) can change the state of the "panel_right_stick" and + "position" properties of an applet that may in fact be locked down. + So check if these are writable before attempting to write them */ + + right_stick = panel_is_applet_right_stick (applet_info->widget) ? 1 : 0; + key = panel_mateconf_full_key ( + key_type, id, "panel_right_stick"); + if (mateconf_client_key_is_writable (client, key, NULL) && + (mateconf_client_get_bool (client, key, NULL) ? 1 : 0) != right_stick) + mateconf_client_set_bool (client, key, right_stick, NULL); + + position = mate_panel_applet_get_position (applet_info); + if (right_stick && !panel_widget->packed) + position = panel_widget->size - position; + + key = panel_mateconf_full_key (key_type, id, "position"); + if (mateconf_client_key_is_writable (client, key, NULL) && + mateconf_client_get_int (client, key, NULL) != position) + mateconf_client_set_int (client, key, position, NULL); + + locked = panel_widget_get_applet_locked (panel_widget, applet_info->widget) ? 1 : 0; + key = panel_mateconf_full_key (key_type, id, "locked"); + if (mateconf_client_get_bool (client, key, NULL) ? 1 : 0 != locked) + mateconf_client_set_bool (client, key, locked, NULL); +} + +const char * +mate_panel_applet_get_id (AppletInfo *info) +{ + if (!info) + return NULL; + + return info->id; +} + +const char * +mate_panel_applet_get_id_by_widget (GtkWidget *applet_widget) +{ + GSList *l; + + if (!applet_widget) + return NULL; + + for (l = registered_applets; l; l = l->next) { + AppletInfo *info = l->data; + + if (info->widget == applet_widget) + return info->id; + } + + return NULL; +} + +AppletInfo * +mate_panel_applet_get_by_id (const char *id) +{ + GSList *l; + + for (l = registered_applets; l; l = l->next) { + AppletInfo *info = l->data; + + if (!strcmp (info->id, id)) + return info; + } + + return NULL; +} + +GSList * +mate_panel_applet_list_applets (void) +{ + return registered_applets; +} + +AppletInfo * +mate_panel_applet_get_by_type (PanelObjectType object_type, GdkScreen *screen) +{ + GSList *l; + + for (l = registered_applets; l; l = l->next) { + AppletInfo *info = l->data; + + if (info->type == object_type) { + if (screen) { + if (screen == gtk_widget_get_screen (info->widget)) + return info; + } else + return info; + } + } + + return NULL; +} + +AppletInfo * +mate_panel_applet_register (GtkWidget *applet, + gpointer data, + GDestroyNotify data_destroy, + PanelWidget *panel, + gboolean locked, + gint pos, + gboolean exactpos, + PanelObjectType type, + const char *id) +{ + AppletInfo *info; + const char *key; + + g_return_val_if_fail (applet != NULL && panel != NULL, NULL); + + if (gtk_widget_get_has_window (applet)) + gtk_widget_set_events (applet, (gtk_widget_get_events (applet) | + APPLET_EVENT_MASK) & + ~( GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK)); + + info = g_new0 (AppletInfo, 1); + info->type = type; + info->widget = applet; + info->menu = NULL; + info->data = data; + info->data_destroy = data_destroy; + info->user_menu = NULL; + info->move_item = NULL; + info->id = g_strdup (id); + + g_object_set_data (G_OBJECT (applet), "applet_info", info); + + if (type != PANEL_OBJECT_APPLET) + panel_lockdown_notify_add (G_CALLBACK (mate_panel_applet_recreate_menu), + info); + + key = panel_mateconf_full_key ((type == PANEL_OBJECT_APPLET) ? + PANEL_MATECONF_APPLETS : PANEL_MATECONF_OBJECTS, + id, "locked"); + panel_mateconf_notify_add_while_alive (key, + (MateConfClientNotifyFunc) mate_panel_applet_locked_change_notify, + G_OBJECT (applet)); + + if (type == PANEL_OBJECT_DRAWER) { + Drawer *drawer = data; + PanelWidget *assoc_panel; + + assoc_panel = panel_toplevel_get_panel_widget (drawer->toplevel); + + g_object_set_data (G_OBJECT (applet), + MATE_PANEL_APPLET_ASSOC_PANEL_KEY, assoc_panel); + assoc_panel->master_widget = applet; + g_object_add_weak_pointer ( + G_OBJECT (applet), (gpointer *) &assoc_panel->master_widget); + } + + g_object_set_data (G_OBJECT (applet), + MATE_PANEL_APPLET_FORBIDDEN_PANELS, NULL); + + registered_applets = g_slist_append (registered_applets, info); + + if (panel_widget_add (panel, applet, locked, pos, exactpos) == -1 && + panel_widget_add (panel, applet, locked, 0, TRUE) == -1) { + GSList *l; + + for (l = panels; l; l = l->next) { + panel = PANEL_WIDGET (l->data); + + if (panel_widget_add (panel, applet, locked, 0, TRUE) != -1) + break; + } + + if (!l) { + g_warning (_("Cannot find an empty spot")); + panel_profile_delete_object (info); + return NULL; + } + } + + if (BUTTON_IS_WIDGET (applet) || + gtk_widget_get_has_window (applet)) { + g_signal_connect (applet, "button_press_event", + G_CALLBACK (applet_button_press), + info); + + g_signal_connect (applet, "popup_menu", + G_CALLBACK (applet_popup_menu), + info); + } + + g_signal_connect (applet, "destroy", + G_CALLBACK (mate_panel_applet_destroy), + info); + + mate_panel_applet_set_dnd_enabled (info, !locked); + + gtk_widget_show_all (applet); + + orientation_change (info, panel); + size_change (info, panel); + back_change (info, panel); + + if (type != PANEL_OBJECT_APPLET) + gtk_widget_grab_focus (applet); + else + gtk_widget_child_focus (applet, GTK_DIR_TAB_FORWARD); + + return info; +} + +int +mate_panel_applet_get_position (AppletInfo *applet) +{ + AppletData *applet_data; + + g_return_val_if_fail (applet != NULL, 0); + g_return_val_if_fail (G_IS_OBJECT (applet->widget), 0); + + applet_data = g_object_get_data (G_OBJECT (applet->widget), MATE_PANEL_APPLET_DATA); + + return applet_data->pos; +} + +gboolean +mate_panel_applet_can_freely_move (AppletInfo *applet) +{ + MateConfClient *client; + PanelMateConfKeyType key_type; + const char *key; + + if (panel_lockdown_get_locked_down ()) + return FALSE; + + client = panel_mateconf_get_client (); + + key_type = (applet->type == PANEL_OBJECT_APPLET) ? PANEL_MATECONF_APPLETS : PANEL_MATECONF_OBJECTS; + + key = panel_mateconf_full_key (key_type, applet->id, "position"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + key = panel_mateconf_full_key (key_type, applet->id, "toplevel_id"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + key = panel_mateconf_full_key (key_type, applet->id, "panel_right_stick"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + return TRUE; +} + +gboolean +mate_panel_applet_lockable (AppletInfo *applet) +{ + MateConfClient *client; + PanelMateConfKeyType key_type; + const char *key; + + if (panel_lockdown_get_locked_down ()) + return FALSE; + + client = panel_mateconf_get_client (); + + key_type = (applet->type == PANEL_OBJECT_APPLET) ? PANEL_MATECONF_APPLETS : PANEL_MATECONF_OBJECTS; + + key = panel_mateconf_full_key (key_type, applet->id, "locked"); + + return mateconf_client_key_is_writable (client, key, NULL); +} diff --git a/mate-panel/applet.h b/mate-panel/applet.h new file mode 100644 index 00000000..531e7e20 --- /dev/null +++ b/mate-panel/applet.h @@ -0,0 +1,119 @@ +#ifndef APPLET_H +#define APPLET_H + +#include +#include +#include "panel-widget.h" +#include "panel-mateconf.h" +#include "panel-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define APPLET_EVENT_MASK (GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_POINTER_MOTION_MASK | \ + GDK_POINTER_MOTION_HINT_MASK) +typedef struct { + PanelObjectType type; + GtkWidget *widget; + + GtkWidget *menu; + GtkWidget *move_item; + GList *user_menu; + + gpointer data; + GDestroyNotify data_destroy; + + char *id; +} AppletInfo; + +typedef gboolean (* CallbackEnabledFunc) (void); + +typedef struct { + char *name; + char *stock_item; + char *text; + + CallbackEnabledFunc is_enabled_func; + + int sensitive; + AppletInfo *info; + + GtkWidget *menuitem; + GtkWidget *submenu; +} AppletUserMenu; + +AppletInfo *mate_panel_applet_register (GtkWidget *applet, + gpointer data, + GDestroyNotify data_destroy, + PanelWidget *panel, + gboolean locked, + gint pos, + gboolean exactpos, + PanelObjectType type, + const char *id); +void mate_panel_applet_stop_loading (const char *id); + +const char *mate_panel_applet_get_id (AppletInfo *info); +const char *mate_panel_applet_get_id_by_widget (GtkWidget *widget); +AppletInfo *mate_panel_applet_get_by_id (const char *id); +AppletInfo *mate_panel_applet_get_by_type (PanelObjectType object_type, GdkScreen *screen); + +GSList *mate_panel_applet_list_applets (void); + +void mate_panel_applet_clean (AppletInfo *info); + +void mate_panel_applet_queue_applet_to_load (const char *id, + PanelObjectType type, + const char *toplevel_id, + int position, + gboolean right_stick, + gboolean locked); +void mate_panel_applet_load_queued_applets (gboolean initial_load); +gboolean mate_panel_applet_on_load_queue (const char *id); + + +void mate_panel_applet_add_callback (AppletInfo *info, + const gchar *callback_name, + const gchar *stock_item, + const gchar *menuitem_text, + CallbackEnabledFunc is_enabled_func); + +AppletUserMenu *mate_panel_applet_get_callback (GList *user_menu, + const gchar *name); + + +void mate_panel_applet_save_position (AppletInfo *applet_info, + const char *id, + gboolean immediate); + +int mate_panel_applet_get_position (AppletInfo *applet); + +/* True if all the keys relevant to moving are writable + (position, toplevel_id, panel_right_stick) */ +gboolean mate_panel_applet_can_freely_move (AppletInfo *applet); + +/* True if the locked flag is writable */ +gboolean mate_panel_applet_lockable (AppletInfo *applet); + +GtkWidget *mate_panel_applet_create_menu (AppletInfo *info); + +void mate_panel_applet_menu_set_recurse (GtkMenu *menu, + const gchar *key, + gpointer data); + +gboolean mate_panel_applet_toggle_locked (AppletInfo *info); + +void mate_panel_applet_position_menu (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + GtkWidget *applet); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mate-panel/button-widget.c b/mate-panel/button-widget.c new file mode 100644 index 00000000..6f2fd6b8 --- /dev/null +++ b/mate-panel/button-widget.c @@ -0,0 +1,902 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "button-widget.h" +#include "panel-widget.h" +#include "panel-types.h" +#include "panel-util.h" +#include "panel-config-global.h" +#include "panel-marshal.h" +#include "panel-typebuiltins.h" +#include "panel-globals.h" + +#define BUTTON_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BUTTON_TYPE_WIDGET, ButtonWidgetPrivate)) + +struct _ButtonWidgetPrivate { + GtkIconTheme *icon_theme; + GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf_hc; + + char *filename; + + PanelOrientation orientation; + + int size; + + guint activatable : 1; + guint ignore_leave : 1; + guint arrow : 1; + guint dnd_highlight : 1; +}; + +static void button_widget_icon_theme_changed (ButtonWidget *button); +static void button_widget_reload_pixbuf (ButtonWidget *button); + +enum { + PROP_0, + PROP_ACTIVATABLE, + PROP_IGNORE_LEAVE, + PROP_HAS_ARROW, + PROP_DND_HIGHLIGHT, + PROP_ORIENTATION, + PROP_ICON_NAME +}; + +#define BUTTON_WIDGET_DISPLACEMENT 2 + +G_DEFINE_TYPE (ButtonWidget, button_widget, GTK_TYPE_BUTTON) + +/* colorshift a pixbuf */ +static void +do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift) +{ + gint i, j; + gint width, height, has_alpha, srcrowstride, destrowstride; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + int val; + guchar r,g,b; + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + srcrowstride = gdk_pixbuf_get_rowstride (src); + destrowstride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) { + pixdest = target_pixels + i*destrowstride; + pixsrc = original_pixels + i*srcrowstride; + for (j = 0; j < width; j++) { + r = *(pixsrc++); + g = *(pixsrc++); + b = *(pixsrc++); + val = r + shift; + *(pixdest++) = CLAMP(val, 0, 255); + val = g + shift; + *(pixdest++) = CLAMP(val, 0, 255); + val = b + shift; + *(pixdest++) = CLAMP(val, 0, 255); + if (has_alpha) + *(pixdest++) = *(pixsrc++); + } + } +} + +static GdkPixbuf * +make_hc_pixbuf (GdkPixbuf *pb) +{ + GdkPixbuf *new; + + if (!pb) + return NULL; + + new = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pb), + gdk_pixbuf_get_has_alpha (pb), + gdk_pixbuf_get_bits_per_sample (pb), + gdk_pixbuf_get_width (pb), + gdk_pixbuf_get_height (pb)); + do_colorshift (new, pb, 30); + + return new; +} + +static void +button_widget_realize(GtkWidget *widget) +{ + GtkAllocation allocation; + GdkWindowAttr attributes; + gint attributes_mask; + GtkButton *button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (BUTTON_IS_WIDGET (widget)); + + button = GTK_BUTTON (widget); + + gtk_widget_set_realized (widget, TRUE); + + gtk_widget_get_allocation (widget, &allocation); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_KEY_PRESS_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y; + + gtk_widget_set_window (widget, gtk_widget_get_parent_window (widget)); + g_object_ref (gtk_widget_get_window (widget)); + + button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + attributes_mask); + gdk_window_set_user_data (button->event_window, widget); + + widget->style = gtk_style_attach (widget->style, gtk_widget_get_window (widget)); + + BUTTON_WIDGET (widget)->priv->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget)); + g_signal_connect_object (BUTTON_WIDGET (widget)->priv->icon_theme, + "changed", + G_CALLBACK (button_widget_icon_theme_changed), + button, + G_CONNECT_SWAPPED); + + button_widget_reload_pixbuf (BUTTON_WIDGET (widget)); +} + +static void +button_widget_unrealize (GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (BUTTON_IS_WIDGET (widget)); + + button = GTK_BUTTON (widget); + + if (button->event_window != NULL) { + gdk_window_set_user_data (button->event_window, NULL); + gdk_window_destroy (button->event_window); + button->event_window = NULL; + } + + GTK_WIDGET_CLASS (button_widget_parent_class)->unrealize (widget); +} + +static void +button_widget_unset_pixbufs (ButtonWidget *button) +{ + if (button->priv->pixbuf) + g_object_unref (button->priv->pixbuf); + button->priv->pixbuf = NULL; + + if (button->priv->pixbuf_hc) + g_object_unref (button->priv->pixbuf_hc); + button->priv->pixbuf_hc = NULL; +} + +static void +button_widget_reload_pixbuf (ButtonWidget *button) +{ + button_widget_unset_pixbufs (button); + + if (button->priv->size <= 1 || button->priv->icon_theme == NULL) + return; + + if (button->priv->filename != NULL && + button->priv->filename [0] != '\0') { + char *error = NULL; + + button->priv->pixbuf = + panel_load_icon (button->priv->icon_theme, + button->priv->filename, + button->priv->size, + button->priv->orientation & PANEL_VERTICAL_MASK ? button->priv->size : -1, + button->priv->orientation & PANEL_HORIZONTAL_MASK ? button->priv->size : -1, + &error); + if (error) { + //FIXME: this is not rendered at button->priv->size + button->priv->pixbuf = + gtk_widget_render_icon (GTK_WIDGET (button), + GTK_STOCK_MISSING_IMAGE, + (GtkIconSize) -1, NULL); + g_free (error); + } + } + + button->priv->pixbuf_hc = make_hc_pixbuf (button->priv->pixbuf); + + gtk_widget_queue_resize (GTK_WIDGET (button)); +} + +static void +button_widget_icon_theme_changed (ButtonWidget *button) +{ + if (button->priv->filename != NULL) + button_widget_reload_pixbuf (button); +} + +static void +button_widget_finalize (GObject *object) +{ + ButtonWidget *button = (ButtonWidget *) object; + + button_widget_unset_pixbufs (button); + + g_free (button->priv->filename); + button->priv->filename = NULL; + + G_OBJECT_CLASS (button_widget_parent_class)->finalize (object); +} + +static void +button_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ButtonWidget *button; + + g_return_if_fail (BUTTON_IS_WIDGET (object)); + + button = BUTTON_WIDGET (object); + + switch (prop_id) { + case PROP_ACTIVATABLE: + g_value_set_boolean (value, button->priv->activatable); + break; + case PROP_IGNORE_LEAVE: + g_value_set_boolean (value, button->priv->ignore_leave); + break; + case PROP_HAS_ARROW: + g_value_set_boolean (value, button->priv->arrow); + break; + case PROP_DND_HIGHLIGHT: + g_value_set_boolean (value, button->priv->dnd_highlight); + break; + case PROP_ORIENTATION: + g_value_set_enum (value, button->priv->orientation); + break; + case PROP_ICON_NAME: + g_value_set_string (value, button->priv->filename); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +button_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ButtonWidget *button; + + g_return_if_fail (BUTTON_IS_WIDGET (object)); + + button = BUTTON_WIDGET (object); + + switch (prop_id) { + case PROP_ACTIVATABLE: + button_widget_set_activatable (button, g_value_get_boolean (value)); + break; + case PROP_IGNORE_LEAVE: + button_widget_set_ignore_leave (button, g_value_get_boolean (value)); + break; + case PROP_HAS_ARROW: + button_widget_set_has_arrow (button, g_value_get_boolean (value)); + break; + case PROP_DND_HIGHLIGHT: + button_widget_set_dnd_highlight (button, g_value_get_boolean (value)); + break; + case PROP_ORIENTATION: + button_widget_set_orientation (button, g_value_get_enum (value)); + break; + case PROP_ICON_NAME: + button_widget_set_icon_name (button, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GtkArrowType +calc_arrow (PanelOrientation orientation, + int button_width, + int button_height, + int *x, + int *y, + int *width, + int *height) +{ + GtkArrowType retval = GTK_ARROW_UP; + double scale; + + scale = (orientation & PANEL_HORIZONTAL_MASK ? button_height : button_width) / 48.0; + + *width = 12 * scale; + *height = 12 * scale; + + switch (orientation) { + case PANEL_ORIENTATION_TOP: + *x = scale * 3; + *y = scale * (48 - 13); + retval = GTK_ARROW_DOWN; + break; + case PANEL_ORIENTATION_BOTTOM: + *x = scale * (48 - 13); + *y = scale * 1; + retval = GTK_ARROW_UP; + break; + case PANEL_ORIENTATION_LEFT: + *x = scale * (48 - 13); + *y = scale * 3; + retval = GTK_ARROW_RIGHT; + break; + case PANEL_ORIENTATION_RIGHT: + *x = scale * 1; + *y = scale * 3; + retval = GTK_ARROW_LEFT; + break; + } + + return retval; +} + +static gboolean +button_widget_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + ButtonWidget *button_widget; + GtkButton *button; + GdkWindow *window; + GtkAllocation allocation; + GdkRectangle area, image_bound; + GtkStyle *style; + int off; + int x, y, w, h; + GdkPixbuf *pb = NULL; + + g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!gtk_widget_get_visible (widget) || !gtk_widget_get_mapped (widget)) + return FALSE; + + button_widget = BUTTON_WIDGET (widget); + + if (!button_widget->priv->pixbuf_hc && !button_widget->priv->pixbuf) + return FALSE; + + button = GTK_BUTTON (widget); + window = gtk_widget_get_window (widget); + gtk_widget_get_allocation (widget, &allocation); + + /* offset for pressed buttons */ + off = (button_widget->priv->activatable && + button->in_button && button->button_down) ? + BUTTON_WIDGET_DISPLACEMENT * allocation.height / 48.0 : 0; + + if (!button_widget->priv->activatable) { + pb = gdk_pixbuf_copy (button_widget->priv->pixbuf); + gdk_pixbuf_saturate_and_pixelate (button_widget->priv->pixbuf, + pb, + 0.8, + TRUE); + } else if (panel_global_config_get_highlight_when_over () && + (button->in_button || gtk_widget_has_focus (widget))) + pb = g_object_ref (button_widget->priv->pixbuf_hc); + else + pb = g_object_ref (button_widget->priv->pixbuf); + + g_assert (pb != NULL); + + w = gdk_pixbuf_get_width (pb); + h = gdk_pixbuf_get_height (pb); + x = allocation.x + off + (allocation.width - w)/2; + y = allocation.y + off + (allocation.height - h)/2; + + image_bound.x = x; + image_bound.y = y; + image_bound.width = w; + image_bound.height = h; + + area = event->area; + + if (gdk_rectangle_intersect (&area, &allocation, &area) && + gdk_rectangle_intersect (&image_bound, &area, &image_bound)) + gdk_draw_pixbuf (window, NULL, pb, + image_bound.x - x, image_bound.y - y, + image_bound.x, image_bound.y, + image_bound.width, image_bound.height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + + g_object_unref (pb); + + style = gtk_widget_get_style (widget); + + if (button_widget->priv->arrow) { + GtkArrowType arrow_type; + int x, y, width, height; + + x = y = width = height = -1; + + arrow_type = calc_arrow (button_widget->priv->orientation, + allocation.width, + allocation.height, + &x, + &y, + &width, + &height); + + gtk_paint_arrow (style, + window, + GTK_STATE_NORMAL, + GTK_SHADOW_NONE, + NULL, + widget, + "panel-button", + arrow_type, + TRUE, + allocation.x + x, + allocation.y + y, + width, + height); + } + + if (button_widget->priv->dnd_highlight) { + gdk_draw_rectangle(window, style->black_gc, FALSE, + allocation.x, allocation.y, + allocation.width - 1, + allocation.height - 1); + } + + if (gtk_widget_has_focus (widget)) { + gint focus_width, focus_pad; + gint x, y, width, height; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + x = allocation.x + focus_pad; + y = allocation.y + focus_pad; + width = allocation.width - 2 * focus_pad; + height = allocation.height - 2 * focus_pad; + gtk_paint_focus (style, window, + GTK_STATE_NORMAL, + &event->area, widget, "button", + x, y, width, height); + } + + return FALSE; +} + +static void +button_widget_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + ButtonWidget *button_widget = BUTTON_WIDGET (widget); + + if (button_widget->priv->pixbuf) { + requisition->width = gdk_pixbuf_get_width (button_widget->priv->pixbuf); + requisition->height = gdk_pixbuf_get_height (button_widget->priv->pixbuf); + } +} + +static void +button_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + ButtonWidget *button_widget = BUTTON_WIDGET (widget); + GtkButton *button = GTK_BUTTON (widget); + int size; + + if (button_widget->priv->orientation & PANEL_HORIZONTAL_MASK) + size = allocation->height; + else + size = allocation->width; + + if (size < 22) + size = 16; + else if (size < 24) + size = 22; + else if (size < 32) + size = 24; + else if (size < 48) + size = 32; + else + size = 48; + + if (button_widget->priv->size != size) { + button_widget->priv->size = size; + + button_widget_reload_pixbuf (button_widget); + } + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) { + gdk_window_move_resize (button->event_window, + allocation->x, + allocation->y, + allocation->width, + allocation->height); + } +} + +static void +button_widget_activate (GtkButton *button) +{ + ButtonWidget *button_widget = BUTTON_WIDGET (button); + + if (!button_widget->priv->activatable) + return; + + if (GTK_BUTTON_CLASS (button_widget_parent_class)->activate) + GTK_BUTTON_CLASS (button_widget_parent_class)->activate (button); +} + +static gboolean +button_widget_button_press (GtkWidget *widget, GdkEventButton *event) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button == 1 && BUTTON_WIDGET (widget)->priv->activatable && + /* we don't want to have two/three "click" events for double/triple + * clicks. FIXME: this is only a workaround, waiting for bug 159101 */ + event->type == GDK_BUTTON_PRESS) + return GTK_WIDGET_CLASS (button_widget_parent_class)->button_press_event (widget, event); + + return FALSE; +} + +static gboolean +button_widget_enter_notify (GtkWidget *widget, GdkEventCrossing *event) +{ + gboolean in_button; + + g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE); + + in_button = GTK_BUTTON (widget)->in_button; + GTK_WIDGET_CLASS (button_widget_parent_class)->enter_notify_event (widget, event); + if (in_button != GTK_BUTTON (widget)->in_button && + panel_global_config_get_highlight_when_over ()) + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +button_widget_leave_notify (GtkWidget *widget, GdkEventCrossing *event) +{ + gboolean in_button; + + g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE); + + in_button = GTK_BUTTON (widget)->in_button; + GTK_WIDGET_CLASS (button_widget_parent_class)->leave_notify_event (widget, event); + if (in_button != GTK_BUTTON (widget)->in_button && + panel_global_config_get_highlight_when_over ()) + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static void +button_widget_init (ButtonWidget *button) +{ + button->priv = BUTTON_WIDGET_GET_PRIVATE (button); + + button->priv->icon_theme = NULL; + button->priv->pixbuf = NULL; + button->priv->pixbuf_hc = NULL; + + button->priv->filename = NULL; + + button->priv->orientation = PANEL_ORIENTATION_TOP; + + button->priv->size = 0; + + button->priv->activatable = FALSE; + button->priv->ignore_leave = FALSE; + button->priv->arrow = FALSE; + button->priv->dnd_highlight = FALSE; +} + +static void +button_widget_class_init (ButtonWidgetClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + GtkButtonClass *button_class = (GtkButtonClass *) klass; + + gobject_class->finalize = button_widget_finalize; + gobject_class->get_property = button_widget_get_property; + gobject_class->set_property = button_widget_set_property; + + g_type_class_add_private (klass, sizeof (ButtonWidgetPrivate)); + + widget_class->realize = button_widget_realize; + widget_class->unrealize = button_widget_unrealize; + widget_class->size_allocate = button_widget_size_allocate; + widget_class->size_request = button_widget_size_request; + widget_class->button_press_event = button_widget_button_press; + widget_class->enter_notify_event = button_widget_enter_notify; + widget_class->leave_notify_event = button_widget_leave_notify; + widget_class->expose_event = button_widget_expose; + + button_class->activate = button_widget_activate; + + g_object_class_install_property ( + gobject_class, + PROP_ACTIVATABLE, + g_param_spec_boolean ("activatable", + "Activatable", + "Whether the button is activatable", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_IGNORE_LEAVE, + g_param_spec_boolean ("ignore-leave", + "Ignore leaving to not unhighlight the icon", + "Whether or not to unhighlight the icon when the cursor leaves it", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_HAS_ARROW, + g_param_spec_boolean ("has-arrow", + "Has Arrow", + "Whether or not to draw an arrow indicator", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_DND_HIGHLIGHT, + g_param_spec_boolean ("dnd-highlight", + "Drag and drop Highlight", + "Whether or not to highlight the icon during drag and drop", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + "Orientation", + "The ButtonWidget orientation", + PANEL_TYPE_ORIENTATION, + PANEL_ORIENTATION_TOP, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_ICON_NAME, + g_param_spec_string ("icon-name", + "Icon Name", + "The desired icon for the ButtonWidget", + NULL, + G_PARAM_READWRITE)); +} + +GtkWidget * +button_widget_new (const char *filename, + gboolean arrow, + PanelOrientation orientation) +{ + GtkWidget *retval; + + retval = g_object_new ( + BUTTON_TYPE_WIDGET, + "has-arrow", arrow, + "orientation", orientation, + "icon-name", filename, + NULL); + + return retval; +} + +void +button_widget_set_activatable (ButtonWidget *button, + gboolean activatable) +{ + g_return_if_fail (BUTTON_IS_WIDGET (button)); + + activatable = activatable != FALSE; + + if (button->priv->activatable != activatable) { + button->priv->activatable = activatable; + + if (gtk_widget_is_drawable (GTK_WIDGET (button))) + gtk_widget_queue_draw (GTK_WIDGET (button)); + + g_object_notify (G_OBJECT (button), "activatable"); + } +} + +gboolean +button_widget_get_activatable (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE); + + return button->priv->activatable; +} + +void +button_widget_set_icon_name (ButtonWidget *button, + const char *icon_name) +{ + g_return_if_fail (BUTTON_IS_WIDGET (button)); + + if (button->priv->filename && icon_name && + !strcmp (button->priv->filename, icon_name)) + return; + + if (button->priv->filename) + g_free (button->priv->filename); + button->priv->filename = g_strdup (icon_name); + + button_widget_reload_pixbuf (button); + + g_object_notify (G_OBJECT (button), "icon-name"); +} + +const char * +button_widget_get_icon_name (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), NULL); + + return button->priv->filename; +} + +void +button_widget_set_orientation (ButtonWidget *button, + PanelOrientation orientation) +{ + g_return_if_fail (BUTTON_IS_WIDGET (button)); + + if (button->priv->orientation == orientation) + return; + + button->priv->orientation = orientation; + + /* Force a re-scale */ + button->priv->size = -1; + + gtk_widget_queue_resize (GTK_WIDGET (button)); + + g_object_notify (G_OBJECT (button), "orientation"); +} + +PanelOrientation +button_widget_get_orientation (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), 0); + + return button->priv->orientation; +} + +void +button_widget_set_has_arrow (ButtonWidget *button, + gboolean has_arrow) +{ + g_return_if_fail (BUTTON_IS_WIDGET (button)); + + has_arrow = has_arrow != FALSE; + + if (button->priv->arrow == has_arrow) + return; + + button->priv->arrow = has_arrow; + + gtk_widget_queue_draw (GTK_WIDGET (button)); + + g_object_notify (G_OBJECT (button), "has-arrow"); +} + +gboolean +button_widget_get_has_arrow (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE); + + return button->priv->arrow; +} + +void +button_widget_set_dnd_highlight (ButtonWidget *button, + gboolean dnd_highlight) +{ + g_return_if_fail (BUTTON_IS_WIDGET (button)); + + dnd_highlight = dnd_highlight != FALSE; + + if (button->priv->dnd_highlight == dnd_highlight) + return; + + button->priv->dnd_highlight = dnd_highlight; + + gtk_widget_queue_draw (GTK_WIDGET (button)); + + g_object_notify (G_OBJECT (button), "dnd-highlight"); +} + +gboolean +button_widget_get_dnd_highlight (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE); + + return button->priv->dnd_highlight; +} + +void +button_widget_set_ignore_leave (ButtonWidget *button, + gboolean ignore_leave) +{ + g_return_if_fail (BUTTON_IS_WIDGET (button)); + + ignore_leave = ignore_leave != FALSE; + + if (button->priv->ignore_leave == ignore_leave) + return; + + button->priv->ignore_leave = ignore_leave; + + gtk_widget_queue_draw (GTK_WIDGET (button)); + + g_object_notify (G_OBJECT (button), "ignore-leave"); +} + +gboolean +button_widget_get_ignore_leave (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE); + + return button->priv->ignore_leave; +} + +GtkIconTheme * +button_widget_get_icon_theme (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), NULL); + + return button->priv->icon_theme; +} + +GdkPixbuf * +button_widget_get_pixbuf (ButtonWidget *button) +{ + g_return_val_if_fail (BUTTON_IS_WIDGET (button), NULL); + + if (!button->priv->pixbuf) + return NULL; + + return g_object_ref (button->priv->pixbuf); +} diff --git a/mate-panel/button-widget.h b/mate-panel/button-widget.h new file mode 100644 index 00000000..e9b87e6d --- /dev/null +++ b/mate-panel/button-widget.h @@ -0,0 +1,60 @@ +#ifndef BUTTON_WIDGET_H +#define BUTTON_WIDGET_H + +#include +#include "panel-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUTTON_TYPE_WIDGET (button_widget_get_type ()) +#define BUTTON_WIDGET(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), BUTTON_TYPE_WIDGET, ButtonWidget)) +#define BUTTON_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass, BUTTON_TYPE_WIDGET, ButtonWidgetClass)) +#define BUTTON_IS_WIDGET(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), BUTTON_TYPE_WIDGET)) +#define BUTTON_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BUTTON_TYPE_WIDGET)) + +typedef struct _ButtonWidget ButtonWidget; +typedef struct _ButtonWidgetClass ButtonWidgetClass; +typedef struct _ButtonWidgetPrivate ButtonWidgetPrivate; + +struct _ButtonWidget { + GtkButton parent; + + ButtonWidgetPrivate *priv; +}; + +struct _ButtonWidgetClass { + GtkButtonClass parent_class; +}; + +GType button_widget_get_type (void) G_GNUC_CONST; +GtkWidget * button_widget_new (const char *pixmap, + gboolean arrow, + PanelOrientation orientation); +void button_widget_set_activatable (ButtonWidget *button, + gboolean activatable); +gboolean button_widget_get_activatable (ButtonWidget *button); +void button_widget_set_icon_name (ButtonWidget *button, + const char *icon_name); +const char * button_widget_get_icon_name (ButtonWidget *button); +void button_widget_set_orientation (ButtonWidget *button, + PanelOrientation orientation); +PanelOrientation button_widget_get_orientation (ButtonWidget *button); +void button_widget_set_has_arrow (ButtonWidget *button, + gboolean has_arrow); +gboolean button_widget_get_has_arrow (ButtonWidget *button); +void button_widget_set_dnd_highlight (ButtonWidget *button, + gboolean dnd_highlight); +gboolean button_widget_get_dnd_highlight (ButtonWidget *button); +void button_widget_set_ignore_leave (ButtonWidget *button, + gboolean ignore_leave); +gboolean button_widget_get_ignore_leave (ButtonWidget *button); +GtkIconTheme *button_widget_get_icon_theme (ButtonWidget *button); +GdkPixbuf *button_widget_get_pixbuf (ButtonWidget *button); + +#ifdef __cplusplus +} +#endif + +#endif /* __BUTTON_WIDGET_H__ */ diff --git a/mate-panel/drawer.c b/mate-panel/drawer.c new file mode 100644 index 00000000..924acb42 --- /dev/null +++ b/mate-panel/drawer.c @@ -0,0 +1,806 @@ +/* + * MATE panel drawer module. + * (C) 1997 The Free Software Foundation + * + * Authors: Miguel de Icaza + * Federico Mena + * George Lebl + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "drawer.h" + +#include "applet.h" +#include "button-widget.h" +#include "panel-config-global.h" +#include "panel-mateconf.h" +#include "panel-profile.h" +#include "panel-util.h" +#include "xstuff.h" +#include "panel-globals.h" +#include "panel-lockdown.h" +#include "panel-icon-names.h" + +static void +drawer_click (GtkWidget *w, Drawer *drawer) +{ + if (!panel_toplevel_get_is_hidden (drawer->toplevel)) + panel_toplevel_hide (drawer->toplevel, FALSE, -1); + else + panel_toplevel_unhide (drawer->toplevel); +} + +static void +toplevel_destroyed (GtkWidget *widget, + Drawer *drawer) +{ + drawer->toplevel = NULL; + gtk_widget_destroy (drawer->button); +} + +static void +destroy_drawer (GtkWidget *widget, + Drawer *drawer) +{ + MateConfClient *client; + int i; + + client = panel_mateconf_get_client (); + + for (i = 0; i < PANEL_DRAWER_N_LISTENERS; i++) { + if (drawer->listeners [i]) + mateconf_client_notify_remove (client, drawer->listeners [i]); + drawer->listeners [i] = 0; + } + + if (drawer->toplevel) + gtk_widget_destroy (GTK_WIDGET (drawer->toplevel)); + drawer->toplevel = NULL; + + if (drawer->close_timeout_id) + g_source_remove (drawer->close_timeout_id); + drawer->close_timeout_id = 0; +} + +static void +drawer_focus_panel_widget (Drawer *drawer, + GtkDirectionType direction) +{ + PanelWidget *panel_widget; + + panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel); + + gtk_window_present (GTK_WINDOW (drawer->toplevel)); + gtk_container_set_focus_child (GTK_CONTAINER (panel_widget), NULL); + gtk_widget_child_focus (GTK_WIDGET (panel_widget), direction); +} + +static gboolean +key_press_drawer (GtkWidget *widget, + GdkEventKey *event, + Drawer *drawer) +{ + gboolean retval = TRUE; + GtkOrientation orient; + + if (event->state & gtk_accelerator_get_default_mod_mask ()) + return FALSE; + + orient = PANEL_WIDGET (gtk_widget_get_parent (drawer->button))->orient; + + switch (event->keyval) { + case GDK_Up: + case GDK_KP_Up: + if (orient == GTK_ORIENTATION_HORIZONTAL) { + if (!panel_toplevel_get_is_hidden (drawer->toplevel)) + drawer_focus_panel_widget (drawer, GTK_DIR_TAB_BACKWARD); + } else { + /* let default focus movement happen */ + retval = FALSE; + } + break; + case GDK_Left: + case GDK_KP_Left: + if (orient == GTK_ORIENTATION_VERTICAL) { + if (!panel_toplevel_get_is_hidden (drawer->toplevel)) + drawer_focus_panel_widget (drawer, GTK_DIR_TAB_BACKWARD); + } else { + /* let default focus movement happen */ + retval = FALSE; + } + break; + case GDK_Down: + case GDK_KP_Down: + if (orient == GTK_ORIENTATION_HORIZONTAL) { + if (!panel_toplevel_get_is_hidden (drawer->toplevel)) + drawer_focus_panel_widget (drawer, GTK_DIR_TAB_FORWARD); + } else { + /* let default focus movement happen */ + retval = FALSE; + } + break; + case GDK_Right: + case GDK_KP_Right: + if (orient == GTK_ORIENTATION_VERTICAL) { + if (!panel_toplevel_get_is_hidden (drawer->toplevel)) + drawer_focus_panel_widget (drawer, GTK_DIR_TAB_FORWARD); + } else { + /* let default focus movement happen */ + retval = FALSE; + } + break; + case GDK_Escape: + panel_toplevel_hide (drawer->toplevel, FALSE, -1); + break; + default: + retval = FALSE; + break; + } + + return retval; +} + +/* + * This function implements Esc moving focus from the drawer to the drawer + * icon and closing the drawer and Shift+Esc moving focus from the drawer + * to the drawer icon without closing the drawer when focus is in the drawer. + */ +static gboolean +key_press_drawer_widget (GtkWidget *widget, + GdkEventKey *event, + Drawer *drawer) +{ + PanelWidget *panel_widget; + + if (event->keyval != GDK_Escape) + return FALSE; + + panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel); + + gtk_window_present (GTK_WINDOW (panel_widget->toplevel)); + + if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_SHIFT_MASK || + panel_toplevel_get_is_hidden (drawer->toplevel)) + return TRUE; + + panel_toplevel_hide (drawer->toplevel, FALSE, -1); + + return TRUE; +} + +static void +drag_data_received_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time_, + Drawer *drawer) +{ + PanelWidget *panel_widget; + + if (!panel_check_dnd_target_data (widget, context, &info, NULL)) { + gtk_drag_finish (context, FALSE, FALSE, time_); + return; + } + + panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel); + + panel_receive_dnd_data ( + panel_widget, info, -1, selection_data, context, time_); +} + +static gboolean +drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + guint time_, + Drawer *drawer) +{ + PanelWidget *panel_widget; + guint info = 0; + + if (!panel_check_dnd_target_data (widget, context, &info, NULL)) + return FALSE; + + panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel); + + if (!panel_check_drop_forbidden (panel_widget, context, info, time_)) + return FALSE; + + if (drawer->close_timeout_id) + g_source_remove (drawer->close_timeout_id); + drawer->close_timeout_id = 0; + + button_widget_set_dnd_highlight (BUTTON_WIDGET (widget), TRUE); + + if (panel_toplevel_get_is_hidden (drawer->toplevel)) { + panel_toplevel_unhide (drawer->toplevel); + drawer->opened_for_drag = TRUE; + } + + return TRUE; +} + +static gboolean +close_drawer_in_idle (gpointer data) +{ + Drawer *drawer = (Drawer *) data; + + drawer->close_timeout_id = 0; + + if (drawer->opened_for_drag) { + panel_toplevel_hide (drawer->toplevel, FALSE, -1); + drawer->opened_for_drag = FALSE; + } + + return FALSE; +} + +static void +queue_drawer_close_for_drag (Drawer *drawer) +{ + if (!drawer->close_timeout_id) + drawer->close_timeout_id = + g_timeout_add_seconds (1, close_drawer_in_idle, drawer); +} + +static void +drag_leave_cb (GtkWidget *widget, + GdkDragContext *context, + guint time_, + Drawer *drawer) +{ + queue_drawer_close_for_drag (drawer); + + button_widget_set_dnd_highlight (BUTTON_WIDGET (widget), FALSE); +} + +static gboolean +drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + guint time_, + Drawer *drawer) +{ + GdkAtom atom = NULL; + + if (!panel_check_dnd_target_data (widget, context, NULL, &atom)) + return FALSE; + + gtk_drag_get_data (widget, context, atom, time_); + + return TRUE; +} + +static void +drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + Drawer *drawer) +{ + char *foo; + + foo = g_strdup_printf ("DRAWER:%d", panel_find_applet_index (widget)); + + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), 8, (guchar *)foo, + strlen (foo)); + + g_free (foo); +} + +static void +set_tooltip_and_name (Drawer *drawer, + const char *tooltip) +{ + g_return_if_fail (drawer != NULL); + g_return_if_fail (tooltip != NULL); + + if (tooltip && !tooltip [0]) + tooltip = NULL; + + panel_toplevel_set_name (drawer->toplevel, tooltip); + panel_util_set_tooltip_text (drawer->button, tooltip); +} + +static Drawer * +create_drawer_applet (PanelToplevel *toplevel, + PanelToplevel *parent_toplevel, + const char *tooltip, + const char *custom_icon, + gboolean use_custom_icon, + PanelOrientation orientation) +{ + Drawer *drawer; + AtkObject *atk_obj; + + drawer = g_new0 (Drawer, 1); + + drawer->toplevel = toplevel; + + if (!use_custom_icon || !custom_icon || !custom_icon [0]) { + drawer->button = button_widget_new (PANEL_ICON_DRAWER, TRUE, + orientation); + } else { + drawer->button = button_widget_new (custom_icon, TRUE, + orientation); + } + + if (!drawer->button) { + g_free (drawer); + return NULL; + } + atk_obj = gtk_widget_get_accessible (drawer->button); + atk_object_set_name (atk_obj, _("Drawer")); + + set_tooltip_and_name (drawer, tooltip); + + gtk_drag_dest_set (drawer->button, 0, NULL, 0, 0); + + g_signal_connect (drawer->button, "drag_data_get", + G_CALLBACK (drag_data_get_cb), drawer); + g_signal_connect (drawer->button, "drag_data_received", + G_CALLBACK (drag_data_received_cb), drawer); + g_signal_connect (drawer->button, "drag_motion", + G_CALLBACK (drag_motion_cb), drawer); + g_signal_connect (drawer->button, "drag_leave", + G_CALLBACK (drag_leave_cb), drawer); + g_signal_connect (drawer->button, "drag_drop", + G_CALLBACK (drag_drop_cb), drawer); + + g_signal_connect (drawer->button, "clicked", + G_CALLBACK (drawer_click), drawer); + g_signal_connect (drawer->button, "destroy", + G_CALLBACK (destroy_drawer), drawer); + g_signal_connect (drawer->button, "key_press_event", + G_CALLBACK (key_press_drawer), drawer); + g_signal_connect (toplevel, "destroy", + G_CALLBACK (toplevel_destroyed), drawer); + + gtk_widget_show (drawer->button); + + g_signal_connect (drawer->toplevel, "key_press_event", + G_CALLBACK (key_press_drawer_widget), drawer); + + panel_toplevel_attach_to_widget ( + toplevel, parent_toplevel, GTK_WIDGET (drawer->button)); + + return drawer; +} + +static PanelToplevel * +create_drawer_toplevel (const char *drawer_id) +{ + PanelToplevel *toplevel; + MateConfClient *client; + const char *key; + char *toplevel_id; + + client = panel_mateconf_get_client (); + + toplevel_id = panel_profile_find_new_id (PANEL_MATECONF_TOPLEVELS); + + toplevel = panel_profile_load_toplevel (client, PANEL_CONFIG_DIR, + PANEL_MATECONF_TOPLEVELS, toplevel_id); + + if (!toplevel) { + g_free (toplevel_id); + return NULL; + } + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer_id, "attached_toplevel_id"); + mateconf_client_set_string (client, key, toplevel_id, NULL); + g_free (toplevel_id); + + panel_profile_set_toplevel_enable_buttons (toplevel, TRUE); + panel_profile_set_toplevel_enable_arrows (toplevel, TRUE); + + return toplevel; +} + +static void +drawer_button_size_allocated (GtkWidget *widget, + GtkAllocation *alloc, + Drawer *drawer) +{ + if (!gtk_widget_get_realized (widget)) + return; + + gtk_widget_queue_resize (GTK_WIDGET (drawer->toplevel)); + + g_object_set_data (G_OBJECT (widget), "allocated", GINT_TO_POINTER (TRUE)); +} + +static void +panel_drawer_use_custom_icon_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + Drawer *drawer) +{ + gboolean use_custom_icon; + char *custom_icon = NULL; + + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + use_custom_icon = mateconf_value_get_bool (entry->value); + + if (use_custom_icon) { + const char *key; + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer->info->id, "custom_icon"); + custom_icon = mateconf_client_get_string (client, key, NULL); + } + + button_widget_set_icon_name (BUTTON_WIDGET (drawer->button), custom_icon); + + g_free (custom_icon); +} + +static void +panel_drawer_custom_icon_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + Drawer *drawer) +{ + const char *custom_icon; + + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + custom_icon = mateconf_value_get_string (entry->value); + + if (custom_icon && custom_icon [0]) { + const char *key; + gboolean use_custom_icon; + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer->info->id, "use_custom_icon"); + use_custom_icon = mateconf_client_get_bool (client, key, NULL); + if (use_custom_icon) + button_widget_set_icon_name (BUTTON_WIDGET (drawer->button), custom_icon); + } +} + +static void +panel_drawer_tooltip_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + Drawer *drawer) +{ + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + set_tooltip_and_name (drawer, + mateconf_value_get_string (entry->value)); +} + +static void +panel_drawer_connect_to_mateconf (Drawer *drawer) +{ + MateConfClient *client; + const char *key; + int i = 0; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer->info->id, "use_custom_icon"); + drawer->listeners [i++] = + mateconf_client_notify_add (client, key, + (MateConfClientNotifyFunc) panel_drawer_use_custom_icon_changed, + drawer, NULL, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer->info->id, "custom_icon"); + drawer->listeners [i++] = + mateconf_client_notify_add (client, key, + (MateConfClientNotifyFunc) panel_drawer_custom_icon_changed, + drawer, NULL, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer->info->id, "tooltip"); + drawer->listeners [i++] = + mateconf_client_notify_add (client, key, + (MateConfClientNotifyFunc) panel_drawer_tooltip_changed, + drawer, NULL, NULL); + + g_assert (i == PANEL_DRAWER_N_LISTENERS); +} + +static gboolean +drawer_changes_enabled (void) +{ + return !panel_lockdown_get_locked_down (); +} + +static void +load_drawer_applet (char *toplevel_id, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip, + PanelToplevel *parent_toplevel, + gboolean locked, + int pos, + gboolean exactpos, + const char *id) +{ + PanelOrientation orientation; + PanelToplevel *toplevel = NULL; + Drawer *drawer = NULL; + PanelWidget *panel_widget; + + orientation = panel_toplevel_get_orientation (parent_toplevel); + + if (toplevel_id) + toplevel = panel_profile_get_toplevel_by_id (toplevel_id); + + if (!toplevel) + toplevel = create_drawer_toplevel (id); + + if (toplevel) { + panel_toplevel_hide (toplevel, FALSE, -1); + drawer = create_drawer_applet (toplevel, + parent_toplevel, + tooltip, + custom_icon, + use_custom_icon, + orientation); + } + + if (!drawer) + return; + + panel_widget = panel_toplevel_get_panel_widget (parent_toplevel); + + drawer->info = mate_panel_applet_register (drawer->button, drawer, + (GDestroyNotify) g_free, + panel_widget, + locked, pos, exactpos, + PANEL_OBJECT_DRAWER, id); + + if (!drawer->info) { + gtk_widget_destroy (GTK_WIDGET (toplevel)); + return; + } + + g_signal_connect_after (drawer->button, "size_allocate", + G_CALLBACK (drawer_button_size_allocated), drawer); + + panel_widget_add_forbidden (panel_toplevel_get_panel_widget (drawer->toplevel)); + panel_widget_set_applet_expandable (panel_widget, GTK_WIDGET (drawer->button), FALSE, TRUE); + panel_widget_set_applet_size_constrained (panel_widget, GTK_WIDGET (drawer->button), TRUE); + + mate_panel_applet_add_callback (drawer->info, + "add", + GTK_STOCK_ADD, + _("_Add to Drawer..."), + drawer_changes_enabled); + + mate_panel_applet_add_callback (drawer->info, + "properties", + GTK_STOCK_PROPERTIES, + _("_Properties"), + drawer_changes_enabled); + + mate_panel_applet_add_callback (drawer->info, + "help", + GTK_STOCK_HELP, + _("_Help"), + NULL); + + panel_drawer_connect_to_mateconf (drawer); +} + +static void +panel_drawer_prepare (const char *drawer_id, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip, + char **attached_toplevel_id) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + if (tooltip) { + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer_id, "tooltip"); + mateconf_client_set_string (client, key, tooltip, NULL); + } + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer_id, "use_custom_icon"); + mateconf_client_set_bool (client, key, use_custom_icon, NULL); + + if (custom_icon) { + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer_id, "custom_icon"); + mateconf_client_set_string (client, key, custom_icon, NULL); + } + + if (attached_toplevel_id) { + char *toplevel_id; + char *toplevel_dir; + + toplevel_id = panel_profile_find_new_id (PANEL_MATECONF_TOPLEVELS); + + toplevel_dir = g_strdup_printf (PANEL_CONFIG_DIR "/toplevels/%s", + toplevel_id); + panel_mateconf_associate_schemas_in_dir (client, toplevel_dir, PANEL_SCHEMAS_DIR "/toplevels"); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, drawer_id, "attached_toplevel_id"); + mateconf_client_set_string (client, key, toplevel_id, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, toplevel_id, "enable_buttons"); + mateconf_client_set_bool (client, key, TRUE, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, toplevel_id, "enable_arrows"); + mateconf_client_set_bool (client, key, TRUE, NULL); + + *attached_toplevel_id = toplevel_id; + } +} + +void +panel_drawer_create (PanelToplevel *toplevel, + int position, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip) +{ + char *id; + + id = panel_profile_prepare_object (PANEL_OBJECT_DRAWER, toplevel, position, FALSE); + + panel_drawer_prepare (id, custom_icon, use_custom_icon, tooltip, NULL); + + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + + g_free (id); +} + +char * +panel_drawer_create_with_id (const char *toplevel_id, + int position, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip) +{ + char *id; + char *attached_toplevel_id = NULL; + + id = panel_profile_prepare_object_with_id (PANEL_OBJECT_DRAWER, toplevel_id, position, FALSE); + + panel_drawer_prepare (id, custom_icon, use_custom_icon, tooltip, &attached_toplevel_id); + + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + + g_free (id); + + return attached_toplevel_id; +} + +void +drawer_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + gint position, + const char *id) +{ + MateConfClient *client; + const char *key; + gboolean use_custom_icon; + char *toplevel_id; + char *custom_icon; + char *tooltip; + + g_return_if_fail (panel_widget != NULL); + g_return_if_fail (id != NULL); + + client = panel_mateconf_get_client (); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "attached_toplevel_id"); + toplevel_id = mateconf_client_get_string (client, key, NULL); + + panel_profile_load_toplevel (client, PANEL_CONFIG_DIR, PANEL_MATECONF_TOPLEVELS, toplevel_id); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "use_custom_icon"); + use_custom_icon = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "custom_icon"); + custom_icon = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "tooltip"); + tooltip = mateconf_client_get_string (client, key, NULL); + + load_drawer_applet (toplevel_id, + custom_icon, + use_custom_icon, + tooltip, + panel_widget->toplevel, + locked, + position, + TRUE, + id); + + g_free (toplevel_id); + g_free (custom_icon); + g_free (tooltip); +} + +void +panel_drawer_set_dnd_enabled (Drawer *drawer, + gboolean dnd_enabled) +{ + if (dnd_enabled) { + static GtkTargetEntry dnd_targets[] = { + { "application/x-mate-panel-applet-internal", 0, 0 } + }; + + gtk_widget_set_has_window (drawer->button, TRUE); + gtk_drag_source_set (drawer->button, + GDK_BUTTON1_MASK, + dnd_targets, 1, + GDK_ACTION_MOVE); + //FIXME: we're forgetting the use_custom_icon case, here + gtk_drag_source_set_icon_name (drawer->button, + button_widget_get_icon_name (BUTTON_WIDGET (drawer->button))); + + gtk_widget_set_has_window (drawer->button, FALSE); + + } else + gtk_drag_source_unset (drawer->button); +} + +static void +drawer_deletion_response (GtkWidget *dialog, + int response, + Drawer *drawer) +{ + if (response == GTK_RESPONSE_OK) + panel_profile_delete_object (drawer->info); + + gtk_widget_destroy (dialog); +} + +void +drawer_query_deletion (Drawer *drawer) +{ + GtkWidget *dialog; + + if (drawer->toplevel) { + PanelWidget *panel_widget; + + panel_widget = panel_toplevel_get_panel_widget ( + drawer->toplevel); + + if (!panel_global_config_get_confirm_panel_remove () || + !g_list_length (panel_widget->applet_list)) { + panel_profile_delete_object (drawer->info); + return; + } + + dialog = panel_deletion_dialog (drawer->toplevel); + + g_signal_connect (dialog, "response", + G_CALLBACK (drawer_deletion_response), + drawer); + + g_signal_connect_object (drawer->toplevel, "destroy", + G_CALLBACK (gtk_widget_destroy), + dialog, + G_CONNECT_SWAPPED); + + gtk_widget_show_all (dialog); + } +} diff --git a/mate-panel/drawer.h b/mate-panel/drawer.h new file mode 100644 index 00000000..800e1a86 --- /dev/null +++ b/mate-panel/drawer.h @@ -0,0 +1,52 @@ +#ifndef DRAWER_H +#define DRAWER_H + +#include "panel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_DRAWER_N_LISTENERS 3 + +typedef struct { + char *tooltip; + + PanelToplevel *toplevel; + GtkWidget *button; + + gboolean opened_for_drag; + guint close_timeout_id; + + AppletInfo *info; + + guint listeners [PANEL_DRAWER_N_LISTENERS]; +} Drawer; + +void panel_drawer_create (PanelToplevel *toplevel, + int position, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip); + +char *panel_drawer_create_with_id (const char *toplevel_id, + int position, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip); + +void panel_drawer_set_dnd_enabled (Drawer *drawer, + gboolean dnd_enabled); + +void drawer_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + gint position, + const char *id); + +void drawer_query_deletion (Drawer *drawer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mate-panel/launcher.c b/mate-panel/launcher.c new file mode 100644 index 00000000..657bc0c8 --- /dev/null +++ b/mate-panel/launcher.c @@ -0,0 +1,1114 @@ +/* + * MATE panel launcher module. + * (C) 1997,1998,1999,2000 The Free Software Foundation + * (C) 2000 Eazel, Inc. + * + * Authors: Miguel de Icaza + * Federico Mena + * CORBAized by George Lebl + * de-CORBAized by George Lebl + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "launcher.h" + +#include "button-widget.h" +#include "panel-util.h" +#include "panel-config-global.h" +#include "panel-mateconf.h" +#include "panel-profile.h" +#include "xstuff.h" +#include "panel-toplevel.h" +#include "panel-a11y.h" +#include "panel-globals.h" +#include "panel-multiscreen.h" +#include "panel-lockdown.h" +#include "panel-compatibility.h" +#include "panel-ditem-editor.h" +#include "panel-icon-names.h" + +static GdkScreen * +launcher_get_screen (Launcher *launcher) +{ + PanelWidget *panel_widget; + + g_return_val_if_fail (launcher != NULL, NULL); + g_return_val_if_fail (launcher->info != NULL, NULL); + g_return_val_if_fail (launcher->info->widget != NULL, NULL); + + panel_widget = PANEL_WIDGET (gtk_widget_get_parent (launcher->info->widget)); + + return gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel)); +} + +static void +launcher_widget_open_dialog_destroyed (GtkWidget *dialog, + Launcher *launcher) +{ + g_return_if_fail (launcher->error_dialogs != NULL); + + launcher->error_dialogs = g_slist_remove (launcher->error_dialogs, dialog); +} + +static void +launcher_widget_destroy_open_dialogs (Launcher *launcher) +{ + GSList *l, *list; + + list = launcher->error_dialogs; + launcher->error_dialogs = NULL; + + for (l = list; l; l = l->next) { + g_signal_handlers_disconnect_by_func (G_OBJECT (l->data), + G_CALLBACK (launcher_widget_open_dialog_destroyed), + launcher); + gtk_widget_destroy (l->data); + } + g_slist_free (list); +} + +static void +launcher_register_error_dialog (Launcher *launcher, + GtkWidget *dialog) +{ + launcher->error_dialogs = g_slist_append (launcher->error_dialogs, + dialog); + g_signal_connect (dialog, "destroy", + G_CALLBACK (launcher_widget_open_dialog_destroyed), + launcher); +} + +static void +launch_url (Launcher *launcher) +{ + char *url; + GdkScreen *screen; + + g_return_if_fail (launcher != NULL); + g_return_if_fail (launcher->key_file != NULL); + + /* FIXME panel_ditem_launch() should be enough for this! */ + url = panel_key_file_get_string (launcher->key_file, "URL"); + + screen = launcher_get_screen (launcher); + + if (!url || *url == 0) { + GtkWidget *error_dialog; + + error_dialog = panel_error_dialog (NULL, screen, + "no_url_dialog", TRUE, + _("Could not show this URL"), + _("No URL was specified.")); + launcher_register_error_dialog (launcher, error_dialog); + g_free (url); + return; + } + + panel_show_uri (screen, url, gtk_get_current_event_time (), NULL); + + g_free (url); +} + +void +launcher_launch (Launcher *launcher, + GtkWidget *widget) +{ + char *type; + + g_return_if_fail (launcher != NULL); + g_return_if_fail (launcher->key_file != NULL); + + if (panel_global_config_get_enable_animations ()) + xstuff_zoom_animate (widget, + button_widget_get_pixbuf (BUTTON_WIDGET (widget)), + button_widget_get_orientation (BUTTON_WIDGET (widget)), + NULL); + + type = panel_key_file_get_string (launcher->key_file, "Type"); + if (type && !strcmp (type, "Link")) + launch_url (launcher); + else { + GError *error = NULL; + + panel_launch_key_file (launcher->key_file, NULL, + launcher_get_screen (launcher), &error); + if (error) { + GtkWidget *error_dialog; + + error_dialog = panel_error_dialog ( + NULL, + launcher_get_screen (launcher), + "cannot_launch_application", + TRUE, + _("Could not launch application"), + error->message); + launcher_register_error_dialog (launcher, error_dialog); + g_clear_error (&error); + } + } + g_free (type); + + if (panel_global_config_get_drawer_auto_close ()) { + PanelToplevel *toplevel; + PanelToplevel *parent; + + toplevel = PANEL_WIDGET (gtk_widget_get_parent (launcher->button))->toplevel; + + if (panel_toplevel_get_is_attached (toplevel)) { + parent = panel_toplevel_get_attach_toplevel (toplevel); + + while (panel_toplevel_get_is_attached (parent)) { + toplevel = parent; + parent = panel_toplevel_get_attach_toplevel (toplevel); + } + + panel_toplevel_hide (toplevel, FALSE, -1); + } + } +} + +static void +drag_data_received_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time, + Launcher *launcher) +{ + GError *error = NULL; + char **uris; + int i; + GList *file_list; + + if (panel_global_config_get_enable_animations ()) + xstuff_zoom_animate (widget, + button_widget_get_pixbuf (BUTTON_WIDGET (widget)), + button_widget_get_orientation (BUTTON_WIDGET (widget)), + NULL); + + file_list = NULL; + uris = g_uri_list_extract_uris ((const char *) gtk_selection_data_get_data (selection_data)); + for (i = 0; uris[i]; i++) + file_list = g_list_prepend (file_list, uris[i]); + file_list = g_list_reverse (file_list); + + panel_launch_key_file (launcher->key_file, file_list, + launcher_get_screen (launcher), &error); + + g_list_free (file_list); + g_strfreev (uris); + + if (error) { + GtkWidget *error_dialog; + error_dialog = panel_error_dialog (NULL, + launcher_get_screen (launcher), + "cannot_use_dropped_item", + TRUE, + _("Could not use dropped item"), + error->message); + launcher_register_error_dialog (launcher, error_dialog); + g_clear_error (&error); + } + + gtk_drag_finish (context, TRUE, FALSE, time); +} + +static void +destroy_launcher (GtkWidget *widget, + Launcher *launcher) +{ + launcher_properties_destroy (launcher); + launcher_widget_destroy_open_dialogs (launcher); +} + +void +launcher_properties_destroy (Launcher *launcher) +{ + GtkWidget *dialog; + + dialog = launcher->prop_dialog; + launcher->prop_dialog = NULL; + + if (dialog) + gtk_widget_destroy (dialog); +} + +static void +free_launcher (gpointer data) +{ + Launcher *launcher = data; + + if (launcher->key_file) + g_key_file_free (launcher->key_file); + launcher->key_file = NULL; + + if (launcher->location != NULL) + g_free (launcher->location); + launcher->location = NULL; + + g_free (launcher); +} + +void +panel_launcher_delete (Launcher *launcher) +{ + if (!launcher->location) + return; + + /* do not remove the file if it's not in the user's launchers path */ + if (panel_launcher_is_in_personal_path (launcher->location)) { + GError *error; + GFile *file; + + file = panel_launcher_get_gfile (launcher->location); + + error = NULL; + if (!g_file_delete (file, NULL, &error)) { + char *path; + + path = g_file_get_path (file); + g_warning ("Error deleting '%s': %s\n", + path, error->message); + g_free (path); + g_error_free (error); + } + + g_object_unref (file); + } +} + +static gboolean +is_this_drop_ok (GtkWidget *widget, + GdkDragContext *context) +{ + static GdkAtom text_uri_list = GDK_NONE; + GList *l; + GtkWidget *source; + + source = gtk_drag_get_source_widget (context); + + if (source == widget) + return FALSE; + + if (!(gdk_drag_context_get_actions (context) & GDK_ACTION_COPY)) + return FALSE; + + if (!text_uri_list) + text_uri_list = gdk_atom_intern_static_string ("text/uri-list"); + + for (l = gdk_drag_context_list_targets (context); l; l = l->next) { + if (GDK_POINTER_TO_ATOM (l->data) == text_uri_list) + break; + } + + return l ? TRUE : FALSE; +} + +static void +drag_leave_cb(GtkWidget *widget, + GdkDragContext *context, + guint time, + Launcher *launcher) +{ + button_widget_set_dnd_highlight(BUTTON_WIDGET(widget), FALSE); +} + + +static gboolean +drag_motion_cb(GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + Launcher *launcher) +{ + if ( ! is_this_drop_ok (widget, context)) + return FALSE; + + gdk_drag_status (context, GDK_ACTION_COPY, time); + + button_widget_set_dnd_highlight(BUTTON_WIDGET(widget), TRUE); + + return TRUE; +} + +static gboolean +drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + Launcher *launcher) +{ + static GdkAtom text_uri_list = NULL; + + if ( ! is_this_drop_ok (widget, context)) + return FALSE; + + if (text_uri_list == NULL) + text_uri_list = gdk_atom_intern_static_string ("text/uri-list"); + + gtk_drag_get_data (widget, context, text_uri_list, time); + + return TRUE; +} + +enum { + TARGET_ICON_INTERNAL, + TARGET_URI_LIST +}; + + +static void +drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + Launcher *launcher) +{ + char *location; + + g_return_if_fail (launcher != NULL); + + location = launcher->location; + + if (info == TARGET_URI_LIST) { + char *uri[2]; + + uri[0] = panel_launcher_get_uri (location); + uri[1] = NULL; + + gtk_selection_data_set_uris (selection_data, uri); + + g_free (uri[0]); + } else if (info == TARGET_ICON_INTERNAL) + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), 8, + (unsigned char *) location, + strlen (location)); + +} + +static Launcher * +create_launcher (const char *location) +{ + GKeyFile *key_file; + gboolean loaded; + Launcher *launcher; + GError *error = NULL; + char *new_location; + + if (!location) { + g_printerr (_("No URI provided for panel launcher desktop file\n")); + return NULL; + } + + new_location = NULL; + key_file = g_key_file_new (); + + if (!strchr (location, G_DIR_SEPARATOR)) { + /* try to first load a file in our config directory, and if it + * doesn't exist there, try to find it in the xdg data dirs */ + char *path; + + path = panel_make_full_path (NULL, location); + + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_free (path); + path = panel_g_lookup_in_applications_dirs (location); + /* it's important to keep the full path if the desktop + * file comes from a data dir: when the user will edit + * it, we'll want to save it in PANEL_LAUNCHERS_PATH + * with a random name (and not evolution.desktop, eg) + * and having only a basename as location will make + * this impossible */ + if (path) + new_location = g_strdup (path); + } + + if (path) { + loaded = g_key_file_load_from_file (key_file, path, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, + &error); + g_free (path); + } + } else + loaded = panel_key_file_load_from_uri (key_file, location, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, + &error); + + if (!loaded) { + g_printerr (_("Unable to open desktop file %s for panel launcher%s%s\n"), + location, + error ? ": " : "", + error ? error->message : ""); + if (error) + g_error_free (error); + + g_key_file_free (key_file); + + return NULL; /*button is null*/ + } + + if (!new_location) + new_location = g_strdup (location); + + launcher = g_new0 (Launcher, 1); + + launcher->info = NULL; + launcher->button = NULL; + launcher->location = new_location; + launcher->key_file = key_file; + launcher->prop_dialog = NULL; + launcher->destroy_handler = 0; + + /* Icon will be setup later */ + launcher->button = button_widget_new (NULL /* icon */, + FALSE, + PANEL_ORIENTATION_TOP); + + gtk_widget_show (launcher->button); + + /*gtk_drag_dest_set (GTK_WIDGET (launcher->button), + GTK_DEST_DEFAULT_ALL, + dnd_targets, 2, + GDK_ACTION_COPY);*/ + gtk_drag_dest_set (GTK_WIDGET (launcher->button), + 0, NULL, 0, 0); + + g_signal_connect (launcher->button, "drag_data_get", + G_CALLBACK (drag_data_get_cb), launcher); + g_signal_connect (launcher->button, "drag_data_received", + G_CALLBACK (drag_data_received_cb), launcher); + g_signal_connect (launcher->button, "drag_motion", + G_CALLBACK (drag_motion_cb), launcher); + g_signal_connect (launcher->button, "drag_drop", + G_CALLBACK (drag_drop_cb), launcher); + g_signal_connect (launcher->button, "drag_leave", + G_CALLBACK (drag_leave_cb), launcher); + g_signal_connect_swapped (launcher->button, "clicked", + G_CALLBACK (launcher_launch), launcher); + + launcher->destroy_handler = + g_signal_connect (launcher->button, "destroy", + G_CALLBACK (destroy_launcher), + launcher); + + return launcher; +} + +static void +setup_button (Launcher *launcher) +{ + char *comment; + char *name; + char *str; + char *icon; + char *unescaped_str; + + g_return_if_fail (launcher != NULL); + + name = panel_key_file_get_locale_string (launcher->key_file, "Name"); + comment = panel_key_file_get_locale_string (launcher->key_file, + "Comment"); + + /* Setup tooltip */ + if (!PANEL_GLIB_STR_EMPTY (name) && !PANEL_GLIB_STR_EMPTY (comment)) + str = g_strdup_printf ("%s\n%s", name, comment); + else if (!PANEL_GLIB_STR_EMPTY (name)) + str = g_strdup (name); + else + str = g_strdup (comment); + + g_free (name); + g_free (comment); + + /* If we can unescape the string, then we probably have an escaped + * string (a location e.g.). If we can't, then it most probably means + * we have a % that is not here to encode a character, and we don't + * want to unescape in this case. See bug #170516 for details. */ + unescaped_str = g_uri_unescape_string (str, NULL); + if (unescaped_str) { + g_free (str); + str = unescaped_str; + } + + panel_util_set_tooltip_text (launcher->button, str); + + /* Setup accessible name */ + panel_a11y_set_atk_name_desc (launcher->button, str, NULL); + + g_free (str); + + /* Setup icon */ + icon = panel_key_file_get_locale_string (launcher->key_file, "Icon"); + if (icon && icon[0] == '\0') { + g_free (icon); + icon = NULL; + } + + if (!icon) + icon = guess_icon_from_exec (button_widget_get_icon_theme (BUTTON_WIDGET (launcher->button)), + launcher->key_file); + if (!icon) + icon = g_strdup (PANEL_ICON_LAUNCHER); + + button_widget_set_icon_name (BUTTON_WIDGET (launcher->button), icon); + g_free (icon); +} + +static char * +panel_launcher_find_writable_uri (const char *launcher_location, + const char *source) +{ + char *path; + char *uri; + + if (!launcher_location) + return panel_make_unique_desktop_uri (NULL, source); + + if (!strchr (launcher_location, G_DIR_SEPARATOR)) { + path = panel_make_full_path (NULL, launcher_location); + uri = g_filename_to_uri (path, NULL, NULL); + g_free (path); + return uri; + } + + if (panel_launcher_get_filename (launcher_location) != NULL) { + /* we have a file in the user directory. We either have a path + * or an URI */ + if (g_path_is_absolute (launcher_location)) + return g_filename_to_uri (launcher_location, + NULL, NULL); + else + return g_strdup (launcher_location); + } + + return panel_make_unique_desktop_uri (NULL, source); +} + +static void +launcher_changed (PanelDItemEditor *dialog, + Launcher *launcher) +{ + /* Setup the button look */ + setup_button (launcher); +} + +static void +launcher_command_changed (PanelDItemEditor *dialog, + const char *command, + Launcher *launcher) +{ + char *exec; + char *old_exec; + GKeyFile *revert_key_file; + + revert_key_file = panel_ditem_editor_get_revert_key_file (dialog); + + if (revert_key_file) { + exec = panel_key_file_get_string (launcher->key_file, "Exec"); + old_exec = panel_key_file_get_string (revert_key_file, "Exec"); + + if (!old_exec || !exec || strcmp (old_exec, exec)) + panel_key_file_remove_key (launcher->key_file, + "StartupNotify"); + + g_free (exec); + g_free (old_exec); + } +} + +static char * +launcher_save_uri (PanelDItemEditor *dialog, + gpointer data) +{ + GKeyFile *key_file; + char *type; + char *exec_or_uri; + Launcher *launcher; + char *new_uri; + const char *uri; + + key_file = panel_ditem_editor_get_key_file (dialog); + type = panel_key_file_get_string (key_file, "Type"); + if (type && !strcmp (type, "Application")) + exec_or_uri = panel_key_file_get_string (key_file, "Exec"); + else if (type && !strcmp (type, "Link")) + exec_or_uri = panel_key_file_get_string (key_file, "URL"); + else + exec_or_uri = panel_key_file_get_string (key_file, "Name"); + g_free (type); + + launcher = (Launcher *) data; + + if (launcher) + new_uri = panel_launcher_find_writable_uri (launcher->location, + exec_or_uri); + else + new_uri = panel_launcher_find_writable_uri (NULL, exec_or_uri); + + g_free (exec_or_uri); + + uri = panel_ditem_editor_get_uri (dialog); + + if (!uri || (new_uri && strcmp (new_uri, uri))) + return new_uri; + + g_free (new_uri); + + return NULL; +} + +static void +launcher_saved (GtkWidget *dialog, + Launcher *launcher) +{ + const char *uri; + MateConfClient *client; + const char *key; + + uri = panel_ditem_editor_get_uri (PANEL_DITEM_EDITOR (dialog)); + if (panel_launcher_get_filename (uri) != NULL) + uri = panel_launcher_get_filename (uri); + + if (uri && launcher->location && strcmp (uri, launcher->location)) { + client = panel_mateconf_get_client (); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, + launcher->info->id, + "launcher_location"); + + mateconf_client_set_string (client, key, uri, NULL); + + if (launcher->location) + g_free (launcher->location); + launcher->location = g_strdup (uri); + } +} + +static void +launcher_error_reported (GtkWidget *dialog, + const char *primary, + const char *secondary, + gpointer data) +{ + panel_error_dialog (GTK_WINDOW (dialog), NULL, + "error_editing_launcher", TRUE, + primary, secondary); +} + +void +launcher_properties (Launcher *launcher) +{ + if (launcher->prop_dialog != NULL) { + gtk_window_set_screen (GTK_WINDOW (launcher->prop_dialog), + gtk_widget_get_screen (launcher->button)); + gtk_window_present (GTK_WINDOW (launcher->prop_dialog)); + return; + } + + launcher->prop_dialog = panel_ditem_editor_new (NULL, + launcher->key_file, + launcher->location, + _("Launcher Properties")); + + panel_widget_register_open_dialog (PANEL_WIDGET + (gtk_widget_get_parent (launcher->info->widget)), + launcher->prop_dialog); + + panel_ditem_register_save_uri_func (PANEL_DITEM_EDITOR (launcher->prop_dialog), + launcher_save_uri, + launcher); + + g_signal_connect (launcher->prop_dialog, "changed", + G_CALLBACK (launcher_changed), launcher); + + g_signal_connect (launcher->prop_dialog, "command_changed", + G_CALLBACK (launcher_command_changed), launcher); + + g_signal_connect (launcher->prop_dialog, "saved", + G_CALLBACK (launcher_saved), launcher); + + g_signal_connect (launcher->prop_dialog, "error_reported", + G_CALLBACK (launcher_error_reported), NULL); + + g_signal_connect (launcher->prop_dialog, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &launcher->prop_dialog); + + gtk_widget_show (launcher->prop_dialog); +} + +static gboolean +lancher_properties_enabled (void) +{ + if (panel_lockdown_get_locked_down () || + panel_lockdown_get_disable_command_line ()) + return FALSE; + + return TRUE; +} + +static Launcher * +load_launcher_applet (const char *location, + PanelWidget *panel, + gboolean locked, + int pos, + gboolean exactpos, + const char *id) +{ + Launcher *launcher; + + launcher = create_launcher (location); + + if (!launcher) + return NULL; + + launcher->info = mate_panel_applet_register (launcher->button, launcher, + free_launcher, + panel, locked, pos, exactpos, + PANEL_OBJECT_LAUNCHER, id); + if (!launcher->info) { + free_launcher (launcher); + return NULL; + } + + mate_panel_applet_add_callback (launcher->info, + "launch", + GTK_STOCK_EXECUTE, + _("_Launch"), + NULL); + + mate_panel_applet_add_callback (launcher->info, + "properties", + GTK_STOCK_PROPERTIES, + _("_Properties"), + lancher_properties_enabled); + + panel_widget_set_applet_expandable (panel, GTK_WIDGET (launcher->button), FALSE, TRUE); + panel_widget_set_applet_size_constrained (panel, GTK_WIDGET (launcher->button), TRUE); + + /* setup button according to ditem */ + setup_button (launcher); + + return launcher; +} + +void +launcher_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + int position, + const char *id) +{ + MateConfClient *client; + Launcher *launcher; + const char *key; + char *launcher_location; + + g_return_if_fail (panel_widget != NULL); + g_return_if_fail (id != NULL); + + client = panel_mateconf_get_client (); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "launcher_location"); + panel_compatibility_migrate_applications_scheme (client, key); + launcher_location = mateconf_client_get_string (client, key, NULL); + + if (!launcher_location) { + g_printerr (_("Key %s is not set, cannot load launcher\n"), + key); + return; + } + + launcher = load_launcher_applet (launcher_location, + panel_widget, + locked, + position, + TRUE, + id); + + if (launcher) { + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "launcher_location"); + if (!mateconf_client_key_is_writable (client, key, NULL)) { + AppletUserMenu *menu; + + menu = mate_panel_applet_get_callback (launcher->info->user_menu, + "properties"); + if (menu != NULL) + menu->sensitive = FALSE; + } + } + + g_free (launcher_location); +} + +static void +launcher_new_saved (GtkWidget *dialog, + gpointer data) +{ + PanelWidget *panel; + int pos; + const char *uri; + + pos = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), "pos")); + panel = g_object_get_data (G_OBJECT (dialog), "panel"); + + uri = panel_ditem_editor_get_uri (PANEL_DITEM_EDITOR (dialog)); + if (panel_launcher_get_filename (uri) != NULL) + uri = panel_launcher_get_filename (uri); + panel_launcher_create (panel->toplevel, pos, uri); +} + +void +ask_about_launcher (const char *file, + PanelWidget *panel, + int pos, + gboolean exactpos) +{ + GtkWidget *dialog; + GKeyFile *key_file; + + if (panel_lockdown_get_disable_command_line ()) + return; + + dialog = panel_ditem_editor_new (NULL, NULL, NULL, + _("Create Launcher")); + panel_widget_register_open_dialog (panel, dialog); + + key_file = panel_ditem_editor_get_key_file (PANEL_DITEM_EDITOR (dialog)); + if (file != NULL) + panel_key_file_set_string (key_file, "Exec", file); + panel_key_file_set_string (key_file, "Type", "Application"); + panel_ditem_editor_sync_display (PANEL_DITEM_EDITOR (dialog)); + + panel_ditem_register_save_uri_func (PANEL_DITEM_EDITOR (dialog), + launcher_save_uri, + NULL); + + g_signal_connect (G_OBJECT (dialog), "saved", + G_CALLBACK (launcher_new_saved), NULL); + + g_signal_connect (G_OBJECT (dialog), "error_reported", + G_CALLBACK (launcher_error_reported), NULL); + + gtk_window_set_screen (GTK_WINDOW (dialog), + gtk_widget_get_screen (GTK_WIDGET (panel))); + + g_object_set_data (G_OBJECT (dialog), "pos", GINT_TO_POINTER (pos)); + g_object_set_data (G_OBJECT (dialog), "panel", panel); + + gtk_widget_show (dialog); +} + +void +panel_launcher_create_from_info (PanelToplevel *toplevel, + int position, + gboolean exec_info, + const char *exec_or_uri, + const char *name, + const char *comment, + const char *icon) +{ + GKeyFile *key_file; + char *location; + GError *error; + + key_file = panel_key_file_new_desktop (); + + /* set current language and the "C" locale to this name, + * this is kind of evil... */ + panel_key_file_set_string (key_file, "Name", name); + panel_key_file_set_string (key_file, "Comment", comment); + panel_key_file_set_string (key_file, "Icon", icon); + panel_key_file_set_locale_string (key_file, "Name", name); + panel_key_file_set_locale_string (key_file, "Comment", comment); + panel_key_file_set_locale_string (key_file, "Icon", icon); + + if (exec_info) { + panel_key_file_set_string (key_file, "Exec", exec_or_uri); + panel_key_file_set_string (key_file, "Type", "Application"); + } else { + panel_key_file_set_string (key_file, "URL", exec_or_uri); + panel_key_file_set_string (key_file, "Type", "Link"); + } + + location = panel_make_unique_desktop_uri (NULL, exec_or_uri); + + error = NULL; + if (panel_key_file_to_file (key_file, location, &error)) { + panel_launcher_create (toplevel, position, location); + } else { + panel_error_dialog (GTK_WINDOW (toplevel), + gtk_window_get_screen (GTK_WINDOW (toplevel)), + "cannot_save_launcher", TRUE, + _("Could not save launcher"), + error->message); + g_error_free (error); + } + + g_key_file_free (key_file); +} + +void +panel_launcher_create_with_id (const char *toplevel_id, + int position, + const char *location) +{ + MateConfClient *client; + const char *key; + char *id; + char *no_uri; + const char *new_location; + + g_return_if_fail (location != NULL); + + client = panel_mateconf_get_client (); + + id = panel_profile_prepare_object_with_id (PANEL_OBJECT_LAUNCHER, + toplevel_id, + position, + FALSE); + + no_uri = NULL; + /* if we have an URI, it might contain escaped characters (? : etc) + * that might get unescaped on disk */ + if (!g_ascii_strncasecmp (location, "file:", strlen ("file:"))) + no_uri = g_filename_from_uri (location, NULL, NULL); + if (!no_uri) + no_uri = g_strdup (location); + + new_location = panel_launcher_get_filename (no_uri); + if (new_location == NULL) + new_location = no_uri; + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, + id, + "launcher_location"); + mateconf_client_set_string (client, key, new_location, NULL); + + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + + g_free (no_uri); + g_free (id); +} + +void +panel_launcher_create (PanelToplevel *toplevel, + int position, + const char *location) +{ + panel_launcher_create_with_id (panel_profile_get_toplevel_id (toplevel), + position, + location); +} + +gboolean +panel_launcher_create_copy (PanelToplevel *toplevel, + int position, + const char *location) +{ + char *new_location; + GFile *source; + GFile *dest; + gboolean copied; + const char *filename; + + new_location = panel_make_unique_desktop_uri (NULL, location); + + source = panel_launcher_get_gfile (location); + dest = g_file_new_for_uri (new_location); + + copied = g_file_copy (source, dest, G_FILE_COPY_OVERWRITE, + NULL, NULL, NULL, NULL); + + if (!copied) { + g_free (new_location); + return FALSE; + } + + filename = panel_launcher_get_filename (new_location); + panel_launcher_create (toplevel, position, filename); + g_free (new_location); + + return TRUE; +} + +Launcher * +find_launcher (const char *path) +{ + GSList *l; + + g_return_val_if_fail (path != NULL, NULL); + + for (l = mate_panel_applet_list_applets (); l; l = l->next) { + AppletInfo *info = l->data; + Launcher *launcher; + + if (info->type != PANEL_OBJECT_LAUNCHER) + continue; + + launcher = info->data; + + if (launcher->key_file == NULL) + continue; + + if (launcher->location != NULL && + strcmp (launcher->location, path) == 0) + return launcher; + } + + return NULL; +} + +void +panel_launcher_set_dnd_enabled (Launcher *launcher, + gboolean dnd_enabled) +{ + GdkPixbuf *pixbuf; + + if (dnd_enabled) { + static GtkTargetEntry dnd_targets[] = { + { "application/x-panel-icon-internal", 0, TARGET_ICON_INTERNAL }, + { "text/uri-list", 0, TARGET_URI_LIST } + }; + + gtk_widget_set_has_window (launcher->button, TRUE); + gtk_drag_source_set (launcher->button, + GDK_BUTTON1_MASK, + dnd_targets, 2, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + //FIXME: this doesn't work since the pixbuf isn't loaded yet + pixbuf = button_widget_get_pixbuf (BUTTON_WIDGET (launcher->button)); + if (pixbuf) { + gtk_drag_source_set_icon_pixbuf (launcher->button, + pixbuf); + g_object_unref (pixbuf); + } + gtk_widget_set_has_window (launcher->button, FALSE); + + + } else + gtk_drag_source_unset (launcher->button); +} diff --git a/mate-panel/launcher.h b/mate-panel/launcher.h new file mode 100644 index 00000000..1b2d7b88 --- /dev/null +++ b/mate-panel/launcher.h @@ -0,0 +1,80 @@ +/* + * MATE panel launcher module. + * (C) 1997 The Free Software Foundation + * + * Authors: Miguel de Icaza + * Federico Mena + * CORBAized by George Lebl + * de-CORBAized by George Lebl + */ + +#ifndef LAUNCHER_H +#define LAUNCHER_H + +#include "applet.h" +#include "panel-widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + AppletInfo *info; + GtkWidget *button; + + char *location; + GKeyFile *key_file; + + GtkWidget *prop_dialog; + GSList *error_dialogs; + + gulong destroy_handler; +} Launcher; + +void panel_launcher_create (PanelToplevel *toplevel, + int position, + const char *location); +void panel_launcher_create_with_id (const char *toplevel_id, + int position, + const char *location); +gboolean panel_launcher_create_copy (PanelToplevel *toplevel, + int position, + const char *location); +void panel_launcher_create_from_info (PanelToplevel *toplevel, + int position, + gboolean exec_info, + const char *exec_or_uri, + const char *name, + const char *comment, + const char *icon); + +void launcher_launch (Launcher *launcher, + GtkWidget *widget); + +void launcher_properties (Launcher *launcher); + +void launcher_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + gint position, + const char *id); + +void panel_launcher_delete (Launcher *launcher); + +void ask_about_launcher (const char *file, + PanelWidget *panel, + int pos, + gboolean exactpos); + +Launcher * find_launcher (const char *path); + +void launcher_properties_destroy (Launcher *launcher); + +void panel_launcher_set_dnd_enabled (Launcher *launcher, + gboolean dnd_enabled); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mate-panel/libegg/Makefile.am b/mate-panel/libegg/Makefile.am new file mode 100644 index 00000000..c50c1fa0 --- /dev/null +++ b/mate-panel/libegg/Makefile.am @@ -0,0 +1,25 @@ +platform_defines = -DEGG_SM_CLIENT_BACKEND_XSMP +platform_sources = eggsmclient-xsmp.c + +noinst_LTLIBRARIES = libegg.la + +AM_CPPFLAGS = \ + $(EGG_SMCLIENT_CFLAGS) \ + -DG_LOG_DOMAIN=\""EggSMClient"\"\ + $(platform_defines) \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) + +libegg_la_SOURCES = \ + eggdesktopfile.c \ + eggdesktopfile.h \ + eggsmclient.c \ + eggsmclient.h \ + eggsmclient-private.h \ + $(platform_sources) + +libegg_la_LIBADD = \ + $(EGG_SMCLIENT_LIBS) + +-include $(top_srcdir)/git.mk diff --git a/mate-panel/libegg/Makefile.in b/mate-panel/libegg/Makefile.in new file mode 100644 index 00000000..742fd6ed --- /dev/null +++ b/mate-panel/libegg/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = mate-panel/libegg +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/d-type.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +libegg_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_1 = eggsmclient-xsmp.lo +am_libegg_la_OBJECTS = eggdesktopfile.lo eggsmclient.lo \ + $(am__objects_1) +libegg_la_OBJECTS = $(am_libegg_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libegg_la_SOURCES) +DIST_SOURCES = $(libegg_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLOCK_CFLAGS = @CLOCK_CFLAGS@ +CLOCK_EDS_ICONDIR = @CLOCK_EDS_ICONDIR@ +CLOCK_LIBS = @CLOCK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DISABLE_DEPRECATED_CFLAGS = @DISABLE_DEPRECATED_CFLAGS@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOC_USER_FORMATS = @DOC_USER_FORMATS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGG_SMCLIENT_CFLAGS = @EGG_SMCLIENT_CFLAGS@ +EGG_SMCLIENT_LIBS = @EGG_SMCLIENT_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FISH_CFLAGS = @FISH_CFLAGS@ +FISH_LIBS = @FISH_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_QUERYMODULES = @GIO_QUERYMODULES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HELP_DIR = @HELP_DIR@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBMATE_PANEL_APPLET_CFLAGS = @LIBMATE_PANEL_APPLET_CFLAGS@ +LIBMATE_PANEL_APPLET_LIBS = @LIBMATE_PANEL_APPLET_LIBS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MATE_PANEL_APPLET_LT_VERSION = @LIB_MATE_PANEL_APPLET_LT_VERSION@ +LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION = @LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECOMPONENT_ACT_IDLDIR = @MATECOMPONENT_ACT_IDLDIR@ +MATECOMPONENT_CFLAGS = @MATECOMPONENT_CFLAGS@ +MATECOMPONENT_IDLDIR = @MATECOMPONENT_IDLDIR@ +MATECOMPONENT_LIBS = @MATECOMPONENT_LIBS@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATECORBA_IDL = @MATECORBA_IDL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NETWORK_MANAGER_CFLAGS = @NETWORK_MANAGER_CFLAGS@ +NETWORK_MANAGER_LIBS = @NETWORK_MANAGER_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOTIFICATION_AREA_CFLAGS = @NOTIFICATION_AREA_CFLAGS@ +NOTIFICATION_AREA_LIBS = @NOTIFICATION_AREA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OMF_DIR = @OMF_DIR@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANEL_CFLAGS = @PANEL_CFLAGS@ +PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE = @PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ +PANEL_LIBS = @PANEL_LIBS@ +PANEL_MODULE_MATECOMPONENT_CFLAGS = @PANEL_MODULE_MATECOMPONENT_CFLAGS@ +PANEL_MODULE_MATECOMPONENT_LIBS = @PANEL_MODULE_MATECOMPONENT_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POFILES = @POFILES@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REBUILD = @REBUILD@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TZ_CFLAGS = @TZ_CFLAGS@ +TZ_LIBS = @TZ_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WNCKLET_CFLAGS = @WNCKLET_CFLAGS@ +WNCKLET_LIBS = @WNCKLET_LIBS@ +XGETTEXT = @XGETTEXT@ +XMKMF = @XMKMF@ +XRANDR_CFLAGS = @XRANDR_CFLAGS@ +XRANDR_LIBS = @XRANDR_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +appletsdir = @appletsdir@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +modulesdir = @modulesdir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +platform_defines = -DEGG_SM_CLIENT_BACKEND_XSMP +platform_sources = eggsmclient-xsmp.c +noinst_LTLIBRARIES = libegg.la +AM_CPPFLAGS = \ + $(EGG_SMCLIENT_CFLAGS) \ + -DG_LOG_DOMAIN=\""EggSMClient"\"\ + $(platform_defines) \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) +libegg_la_SOURCES = \ + eggdesktopfile.c \ + eggdesktopfile.h \ + eggsmclient.c \ + eggsmclient.h \ + eggsmclient-private.h \ + $(platform_sources) + +libegg_la_LIBADD = \ + $(EGG_SMCLIENT_LIBS) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu mate-panel/libegg/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu mate-panel/libegg/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libegg.la: $(libegg_la_OBJECTS) $(libegg_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libegg_la_OBJECTS) $(libegg_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eggdesktopfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eggsmclient-xsmp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eggsmclient.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mate-panel/libegg/eggdesktopfile.c b/mate-panel/libegg/eggdesktopfile.c new file mode 100644 index 00000000..5ac79507 --- /dev/null +++ b/mate-panel/libegg/eggdesktopfile.c @@ -0,0 +1,1510 @@ +/* eggdesktopfile.c - Freedesktop.Org Desktop Files + * Copyright (C) 2007 Novell, Inc. + * + * Based on mate-desktop-item.c + * Copyright (C) 1999, 2000 Red Hat Inc. + * Copyright (C) 2001 George Lebl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - + * Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "eggdesktopfile.h" + +#include +#include + +#include +#include +#include + +struct EggDesktopFile { + GKeyFile *key_file; + char *source; + + char *name, *icon; + EggDesktopFileType type; + char document_code; +}; + +/** + * egg_desktop_file_new: + * @desktop_file_path: path to a Freedesktop-style Desktop file + * @error: error pointer + * + * Creates a new #EggDesktopFile for @desktop_file. + * + * Return value: the new #EggDesktopFile, or %NULL on error. + **/ +EggDesktopFile * +egg_desktop_file_new (const char *desktop_file_path, GError **error) +{ + GKeyFile *key_file; + + key_file = g_key_file_new (); + if (!g_key_file_load_from_file (key_file, desktop_file_path, 0, error)) + { + g_key_file_free (key_file); + return NULL; + } + + return egg_desktop_file_new_from_key_file (key_file, desktop_file_path, + error); +} + +/** + * egg_desktop_file_new_from_data_dirs: + * @desktop_file_path: relative path to a Freedesktop-style Desktop file + * @error: error pointer + * + * Looks for @desktop_file_path in the paths returned from + * g_get_user_data_dir() and g_get_system_data_dirs(), and creates + * a new #EggDesktopFile from it. + * + * Return value: the new #EggDesktopFile, or %NULL on error. + **/ +EggDesktopFile * +egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, + GError **error) +{ + EggDesktopFile *desktop_file; + GKeyFile *key_file; + char *full_path; + + key_file = g_key_file_new (); + if (!g_key_file_load_from_data_dirs (key_file, desktop_file_path, + &full_path, 0, error)) + { + g_key_file_free (key_file); + return NULL; + } + + desktop_file = egg_desktop_file_new_from_key_file (key_file, + full_path, + error); + g_free (full_path); + return desktop_file; +} + +/** + * egg_desktop_file_new_from_dirs: + * @desktop_file_path: relative path to a Freedesktop-style Desktop file + * @search_dirs: NULL-terminated array of directories to search + * @error: error pointer + * + * Looks for @desktop_file_path in the paths returned from + * g_get_user_data_dir() and g_get_system_data_dirs(), and creates + * a new #EggDesktopFile from it. + * + * Return value: the new #EggDesktopFile, or %NULL on error. + **/ +EggDesktopFile * +egg_desktop_file_new_from_dirs (const char *desktop_file_path, + const char **search_dirs, + GError **error) +{ + EggDesktopFile *desktop_file; + GKeyFile *key_file; + char *full_path; + + key_file = g_key_file_new (); + if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs, + &full_path, 0, error)) + { + g_key_file_free (key_file); + return NULL; + } + + desktop_file = egg_desktop_file_new_from_key_file (key_file, + full_path, + error); + g_free (full_path); + return desktop_file; +} + +/** + * egg_desktop_file_new_from_key_file: + * @key_file: a #GKeyFile representing a desktop file + * @source: the path or URI that @key_file was loaded from, or %NULL + * @error: error pointer + * + * Creates a new #EggDesktopFile for @key_file. Assumes ownership of + * @key_file (on success or failure); you should consider @key_file to + * be freed after calling this function. + * + * Return value: the new #EggDesktopFile, or %NULL on error. + **/ +EggDesktopFile * +egg_desktop_file_new_from_key_file (GKeyFile *key_file, + const char *source, + GError **error) +{ + EggDesktopFile *desktop_file; + char *version, *type; + + if (!g_key_file_has_group (key_file, EGG_DESKTOP_FILE_GROUP)) + { + g_set_error (error, EGG_DESKTOP_FILE_ERROR, + EGG_DESKTOP_FILE_ERROR_INVALID, + _("File is not a valid .desktop file")); + g_key_file_free (key_file); + return NULL; + } + + version = g_key_file_get_value (key_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_VERSION, + NULL); + if (version) + { + double version_num; + char *end; + + version_num = g_ascii_strtod (version, &end); + if (*end) + { + g_warning ("Invalid Version string '%s' in %s", + version, source ? source : "(unknown)"); + } + else if (version_num > 1.0) + { + g_set_error (error, EGG_DESKTOP_FILE_ERROR, + EGG_DESKTOP_FILE_ERROR_INVALID, + _("Unrecognized desktop file Version '%s'"), version); + g_free (version); + g_key_file_free (key_file); + return NULL; + } + g_free (version); + } + + desktop_file = g_new0 (EggDesktopFile, 1); + desktop_file->key_file = key_file; + + if (g_path_is_absolute (source)) + desktop_file->source = g_filename_to_uri (source, NULL, NULL); + else + desktop_file->source = g_strdup (source); + + desktop_file->name = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_NAME, error); + if (!desktop_file->name) + { + egg_desktop_file_free (desktop_file); + return NULL; + } + + type = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_TYPE, error); + if (!type) + { + egg_desktop_file_free (desktop_file); + return NULL; + } + + if (!strcmp (type, "Application")) + { + char *exec, *p; + + desktop_file->type = EGG_DESKTOP_FILE_TYPE_APPLICATION; + + exec = g_key_file_get_string (key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_EXEC, + error); + if (!exec) + { + egg_desktop_file_free (desktop_file); + g_free (type); + return NULL; + } + + /* See if it takes paths or URIs or neither */ + for (p = exec; *p; p++) + { + if (*p == '%') + { + if (p[1] == '\0' || strchr ("FfUu", p[1])) + { + desktop_file->document_code = p[1]; + break; + } + p++; + } + } + + g_free (exec); + } + else if (!strcmp (type, "Link")) + { + char *url; + + desktop_file->type = EGG_DESKTOP_FILE_TYPE_LINK; + + url = g_key_file_get_string (key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_URL, + error); + if (!url) + { + egg_desktop_file_free (desktop_file); + g_free (type); + return NULL; + } + g_free (url); + } + else if (!strcmp (type, "Directory")) + desktop_file->type = EGG_DESKTOP_FILE_TYPE_DIRECTORY; + else + desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED; + + g_free (type); + + /* Check the Icon key */ + desktop_file->icon = g_key_file_get_string (key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_ICON, + NULL); + if (desktop_file->icon && !g_path_is_absolute (desktop_file->icon)) + { + char *ext; + + /* Lots of .desktop files still get this wrong */ + ext = strrchr (desktop_file->icon, '.'); + if (ext && (!strcmp (ext, ".png") || + !strcmp (ext, ".xpm") || + !strcmp (ext, ".svg"))) + { + g_warning ("Desktop file '%s' has malformed Icon key '%s'" + "(should not include extension)", + source ? source : "(unknown)", + desktop_file->icon); + *ext = '\0'; + } + } + + return desktop_file; +} + +/** + * egg_desktop_file_free: + * @desktop_file: an #EggDesktopFile + * + * Frees @desktop_file. + **/ +void +egg_desktop_file_free (EggDesktopFile *desktop_file) +{ + g_key_file_free (desktop_file->key_file); + g_free (desktop_file->source); + g_free (desktop_file->name); + g_free (desktop_file->icon); + g_free (desktop_file); +} + +/** + * egg_desktop_file_get_source: + * @desktop_file: an #EggDesktopFile + * + * Gets the URI that @desktop_file was loaded from. + * + * Return value: @desktop_file's source URI + **/ +const char * +egg_desktop_file_get_source (EggDesktopFile *desktop_file) +{ + return desktop_file->source; +} + +/** + * egg_desktop_file_get_desktop_file_type: + * @desktop_file: an #EggDesktopFile + * + * Gets the desktop file type of @desktop_file. + * + * Return value: @desktop_file's type + **/ +EggDesktopFileType +egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file) +{ + return desktop_file->type; +} + +/** + * egg_desktop_file_get_name: + * @desktop_file: an #EggDesktopFile + * + * Gets the (localized) value of @desktop_file's "Name" key. + * + * Return value: the application/link name + **/ +const char * +egg_desktop_file_get_name (EggDesktopFile *desktop_file) +{ + return desktop_file->name; +} + +/** + * egg_desktop_file_get_icon: + * @desktop_file: an #EggDesktopFile + * + * Gets the value of @desktop_file's "Icon" key. + * + * If the icon string is a full path (that is, if g_path_is_absolute() + * returns %TRUE when called on it), it points to a file containing an + * unthemed icon. If the icon string is not a full path, it is the + * name of a themed icon, which can be looked up with %GtkIconTheme, + * or passed directly to a theme-aware widget like %GtkImage or + * %GtkCellRendererPixbuf. + * + * Return value: the icon path or name + **/ +const char * +egg_desktop_file_get_icon (EggDesktopFile *desktop_file) +{ + return desktop_file->icon; +} + +gboolean +egg_desktop_file_has_key (EggDesktopFile *desktop_file, + const char *key, + GError **error) +{ + return g_key_file_has_key (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, + error); +} + +char * +egg_desktop_file_get_string (EggDesktopFile *desktop_file, + const char *key, + GError **error) +{ + return g_key_file_get_string (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, + error); +} + +char * +egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, + const char *key, + const char *locale, + GError **error) +{ + return g_key_file_get_locale_string (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, locale, + error); +} + +gboolean +egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, + const char *key, + GError **error) +{ + return g_key_file_get_boolean (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, + error); +} + +double +egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, + const char *key, + GError **error) +{ + return g_key_file_get_double (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, + error); +} + +char ** +egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, + const char *key, + gsize *length, + GError **error) +{ + return g_key_file_get_string_list (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, length, + error); +} + +char ** +egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, + const char *key, + const char *locale, + gsize *length, + GError **error) +{ + return g_key_file_get_locale_string_list (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, key, + locale, length, + error); +} + +/** + * egg_desktop_file_can_launch: + * @desktop_file: an #EggDesktopFile + * @desktop_environment: the name of the running desktop environment, + * or %NULL + * + * Tests if @desktop_file can/should be launched in the current + * environment. If @desktop_environment is non-%NULL, @desktop_file's + * "OnlyShowIn" and "NotShowIn" keys are checked to make sure that + * this desktop_file is appropriate for the named environment. + * + * Furthermore, if @desktop_file has type + * %EGG_DESKTOP_FILE_TYPE_APPLICATION, its "TryExec" key (if any) is + * also checked, to make sure the binary it points to exists. + * + * egg_desktop_file_can_launch() does NOT check the value of the + * "Hidden" key. + * + * Return value: %TRUE if @desktop_file can be launched + **/ +gboolean +egg_desktop_file_can_launch (EggDesktopFile *desktop_file, + const char *desktop_environment) +{ + char *try_exec, *found_program; + char **only_show_in, **not_show_in; + gboolean found; + int i; + + if (desktop_file->type != EGG_DESKTOP_FILE_TYPE_APPLICATION && + desktop_file->type != EGG_DESKTOP_FILE_TYPE_LINK) + return FALSE; + + if (desktop_environment) + { + only_show_in = g_key_file_get_string_list (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN, + NULL, NULL); + if (only_show_in) + { + for (i = 0, found = FALSE; only_show_in[i] && !found; i++) + { + if (!strcmp (only_show_in[i], desktop_environment)) + found = TRUE; + } + + g_strfreev (only_show_in); + + if (!found) + return FALSE; + } + + not_show_in = g_key_file_get_string_list (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN, + NULL, NULL); + if (not_show_in) + { + for (i = 0, found = FALSE; not_show_in[i] && !found; i++) + { + if (!strcmp (not_show_in[i], desktop_environment)) + found = TRUE; + } + + g_strfreev (not_show_in); + + if (found) + return FALSE; + } + } + + if (desktop_file->type == EGG_DESKTOP_FILE_TYPE_APPLICATION) + { + try_exec = g_key_file_get_string (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_TRY_EXEC, + NULL); + if (try_exec) + { + found_program = g_find_program_in_path (try_exec); + g_free (try_exec); + + if (!found_program) + return FALSE; + g_free (found_program); + } + } + + return TRUE; +} + +/** + * egg_desktop_file_accepts_documents: + * @desktop_file: an #EggDesktopFile + * + * Tests if @desktop_file represents an application that can accept + * documents on the command line. + * + * Return value: %TRUE or %FALSE + **/ +gboolean +egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file) +{ + return desktop_file->document_code != 0; +} + +/** + * egg_desktop_file_accepts_multiple: + * @desktop_file: an #EggDesktopFile + * + * Tests if @desktop_file can accept multiple documents at once. + * + * If this returns %FALSE, you can still pass multiple documents to + * egg_desktop_file_launch(), but that will result in multiple copies + * of the application being launched. See egg_desktop_file_launch() + * for more details. + * + * Return value: %TRUE or %FALSE + **/ +gboolean +egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file) +{ + return (desktop_file->document_code == 'F' || + desktop_file->document_code == 'U'); +} + +/** + * egg_desktop_file_accepts_uris: + * @desktop_file: an #EggDesktopFile + * + * Tests if @desktop_file can accept (non-"file:") URIs as documents to + * open. + * + * Return value: %TRUE or %FALSE + **/ +gboolean +egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file) +{ + return (desktop_file->document_code == 'U' || + desktop_file->document_code == 'u'); +} + +static void +append_quoted_word (GString *str, + const char *s, + gboolean in_single_quotes, + gboolean in_double_quotes) +{ + const char *p; + + if (!in_single_quotes && !in_double_quotes) + g_string_append_c (str, '\''); + else if (!in_single_quotes && in_double_quotes) + g_string_append (str, "\"'"); + + if (!strchr (s, '\'')) + g_string_append (str, s); + else + { + for (p = s; *p != '\0'; p++) + { + if (*p == '\'') + g_string_append (str, "'\\''"); + else + g_string_append_c (str, *p); + } + } + + if (!in_single_quotes && !in_double_quotes) + g_string_append_c (str, '\''); + else if (!in_single_quotes && in_double_quotes) + g_string_append (str, "'\""); +} + +static void +do_percent_subst (EggDesktopFile *desktop_file, + char code, + GString *str, + GSList **documents, + gboolean in_single_quotes, + gboolean in_double_quotes) +{ + GSList *d; + char *doc; + + switch (code) + { + case '%': + g_string_append_c (str, '%'); + break; + + case 'F': + case 'U': + for (d = *documents; d; d = d->next) + { + doc = d->data; + g_string_append (str, " "); + append_quoted_word (str, doc, in_single_quotes, in_double_quotes); + } + *documents = NULL; + break; + + case 'f': + case 'u': + if (*documents) + { + doc = (*documents)->data; + g_string_append (str, " "); + append_quoted_word (str, doc, in_single_quotes, in_double_quotes); + *documents = (*documents)->next; + } + break; + + case 'i': + if (desktop_file->icon) + { + g_string_append (str, "--icon "); + append_quoted_word (str, desktop_file->icon, + in_single_quotes, in_double_quotes); + } + break; + + case 'c': + if (desktop_file->name) + { + append_quoted_word (str, desktop_file->name, + in_single_quotes, in_double_quotes); + } + break; + + case 'k': + if (desktop_file->source) + { + append_quoted_word (str, desktop_file->source, + in_single_quotes, in_double_quotes); + } + break; + + case 'D': + case 'N': + case 'd': + case 'n': + case 'v': + case 'm': + /* Deprecated; skip */ + break; + + default: + g_warning ("Unrecognized %%-code '%%%c' in Exec", code); + break; + } +} + +static char * +parse_exec (EggDesktopFile *desktop_file, + GSList **documents, + GError **error) +{ + char *exec, *p, *command; + gboolean escape, single_quot, double_quot; + GString *gs; + + exec = g_key_file_get_string (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_EXEC, + error); + if (!exec) + return NULL; + + /* Build the command */ + gs = g_string_new (NULL); + escape = single_quot = double_quot = FALSE; + + for (p = exec; *p != '\0'; p++) + { + if (escape) + { + escape = FALSE; + g_string_append_c (gs, *p); + } + else if (*p == '\\') + { + if (!single_quot) + escape = TRUE; + g_string_append_c (gs, *p); + } + else if (*p == '\'') + { + g_string_append_c (gs, *p); + if (!single_quot && !double_quot) + single_quot = TRUE; + else if (single_quot) + single_quot = FALSE; + } + else if (*p == '"') + { + g_string_append_c (gs, *p); + if (!single_quot && !double_quot) + double_quot = TRUE; + else if (double_quot) + double_quot = FALSE; + } + else if (*p == '%' && p[1]) + { + do_percent_subst (desktop_file, p[1], gs, documents, + single_quot, double_quot); + p++; + } + else + g_string_append_c (gs, *p); + } + + g_free (exec); + command = g_string_free (gs, FALSE); + + /* Prepend "xdg-terminal " if needed (FIXME: use gvfs) */ + if (g_key_file_has_key (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_TERMINAL, + NULL)) + { + GError *terminal_error = NULL; + gboolean use_terminal = + g_key_file_get_boolean (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_TERMINAL, + &terminal_error); + if (terminal_error) + { + g_free (command); + g_propagate_error (error, terminal_error); + return NULL; + } + + if (use_terminal) + { + gs = g_string_new ("xdg-terminal "); + append_quoted_word (gs, command, FALSE, FALSE); + g_free (command); + command = g_string_free (gs, FALSE); + } + } + + return command; +} + +static GSList * +translate_document_list (EggDesktopFile *desktop_file, GSList *documents) +{ + gboolean accepts_uris = egg_desktop_file_accepts_uris (desktop_file); + GSList *ret, *d; + + for (d = documents, ret = NULL; d; d = d->next) + { + const char *document = d->data; + gboolean is_uri = !g_path_is_absolute (document); + char *translated; + + if (accepts_uris) + { + if (is_uri) + translated = g_strdup (document); + else + translated = g_filename_to_uri (document, NULL, NULL); + } + else + { + if (is_uri) + translated = g_filename_from_uri (document, NULL, NULL); + else + translated = g_strdup (document); + } + + if (translated) + ret = g_slist_prepend (ret, translated); + } + + return g_slist_reverse (ret); +} + +static void +free_document_list (GSList *documents) +{ + GSList *d; + + for (d = documents; d; d = d->next) + g_free (d->data); + g_slist_free (documents); +} + +/** + * egg_desktop_file_parse_exec: + * @desktop_file: a #EggDesktopFile + * @documents: a list of document paths or URIs + * @error: error pointer + * + * Parses @desktop_file's Exec key, inserting @documents into it, and + * returns the result. + * + * If @documents contains non-file: URIs and @desktop_file does not + * accept URIs, those URIs will be ignored. Likewise, if @documents + * contains more elements than @desktop_file accepts, the extra + * documents will be ignored. + * + * Return value: the parsed Exec string + **/ +char * +egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, + GSList *documents, + GError **error) +{ + GSList *translated, *docs; + char *command; + + docs = translated = translate_document_list (desktop_file, documents); + command = parse_exec (desktop_file, &docs, error); + free_document_list (translated); + + return command; +} + +static gboolean +parse_link (EggDesktopFile *desktop_file, + EggDesktopFile **app_desktop_file, + GSList **documents, + GError **error) +{ + char *url; + GKeyFile *key_file; + + url = g_key_file_get_string (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_URL, + error); + if (!url) + return FALSE; + *documents = g_slist_prepend (NULL, url); + + /* FIXME: use gvfs */ + key_file = g_key_file_new (); + g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_NAME, + "xdg-open"); + g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_TYPE, + "Application"); + g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_EXEC, + "xdg-open %u"); + *app_desktop_file = egg_desktop_file_new_from_key_file (key_file, NULL, NULL); + return TRUE; +} + +#if GTK_CHECK_VERSION (2, 12, 0) +static char * +start_startup_notification (GdkDisplay *display, + EggDesktopFile *desktop_file, + const char *argv0, + int screen, + int workspace, + guint32 launch_time) +{ + static int sequence = 0; + char *startup_id; + char *description, *wmclass; + char *screen_str, *workspace_str; + + if (g_key_file_has_key (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, + NULL)) + { + if (!g_key_file_get_boolean (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, + NULL)) + return NULL; + wmclass = NULL; + } + else + { + wmclass = g_key_file_get_string (desktop_file->key_file, + EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS, + NULL); + if (!wmclass) + return NULL; + } + + if (launch_time == (guint32)-1) + launch_time = gdk_x11_display_get_user_time (display); + startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu", + g_get_prgname (), + (unsigned long)getpid (), + g_get_host_name (), + argv0, + sequence++, + (unsigned long)launch_time); + + description = g_strdup_printf (_("Starting %s"), desktop_file->name); + screen_str = g_strdup_printf ("%d", screen); + workspace_str = workspace == -1 ? NULL : g_strdup_printf ("%d", workspace); + + gdk_x11_display_broadcast_startup_message (display, "new", + "ID", startup_id, + "NAME", desktop_file->name, + "SCREEN", screen_str, + "BIN", argv0, + "ICON", desktop_file->icon, + "DESKTOP", workspace_str, + "DESCRIPTION", description, + "WMCLASS", wmclass, + NULL); + + g_free (description); + g_free (wmclass); + g_free (screen_str); + g_free (workspace_str); + + return startup_id; +} + +static void +end_startup_notification (GdkDisplay *display, + const char *startup_id) +{ + gdk_x11_display_broadcast_startup_message (display, "remove", + "ID", startup_id, + NULL); +} + +#define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */) + +typedef struct { + GdkDisplay *display; + char *startup_id; +} StartupNotificationData; + +static gboolean +startup_notification_timeout (gpointer data) +{ + StartupNotificationData *sn_data = data; + + end_startup_notification (sn_data->display, sn_data->startup_id); + g_object_unref (sn_data->display); + g_free (sn_data->startup_id); + g_free (sn_data); + + return FALSE; +} + +static void +set_startup_notification_timeout (GdkDisplay *display, + const char *startup_id) +{ + StartupNotificationData *sn_data; + + sn_data = g_new (StartupNotificationData, 1); + sn_data->display = g_object_ref (display); + sn_data->startup_id = g_strdup (startup_id); + + g_timeout_add_seconds (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH, + startup_notification_timeout, sn_data); +} +#endif /* GTK 2.12 */ + +static GPtrArray * +array_putenv (GPtrArray *env, char *variable) +{ + guint i, keylen; + + if (!env) + { + char **envp; + + env = g_ptr_array_new (); + + envp = g_listenv (); + for (i = 0; envp[i]; i++) + { + const char *value; + + value = g_getenv (envp[i]); + g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i], + value ? value : "")); + } + g_strfreev (envp); + } + + keylen = strcspn (variable, "="); + + /* Remove old value of key */ + for (i = 0; i < env->len; i++) + { + char *envvar = env->pdata[i]; + + if (!strncmp (envvar, variable, keylen) && envvar[keylen] == '=') + { + g_free (envvar); + g_ptr_array_remove_index_fast (env, i); + break; + } + } + + /* Add new value */ + g_ptr_array_add (env, g_strdup (variable)); + + return env; +} + +static gboolean +egg_desktop_file_launchv (EggDesktopFile *desktop_file, + GSList *documents, va_list args, + GError **error) +{ + EggDesktopFileLaunchOption option; + GSList *translated_documents = NULL, *docs = NULL; + char *command, **argv; + int argc, i, screen_num; + gboolean success, current_success; + GdkDisplay *display; + char *startup_id; + + GPtrArray *env = NULL; + char **variables = NULL; + GdkScreen *screen = NULL; + int workspace = -1; + const char *directory = NULL; + guint32 launch_time = (guint32)-1; + GSpawnFlags flags = G_SPAWN_SEARCH_PATH; + GSpawnChildSetupFunc setup_func = NULL; + gpointer setup_data = NULL; + + GPid *ret_pid = NULL; + int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL; + char **ret_startup_id = NULL; + + if (documents && desktop_file->document_code == 0) + { + g_set_error (error, EGG_DESKTOP_FILE_ERROR, + EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, + _("Application does not accept documents on command line")); + return FALSE; + } + + /* Read the options: technically it's incorrect for the caller to + * NULL-terminate the list of options (rather than 0-terminating + * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED, + * it's more consistent with other glib/gtk methods, and it will + * work as long as sizeof (int) <= sizeof (NULL), and NULL is + * represented as 0. (Which is true everywhere we care about.) + */ + while ((option = va_arg (args, EggDesktopFileLaunchOption))) + { + switch (option) + { + case EGG_DESKTOP_FILE_LAUNCH_CLEARENV: + if (env) + g_ptr_array_free (env, TRUE); + env = g_ptr_array_new (); + break; + case EGG_DESKTOP_FILE_LAUNCH_PUTENV: + variables = va_arg (args, char **); + for (i = 0; variables[i]; i++) + env = array_putenv (env, variables[i]); + break; + + case EGG_DESKTOP_FILE_LAUNCH_SCREEN: + screen = va_arg (args, GdkScreen *); + break; + case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: + workspace = va_arg (args, int); + break; + + case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: + directory = va_arg (args, const char *); + break; + case EGG_DESKTOP_FILE_LAUNCH_TIME: + launch_time = va_arg (args, guint32); + break; + case EGG_DESKTOP_FILE_LAUNCH_FLAGS: + flags |= va_arg (args, GSpawnFlags); + /* Make sure they didn't set any flags that don't make sense. */ + flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO; + break; + case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC: + setup_func = va_arg (args, GSpawnChildSetupFunc); + setup_data = va_arg (args, gpointer); + break; + + case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID: + ret_pid = va_arg (args, GPid *); + break; + case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE: + ret_stdin = va_arg (args, int *); + break; + case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE: + ret_stdout = va_arg (args, int *); + break; + case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE: + ret_stderr = va_arg (args, int *); + break; + case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID: + ret_startup_id = va_arg (args, char **); + break; + + default: + g_set_error (error, EGG_DESKTOP_FILE_ERROR, + EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION, + _("Unrecognized launch option: %d"), + GPOINTER_TO_INT (option)); + success = FALSE; + goto out; + } + } + + if (screen) + { + char *display_name = gdk_screen_make_display_name (screen); + char *display_env = g_strdup_printf ("DISPLAY=%s", display_name); + env = array_putenv (env, display_env); + g_free (display_name); + g_free (display_env); + + display = gdk_screen_get_display (screen); + } + else + { + display = gdk_display_get_default (); + screen = gdk_display_get_default_screen (display); + } + screen_num = gdk_screen_get_number (screen); + + translated_documents = translate_document_list (desktop_file, documents); + docs = translated_documents; + + success = FALSE; + + do + { + command = parse_exec (desktop_file, &docs, error); + if (!command) + goto out; + + if (!g_shell_parse_argv (command, &argc, &argv, error)) + { + g_free (command); + goto out; + } + g_free (command); + +#if GTK_CHECK_VERSION (2, 12, 0) + startup_id = start_startup_notification (display, desktop_file, + argv[0], screen_num, + workspace, launch_time); + if (startup_id) + { + char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s", + startup_id); + env = array_putenv (env, startup_id_env); + g_free (startup_id_env); + } +#else + startup_id = NULL; +#endif /* GTK 2.12 */ + + if (env != NULL) + g_ptr_array_add (env, NULL); + + current_success = + g_spawn_async_with_pipes (directory, + argv, + env ? (char **)(env->pdata) : NULL, + flags, + setup_func, setup_data, + ret_pid, + ret_stdin, ret_stdout, ret_stderr, + error); + g_strfreev (argv); + + if (startup_id) + { +#if GTK_CHECK_VERSION (2, 12, 0) + if (current_success) + { + set_startup_notification_timeout (display, startup_id); + + if (ret_startup_id) + *ret_startup_id = startup_id; + else + g_free (startup_id); + } + else +#endif /* GTK 2.12 */ + g_free (startup_id); + } + else if (ret_startup_id) + *ret_startup_id = NULL; + + if (current_success) + { + /* If we successfully launch any instances of the app, make + * sure we return TRUE and don't set @error. + */ + success = TRUE; + error = NULL; + + /* Also, only set the output params on the first one */ + ret_pid = NULL; + ret_stdin = ret_stdout = ret_stderr = NULL; + ret_startup_id = NULL; + } + } + while (docs && current_success); + + out: + if (env) + { + g_ptr_array_foreach (env, (GFunc)g_free, NULL); + g_ptr_array_free (env, TRUE); + } + free_document_list (translated_documents); + + return success; +} + +/** + * egg_desktop_file_launch: + * @desktop_file: an #EggDesktopFile + * @documents: a list of URIs or paths to documents to open + * @error: error pointer + * @...: additional options + * + * Launches @desktop_file with the given arguments. Additional options + * can be specified as follows: + * + * %EGG_DESKTOP_FILE_LAUNCH_CLEARENV: (no arguments) + * clears the environment in the child process + * %EGG_DESKTOP_FILE_LAUNCH_PUTENV: (char **variables) + * adds the NAME=VALUE strings in the given %NULL-terminated + * array to the child process's environment + * %EGG_DESKTOP_FILE_LAUNCH_SCREEN: (GdkScreen *screen) + * causes the application to be launched on the given screen + * %EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: (int workspace) + * causes the application to be launched on the given workspace + * %EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: (char *dir) + * causes the application to be launched in the given directory + * %EGG_DESKTOP_FILE_LAUNCH_TIME: (guint32 launch_time) + * sets the "launch time" for the application. If the user + * interacts with another window after @launch_time but before + * the launched application creates its first window, the window + * manager may choose to not give focus to the new application. + * Passing 0 for @launch_time will explicitly request that the + * application not receive focus. + * %EGG_DESKTOP_FILE_LAUNCH_FLAGS (GSpawnFlags flags) + * Sets additional #GSpawnFlags to use. See g_spawn_async() for + * more details. + * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC (GSpawnChildSetupFunc, gpointer) + * Sets the child setup callback and the data to pass to it. + * (See g_spawn_async() for more details.) + * + * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID (GPid **pid) + * On a successful launch, sets *@pid to the PID of the launched + * application. + * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID (char **startup_id) + * On a successful launch, sets *@startup_id to the Startup + * Notification "startup id" of the launched application. + * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE (int *fd) + * On a successful launch, sets *@fd to the file descriptor of + * a pipe connected to the application's stdin. + * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE (int *fd) + * On a successful launch, sets *@fd to the file descriptor of + * a pipe connected to the application's stdout. + * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE (int *fd) + * On a successful launch, sets *@fd to the file descriptor of + * a pipe connected to the application's stderr. + * + * The options should be terminated with a single %NULL. + * + * If @documents contains multiple documents, but + * egg_desktop_file_accepts_multiple() returns %FALSE for + * @desktop_file, then egg_desktop_file_launch() will actually launch + * multiple instances of the application. In that case, the return + * value (as well as any values passed via + * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, etc) will only reflect the + * first instance of the application that was launched (but the + * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC will be called for each + * instance). + * + * Return value: %TRUE if the application was successfully launched. + **/ +gboolean +egg_desktop_file_launch (EggDesktopFile *desktop_file, + GSList *documents, GError **error, + ...) +{ + va_list args; + gboolean success; + EggDesktopFile *app_desktop_file; + + switch (desktop_file->type) + { + case EGG_DESKTOP_FILE_TYPE_APPLICATION: + va_start (args, error); + success = egg_desktop_file_launchv (desktop_file, documents, + args, error); + va_end (args); + break; + + case EGG_DESKTOP_FILE_TYPE_LINK: + if (documents) + { + g_set_error (error, EGG_DESKTOP_FILE_ERROR, + EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, + _("Can't pass document URIs to a 'Type=Link' desktop entry")); + return FALSE; + } + + if (!parse_link (desktop_file, &app_desktop_file, &documents, error)) + return FALSE; + + va_start (args, error); + success = egg_desktop_file_launchv (app_desktop_file, documents, + args, error); + va_end (args); + + egg_desktop_file_free (app_desktop_file); + free_document_list (documents); + break; + + case EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED: + case EGG_DESKTOP_FILE_TYPE_DIRECTORY: + default: + g_set_error (error, EGG_DESKTOP_FILE_ERROR, + EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, + _("Not a launchable item")); + success = FALSE; + break; + } + + return success; +} + + +GQuark +egg_desktop_file_error_quark (void) +{ + return g_quark_from_static_string ("egg-desktop_file-error-quark"); +} + + +G_LOCK_DEFINE_STATIC (egg_desktop_file); +static EggDesktopFile *egg_desktop_file; + +static void +egg_set_desktop_file_internal (const char *desktop_file_path, + gboolean set_defaults) +{ + GError *error = NULL; + + G_LOCK (egg_desktop_file); + if (egg_desktop_file) + egg_desktop_file_free (egg_desktop_file); + + egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error); + if (error) + { + g_warning ("Could not load desktop file '%s': %s", + desktop_file_path, error->message); + g_error_free (error); + } + + if (set_defaults && egg_desktop_file != NULL) { + /* Set localized application name and default window icon */ + if (egg_desktop_file->name) + g_set_application_name (egg_desktop_file->name); + if (egg_desktop_file->icon) + { + if (g_path_is_absolute (egg_desktop_file->icon)) + gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL); + else + gtk_window_set_default_icon_name (egg_desktop_file->icon); + } + } + + G_UNLOCK (egg_desktop_file); +} + +/** + * egg_set_desktop_file: + * @desktop_file_path: path to the application's desktop file + * + * Creates an #EggDesktopFile for the application from the data at + * @desktop_file_path. This will also call g_set_application_name() + * with the localized application name from the desktop file, and + * gtk_window_set_default_icon_name() or + * gtk_window_set_default_icon_from_file() with the application's + * icon. Other code may use additional information from the desktop + * file. + * See egg_set_desktop_file_without_defaults() for a variant of this + * function that does not set the application name and default window + * icon. + * + * Note that for thread safety reasons, this function can only + * be called once, and is mutually exclusive with calling + * egg_set_desktop_file_without_defaults(). + **/ +void +egg_set_desktop_file (const char *desktop_file_path) +{ + egg_set_desktop_file_internal (desktop_file_path, TRUE); +} + +/** + * egg_set_desktop_file_without_defaults: + * @desktop_file_path: path to the application's desktop file + * + * Creates an #EggDesktopFile for the application from the data at + * @desktop_file_path. + * See egg_set_desktop_file() for a variant of this function that + * sets the application name and default window icon from the information + * in the desktop file. + * + * Note that for thread safety reasons, this function can only + * be called once, and is mutually exclusive with calling + * egg_set_desktop_file(). + **/ +void +egg_set_desktop_file_without_defaults (const char *desktop_file_path) +{ + egg_set_desktop_file_internal (desktop_file_path, FALSE); +} + +/** + * egg_get_desktop_file: + * + * Gets the application's #EggDesktopFile, as set by + * egg_set_desktop_file(). + * + * Return value: the #EggDesktopFile, or %NULL if it hasn't been set. + **/ +EggDesktopFile * +egg_get_desktop_file (void) +{ + EggDesktopFile *retval; + + G_LOCK (egg_desktop_file); + retval = egg_desktop_file; + G_UNLOCK (egg_desktop_file); + + return retval; +} diff --git a/mate-panel/libegg/eggdesktopfile.h b/mate-panel/libegg/eggdesktopfile.h new file mode 100644 index 00000000..68850b71 --- /dev/null +++ b/mate-panel/libegg/eggdesktopfile.h @@ -0,0 +1,164 @@ +/* eggdesktopfile.h - Freedesktop.Org Desktop Files + * Copyright (C) 2007 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - + * Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_DESKTOP_FILE_H__ +#define __EGG_DESKTOP_FILE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct EggDesktopFile EggDesktopFile; + +typedef enum { + EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED, + + EGG_DESKTOP_FILE_TYPE_APPLICATION, + EGG_DESKTOP_FILE_TYPE_LINK, + EGG_DESKTOP_FILE_TYPE_DIRECTORY +} EggDesktopFileType; + +EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path, + GError **error); + +EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, + GError **error); +EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path, + const char **search_dirs, + GError **error); +EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file, + const char *source, + GError **error); + +void egg_desktop_file_free (EggDesktopFile *desktop_file); + +const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file); + +EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file); + +const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file); +const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file); + +gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file, + const char *desktop_environment); + +gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file); +gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file); +gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file); + +char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, + GSList *documents, + GError **error); + +gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file, + GSList *documents, + GError **error, + ...) G_GNUC_NULL_TERMINATED; + +typedef enum { + EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1, + EGG_DESKTOP_FILE_LAUNCH_PUTENV, + EGG_DESKTOP_FILE_LAUNCH_SCREEN, + EGG_DESKTOP_FILE_LAUNCH_WORKSPACE, + EGG_DESKTOP_FILE_LAUNCH_DIRECTORY, + EGG_DESKTOP_FILE_LAUNCH_TIME, + EGG_DESKTOP_FILE_LAUNCH_FLAGS, + EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC, + EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, + EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE, + EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE, + EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE, + EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID +} EggDesktopFileLaunchOption; + +/* Standard Keys */ +#define EGG_DESKTOP_FILE_GROUP "Desktop Entry" + +#define EGG_DESKTOP_FILE_KEY_TYPE "Type" +#define EGG_DESKTOP_FILE_KEY_VERSION "Version" +#define EGG_DESKTOP_FILE_KEY_NAME "Name" +#define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName" +#define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay" +#define EGG_DESKTOP_FILE_KEY_COMMENT "Comment" +#define EGG_DESKTOP_FILE_KEY_ICON "Icon" +#define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden" +#define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn" +#define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn" +#define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec" +#define EGG_DESKTOP_FILE_KEY_EXEC "Exec" +#define EGG_DESKTOP_FILE_KEY_PATH "Path" +#define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal" +#define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType" +#define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories" +#define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify" +#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass" +#define EGG_DESKTOP_FILE_KEY_URL "URL" + +/* Accessors */ +gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file, + const char *key, + GError **error); +char *egg_desktop_file_get_string (EggDesktopFile *desktop_file, + const char *key, + GError **error) G_GNUC_MALLOC; +char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, + const char *key, + const char *locale, + GError **error) G_GNUC_MALLOC; +gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, + const char *key, + GError **error); +double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, + const char *key, + GError **error); +char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, + const char *key, + gsize *length, + GError **error) G_GNUC_MALLOC; +char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, + const char *key, + const char *locale, + gsize *length, + GError **error) G_GNUC_MALLOC; + + +/* Errors */ +#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark() + +GQuark egg_desktop_file_error_quark (void); + +typedef enum { + EGG_DESKTOP_FILE_ERROR_INVALID, + EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, + EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION +} EggDesktopFileError; + +/* Global application desktop file */ +void egg_set_desktop_file (const char *desktop_file_path); +void egg_set_desktop_file_without_defaults (const char *desktop_file_path); +EggDesktopFile *egg_get_desktop_file (void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __EGG_DESKTOP_FILE_H__ */ diff --git a/mate-panel/libegg/eggsmclient-private.h b/mate-panel/libegg/eggsmclient-private.h new file mode 100644 index 00000000..9f2498ac --- /dev/null +++ b/mate-panel/libegg/eggsmclient-private.h @@ -0,0 +1,57 @@ +/* eggsmclient-private.h + * Copyright (C) 2007 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_SM_CLIENT_PRIVATE_H__ +#define __EGG_SM_CLIENT_PRIVATE_H__ + +#include +#include "eggsmclient.h" + +#ifdef __cplusplus +extern "C" { +#endif + +GKeyFile *egg_sm_client_save_state (EggSMClient *client); +void egg_sm_client_quit_requested (EggSMClient *client); +void egg_sm_client_quit_cancelled (EggSMClient *client); +void egg_sm_client_quit (EggSMClient *client); + +#if defined (GDK_WINDOWING_X11) +# ifdef EGG_SM_CLIENT_BACKEND_XSMP +GType egg_sm_client_xsmp_get_type (void); +EggSMClient *egg_sm_client_xsmp_new (void); +# endif +# ifdef EGG_SM_CLIENT_BACKEND_DBUS +GType egg_sm_client_dbus_get_type (void); +EggSMClient *egg_sm_client_dbus_new (void); +# endif +#elif defined (GDK_WINDOWING_WIN32) +GType egg_sm_client_win32_get_type (void); +EggSMClient *egg_sm_client_win32_new (void); +#elif defined (GDK_WINDOWING_QUARTZ) +GType egg_sm_client_osx_get_type (void); +EggSMClient *egg_sm_client_osx_new (void); +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* __EGG_SM_CLIENT_PRIVATE_H__ */ diff --git a/mate-panel/libegg/eggsmclient-xsmp.c b/mate-panel/libegg/eggsmclient-xsmp.c new file mode 100644 index 00000000..a6d3f11f --- /dev/null +++ b/mate-panel/libegg/eggsmclient-xsmp.c @@ -0,0 +1,1370 @@ +/* + * Copyright (C) 2007 Novell, Inc. + * + * Inspired by various other pieces of code including GsmClient (C) + * 2001 Havoc Pennington, MateClient (C) 1998 Carsten Schaar, and twm + * session code (C) 1998 The Open Group. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "eggsmclient.h" +#include "eggsmclient-private.h" + +#include "eggdesktopfile.h" + +#include +#include +#include +#include +#include +#include + +#include + +#define EGG_TYPE_SM_CLIENT_XSMP (egg_sm_client_xsmp_get_type ()) +#define EGG_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP)) +#define EGG_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)) +#define EGG_IS_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP)) +#define EGG_IS_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP)) +#define EGG_SM_CLIENT_XSMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)) + +typedef struct _EggSMClientXSMP EggSMClientXSMP; +typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass; + +/* These mostly correspond to the similarly-named states in section + * 9.1 of the XSMP spec. Some of the states there aren't represented + * here, because we don't need them. SHUTDOWN_CANCELLED is slightly + * different from the spec; we use it when the client is IDLE after a + * ShutdownCancelled message, but the application is still interacting + * and doesn't know the shutdown has been cancelled yet. + */ +typedef enum +{ + XSMP_STATE_IDLE, + XSMP_STATE_SAVE_YOURSELF, + XSMP_STATE_INTERACT_REQUEST, + XSMP_STATE_INTERACT, + XSMP_STATE_SAVE_YOURSELF_DONE, + XSMP_STATE_SHUTDOWN_CANCELLED, + XSMP_STATE_CONNECTION_CLOSED +} EggSMClientXSMPState; + +static const char *state_names[] = { + "idle", + "save-yourself", + "interact-request", + "interact", + "save-yourself-done", + "shutdown-cancelled", + "connection-closed" +}; + +#define EGG_SM_CLIENT_XSMP_STATE(xsmp) (state_names[(xsmp)->state]) + +struct _EggSMClientXSMP +{ + EggSMClient parent; + + SmcConn connection; + char *client_id; + + EggSMClientXSMPState state; + char **restart_command; + gboolean set_restart_command; + int restart_style; + + guint idle; + + /* Current SaveYourself state */ + guint expecting_initial_save_yourself : 1; + guint need_save_state : 1; + guint need_quit_requested : 1; + guint interact_errors : 1; + guint shutting_down : 1; + + /* Todo list */ + guint waiting_to_set_initial_properties : 1; + guint waiting_to_emit_quit : 1; + guint waiting_to_emit_quit_cancelled : 1; + guint waiting_to_save_myself : 1; + +}; + +struct _EggSMClientXSMPClass +{ + EggSMClientClass parent_class; + +}; + +static void sm_client_xsmp_startup (EggSMClient *client, + const char *client_id); +static void sm_client_xsmp_set_restart_command (EggSMClient *client, + int argc, + const char **argv); +static void sm_client_xsmp_will_quit (EggSMClient *client, + gboolean will_quit); +static gboolean sm_client_xsmp_end_session (EggSMClient *client, + EggSMClientEndStyle style, + gboolean request_confirmation); + +static void xsmp_save_yourself (SmcConn smc_conn, + SmPointer client_data, + int save_style, + Bool shutdown, + int interact_style, + Bool fast); +static void xsmp_die (SmcConn smc_conn, + SmPointer client_data); +static void xsmp_save_complete (SmcConn smc_conn, + SmPointer client_data); +static void xsmp_shutdown_cancelled (SmcConn smc_conn, + SmPointer client_data); +static void xsmp_interact (SmcConn smc_conn, + SmPointer client_data); + +static SmProp *array_prop (const char *name, + ...); +static SmProp *ptrarray_prop (const char *name, + GPtrArray *values); +static SmProp *string_prop (const char *name, + const char *value); +static SmProp *card8_prop (const char *name, + unsigned char value); + +static void set_properties (EggSMClientXSMP *xsmp, ...); +static void delete_properties (EggSMClientXSMP *xsmp, ...); + +static GPtrArray *generate_command (char **restart_command, + const char *client_id, + const char *state_file); + +static void save_state (EggSMClientXSMP *xsmp); +static void do_save_yourself (EggSMClientXSMP *xsmp); +static void update_pending_events (EggSMClientXSMP *xsmp); + +static void ice_init (void); +static gboolean process_ice_messages (IceConn ice_conn); +static void smc_error_handler (SmcConn smc_conn, + Bool swap, + int offending_minor_opcode, + unsigned long offending_sequence, + int error_class, + int severity, + SmPointer values); + +G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT) + +static void +egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp) +{ + xsmp->state = XSMP_STATE_CONNECTION_CLOSED; + xsmp->connection = NULL; + xsmp->restart_style = SmRestartIfRunning; +} + +static void +egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass) +{ + EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass); + + sm_client_class->startup = sm_client_xsmp_startup; + sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command; + sm_client_class->will_quit = sm_client_xsmp_will_quit; + sm_client_class->end_session = sm_client_xsmp_end_session; +} + +EggSMClient * +egg_sm_client_xsmp_new (void) +{ + if (!g_getenv ("SESSION_MANAGER")) + return NULL; + + return g_object_new (EGG_TYPE_SM_CLIENT_XSMP, NULL); +} + +static gboolean +sm_client_xsmp_set_initial_properties (gpointer user_data) +{ + EggSMClientXSMP *xsmp = user_data; + EggDesktopFile *desktop_file; + GPtrArray *clone, *restart; + char pid_str[64]; + + if (xsmp->idle) + { + g_source_remove (xsmp->idle); + xsmp->idle = 0; + } + xsmp->waiting_to_set_initial_properties = FALSE; + + if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART) + xsmp->restart_style = SmRestartNever; + + /* Parse info out of desktop file */ + desktop_file = egg_get_desktop_file (); + if (desktop_file) + { + GError *err = NULL; + char *cmdline, **argv; + int argc; + + if (xsmp->restart_style == SmRestartIfRunning) + { + if (egg_desktop_file_get_boolean (desktop_file, + "X-MATE-AutoRestart", NULL)) + xsmp->restart_style = SmRestartImmediately; + } + + if (!xsmp->set_restart_command) + { + cmdline = egg_desktop_file_parse_exec (desktop_file, NULL, &err); + if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err)) + { + egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp), + argc, (const char **)argv); + g_strfreev (argv); + } + else + { + g_warning ("Could not parse Exec line in desktop file: %s", + err->message); + g_error_free (err); + } + g_free (cmdline); + } + } + + if (!xsmp->set_restart_command) + xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1); + + clone = generate_command (xsmp->restart_command, NULL, NULL); + restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL); + + g_debug ("Setting initial properties"); + + /* Program, CloneCommand, RestartCommand, and UserID are required. + * ProcessID isn't required, but the SM may be able to do something + * useful with it. + */ + g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ()); + set_properties (xsmp, + string_prop (SmProgram, g_get_prgname ()), + ptrarray_prop (SmCloneCommand, clone), + ptrarray_prop (SmRestartCommand, restart), + string_prop (SmUserID, g_get_user_name ()), + string_prop (SmProcessID, pid_str), + card8_prop (SmRestartStyleHint, xsmp->restart_style), + NULL); + g_ptr_array_free (clone, TRUE); + g_ptr_array_free (restart, TRUE); + + if (desktop_file) + { + set_properties (xsmp, + string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)), + NULL); + } + + update_pending_events (xsmp); + return FALSE; +} + +/* This gets called from two different places: xsmp_die() (when the + * server asks us to disconnect) and process_ice_messages() (when the + * server disconnects unexpectedly). + */ +static void +sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp) +{ + SmcConn connection; + + if (!xsmp->connection) + return; + + g_debug ("Disconnecting"); + + connection = xsmp->connection; + xsmp->connection = NULL; + SmcCloseConnection (connection, 0, NULL); + xsmp->state = XSMP_STATE_CONNECTION_CLOSED; + + xsmp->waiting_to_save_myself = FALSE; + update_pending_events (xsmp); +} + +static void +sm_client_xsmp_startup (EggSMClient *client, + const char *client_id) +{ + EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; + SmcCallbacks callbacks; + char *ret_client_id; + char error_string_ret[256]; + + xsmp->client_id = g_strdup (client_id); + + ice_init (); + SmcSetErrorHandler (smc_error_handler); + + callbacks.save_yourself.callback = xsmp_save_yourself; + callbacks.die.callback = xsmp_die; + callbacks.save_complete.callback = xsmp_save_complete; + callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled; + + callbacks.save_yourself.client_data = xsmp; + callbacks.die.client_data = xsmp; + callbacks.save_complete.client_data = xsmp; + callbacks.shutdown_cancelled.client_data = xsmp; + + client_id = NULL; + error_string_ret[0] = '\0'; + xsmp->connection = + SmcOpenConnection (NULL, xsmp, SmProtoMajor, SmProtoMinor, + SmcSaveYourselfProcMask | SmcDieProcMask | + SmcSaveCompleteProcMask | + SmcShutdownCancelledProcMask, + &callbacks, + xsmp->client_id, &ret_client_id, + sizeof (error_string_ret), error_string_ret); + + if (!xsmp->connection) + { + g_warning ("Failed to connect to the session manager: %s\n", + error_string_ret[0] ? + error_string_ret : "no error message given"); + xsmp->state = XSMP_STATE_CONNECTION_CLOSED; + return; + } + + /* We expect a pointless initial SaveYourself if either (a) we + * didn't have an initial client ID, or (b) we DID have an initial + * client ID, but the server rejected it and gave us a new one. + */ + if (!xsmp->client_id || + (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0)) + xsmp->expecting_initial_save_yourself = TRUE; + + if (ret_client_id) + { + g_free (xsmp->client_id); + xsmp->client_id = g_strdup (ret_client_id); + free (ret_client_id); + + gdk_threads_enter (); + gdk_set_sm_client_id (xsmp->client_id); + gdk_threads_leave (); + + g_debug ("Got client ID \"%s\"", xsmp->client_id); + } + + xsmp->state = XSMP_STATE_IDLE; + + /* Do not set the initial properties until we reach the main loop, + * so that the application has a chance to call + * egg_set_desktop_file(). (This may also help the session manager + * have a better idea of when the application is fully up and + * running.) + */ + xsmp->waiting_to_set_initial_properties = TRUE; + xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client); +} + +static void +sm_client_xsmp_set_restart_command (EggSMClient *client, + int argc, + const char **argv) +{ + EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; + int i; + + g_strfreev (xsmp->restart_command); + + xsmp->restart_command = g_new (char *, argc + 1); + for (i = 0; i < argc; i++) + xsmp->restart_command[i] = g_strdup (argv[i]); + xsmp->restart_command[i] = NULL; + + xsmp->set_restart_command = TRUE; +} + +static void +sm_client_xsmp_will_quit (EggSMClient *client, + gboolean will_quit) +{ + EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; + + if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED) + { + /* The session manager has already exited! Schedule a quit + * signal. + */ + xsmp->waiting_to_emit_quit = TRUE; + update_pending_events (xsmp); + return; + } + else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) + { + /* We received a ShutdownCancelled message while the application + * was interacting; Schedule a quit_cancelled signal. + */ + xsmp->waiting_to_emit_quit_cancelled = TRUE; + update_pending_events (xsmp); + return; + } + + g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT); + + g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True"); + SmcInteractDone (xsmp->connection, !will_quit); + + if (will_quit && xsmp->need_save_state) + save_state (xsmp); + + g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False"); + SmcSaveYourselfDone (xsmp->connection, will_quit); + xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; +} + +static gboolean +sm_client_xsmp_end_session (EggSMClient *client, + EggSMClientEndStyle style, + gboolean request_confirmation) +{ + EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; + int save_type; + + /* To end the session via XSMP, we have to send a + * SaveYourselfRequest. We aren't allowed to do that if anything + * else is going on, but we don't want to expose this fact to the + * application. So we do our best to patch things up here... + * + * In the worst case, this method might block for some length of + * time in process_ice_messages, but the only time that code path is + * honestly likely to get hit is if the application tries to end the + * session as the very first thing it does, in which case it + * probably won't actually block anyway. It's not worth gunking up + * the API to try to deal nicely with the other 0.01% of cases where + * this happens. + */ + + while (xsmp->state != XSMP_STATE_IDLE || + xsmp->expecting_initial_save_yourself) + { + /* If we're already shutting down, we don't need to do anything. */ + if (xsmp->shutting_down) + return TRUE; + + switch (xsmp->state) + { + case XSMP_STATE_CONNECTION_CLOSED: + return FALSE; + + case XSMP_STATE_SAVE_YOURSELF: + /* Trying to log out from the save_state callback? Whatever. + * Abort the save_state. + */ + SmcSaveYourselfDone (xsmp->connection, FALSE); + xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; + break; + + case XSMP_STATE_INTERACT_REQUEST: + case XSMP_STATE_INTERACT: + case XSMP_STATE_SHUTDOWN_CANCELLED: + /* Already in a shutdown-related state, just ignore + * the new shutdown request... + */ + return TRUE; + + case XSMP_STATE_IDLE: + if (xsmp->waiting_to_set_initial_properties) + sm_client_xsmp_set_initial_properties (xsmp); + + if (!xsmp->expecting_initial_save_yourself) + break; + /* else fall through */ + + case XSMP_STATE_SAVE_YOURSELF_DONE: + /* We need to wait for some response from the server.*/ + process_ice_messages (SmcGetIceConnection (xsmp->connection)); + break; + + default: + /* Hm... shouldn't happen */ + return FALSE; + } + } + + /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and + * the user chooses to save the session. But mate-session will do + * the wrong thing if we pass SmSaveBoth and the user chooses NOT to + * save the session... Sigh. + */ + if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session")) + save_type = SmSaveBoth; + else + save_type = SmSaveGlobal; + + g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : ""); + SmcRequestSaveYourself (xsmp->connection, + save_type, + True, /* shutdown */ + SmInteractStyleAny, + !request_confirmation, /* fast */ + True /* global */); + return TRUE; +} + +static gboolean +idle_do_pending_events (gpointer data) +{ + EggSMClientXSMP *xsmp = data; + EggSMClient *client = data; + + gdk_threads_enter (); + + xsmp->idle = 0; + + if (xsmp->waiting_to_emit_quit) + { + xsmp->waiting_to_emit_quit = FALSE; + egg_sm_client_quit (client); + goto out; + } + + if (xsmp->waiting_to_emit_quit_cancelled) + { + xsmp->waiting_to_emit_quit_cancelled = FALSE; + egg_sm_client_quit_cancelled (client); + xsmp->state = XSMP_STATE_IDLE; + } + + if (xsmp->waiting_to_save_myself) + { + xsmp->waiting_to_save_myself = FALSE; + do_save_yourself (xsmp); + } + + out: + gdk_threads_leave (); + return FALSE; +} + +static void +update_pending_events (EggSMClientXSMP *xsmp) +{ + gboolean want_idle = + xsmp->waiting_to_emit_quit || + xsmp->waiting_to_emit_quit_cancelled || + xsmp->waiting_to_save_myself; + + if (want_idle) + { + if (xsmp->idle == 0) + xsmp->idle = g_idle_add (idle_do_pending_events, xsmp); + } + else + { + if (xsmp->idle != 0) + g_source_remove (xsmp->idle); + xsmp->idle = 0; + } +} + +static void +fix_broken_state (EggSMClientXSMP *xsmp, const char *message, + gboolean send_interact_done, + gboolean send_save_yourself_done) +{ + g_warning ("Received XSMP %s message in state %s: client or server error", + message, EGG_SM_CLIENT_XSMP_STATE (xsmp)); + + /* Forget any pending SaveYourself plans we had */ + xsmp->waiting_to_save_myself = FALSE; + update_pending_events (xsmp); + + if (send_interact_done) + SmcInteractDone (xsmp->connection, False); + if (send_save_yourself_done) + SmcSaveYourselfDone (xsmp->connection, True); + + xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE; +} + +/* SM callbacks */ + +static void +xsmp_save_yourself (SmcConn smc_conn, + SmPointer client_data, + int save_type, + Bool shutdown, + int interact_style, + Bool fast) +{ + EggSMClientXSMP *xsmp = client_data; + gboolean wants_quit_requested; + + g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s", + save_type == SmSaveLocal ? "SmSaveLocal" : + save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth", + shutdown ? "Shutdown" : "!Shutdown", + interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : + interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" : + "SmInteractStyleNone", fast ? "Fast" : "!Fast", + EGG_SM_CLIENT_XSMP_STATE (xsmp)); + + if (xsmp->state != XSMP_STATE_IDLE && + xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED) + { + fix_broken_state (xsmp, "SaveYourself", FALSE, TRUE); + return; + } + + if (xsmp->waiting_to_set_initial_properties) + sm_client_xsmp_set_initial_properties (xsmp); + + /* If this is the initial SaveYourself, ignore it; we've already set + * properties and there's no reason to actually save state too. + */ + if (xsmp->expecting_initial_save_yourself) + { + xsmp->expecting_initial_save_yourself = FALSE; + + if (save_type == SmSaveLocal && + interact_style == SmInteractStyleNone && + !shutdown && !fast) + { + g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself"); + SmcSaveYourselfDone (xsmp->connection, True); + /* As explained in the comment at the end of + * do_save_yourself(), SAVE_YOURSELF_DONE is the correct + * state here, not IDLE. + */ + xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; + return; + } + else + g_warning ("First SaveYourself was not the expected one!"); + } + + /* Even ignoring the "fast" flag completely, there are still 18 + * different combinations of save_type, shutdown and interact_style. + * We interpret them as follows: + * + * Type Shutdown Interact Interpretation + * G F A/E/N do nothing (1) + * G T N do nothing (1)* + * G T A/E quit_requested (2) + * L/B F A/E/N save_state (3) + * L/B T N save_state (3)* + * L/B T A/E quit_requested, then save_state (4) + * + * 1. Do nothing, because the SM asked us to do something + * uninteresting (save open files, but then don't quit + * afterward) or rude (save open files without asking the user + * for confirmation). + * + * 2. Request interaction and then emit ::quit_requested. This + * perhaps isn't quite correct for the SmInteractStyleErrors + * case, but we don't care. + * + * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these + * rows essentially get demoted to SmSaveLocal, because their + * Global halves correspond to "do nothing". + * + * 4. Request interaction, emit ::quit_requested, and then emit + * ::save_state after interacting. This is the SmSaveBoth + * equivalent of #2, but we also promote SmSaveLocal shutdown + * SaveYourselfs to SmSaveBoth here, because we want to give + * the user a chance to save open files before quitting. + * + * (* It would be nice if we could do something useful when the + * session manager sends a SaveYourself with shutdown True and + * SmInteractStyleNone. But we can't, so we just pretend it didn't + * even tell us it was shutting down. The docs for ::quit mention + * that it might not always be preceded by ::quit_requested.) + */ + + /* As an optimization, we don't actually request interaction and + * emit ::quit_requested if the application isn't listening to the + * signal. + */ + wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT), 0, FALSE); + + xsmp->need_save_state = (save_type != SmSaveGlobal); + xsmp->need_quit_requested = (shutdown && wants_quit_requested && + interact_style != SmInteractStyleNone); + xsmp->interact_errors = (interact_style == SmInteractStyleErrors); + + xsmp->shutting_down = shutdown; + + do_save_yourself (xsmp); +} + +static void +do_save_yourself (EggSMClientXSMP *xsmp) +{ + if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) + { + /* The SM cancelled a previous SaveYourself, but we haven't yet + * had a chance to tell the application, so we can't start + * processing this SaveYourself yet. + */ + xsmp->waiting_to_save_myself = TRUE; + update_pending_events (xsmp); + return; + } + + if (xsmp->need_quit_requested) + { + xsmp->state = XSMP_STATE_INTERACT_REQUEST; + + g_debug ("Sending InteractRequest(%s)", + xsmp->interact_errors ? "Error" : "Normal"); + SmcInteractRequest (xsmp->connection, + xsmp->interact_errors ? SmDialogError : SmDialogNormal, + xsmp_interact, + xsmp); + return; + } + + if (xsmp->need_save_state) + { + save_state (xsmp); + + /* Though unlikely, the client could have been disconnected + * while the application was saving its state. + */ + if (!xsmp->connection) + return; + } + + g_debug ("Sending SaveYourselfDone(True)"); + SmcSaveYourselfDone (xsmp->connection, True); + + /* The client state diagram in the XSMP spec says that after a + * non-shutdown SaveYourself, we go directly back to "idle". But + * everything else in both the XSMP spec and the libSM docs + * disagrees. + */ + xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; +} + +static void +save_state (EggSMClientXSMP *xsmp) +{ + GKeyFile *state_file; + char *state_file_path, *data; + EggDesktopFile *desktop_file; + GPtrArray *restart; + int offset, fd; + + /* We set xsmp->state before emitting save_state, but our caller is + * responsible for setting it back afterward. + */ + xsmp->state = XSMP_STATE_SAVE_YOURSELF; + + state_file = egg_sm_client_save_state ((EggSMClient *)xsmp); + if (!state_file) + { + restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL); + set_properties (xsmp, + ptrarray_prop (SmRestartCommand, restart), + NULL); + g_ptr_array_free (restart, TRUE); + delete_properties (xsmp, SmDiscardCommand, NULL); + return; + } + + desktop_file = egg_get_desktop_file (); + if (desktop_file) + { + GKeyFile *merged_file; + char *desktop_file_path; + + merged_file = g_key_file_new (); + desktop_file_path = + g_filename_from_uri (egg_desktop_file_get_source (desktop_file), + NULL, NULL); + if (desktop_file_path && + g_key_file_load_from_file (merged_file, desktop_file_path, + G_KEY_FILE_KEEP_COMMENTS | + G_KEY_FILE_KEEP_TRANSLATIONS, NULL)) + { + guint g, k, i; + char **groups, **keys, *value, *exec; + + groups = g_key_file_get_groups (state_file, NULL); + for (g = 0; groups[g]; g++) + { + keys = g_key_file_get_keys (state_file, groups[g], NULL, NULL); + for (k = 0; keys[k]; k++) + { + value = g_key_file_get_value (state_file, groups[g], + keys[k], NULL); + if (value) + { + g_key_file_set_value (merged_file, groups[g], + keys[k], value); + g_free (value); + } + } + g_strfreev (keys); + } + g_strfreev (groups); + + g_key_file_free (state_file); + state_file = merged_file; + + /* Update Exec key using "--sm-client-state-file %k" */ + restart = generate_command (xsmp->restart_command, + NULL, "%k"); + for (i = 0; i < restart->len; i++) + restart->pdata[i] = g_shell_quote (restart->pdata[i]); + g_ptr_array_add (restart, NULL); + exec = g_strjoinv (" ", (char **)restart->pdata); + g_strfreev ((char **)restart->pdata); + g_ptr_array_free (restart, FALSE); + + g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP, + EGG_DESKTOP_FILE_KEY_EXEC, + exec); + g_free (exec); + } + else + desktop_file = NULL; + + g_free (desktop_file_path); + } + + /* Now write state_file to disk. (We can't use mktemp(), because + * that requires the filename to end with "XXXXXX", and we want + * it to end with ".desktop".) + */ + + data = g_key_file_to_data (state_file, NULL, NULL); + g_key_file_free (state_file); + + offset = 0; + while (1) + { + state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s", + g_get_user_config_dir (), + G_DIR_SEPARATOR, G_DIR_SEPARATOR, + g_get_prgname (), + (long)time (NULL) + offset, + desktop_file ? "desktop" : "state"); + + fd = open (state_file_path, O_WRONLY | O_CREAT | O_EXCL, 0644); + if (fd == -1) + { + if (errno == EEXIST) + { + offset++; + g_free (state_file_path); + continue; + } + else if (errno == ENOTDIR || errno == ENOENT) + { + char *sep = strrchr (state_file_path, G_DIR_SEPARATOR); + + *sep = '\0'; + if (g_mkdir_with_parents (state_file_path, 0755) != 0) + { + g_warning ("Could not create directory '%s'", + state_file_path); + g_free (state_file_path); + state_file_path = NULL; + break; + } + + continue; + } + + g_warning ("Could not create file '%s': %s", + state_file_path, g_strerror (errno)); + g_free (state_file_path); + state_file_path = NULL; + break; + } + + close (fd); + g_file_set_contents (state_file_path, data, -1, NULL); + break; + } + g_free (data); + + restart = generate_command (xsmp->restart_command, xsmp->client_id, + state_file_path); + set_properties (xsmp, + ptrarray_prop (SmRestartCommand, restart), + NULL); + g_ptr_array_free (restart, TRUE); + + if (state_file_path) + { + set_properties (xsmp, + array_prop (SmDiscardCommand, + "/bin/rm", "-rf", state_file_path, + NULL), + NULL); + g_free (state_file_path); + } +} + +static void +xsmp_interact (SmcConn smc_conn, + SmPointer client_data) +{ + EggSMClientXSMP *xsmp = client_data; + EggSMClient *client = client_data; + + g_debug ("Received Interact message in state %s", + EGG_SM_CLIENT_XSMP_STATE (xsmp)); + + if (xsmp->state != XSMP_STATE_INTERACT_REQUEST) + { + fix_broken_state (xsmp, "Interact", TRUE, TRUE); + return; + } + + xsmp->state = XSMP_STATE_INTERACT; + egg_sm_client_quit_requested (client); +} + +static void +xsmp_die (SmcConn smc_conn, + SmPointer client_data) +{ + EggSMClientXSMP *xsmp = client_data; + EggSMClient *client = client_data; + + g_debug ("Received Die message in state %s", + EGG_SM_CLIENT_XSMP_STATE (xsmp)); + + sm_client_xsmp_disconnect (xsmp); + egg_sm_client_quit (client); +} + +static void +xsmp_save_complete (SmcConn smc_conn, + SmPointer client_data) +{ + EggSMClientXSMP *xsmp = client_data; + + g_debug ("Received SaveComplete message in state %s", + EGG_SM_CLIENT_XSMP_STATE (xsmp)); + + if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE) + xsmp->state = XSMP_STATE_IDLE; + else + fix_broken_state (xsmp, "SaveComplete", FALSE, FALSE); +} + +static void +xsmp_shutdown_cancelled (SmcConn smc_conn, + SmPointer client_data) +{ + EggSMClientXSMP *xsmp = client_data; + EggSMClient *client = client_data; + + g_debug ("Received ShutdownCancelled message in state %s", + EGG_SM_CLIENT_XSMP_STATE (xsmp)); + + xsmp->shutting_down = FALSE; + + if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE) + { + /* We've finished interacting and now the SM has agreed to + * cancel the shutdown. + */ + xsmp->state = XSMP_STATE_IDLE; + egg_sm_client_quit_cancelled (client); + } + else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) + { + /* Hm... ok, so we got a shutdown SaveYourself, which got + * cancelled, but the application was still interacting, so we + * didn't tell it yet, and then *another* SaveYourself arrived, + * which we must still be waiting to tell the app about, except + * that now that SaveYourself has been cancelled too! Dizzy yet? + */ + xsmp->waiting_to_save_myself = FALSE; + update_pending_events (xsmp); + } + else + { + g_debug ("Sending SaveYourselfDone(False)"); + SmcSaveYourselfDone (xsmp->connection, False); + + if (xsmp->state == XSMP_STATE_INTERACT) + { + /* The application is currently interacting, so we can't + * tell it about the cancellation yet; we will wait until + * after it calls egg_sm_client_will_quit(). + */ + xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED; + } + else + { + /* The shutdown was cancelled before the application got a + * chance to interact. + */ + xsmp->state = XSMP_STATE_IDLE; + } + } +} + +/* Utilities */ + +/* Create a restart/clone/Exec command based on @restart_command. + * If @client_id is non-%NULL, add "--sm-client-id @client_id". + * If @state_file is non-%NULL, add "--sm-client-state-file @state_file". + * + * None of the input strings are g_strdup()ed; the caller must keep + * them around until it is done with the returned GPtrArray, and must + * then free the array, but not its contents. + */ +static GPtrArray * +generate_command (char **restart_command, const char *client_id, + const char *state_file) +{ + GPtrArray *cmd; + int i; + + cmd = g_ptr_array_new (); + g_ptr_array_add (cmd, restart_command[0]); + + if (client_id) + { + g_ptr_array_add (cmd, (char *)"--sm-client-id"); + g_ptr_array_add (cmd, (char *)client_id); + } + + if (state_file) + { + g_ptr_array_add (cmd, (char *)"--sm-client-state-file"); + g_ptr_array_add (cmd, (char *)state_file); + } + + for (i = 1; restart_command[i]; i++) + g_ptr_array_add (cmd, restart_command[i]); + + return cmd; +} + +/* Takes a NULL-terminated list of SmProp * values, created by + * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and + * frees them. + */ +static void +set_properties (EggSMClientXSMP *xsmp, ...) +{ + GPtrArray *props; + SmProp *prop; + va_list ap; + guint i; + + props = g_ptr_array_new (); + + va_start (ap, xsmp); + while ((prop = va_arg (ap, SmProp *))) + g_ptr_array_add (props, prop); + va_end (ap); + + if (xsmp->connection) + { + SmcSetProperties (xsmp->connection, props->len, + (SmProp **)props->pdata); + } + + for (i = 0; i < props->len; i++) + { + prop = props->pdata[i]; + g_free (prop->vals); + g_free (prop); + } + g_ptr_array_free (props, TRUE); +} + +/* Takes a NULL-terminated list of property names and deletes them. */ +static void +delete_properties (EggSMClientXSMP *xsmp, ...) +{ + GPtrArray *props; + char *prop; + va_list ap; + + if (!xsmp->connection) + return; + + props = g_ptr_array_new (); + + va_start (ap, xsmp); + while ((prop = va_arg (ap, char *))) + g_ptr_array_add (props, prop); + va_end (ap); + + SmcDeleteProperties (xsmp->connection, props->len, + (char **)props->pdata); + + g_ptr_array_free (props, TRUE); +} + +/* Takes an array of strings and creates a LISTofARRAY8 property. The + * strings are neither dupped nor freed; they need to remain valid + * until you're done with the SmProp. + */ +static SmProp * +array_prop (const char *name, ...) +{ + SmProp *prop; + SmPropValue pv; + GArray *vals; + char *value; + va_list ap; + + prop = g_new (SmProp, 1); + prop->name = (char *)name; + prop->type = (char *)SmLISTofARRAY8; + + vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue)); + + va_start (ap, name); + while ((value = va_arg (ap, char *))) + { + pv.length = strlen (value); + pv.value = value; + g_array_append_val (vals, pv); + } + + prop->num_vals = vals->len; + prop->vals = (SmPropValue *)vals->data; + + g_array_free (vals, FALSE); + + return prop; +} + +/* Takes a GPtrArray of strings and creates a LISTofARRAY8 property. + * The array contents are neither dupped nor freed; they need to + * remain valid until you're done with the SmProp. + */ +static SmProp * +ptrarray_prop (const char *name, GPtrArray *values) +{ + SmProp *prop; + SmPropValue pv; + GArray *vals; + guint i; + + prop = g_new (SmProp, 1); + prop->name = (char *)name; + prop->type = (char *)SmLISTofARRAY8; + + vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue)); + + for (i = 0; i < values->len; i++) + { + pv.length = strlen (values->pdata[i]); + pv.value = values->pdata[i]; + g_array_append_val (vals, pv); + } + + prop->num_vals = vals->len; + prop->vals = (SmPropValue *)vals->data; + + g_array_free (vals, FALSE); + + return prop; +} + +/* Takes a string and creates an ARRAY8 property. The string is + * neither dupped nor freed; it needs to remain valid until you're + * done with the SmProp. + */ +static SmProp * +string_prop (const char *name, const char *value) +{ + SmProp *prop; + + prop = g_new (SmProp, 1); + prop->name = (char *)name; + prop->type = (char *)SmARRAY8; + + prop->num_vals = 1; + prop->vals = g_new (SmPropValue, 1); + + prop->vals[0].length = strlen (value); + prop->vals[0].value = (char *)value; + + return prop; +} + +/* Takes a char and creates a CARD8 property. */ +static SmProp * +card8_prop (const char *name, unsigned char value) +{ + SmProp *prop; + char *card8val; + + /* To avoid having to allocate and free prop->vals[0], we cheat and + * make vals a 2-element-long array and then use the second element + * to store value. + */ + + prop = g_new (SmProp, 1); + prop->name = (char *)name; + prop->type = (char *)SmCARD8; + + prop->num_vals = 1; + prop->vals = g_new (SmPropValue, 2); + card8val = (char *)(&prop->vals[1]); + card8val[0] = value; + + prop->vals[0].length = 1; + prop->vals[0].value = card8val; + + return prop; +} + +/* ICE code. This makes no effort to play nice with anyone else trying + * to use libICE. Fortunately, no one uses libICE for anything other + * than SM. (DCOP uses ICE, but it has its own private copy of + * libICE.) + * + * When this moves to gtk, it will need to be cleverer, to avoid + * tripping over old apps that use MateClient or that use libSM + * directly. + */ + +#include +#include + +static void ice_error_handler (IceConn ice_conn, + Bool swap, + int offending_minor_opcode, + unsigned long offending_sequence, + int error_class, + int severity, + IcePointer values); +static void ice_io_error_handler (IceConn ice_conn); +static void ice_connection_watch (IceConn ice_conn, + IcePointer client_data, + Bool opening, + IcePointer *watch_data); + +static void +ice_init (void) +{ + IceSetIOErrorHandler (ice_io_error_handler); + IceSetErrorHandler (ice_error_handler); + IceAddConnectionWatch (ice_connection_watch, NULL); +} + +static gboolean +process_ice_messages (IceConn ice_conn) +{ + IceProcessMessagesStatus status; + + gdk_threads_enter (); + status = IceProcessMessages (ice_conn, NULL, NULL); + gdk_threads_leave (); + + switch (status) + { + case IceProcessMessagesSuccess: + return TRUE; + + case IceProcessMessagesIOError: + sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn)); + return FALSE; + + case IceProcessMessagesConnectionClosed: + return FALSE; + + default: + g_assert_not_reached (); + } +} + +static gboolean +ice_iochannel_watch (GIOChannel *channel, + GIOCondition condition, + gpointer client_data) +{ + return process_ice_messages (client_data); +} + +static void +ice_connection_watch (IceConn ice_conn, + IcePointer client_data, + Bool opening, + IcePointer *watch_data) +{ + guint watch_id; + + if (opening) + { + GIOChannel *channel; + int fd = IceConnectionNumber (ice_conn); + + fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC); + channel = g_io_channel_unix_new (fd); + watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR, + ice_iochannel_watch, ice_conn); + g_io_channel_unref (channel); + + *watch_data = GUINT_TO_POINTER (watch_id); + } + else + { + watch_id = GPOINTER_TO_UINT (*watch_data); + g_source_remove (watch_id); + } +} + +static void +ice_error_handler (IceConn ice_conn, + Bool swap, + int offending_minor_opcode, + unsigned long offending_sequence, + int error_class, + int severity, + IcePointer values) +{ + /* Do nothing */ +} + +static void +ice_io_error_handler (IceConn ice_conn) +{ + /* Do nothing */ +} + +static void +smc_error_handler (SmcConn smc_conn, + Bool swap, + int offending_minor_opcode, + unsigned long offending_sequence, + int error_class, + int severity, + SmPointer values) +{ + /* Do nothing */ +} diff --git a/mate-panel/libegg/eggsmclient.c b/mate-panel/libegg/eggsmclient.c new file mode 100644 index 00000000..2b480cca --- /dev/null +++ b/mate-panel/libegg/eggsmclient.c @@ -0,0 +1,604 @@ +/* + * Copyright (C) 2007 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "eggsmclient.h" +#include "eggsmclient-private.h" + +static void egg_sm_client_debug_handler (const char *log_domain, + GLogLevelFlags log_level, + const char *message, + gpointer user_data); + +enum { + SAVE_STATE, + QUIT_REQUESTED, + QUIT_CANCELLED, + QUIT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +struct _EggSMClientPrivate { + GKeyFile *state_file; +}; + +#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate)) + +G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT) + +static EggSMClient *global_client; +static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL; + +static void +egg_sm_client_init (EggSMClient *client) +{ + ; +} + +static void +egg_sm_client_class_init (EggSMClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (EggSMClientPrivate)); + + /** + * EggSMClient::save_state: + * @client: the client + * @state_file: a #GKeyFile to save state information into + * + * Emitted when the session manager has requested that the + * application save information about its current state. The + * application should save its state into @state_file, and then the + * session manager may then restart the application in a future + * session and tell it to initialize itself from that state. + * + * You should not save any data into @state_file's "start group" + * (ie, the %NULL group). Instead, applications should save their + * data into groups with names that start with the application name, + * and libraries that connect to this signal should save their data + * into groups with names that start with the library name. + * + * Alternatively, rather than (or in addition to) using @state_file, + * the application can save its state by calling + * egg_sm_client_set_restart_command() during the processing of this + * signal (eg, to include a list of files to open). + **/ + signals[SAVE_STATE] = + g_signal_new ("save_state", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggSMClientClass, save_state), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, G_TYPE_POINTER); + + /** + * EggSMClient::quit_requested: + * @client: the client + * + * Emitted when the session manager requests that the application + * exit (generally because the user is logging out). The application + * should decide whether or not it is willing to quit (perhaps after + * asking the user what to do with documents that have unsaved + * changes) and then call egg_sm_client_will_quit(), passing %TRUE + * or %FALSE to give its answer to the session manager. (It does not + * need to give an answer before returning from the signal handler; + * it can interact with the user asynchronously and then give its + * answer later on.) If the application does not connect to this + * signal, then #EggSMClient will automatically return %TRUE on its + * behalf. + * + * The application should not save its session state as part of + * handling this signal; if the user has requested that the session + * be saved when logging out, then ::save_state will be emitted + * separately. + * + * If the application agrees to quit, it should then wait for either + * the ::quit_cancelled or ::quit signals to be emitted. + **/ + signals[QUIT_REQUESTED] = + g_signal_new ("quit_requested", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggSMClientClass, quit_requested), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * EggSMClient::quit_cancelled: + * @client: the client + * + * Emitted when the session manager decides to cancel a logout after + * the application has already agreed to quit. After receiving this + * signal, the application can go back to what it was doing before + * receiving the ::quit_requested signal. + **/ + signals[QUIT_CANCELLED] = + g_signal_new ("quit_cancelled", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * EggSMClient::quit: + * @client: the client + * + * Emitted when the session manager wants the application to quit + * (generally because the user is logging out). The application + * should exit as soon as possible after receiving this signal; if + * it does not, the session manager may choose to forcibly kill it. + * + * Normally a GUI application would only be sent a ::quit if it + * agreed to quit in response to a ::quit_requested signal. However, + * this is not guaranteed; in some situations the session manager + * may decide to end the session without giving applications a + * chance to object. + **/ + signals[QUIT] = + g_signal_new ("quit", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggSMClientClass, quit), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static gboolean sm_client_disable = FALSE; +static char *sm_client_state_file = NULL; +static char *sm_client_id = NULL; +static char *sm_config_prefix = NULL; + +static gboolean +sm_client_post_parse_func (GOptionContext *context, + GOptionGroup *group, + gpointer data, + GError **error) +{ + EggSMClient *client = egg_sm_client_get (); + + if (sm_client_id == NULL) + { + const gchar *desktop_autostart_id; + + desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); + + if (desktop_autostart_id != NULL) + sm_client_id = g_strdup (desktop_autostart_id); + } + + /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to + * use the same client id. */ + g_unsetenv ("DESKTOP_AUTOSTART_ID"); + + if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED && + EGG_SM_CLIENT_GET_CLASS (client)->startup) + EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id); + return TRUE; +} + +/** + * egg_sm_client_get_option_group: + * + * Creates a %GOptionGroup containing the session-management-related + * options. You should add this group to the application's + * %GOptionContext if you want to use #EggSMClient. + * + * Return value: the %GOptionGroup + **/ +GOptionGroup * +egg_sm_client_get_option_group (void) +{ + const GOptionEntry entries[] = { + { "sm-client-disable", 0, 0, + G_OPTION_ARG_NONE, &sm_client_disable, + N_("Disable connection to session manager"), NULL }, + { "sm-client-state-file", 0, 0, + G_OPTION_ARG_FILENAME, &sm_client_state_file, + N_("Specify file containing saved configuration"), N_("FILE") }, + { "sm-client-id", 0, 0, + G_OPTION_ARG_STRING, &sm_client_id, + N_("Specify session management ID"), N_("ID") }, + /* MateClient compatibility option */ + { "sm-disable", 0, G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_NONE, &sm_client_disable, + NULL, NULL }, + /* MateClient compatibility option. This is a dummy option that only + * exists so that sessions saved by apps with MateClient can be restored + * later when they've switched to EggSMClient. See bug #575308. + */ + { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_STRING, &sm_config_prefix, + NULL, NULL }, + { NULL } + }; + GOptionGroup *group; + + /* Use our own debug handler for the "EggSMClient" domain. */ + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + egg_sm_client_debug_handler, NULL); + + group = g_option_group_new ("sm-client", + _("Session management options:"), + _("Show session management options"), + NULL, NULL); + g_option_group_add_entries (group, entries); + g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func); + + return group; +} + +/** + * egg_sm_client_set_mode: + * @mode: an #EggSMClient mode + * + * Sets the "mode" of #EggSMClient as follows: + * + * %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely + * disabled, until the mode is changed again. The application will + * not even connect to the session manager. (egg_sm_client_get() + * will still return an #EggSMClient object.) + * + * %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to + * the session manager (and thus will receive notification when the + * user is logging out, etc), but will request to not be + * automatically restarted with saved state in future sessions. + * + * %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will + * function normally. + * + * This must be called before the application's main loop begins and + * before any call to egg_sm_client_get(), unless the mode was set + * earlier to %EGG_SM_CLIENT_MODE_DISABLED and this call enables + * session management. Note that option parsing will call + * egg_sm_client_get(). + **/ +void +egg_sm_client_set_mode (EggSMClientMode mode) +{ + EggSMClientMode old_mode = global_client_mode; + + g_return_if_fail (global_client == NULL || global_client_mode == EGG_SM_CLIENT_MODE_DISABLED); + g_return_if_fail (!(global_client != NULL && mode == EGG_SM_CLIENT_MODE_DISABLED)); + + global_client_mode = mode; + + if (global_client != NULL && old_mode == EGG_SM_CLIENT_MODE_DISABLED) + { + if (EGG_SM_CLIENT_GET_CLASS (global_client)->startup) + EGG_SM_CLIENT_GET_CLASS (global_client)->startup (global_client, sm_client_id); + } +} + +/** + * egg_sm_client_get_mode: + * + * Gets the global #EggSMClientMode. See egg_sm_client_set_mode() + * for details. + * + * Return value: the global #EggSMClientMode + **/ +EggSMClientMode +egg_sm_client_get_mode (void) +{ + return global_client_mode; +} + +/** + * egg_sm_client_get: + * + * Returns the master #EggSMClient for the application. + * + * On platforms that support saved sessions (ie, POSIX/X11), the + * application will only request to be restarted by the session + * manager if you call egg_set_desktop_file() to set an application + * desktop file. In particular, if the desktop file contains the key + * "X + * + * Return value: the master #EggSMClient. + **/ +EggSMClient * +egg_sm_client_get (void) +{ + if (!global_client) + { + if (!sm_client_disable) + { +#if defined (GDK_WINDOWING_WIN32) + global_client = egg_sm_client_win32_new (); +#elif defined (GDK_WINDOWING_QUARTZ) + global_client = egg_sm_client_osx_new (); +#else + /* If both D-Bus and XSMP are compiled in, try XSMP first + * (since it supports state saving) and fall back to D-Bus + * if XSMP isn't available. + */ +# ifdef EGG_SM_CLIENT_BACKEND_XSMP + global_client = egg_sm_client_xsmp_new (); +# endif +# ifdef EGG_SM_CLIENT_BACKEND_DBUS + if (!global_client) + global_client = egg_sm_client_dbus_new (); +# endif +#endif + } + + /* Fallback: create a dummy client, so that callers don't have + * to worry about a %NULL return value. + */ + if (!global_client) + global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL); + } + + return global_client; +} + +/** + * egg_sm_client_is_resumed: + * @client: the client + * + * Checks whether or not the current session has been resumed from + * a previous saved session. If so, the application should call + * egg_sm_client_get_state_file() and restore its state from the + * returned #GKeyFile. + * + * Return value: %TRUE if the session has been resumed + **/ +gboolean +egg_sm_client_is_resumed (EggSMClient *client) +{ + g_return_val_if_fail (client == global_client, FALSE); + + return sm_client_state_file != NULL; +} + +/** + * egg_sm_client_get_state_file: + * @client: the client + * + * If the application was resumed by the session manager, this will + * return the #GKeyFile containing its state from the previous + * session. + * + * Note that other libraries and #EggSMClient itself may also store + * state in the key file, so if you call egg_sm_client_get_groups(), + * on it, the return value will likely include groups that you did not + * put there yourself. (It is also not guaranteed that the first + * group created by the application will still be the "start group" + * when it is resumed.) + * + * Return value: the #GKeyFile containing the application's earlier + * state, or %NULL on error. You should not free this key file; it + * is owned by @client. + **/ +GKeyFile * +egg_sm_client_get_state_file (EggSMClient *client) +{ + EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client); + char *state_file_path; + GError *err = NULL; + + g_return_val_if_fail (client == global_client, NULL); + + if (!sm_client_state_file) + return NULL; + if (priv->state_file) + return priv->state_file; + + if (!strncmp (sm_client_state_file, "file://", 7)) + state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL); + else + state_file_path = g_strdup (sm_client_state_file); + + priv->state_file = g_key_file_new (); + if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err)) + { + g_warning ("Could not load SM state file '%s': %s", + sm_client_state_file, err->message); + g_clear_error (&err); + g_key_file_free (priv->state_file); + priv->state_file = NULL; + } + + g_free (state_file_path); + return priv->state_file; +} + +/** + * egg_sm_client_set_restart_command: + * @client: the client + * @argc: the length of @argv + * @argv: argument vector + * + * Sets the command used to restart @client if it does not have a + * .desktop file that can be used to find its restart command. + * + * This can also be used when handling the ::save_state signal, to + * save the current state via an updated command line. (Eg, providing + * a list of filenames to open when the application is resumed.) + **/ +void +egg_sm_client_set_restart_command (EggSMClient *client, + int argc, + const char **argv) +{ + g_return_if_fail (EGG_IS_SM_CLIENT (client)); + + if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command) + EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv); +} + +/** + * egg_sm_client_will_quit: + * @client: the client + * @will_quit: whether or not the application is willing to quit + * + * This MUST be called in response to the ::quit_requested signal, to + * indicate whether or not the application is willing to quit. The + * application may call it either directly from the signal handler, or + * at some later point (eg, after asynchronously interacting with the + * user). + * + * If the application does not connect to ::quit_requested, + * #EggSMClient will call this method on its behalf (passing %TRUE + * for @will_quit). + * + * After calling this method, the application should wait to receive + * either ::quit_cancelled or ::quit. + **/ +void +egg_sm_client_will_quit (EggSMClient *client, + gboolean will_quit) +{ + g_return_if_fail (EGG_IS_SM_CLIENT (client)); + + if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit) + EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit); +} + +/** + * egg_sm_client_end_session: + * @style: a hint at how to end the session + * @request_confirmation: whether or not the user should get a chance + * to confirm the action + * + * Requests that the session manager end the current session. @style + * indicates how the session should be ended, and + * @request_confirmation indicates whether or not the user should be + * given a chance to confirm the logout/reboot/shutdown. Both of these + * flags are merely hints though; the session manager may choose to + * ignore them. + * + * Return value: %TRUE if the request was sent; %FALSE if it could not + * be (eg, because it could not connect to the session manager). + **/ +gboolean +egg_sm_client_end_session (EggSMClientEndStyle style, + gboolean request_confirmation) +{ + EggSMClient *client = egg_sm_client_get (); + + g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE); + + if (EGG_SM_CLIENT_GET_CLASS (client)->end_session) + { + return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style, + request_confirmation); + } + else + return FALSE; +} + +/* Signal-emitting callbacks from platform-specific code */ + +GKeyFile * +egg_sm_client_save_state (EggSMClient *client) +{ + GKeyFile *state_file; + char *group; + + g_return_val_if_fail (client == global_client, NULL); + + state_file = g_key_file_new (); + + g_debug ("Emitting save_state"); + g_signal_emit (client, signals[SAVE_STATE], 0, state_file); + g_debug ("Done emitting save_state"); + + group = g_key_file_get_start_group (state_file); + if (group) + { + g_free (group); + return state_file; + } + else + { + g_key_file_free (state_file); + return NULL; + } +} + +void +egg_sm_client_quit_requested (EggSMClient *client) +{ + g_return_if_fail (client == global_client); + + if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE)) + { + g_debug ("Not emitting quit_requested because no one is listening"); + egg_sm_client_will_quit (client, TRUE); + return; + } + + g_debug ("Emitting quit_requested"); + g_signal_emit (client, signals[QUIT_REQUESTED], 0); + g_debug ("Done emitting quit_requested"); +} + +void +egg_sm_client_quit_cancelled (EggSMClient *client) +{ + g_return_if_fail (client == global_client); + + g_debug ("Emitting quit_cancelled"); + g_signal_emit (client, signals[QUIT_CANCELLED], 0); + g_debug ("Done emitting quit_cancelled"); +} + +void +egg_sm_client_quit (EggSMClient *client) +{ + g_return_if_fail (client == global_client); + + g_debug ("Emitting quit"); + g_signal_emit (client, signals[QUIT], 0); + g_debug ("Done emitting quit"); + + /* FIXME: should we just call gtk_main_quit() here? */ +} + +static void +egg_sm_client_debug_handler (const char *log_domain, + GLogLevelFlags log_level, + const char *message, + gpointer user_data) +{ + static int debug = -1; + + if (debug < 0) + debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL); + + if (debug) + g_log_default_handler (log_domain, log_level, message, NULL); +} diff --git a/mate-panel/libegg/eggsmclient.h b/mate-panel/libegg/eggsmclient.h new file mode 100644 index 00000000..be585376 --- /dev/null +++ b/mate-panel/libegg/eggsmclient.h @@ -0,0 +1,121 @@ +/* eggsmclient.h + * Copyright (C) 2007 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_SM_CLIENT_H__ +#define __EGG_SM_CLIENT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ()) +#define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient)) +#define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass)) +#define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT)) +#define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT)) +#define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass)) + +typedef struct _EggSMClient EggSMClient; +typedef struct _EggSMClientClass EggSMClientClass; +typedef struct _EggSMClientPrivate EggSMClientPrivate; + +typedef enum { + EGG_SM_CLIENT_END_SESSION_DEFAULT, + EGG_SM_CLIENT_LOGOUT, + EGG_SM_CLIENT_REBOOT, + EGG_SM_CLIENT_SHUTDOWN +} EggSMClientEndStyle; + +typedef enum { + EGG_SM_CLIENT_MODE_DISABLED, + EGG_SM_CLIENT_MODE_NO_RESTART, + EGG_SM_CLIENT_MODE_NORMAL +} EggSMClientMode; + +struct _EggSMClient +{ + GObject parent; + +}; + +struct _EggSMClientClass +{ + GObjectClass parent_class; + + /* signals */ + void (*save_state) (EggSMClient *client, + GKeyFile *state_file); + + void (*quit_requested) (EggSMClient *client); + void (*quit_cancelled) (EggSMClient *client); + void (*quit) (EggSMClient *client); + + /* virtual methods */ + void (*startup) (EggSMClient *client, + const char *client_id); + void (*set_restart_command) (EggSMClient *client, + int argc, + const char **argv); + void (*will_quit) (EggSMClient *client, + gboolean will_quit); + gboolean (*end_session) (EggSMClient *client, + EggSMClientEndStyle style, + gboolean request_confirmation); + + /* Padding for future expansion */ + void (*_egg_reserved1) (void); + void (*_egg_reserved2) (void); + void (*_egg_reserved3) (void); + void (*_egg_reserved4) (void); +}; + +GType egg_sm_client_get_type (void) G_GNUC_CONST; + +GOptionGroup *egg_sm_client_get_option_group (void); + +/* Initialization */ +void egg_sm_client_set_mode (EggSMClientMode mode); +EggSMClientMode egg_sm_client_get_mode (void); +EggSMClient *egg_sm_client_get (void); + +/* Resuming a saved session */ +gboolean egg_sm_client_is_resumed (EggSMClient *client); +GKeyFile *egg_sm_client_get_state_file (EggSMClient *client); + +/* Alternate means of saving state */ +void egg_sm_client_set_restart_command (EggSMClient *client, + int argc, + const char **argv); + +/* Handling "quit_requested" signal */ +void egg_sm_client_will_quit (EggSMClient *client, + gboolean will_quit); + +/* Initiate a logout/reboot/shutdown */ +gboolean egg_sm_client_end_session (EggSMClientEndStyle style, + gboolean request_confirmation); + +#ifdef __cplusplus +} +#endif + + +#endif /* __EGG_SM_CLIENT_H__ */ diff --git a/mate-panel/libmate-panel-applet-private/Makefile.am b/mate-panel/libmate-panel-applet-private/Makefile.am new file mode 100644 index 00000000..9dd4b631 --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/Makefile.am @@ -0,0 +1,34 @@ +noinst_LTLIBRARIES = \ + libmate-panel-applet-private.la \ + libmate-panel-applet-private-mini.la + +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + -I. \ + -I$(srcdir) \ + -I$(top_srcdir)/mate-panel \ + -I$(top_builddir)/mate-panel \ + -I$(top_builddir)/mate-panel/libmate-panel-applets-private \ + -I$(top_builddir)/mate-panel/libpanel-util \ + -DDATADIR=\""$(datadir)"\" \ + -DMATE_PANEL_APPLETS_DIR=\"$(appletsdir)\" \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) + +libmate_panel_applet_private_la_SOURCES = \ + mate-panel-applets-manager-dbus.c \ + mate-panel-applets-manager-dbus.h \ + mate-panel-applet-container.c \ + mate-panel-applet-container.h \ + mate-panel-applet-frame-dbus.c \ + mate-panel-applet-frame-dbus.h + +libmate_panel_applet_private_mini_la_SOURCES =\ + mate-panel-applet-mini.c \ + mate-panel-applets-manager-dbus.c \ + mate-panel-applets-manager-dbus.h \ + mate-panel-applet-container.c \ + mate-panel-applet-container.h + +-include $(top_srcdir)/git.mk diff --git a/mate-panel/libmate-panel-applet-private/Makefile.in b/mate-panel/libmate-panel-applet-private/Makefile.in new file mode 100644 index 00000000..9c7e63bf --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/Makefile.in @@ -0,0 +1,644 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = mate-panel/libmate-panel-applet-private +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/d-type.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libmate_panel_applet_private_mini_la_LIBADD = +am_libmate_panel_applet_private_mini_la_OBJECTS = \ + mate-panel-applet-mini.lo mate-panel-applets-manager-dbus.lo \ + mate-panel-applet-container.lo +libmate_panel_applet_private_mini_la_OBJECTS = \ + $(am_libmate_panel_applet_private_mini_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libmate_panel_applet_private_la_LIBADD = +am_libmate_panel_applet_private_la_OBJECTS = \ + mate-panel-applets-manager-dbus.lo \ + mate-panel-applet-container.lo mate-panel-applet-frame-dbus.lo +libmate_panel_applet_private_la_OBJECTS = \ + $(am_libmate_panel_applet_private_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libmate_panel_applet_private_mini_la_SOURCES) \ + $(libmate_panel_applet_private_la_SOURCES) +DIST_SOURCES = $(libmate_panel_applet_private_mini_la_SOURCES) \ + $(libmate_panel_applet_private_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLOCK_CFLAGS = @CLOCK_CFLAGS@ +CLOCK_EDS_ICONDIR = @CLOCK_EDS_ICONDIR@ +CLOCK_LIBS = @CLOCK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DISABLE_DEPRECATED_CFLAGS = @DISABLE_DEPRECATED_CFLAGS@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOC_USER_FORMATS = @DOC_USER_FORMATS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGG_SMCLIENT_CFLAGS = @EGG_SMCLIENT_CFLAGS@ +EGG_SMCLIENT_LIBS = @EGG_SMCLIENT_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FISH_CFLAGS = @FISH_CFLAGS@ +FISH_LIBS = @FISH_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_QUERYMODULES = @GIO_QUERYMODULES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HELP_DIR = @HELP_DIR@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBMATE_PANEL_APPLET_CFLAGS = @LIBMATE_PANEL_APPLET_CFLAGS@ +LIBMATE_PANEL_APPLET_LIBS = @LIBMATE_PANEL_APPLET_LIBS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MATE_PANEL_APPLET_LT_VERSION = @LIB_MATE_PANEL_APPLET_LT_VERSION@ +LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION = @LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECOMPONENT_ACT_IDLDIR = @MATECOMPONENT_ACT_IDLDIR@ +MATECOMPONENT_CFLAGS = @MATECOMPONENT_CFLAGS@ +MATECOMPONENT_IDLDIR = @MATECOMPONENT_IDLDIR@ +MATECOMPONENT_LIBS = @MATECOMPONENT_LIBS@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATECORBA_IDL = @MATECORBA_IDL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NETWORK_MANAGER_CFLAGS = @NETWORK_MANAGER_CFLAGS@ +NETWORK_MANAGER_LIBS = @NETWORK_MANAGER_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOTIFICATION_AREA_CFLAGS = @NOTIFICATION_AREA_CFLAGS@ +NOTIFICATION_AREA_LIBS = @NOTIFICATION_AREA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OMF_DIR = @OMF_DIR@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANEL_CFLAGS = @PANEL_CFLAGS@ +PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE = @PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ +PANEL_LIBS = @PANEL_LIBS@ +PANEL_MODULE_MATECOMPONENT_CFLAGS = @PANEL_MODULE_MATECOMPONENT_CFLAGS@ +PANEL_MODULE_MATECOMPONENT_LIBS = @PANEL_MODULE_MATECOMPONENT_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POFILES = @POFILES@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REBUILD = @REBUILD@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TZ_CFLAGS = @TZ_CFLAGS@ +TZ_LIBS = @TZ_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WNCKLET_CFLAGS = @WNCKLET_CFLAGS@ +WNCKLET_LIBS = @WNCKLET_LIBS@ +XGETTEXT = @XGETTEXT@ +XMKMF = @XMKMF@ +XRANDR_CFLAGS = @XRANDR_CFLAGS@ +XRANDR_LIBS = @XRANDR_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +appletsdir = @appletsdir@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +modulesdir = @modulesdir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + libmate-panel-applet-private.la \ + libmate-panel-applet-private-mini.la + +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + -I. \ + -I$(srcdir) \ + -I$(top_srcdir)/mate-panel \ + -I$(top_builddir)/mate-panel \ + -I$(top_builddir)/mate-panel/libmate-panel-applets-private \ + -I$(top_builddir)/mate-panel/libpanel-util \ + -DDATADIR=\""$(datadir)"\" \ + -DMATE_PANEL_APPLETS_DIR=\"$(appletsdir)\" \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) +libmate_panel_applet_private_la_SOURCES = \ + mate-panel-applets-manager-dbus.c \ + mate-panel-applets-manager-dbus.h \ + mate-panel-applet-container.c \ + mate-panel-applet-container.h \ + mate-panel-applet-frame-dbus.c \ + mate-panel-applet-frame-dbus.h + +libmate_panel_applet_private_mini_la_SOURCES = \ + mate-panel-applet-mini.c \ + mate-panel-applets-manager-dbus.c \ + mate-panel-applets-manager-dbus.h \ + mate-panel-applet-container.c \ + mate-panel-applet-container.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu mate-panel/libmate-panel-applet-private/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu mate-panel/libmate-panel-applet-private/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmate-panel-applet-private-mini.la: $(libmate_panel_applet_private_mini_la_OBJECTS) $(libmate_panel_applet_private_mini_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmate_panel_applet_private_mini_la_OBJECTS) $(libmate_panel_applet_private_mini_la_LIBADD) $(LIBS) +libmate-panel-applet-private.la: $(libmate_panel_applet_private_la_OBJECTS) $(libmate_panel_applet_private_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmate_panel_applet_private_la_OBJECTS) $(libmate_panel_applet_private_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate-panel-applet-container.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate-panel-applet-frame-dbus.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate-panel-applet-mini.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate-panel-applets-manager-dbus.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applet-container.c b/mate-panel/libmate-panel-applet-private/mate-panel-applet-container.c new file mode 100644 index 00000000..f2e39019 --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applet-container.c @@ -0,0 +1,790 @@ +/* + * mate-panel-applet-container.c: a container for applets. + * + * Copyright (C) 2010 Carlos Garcia Campos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include +#include "mate-panel-applet-container.h" +#include "panel-marshal.h" + +struct _MatePanelAppletContainerPrivate { + GDBusProxy *applet_proxy; + + guint name_watcher_id; + gchar *bus_name; + + guint32 xid; + GtkWidget *socket; + + GHashTable *pending_ops; +}; + +enum { + APPLET_BROKEN, + APPLET_MOVE, + APPLET_REMOVE, + APPLET_LOCK, + CHILD_PROPERTY_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +typedef struct { + const gchar *name; + const gchar *dbus_name; +} AppletPropertyInfo; + +static const AppletPropertyInfo applet_properties [] = { + { "prefs-key", "PrefsKey" }, + { "orient", "Orient" }, + { "size", "Size" }, + { "size-hints", "SizeHints" }, + { "background", "Background" }, + { "flags", "Flags" }, + { "locked", "Locked" }, + { "locked-down", "LockedDown" } +}; + +#define MATE_PANEL_APPLET_CONTAINER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_APPLET_CONTAINER, MatePanelAppletContainerPrivate)) + +#define MATE_PANEL_APPLET_BUS_NAME "org.mate.panel.applet.%s" +#define MATE_PANEL_APPLET_FACTORY_INTERFACE "org.mate.panel.applet.AppletFactory" +#define MATE_PANEL_APPLET_FACTORY_OBJECT_PATH "/org/mate/panel/applet/%s" +#define MATE_PANEL_APPLET_INTERFACE "org.mate.panel.applet.Applet" + +static gboolean mate_panel_applet_container_plug_removed (MatePanelAppletContainer *container); + +G_DEFINE_TYPE (MatePanelAppletContainer, mate_panel_applet_container, GTK_TYPE_EVENT_BOX); + +GQuark mate_panel_applet_container_error_quark (void) +{ + return g_quark_from_static_string ("mate-panel-applet-container-error-quark"); +} + +static void mate_panel_applet_container_init(MatePanelAppletContainer* container) +{ + container->priv = MATE_PANEL_APPLET_CONTAINER_GET_PRIVATE (container); + + container->priv->socket = gtk_socket_new (); + g_signal_connect_swapped (container->priv->socket, "plug-removed", G_CALLBACK (mate_panel_applet_container_plug_removed), container); + + container->priv->pending_ops = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + gtk_container_add (GTK_CONTAINER (container), + container->priv->socket); + gtk_widget_show (container->priv->socket); +} + +static void +mate_panel_applet_container_cancel_pending_operations (MatePanelAppletContainer *container) +{ + GList *keys, *l; + + if (!container->priv->pending_ops) + return; + + keys = g_hash_table_get_keys (container->priv->pending_ops); + for (l = keys; l; l = g_list_next (l)) { + GCancellable *cancellable; + + cancellable = G_CANCELLABLE (g_hash_table_lookup (container->priv->pending_ops, l->data)); + g_cancellable_cancel (cancellable); + } + g_list_free (keys); +} + +static void +mate_panel_applet_container_dispose (GObject *object) +{ + MatePanelAppletContainer *container = MATE_PANEL_APPLET_CONTAINER (object); + + if (container->priv->pending_ops) { + mate_panel_applet_container_cancel_pending_operations (container); + g_hash_table_destroy (container->priv->pending_ops); + container->priv->pending_ops = NULL; + } + + if (container->priv->bus_name) { + g_free (container->priv->bus_name); + container->priv->bus_name = NULL; + } + + if (container->priv->name_watcher_id > 0) { + g_bus_unwatch_name (container->priv->name_watcher_id); + container->priv->name_watcher_id = 0; + } + + if (container->priv->applet_proxy) { + g_object_unref (container->priv->applet_proxy); + container->priv->applet_proxy = NULL; + } + + G_OBJECT_CLASS (mate_panel_applet_container_parent_class)->dispose (object); +} + +static void +mate_panel_applet_container_class_init (MatePanelAppletContainerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (MatePanelAppletContainerPrivate)); + + gobject_class->dispose = mate_panel_applet_container_dispose; + + signals[APPLET_BROKEN] = + g_signal_new ("applet-broken", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_broken), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[APPLET_MOVE] = + g_signal_new ("applet-move", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_move), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[APPLET_REMOVE] = + g_signal_new ("applet-remove", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_remove), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[APPLET_LOCK] = + g_signal_new ("applet-lock", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, applet_lock), + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, G_TYPE_BOOLEAN); + signals[CHILD_PROPERTY_CHANGED] = + g_signal_new ("child-property-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | + G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (MatePanelAppletContainerClass, child_property_changed), + NULL, + NULL, + panel_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_POINTER); +} + +static const AppletPropertyInfo * +mate_panel_applet_container_child_property_get_info (const gchar *property_name) +{ + gint i; + + g_assert (property_name != NULL); + + for (i = 0; i < G_N_ELEMENTS (applet_properties); i++) { + if (g_ascii_strcasecmp (applet_properties[i].name, property_name) == 0) + return &applet_properties[i]; + } + + return NULL; +} + +GtkWidget * +mate_panel_applet_container_new (void) +{ + GtkWidget *container; + + container = GTK_WIDGET (g_object_new (PANEL_TYPE_APPLET_CONTAINER, NULL)); + + return container; +} + +static gboolean +mate_panel_applet_container_plug_removed (MatePanelAppletContainer *container) +{ + if (!container->priv->applet_proxy) + return FALSE; + + mate_panel_applet_container_cancel_pending_operations (container); + + if (container->priv->name_watcher_id > 0) { + g_bus_unwatch_name (container->priv->name_watcher_id); + container->priv->name_watcher_id = 0; + } + + g_object_unref (container->priv->applet_proxy); + container->priv->applet_proxy = NULL; + + g_signal_emit (container, signals[APPLET_BROKEN], 0); + + /* Continue destroying, in case of reloading + * a new frame widget is created + */ + return FALSE; +} + +static void +mate_panel_applet_container_child_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + MatePanelAppletContainer *container) +{ + if (g_strcmp0 (signal_name, "Move") == 0) { + g_signal_emit (container, signals[APPLET_MOVE], 0); + } else if (g_strcmp0 (signal_name, "RemoveFromPanel") == 0) { + g_signal_emit (container, signals[APPLET_REMOVE], 0); + } else if (g_strcmp0 (signal_name, "Lock") == 0) { + g_signal_emit (container, signals[APPLET_LOCK], 0, TRUE); + } else if (g_strcmp0 (signal_name, "Unlock") == 0) { + g_signal_emit (container, signals[APPLET_LOCK], 0, FALSE); + } +} + +static void +on_property_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + MatePanelAppletContainer *container) +{ + GVariant *props; + GVariantIter iter; + GVariant *value; + gchar *key; + + g_variant_get (parameters, "(s@a{sv}*)", NULL, &props, NULL); + + g_variant_iter_init (&iter, props); + while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) { + if (g_strcmp0 (key, "Flags") == 0) { + g_signal_emit (container, signals[CHILD_PROPERTY_CHANGED], + g_quark_from_string ("flags"), + "flags", value); + } else if (g_strcmp0 (key, "SizeHints") == 0) { + g_signal_emit (container, signals[CHILD_PROPERTY_CHANGED], + g_quark_from_string ("size-hints"), + "size-hints", value); + } + } + + g_variant_unref (props); +} + +static void +on_proxy_appeared (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GDBusProxy *proxy; + GError *error = NULL; + + proxy = g_dbus_proxy_new_finish (res, &error); + if (!proxy) { + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + g_simple_async_result_complete (result); + g_object_unref (result); + + return; + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + + container->priv->applet_proxy = proxy; + g_signal_connect (container->priv->applet_proxy, "g-signal", + G_CALLBACK (mate_panel_applet_container_child_signal), + container); + g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_dbus_proxy_get_object_path (proxy), + MATE_PANEL_APPLET_INTERFACE, + G_DBUS_SIGNAL_FLAGS_NONE, + (GDBusSignalCallback) on_property_changed, + container, NULL); + + g_simple_async_result_complete (result); + g_object_unref (result); + + if (container->priv->xid > 0) { + gtk_socket_add_id (GTK_SOCKET (container->priv->socket), + container->priv->xid); + } + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +static void +get_applet_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GVariant *retvals; + const gchar *applet_path; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + g_simple_async_result_complete (result); + g_object_unref (result); + + return; + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + g_variant_get (retvals, "(&ou)", &applet_path, &container->priv->xid); + + g_dbus_proxy_new (connection, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + container->priv->bus_name, + applet_path, + MATE_PANEL_APPLET_INTERFACE, + NULL, + (GAsyncReadyCallback) on_proxy_appeared, + result); + + g_variant_unref (retvals); + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +typedef struct { + GSimpleAsyncResult *result; + gchar *factory_id; + GVariant *parameters; + GCancellable *cancellable; +} AppletFactoryData; + +static void +applet_factory_data_free (AppletFactoryData *data) +{ + g_free (data->factory_id); + if (data->cancellable) + g_object_unref (data->cancellable); + + g_free (data); +} + +static void +on_factory_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + AppletFactoryData *data) +{ + MatePanelAppletContainer *container; + gchar *object_path; + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (data->result))); + container->priv->bus_name = g_strdup (name_owner); + object_path = g_strdup_printf (MATE_PANEL_APPLET_FACTORY_OBJECT_PATH, data->factory_id); + g_dbus_connection_call (connection, + name_owner, + object_path, + MATE_PANEL_APPLET_FACTORY_INTERFACE, + "GetApplet", + data->parameters, + G_VARIANT_TYPE ("(ou)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + data->cancellable, + get_applet_cb, + data->result); + g_free (object_path); +} + +static void +mate_panel_applet_container_get_applet (MatePanelAppletContainer *container, + const gchar *iid, + GVariant *props, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + AppletFactoryData *data; + gint screen; + gchar *bus_name; + gchar *factory_id; + gchar *applet_id; + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_get_applet); + + applet_id = g_strrstr (iid, "::"); + if (!applet_id) { + g_simple_async_result_set_error (result, + MATE_PANEL_APPLET_CONTAINER_ERROR, + MATE_PANEL_APPLET_CONTAINER_INVALID_APPLET, + "Invalid applet iid: %s", iid); + g_simple_async_result_complete (result); + g_object_unref (result); + + return; + } + + factory_id = g_strndup (iid, strlen (iid) - strlen (applet_id)); + applet_id += 2; + + screen = gdk_screen_get_number (gtk_widget_get_screen (container->priv->socket)); + + data = g_new (AppletFactoryData, 1); + data->result = result; + data->factory_id = factory_id; + data->parameters = g_variant_new ("(si*)", applet_id, screen, props); + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + bus_name = g_strdup_printf (MATE_PANEL_APPLET_BUS_NAME, factory_id); + + container->priv->name_watcher_id = + g_bus_watch_name (G_BUS_TYPE_SESSION, + bus_name, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + (GBusNameAppearedCallback) on_factory_appeared, + NULL, + data, + (GDestroyNotify) applet_factory_data_free); + + g_free (bus_name); +} + +void +mate_panel_applet_container_add (MatePanelAppletContainer *container, + const gchar *iid, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + GVariant *properties) +{ + g_return_if_fail (PANEL_IS_APPLET_CONTAINER (container)); + g_return_if_fail (iid != NULL); + + mate_panel_applet_container_cancel_pending_operations (container); + + mate_panel_applet_container_get_applet (container, iid, properties, + cancellable, callback, user_data); +} + +gboolean +mate_panel_applet_container_add_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_get_applet); + + return !g_simple_async_result_propagate_error (simple, error); +} + +/* Child Properties */ +static void +set_applet_property_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GVariant *retvals; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Error setting property: %s\n", error->message); + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + } else { + g_variant_unref (retvals); + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + g_hash_table_remove (container->priv->pending_ops, result); + g_simple_async_result_complete (result); + g_object_unref (result); + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +void +mate_panel_applet_container_child_set (MatePanelAppletContainer *container, + const gchar *property_name, + const GVariant *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDBusProxy *proxy = container->priv->applet_proxy; + const AppletPropertyInfo *info; + GSimpleAsyncResult *result; + + if (!proxy) + return; + + info = mate_panel_applet_container_child_property_get_info (property_name); + if (!info) { + g_simple_async_report_error_in_idle (G_OBJECT (container), + callback, user_data, + MATE_PANEL_APPLET_CONTAINER_ERROR, + MATE_PANEL_APPLET_CONTAINER_INVALID_CHILD_PROPERTY, + "%s: Applet has no child property named `%s'", + G_STRLOC, property_name); + return; + } + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_child_set); + + if (cancellable) + g_object_ref (cancellable); + else + cancellable = g_cancellable_new (); + g_hash_table_insert (container->priv->pending_ops, result, cancellable); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + "org.freedesktop.DBus.Properties", + "Set", + g_variant_new ("(ssv)", + g_dbus_proxy_get_interface_name (proxy), + info->dbus_name, + value), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + set_applet_property_cb, + result); +} + +gboolean +mate_panel_applet_container_child_set_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_child_set); + + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +get_applet_property_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + MatePanelAppletContainer *container; + GVariant *retvals; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Error getting property: %s\n", error->message); + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + } else { + GVariant *value, *item; + + item = g_variant_get_child_value (retvals, 0); + value = g_variant_get_variant (item); + g_variant_unref (item); + g_simple_async_result_set_op_res_gpointer (result, value, + (GDestroyNotify) g_variant_unref); + g_variant_unref (retvals); + } + + container = MATE_PANEL_APPLET_CONTAINER (g_async_result_get_source_object (G_ASYNC_RESULT (result))); + g_hash_table_remove (container->priv->pending_ops, result); + g_simple_async_result_complete (result); + g_object_unref (result); + + /* g_async_result_get_source_object returns new ref */ + g_object_unref (container); +} + +void +mate_panel_applet_container_child_get (MatePanelAppletContainer *container, + const gchar *property_name, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GDBusProxy *proxy = container->priv->applet_proxy; + const AppletPropertyInfo *info; + GSimpleAsyncResult *result; + + if (!proxy) + return; + + info = mate_panel_applet_container_child_property_get_info (property_name); + if (!info) { + g_simple_async_report_error_in_idle (G_OBJECT (container), + callback, user_data, + MATE_PANEL_APPLET_CONTAINER_ERROR, + MATE_PANEL_APPLET_CONTAINER_INVALID_CHILD_PROPERTY, + "%s: Applet has no child property named `%s'", + G_STRLOC, property_name); + return; + } + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_child_get); + if (cancellable) + g_object_ref (cancellable); + else + cancellable = g_cancellable_new (); + g_hash_table_insert (container->priv->pending_ops, result, cancellable); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + g_dbus_proxy_get_interface_name (proxy), + info->dbus_name), + G_VARIANT_TYPE ("(v)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + get_applet_property_cb, + result); +} + +GVariant * +mate_panel_applet_container_child_get_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_child_get); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_variant_ref (g_simple_async_result_get_op_res_gpointer (simple)); +} + +static void +child_popup_menu_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); + GVariant *retvals; + GError *error = NULL; + + retvals = g_dbus_connection_call_finish (connection, res, &error); + if (!retvals) { + g_simple_async_result_set_from_error (result, error); + g_error_free (error); + } else { + g_variant_unref (retvals); + } + + g_simple_async_result_complete (result); + g_object_unref (result); +} + +void +mate_panel_applet_container_child_popup_menu (MatePanelAppletContainer *container, + guint button, + guint32 timestamp, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + GDBusProxy *proxy = container->priv->applet_proxy; + + if (!proxy) + return; + + result = g_simple_async_result_new (G_OBJECT (container), + callback, + user_data, + mate_panel_applet_container_child_popup_menu); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + MATE_PANEL_APPLET_INTERFACE, + "PopupMenu", + g_variant_new ("(uu)", button, timestamp), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + child_popup_menu_cb, + result); +} + +gboolean +mate_panel_applet_container_child_popup_menu_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == mate_panel_applet_container_child_popup_menu); + + return !g_simple_async_result_propagate_error (simple, error); +} diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applet-container.h b/mate-panel/libmate-panel-applet-private/mate-panel-applet-container.h new file mode 100644 index 00000000..4b1e316a --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applet-container.h @@ -0,0 +1,118 @@ +/* + * mate-panel-applet-container.c: a container for applets. + * + * Copyright (C) 2010 Carlos Garcia Campos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef __MATE_PANEL_APPLET_CONTAINER_H__ +#define __MATE_PANEL_APPLET_CONTAINER_H__ + +#include +#include +#include "panel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_APPLET_CONTAINER (mate_panel_applet_container_get_type ()) +#define MATE_PANEL_APPLET_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_APPLET_CONTAINER, MatePanelAppletContainer)) +#define MATE_PANEL_APPLET_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PANEL_TYPE_APPLET_CONTAINER, MatePanelAppletContainerClass)) +#define PANEL_IS_APPLET_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_APPLET_CONTAINER)) +#define PANEL_IS_APPLET_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_APPLET_CONTAINER)) +#define MATE_PANEL_APPLET_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_APPLET_CONTAINER, MatePanelAppletContainerClass)) + +#define MATE_PANEL_APPLET_CONTAINER_ERROR (mate_panel_applet_container_error_quark()) + +typedef enum { + MATE_PANEL_APPLET_CONTAINER_INVALID_APPLET, + MATE_PANEL_APPLET_CONTAINER_INVALID_CHILD_PROPERTY +} MatePanelAppletContainerError; + +typedef struct _MatePanelAppletContainer MatePanelAppletContainer; +typedef struct _MatePanelAppletContainerClass MatePanelAppletContainerClass; +typedef struct _MatePanelAppletContainerPrivate MatePanelAppletContainerPrivate; + +struct _MatePanelAppletContainer { + GtkEventBox parent; + + MatePanelAppletContainerPrivate *priv; +}; + +struct _MatePanelAppletContainerClass { + GtkEventBoxClass parent_class; + + /* Signals */ + void (*applet_broken) (MatePanelAppletContainer *container); + void (*applet_move) (MatePanelAppletContainer *container); + void (*applet_remove) (MatePanelAppletContainer *container); + void (*applet_lock) (MatePanelAppletContainer *container, + gboolean locked); + void (*child_property_changed) (MatePanelAppletContainer *container, + const gchar *property_name, + GVariant *value); +}; + +GType mate_panel_applet_container_get_type (void) G_GNUC_CONST; +GQuark mate_panel_applet_container_error_quark (void) G_GNUC_CONST; +GtkWidget *mate_panel_applet_container_new (void); + + +void mate_panel_applet_container_add (MatePanelAppletContainer *container, + const gchar *iid, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + GVariant *properties); +gboolean mate_panel_applet_container_add_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error); +void mate_panel_applet_container_child_popup_menu (MatePanelAppletContainer *container, + guint button, + guint32 timestamp, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mate_panel_applet_container_child_popup_menu_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error); + +void mate_panel_applet_container_child_set (MatePanelAppletContainer *container, + const gchar *property_name, + const GVariant *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mate_panel_applet_container_child_set_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error); +void mate_panel_applet_container_child_get (MatePanelAppletContainer *container, + const gchar *property_name, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GVariant *mate_panel_applet_container_child_get_finish (MatePanelAppletContainer *container, + GAsyncResult *result, + GError **error); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATE_PANEL_APPLET_CONTAINER_H__ */ diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.c b/mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.c new file mode 100644 index 00000000..b2e90e73 --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.c @@ -0,0 +1,468 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * mate-panel-applet-frame-dbus.c: panel side container for applets + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include + +#include +#include + +#include "mate-panel-applet-container.h" + +#include "mate-panel-applet-frame-dbus.h" + +G_DEFINE_TYPE (MatePanelAppletFrameDBus, + mate_panel_applet_frame_dbus, + PANEL_TYPE_APPLET_FRAME) + +struct _MatePanelAppletFrameDBusPrivate +{ + MatePanelAppletContainer *container; + GCancellable *bg_cancellable; +}; + +/* Keep in sync with mate-panel-applet.h. Uggh. */ +typedef enum { + APPLET_FLAGS_NONE = 0, + APPLET_EXPAND_MAJOR = 1 << 0, + APPLET_EXPAND_MINOR = 1 << 1, + APPLET_HAS_HANDLE = 1 << 2 +} MatePanelAppletFlags; + + +static guint +get_mate_panel_applet_orient (PanelOrientation orientation) +{ + /* For some reason libmate-panel-applet and panel use a different logic for + * orientation, so we need to convert it. We should fix this. */ + switch (orientation) { + case PANEL_ORIENTATION_TOP: + return 1; + case PANEL_ORIENTATION_BOTTOM: + return 0; + case PANEL_ORIENTATION_LEFT: + return 3; + case PANEL_ORIENTATION_RIGHT: + return 2; + default: + g_assert_not_reached (); + break; + } +} + +static void +mate_panel_applet_frame_dbus_update_flags (MatePanelAppletFrame *frame, + GVariant *value) +{ + guint32 flags; + gboolean major; + gboolean minor; + gboolean has_handle; + + flags = g_variant_get_uint32 (value); + + major = (flags & APPLET_EXPAND_MAJOR) != 0; + minor = (flags & APPLET_EXPAND_MINOR) != 0; + has_handle = (flags & APPLET_HAS_HANDLE) != 0; + + _mate_panel_applet_frame_update_flags (frame, major, minor, has_handle); +} + + +static void +mate_panel_applet_frame_dbus_get_flags_cb (MatePanelAppletContainer *container, + GAsyncResult *res, + MatePanelAppletFrame *frame) +{ + GVariant *value; + GError *error = NULL; + + value = mate_panel_applet_container_child_get_finish (container, res, &error); + if (!value) { + g_warning ("%s\n", error->message); + g_error_free (error); + return; + } + + mate_panel_applet_frame_dbus_update_flags (frame, value); + g_variant_unref (value); +} + +static void +mate_panel_applet_frame_dbus_get_size_hints_cb (MatePanelAppletContainer *container, + GAsyncResult *res, + MatePanelAppletFrame *frame) +{ + GVariant *value; + const gint *sz; + gint *size_hints = NULL; + gsize n_elements; + GError *error = NULL; + + value = mate_panel_applet_container_child_get_finish (container, res, &error); + if (!value) { + g_warning ("%s\n", error->message); + g_error_free (error); + return; + } + + sz = g_variant_get_fixed_array (value, &n_elements, sizeof (gint32)); + if (n_elements > 0) { + size_hints = g_new (gint32, n_elements); + memcpy (size_hints, sz, n_elements * sizeof (gint32)); + } + + _mate_panel_applet_frame_update_size_hints (frame, size_hints, n_elements); + g_variant_unref (value); +} + +static void +mate_panel_applet_frame_dbus_init_properties (MatePanelAppletFrame *frame) +{ + MatePanelAppletFrameDBus *dbus_frame = MATE_PANEL_APPLET_FRAME_DBUS (frame); + + mate_panel_applet_container_child_get (dbus_frame->priv->container, "flags", NULL, + (GAsyncReadyCallback) mate_panel_applet_frame_dbus_get_flags_cb, + frame); + mate_panel_applet_container_child_get (dbus_frame->priv->container, "size-hints", NULL, + (GAsyncReadyCallback) mate_panel_applet_frame_dbus_get_size_hints_cb, + frame); +} + +static void +mate_panel_applet_frame_dbus_sync_menu_state (MatePanelAppletFrame *frame, + gboolean movable, + gboolean removable, + gboolean lockable, + gboolean locked, + gboolean locked_down) +{ + MatePanelAppletFrameDBus *dbus_frame = MATE_PANEL_APPLET_FRAME_DBUS (frame); + + mate_panel_applet_container_child_set (dbus_frame->priv->container, + "locked", g_variant_new_boolean (lockable && locked), + NULL, NULL, NULL); + mate_panel_applet_container_child_set (dbus_frame->priv->container, + "locked-down", g_variant_new_boolean (locked_down), + NULL, NULL, NULL); +} + +static void +mate_panel_applet_frame_dbus_popup_menu (MatePanelAppletFrame *frame, + guint button, + guint32 timestamp) +{ + MatePanelAppletFrameDBus *dbus_frame = MATE_PANEL_APPLET_FRAME_DBUS (frame); + + mate_panel_applet_container_child_popup_menu (dbus_frame->priv->container, + button, timestamp, + NULL, NULL, NULL); +} + +static void +change_orientation_cb (MatePanelAppletContainer *container, + GAsyncResult *res, + MatePanelAppletFrame *frame) +{ + GError *error = NULL; + + if (!mate_panel_applet_container_child_set_finish (container, res, &error)) { + g_warning ("%s\n", error->message); + g_error_free (error); + + return; + } + + gtk_widget_queue_resize (GTK_WIDGET (frame)); +} + +static void +mate_panel_applet_frame_dbus_change_orientation (MatePanelAppletFrame *frame, + PanelOrientation orientation) +{ + MatePanelAppletFrameDBus *dbus_frame = MATE_PANEL_APPLET_FRAME_DBUS (frame); + + mate_panel_applet_container_child_set (dbus_frame->priv->container, + "orient", + g_variant_new_uint32 (get_mate_panel_applet_orient (orientation)), + NULL, + (GAsyncReadyCallback)change_orientation_cb, + frame); +} + +static void +mate_panel_applet_frame_dbus_change_size (MatePanelAppletFrame *frame, + guint size) +{ + MatePanelAppletFrameDBus *dbus_frame = MATE_PANEL_APPLET_FRAME_DBUS (frame); + + mate_panel_applet_container_child_set (dbus_frame->priv->container, + "size", g_variant_new_uint32 (size), + NULL, NULL, NULL); +} + +static void +container_child_background_set (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + MatePanelAppletContainer *container = MATE_PANEL_APPLET_CONTAINER (source_object); + MatePanelAppletFrameDBus *frame = MATE_PANEL_APPLET_FRAME_DBUS (user_data); + + mate_panel_applet_container_child_set_finish (container, res, NULL); + + if (frame->priv->bg_cancellable) + g_object_unref (frame->priv->bg_cancellable); + frame->priv->bg_cancellable = NULL; +} + +static void +mate_panel_applet_frame_dbus_change_background (MatePanelAppletFrame *frame, + PanelBackgroundType type) +{ + MatePanelAppletFrameDBus *dbus_frame = MATE_PANEL_APPLET_FRAME_DBUS (frame); + char *bg_str; + + bg_str = _mate_panel_applet_frame_get_background_string ( + frame, PANEL_WIDGET (gtk_widget_get_parent (GTK_WIDGET (frame))), type); + + if (bg_str != NULL) { + if (dbus_frame->priv->bg_cancellable) + g_cancellable_cancel (dbus_frame->priv->bg_cancellable); + dbus_frame->priv->bg_cancellable = g_cancellable_new (); + + mate_panel_applet_container_child_set (dbus_frame->priv->container, + "background", + g_variant_new_string (bg_str), + dbus_frame->priv->bg_cancellable, + container_child_background_set, + dbus_frame); + g_free (bg_str); + } +} + +static void +mate_panel_applet_frame_dbus_flags_changed (MatePanelAppletContainer *container, + const gchar *prop_name, + GVariant *value, + MatePanelAppletFrame *frame) +{ + mate_panel_applet_frame_dbus_update_flags (frame, value); +} + +static void +mate_panel_applet_frame_dbus_size_hints_changed (MatePanelAppletContainer *container, + const gchar *prop_name, + GVariant *value, + MatePanelAppletFrame *frame) +{ + const gint *sz; + gint *size_hints = NULL; + gsize n_elements; + + sz = g_variant_get_fixed_array (value, &n_elements, sizeof (gint32)); + if (n_elements > 0) { + size_hints = g_new (gint32, n_elements); + memcpy (size_hints, sz, n_elements * sizeof (gint32)); + } + + _mate_panel_applet_frame_update_size_hints (frame, size_hints, n_elements); +} + +static void +mate_panel_applet_frame_dbus_applet_broken (MatePanelAppletContainer *container, + MatePanelAppletFrame *frame) +{ + _mate_panel_applet_frame_applet_broken (frame); +} + +static void +mate_panel_applet_frame_dbus_applet_remove (MatePanelAppletContainer *container, + MatePanelAppletFrame *frame) +{ + _mate_panel_applet_frame_applet_remove (frame); +} + +static void +mate_panel_applet_frame_dbus_applet_move (MatePanelAppletContainer *container, + MatePanelAppletFrame *frame) +{ + _mate_panel_applet_frame_applet_move (frame); +} + +static void +mate_panel_applet_frame_dbus_applet_lock (MatePanelAppletContainer *container, + gboolean locked, + MatePanelAppletFrame *frame) +{ + _mate_panel_applet_frame_applet_lock (frame, locked); +} + +static void +mate_panel_applet_frame_dbus_finalize (GObject *object) +{ + MatePanelAppletFrameDBus *frame = MATE_PANEL_APPLET_FRAME_DBUS (object); + + if (frame->priv->bg_cancellable) + g_object_unref (frame->priv->bg_cancellable); + frame->priv->bg_cancellable = NULL; + + G_OBJECT_CLASS (mate_panel_applet_frame_dbus_parent_class)->finalize (object); +} + +static void +mate_panel_applet_frame_dbus_init (MatePanelAppletFrameDBus *frame) +{ + GtkWidget *container; + + frame->priv = G_TYPE_INSTANCE_GET_PRIVATE (frame, + PANEL_TYPE_APPLET_FRAME_DBUS, + MatePanelAppletFrameDBusPrivate); + + container = mate_panel_applet_container_new (); + gtk_widget_show (container); + gtk_container_add (GTK_CONTAINER (frame), container); + frame->priv->container = MATE_PANEL_APPLET_CONTAINER (container); + + g_signal_connect (container, "child-property-changed::flags", + G_CALLBACK (mate_panel_applet_frame_dbus_flags_changed), + frame); + g_signal_connect (container, "child-property-changed::size-hints", + G_CALLBACK (mate_panel_applet_frame_dbus_size_hints_changed), + frame); + g_signal_connect (container, "applet-broken", + G_CALLBACK (mate_panel_applet_frame_dbus_applet_broken), + frame); + g_signal_connect (container, "applet-remove", + G_CALLBACK (mate_panel_applet_frame_dbus_applet_remove), + frame); + g_signal_connect (container, "applet-move", + G_CALLBACK (mate_panel_applet_frame_dbus_applet_move), + frame); + g_signal_connect (container, "applet-lock", + G_CALLBACK (mate_panel_applet_frame_dbus_applet_lock), + frame); +} + +static void +mate_panel_applet_frame_dbus_class_init (MatePanelAppletFrameDBusClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + MatePanelAppletFrameClass *frame_class = MATE_PANEL_APPLET_FRAME_CLASS (class); + + gobject_class->finalize = mate_panel_applet_frame_dbus_finalize; + + frame_class->init_properties = mate_panel_applet_frame_dbus_init_properties; + frame_class->sync_menu_state = mate_panel_applet_frame_dbus_sync_menu_state; + frame_class->popup_menu = mate_panel_applet_frame_dbus_popup_menu; + frame_class->change_orientation = mate_panel_applet_frame_dbus_change_orientation; + frame_class->change_size = mate_panel_applet_frame_dbus_change_size; + frame_class->change_background = mate_panel_applet_frame_dbus_change_background; + + g_type_class_add_private (class, sizeof (MatePanelAppletFrameDBusPrivate)); +} + +static void +mate_panel_applet_frame_dbus_activated (MatePanelAppletContainer *container, + GAsyncResult *res, + MatePanelAppletFrame *frame) +{ + MatePanelAppletFrameActivating *frame_act; + GError *error = NULL; + + if (!mate_panel_applet_container_add_finish (container, res, &error)) + g_assert (error != NULL); + + frame_act = g_object_get_data (G_OBJECT (frame), "mate-panel-applet-frame-activating"); + g_object_set_data (G_OBJECT (frame), "mate-panel-applet-frame-activating", NULL); + + _mate_panel_applet_frame_activated (frame, frame_act, error); +} + +gboolean +mate_panel_applet_frame_dbus_load (const gchar *iid, + MatePanelAppletFrameActivating *frame_act) +{ + MatePanelAppletFrameDBus *dbus_frame; + MatePanelAppletFrame *frame; + GVariantBuilder builder; + gchar *conf_path; + gchar *background; + guint orient; + + g_return_val_if_fail (iid != NULL, FALSE); + g_return_val_if_fail (frame_act != NULL, FALSE); + + if (!mate_panel_applets_manager_factory_activate (iid)) + return FALSE; + + dbus_frame = g_object_new (PANEL_TYPE_APPLET_FRAME_DBUS, NULL); + frame = MATE_PANEL_APPLET_FRAME (dbus_frame); + _mate_panel_applet_frame_set_iid (frame, iid); + + orient = get_mate_panel_applet_orient (mate_panel_applet_frame_activating_get_orientation (frame_act)); + conf_path = mate_panel_applet_frame_activating_get_conf_path (frame_act); + /* we can't really get a background string at this point since we don't + * know the position of the applet */ + background = NULL; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", + "prefs-key", + g_variant_new_string (conf_path)); + g_variant_builder_add (&builder, "{sv}", + "orient", + g_variant_new_uint32 (orient)); + g_variant_builder_add (&builder, "{sv}", + "size", + g_variant_new_uint32 (mate_panel_applet_frame_activating_get_size (frame_act))); + g_variant_builder_add (&builder, "{sv}", + "locked", + g_variant_new_boolean (mate_panel_applet_frame_activating_get_locked (frame_act))); + g_variant_builder_add (&builder, "{sv}", + "locked-down", + g_variant_new_boolean (mate_panel_applet_frame_activating_get_locked_down (frame_act))); + if (background) { + g_variant_builder_add (&builder, "{sv}", + "background", + g_variant_new_string (background)); + } + + g_object_set_data (G_OBJECT (frame), "mate-panel-applet-frame-activating", frame_act); + + mate_panel_applet_container_add (dbus_frame->priv->container, + iid, NULL, + (GAsyncReadyCallback) mate_panel_applet_frame_dbus_activated, + frame, + g_variant_builder_end (&builder)); + + g_free (conf_path); + g_free (background); + + return TRUE; +} diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.h b/mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.h new file mode 100644 index 00000000..e42e792b --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applet-frame-dbus.h @@ -0,0 +1,65 @@ +/* + * mate-panel-applet-frame-dbus.h: panel side container for applets + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __MATE_PANEL_APPLET_FRAME_DBUS_H__ +#define __MATE_PANEL_APPLET_FRAME_DBUS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_APPLET_FRAME_DBUS (mate_panel_applet_frame_dbus_get_type ()) +#define MATE_PANEL_APPLET_FRAME_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_APPLET_FRAME_DBUS, MatePanelAppletFrameDBus)) +#define MATE_PANEL_APPLET_FRAME_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_APPLET_FRAME_DBUS, MatePanelAppletFrameDBusClass)) +#define PANEL_IS_APPLET_FRAME_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_APPLET_FRAME_DBUS)) +#define PANEL_IS_APPLET_FRAME_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_APPLET_FRAME_DBUS)) +#define MATE_PANEL_APPLET_FRAME_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_APPLET_FRAME_DBUS, MatePanelAppletFrameDBusClass)) + +typedef struct _MatePanelAppletFrameDBus MatePanelAppletFrameDBus; +typedef struct _MatePanelAppletFrameDBusClass MatePanelAppletFrameDBusClass; +typedef struct _MatePanelAppletFrameDBusPrivate MatePanelAppletFrameDBusPrivate; + +struct _MatePanelAppletFrameDBusClass { + MatePanelAppletFrameClass parent_class; +}; + +struct _MatePanelAppletFrameDBus{ + MatePanelAppletFrame parent; + + MatePanelAppletFrameDBusPrivate *priv; +}; + +GType mate_panel_applet_frame_dbus_get_type (void) G_GNUC_CONST; + +gboolean mate_panel_applet_frame_dbus_load (const gchar *iid, + MatePanelAppletFrameActivating *frame_act); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATE_PANEL_APPLET_FRAME_DBUS_H__ */ diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applet-mini.c b/mate-panel/libmate-panel-applet-private/mate-panel-applet-mini.c new file mode 100644 index 00000000..13112376 --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applet-mini.c @@ -0,0 +1,5 @@ +/* Symbols needed for libmate-panel-applet-private-mini, which is used by the test + * program */ +#include +gboolean mate_panel_applet_frame_dbus_load (const gchar *iid, gpointer frame_act); +gboolean mate_panel_applet_frame_dbus_load (const gchar *iid, gpointer frame_act) { return FALSE; } diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.c b/mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.c new file mode 100644 index 00000000..9e330f9e --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.c @@ -0,0 +1,604 @@ +/* + * mate-panel-applets-manager-dbus.c + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include +#include + +#include + +#include "mate-panel-applet-frame-dbus.h" + +#include "mate-panel-applets-manager-dbus.h" + +G_DEFINE_TYPE_WITH_CODE (MatePanelAppletsManagerDBus, + mate_panel_applets_manager_dbus, + PANEL_TYPE_APPLETS_MANAGER, + g_io_extension_point_implement (MATE_PANEL_APPLETS_MANAGER_EXTENSION_POINT_NAME, + g_define_type_id, + "dbus", + 10)) + +struct _MatePanelAppletsManagerDBusPrivate +{ + GHashTable *applet_factories; + GList *monitors; +}; + +typedef gint (* ActivateAppletFunc) (void); + +typedef struct _MatePanelAppletFactoryInfo { + gchar *id; + gchar *location; + gboolean in_process; + GModule *module; + ActivateAppletFunc activate_applet; + guint n_applets; + + gchar *srcdir; + + GList *applet_list; + gboolean has_old_ids; +} MatePanelAppletFactoryInfo; + +#define MATE_PANEL_APPLET_FACTORY_GROUP "Applet Factory" +#define MATE_PANEL_APPLETS_EXTENSION ".mate-panel-applet" + +static void +mate_panel_applet_factory_info_free (MatePanelAppletFactoryInfo *info) +{ + if (!info) + return; + + g_free (info->id); + g_free (info->location); + g_list_foreach (info->applet_list, + (GFunc) mate_panel_applet_info_free, + NULL); + g_list_free (info->applet_list); + info->applet_list = NULL; + g_free (info->srcdir); + + g_slice_free (MatePanelAppletFactoryInfo, info); +} + +static MatePanelAppletInfo * +_mate_panel_applets_manager_get_applet_info (GKeyFile *applet_file, + const gchar *group, + const gchar *factory_id) +{ + MatePanelAppletInfo *info; + char *iid; + char *name; + char *comment; + char *icon; + char **old_ids; + + iid = g_strdup_printf ("%s::%s", factory_id, group); + name = g_key_file_get_locale_string (applet_file, group, + "Name", NULL, NULL); + comment = g_key_file_get_locale_string (applet_file, group, + "Description", NULL, NULL); + icon = g_key_file_get_string (applet_file, group, "Icon", NULL); + /* MateComponent compatibility */ + old_ids = g_key_file_get_string_list (applet_file, group, + "MateComponentId", NULL, NULL); + + info = mate_panel_applet_info_new (iid, name, comment, icon, (const char **) old_ids); + + g_free (iid); + g_free (name); + g_free (comment); + g_free (icon); + g_strfreev (old_ids); + + return info; +} + +static MatePanelAppletFactoryInfo * +mate_panel_applets_manager_get_applet_factory_info_from_file (const gchar *filename) +{ + MatePanelAppletFactoryInfo *info; + GKeyFile *applet_file; + gchar **groups; + gsize n_groups; + gint i; + GError *error = NULL; + + applet_file = g_key_file_new (); + if (!g_key_file_load_from_file (applet_file, filename, G_KEY_FILE_NONE, &error)) { + g_warning ("Error opening panel applet file %s: %s", + filename, error->message); + g_error_free (error); + g_key_file_free (applet_file); + + return NULL; + } + + info = g_slice_new0 (MatePanelAppletFactoryInfo); + info->id = g_key_file_get_string (applet_file, MATE_PANEL_APPLET_FACTORY_GROUP, "Id", NULL); + if (!info->id) { + g_warning ("Bad panel applet file %s: Could not find 'Id' in group '%s'", + filename, MATE_PANEL_APPLET_FACTORY_GROUP); + mate_panel_applet_factory_info_free (info); + g_key_file_free (applet_file); + + return NULL; + } + + info->in_process = g_key_file_get_boolean (applet_file, MATE_PANEL_APPLET_FACTORY_GROUP, + "InProcess", NULL); + if (info->in_process) { + info->location = g_key_file_get_string (applet_file, MATE_PANEL_APPLET_FACTORY_GROUP, + "Location", NULL); + if (!info->location) { + g_warning ("Bad panel applet file %s: In-process applet without 'Location'", + filename); + mate_panel_applet_factory_info_free (info); + g_key_file_free (applet_file); + + return NULL; + } + } + + info->has_old_ids = FALSE; + + groups = g_key_file_get_groups (applet_file, &n_groups); + for (i = 0; i < n_groups; i++) { + MatePanelAppletInfo *ainfo; + + if (g_strcmp0 (groups[i], MATE_PANEL_APPLET_FACTORY_GROUP) == 0) + continue; + + ainfo = _mate_panel_applets_manager_get_applet_info (applet_file, + groups[i], info->id); + if (mate_panel_applet_info_get_old_ids (ainfo) != NULL) + info->has_old_ids = TRUE; + + info->applet_list = g_list_prepend (info->applet_list, ainfo); + } + g_strfreev (groups); + + g_key_file_free (applet_file); + + if (!info->applet_list) { + mate_panel_applet_factory_info_free (info); + return NULL; + } + + info->srcdir = g_path_get_dirname (filename); + + return info; +} + +static GSList * +mate_panel_applets_manager_get_applets_dirs (void) +{ + const gchar *dir = NULL; + gchar **paths; + guint i; + GSList *retval = NULL; + + dir = g_getenv ("MATE_PANEL_APPLETS_DIR"); + if (!dir || g_strcmp0 (dir, "") == 0) { + return g_slist_prepend (NULL, g_strdup (MATE_PANEL_APPLETS_DIR)); + } + + paths = g_strsplit (dir, ":", 0); + for (i = 0; paths[i]; i++) { + if (g_slist_find_custom (retval, paths[i], (GCompareFunc) g_strcmp0)) + continue; + retval = g_slist_prepend (retval, g_strdup (paths[i])); + } + g_strfreev (paths); + + return g_slist_reverse (retval); +} + +static void +applets_directory_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + MatePanelAppletsManagerDBus *manager = MATE_PANEL_APPLETS_MANAGER_DBUS (user_data); + + switch (event_type) { + case G_FILE_MONITOR_EVENT_CHANGED: + case G_FILE_MONITOR_EVENT_CREATED: { + MatePanelAppletFactoryInfo *info; + MatePanelAppletFactoryInfo *old_info; + gchar *filename; + GSList *dirs, *d; + + filename = g_file_get_path (file); + if (!g_str_has_suffix (filename, MATE_PANEL_APPLETS_EXTENSION)) { + g_free (filename); + return; + } + + info = mate_panel_applets_manager_get_applet_factory_info_from_file (filename); + g_free (filename); + + if (!info) + return; + + old_info = g_hash_table_lookup (manager->priv->applet_factories, info->id); + if (!old_info) { + /* New applet, just insert it */ + g_hash_table_insert (manager->priv->applet_factories, g_strdup (info->id), info); + return; + } + + /* Make sure we don't update an applet that has changed in + * another source dir unless it takes precedence over the + * current one */ + if (g_strcmp0 (info->srcdir, old_info->srcdir) == 0) { + g_hash_table_replace (manager->priv->applet_factories, g_strdup (info->id), info); + return; + } + + dirs = mate_panel_applets_manager_get_applets_dirs (); + + for (d = dirs; d; d = g_slist_next (d)) { + gchar *path = (gchar *) d->data; + + if (g_strcmp0 (path, old_info->srcdir) == 0) { + mate_panel_applet_factory_info_free (info); + break; + } else if (g_strcmp0 (path, info->srcdir) == 0) { + g_hash_table_replace (manager->priv->applet_factories, g_strdup (info->id), info); + break; + } + } + + g_slist_foreach (dirs, (GFunc) g_free, NULL); + g_slist_free (dirs); + } + break; + default: + /* Ignore any other change */ + break; + } +} + +static void +mate_panel_applets_manager_dbus_load_applet_infos (MatePanelAppletsManagerDBus *manager) +{ + GSList *dirs, *d; + GDir *dir; + const gchar *dirent; + GError *error = NULL; + + dirs = mate_panel_applets_manager_get_applets_dirs (); + for (d = dirs; d; d = g_slist_next (d)) { + GFileMonitor *monitor; + GFile *dir_file; + gchar *path = (gchar *) d->data; + + dir = g_dir_open (path, 0, &error); + if (!dir) { + g_warning ("%s", error->message); + g_error_free (error); + g_free (path); + + continue; + } + + /* Monitor dir */ + dir_file = g_file_new_for_path (path); + monitor = g_file_monitor_directory (dir_file, + G_FILE_MONITOR_NONE, + NULL, NULL); + if (monitor) { + g_signal_connect (monitor, "changed", + G_CALLBACK (applets_directory_changed), + manager); + manager->priv->monitors = g_list_prepend (manager->priv->monitors, monitor); + } + g_object_unref (dir_file); + + while ((dirent = g_dir_read_name (dir))) { + MatePanelAppletFactoryInfo *info; + gchar *file; + + if (!g_str_has_suffix (dirent, MATE_PANEL_APPLETS_EXTENSION)) + continue; + + file = g_build_filename (path, dirent, NULL); + info = mate_panel_applets_manager_get_applet_factory_info_from_file (file); + g_free (file); + + if (!info) + continue; + + if (g_hash_table_lookup (manager->priv->applet_factories, info->id)) { + mate_panel_applet_factory_info_free (info); + continue; + } + + g_hash_table_insert (manager->priv->applet_factories, g_strdup (info->id), info); + } + + g_dir_close (dir); + g_free (path); + } + + g_slist_free (dirs); +} + +static GList * +mate_panel_applets_manager_dbus_get_applets (MatePanelAppletsManager *manager) +{ + MatePanelAppletsManagerDBus *dbus_manager = MATE_PANEL_APPLETS_MANAGER_DBUS (manager); + + GHashTableIter iter; + gpointer key, value; + GList *retval = NULL; + + g_hash_table_iter_init (&iter, dbus_manager->priv->applet_factories); + while (g_hash_table_iter_next (&iter, &key, &value)) { + MatePanelAppletFactoryInfo *info; + + info = (MatePanelAppletFactoryInfo *) value; + retval = g_list_concat (retval, g_list_copy (info->applet_list)); + } + + return retval; +} + +static MatePanelAppletFactoryInfo * +get_applet_factory_info (MatePanelAppletsManager *manager, + const gchar *iid) +{ + MatePanelAppletsManagerDBus *dbus_manager = MATE_PANEL_APPLETS_MANAGER_DBUS (manager); + + MatePanelAppletFactoryInfo *info; + const gchar *sp; + gchar *factory_id; + + sp = g_strrstr (iid, "::"); + if (!sp) + return NULL; + + factory_id = g_strndup (iid, strlen (iid) - strlen (sp)); + info = g_hash_table_lookup (dbus_manager->priv->applet_factories, factory_id); + g_free (factory_id); + + return info; +} + +static gboolean +mate_panel_applets_manager_dbus_factory_activate (MatePanelAppletsManager *manager, + const gchar *iid) +{ + MatePanelAppletFactoryInfo *info; + ActivateAppletFunc activate_applet; + + info = get_applet_factory_info (manager, iid); + if (!info) + return FALSE; + + /* Out-of-process applets are activated by the session bus */ + if (!info->in_process) + return TRUE; + + if (info->module) { + if (info->n_applets == 0) { + if (info->activate_applet () != 0) { + g_warning ("Failed to reactivate factory %s\n", iid); + return FALSE; + } + } + info->n_applets++; + + return TRUE; + } + + info->module = g_module_open (info->location, G_MODULE_BIND_LAZY); + if (!info->module) { + /* FIXME: use a GError? */ + g_warning ("Failed to load applet %s: %s\n", + iid, g_module_error ()); + return FALSE; + } + + if (!g_module_symbol (info->module, "_mate_panel_applet_shlib_factory", (gpointer *) &activate_applet)) { + /* FIXME: use a GError? */ + g_warning ("Failed to load applet %s: %s\n", + iid, g_module_error ()); + g_module_close (info->module); + info->module = NULL; + + return FALSE; + } + + /* Activate the applet */ + if (activate_applet () != 0) { + /* FIXME: use a GError? */ + g_warning ("Failed to load applet %s\n", iid); + g_module_close (info->module); + info->module = NULL; + + return FALSE; + } + info->activate_applet = activate_applet; + + info->n_applets = 1; + + return TRUE; +} + +static gboolean +mate_panel_applets_manager_dbus_factory_deactivate (MatePanelAppletsManager *manager, + const gchar *iid) +{ + MatePanelAppletFactoryInfo *info; + + info = get_applet_factory_info (manager, iid); + if (!info) + return FALSE; + + /* Out-of-process applets are deactivated by the session bus */ + if (!info->in_process) + return TRUE; + + if (!info->module) + return TRUE; + + info->n_applets--; + if (info->n_applets == 0) { + /* FIXME: we should close the module here, however applet types + * are registered static */ +#if 0 + g_module_close (info->module); + info->module = NULL; +#endif + } + + return TRUE; +} + +static MatePanelAppletInfo * +mate_panel_applets_manager_dbus_get_applet_info (MatePanelAppletsManager *manager, + const gchar *iid) +{ + MatePanelAppletFactoryInfo *info; + GList *l; + + info = get_applet_factory_info (manager, iid); + if (!info) + return NULL; + + for (l = info->applet_list; l; l = g_list_next (l)) { + MatePanelAppletInfo *ainfo = (MatePanelAppletInfo *) l->data; + + if (g_strcmp0 (mate_panel_applet_info_get_iid (ainfo), iid) == 0) + return ainfo; + } + + return NULL; +} + +static MatePanelAppletInfo * +mate_panel_applets_manager_dbus_get_applet_info_from_old_id (MatePanelAppletsManager *manager, + const gchar *iid) +{ + MatePanelAppletsManagerDBus *dbus_manager = MATE_PANEL_APPLETS_MANAGER_DBUS (manager); + + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, dbus_manager->priv->applet_factories); + while (g_hash_table_iter_next (&iter, &key, &value)) { + MatePanelAppletFactoryInfo *info; + GList *l; + + info = (MatePanelAppletFactoryInfo *) value; + if (!info->has_old_ids) + continue; + + for (l = info->applet_list; l; l = g_list_next (l)) { + MatePanelAppletInfo *ainfo; + gint i = 0; + const gchar * const *old_ids; + + ainfo = (MatePanelAppletInfo *) l->data; + + old_ids = mate_panel_applet_info_get_old_ids (ainfo); + + if (old_ids == NULL) + continue; + + while (old_ids[i]) { + if (g_strcmp0 (old_ids[i], iid) == 0) + return ainfo; + i++; + } + } + } + + return NULL; +} + +static gboolean +mate_panel_applets_manager_dbus_load_applet (MatePanelAppletsManager *manager, + const gchar *iid, + MatePanelAppletFrameActivating *frame_act) +{ + return mate_panel_applet_frame_dbus_load (iid, frame_act); +} + +static void +mate_panel_applets_manager_dbus_finalize (GObject *object) +{ + MatePanelAppletsManagerDBus *manager = MATE_PANEL_APPLETS_MANAGER_DBUS (object); + + if (manager->priv->monitors) { + g_list_foreach (manager->priv->monitors, (GFunc) g_object_unref, NULL); + g_list_free (manager->priv->monitors); + manager->priv->monitors = NULL; + } + + if (manager->priv->applet_factories) { + g_hash_table_destroy (manager->priv->applet_factories); + manager->priv->applet_factories = NULL; + } + + G_OBJECT_CLASS (mate_panel_applets_manager_dbus_parent_class)->finalize (object); +} + +static void +mate_panel_applets_manager_dbus_init (MatePanelAppletsManagerDBus *manager) +{ + manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, + PANEL_TYPE_APPLETS_MANAGER_DBUS, + MatePanelAppletsManagerDBusPrivate); + + manager->priv->applet_factories = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) mate_panel_applet_factory_info_free); + + mate_panel_applets_manager_dbus_load_applet_infos (manager); +} + +static void +mate_panel_applets_manager_dbus_class_init (MatePanelAppletsManagerDBusClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + MatePanelAppletsManagerClass *manager_class = MATE_PANEL_APPLETS_MANAGER_CLASS (class); + + gobject_class->finalize = mate_panel_applets_manager_dbus_finalize; + + manager_class->get_applets = mate_panel_applets_manager_dbus_get_applets; + manager_class->factory_activate = mate_panel_applets_manager_dbus_factory_activate; + manager_class->factory_deactivate = mate_panel_applets_manager_dbus_factory_deactivate; + manager_class->get_applet_info = mate_panel_applets_manager_dbus_get_applet_info; + manager_class->get_applet_info_from_old_id = mate_panel_applets_manager_dbus_get_applet_info_from_old_id; + manager_class->load_applet = mate_panel_applets_manager_dbus_load_applet; + + g_type_class_add_private (class, sizeof (MatePanelAppletsManagerDBusPrivate)); +} diff --git a/mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.h b/mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.h new file mode 100644 index 00000000..808795be --- /dev/null +++ b/mate-panel/libmate-panel-applet-private/mate-panel-applets-manager-dbus.h @@ -0,0 +1,60 @@ +/* + * mate-panel-applets-manager-dbus.h + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __MATE_PANEL_APPLETS_MANAGER_DBUS_H__ +#define __MATE_PANEL_APPLETS_MANAGER_DBUS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_APPLETS_MANAGER_DBUS (mate_panel_applets_manager_dbus_get_type ()) +#define MATE_PANEL_APPLETS_MANAGER_DBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_APPLETS_MANAGER_DBUS, MatePanelAppletsManagerDBus)) +#define MATE_PANEL_APPLETS_MANAGER_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_APPLETS_MANAGER_DBUS, MatePanelAppletsManagerDBusClass)) +#define PANEL_IS_APPLETS_MANAGER_DBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_APPLETS_MANAGER_DBUS)) +#define PANEL_IS_APPLETS_MANAGER_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_APPLETS_MANAGER_DBUS)) +#define MATE_PANEL_APPLETS_MANAGER_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PANEL_TYPE_APPLETS_MANAGER_DBUS, MatePanelAppletsManagerDBusClass)) + +typedef struct _MatePanelAppletsManagerDBus MatePanelAppletsManagerDBus; +typedef struct _MatePanelAppletsManagerDBusClass MatePanelAppletsManagerDBusClass; +typedef struct _MatePanelAppletsManagerDBusPrivate MatePanelAppletsManagerDBusPrivate; + +struct _MatePanelAppletsManagerDBusClass { + MatePanelAppletsManagerClass parent_class; +}; + +struct _MatePanelAppletsManagerDBus { + MatePanelAppletsManager parent; + + /*< private > */ + MatePanelAppletsManagerDBusPrivate *priv; +}; + +GType mate_panel_applets_manager_dbus_get_type (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATE_PANEL_APPLETS_MANAGER_DBUS_H__ */ diff --git a/mate-panel/libpanel-util/Makefile.am b/mate-panel/libpanel-util/Makefile.am new file mode 100644 index 00000000..377e26e5 --- /dev/null +++ b/mate-panel/libpanel-util/Makefile.am @@ -0,0 +1,39 @@ +noinst_LTLIBRARIES = libpanel-util.la + +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + -I. \ + -I$(srcdir) \ + -I$(top_builddir)/mate-panel/libpanel-util \ + -DDATADIR=\""$(datadir)"\" \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) + +libpanel_util_la_SOURCES = \ + panel-cleanup.c \ + panel-cleanup.h \ + panel-dbus-service.c \ + panel-dbus-service.h \ + panel-error.c \ + panel-error.h \ + panel-glib.c \ + panel-glib.h \ + panel-gtk.c \ + panel-gtk.h \ + panel-icon-chooser.c \ + panel-icon-chooser.h \ + panel-keyfile.c \ + panel-keyfile.h \ + panel-launch.c \ + panel-launch.h \ + panel-list.c \ + panel-list.h \ + panel-session-manager.c \ + panel-session-manager.h \ + panel-show.c \ + panel-show.h \ + panel-xdg.c \ + panel-xdg.h + +-include $(top_srcdir)/git.mk diff --git a/mate-panel/libpanel-util/Makefile.in b/mate-panel/libpanel-util/Makefile.in new file mode 100644 index 00000000..05758f14 --- /dev/null +++ b/mate-panel/libpanel-util/Makefile.in @@ -0,0 +1,647 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = mate-panel/libpanel-util +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/d-type.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libpanel_util_la_LIBADD = +am_libpanel_util_la_OBJECTS = panel-cleanup.lo panel-dbus-service.lo \ + panel-error.lo panel-glib.lo panel-gtk.lo \ + panel-icon-chooser.lo panel-keyfile.lo panel-launch.lo \ + panel-list.lo panel-session-manager.lo panel-show.lo \ + panel-xdg.lo +libpanel_util_la_OBJECTS = $(am_libpanel_util_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libpanel_util_la_SOURCES) +DIST_SOURCES = $(libpanel_util_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLOCK_CFLAGS = @CLOCK_CFLAGS@ +CLOCK_EDS_ICONDIR = @CLOCK_EDS_ICONDIR@ +CLOCK_LIBS = @CLOCK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISABLE_DEPRECATED = @DISABLE_DEPRECATED@ +DISABLE_DEPRECATED_CFLAGS = @DISABLE_DEPRECATED_CFLAGS@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOC_USER_FORMATS = @DOC_USER_FORMATS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGG_SMCLIENT_CFLAGS = @EGG_SMCLIENT_CFLAGS@ +EGG_SMCLIENT_LIBS = @EGG_SMCLIENT_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FISH_CFLAGS = @FISH_CFLAGS@ +FISH_LIBS = @FISH_LIBS@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_QUERYMODULES = @GIO_QUERYMODULES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HELP_DIR = @HELP_DIR@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBMATE_PANEL_APPLET_CFLAGS = @LIBMATE_PANEL_APPLET_CFLAGS@ +LIBMATE_PANEL_APPLET_LIBS = @LIBMATE_PANEL_APPLET_LIBS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_CFLAGS@ +LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS = @LIBMATE_PANEL_APPLET_MATECOMPONENT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MATE_PANEL_APPLET_LT_VERSION = @LIB_MATE_PANEL_APPLET_LT_VERSION@ +LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION = @LIB_MATE_PANEL_APPLET_MATECOMPONENT_LT_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MATECOMPONENT_ACT_IDLDIR = @MATECOMPONENT_ACT_IDLDIR@ +MATECOMPONENT_CFLAGS = @MATECOMPONENT_CFLAGS@ +MATECOMPONENT_IDLDIR = @MATECOMPONENT_IDLDIR@ +MATECOMPONENT_LIBS = @MATECOMPONENT_LIBS@ +MATECONFTOOL = @MATECONFTOOL@ +MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@ +MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@ +MATECORBA_IDL = @MATECORBA_IDL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +NETWORK_MANAGER_CFLAGS = @NETWORK_MANAGER_CFLAGS@ +NETWORK_MANAGER_LIBS = @NETWORK_MANAGER_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOTIFICATION_AREA_CFLAGS = @NOTIFICATION_AREA_CFLAGS@ +NOTIFICATION_AREA_LIBS = @NOTIFICATION_AREA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OMF_DIR = @OMF_DIR@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANEL_CFLAGS = @PANEL_CFLAGS@ +PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE = @PANEL_INTLTOOL_MATE_PANEL_APPLET_RULE@ +PANEL_LIBS = @PANEL_LIBS@ +PANEL_MODULE_MATECOMPONENT_CFLAGS = @PANEL_MODULE_MATECOMPONENT_CFLAGS@ +PANEL_MODULE_MATECOMPONENT_LIBS = @PANEL_MODULE_MATECOMPONENT_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POFILES = @POFILES@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +REBUILD = @REBUILD@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TZ_CFLAGS = @TZ_CFLAGS@ +TZ_LIBS = @TZ_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WNCKLET_CFLAGS = @WNCKLET_CFLAGS@ +WNCKLET_LIBS = @WNCKLET_LIBS@ +XGETTEXT = @XGETTEXT@ +XMKMF = @XMKMF@ +XRANDR_CFLAGS = @XRANDR_CFLAGS@ +XRANDR_LIBS = @XRANDR_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +appletsdir = @appletsdir@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +modulesdir = @modulesdir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libpanel-util.la +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + -I. \ + -I$(srcdir) \ + -I$(top_builddir)/mate-panel/libpanel-util \ + -DDATADIR=\""$(datadir)"\" \ + $(DISABLE_DEPRECATED_CFLAGS) + +AM_CFLAGS = $(WARN_CFLAGS) +libpanel_util_la_SOURCES = \ + panel-cleanup.c \ + panel-cleanup.h \ + panel-dbus-service.c \ + panel-dbus-service.h \ + panel-error.c \ + panel-error.h \ + panel-glib.c \ + panel-glib.h \ + panel-gtk.c \ + panel-gtk.h \ + panel-icon-chooser.c \ + panel-icon-chooser.h \ + panel-keyfile.c \ + panel-keyfile.h \ + panel-launch.c \ + panel-launch.h \ + panel-list.c \ + panel-list.h \ + panel-session-manager.c \ + panel-session-manager.h \ + panel-show.c \ + panel-show.h \ + panel-xdg.c \ + panel-xdg.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu mate-panel/libpanel-util/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu mate-panel/libpanel-util/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libpanel-util.la: $(libpanel_util_la_OBJECTS) $(libpanel_util_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libpanel_util_la_OBJECTS) $(libpanel_util_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-cleanup.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-dbus-service.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-glib.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-gtk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-icon-chooser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-keyfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-launch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-session-manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-show.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel-xdg.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mate-panel/libpanel-util/panel-cleanup.c b/mate-panel/libpanel-util/panel-cleanup.c new file mode 100644 index 00000000..90b089da --- /dev/null +++ b/mate-panel/libpanel-util/panel-cleanup.c @@ -0,0 +1,110 @@ +/* + * panel-cleanup.c: utility to clean up things on exit + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include +#include + +#include "panel-cleanup.h" + +typedef struct { + PanelCleanFunc func; + gpointer data; +} PanelClean; + +static GSList *cleaner; + +void +panel_cleanup_do (void) +{ + GSList *l; + + if (!cleaner) + return; + + for (l = cleaner; l; l = l->next) { + PanelClean *clean; + + clean = l->data; + clean->func (clean->data); + g_slice_free (PanelClean, clean); + } + + g_slist_free (cleaner); + cleaner = NULL; +} + +void +panel_cleanup_register (PanelCleanFunc func, + gpointer data) +{ + PanelClean *clean; + + g_return_if_fail (func != NULL); + + clean = g_slice_new (PanelClean); + clean->func = func; + clean->data = data; + + cleaner = g_slist_prepend (cleaner, clean); +} + +void +panel_cleanup_unregister (PanelCleanFunc func, + gpointer data) +{ + GSList *l, *next; + PanelClean *clean; + + g_return_if_fail (func != NULL); + + if (!cleaner) + return; + + l = cleaner; + + do { + next = l->next; + + clean = l->data; + if (clean->func == func && clean->data == data) { + g_slice_free (PanelClean, clean); + cleaner = g_slist_delete_link (cleaner, l); + } + + l = next; + } while (l); +} + +void +panel_cleanup_unref_and_nullify (gpointer data) +{ + GObject **obj; + + g_return_if_fail (data != NULL); + + obj = data; + + g_object_unref (*obj); + *obj = NULL; +} diff --git a/mate-panel/libpanel-util/panel-cleanup.h b/mate-panel/libpanel-util/panel-cleanup.h new file mode 100644 index 00000000..3e5a27ab --- /dev/null +++ b/mate-panel/libpanel-util/panel-cleanup.h @@ -0,0 +1,51 @@ +/* + * panel-cleanup.h: utility to clean up things on exit + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_CLEANUP_H +#define PANEL_CLEANUP_H + +#include "glib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_CLEAN_FUNC(f) ((PanelCleanFunc) (f)) + +typedef void (*PanelCleanFunc) (gpointer data); + +void panel_cleanup_unref_and_nullify (gpointer data); + +void panel_cleanup_do (void); + +void panel_cleanup_register (PanelCleanFunc func, + gpointer data); +void panel_cleanup_unregister (PanelCleanFunc func, + gpointer data); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_CLEANUP_H */ diff --git a/mate-panel/libpanel-util/panel-dbus-service.c b/mate-panel/libpanel-util/panel-dbus-service.c new file mode 100644 index 00000000..740d9212 --- /dev/null +++ b/mate-panel/libpanel-util/panel-dbus-service.c @@ -0,0 +1,307 @@ +/* + * panel-dbus-service.c: a simple base object to use a DBus service. Only + * useful when subclassed. + * + * Copyright (C) 2008 Novell, Inc. + * + * Based on code from panel-power-manager.c: + * Copyright (C) 2006 Ray Strode + * (not sure the copyright header was complete) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include +#include + +#include + +#include "panel-dbus-service.h" + +struct _PanelDBusServicePrivate { + DBusGConnection *dbus_connection; + DBusGProxy *bus_proxy; + DBusGProxy *service_proxy; + guint32 is_connected : 1; + + const char *service_name; + const char *service_path; + const char *service_interface; +}; + +static void panel_dbus_service_finalize (GObject *object); +static void panel_dbus_service_class_install_properties (PanelDBusServiceClass *service_class); + +static void panel_dbus_service_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +enum { + PROP_0 = 0, + PROP_IS_CONNECTED +}; + +G_DEFINE_TYPE (PanelDBusService, panel_dbus_service, G_TYPE_OBJECT); + +static void +panel_dbus_service_class_init (PanelDBusServiceClass *service_class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (service_class); + + object_class->finalize = panel_dbus_service_finalize; + + panel_dbus_service_class_install_properties (service_class); + + g_type_class_add_private (service_class, + sizeof (PanelDBusServicePrivate)); +} + +static void +panel_dbus_service_class_install_properties (PanelDBusServiceClass *service_class) +{ + GObjectClass *object_class; + GParamSpec *param_spec; + + object_class = G_OBJECT_CLASS (service_class); + object_class->get_property = panel_dbus_service_get_property; + + param_spec = g_param_spec_boolean ("is-connected", + "Is connected", + "Whether the panel is connected to " + "a DBus service", + FALSE, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_IS_CONNECTED, + param_spec); +} + +static void +panel_dbus_service_init (PanelDBusService *service) +{ + service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, + PANEL_TYPE_DBUS_SERVICE, + PanelDBusServicePrivate); + + service->priv->dbus_connection = NULL; + service->priv->bus_proxy = NULL; + service->priv->service_proxy = NULL; + service->priv->is_connected = FALSE; + + service->priv->service_name = NULL; + service->priv->service_path = NULL; + service->priv->service_interface = NULL; +} + +static void +panel_dbus_service_finalize (GObject *object) +{ + PanelDBusService *service; + + service = PANEL_DBUS_SERVICE (object); + + if (service->priv->dbus_connection != NULL) { + dbus_g_connection_unref (service->priv->dbus_connection); + service->priv->dbus_connection = NULL; + } + + if (service->priv->bus_proxy != NULL) { + g_object_unref (service->priv->bus_proxy); + service->priv->bus_proxy = NULL; + } + + if (service->priv->service_proxy != NULL) { + g_object_unref (service->priv->service_proxy); + service->priv->service_proxy = NULL; + } + + G_OBJECT_CLASS (panel_dbus_service_parent_class)->finalize (object); +} + +static void +panel_dbus_service_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelDBusService *service; + + service = PANEL_DBUS_SERVICE (object); + + switch (prop_id) { + case PROP_IS_CONNECTED: + g_value_set_boolean (value, + service->priv->is_connected); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + pspec); + } +} + +static void +panel_dbus_service_on_name_owner_changed (DBusGProxy *bus_proxy, + const char *name, + const char *prev_owner, + const char *new_owner, + PanelDBusService *service) +{ + g_assert (service->priv->service_name != NULL); + + if (name && strcmp (name, service->priv->service_name) != 0) + return; + + if (service->priv->service_proxy != NULL) { + g_object_unref (service->priv->service_proxy); + service->priv->service_proxy = NULL; + } + + panel_dbus_service_ensure_connection (service, NULL); +} + +gboolean +panel_dbus_service_ensure_connection (PanelDBusService *service, + GError **error) +{ + GError *connection_error; + gboolean is_connected; + + g_return_val_if_fail (PANEL_IS_DBUS_SERVICE (service), FALSE); + + if (!service->priv->service_name || + !service->priv->service_path || + !service->priv->service_interface) + return FALSE; + + connection_error = NULL; + if (service->priv->dbus_connection == NULL) { + service->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, + &connection_error); + + if (service->priv->dbus_connection == NULL) { + g_propagate_error (error, connection_error); + is_connected = FALSE; + goto out; + } + } + + if (service->priv->bus_proxy == NULL) { + service->priv->bus_proxy = + dbus_g_proxy_new_for_name_owner (service->priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + &connection_error); + + if (service->priv->bus_proxy == NULL) { + g_propagate_error (error, connection_error); + is_connected = FALSE; + goto out; + } + + dbus_g_proxy_add_signal (service->priv->bus_proxy, + "NameOwnerChanged", + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (service->priv->bus_proxy, + "NameOwnerChanged", + G_CALLBACK (panel_dbus_service_on_name_owner_changed), + service, NULL); + } + + if (service->priv->service_proxy == NULL) { + service->priv->service_proxy = + dbus_g_proxy_new_for_name_owner ( + service->priv->dbus_connection, + service->priv->service_name, + service->priv->service_path, + service->priv->service_interface, + &connection_error); + + if (service->priv->service_proxy == NULL) { + g_propagate_error (error, connection_error); + is_connected = FALSE; + goto out; + } + } + is_connected = TRUE; + +out: + if (service->priv->is_connected != is_connected) { + service->priv->is_connected = is_connected; + g_object_notify (G_OBJECT (service), "is-connected"); + } + + if (!is_connected) { + if (service->priv->dbus_connection == NULL) { + if (service->priv->bus_proxy != NULL) { + g_object_unref (service->priv->bus_proxy); + service->priv->bus_proxy = NULL; + } + + if (service->priv->service_proxy != NULL) { + g_object_unref (service->priv->service_proxy); + service->priv->service_proxy = NULL; + } + } else if (service->priv->bus_proxy == NULL) { + if (service->priv->service_proxy != NULL) { + g_object_unref (service->priv->service_proxy); + service->priv->service_proxy = NULL; + } + } + } + + return is_connected; +} + +void +panel_dbus_service_define_service (PanelDBusService *service, + const char *name, + const char *path, + const char *interface) +{ + g_return_if_fail (PANEL_IS_DBUS_SERVICE (service)); + + g_assert (name != NULL); + g_assert (path != NULL); + g_assert (interface != NULL); + g_assert (service->priv->service_name == NULL); + g_assert (service->priv->service_path == NULL); + g_assert (service->priv->service_interface == NULL); + + service->priv->service_name = name; + service->priv->service_path = path; + service->priv->service_interface = interface; +} + +DBusGProxy * +panel_dbus_service_get_proxy (PanelDBusService *service) +{ + g_return_val_if_fail (PANEL_IS_DBUS_SERVICE (service), NULL); + + return service->priv->service_proxy; +} diff --git a/mate-panel/libpanel-util/panel-dbus-service.h b/mate-panel/libpanel-util/panel-dbus-service.h new file mode 100644 index 00000000..bfd1830f --- /dev/null +++ b/mate-panel/libpanel-util/panel-dbus-service.h @@ -0,0 +1,78 @@ +/* + * panel-dbus-service.h: a simple base object to use a DBus service. Only + * useful when subclassed. + * + * Copyright (C) 2008 Novell, Inc. + * + * Based on code from panel-power-manager.h: + * Copyright (C) 2006 Ray Strode + * (not sure the copyright header was complete) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_DBUS_SERVICE_H +#define PANEL_DBUS_SERVICE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_DBUS_SERVICE (panel_dbus_service_get_type ()) +#define PANEL_DBUS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_DBUS_SERVICE, PanelDBusService)) +#define PANEL_DBUS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_DBUS_SERVICE, PanelDBusServiceClass)) +#define PANEL_IS_DBUS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_DBUS_SERVICE)) +#define PANEL_IS_DBUS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_DBUS_SERVICE)) +#define PANEL_DBUS_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PANEL_TYPE_DBUS_SERVICE, PanelDBusServiceClass)) + +typedef struct _PanelDBusService PanelDBusService; +typedef struct _PanelDBusServiceClass PanelDBusServiceClass; +typedef struct _PanelDBusServicePrivate PanelDBusServicePrivate; + +struct _PanelDBusService { + GObject parent; + + /*< private > */ + PanelDBusServicePrivate *priv; +}; + +struct _PanelDBusServiceClass { + GObjectClass parent_class; +}; + +GType panel_dbus_service_get_type (void); + +void panel_dbus_service_define_service (PanelDBusService *service, + const char *name, + const char *path, + const char *interface); + +gboolean panel_dbus_service_ensure_connection (PanelDBusService *service, + GError **error); + +DBusGProxy *panel_dbus_service_get_proxy (PanelDBusService *service); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_DBUS_SERVICE_H */ diff --git a/mate-panel/libpanel-util/panel-error.c b/mate-panel/libpanel-util/panel-error.c new file mode 100644 index 00000000..de5c9704 --- /dev/null +++ b/mate-panel/libpanel-util/panel-error.c @@ -0,0 +1,96 @@ +/* + * panel-error.c: an easy-to-use error dialog + * + * Copyright (C) 2008 Novell, Inc. + * + * Originally based on code from panel-util.c (there was no relevant copyright + * header at the time). + * + * Originally based on code from panel-util.c (there was no relevant copyright + * header at the time), but the code was: + * Copyright (C) Novell, Inc. (for the panel_g_utf8_strstrcase() code) + * Copyright (C) Dennis Cranston (for the panel_g_lookup_in_data_dirs() code) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include + +#include "panel-error.h" + +GtkWidget * +panel_error_dialog (GtkWindow *parent, + GdkScreen *screen, + const char *dialog_class, + gboolean auto_destroy, + const char *primary_text, + const char *secondary_text) +{ + GtkWidget *dialog; + char *freeme; + + freeme = NULL; + + if (primary_text == NULL) { + g_warning ("NULL dialog"); + /* No need to translate this, this should NEVER happen */ + freeme = g_strdup_printf ("Error with displaying error " + "for dialog of class %s", + dialog_class); + primary_text = freeme; + } + + dialog = gtk_message_dialog_new (parent, 0, GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, "%s", primary_text); + if (secondary_text != NULL) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", secondary_text); + + /* FIXME: we're losing this feature + gtk_widget_add_events (dialog, GDK_KEY_PRESS_MASK); + g_signal_connect (dialog, "event", + G_CALLBACK (panel_dialog_window_event), NULL); + */ + + if (screen) + gtk_window_set_screen (GTK_WINDOW (dialog), screen); + + if (!parent) { + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE); + /* FIXME: We need a title in this case, but we don't know what + * the format should be. Let's put something simple until + * the following bug gets fixed: + * http://bugzilla.gnome.org/show_bug.cgi?id=165132 */ + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + } + + gtk_widget_show_all (dialog); + + if (auto_destroy) + g_signal_connect_swapped (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), + G_OBJECT (dialog)); + + if (freeme) + g_free (freeme); + + return dialog; +} diff --git a/mate-panel/libpanel-util/panel-error.h b/mate-panel/libpanel-util/panel-error.h new file mode 100644 index 00000000..314acb08 --- /dev/null +++ b/mate-panel/libpanel-util/panel-error.h @@ -0,0 +1,49 @@ +/* + * panel-error.h: an easy-to-use error dialog + * + * Copyright (C) 2008 Novell, Inc. + * + * Originally based on code from panel-util.h (there was no relevant copyright + * header at the time). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_ERROR_H +#define PANEL_ERROR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +GtkWidget *panel_error_dialog (GtkWindow *parent, + GdkScreen *screen, + const char *dialog_class, + gboolean auto_destroy, + const char *primary_text, + const char *secondary_text); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_ERROR_H */ diff --git a/mate-panel/libpanel-util/panel-glib.c b/mate-panel/libpanel-util/panel-glib.c new file mode 100644 index 00000000..a728f25d --- /dev/null +++ b/mate-panel/libpanel-util/panel-glib.c @@ -0,0 +1,164 @@ +/* + * panel-glib.c: various small extensions to glib + * + * Copyright (C) 2008 Novell, Inc. + * + * Originally based on code from panel-util.c (there was no relevant copyright + * header at the time), but the code was: + * Copyright (C) Novell, Inc. (for the panel_g_utf8_strstrcase() code) + * Copyright (C) Dennis Cranston (for the panel_g_lookup_in_data_dirs() code) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include + +#include "panel-glib.h" + +typedef char * (*LookupInDir) (const char *basename, const char *dir); + +static char * +_lookup_in_dir (const char *basename, + const char *dir) +{ + char *path; + + path = g_build_filename (dir, basename, NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_free (path); + return NULL; + } + + return path; +} + +static char * +_lookup_in_applications_subdir (const char *basename, + const char *dir) +{ + char *path; + + path = g_build_filename (dir, "applications", basename, NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_free (path); + return NULL; + } + + return path; +} + +static char * +_panel_g_lookup_in_data_dirs_internal (const char *basename, + LookupInDir lookup) +{ + const char * const *system_data_dirs; + const char *user_data_dir; + char *retval; + int i; + + user_data_dir = g_get_user_data_dir (); + system_data_dirs = g_get_system_data_dirs (); + + if ((retval = lookup (basename, user_data_dir))) + return retval; + + for (i = 0; system_data_dirs[i]; i++) + if ((retval = lookup (basename, system_data_dirs[i]))) + return retval; + + return NULL; +} + +char * +panel_g_lookup_in_data_dirs (const char *basename) +{ + return _panel_g_lookup_in_data_dirs_internal (basename, + _lookup_in_dir); +} + +char * +panel_g_lookup_in_applications_dirs (const char *basename) +{ + return _panel_g_lookup_in_data_dirs_internal (basename, + _lookup_in_applications_subdir); +} + +/* Copied from evolution-data-server/libedataserver/e-util.c: + * e_util_unicode_get_utf8() */ +static char * +_unicode_get_utf8 (const char *text, gunichar *out) +{ + *out = g_utf8_get_char (text); + return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text); +} + +/* Copied from evolution-data-server/libedataserver/e-util.c: + * e_util_utf8_strstrcase() */ +const char * +panel_g_utf8_strstrcase (const char *haystack, const char *needle) +{ + gunichar *nuni; + gunichar unival; + gint nlen; + const char *o, *p; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + if (strlen (haystack) == 0) return NULL; + + nuni = g_alloca (sizeof (gunichar) * strlen (needle)); + + nlen = 0; + for (p = _unicode_get_utf8 (needle, &unival); + p && unival; + p = _unicode_get_utf8 (p, &unival)) { + nuni[nlen++] = g_unichar_tolower (unival); + } + /* NULL means there was illegal utf-8 sequence */ + if (!p) return NULL; + + o = haystack; + for (p = _unicode_get_utf8 (o, &unival); + p && unival; + p = _unicode_get_utf8 (p, &unival)) { + gint sc; + sc = g_unichar_tolower (unival); + /* We have valid stripped char */ + if (sc == nuni[0]) { + const char *q = p; + gint npos = 1; + while (npos < nlen) { + q = _unicode_get_utf8 (q, &unival); + if (!q || !unival) return NULL; + sc = g_unichar_tolower (unival); + if (sc != nuni[npos]) break; + npos++; + } + if (npos == nlen) { + return o; + } + } + o = p; + } + + return NULL; +} diff --git a/mate-panel/libpanel-util/panel-glib.h b/mate-panel/libpanel-util/panel-glib.h new file mode 100644 index 00000000..6b7b4878 --- /dev/null +++ b/mate-panel/libpanel-util/panel-glib.h @@ -0,0 +1,46 @@ +/* + * panel-glib.h: various small extensions to glib + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_GLIB_H +#define PANEL_GLIB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_GLIB_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') + +char *panel_g_lookup_in_data_dirs (const char *basename); +char *panel_g_lookup_in_applications_dirs (const char *basename); + +const char *panel_g_utf8_strstrcase (const char *haystack, + const char *needle); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_GLIB_H */ diff --git a/mate-panel/libpanel-util/panel-gtk.c b/mate-panel/libpanel-util/panel-gtk.c new file mode 100644 index 00000000..097367fb --- /dev/null +++ b/mate-panel/libpanel-util/panel-gtk.c @@ -0,0 +1,83 @@ +/* + * panel-gtk.c: various small extensions to gtk+ + * + * Copyright (C) 2010 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include "panel-gtk.h" + +/* + * Originally based on code from panel-properties-dialog.c. This part of the + * code was: + * Copyright (C) 2005 Vincent Untz + */ + +static void +panel_gtk_file_chooser_preview_update (GtkFileChooser *chooser, + gpointer data) +{ + GtkWidget *preview; + char *filename; + GdkPixbuf *pixbuf; + gboolean have_preview; + + preview = GTK_WIDGET (data); + filename = gtk_file_chooser_get_preview_filename (chooser); + + if (filename == NULL) + return; + + pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL); + have_preview = (pixbuf != NULL); + g_free (filename); + + gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); + if (pixbuf) + g_object_unref (pixbuf); + + gtk_file_chooser_set_preview_widget_active (chooser, + have_preview); +} + +void +panel_gtk_file_chooser_add_image_preview (GtkFileChooser *chooser) +{ + GtkFileFilter *filter; + GtkWidget *chooser_preview; + + g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser)); + + filter = gtk_file_filter_new (); + gtk_file_filter_add_pixbuf_formats (filter); + gtk_file_chooser_set_filter (chooser, filter); + + chooser_preview = gtk_image_new (); + gtk_file_chooser_set_preview_widget (chooser, chooser_preview); + g_signal_connect (chooser, "update-preview", + G_CALLBACK (panel_gtk_file_chooser_preview_update), + chooser_preview); +} + +/* + * End of code coming from panel-properties-dialog.c + */ diff --git a/mate-panel/libpanel-util/panel-gtk.h b/mate-panel/libpanel-util/panel-gtk.h new file mode 100644 index 00000000..282fb82f --- /dev/null +++ b/mate-panel/libpanel-util/panel-gtk.h @@ -0,0 +1,42 @@ +/* + * panel-gtk.h: various small extensions to gtk+ + * + * Copyright (C) 2009-2010 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_GTK_H +#define PANEL_GTK_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_GTK_BUILDER_GET(builder, name) GTK_WIDGET (gtk_builder_get_object (builder, name)) + +void panel_gtk_file_chooser_add_image_preview (GtkFileChooser *chooser); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_GTK_H */ diff --git a/mate-panel/libpanel-util/panel-icon-chooser.c b/mate-panel/libpanel-util/panel-icon-chooser.c new file mode 100644 index 00000000..07d14641 --- /dev/null +++ b/mate-panel/libpanel-util/panel-icon-chooser.c @@ -0,0 +1,555 @@ +/* + * panel-icon-chooser.c: An icon chooser widget + * + * Copyright (C) 2010 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include +#include + +#include "panel-gtk.h" +#include "panel-xdg.h" + +#include "panel-icon-chooser.h" + +#define PANEL_ICON_CHOOSER_ICON_SIZE GTK_ICON_SIZE_DIALOG + +struct _PanelIconChooserPrivate +{ + char *fallback_icon_name; + char *icon; + + char *icon_theme_dir; + + GtkWidget *image; + + GtkWidget *filechooser; +}; + +enum { + CHANGED, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_FALLBACK_ICON, + PROP_ICON +}; + +static guint panel_icon_chooser_signals[LAST_SIGNAL] = { 0 }; + +#define PANEL_ICON_CHOOSER_GET_PRIVATE(o) (PANEL_ICON_CHOOSER (o)->priv) + +G_DEFINE_TYPE (PanelIconChooser, panel_icon_chooser, GTK_TYPE_BUTTON) + +static void _panel_icon_chooser_clicked (GtkButton *button); +static void _panel_icon_chooser_style_set (GtkWidget *widget, + GtkStyle *prev_style); +static void _panel_icon_chooser_screen_changed (GtkWidget *widget, + GdkScreen *prev_screen); + +/* gobject stuff */ + +static GObject * +panel_icon_chooser_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + PanelIconChooser *chooser; + + obj = G_OBJECT_CLASS (panel_icon_chooser_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + + chooser = PANEL_ICON_CHOOSER (obj); + gtk_container_add (GTK_CONTAINER (chooser), chooser->priv->image); + gtk_widget_show (chooser->priv->image); + + return obj; +} + +static void +panel_icon_chooser_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelIconChooser *chooser; + + g_return_if_fail (PANEL_IS_ICON_CHOOSER (object)); + + chooser = PANEL_ICON_CHOOSER (object); + + switch (prop_id) { + case PROP_FALLBACK_ICON: + g_value_set_string (value, panel_icon_chooser_get_fallback_icon_name (chooser)); + break; + case PROP_ICON: + g_value_set_string (value, panel_icon_chooser_get_icon (chooser)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_icon_chooser_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PanelIconChooser *chooser; + + g_return_if_fail (PANEL_IS_ICON_CHOOSER (object)); + + chooser = PANEL_ICON_CHOOSER (object); + + switch (prop_id) { + case PROP_FALLBACK_ICON: + panel_icon_chooser_set_fallback_icon_name (chooser, + g_value_get_string (value)); + break; + case PROP_ICON: + panel_icon_chooser_set_icon (chooser, + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_icon_chooser_destroy (GtkObject *object) +{ + PanelIconChooser *chooser; + + chooser = PANEL_ICON_CHOOSER (object); + + if (chooser->priv->filechooser) { + gtk_widget_destroy (chooser->priv->filechooser); + chooser->priv->filechooser = NULL; + } + + /* remember, destroy can be run multiple times! */ + + if (chooser->priv->fallback_icon_name != NULL) + g_free (chooser->priv->fallback_icon_name); + chooser->priv->fallback_icon_name = NULL; + + if (chooser->priv->icon != NULL) + g_free (chooser->priv->icon); + chooser->priv->icon = NULL; + + if (chooser->priv->icon_theme_dir != NULL) + g_free (chooser->priv->icon_theme_dir); + chooser->priv->icon_theme_dir = NULL; + + GTK_OBJECT_CLASS (panel_icon_chooser_parent_class)->destroy (object); +} + +static void +panel_icon_chooser_class_init (PanelIconChooserClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (class); + GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (class); + GtkButtonClass *gtkbutton_class = GTK_BUTTON_CLASS (class); + + gobject_class->constructor = panel_icon_chooser_constructor; + gobject_class->get_property = panel_icon_chooser_get_property; + gobject_class->set_property = panel_icon_chooser_set_property; + + gtkobject_class->destroy = panel_icon_chooser_destroy; + + gtkwidget_class->style_set = _panel_icon_chooser_style_set; + gtkwidget_class->screen_changed = _panel_icon_chooser_screen_changed; + + gtkbutton_class->clicked = _panel_icon_chooser_clicked; + + g_type_class_add_private (class, + sizeof (PanelIconChooserPrivate)); + + panel_icon_chooser_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelIconChooserClass, + changed), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + g_object_class_install_property ( + gobject_class, + PROP_FALLBACK_ICON, + g_param_spec_string ("fallback-icon-name", + "Fallback Icon Name", + "Icon name of the icon displayed (but not returned) if the current icon does not exit", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_ICON, + g_param_spec_string ("icon", + "Icon", + "Icon name or path", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +} + +static void +panel_icon_chooser_init (PanelIconChooser *chooser) +{ + PanelIconChooserPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser, + PANEL_TYPE_ICON_CHOOSER, + PanelIconChooserPrivate); + + chooser->priv = priv; + + priv->fallback_icon_name = g_strdup ("gtk-missing-image"); + priv->icon = NULL; + priv->icon_theme_dir = NULL; + + priv->image = gtk_image_new_from_icon_name (priv->fallback_icon_name, + PANEL_ICON_CHOOSER_ICON_SIZE); + + priv->filechooser = NULL; +} + +/* internal code */ + +static void +_panel_icon_chooser_update (PanelIconChooser *chooser) +{ + if (!chooser->priv->icon) { + gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image), + chooser->priv->fallback_icon_name, + PANEL_ICON_CHOOSER_ICON_SIZE); + + } else if (g_path_is_absolute (chooser->priv->icon)) { + gboolean fallback; + + fallback = TRUE; + + if (g_file_test (chooser->priv->icon, G_FILE_TEST_EXISTS)) { + /* we pass via a pixbuf to force the size we want */ + GdkPixbuf *pixbuf; + int width, height; + + gtk_icon_size_lookup (PANEL_ICON_CHOOSER_ICON_SIZE, + &width, &height); + pixbuf = gdk_pixbuf_new_from_file_at_size (chooser->priv->icon, + width, height, + NULL); + + if (pixbuf) { + gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), + pixbuf); + g_object_unref (pixbuf); + fallback = FALSE; + } + } + + if (fallback) { + gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image), + chooser->priv->fallback_icon_name, + PANEL_ICON_CHOOSER_ICON_SIZE); + } + + } else { + /* Note: using GThemedIcon doesn't work well, see bug #606752. + * When we'll remove the alternative code, we won't need the + * style_set/screen_changed handlers anymore. + */ +#if 0 + GIcon *icon; + char *names[2]; + + names[0] = panel_xdg_icon_remove_extension (chooser->priv->icon); + names[1] = chooser->priv->fallback_icon_name; + icon = g_themed_icon_new_from_names (names, 2); + + gtk_image_set_from_gicon (GTK_IMAGE (chooser->priv->image), + icon, + PANEL_ICON_CHOOSER_ICON_SIZE); + + g_free (names[0]); +#endif + GtkIconTheme *icon_theme; + const char *icon; + char *no_ext; + + no_ext = panel_xdg_icon_remove_extension (chooser->priv->icon); + + icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (chooser))); + if (gtk_icon_theme_has_icon (icon_theme, no_ext)) + icon = no_ext; + else + icon = chooser->priv->fallback_icon_name; + + gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image), + icon, + PANEL_ICON_CHOOSER_ICON_SIZE); + + g_free (no_ext); + } +} + +static char * +_panel_icon_chooser_find_icon_from_path (PanelIconChooser *chooser, + const char *path) +{ + GdkScreen *screen; + char *icon; + + screen = gtk_widget_get_screen (GTK_WIDGET (chooser)); + + icon = panel_xdg_icon_name_from_icon_path (path, screen); + if (!icon) + icon = g_strdup (path); + + return icon; +} + +static void +_panel_icon_chooser_file_chooser_response (GtkFileChooser *filechooser, + gint response_id, + PanelIconChooser *chooser) +{ + if (response_id == GTK_RESPONSE_ACCEPT) { + char *path; + char *icon; + + path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); + icon = _panel_icon_chooser_find_icon_from_path (chooser, path); + g_free (path); + + panel_icon_chooser_set_icon (chooser, icon); + g_free (icon); + } + + gtk_widget_destroy (GTK_WIDGET (filechooser)); +} + +static void +_panel_icon_chooser_clicked (GtkButton *button) +{ + PanelIconChooser *chooser = PANEL_ICON_CHOOSER (button); + GtkWidget *filechooser; + GtkWidget *toplevel; + GtkWindow *parent; + char *path; + gboolean filechooser_path_set; + + if (chooser->priv->filechooser) { + gtk_window_present (GTK_WINDOW (chooser->priv->filechooser)); + return; + } + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + if (gtk_widget_is_toplevel (toplevel)) + parent = GTK_WINDOW (toplevel); + else + parent = NULL; + + filechooser = gtk_file_chooser_dialog_new (_("Choose an icon"), + parent, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, + GTK_RESPONSE_ACCEPT, + NULL); + panel_gtk_file_chooser_add_image_preview (GTK_FILE_CHOOSER (filechooser)); + + path = g_build_filename (DATADIR, "icons", NULL); + gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (filechooser), + path, NULL); + g_free (path); + + path = g_build_filename (DATADIR, "pixmaps", NULL); + gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (filechooser), + path, NULL); + g_free (path); + + filechooser_path_set = FALSE; + + if (chooser->priv->icon) { + char *path = NULL; + if (g_path_is_absolute (chooser->priv->icon)) { + path = g_strdup (chooser->priv->icon); + } else { + GtkIconTheme *icon_theme; + GtkIconInfo *info; + char *no_ext; + int size; + + icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (chooser))); + no_ext = panel_xdg_icon_remove_extension (chooser->priv->icon); + gtk_icon_size_lookup (PANEL_ICON_CHOOSER_ICON_SIZE, + &size, NULL); + + info = gtk_icon_theme_lookup_icon (icon_theme, no_ext, + size, 0); + g_free (no_ext); + + if (info) { + path = g_strdup (gtk_icon_info_get_filename (info)); + gtk_icon_info_free (info); + } + } + + if (path) { + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser), + path); + g_free (path); + filechooser_path_set = TRUE; + } + } + + if (!filechooser_path_set) { + char *path; + // FIXME? Use current icon theme? But there might not be a lot + // of icons there... + path = g_build_filename (DATADIR, "icons", NULL); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser), + path); + } + + gtk_window_set_destroy_with_parent (GTK_WINDOW (filechooser), TRUE); + + g_signal_connect (filechooser, "response", + G_CALLBACK (_panel_icon_chooser_file_chooser_response), + chooser); + + chooser->priv->filechooser = filechooser; + + g_signal_connect (G_OBJECT (filechooser), "destroy", + G_CALLBACK (gtk_widget_destroyed), + &chooser->priv->filechooser); + + gtk_widget_show (filechooser); +} + +static void +_panel_icon_chooser_style_set (GtkWidget *widget, + GtkStyle *prev_style) +{ + PanelIconChooser *chooser; + + chooser = PANEL_ICON_CHOOSER (widget); + + GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->style_set (widget, prev_style); + + _panel_icon_chooser_update (chooser); +} + +static void +_panel_icon_chooser_screen_changed (GtkWidget *widget, + GdkScreen *prev_screen) +{ + PanelIconChooser *chooser; + + chooser = PANEL_ICON_CHOOSER (widget); + + if (GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->screen_changed) + GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->screen_changed (widget, prev_screen); + + _panel_icon_chooser_update (chooser); +} + +/* public methods */ + +GtkWidget * +panel_icon_chooser_new (const char *icon) +{ + GtkWidget *chooser; + + chooser = g_object_new (PANEL_TYPE_ICON_CHOOSER, + "icon", icon, + NULL); + + return chooser; +} + +const char * +panel_icon_chooser_get_fallback_icon_name (PanelIconChooser *chooser) +{ + g_return_val_if_fail (PANEL_IS_ICON_CHOOSER (chooser), NULL); + + return chooser->priv->fallback_icon_name; +} + +void +panel_icon_chooser_set_fallback_icon_name (PanelIconChooser *chooser, + const char *fallback_icon_name) +{ + g_return_if_fail (PANEL_IS_ICON_CHOOSER (chooser)); + + if (g_strcmp0 (chooser->priv->fallback_icon_name, fallback_icon_name) == 0) + return; + + if (chooser->priv->fallback_icon_name) + g_free (chooser->priv->fallback_icon_name); + chooser->priv->fallback_icon_name = g_strdup (fallback_icon_name); + + _panel_icon_chooser_update (chooser); + + g_object_notify (G_OBJECT (chooser), "fallback-icon-name"); +} + +const char * +panel_icon_chooser_get_icon (PanelIconChooser *chooser) +{ + g_return_val_if_fail (PANEL_IS_ICON_CHOOSER (chooser), NULL); + + return chooser->priv->icon; +} + +void +panel_icon_chooser_set_icon (PanelIconChooser *chooser, + const char *icon) +{ + g_return_if_fail (PANEL_IS_ICON_CHOOSER (chooser)); + + if (g_strcmp0 (chooser->priv->icon, icon) == 0) + return; + + if (chooser->priv->icon) + g_free (chooser->priv->icon); + chooser->priv->icon = g_strdup (icon); + + _panel_icon_chooser_update (chooser); + + g_object_notify (G_OBJECT (chooser), "icon"); + + g_signal_emit (G_OBJECT (chooser), + panel_icon_chooser_signals[CHANGED], 0, icon); +} diff --git a/mate-panel/libpanel-util/panel-icon-chooser.h b/mate-panel/libpanel-util/panel-icon-chooser.h new file mode 100644 index 00000000..03475e8f --- /dev/null +++ b/mate-panel/libpanel-util/panel-icon-chooser.h @@ -0,0 +1,79 @@ +/* + * panel-icon-chooser.h: An icon chooser widget + * + * Copyright (C) 2010 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_ICON_CHOOSER_H +#define PANEL_ICON_CHOOSER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_ICON_CHOOSER (panel_icon_chooser_get_type ()) +#define PANEL_ICON_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_ICON_CHOOSER, PanelIconChooser)) +#define PANEL_ICON_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_ICON_CHOOSER, PanelIconChooserClass)) +#define PANEL_IS_ICON_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_ICON_CHOOSER)) +#define PANEL_IS_ICON_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_ICON_CHOOSER)) +#define PANEL_ICON_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_ICON_CHOOSER, PanelIconChooserClass)) + +typedef struct _PanelIconChooser PanelIconChooser; +typedef struct _PanelIconChooserClass PanelIconChooserClass; + +typedef struct _PanelIconChooserPrivate PanelIconChooserPrivate; + +struct _PanelIconChooserClass +{ + GtkButtonClass parent_class; + + void (* changed) (PanelIconChooser *chooser, + const char *icon); +}; + +struct _PanelIconChooser +{ + GtkButton parent_instance; + + PanelIconChooserPrivate *priv; +}; + +GType panel_icon_chooser_get_type (void); + +GtkWidget *panel_icon_chooser_new (const char *icon); + +const char *panel_icon_chooser_get_fallback_icon_name (PanelIconChooser *chooser); + +void panel_icon_chooser_set_fallback_icon_name (PanelIconChooser *chooser, + const char *fallback_icon_name); + +const char *panel_icon_chooser_get_icon (PanelIconChooser *chooser); + +void panel_icon_chooser_set_icon (PanelIconChooser *chooser, + const char *icon); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_ICON_CHOOSER_H */ diff --git a/mate-panel/libpanel-util/panel-keyfile.c b/mate-panel/libpanel-util/panel-keyfile.c new file mode 100644 index 00000000..28ec5853 --- /dev/null +++ b/mate-panel/libpanel-util/panel-keyfile.c @@ -0,0 +1,363 @@ +/* + * panel-keyfile.c: GKeyFile extensions + * + * Copyright (C) 2008 Novell, Inc. + * + * Based on code from panel-util.c (there was no copyright header at the time) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include +#include + +#include +#include + +#include "panel-keyfile.h" + +#define KEYFILE_TRUSTED_SHEBANG "#!/usr/bin/env xdg-open\n" + +GKeyFile * +panel_key_file_new_desktop (void) +{ + GKeyFile *retval; + + retval = g_key_file_new (); + + //FIXME? g_key_file_set_string (retval, G_KEY_FILE_DESKTOP_GROUP, "Name", _("No Name")); + g_key_file_set_string (retval, G_KEY_FILE_DESKTOP_GROUP, "Version", "1.0"); + + return retval; +} + +static void +_panel_key_file_make_executable (const gchar *path) +{ + GFile *file; + GFileInfo *info; + guint32 current_perms; + guint32 new_perms; + + file = g_file_new_for_path (path); + + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_TYPE"," + G_FILE_ATTRIBUTE_UNIX_MODE, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, + NULL); + + if (info == NULL) { + g_warning ("Cannot mark %s executable", path); + g_object_unref (file); + return; + } + + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE)) { + current_perms = g_file_info_get_attribute_uint32 (info, + G_FILE_ATTRIBUTE_UNIX_MODE); + new_perms = current_perms | S_IXGRP | S_IXUSR | S_IXOTH; + if ((current_perms != new_perms) && + !g_file_set_attribute_uint32 (file, + G_FILE_ATTRIBUTE_UNIX_MODE, + new_perms, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, NULL)) + g_warning ("Cannot mark %s executable", path); + } + + g_object_unref (info); + g_object_unref (file); +} + +//FIXME: kill this when bug #309224 is fixed +gboolean +panel_key_file_to_file (GKeyFile *keyfile, + const gchar *file, + GError **error) +{ + gchar *filename; + GError *write_error; + gchar *data; + gsize length; + gboolean res; + + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (file != NULL, FALSE); + + write_error = NULL; + data = g_key_file_to_data (keyfile, &length, &write_error); + if (write_error) { + g_propagate_error (error, write_error); + return FALSE; + } + + if (!g_path_is_absolute (file)) + filename = g_filename_from_uri (file, NULL, &write_error); + else + filename = g_filename_from_utf8 (file, -1, NULL, NULL, + &write_error); + + if (write_error) { + g_propagate_error (error, write_error); + g_free (data); + return FALSE; + } + + if (!g_str_has_prefix (data, "#!")) { + gchar *new_data; + gsize new_length; + + new_length = length + strlen (KEYFILE_TRUSTED_SHEBANG); + new_data = g_malloc (new_length); + + strcpy (new_data, KEYFILE_TRUSTED_SHEBANG); + memcpy (new_data + strlen (KEYFILE_TRUSTED_SHEBANG), + data, length); + + g_free (data); + data = new_data; + length = new_length; + } + + res = g_file_set_contents (filename, data, length, &write_error); + + if (write_error) { + g_propagate_error (error, write_error); + g_free (data); + g_free (filename); + return FALSE; + } + + g_free (data); + + _panel_key_file_make_executable (filename); + g_free (filename); + + return res; +} + +gboolean +panel_key_file_load_from_uri (GKeyFile *keyfile, + const gchar *uri, + GKeyFileFlags flags, + GError **error) +{ + char *scheme; + gboolean is_local; + gboolean result; + + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + scheme = g_uri_parse_scheme (uri); + is_local = (scheme == NULL) || !g_ascii_strcasecmp (scheme, "file"); + g_free (scheme); + + if (is_local) { + char *path; + + if (g_path_is_absolute (uri)) + path = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL); + else + path = g_filename_from_uri (uri, NULL, NULL); + result = g_key_file_load_from_file (keyfile, path, + flags, error); + g_free (path); + } else { + GFile *file; + char *contents; + gsize size; + gboolean ret; + + file = g_file_new_for_uri (uri); + ret = g_file_load_contents (file, NULL, &contents, &size, + NULL, NULL); + g_object_unref (file); + + if (!ret) + return FALSE; + + result = g_key_file_load_from_data (keyfile, contents, size, + flags, error); + + g_free (contents); + } + + return result; +} + +gboolean +panel_key_file_copy_and_mark_trusted (const char *source_path, + const char *target_path, + GError **error) +{ + GKeyFile *key_file; + gboolean res = FALSE; + + key_file = g_key_file_new (); + res = g_key_file_load_from_file (key_file, source_path, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, + error); + if (!res) { + g_key_file_free (key_file); + return FALSE; + } + + res = panel_key_file_to_file (key_file, target_path, error); + + g_key_file_free (key_file); + + return res; +} + +gboolean +panel_key_file_get_boolean (GKeyFile *keyfile, + const gchar *key, + gboolean default_value) +{ + GError *error; + gboolean retval; + + error = NULL; + retval = g_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_GROUP, key, &error); + if (error != NULL) { + retval = default_value; + g_error_free (error); + } + + return retval; +} + +void +panel_key_file_set_locale_string (GKeyFile *keyfile, + const gchar *key, + const gchar *value) +{ + const char *locale; + const char * const *langs_pointer; + int i; + + locale = NULL; + langs_pointer = g_get_language_names (); + for (i = 0; langs_pointer[i] != NULL; i++) { + /* find first without encoding */ + if (strchr (langs_pointer[i], '.') == NULL) { + locale = langs_pointer[i]; + break; + } + } + + if (locale) + g_key_file_set_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, + key, locale, value); + else + g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, + key, value); +} + +void +panel_key_file_remove_locale_key (GKeyFile *keyfile, + const gchar *key) +{ + const char * const *langs_pointer; + int i; + char *locale_key; + + locale_key = NULL; + langs_pointer = g_get_language_names (); + for (i = 0; langs_pointer[i] != NULL; i++) { + /* find first without encoding */ + if (strchr (langs_pointer[i], '.') == NULL) { + locale_key = g_strdup_printf ("%s[%s]", + key, langs_pointer[i]); + if (g_key_file_has_key (keyfile, G_KEY_FILE_DESKTOP_GROUP, + locale_key, NULL)) + break; + + g_free (locale_key); + locale_key = NULL; + } + } + + if (locale_key) { + g_key_file_remove_key (keyfile, G_KEY_FILE_DESKTOP_GROUP, + locale_key, NULL); + g_free (locale_key); + } else + g_key_file_remove_key (keyfile, G_KEY_FILE_DESKTOP_GROUP, + key, NULL); +} + +void +panel_key_file_remove_all_locale_key (GKeyFile *keyfile, + const gchar *key) +{ + char **keys; + int key_len; + int i; + + if (!key) + return; + + keys = g_key_file_get_keys (keyfile, G_KEY_FILE_DESKTOP_GROUP, NULL, NULL); + if (!keys) + return; + + key_len = strlen (key); + + for (i = 0; keys[i] != NULL; i++) { + int len; + + if (strncmp (keys[i], key, key_len)) + continue; + + len = strlen (keys[i]); + if (len == key_len || + (len > key_len && keys[i][key_len] == '[')) + g_key_file_remove_key (keyfile, G_KEY_FILE_DESKTOP_GROUP, + keys[i], NULL); + } + + g_strfreev (keys); +} + +void +panel_key_file_ensure_C_key (GKeyFile *keyfile, + const char *key) +{ + char *C_value; + char *buffer; + + /* Make sure we set the "C" locale strings to the terms we set here. + * This is so that if the user logs into another locale they get their + * own description there rather then empty. It is not the C locale + * however, but the user created this entry herself so it's OK */ + C_value = panel_key_file_get_string (keyfile, key); + if (C_value == NULL || C_value [0] == '\0') { + buffer = panel_key_file_get_locale_string (keyfile, key); + if (buffer) { + panel_key_file_set_string (keyfile, key, buffer); + g_free (buffer); + } + } + g_free (C_value); +} diff --git a/mate-panel/libpanel-util/panel-keyfile.h b/mate-panel/libpanel-util/panel-keyfile.h new file mode 100644 index 00000000..addcefe4 --- /dev/null +++ b/mate-panel/libpanel-util/panel-keyfile.h @@ -0,0 +1,79 @@ +/* + * panel-keyfile.h: GKeyFile extensions + * + * Copyright (C) 2008 Novell, Inc. + * + * Based on code from panel-util.h (there was no copyright header at the time) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_KEYFILE_H +#define PANEL_KEYFILE_H + +#include "glib.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +GKeyFile *panel_key_file_new_desktop (void); +gboolean panel_key_file_to_file (GKeyFile *keyfile, + const gchar *file, + GError **error); +gboolean panel_key_file_load_from_uri (GKeyFile *keyfile, + const gchar *uri, + GKeyFileFlags flags, + GError **error); + +gboolean panel_key_file_copy_and_mark_trusted (const char *source_path, + const char *target_path, + GError **error); + +gboolean panel_key_file_get_boolean (GKeyFile *keyfile, + const gchar *key, + gboolean default_value); +#define panel_key_file_get_string(key_file, key) \ + g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, key, NULL) +#define panel_key_file_get_locale_string(key_file, key) \ + g_key_file_get_locale_string(key_file, G_KEY_FILE_DESKTOP_GROUP, key, NULL, NULL) + +#define panel_key_file_set_boolean(key_file, key, value) \ + g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, key, value) +#define panel_key_file_set_string(key_file, key, value) \ + g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP, key, value) +void panel_key_file_set_locale_string (GKeyFile *keyfile, + const gchar *key, + const gchar *value); + +#define panel_key_file_remove_key(key_file, key) \ + g_key_file_remove_key (key_file, G_KEY_FILE_DESKTOP_GROUP, key, NULL) +void panel_key_file_remove_locale_key (GKeyFile *keyfile, + const gchar *key); +void panel_key_file_remove_all_locale_key (GKeyFile *keyfile, + const gchar *key); +void panel_key_file_ensure_C_key (GKeyFile *keyfile, + const char *key); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_KEYFILE_H */ diff --git a/mate-panel/libpanel-util/panel-launch.c b/mate-panel/libpanel-util/panel-launch.c new file mode 100644 index 00000000..af2b4282 --- /dev/null +++ b/mate-panel/libpanel-util/panel-launch.c @@ -0,0 +1,234 @@ +/* + * panel-launch.c: some helpers to launch desktop files + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include +#include +#include + +#include +#include + +#include "panel-error.h" +#include "panel-glib.h" + +#include "panel-launch.h" + +static void +_panel_launch_error_dialog (const gchar *name, + GdkScreen *screen, + const gchar *message) +{ + char *primary; + + if (name) + primary = g_markup_printf_escaped (_("Could not launch '%s'"), + name); + else + primary = g_strdup (_("Could not launch application")); + + panel_error_dialog (NULL, screen, "cannot_launch", TRUE, + primary, message); + g_free (primary); +} + +static gboolean +_panel_launch_handle_error (const gchar *name, + GdkScreen *screen, + GError *local_error, + GError **error) +{ + if (local_error == NULL) + return TRUE; + + else if (g_error_matches (local_error, + G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (local_error); + return TRUE; + } + + else if (error != NULL) + g_propagate_error (error, local_error); + + else { + _panel_launch_error_dialog (name, screen, local_error->message); + g_error_free (local_error); + } + + return FALSE; +} + +gboolean +panel_app_info_launch_uris (GAppInfo *appinfo, + GList *uris, + GdkScreen *screen, + guint32 timestamp, + GError **error) +{ + GdkAppLaunchContext *context; + GError *local_error; + gboolean retval; + + g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE); + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + context = gdk_app_launch_context_new (); + gdk_app_launch_context_set_screen (context, screen); + gdk_app_launch_context_set_timestamp (context, timestamp); + + local_error = NULL; + retval = g_app_info_launch_uris (appinfo, uris, + (GAppLaunchContext *) context, + &local_error); + + g_object_unref (context); + + return _panel_launch_handle_error (g_app_info_get_name (appinfo), + screen, local_error, error); +} + +gboolean +panel_app_info_launch_uri (GAppInfo *appinfo, + const gchar *uri, + GdkScreen *screen, + guint32 timestamp, + GError **error) +{ + GList *uris; + gboolean retval; + + g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE); + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + uris = NULL; + if (uri) + uris = g_list_prepend (uris, (gpointer) uri); + + retval = panel_app_info_launch_uris (appinfo, uris, + screen, timestamp, error); + + g_list_free (uris); + + return retval; +} + +gboolean +panel_launch_key_file (GKeyFile *keyfile, + GList *uri_list, + GdkScreen *screen, + GError **error) +{ + GDesktopAppInfo *appinfo; + gboolean retval; + + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + appinfo = g_desktop_app_info_new_from_keyfile (keyfile); + + if (appinfo == NULL) + return FALSE; + + retval = panel_app_info_launch_uris (G_APP_INFO (appinfo), + uri_list, screen, + gtk_get_current_event_time (), + error); + + g_object_unref (appinfo); + + return retval; +} + +gboolean +panel_launch_desktop_file (const char *desktop_file, + GdkScreen *screen, + GError **error) +{ + GDesktopAppInfo *appinfo; + gboolean retval; + + g_return_val_if_fail (desktop_file != NULL, FALSE); + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + appinfo = NULL; + + if (g_path_is_absolute (desktop_file)) + appinfo = g_desktop_app_info_new_from_filename (desktop_file); + else { + char *full; + + full = panel_g_lookup_in_applications_dirs (desktop_file); + if (full) { + appinfo = g_desktop_app_info_new_from_filename (full); + g_free (full); + } + } + + if (appinfo == NULL) + return FALSE; + + retval = panel_app_info_launch_uris (G_APP_INFO (appinfo), NULL, screen, + gtk_get_current_event_time (), + error); + + g_object_unref (appinfo); + + return retval; +} + +gboolean +panel_launch_desktop_file_with_fallback (const char *desktop_file, + const char *fallback_exec, + GdkScreen *screen, + GError **error) +{ + char *argv[2] = { (char *) fallback_exec, NULL }; + GError *local_error; + gboolean retval; + + g_return_val_if_fail (desktop_file != NULL, FALSE); + g_return_val_if_fail (fallback_exec != NULL, FALSE); + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* need to pass a non-NULL error to avoid getting a dialog */ + local_error = NULL; + if (panel_launch_desktop_file (desktop_file, screen, &local_error)) + return TRUE; + + if (local_error) { + g_error_free (local_error); + local_error = NULL; + } + + retval = gdk_spawn_on_screen (screen, NULL, argv, NULL, + G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &local_error); + + return _panel_launch_handle_error (fallback_exec, + screen, local_error, error); +} diff --git a/mate-panel/libpanel-util/panel-launch.h b/mate-panel/libpanel-util/panel-launch.h new file mode 100644 index 00000000..d580f375 --- /dev/null +++ b/mate-panel/libpanel-util/panel-launch.h @@ -0,0 +1,65 @@ +/* + * panel-launch.h: some helpers to launch desktop files + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_LAUNCH_H +#define PANEL_LAUNCH_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +gboolean panel_app_info_launch_uris (GAppInfo *appinfo, + GList *uris, + GdkScreen *screen, + guint32 timestamp, + GError **error); + +gboolean panel_app_info_launch_uri (GAppInfo *appinfo, + const gchar *uri, + GdkScreen *screen, + guint32 timestamp, + GError **error); + +gboolean panel_launch_key_file (GKeyFile *keyfile, + GList *uri_list, + GdkScreen *screen, + GError **error); + +gboolean panel_launch_desktop_file (const char *desktop_file, + GdkScreen *screen, + GError **error); + +gboolean panel_launch_desktop_file_with_fallback (const char *desktop_file, + const char *fallback_exec, + GdkScreen *screen, + GError **error); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_LAUNCH_H */ diff --git a/mate-panel/libpanel-util/panel-list.c b/mate-panel/libpanel-util/panel-list.c new file mode 100644 index 00000000..db036186 --- /dev/null +++ b/mate-panel/libpanel-util/panel-list.c @@ -0,0 +1,212 @@ +/* + * panel-list.c: GList & GSList extensions + * + * Copyright (C) 2008 Novell, Inc. + * + * Originally based on code from panel-util.c (there was no relevant copyright + * header at the time), but the code was: + * Copyright (C) Mark McLoughlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include "panel-list.h" + +GList * +panel_g_list_insert_before (GList *list, + GList *sibling, + GList *link) +{ + if (!list) { + g_return_val_if_fail (sibling == NULL, list); + return link; + } else if (sibling) { + if (sibling->prev) { + link->prev = sibling->prev; + link->prev->next = link; + link->next = sibling; + sibling->prev = link; + return list; + } else { + link->next = sibling; + sibling->prev = link; + g_return_val_if_fail (sibling == list, link); + return link; + } + } else { + GList *last; + + last = list; + while (last->next) + last = last->next; + + last->next = link; + link->prev = last; + return list; + } +} + +GList * +panel_g_list_insert_after (GList *list, + GList *sibling, + GList *link) +{ + if (!list) { + g_return_val_if_fail (sibling == NULL, link); + return link; + } else if (sibling) { + if (sibling->next) { + link->next = sibling->next; + link->next->prev = link; + link->prev = sibling; + sibling->next = link; + return list; + } else { + sibling->next = link; + link->prev = sibling; + return list; + } + + } else { + link->next = list; + list->prev = link; + return link; + } +} + +GList * +panel_g_list_swap_next (GList *list, + GList *dl) +{ + GList *t; + + if (!dl) + return list; + + if (!dl->next) + return list; + + if (dl->prev) + dl->prev->next = dl->next; + t = dl->prev; + dl->prev = dl->next; + dl->next->prev = t; + if (dl->next->next) + dl->next->next->prev = dl; + t = dl->next->next; + dl->next->next = dl; + dl->next = t; + + if (list == dl) + return dl->prev; + + return list; +} + +GList * +panel_g_list_swap_prev (GList *list, + GList *dl) +{ + GList *t; + + if (!dl) + return list; + + if (!dl->prev) + return list; + + if (dl->next) + dl->next->prev = dl->prev; + t = dl->next; + dl->next = dl->prev; + dl->prev->next = t; + if (dl->prev->prev) + dl->prev->prev->next = dl; + t = dl->prev->prev; + dl->prev->prev = dl; + dl->prev = t; + + if (list == dl->next) + return dl; + + return list; +} + +/*maybe this should be a glib function? + it resorts a single item in the list*/ +GList * +panel_g_list_resort_item (GList *list, + gpointer data, + GCompareFunc func) +{ + GList *dl; + + g_return_val_if_fail (func != NULL, list); + + if (!list) + return NULL; + + dl = g_list_find (list, data); + + if (dl != NULL) + return list; + + while (dl->next && + (*func)(dl->data, dl->next->data) > 0) + list = panel_g_list_swap_next (list, dl); + while (dl->prev && + (*func) (dl->data, dl->prev->data) < 0) + list = panel_g_list_swap_prev (list, dl); + + return list; +} + +GSList * +panel_g_slist_make_unique (GSList *list, + GCompareFunc compare, + gboolean free_data) +{ + GSList *sorted, *l; + + g_return_val_if_fail (compare != NULL, list); + + if (!list) + return NULL; + + sorted = g_slist_copy (list); + sorted = g_slist_sort (sorted, compare); + + for (l = sorted; l; l = l->next) { + GSList *next; + + next = l->next; + if (l->data && next && next->data) + if (!compare (l->data, next->data)) { + list = g_slist_remove (list, l->data); + if (free_data) + g_free (l->data); + } + } + + g_slist_free (sorted); + + return list; +} diff --git a/mate-panel/libpanel-util/panel-list.h b/mate-panel/libpanel-util/panel-list.h new file mode 100644 index 00000000..c3e48f53 --- /dev/null +++ b/mate-panel/libpanel-util/panel-list.h @@ -0,0 +1,56 @@ +/* + * panel-list.h: GList & GSList extensions + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_LIST_H +#define PANEL_LIST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +GList *panel_g_list_insert_before (GList *list, + GList *sibling, + GList *link); +GList *panel_g_list_insert_after (GList *list, + GList *sibling, + GList *link); +GList *panel_g_list_swap_next (GList *list, + GList *dl); +GList *panel_g_list_swap_prev (GList *list, + GList *dl); +GList *panel_g_list_resort_item (GList *list, + gpointer data, + GCompareFunc func); + +GSList *panel_g_slist_make_unique (GSList *list, + GCompareFunc compare, + gboolean free_data); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_LIST_H */ diff --git a/mate-panel/libpanel-util/panel-session-manager.c b/mate-panel/libpanel-util/panel-session-manager.c new file mode 100644 index 00000000..63152e1a --- /dev/null +++ b/mate-panel/libpanel-util/panel-session-manager.c @@ -0,0 +1,192 @@ +/* + * panel-session.c: + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include "panel-cleanup.h" +#include "panel-dbus-service.h" + +#include "panel-session-manager.h" + +static GObject *panel_session_manager_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); + +G_DEFINE_TYPE (PanelSessionManager, panel_session_manager, PANEL_TYPE_DBUS_SERVICE); + +static void +panel_session_manager_class_init (PanelSessionManagerClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = panel_session_manager_constructor; +} + +static void +panel_session_manager_init (PanelSessionManager *manager) +{ +} + +static GObject * +panel_session_manager_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + GError *error; + + obj = G_OBJECT_CLASS (panel_session_manager_parent_class)->constructor ( + type, + n_construct_properties, + construct_properties); + + + panel_dbus_service_define_service (PANEL_DBUS_SERVICE (obj), + "org.mate.SessionManager", + "/org/mate/SessionManager", + "org.mate.SessionManager"); + + error = NULL; + if (!panel_dbus_service_ensure_connection (PANEL_DBUS_SERVICE (obj), + &error)) { + g_message ("Could not connect to session manager: %s", + error->message); + g_error_free (error); + } + + return obj; +} + +void +panel_session_manager_request_logout (PanelSessionManager *manager, + PanelSessionManagerLogoutType mode) +{ + GError *error; + DBusGProxy *proxy; + + g_return_if_fail (PANEL_IS_SESSION_MANAGER (manager)); + + error = NULL; + + if (!panel_dbus_service_ensure_connection (PANEL_DBUS_SERVICE (manager), + &error)) { + g_warning ("Could not connect to session manager: %s", + error->message); + g_error_free (error); + return; + } + + proxy = panel_dbus_service_get_proxy (PANEL_DBUS_SERVICE (manager)); + + if (!dbus_g_proxy_call (proxy, "Logout", &error, + G_TYPE_UINT, mode, G_TYPE_INVALID, + G_TYPE_INVALID) && + error != NULL) { + g_warning ("Could not ask session manager to log out: %s", + error->message); + g_error_free (error); + } +} + +void +panel_session_manager_request_shutdown (PanelSessionManager *manager) +{ + GError *error; + DBusGProxy *proxy; + + g_return_if_fail (PANEL_IS_SESSION_MANAGER (manager)); + + error = NULL; + + if (!panel_dbus_service_ensure_connection (PANEL_DBUS_SERVICE (manager), + &error)) { + g_warning ("Could not connect to session manager: %s", + error->message); + g_error_free (error); + return; + } + + proxy = panel_dbus_service_get_proxy (PANEL_DBUS_SERVICE (manager)); + + if (!dbus_g_proxy_call (proxy, "Shutdown", &error, + G_TYPE_INVALID, + G_TYPE_INVALID) && + error != NULL) { + g_warning ("Could not ask session manager to shut down: %s", + error->message); + g_error_free (error); + } +} + +gboolean +panel_session_manager_is_shutdown_available (PanelSessionManager *manager) +{ + GError *error; + DBusGProxy *proxy; + gboolean is_shutdown_available; + + g_return_val_if_fail (PANEL_IS_SESSION_MANAGER (manager), FALSE); + + error = NULL; + + if (!panel_dbus_service_ensure_connection (PANEL_DBUS_SERVICE (manager), + &error)) { + g_warning ("Could not connect to session manager: %s", + error->message); + g_error_free (error); + + return FALSE; + } + + proxy = panel_dbus_service_get_proxy (PANEL_DBUS_SERVICE (manager)); + + if (!dbus_g_proxy_call (proxy, "CanShutdown", &error, + G_TYPE_INVALID, G_TYPE_BOOLEAN, + &is_shutdown_available, G_TYPE_INVALID) && + error != NULL) { + g_warning ("Could not ask session manager if shut down is available: %s", + error->message); + g_error_free (error); + + return FALSE; + } + + return is_shutdown_available; +} + +PanelSessionManager * +panel_session_manager_get (void) +{ + static PanelSessionManager *manager = NULL; + + if (manager == NULL) { + manager = g_object_new (PANEL_TYPE_SESSION_MANAGER, NULL); + panel_cleanup_register (panel_cleanup_unref_and_nullify, + &manager); + } + + return manager; +} diff --git a/mate-panel/libpanel-util/panel-session-manager.h b/mate-panel/libpanel-util/panel-session-manager.h new file mode 100644 index 00000000..d48ce5d3 --- /dev/null +++ b/mate-panel/libpanel-util/panel-session-manager.h @@ -0,0 +1,75 @@ +/* + * panel-session.h: + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_SESSION_MANAGER_H +#define PANEL_SESSION_MANAGER_H + +#include + +#include "panel-dbus-service.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_SESSION_MANAGER (panel_session_manager_get_type ()) +#define PANEL_SESSION_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_SESSION_MANAGER, PanelSessionManager)) +#define PANEL_SESSION_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_SESSION_MANAGER, PanelSessionManagerClass)) +#define PANEL_IS_SESSION_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_SESSION_MANAGER)) +#define PANEL_IS_SESSION_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_SESSION_MANAGER)) +#define PANEL_SESSION_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PANEL_TYPE_SESSION_MANAGER, PanelSessionManagerClass)) + +typedef struct _PanelSessionManager PanelSessionManager; +typedef struct _PanelSessionManagerClass PanelSessionManagerClass; + +struct _PanelSessionManager { + PanelDBusService parent; +}; + +struct _PanelSessionManagerClass { + PanelDBusServiceClass parent_class; +}; + +GType panel_session_manager_get_type (void); + +/* Keep in sync with the values defined in mate-session/session.h */ +typedef enum { + PANEL_SESSION_MANAGER_LOGOUT_MODE_NORMAL = 0, + PANEL_SESSION_MANAGER_LOGOUT_MODE_NO_CONFIRMATION, + PANEL_SESSION_MANAGER_LOGOUT_MODE_FORCE +} PanelSessionManagerLogoutType; + +PanelSessionManager *panel_session_manager_get (void); + +void panel_session_manager_request_logout (PanelSessionManager *session, + PanelSessionManagerLogoutType mode); +void panel_session_manager_request_shutdown (PanelSessionManager *session); + +gboolean panel_session_manager_is_shutdown_available (PanelSessionManager *session); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_SESSION_MANAGER_H */ diff --git a/mate-panel/libpanel-util/panel-show.c b/mate-panel/libpanel-util/panel-show.c new file mode 100644 index 00000000..02ea2e63 --- /dev/null +++ b/mate-panel/libpanel-util/panel-show.c @@ -0,0 +1,283 @@ +/* + * panel-show.c: a helper around gtk_show_uri + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include +#include +#include + +#include + +#include "panel-error.h" +#include "panel-glib.h" +#include "panel-launch.h" + +#include "panel-show.h" + +static void +_panel_show_error_dialog (const gchar *uri, + GdkScreen *screen, + const gchar *message) +{ + char *primary; + + primary = g_markup_printf_escaped (_("Could not open location '%s'"), + uri); + panel_error_dialog (NULL, screen, "cannot_show_url", TRUE, + primary, message); + g_free (primary); +} + +typedef struct { + GMountOperation *mount_op; + GdkScreen *screen; +} PanelShowMountOperationHandle; + +static void +_panel_show_mount_async_callback (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + GFile *file; + PanelShowMountOperationHandle *handle = user_data; + + file = G_FILE (source_object); + + error = NULL; + if (g_file_mount_enclosing_volume_finish (file, result, &error)) { + char *uri = g_file_get_uri (file); + + panel_show_uri (handle->screen, uri, + gtk_get_current_event_time (), NULL); + g_free (uri); + } else { + if (!g_error_matches (error, G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED) && + !g_error_matches (error, G_IO_ERROR, + G_IO_ERROR_FAILED_HANDLED)) { + char *uri; + + uri = g_file_get_uri (file); + _panel_show_error_dialog (uri, handle->screen, + error->message); + g_free (uri); + } + g_error_free (error); + } + + if (handle->mount_op) + g_object_unref (handle->mount_op); + + g_slice_free (PanelShowMountOperationHandle, handle); +} + +static gboolean _panel_show_handle_error(const gchar* uri, GdkScreen* screen, GError* local_error, GError** error) +{ + if (local_error == NULL) + { + return TRUE; + } + + else if (g_error_matches (local_error, + G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (local_error); + return TRUE; + } + + else if (g_error_matches (local_error, + G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED)) { + GFile *file; + PanelShowMountOperationHandle *handle; + + handle = g_slice_new (PanelShowMountOperationHandle); + file = g_file_new_for_uri (uri); + + /* If it's not mounted, try to mount it ourselves */ + handle->mount_op = gtk_mount_operation_new (NULL); + gtk_mount_operation_set_screen (GTK_MOUNT_OPERATION (handle->mount_op), + screen); + handle->screen = screen; + + g_file_mount_enclosing_volume (file, G_MOUNT_MOUNT_NONE, + handle->mount_op, NULL, + _panel_show_mount_async_callback, + handle); + g_object_unref (file); + + return TRUE; + } + + else if (error != NULL) + g_propagate_error (error, local_error); + + else { + _panel_show_error_dialog (uri, screen, local_error->message); + g_error_free (local_error); + } + + return FALSE; +} + +static gboolean panel_show_caja_search_uri(GdkScreen* screen, const gchar* uri, guint32 timestamp, GError** error) +{ + char* desktopfile; + GDesktopAppInfo* appinfo; + gboolean ret; + + desktopfile = panel_g_lookup_in_applications_dirs("caja-folder-handler.desktop"); + + if (desktopfile) + { + appinfo = g_desktop_app_info_new_from_filename(desktopfile); + g_free(desktopfile); + } + + if (!appinfo) + { + _panel_show_error_dialog (uri, screen, _("No application to handle search folders is installed.")); + return FALSE; + } + + ret = panel_app_info_launch_uri((GAppInfo*) appinfo, uri, screen, timestamp, error); + g_object_unref(appinfo); + + return ret; +} + +gboolean panel_show_uri(GdkScreen* screen, const gchar* uri, guint32 timestamp, GError** error) +{ + GError* local_error = NULL; + + g_return_val_if_fail(GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail(uri != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + if (g_str_has_prefix(uri, "x-caja-search:")) + { + return panel_show_caja_search_uri(screen, uri, timestamp, error); + } + + gtk_show_uri(screen, uri, timestamp, &local_error); + + return _panel_show_handle_error(uri, screen, local_error, error); +} + +gboolean +panel_show_uri_force_mime_type (GdkScreen *screen, + const gchar *uri, + const gchar *mime_type, + guint32 timestamp, + GError **error) +{ + GFile *file; + GAppInfo *app; + gboolean ret; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (mime_type != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + file = g_file_new_for_uri (uri); + app = g_app_info_get_default_for_type (mime_type, + !g_file_is_native (file)); + g_object_unref (file); + + if (app == NULL) { + /* no application for the mime type, so let's fallback on + * automatic detection */ + return panel_show_uri (screen, uri, timestamp, error); + } + + ret = panel_app_info_launch_uri (app, uri, screen, timestamp, error); + g_object_unref (app); + + return ret; +} + +static void +_panel_show_help_error_dialog (const gchar *doc, + GdkScreen *screen, + const gchar *message) +{ + char *primary; + + primary = g_markup_printf_escaped (_("Could not display help document '%s'"), + doc); + panel_error_dialog (NULL, screen, "cannot_show_help", TRUE, + primary, message); + g_free (primary); +} + +static gboolean +_panel_show_help_handle_error (const gchar *doc, + GdkScreen *screen, + GError *local_error, + GError **error) +{ + if (local_error == NULL) + return TRUE; + + else if (g_error_matches (local_error, + G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (local_error); + return TRUE; + } + + else if (error != NULL) + g_propagate_error (error, local_error); + + else { + _panel_show_help_error_dialog (doc, screen, + local_error->message); + g_error_free (local_error); + } + + return FALSE; +} + +gboolean +panel_show_help (GdkScreen *screen, + const gchar *doc, + const gchar *link, + GError **error) +{ + GError *local_error = NULL; + char *uri; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (doc != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (link) + uri = g_strdup_printf ("ghelp:%s?%s", doc, link); + else + uri = g_strdup_printf ("ghelp:%s", doc); + + gtk_show_uri (screen, uri, gtk_get_current_event_time (), &local_error); + + g_free (uri); + + return _panel_show_help_handle_error (doc, screen, local_error, error); +} diff --git a/mate-panel/libpanel-util/panel-show.h b/mate-panel/libpanel-util/panel-show.h new file mode 100644 index 00000000..a0eac9bc --- /dev/null +++ b/mate-panel/libpanel-util/panel-show.h @@ -0,0 +1,54 @@ +/* + * panel-show.h: a helper around gtk_show_uri + * + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_SHOW_H +#define PANEL_SHOW_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +gboolean panel_show_uri (GdkScreen *screen, + const gchar *uri, + guint32 timestamp, + GError **error); + +gboolean panel_show_uri_force_mime_type (GdkScreen *screen, + const gchar *uri, + const gchar *mime_type, + guint32 timestamp, + GError **error); + +gboolean panel_show_help (GdkScreen *screen, + const gchar *doc, + const gchar *link, + GError **error); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_SHOW_H */ diff --git a/mate-panel/libpanel-util/panel-xdg.c b/mate-panel/libpanel-util/panel-xdg.c new file mode 100644 index 00000000..5415a22e --- /dev/null +++ b/mate-panel/libpanel-util/panel-xdg.c @@ -0,0 +1,152 @@ +/* + * panel-xdg.c: miscellaneous XDG-related functions. + * + * Copyright (C) 2010 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include +#include + +#include "panel-xdg.h" + +#define DEFAULT_THEME_NAME "hicolor" + +/* + * Originally based on code from panel-util.c. This part of the code was: + * Copyright (C) 2006 Vincent Untz + */ + +char * +panel_xdg_icon_remove_extension (const char *icon) +{ + char *icon_no_extension; + char *p; + + icon_no_extension = g_strdup (icon); + p = strrchr (icon_no_extension, '.'); + if (p && + (strcmp (p, ".png") == 0 || + strcmp (p, ".xpm") == 0 || + strcmp (p, ".svg") == 0)) { + *p = 0; + } + + return icon_no_extension; +} + +/* + * End of code coming from panel-util.c + */ + +char * +panel_xdg_icon_name_from_icon_path (const char *path, + GdkScreen *screen) +{ + GtkIconTheme *theme; + GtkSettings *settings; + char *theme_name; + char *icon; + char **paths; + int n_paths; + int i; + GFile *file; + + /* we look if the icon comes from the current icon theme */ + if (!screen) + screen = gdk_screen_get_default (); + + settings = gtk_settings_get_for_screen (screen); + g_object_get (settings, + "gtk-icon-theme-name", &theme_name, + NULL); + + theme = gtk_icon_theme_get_for_screen (screen); + gtk_icon_theme_get_search_path (theme, &paths, &n_paths); + + file = g_file_new_for_path (path); + icon = NULL; + + for (i = 0; i < n_paths; i++) { + GFile *parent; + char *basename; + + parent = g_file_new_for_path (paths[i]); + + if (!g_file_has_prefix (file, parent)) { + g_object_unref (parent); + continue; + } + + basename = g_file_get_basename (parent); + + if (g_strcmp0 (basename, "pixmaps") == 0) { + char *relative_path; + + relative_path = g_file_get_relative_path (parent, file); + + /* if the icon is in a subdir of pixmaps, then it's not + * a real icon name */ + if (!strchr (relative_path, G_DIR_SEPARATOR)) + icon = panel_xdg_icon_remove_extension (relative_path); + + g_free (relative_path); + } else { + /* real icon theme; but is it the current one? */ + GFile *theme_dir; + gboolean current; + + theme_dir = g_file_get_child (parent, theme_name); + + current = FALSE; + if (g_file_has_prefix (file, theme_dir)) { + /* it's the current one */ + current = TRUE; + } else { + /* it's the default one */ + g_object_unref (theme_dir); + theme_dir = g_file_get_child (parent, DEFAULT_THEME_NAME); + current = g_file_has_prefix (file, theme_dir); + } + + g_object_unref (theme_dir); + + if (current) { + char *buffer; + + buffer = g_file_get_basename (file); + icon = panel_xdg_icon_remove_extension (buffer); + g_free (buffer); + } + } + + g_free (basename); + g_object_unref (parent); + + break; + } + + g_object_unref (file); + g_free (theme_name); + + return icon; +} diff --git a/mate-panel/libpanel-util/panel-xdg.h b/mate-panel/libpanel-util/panel-xdg.h new file mode 100644 index 00000000..8fa71b2e --- /dev/null +++ b/mate-panel/libpanel-util/panel-xdg.h @@ -0,0 +1,43 @@ +/* + * panel-xdg.h: miscellaneous XDG-related functions. + * + * Copyright (C) 2010 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_XDG_H +#define PANEL_XDG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +char *panel_xdg_icon_remove_extension (const char *icon); + +char *panel_xdg_icon_name_from_icon_path (const char *path, + GdkScreen *screen); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_XDG_H */ diff --git a/mate-panel/main.c b/mate-panel/main.c new file mode 100644 index 00000000..7721fade --- /dev/null +++ b/mate-panel/main.c @@ -0,0 +1,153 @@ +/* Mate panel: Initialization routines + * (C) 1997,1998,1999,2000 the Free Software Foundation + * (C) 2000 Eazel, Inc. + * + * Authors: Federico Mena + * Miguel de Icaza + * George Lebl + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "panel-mateconf.h" +#include "panel-profile.h" +#include "panel-config-global.h" +#include "panel-shell.h" +#include "panel-multiscreen.h" +#include "panel-session.h" +#include "panel-stock-icons.h" +#include "panel-action-protocol.h" +#include "panel-lockdown.h" +#include "panel-icon-names.h" +#include "panel-reset.h" +#include "xstuff.h" + +#include "nothing.cP" + +/* globals */ +GSList *panels = NULL; +GSList *panel_list = NULL; + +static char* deprecated_profile; +static gboolean replace = FALSE; +static gboolean reset = FALSE; + +static const GOptionEntry options[] = { + { "replace", 0, 0, G_OPTION_ARG_NONE, &replace, N_("Replace a currently running panel"), NULL }, + /* keep this for compatibilty with old MATE < 2.10 */ + { "profile", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &deprecated_profile, NULL, NULL }, + /* this feature was request in #mate irc channel */ + { "reset", 0, 0, G_OPTION_ARG_NONE, &reset, N_("Reset the panel configuration to default"), NULL }, + { NULL } +}; + +int +main (int argc, char **argv) +{ + char *desktopfile; + GOptionContext *context; + GError *error; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* We will register explicitly when we're ready -- see panel-session.c */ + egg_sm_client_set_mode (EGG_SM_CLIENT_MODE_DISABLED); + + g_set_prgname ("mate-panel"); + + desktopfile = panel_g_lookup_in_applications_dirs ("mate-panel.desktop"); + if (desktopfile) { + egg_set_desktop_file (desktopfile); + g_free (desktopfile); + } + + context = g_option_context_new (""); + g_option_context_add_group (context, + egg_sm_client_get_option_group ()); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + error = NULL; + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("%s\n", error->message); + g_error_free (error); + g_option_context_free (context); + + return 1; + } + + g_option_context_free (context); + + /* reset the configuration and exit. */ + if (reset == TRUE) + { + panel_reset(); + return 0; + } + + + if (!egg_get_desktop_file ()) { + g_set_application_name (_("Panel")); + gtk_window_set_default_icon_name (PANEL_ICON_PANEL); + } + + if (!panel_shell_register (replace)) { + panel_cleanup_do (); + return -1; + } + + panel_action_protocol_init (); + panel_multiscreen_init (); + panel_init_stock_icons_and_items (); + + mateconf_client_add_dir (panel_mateconf_get_client (), + "/desktop/mate/interface", + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + + panel_global_config_load (); + panel_lockdown_init (); + panel_profile_load (); + + /*add forbidden lists to ALL panels*/ + g_slist_foreach (panels, + (GFunc)panel_widget_add_forbidden, + NULL); + + xstuff_init (); + + /* Flush to make sure our struts are seen by everyone starting + * immediate after (eg, the caja desktop). */ + gdk_flush (); + + /* Do this at the end, to be sure that we're really ready when + * connecting to the session manager */ + panel_session_init (); + + gtk_main (); + + panel_lockdown_finalize (); + + mateconf_client_remove_dir (panel_mateconf_get_client (), + "/desktop/mate/interface", + NULL); + + panel_cleanup_do (); + + return 0; +} diff --git a/mate-panel/mate-desktop-item-edit.c b/mate-panel/mate-desktop-item-edit.c new file mode 100644 index 00000000..f94b9254 --- /dev/null +++ b/mate-panel/mate-desktop-item-edit.c @@ -0,0 +1,225 @@ +#include "config.h" + +#include +#include +#include + +#include +#include + +#include "panel-ditem-editor.h" +#include "panel-icon-names.h" +#include "panel-util.h" + +/* FIXME Symbols needed by panel-util.c - sucky */ +#include "applet.h" +GSList *mate_panel_applet_list_applets (void) { return NULL; } +#include "panel-mateconf.h" +MateConfClient *panel_mateconf_get_client (void) { return NULL; } +#include "panel-config-global.h" +gboolean panel_global_config_get_tooltips_enabled (void) { return FALSE; } +#include "panel-lockdown.h" +gboolean panel_lockdown_get_disable_lock_screen (void) { return FALSE; } + +static int dialogs = 0; +static gboolean create_new = FALSE; +static char **desktops = NULL; + +static GOptionEntry options[] = { + { "create-new", 0, 0, G_OPTION_ARG_NONE, &create_new, N_("Create new file in the given directory"), NULL }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &desktops, NULL, N_("[FILE...]") }, + { NULL } +}; + +static void +dialog_destroyed (GtkWidget *dialog, gpointer data) +{ + dialogs --; + + if (dialogs <= 0) + gtk_main_quit (); +} + +static void +validate_for_filename (char *file) +{ + char *ptr; + + g_return_if_fail (file != NULL); + + ptr = file; + while (*ptr != '\0') { + if (*ptr == '/') + *ptr = '_'; + ptr++; + } +} + +static char * +find_uri_on_save (PanelDItemEditor *dialog, + gpointer data) +{ + GKeyFile *keyfile; + char *name; + char *filename; + char *uri; + char *dir; + + keyfile = panel_ditem_editor_get_key_file (dialog); + name = panel_key_file_get_string (keyfile, "Name"); + + validate_for_filename (name); + filename = g_filename_from_utf8 (name, -1, NULL, NULL, NULL); + g_free (name); + + if (filename == NULL) + filename = g_strdup ("foo"); + + dir = g_object_get_data (G_OBJECT (dialog), "dir"); + uri = panel_make_unique_desktop_path_from_name (dir, filename); + + g_free (filename); + + return uri; +} + +static void +error_reported (GtkWidget *dialog, + const char *primary, + const char *secondary, + gpointer data) +{ + panel_error_dialog (GTK_WINDOW (dialog), NULL, + "error_editing_launcher", TRUE, + primary, secondary); +} + +int +main (int argc, char * argv[]) +{ + GError *error = NULL; + int i; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + if (!gtk_init_with_args (&argc, &argv, + _("- Edit .desktop files"), + options, + GETTEXT_PACKAGE, + &error)) { + g_printerr ("%s\n", error->message); + g_error_free (error); + return 1; + } + + gtk_window_set_default_icon_name (PANEL_ICON_LAUNCHER); + + if (desktops == NULL || + desktops[0] == NULL) { + g_printerr ("mate-desktop-item-edit: no file to edit\n"); + return 0; + } + + for (i = 0; desktops[i] != NULL; i++) { + GFile *file; + GFileInfo *info; + GFileType type; + char *uri; + char *path; + GtkWidget *dlg = NULL; + + file = g_file_new_for_commandline_arg (desktops[i]); + uri = g_file_get_uri (file); + path = g_file_get_path (file); + info = g_file_query_info (file, "standard::type", + G_FILE_QUERY_INFO_NONE, NULL, NULL); + g_object_unref (file); + + if (info) { + type = g_file_info_get_file_type (info); + + if (type == G_FILE_TYPE_DIRECTORY && create_new) { + + dlg = panel_ditem_editor_new (NULL, NULL, NULL, + _("Create Launcher")); + g_object_set_data_full (G_OBJECT (dlg), "dir", + g_strdup (path), + (GDestroyNotify)g_free); + + panel_ditem_register_save_uri_func (PANEL_DITEM_EDITOR (dlg), + find_uri_on_save, + NULL); + + } else if (type == G_FILE_TYPE_DIRECTORY) { + /* Rerun this iteration with the .directory + * file + * Note: No need to free, for one we can't free + * an individual member of desktops and + * secondly we will soon exit */ + desktops[i] = g_build_path ("/", uri, + ".directory", NULL); + i--; + } else if (type == G_FILE_TYPE_REGULAR + && g_str_has_suffix (desktops [i], + ".directory") + && !create_new) { + dlg = panel_ditem_editor_new_directory (NULL, + NULL, + uri, + _("Directory Properties")); + } else if (type == G_FILE_TYPE_REGULAR + && g_str_has_suffix (desktops [i], + ".desktop") + && !create_new) { + dlg = panel_ditem_editor_new (NULL, NULL, uri, + _("Launcher Properties")); + } else if (type == G_FILE_TYPE_REGULAR + && create_new) { + g_printerr ("mate-desktop-item-edit: %s " + "already exists\n", uri); + } else { + g_printerr ("mate-desktop-item-edit: %s " + "does not look like a desktop " + "item\n", uri); + } + + g_object_unref (info); + + } else if (g_str_has_suffix (desktops [i], ".directory")) { + /* a non-existant file. Well we can still edit that + * sort of. We will just create it new */ + dlg = panel_ditem_editor_new_directory (NULL, NULL, uri, + _("Directory Properties")); + + } else if (g_str_has_suffix (desktops [i], ".desktop")) { + /* a non-existant file. Well we can still edit that + * sort of. We will just create it new */ + dlg = panel_ditem_editor_new (NULL, NULL, uri, + _("Create Launcher")); + + } else { + g_printerr ("mate-desktop-item-edit: %s does not " + "have a .desktop or .directory " + "suffix\n", uri); + } + + if (dlg != NULL) { + dialogs ++; + g_signal_connect (G_OBJECT (dlg), "destroy", + G_CALLBACK (dialog_destroyed), NULL); + g_signal_connect (G_OBJECT (dlg), "error_reported", + G_CALLBACK (error_reported), NULL); + gtk_widget_show (dlg); + } + + g_free (uri); + g_free (path); + } + + if (dialogs > 0) + gtk_main (); + + return 0; +} diff --git a/mate-panel/mate-panel-add.in b/mate-panel/mate-panel-add.in new file mode 100644 index 00000000..b50669cd --- /dev/null +++ b/mate-panel/mate-panel-add.in @@ -0,0 +1,325 @@ +#!@PYTHON@ +# vim: set ts=4 sw=4 et: + +# +# Copyright (C) 2009 Novell, Inc. +# +# Authors: Vincent Untz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import optparse +import os +import shutil +import sys +import urllib +import ConfigParser + +try: + import matecomponent + has_matecomponent = True +except ImportError: + has_matecomponent = False + +import mateconf + +PANEL_SCHEMAS_OBJECTS_DIR='/schemas/apps/panel/objects' + +PANEL_TOPLEVELS_DIR='/apps/panel/toplevels' +PANEL_TOPLEVELS_KEY='/apps/panel/general/toplevel_id_list' +MATE_PANEL_APPLETS_DIR='/apps/panel/applets' +MATE_PANEL_APPLETS_KEY='/apps/panel/general/applet_id_list' +PANEL_OBJECTS_DIR='/apps/panel/objects' +PANEL_OBJECTS_KEY='/apps/panel/general/object_id_list' + +PANEL_LAUNCHER_USER_DIR=os.path.join(os.path.expanduser('~'), '.mate2', 'panel2.d', 'default', 'launchers') + +PANEL_TYPE_NONE = 0 +PANEL_TYPE_APPLET = 1 +PANEL_TYPE_LAUNCHER = 2 + +MATE_PANEL_APPLETS_EXTENSION='.mate-panel-applet' +MATE_PANEL_APPLETS_PATH='@MATE_PANEL_APPLETS_DIR@' +MATE_PANEL_APPLET_FACTORY_GROUP='Applet Factory' + +class PanelAddException(Exception): + pass + +class PanelAdder: + + def __init__(self, toplevel, position, right_stick, applet_iid = None, launcher_path = None, copy_launcher = False): + self.toplevel = toplevel + self.position = position + self.right_stick = right_stick + + # FIXME workaround: -1 and right_click don't play well together. Just + # use an arbitrary value so that the applet ends up at the left of all + # right-click applets (it'd be surprising to have a config with more + # than 10 applets...) + if self.right_stick and self.position < 0: + self.position = 10 + + self.type = PANEL_TYPE_NONE + self.applet_iid = None + self.launcher_path = None + self.copy_launcher = False + + self.client = None + + if applet_iid: + self._set_applet_iid(applet_iid) + self.type = PANEL_TYPE_APPLET + elif launcher_path: + self._set_launcher_path(launcher_path) + self.copy_launcher = copy_launcher + self.type = PANEL_TYPE_LAUNCHER + + def _panel_get_subdirs(self, key): + return [ os.path.basename(s) for s in self.client.all_dirs(key) ] + + def _panel_get_list(self, key): + list_v = self.client.get(key) + + if not list_v: + return [] + + if list_v.type != mateconf.VALUE_LIST or list_v.get_list_type() != mateconf.VALUE_STRING: + return [] + + return [ v.get_string() for v in list_v.get_list() ] + + def _toplevel_id_ensure(self): + toplevel_subdirs = self._panel_get_subdirs(PANEL_TOPLEVELS_DIR) + toplevel_id_list = self._panel_get_list(PANEL_TOPLEVELS_KEY) + + if self.toplevel: + if not self.toplevel in toplevel_subdirs or not self.toplevel in toplevel_id_list: + raise PanelAddException('%s is not an existing panel identifier' % self.toplevel) + else: + for toplevel in toplevel_id_list: + if toplevel in toplevel_subdirs: + self.toplevel = toplevel + return + + raise PanelAddException('Cannot find a panel identifier') + + def _get_applet_list(self): + dirs = os.getenv('MATE_PANEL_APPLETS_DIR') + if not dirs: + dirs = MATE_PANEL_APPLETS_PATH + + retval = [] + dups = [] + for path in dirs.split(":"): + if not os.path.isdir(path): + continue + + if path in dups: + continue + + dups.append(path) + + for f in os.listdir(path): + if not f.endswith(MATE_PANEL_APPLETS_EXTENSION): + continue + + config = ConfigParser.RawConfigParser() + try: + config.read(os.path.join(path, f)) + except ConfigParser.ParsingError: + continue + + fid = config.get(MATE_PANEL_APPLET_FACTORY_GROUP, 'Id') + retval.extend(["%s::%s" % (fid, s) for s in config.sections() if s != MATE_PANEL_APPLET_FACTORY_GROUP]) + + return retval + + def _set_applet_iid(self, applet_iid): + if not applet_iid: + raise PanelAddException('No applet specified') + + applets = self._get_applet_list () + if not applet_iid in applets: + if has_matecomponent: + applets = matecomponent.activation.query ("has_all (repo_ids, ['IDL:MateComponent/Control:1.0', 'IDL:MATE/Vertigo/MatePanelAppletShell:1.0'])") + if not applet_iid in [ a.iid for a in applets ]: + raise PanelAddException('%s is not a valid applet' % applet_iid) + else: + raise PanelAddException('%s is not a valid applet' % applet_iid) + + self.applet_iid = applet_iid + + def _set_launcher_path(self, launcher_path): + if not launcher_path: + raise PanelAddException('No launcher specified') + + if not launcher_path.endswith('.desktop'): + raise PanelAddException('%s does not have a .desktop extension' % launcher_path) + + if not os.path.exists(launcher_path): + raise PanelAddException('%s is not an existing launcher' % launcher_path) + + self.launcher_path = launcher_path + + def _object_id_find_unused(self): + if self.type == PANEL_TYPE_APPLET: + subdirs = self._panel_get_subdirs(MATE_PANEL_APPLETS_DIR) + id_list = self._panel_get_list(MATE_PANEL_APPLETS_KEY) + prefix = 'applet' + else: + subdirs = self._panel_get_subdirs(PANEL_OBJECTS_DIR) + id_list = self._panel_get_list(PANEL_OBJECTS_KEY) + prefix = 'object' + + i = 0 + while i < 1000: + id = '%s_%d' % (prefix, i) + if id not in subdirs and id not in id_list: + return id + i += 1 + + return None + + def _launcher_find_unused(self): + basename = os.path.basename(self.launcher_path) + if not os.path.exists(os.path.join(PANEL_LAUNCHER_USER_DIR, basename)): + return basename + + dot = basename.rfind('.') + prefix = basename[:dot] + extension = basename[dot:] + + i = 0 + while i < 1000: + basename = '%s-%d%s' % (prefix, i, extension) + if not os.path.exists(os.path.join(PANEL_LAUNCHER_USER_DIR, basename)): + return basename + i += 1 + + raise PanelAddException('Copying %s would overwrite existing launchers' % self.launcher_path) + + def _associate_schemas(self, engine, schema_dir, dest_dir): + entries = self.client.all_entries(schema_dir) + for entry in entries: + dest_key = os.path.basename(entry.key) + engine.associate_schema(os.path.join(dest_dir, dest_key), entry.key) + + subdirs = self.client.all_dirs(schema_dir) + for subdir in subdirs: + dest_subdir = os.path.join(subdir) + self._associate_schemas(engine, subdir, os.path.join(dest_dir, dest_subdir)) + + def run(self): + self.client = mateconf.client_get_default () + self._toplevel_id_ensure() + + id = self._object_id_find_unused() + if not id: + raise PanelAddException('No identifier available for the new object') + + if self.type == PANEL_TYPE_APPLET: + dir = os.path.join(MATE_PANEL_APPLETS_DIR, id) + + elif self.type == PANEL_TYPE_LAUNCHER: + dir = os.path.join(PANEL_OBJECTS_DIR, id) + + if self.copy_launcher: + try: + if not os.path.exists(PANEL_LAUNCHER_USER_DIR): + os.makedirs(PANEL_LAUNCHER_USER_DIR) + unused = self._launcher_find_unused() + dest = os.path.join (PANEL_LAUNCHER_USER_DIR, unused) + shutil.copyfile(self.launcher_path, dest) + + launcher_location = unused + except (OSError, IOError), e: + raise PanelAddException('Cannot copy launcher: %s' % e) + else: + launcher_location = 'file://' + urllib.pathname2url(os.path.realpath(self.launcher_path)) + + else: + raise PanelAddException('Unknown panel object type %d' % self.type) + + engine = mateconf.engine_get_default() + self._associate_schemas(engine, PANEL_SCHEMAS_OBJECTS_DIR, dir) + + self.client.set_string(os.path.join(dir, 'toplevel_id'), self.toplevel) + self.client.set_int(os.path.join(dir, 'position'), self.position) + self.client.set_bool(os.path.join(dir, 'panel_right_stick'), self.right_stick) + + if self.type == PANEL_TYPE_APPLET: + self.client.set_string(os.path.join(dir, 'object_type'), 'matecomponent-applet') + self.client.set_string(os.path.join(dir, 'applet_iid'), self.applet_iid) + id_list = self._panel_get_list(MATE_PANEL_APPLETS_KEY) + id_list.append(id) + self.client.set_list(MATE_PANEL_APPLETS_KEY, mateconf.VALUE_STRING, id_list) + + elif self.type == PANEL_TYPE_LAUNCHER: + self.client.set_string(os.path.join(dir, 'object_type'), 'launcher-object') + self.client.set_string(os.path.join(dir, 'launcher_location'), launcher_location) + id_list = self._panel_get_list(PANEL_OBJECTS_KEY) + id_list.append(id) + self.client.set_list(PANEL_OBJECTS_KEY, mateconf.VALUE_STRING, id_list) + + else: + raise PanelAddException('Unknown panel object type %d' % self.type) + +def main(args): + parser = optparse.OptionParser() + + parser.add_option('--applet', dest='applet', + help='Applet to add') + parser.add_option('--copy-launcher', dest='copy_launcher', + action='store_true', default=False, + help='Copy the launcher to the user directory') + parser.add_option('--launcher', dest='launcher', + help='Launcher to add') + parser.add_option('--panel', dest='toplevel', + help='Identifier of the panel where to add the applet') + parser.add_option('--position', dest='position', + help='Position on the panel where to add the applet') + parser.add_option('--right-stick', dest='right_stick', + action='store_true', default=False, + help='Make the applet right-aligned on the panel') + + (options, args) = parser.parse_args() + + if not options.applet and not options.launcher: + print parser.format_help() + return 1 + + if options.applet and options.launcher: + raise PanelAddException('Cannot add an applet and a launcher at the same time') + + if options.position: + try: + position = int(options.position) + except ValueError: + raise PanelAddException('%s is not an integer, required for position' % options.position) + else: + position = -1 + + adder = PanelAdder(options.toplevel, position, options.right_stick, options.applet, options.launcher, options.copy_launcher) + adder.run() + +if __name__ == '__main__': + try: + main(sys.argv) + except PanelAddException, e: + print >> sys.stderr, e + sys.exit(1) + except KeyboardInterrupt: + pass diff --git a/mate-panel/mate-panel-applet-frame.c b/mate-panel/mate-panel-applet-frame.c new file mode 100644 index 00000000..12f1c103 --- /dev/null +++ b/mate-panel/mate-panel-applet-frame.c @@ -0,0 +1,1002 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * mate-panel-applet-frame.c: panel side container for applets + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include +#include + +#include + +#include +#include +#include + +#include "mate-panel-applets-manager.h" +#include "panel-profile.h" +#include "panel.h" +#include "applet.h" +#include "panel-marshal.h" +#include "panel-background.h" +#include "panel-lockdown.h" +#include "panel-stock-icons.h" +#include "xstuff.h" +#include "panel-compatibility.h" + +#include "mate-panel-applet-frame.h" + +static void mate_panel_applet_frame_activating_free (MatePanelAppletFrameActivating *frame_act); + +static void mate_panel_applet_frame_loading_failed (const char *iid, + PanelWidget *panel, + const char *id); + +static void mate_panel_applet_frame_load (const gchar *iid, + PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id); + +struct _MatePanelAppletFrameActivating { + gboolean locked; + PanelWidget *panel; + int position; + gboolean exactpos; + char *id; +}; + +/* MatePanelAppletFrame implementation */ + +G_DEFINE_TYPE (MatePanelAppletFrame, mate_panel_applet_frame, GTK_TYPE_EVENT_BOX) + +#define MATE_PANEL_APPLET_FRAME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_APPLET_FRAME, MatePanelAppletFramePrivate)) + +#define HANDLE_SIZE 10 +#define MATE_PANEL_APPLET_PREFS_KEY "/apps/panel/applets/%s/prefs" + +struct _MatePanelAppletFramePrivate { + PanelWidget *panel; + AppletInfo *applet_info; + + PanelOrientation orientation; + + gchar *iid; + + GtkAllocation child_allocation; + GdkRectangle handle_rect; + + guint has_handle : 1; +}; + +static void +mate_panel_applet_frame_paint (GtkWidget *widget, + GdkRectangle *area) +{ + MatePanelAppletFrame *frame; + + frame = MATE_PANEL_APPLET_FRAME (widget); + + if (!frame->priv->has_handle) + return; + + if (gtk_widget_is_drawable (widget)) { + GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL; + + switch (frame->priv->orientation) { + case PANEL_ORIENTATION_TOP: + case PANEL_ORIENTATION_BOTTOM: + orientation = GTK_ORIENTATION_VERTICAL; + break; + case PANEL_ORIENTATION_LEFT: + case PANEL_ORIENTATION_RIGHT: + orientation = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_assert_not_reached (); + break; + } + + gtk_paint_handle ( + gtk_widget_get_style (widget), gtk_widget_get_window (widget), + gtk_widget_get_state (widget), + GTK_SHADOW_OUT, + area, widget, "handlebox", + frame->priv->handle_rect.x, + frame->priv->handle_rect.y, + frame->priv->handle_rect.width, + frame->priv->handle_rect.height, + orientation); + } +} + +static gboolean mate_panel_applet_frame_expose(GtkWidget* widget, GdkEventExpose* event) +{ + if (gtk_widget_is_drawable (widget)) + { + GTK_WIDGET_CLASS (mate_panel_applet_frame_parent_class)->expose_event (widget, event); + + mate_panel_applet_frame_paint (widget, &event->area); + } + + return FALSE; +} + +static void +mate_panel_applet_frame_update_background_size (MatePanelAppletFrame *frame, + GtkAllocation *old_allocation, + GtkAllocation *new_allocation) +{ + PanelBackground *background; + + if (old_allocation->x == new_allocation->x && + old_allocation->y == new_allocation->y && + old_allocation->width == new_allocation->width && + old_allocation->height == new_allocation->height) + return; + + background = &frame->priv->panel->background; + + if (background->type == PANEL_BACK_NONE || + (background->type == PANEL_BACK_COLOR && !background->has_alpha)) + return; + + mate_panel_applet_frame_change_background (frame, background->type); +} + +static void +mate_panel_applet_frame_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + MatePanelAppletFrame *frame; + GtkBin *bin; + GtkWidget *child; + GtkRequisition child_requisition; + guint border_width; + + frame = MATE_PANEL_APPLET_FRAME (widget); + bin = GTK_BIN (widget); + + if (!frame->priv->has_handle) { + GTK_WIDGET_CLASS (mate_panel_applet_frame_parent_class)->size_request (widget, requisition); + return; + } + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) { + gtk_widget_size_request (child, &child_requisition); + + requisition->width = child_requisition.width; + requisition->height = child_requisition.height; + } + + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + requisition->width += border_width; + requisition->height += border_width; + + switch (frame->priv->orientation) { + case PANEL_ORIENTATION_TOP: + case PANEL_ORIENTATION_BOTTOM: + requisition->width += HANDLE_SIZE; + break; + case PANEL_ORIENTATION_LEFT: + case PANEL_ORIENTATION_RIGHT: + requisition->height += HANDLE_SIZE; + break; + default: + g_assert_not_reached (); + break; + } +} + +static void +mate_panel_applet_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + MatePanelAppletFrame *frame; + GtkBin *bin; + GtkWidget *child; + GdkWindow *window; + GtkAllocation new_allocation; + GtkAllocation old_allocation; + GtkAllocation widget_allocation; + + gtk_widget_get_allocation (widget, &widget_allocation); + + old_allocation.x = widget_allocation.x; + old_allocation.y = widget_allocation.y; + old_allocation.width = widget_allocation.width; + old_allocation.height = widget_allocation.height; + + frame = MATE_PANEL_APPLET_FRAME (widget); + bin = GTK_BIN (widget); + + if (!frame->priv->has_handle) { + GTK_WIDGET_CLASS (mate_panel_applet_frame_parent_class)->size_allocate (widget, allocation); + mate_panel_applet_frame_update_background_size (frame, &old_allocation, allocation); + return; + } + + window = gtk_widget_get_window (widget); + child = gtk_bin_get_child (bin); + gtk_widget_set_allocation (widget, allocation); + + frame->priv->handle_rect.x = 0; + frame->priv->handle_rect.y = 0; + + switch (frame->priv->orientation) { + case PANEL_ORIENTATION_TOP: + case PANEL_ORIENTATION_BOTTOM: + frame->priv->handle_rect.width = HANDLE_SIZE; + frame->priv->handle_rect.height = allocation->height; + + if (gtk_widget_get_direction (GTK_WIDGET (frame)) != + GTK_TEXT_DIR_RTL) { + frame->priv->handle_rect.x = 0; + new_allocation.x = HANDLE_SIZE; + } else { + frame->priv->handle_rect.x = allocation->width - HANDLE_SIZE; + new_allocation.x = 0; + } + + new_allocation.y = 0; + new_allocation.width = allocation->width - HANDLE_SIZE; + new_allocation.height = allocation->height; + break; + case PANEL_ORIENTATION_LEFT: + case PANEL_ORIENTATION_RIGHT: + frame->priv->handle_rect.width = allocation->width; + frame->priv->handle_rect.height = HANDLE_SIZE; + + new_allocation.x = 0; + new_allocation.y = HANDLE_SIZE; + new_allocation.width = allocation->width; + new_allocation.height = allocation->height - HANDLE_SIZE; + break; + default: + g_assert_not_reached (); + break; + } + + new_allocation.width = MAX (1, new_allocation.width); + new_allocation.height = MAX (1, new_allocation.height); + + /* If the child allocation changed, that means that the frame is drawn + * in a new place, so we must redraw the entire widget. + */ + if (gtk_widget_get_mapped (widget) && + (new_allocation.x != frame->priv->child_allocation.x || + new_allocation.y != frame->priv->child_allocation.y || + new_allocation.width != frame->priv->child_allocation.width || + new_allocation.height != frame->priv->child_allocation.height)) + gdk_window_invalidate_rect (window, &widget_allocation, FALSE); + + if (gtk_widget_get_realized (widget)) { + guint border_width; + + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + gdk_window_move_resize (window, + allocation->x + border_width, + allocation->y + border_width, + MAX (allocation->width - border_width * 2, 0), + MAX (allocation->height - border_width * 2, 0)); + } + + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_allocate (child, &new_allocation); + + frame->priv->child_allocation = new_allocation; + + mate_panel_applet_frame_update_background_size (frame, + &old_allocation, + allocation); +} + +static inline gboolean +button_event_in_rect (GdkEventButton *event, + GdkRectangle *rect) +{ + if (event->x >= rect->x && + event->x <= (rect->x + rect->width) && + event->y >= rect->y && + event->y <= (rect->y + rect->height)) + return TRUE; + + return FALSE; +} + +static gboolean +mate_panel_applet_frame_button_changed (GtkWidget *widget, + GdkEventButton *event) +{ + MatePanelAppletFrame *frame; + gboolean handled = FALSE; + + frame = MATE_PANEL_APPLET_FRAME (widget); + + if (!frame->priv->has_handle) + return handled; + + if (event->window != gtk_widget_get_window (widget)) + return FALSE; + + switch (event->button) { + case 1: + case 2: + if (button_event_in_rect (event, &frame->priv->handle_rect)) { + if (event->type == GDK_BUTTON_PRESS || + event->type == GDK_2BUTTON_PRESS) { + panel_widget_applet_drag_start ( + frame->priv->panel, GTK_WIDGET (frame), + PW_DRAG_OFF_CURSOR, event->time); + handled = TRUE; + } else if (event->type == GDK_BUTTON_RELEASE) { + panel_widget_applet_drag_end (frame->priv->panel); + handled = TRUE; + } + } + break; + case 3: + if (event->type == GDK_BUTTON_PRESS || + event->type == GDK_2BUTTON_PRESS) { + gdk_pointer_ungrab (GDK_CURRENT_TIME); + + MATE_PANEL_APPLET_FRAME_GET_CLASS (frame)->popup_menu (frame, + event->button, + event->time); + + handled = TRUE; + } else if (event->type == GDK_BUTTON_RELEASE) + handled = TRUE; + break; + default: + break; + } + + return handled; +} + +static void +mate_panel_applet_frame_finalize (GObject *object) +{ + MatePanelAppletFrame *frame = MATE_PANEL_APPLET_FRAME (object); + + mate_panel_applets_manager_factory_deactivate (frame->priv->iid); + + panel_lockdown_notify_remove (G_CALLBACK (mate_panel_applet_frame_sync_menu_state), + frame); + + g_free (frame->priv->iid); + frame->priv->iid = NULL; + + G_OBJECT_CLASS (mate_panel_applet_frame_parent_class)->finalize (object); +} + +static void +mate_panel_applet_frame_class_init (MatePanelAppletFrameClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + gobject_class->finalize = mate_panel_applet_frame_finalize; + + widget_class->expose_event = mate_panel_applet_frame_expose; + widget_class->size_request = mate_panel_applet_frame_size_request; + widget_class->size_allocate = mate_panel_applet_frame_size_allocate; + widget_class->button_press_event = mate_panel_applet_frame_button_changed; + widget_class->button_release_event = mate_panel_applet_frame_button_changed; + + g_type_class_add_private (klass, sizeof (MatePanelAppletFramePrivate)); +} + +static void +mate_panel_applet_frame_init (MatePanelAppletFrame *frame) +{ + frame->priv = MATE_PANEL_APPLET_FRAME_GET_PRIVATE (frame); + + frame->priv->panel = NULL; + frame->priv->orientation = PANEL_ORIENTATION_TOP; + frame->priv->applet_info = NULL; + frame->priv->has_handle = FALSE; +} + +static void +mate_panel_applet_frame_init_properties (MatePanelAppletFrame *frame) +{ + MATE_PANEL_APPLET_FRAME_GET_CLASS (frame)->init_properties (frame); +} + +void +mate_panel_applet_frame_sync_menu_state (MatePanelAppletFrame *frame) +{ + PanelWidget *panel_widget; + gboolean locked_down; + gboolean locked; + gboolean lockable; + gboolean movable; + gboolean removable; + + panel_widget = PANEL_WIDGET (gtk_widget_get_parent (GTK_WIDGET (frame))); + + movable = mate_panel_applet_can_freely_move (frame->priv->applet_info); + removable = panel_profile_id_lists_are_writable (); + lockable = mate_panel_applet_lockable (frame->priv->applet_info); + + locked = panel_widget_get_applet_locked (panel_widget, GTK_WIDGET (frame)); + locked_down = panel_lockdown_get_locked_down (); + + MATE_PANEL_APPLET_FRAME_GET_CLASS (frame)->sync_menu_state (frame, movable, removable, lockable, locked, locked_down); +} + +void +mate_panel_applet_frame_change_orientation (MatePanelAppletFrame *frame, + PanelOrientation orientation) +{ + if (orientation == frame->priv->orientation) + return; + + frame->priv->orientation = orientation; + MATE_PANEL_APPLET_FRAME_GET_CLASS (frame)->change_orientation (frame, orientation); +} + +void +mate_panel_applet_frame_change_size (MatePanelAppletFrame *frame, + guint size) +{ + MATE_PANEL_APPLET_FRAME_GET_CLASS (frame)->change_size (frame, size); +} + +void +mate_panel_applet_frame_change_background (MatePanelAppletFrame *frame, + PanelBackgroundType type) +{ + GtkWidget *parent; + + g_return_if_fail (PANEL_IS_APPLET_FRAME (frame)); + + parent = gtk_widget_get_parent (GTK_WIDGET (frame)); + + g_return_if_fail (PANEL_IS_WIDGET (parent)); + + if (frame->priv->has_handle) { + PanelBackground *background; + + background = &PANEL_WIDGET (parent)->background; + panel_background_change_background_on_widget (background, + GTK_WIDGET (frame)); + } + + MATE_PANEL_APPLET_FRAME_GET_CLASS (frame)->change_background (frame, type); +} + +void +mate_panel_applet_frame_set_panel (MatePanelAppletFrame *frame, + PanelWidget *panel) +{ + g_return_if_fail (PANEL_IS_APPLET_FRAME (frame)); + g_return_if_fail (PANEL_IS_WIDGET (panel)); + + frame->priv->panel = panel; +} + +void +_mate_panel_applet_frame_set_iid (MatePanelAppletFrame *frame, + const gchar *iid) +{ + if (frame->priv->iid) + g_free (frame->priv->iid); + frame->priv->iid = g_strdup (iid); +} + +void +_mate_panel_applet_frame_activated (MatePanelAppletFrame *frame, + MatePanelAppletFrameActivating *frame_act, + GError *error) +{ + AppletInfo *info; + + g_assert (frame->priv->iid != NULL); + + if (error != NULL) { + g_warning ("Failed to load applet %s:\n%s", + frame->priv->iid, error->message); + g_error_free (error); + + mate_panel_applet_frame_loading_failed (frame->priv->iid, + frame_act->panel, + frame_act->id); + mate_panel_applet_frame_activating_free (frame_act); + gtk_widget_destroy (GTK_WIDGET (frame)); + + return; + } + + frame->priv->panel = frame_act->panel; + gtk_widget_show_all (GTK_WIDGET (frame)); + + info = mate_panel_applet_register (GTK_WIDGET (frame), GTK_WIDGET (frame), + NULL, frame->priv->panel, + frame_act->locked, frame_act->position, + frame_act->exactpos, PANEL_OBJECT_APPLET, + frame_act->id); + frame->priv->applet_info = info; + + panel_widget_set_applet_size_constrained (frame->priv->panel, + GTK_WIDGET (frame), TRUE); + + mate_panel_applet_frame_sync_menu_state (frame); + mate_panel_applet_frame_init_properties (frame); + + panel_lockdown_notify_add (G_CALLBACK (mate_panel_applet_frame_sync_menu_state), + frame); + + mate_panel_applet_stop_loading (frame_act->id); + mate_panel_applet_frame_activating_free (frame_act); +} + +void +_mate_panel_applet_frame_update_flags (MatePanelAppletFrame *frame, + gboolean major, + gboolean minor, + gboolean has_handle) +{ + gboolean old_has_handle; + + panel_widget_set_applet_expandable ( + frame->priv->panel, GTK_WIDGET (frame), major, minor); + + old_has_handle = frame->priv->has_handle; + frame->priv->has_handle = has_handle; + + if (!old_has_handle && frame->priv->has_handle) { + /* we've added an handle, so we need to get the background for + * it */ + PanelBackground *background; + + background = &frame->priv->panel->background; + mate_panel_applet_frame_change_background (frame, background->type); + } +} + +void +_mate_panel_applet_frame_update_size_hints (MatePanelAppletFrame *frame, + gint *size_hints, + guint n_elements) +{ + if (frame->priv->has_handle) { + gint extra_size = HANDLE_SIZE + 1; + gint i; + + for (i = 0; i < n_elements; i++) + size_hints[i] += extra_size; + } + + /* It takes the ownership of size-hints array */ + panel_widget_set_applet_size_hints (frame->priv->panel, + GTK_WIDGET (frame), + size_hints, + n_elements); +} + +char * +_mate_panel_applet_frame_get_background_string (MatePanelAppletFrame *frame, + PanelWidget *panel, + PanelBackgroundType type) +{ + GtkAllocation allocation; + int x; + int y; + + gtk_widget_get_allocation (GTK_WIDGET (frame), &allocation); + + x = allocation.x; + y = allocation.y; + + if (frame->priv->has_handle) { + switch (frame->priv->orientation) { + case PANEL_ORIENTATION_TOP: + case PANEL_ORIENTATION_BOTTOM: + if (gtk_widget_get_direction (GTK_WIDGET (frame)) != + GTK_TEXT_DIR_RTL) + x += frame->priv->handle_rect.width; + break; + case PANEL_ORIENTATION_LEFT: + case PANEL_ORIENTATION_RIGHT: + y += frame->priv->handle_rect.height; + break; + default: + g_assert_not_reached (); + break; + } + } + + return panel_background_make_string (&panel->background, x, y); +} + +static void +mate_panel_applet_frame_reload_response (GtkWidget *dialog, + int response, + MatePanelAppletFrame *frame) +{ + AppletInfo *info; + + g_return_if_fail (PANEL_IS_APPLET_FRAME (frame)); + + if (!frame->priv->iid || !frame->priv->panel) { + g_object_unref (frame); + gtk_widget_destroy (dialog); + return; + } + + info = frame->priv->applet_info; + + if (response == GTK_RESPONSE_YES) { + PanelWidget *panel; + char *iid; + char *id = NULL; + int position = -1; + gboolean locked = FALSE; + + panel = frame->priv->panel; + iid = g_strdup (frame->priv->iid); + + if (info) { + id = g_strdup (info->id); + position = mate_panel_applet_get_position (info); + locked = panel_widget_get_applet_locked (panel, info->widget); + mate_panel_applet_clean (info); + } + + mate_panel_applet_frame_load (iid, panel, locked, + position, TRUE, id); + + g_free (iid); + g_free (id); + + } else if (info) { + /* if we can't write to applets list we can't really delete + it, so we'll just ignore this. FIXME: handle this + more correctly I suppose. */ + if (panel_profile_id_lists_are_writable ()) + panel_profile_delete_object (info); + } + + g_object_unref (frame); + gtk_widget_destroy (dialog); +} + +void +_mate_panel_applet_frame_applet_broken (MatePanelAppletFrame *frame) +{ + GtkWidget *dialog; + GdkScreen *screen; + const char *applet_name = NULL; + char *dialog_txt; + + screen = gtk_widget_get_screen (GTK_WIDGET (frame)); + + if (xstuff_is_display_dead ()) + return; + + if (frame->priv->iid) { + MatePanelAppletInfo *info; + + info = (MatePanelAppletInfo *)mate_panel_applets_manager_get_applet_info (frame->priv->iid); + applet_name = mate_panel_applet_info_get_name (info); + } + + if (applet_name) + dialog_txt = g_strdup_printf (_("\"%s\" has quit unexpectedly"), applet_name); + else + dialog_txt = g_strdup (_("Panel object has quit unexpectedly")); + + dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, + dialog_txt, applet_name ? applet_name : NULL); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("If you reload a panel object, it will automatically " + "be added back to the panel.")); + + gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("_Don't Reload"), GTK_RESPONSE_NO, + _("_Reload"), GTK_RESPONSE_YES, + NULL); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_YES); + + gtk_window_set_screen (GTK_WINDOW (dialog), screen); + + g_signal_connect (dialog, "response", + G_CALLBACK (mate_panel_applet_frame_reload_response), + g_object_ref (frame)); + + panel_widget_register_open_dialog (frame->priv->panel, dialog); + gtk_window_set_urgency_hint (GTK_WINDOW (dialog), TRUE); + /* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=165132 */ + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + + gtk_widget_show (dialog); + g_free (dialog_txt); +} + +void +_mate_panel_applet_frame_applet_remove (MatePanelAppletFrame *frame) +{ + AppletInfo *info; + + if (!frame->priv->applet_info) + return; + + info = frame->priv->applet_info; + frame->priv->applet_info = NULL; + + panel_profile_delete_object (info); +} + +void +_mate_panel_applet_frame_applet_move (MatePanelAppletFrame *frame) +{ + GtkWidget *widget = GTK_WIDGET (frame); + GtkWidget *parent = gtk_widget_get_parent (widget); + + if (!PANEL_IS_WIDGET (parent)) + return; + + panel_widget_applet_drag_start (PANEL_WIDGET (parent), + widget, + PW_DRAG_OFF_CENTER, + GDK_CURRENT_TIME); +} + +void +_mate_panel_applet_frame_applet_lock (MatePanelAppletFrame *frame, + gboolean locked) +{ + PanelWidget *panel_widget = PANEL_WIDGET (gtk_widget_get_parent (GTK_WIDGET (frame))); + + if (panel_widget_get_applet_locked (panel_widget, GTK_WIDGET (frame)) == locked) + return; + + mate_panel_applet_toggle_locked (frame->priv->applet_info); +} + +/* Generic methods */ + +static GSList *no_reload_applets = NULL; + +enum { + LOADING_FAILED_RESPONSE_DONT_DELETE, + LOADING_FAILED_RESPONSE_DELETE +}; + +static void +mate_panel_applet_frame_activating_free (MatePanelAppletFrameActivating *frame_act) +{ + g_free (frame_act->id); + g_slice_free (MatePanelAppletFrameActivating, frame_act); +} + +PanelOrientation +mate_panel_applet_frame_activating_get_orientation(MatePanelAppletFrameActivating *frame_act) +{ + return panel_widget_get_applet_orientation(frame_act->panel); +} + +guint32 +mate_panel_applet_frame_activating_get_size (MatePanelAppletFrameActivating *frame_act) +{ + return frame_act->panel->sz; +} + +gboolean +mate_panel_applet_frame_activating_get_locked (MatePanelAppletFrameActivating *frame_act) +{ + return frame_act->locked; +} + +gboolean +mate_panel_applet_frame_activating_get_locked_down (MatePanelAppletFrameActivating *frame_act) +{ + return panel_lockdown_get_locked_down (); +} + +gchar * +mate_panel_applet_frame_activating_get_conf_path (MatePanelAppletFrameActivating *frame_act) +{ + return g_strdup_printf (MATE_PANEL_APPLET_PREFS_KEY, frame_act->id); +} + +static void +mate_panel_applet_frame_loading_failed_response (GtkWidget *dialog, + guint response, + char *id) +{ + gtk_widget_destroy (dialog); + + if (response == LOADING_FAILED_RESPONSE_DELETE && + !panel_lockdown_get_locked_down () && + panel_profile_id_lists_are_writable ()) { + GSList *item; + + item = g_slist_find_custom (no_reload_applets, id, + (GCompareFunc) strcmp); + if (item) { + g_free (item->data); + no_reload_applets = g_slist_delete_link (no_reload_applets, + item); + } + + panel_profile_remove_from_list (PANEL_MATECONF_APPLETS, id); + } + + g_free (id); +} + +static void +mate_panel_applet_frame_loading_failed (const char *iid, + PanelWidget *panel, + const char *id) +{ + GtkWidget *dialog; + char *problem_txt; + gboolean locked_down; + + no_reload_applets = g_slist_prepend (no_reload_applets, + g_strdup (id)); + + locked_down = panel_lockdown_get_locked_down (); + + problem_txt = g_strdup_printf (_("The panel encountered a problem " + "while loading \"%s\"."), + iid); + + dialog = gtk_message_dialog_new (NULL, 0, + locked_down ? GTK_MESSAGE_INFO : GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + "%s", problem_txt); + g_free (problem_txt); + + if (locked_down) { + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_OK, LOADING_FAILED_RESPONSE_DONT_DELETE, + NULL); + } else { + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Do you want to delete the applet " + "from your configuration?")); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + PANEL_STOCK_DONT_DELETE, LOADING_FAILED_RESPONSE_DONT_DELETE, + GTK_STOCK_DELETE, LOADING_FAILED_RESPONSE_DELETE, + NULL); + } + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + LOADING_FAILED_RESPONSE_DONT_DELETE); + + gtk_window_set_screen (GTK_WINDOW (dialog), + gtk_window_get_screen (GTK_WINDOW (panel->toplevel))); + + g_signal_connect (dialog, "response", + G_CALLBACK (mate_panel_applet_frame_loading_failed_response), + g_strdup (id)); + + panel_widget_register_open_dialog (panel, dialog); + gtk_window_set_urgency_hint (GTK_WINDOW (dialog), TRUE); + /* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=165132 */ + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + + gtk_widget_show_all (dialog); + + /* Note: this call will free the memory for id, so the variable should + * not get accessed afterwards. */ + mate_panel_applet_stop_loading (id); +} + +static void +mate_panel_applet_frame_load (const gchar *iid, + PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id) +{ + MatePanelAppletFrameActivating *frame_act; + + g_return_if_fail (iid != NULL); + g_return_if_fail (panel != NULL); + g_return_if_fail (id != NULL); + + if (g_slist_find_custom (no_reload_applets, id, + (GCompareFunc) strcmp)) { + mate_panel_applet_stop_loading (id); + return; + } + + if (panel_lockdown_is_applet_disabled (iid)) { + mate_panel_applet_stop_loading (id); + return; + } + + frame_act = g_slice_new0 (MatePanelAppletFrameActivating); + frame_act->locked = locked; + frame_act->panel = panel; + frame_act->position = position; + frame_act->exactpos = exactpos; + frame_act->id = g_strdup (id); + + if (!mate_panel_applets_manager_load_applet (iid, frame_act)) { + mate_panel_applet_frame_loading_failed (iid, panel, id); + mate_panel_applet_frame_activating_free (frame_act); + } +} + +void +mate_panel_applet_frame_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + int position, + const char *id) +{ + gchar *applet_iid; + + g_return_if_fail (panel_widget != NULL); + g_return_if_fail (id != NULL); + + applet_iid = panel_compatibility_get_applet_iid (id); + if (!applet_iid) { + mate_panel_applet_stop_loading (id); + return; + } + + mate_panel_applet_frame_load (applet_iid, panel_widget, + locked, position, TRUE, id); + + g_free (applet_iid); +} + +void +mate_panel_applet_frame_create (PanelToplevel *toplevel, + int position, + const char *iid) +{ + MateConfClient *client; + const char *key; + char *id; + + g_return_if_fail (iid != NULL); + + client = panel_mateconf_get_client (); + + id = panel_profile_prepare_object (PANEL_OBJECT_APPLET, toplevel, position, FALSE); + + key = panel_mateconf_full_key (PANEL_MATECONF_APPLETS, id, "applet_iid"); + mateconf_client_set_string (client, key, iid, NULL); + + panel_profile_add_to_list (PANEL_MATECONF_APPLETS, id); + + g_free (id); +} diff --git a/mate-panel/mate-panel-applet-frame.h b/mate-panel/mate-panel-applet-frame.h new file mode 100644 index 00000000..d8518830 --- /dev/null +++ b/mate-panel/mate-panel-applet-frame.h @@ -0,0 +1,146 @@ +/* + * mate-panel-applet-frame.h: panel side container for applets + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __MATE_PANEL_APPLET_FRAME_H__ +#define __MATE_PANEL_APPLET_FRAME_H__ + +#include + +#include "panel-widget.h" +#include "applet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_APPLET_FRAME (mate_panel_applet_frame_get_type ()) +#define MATE_PANEL_APPLET_FRAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_APPLET_FRAME, MatePanelAppletFrame)) +#define MATE_PANEL_APPLET_FRAME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_APPLET_FRAME, MatePanelAppletFrameClass)) +#define PANEL_IS_APPLET_FRAME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_APPLET_FRAME)) +#define PANEL_IS_APPLET_FRAME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_APPLET_FRAME)) +#define MATE_PANEL_APPLET_FRAME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_APPLET_FRAME, MatePanelAppletFrameClass)) + +typedef struct _MatePanelAppletFrame MatePanelAppletFrame; +typedef struct _MatePanelAppletFrameClass MatePanelAppletFrameClass; +typedef struct _MatePanelAppletFramePrivate MatePanelAppletFramePrivate; + +struct _MatePanelAppletFrameClass { + GtkEventBoxClass parent_class; + + void (*init_properties) (MatePanelAppletFrame *frame); + + void (*sync_menu_state) (MatePanelAppletFrame *frame, + gboolean movable, + gboolean removable, + gboolean lockable, + gboolean locked, + gboolean locked_down); + + void (*popup_menu) (MatePanelAppletFrame *frame, + guint button, + guint32 timestamp); + + void (*change_orientation) (MatePanelAppletFrame *frame, + PanelOrientation orientation); + + void (*change_size) (MatePanelAppletFrame *frame, + guint size); + + void (*change_background) (MatePanelAppletFrame *frame, + PanelBackgroundType type); +}; + +struct _MatePanelAppletFrame { + GtkEventBox parent; + + MatePanelAppletFramePrivate *priv; +}; + +GType mate_panel_applet_frame_get_type (void) G_GNUC_CONST; + +void mate_panel_applet_frame_create (PanelToplevel *toplevel, + int position, + const char *iid); + +void mate_panel_applet_frame_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + int position, + const char *id); + +void mate_panel_applet_frame_sync_menu_state (MatePanelAppletFrame *frame); + +void mate_panel_applet_frame_change_orientation (MatePanelAppletFrame *frame, + PanelOrientation orientation); + +void mate_panel_applet_frame_change_size (MatePanelAppletFrame *frame, + guint size); + +void mate_panel_applet_frame_change_background (MatePanelAppletFrame *frame, + PanelBackgroundType type); + +void mate_panel_applet_frame_set_panel (MatePanelAppletFrame *frame, + PanelWidget *panel); + + +/* For module implementations only */ + +typedef struct _MatePanelAppletFrameActivating MatePanelAppletFrameActivating; + +PanelOrientation mate_panel_applet_frame_activating_get_orientation (MatePanelAppletFrameActivating *frame_act); +guint32 mate_panel_applet_frame_activating_get_size (MatePanelAppletFrameActivating *frame_act); +gboolean mate_panel_applet_frame_activating_get_locked (MatePanelAppletFrameActivating *frame_act); +gboolean mate_panel_applet_frame_activating_get_locked_down (MatePanelAppletFrameActivating *frame_act); +gchar *mate_panel_applet_frame_activating_get_conf_path (MatePanelAppletFrameActivating *frame_act); + +void _mate_panel_applet_frame_set_iid (MatePanelAppletFrame *frame, + const gchar *iid); + +void _mate_panel_applet_frame_activated (MatePanelAppletFrame *frame, + MatePanelAppletFrameActivating *frame_act, + GError *error); + +void _mate_panel_applet_frame_update_flags (MatePanelAppletFrame *frame, + gboolean major, + gboolean minor, + gboolean has_handle); + +void _mate_panel_applet_frame_update_size_hints (MatePanelAppletFrame *frame, + gint *size_hints, + guint n_elements); + +char *_mate_panel_applet_frame_get_background_string (MatePanelAppletFrame *frame, + PanelWidget *panel, + PanelBackgroundType type); + +void _mate_panel_applet_frame_applet_broken (MatePanelAppletFrame *frame); + +void _mate_panel_applet_frame_applet_remove (MatePanelAppletFrame *frame); +void _mate_panel_applet_frame_applet_move (MatePanelAppletFrame *frame); +void _mate_panel_applet_frame_applet_lock (MatePanelAppletFrame *frame, + gboolean locked); +#ifdef __cplusplus +} +#endif + +#endif /* __MATE_PANEL_APPLET_FRAME_H__ */ diff --git a/mate-panel/mate-panel-applet-info.c b/mate-panel/mate-panel-applet-info.c new file mode 100644 index 00000000..123b0806 --- /dev/null +++ b/mate-panel/mate-panel-applet-info.c @@ -0,0 +1,113 @@ +/* + * mate-panel-applet-info.c + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "mate-panel-applet-info.h" + +struct _MatePanelAppletInfo { + gchar *iid; + + gchar *name; + gchar *comment; + gchar *icon; + + gchar **old_ids; +}; + +MatePanelAppletInfo * +mate_panel_applet_info_new (const gchar *iid, + const gchar *name, + const gchar *comment, + const gchar *icon, + const gchar **old_ids) +{ + MatePanelAppletInfo *info; + int len; + + info = g_slice_new0 (MatePanelAppletInfo); + + info->iid = g_strdup (iid); + info->name = g_strdup (name); + info->comment = g_strdup (comment); + info->icon = g_strdup (icon); + + /* MateComponent compatibility */ + if (old_ids != NULL) { + len = g_strv_length ((gchar **) old_ids); + if (len > 0) { + int i; + + info->old_ids = g_new0 (gchar *, len + 1); + + for (i = 0; i < len; i++) + info->old_ids[i] = g_strdup (old_ids[i]); + } + } + + return info; +} + +void +mate_panel_applet_info_free (MatePanelAppletInfo *info) +{ + if (!info) + return; + + g_free (info->iid); + g_free (info->name); + g_free (info->comment); + g_free (info->icon); + g_strfreev (info->old_ids); + + g_slice_free (MatePanelAppletInfo, info); +} + +const gchar * +mate_panel_applet_info_get_iid (MatePanelAppletInfo *info) +{ + return info->iid; +} + +const gchar * +mate_panel_applet_info_get_name (MatePanelAppletInfo *info) +{ + return info->name; +} + +const gchar * +mate_panel_applet_info_get_description (MatePanelAppletInfo *info) +{ + return info->comment; +} + +const gchar * +mate_panel_applet_info_get_icon (MatePanelAppletInfo *info) +{ + return info->icon; +} + +const gchar * const * +mate_panel_applet_info_get_old_ids (MatePanelAppletInfo *info) +{ + return (const gchar * const *) info->old_ids; +} diff --git a/mate-panel/mate-panel-applet-info.h b/mate-panel/mate-panel-applet-info.h new file mode 100644 index 00000000..264c0730 --- /dev/null +++ b/mate-panel/mate-panel-applet-info.h @@ -0,0 +1,51 @@ +/* + * mate-panel-applet-info.h + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __MATE_PANEL_APPLET_INFO_H__ +#define __MATE_PANEL_APPLET_INFO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _MatePanelAppletInfo MatePanelAppletInfo; + +MatePanelAppletInfo *mate_panel_applet_info_new (const gchar *iid, + const gchar *name, + const gchar *comment, + const gchar *icon, + const gchar **old_ids); +void mate_panel_applet_info_free (MatePanelAppletInfo *info); + +const gchar *mate_panel_applet_info_get_iid (MatePanelAppletInfo *info); +const gchar *mate_panel_applet_info_get_name (MatePanelAppletInfo *info); +const gchar *mate_panel_applet_info_get_description (MatePanelAppletInfo *info); +const gchar *mate_panel_applet_info_get_icon (MatePanelAppletInfo *info); +const gchar * const *mate_panel_applet_info_get_old_ids (MatePanelAppletInfo *info); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATE_PANEL_APPLET_INFO_H__ */ diff --git a/mate-panel/mate-panel-applets-manager.c b/mate-panel/mate-panel-applets-manager.c new file mode 100644 index 00000000..347176e4 --- /dev/null +++ b/mate-panel/mate-panel-applets-manager.c @@ -0,0 +1,201 @@ +/* + * mate-panel-applets-manager.c + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#include + +#include "panel-modules.h" + +#include "mate-panel-applets-manager.h" + +G_DEFINE_ABSTRACT_TYPE (MatePanelAppletsManager, mate_panel_applets_manager, G_TYPE_OBJECT) + +static void +mate_panel_applets_manager_init (MatePanelAppletsManager *manager) +{ +} + +static void +mate_panel_applets_manager_class_init (MatePanelAppletsManagerClass *class) +{ +} + +/* Generic methods */ + +static GSList *mate_panel_applets_managers = NULL; + +static void +_mate_panel_applets_manager_cleanup (gpointer data) +{ + g_slist_foreach (mate_panel_applets_managers, (GFunc) g_object_unref, NULL); + g_slist_free (mate_panel_applets_managers); + mate_panel_applets_managers = NULL; +} + +static void +_mate_panel_applets_managers_ensure_loaded (void) +{ + GIOExtensionPoint *point; + GList *extensions, *l; + + if (mate_panel_applets_managers != NULL) + return; + + panel_cleanup_register (PANEL_CLEAN_FUNC (_mate_panel_applets_manager_cleanup), NULL); + + panel_modules_ensure_loaded (); + + point = g_io_extension_point_lookup (MATE_PANEL_APPLETS_MANAGER_EXTENSION_POINT_NAME); + + extensions = g_io_extension_point_get_extensions (point); + + if (extensions == NULL) + g_error ("No MatePanelAppletsManager implementations exist."); + + for (l = extensions; l != NULL; l = l->next) { + GIOExtension *extension; + GType type; + GObject *object; + + extension = l->data; + type = g_io_extension_get_type (extension); + object = g_object_new (type, NULL); + mate_panel_applets_managers = g_slist_prepend (mate_panel_applets_managers, object); + } + + mate_panel_applets_managers = g_slist_reverse (mate_panel_applets_managers); +} + +GList * +mate_panel_applets_manager_get_applets (void) +{ + GSList *l; + GList *retval = NULL; + + _mate_panel_applets_managers_ensure_loaded (); + + for (l = mate_panel_applets_managers; l != NULL; l = l->next) { + GList *applets; + MatePanelAppletsManager *manager = MATE_PANEL_APPLETS_MANAGER (l->data); + + applets = MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->get_applets (manager); + if (applets) + retval = g_list_concat (retval, applets); + } + + return retval; +} + +gboolean +mate_panel_applets_manager_factory_activate (const gchar *iid) +{ + GSList *l; + + _mate_panel_applets_managers_ensure_loaded (); + + for (l = mate_panel_applets_managers; l != NULL; l = l->next) { + MatePanelAppletsManager *manager = MATE_PANEL_APPLETS_MANAGER (l->data); + + if (MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->factory_activate (manager, iid)) + return TRUE; + } + + return FALSE; +} + +void +mate_panel_applets_manager_factory_deactivate (const gchar *iid) +{ + GSList *l; + + _mate_panel_applets_managers_ensure_loaded (); + + for (l = mate_panel_applets_managers; l != NULL; l = l->next) { + MatePanelAppletsManager *manager = MATE_PANEL_APPLETS_MANAGER (l->data); + + if (MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->factory_deactivate (manager, iid)) + return; + } +} + +MatePanelAppletInfo * +mate_panel_applets_manager_get_applet_info (const gchar *iid) +{ + GSList *l; + MatePanelAppletInfo *retval = NULL; + + _mate_panel_applets_managers_ensure_loaded (); + + for (l = mate_panel_applets_managers; l != NULL; l = l->next) { + MatePanelAppletsManager *manager = MATE_PANEL_APPLETS_MANAGER (l->data); + + retval = MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->get_applet_info (manager, iid); + + if (retval != NULL) + return retval; + } + + return NULL; +} + +MatePanelAppletInfo * +mate_panel_applets_manager_get_applet_info_from_old_id (const gchar *iid) +{ + GSList *l; + MatePanelAppletInfo *retval = NULL; + + _mate_panel_applets_managers_ensure_loaded (); + + for (l = mate_panel_applets_managers; l != NULL; l = l->next) { + MatePanelAppletsManager *manager = MATE_PANEL_APPLETS_MANAGER (l->data); + + retval = MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->get_applet_info_from_old_id (manager, iid); + + if (retval != NULL) + return retval; + } + + return NULL; +} + +gboolean +mate_panel_applets_manager_load_applet (const gchar *iid, + MatePanelAppletFrameActivating *frame_act) +{ + GSList *l; + + _mate_panel_applets_managers_ensure_loaded (); + + for (l = mate_panel_applets_managers; l != NULL; l = l->next) { + MatePanelAppletsManager *manager = MATE_PANEL_APPLETS_MANAGER (l->data); + + if (!MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->get_applet_info (manager, iid)) + continue; + + return MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->load_applet (manager, iid, frame_act); + } + + return FALSE; +} diff --git a/mate-panel/mate-panel-applets-manager.h b/mate-panel/mate-panel-applets-manager.h new file mode 100644 index 00000000..dfe98074 --- /dev/null +++ b/mate-panel/mate-panel-applets-manager.h @@ -0,0 +1,94 @@ +/* + * mate-panel-applets-manager.h + * + * Copyright (C) 2010 Carlos Garcia Campos + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __MATE_PANEL_APPLETS_MANAGER_H__ +#define __MATE_PANEL_APPLETS_MANAGER_H__ + +#include + +#include "mate-panel-applet-frame.h" +#include "mate-panel-applet-info.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_APPLETS_MANAGER (mate_panel_applets_manager_get_type ()) +#define MATE_PANEL_APPLETS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_APPLETS_MANAGER, MatePanelAppletsManager)) +#define MATE_PANEL_APPLETS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_APPLETS_MANAGER, MatePanelAppletsManagerClass)) +#define PANEL_IS_APPLETS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_APPLETS_MANAGER)) +#define PANEL_IS_APPLETS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_APPLETS_MANAGER)) +#define MATE_PANEL_APPLETS_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PANEL_TYPE_APPLETS_MANAGER, MatePanelAppletsManagerClass)) + +/** + * MATE_PANEL_APPLETS_MANAGER_EXTENSION_POINT_NAME: + * + * Extension point for #MatePanelAppletsManager functionality. + **/ +#define MATE_PANEL_APPLETS_MANAGER_EXTENSION_POINT_NAME "mate-panel-applets-manager" + +typedef struct _MatePanelAppletsManager MatePanelAppletsManager; +typedef struct _MatePanelAppletsManagerClass MatePanelAppletsManagerClass; + +struct _MatePanelAppletsManagerClass { + GObjectClass parent_class; + + GList * (*get_applets) (MatePanelAppletsManager *manager); + + gboolean (*factory_activate) (MatePanelAppletsManager *manager, + const gchar *iid); + gboolean (*factory_deactivate) (MatePanelAppletsManager *manager, + const gchar *iid); + + MatePanelAppletInfo * (*get_applet_info) (MatePanelAppletsManager *manager, + const gchar *iid); + + MatePanelAppletInfo * (*get_applet_info_from_old_id) (MatePanelAppletsManager *manager, + const gchar *iid); + + gboolean (*load_applet) (MatePanelAppletsManager *manager, + const gchar *iid, + MatePanelAppletFrameActivating *frame_act); +}; + +struct _MatePanelAppletsManager { + GObject parent; +}; + +GType mate_panel_applets_manager_get_type (void); + +GList *mate_panel_applets_manager_get_applets (void); + +gboolean mate_panel_applets_manager_factory_activate (const gchar *iid); +void mate_panel_applets_manager_factory_deactivate (const gchar *iid); + +MatePanelAppletInfo *mate_panel_applets_manager_get_applet_info (const gchar *iid); +MatePanelAppletInfo *mate_panel_applets_manager_get_applet_info_from_old_id (const gchar *iid); + +gboolean mate_panel_applets_manager_load_applet (const gchar *iid, + MatePanelAppletFrameActivating *frame_act); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATE_PANEL_APPLETS_MANAGER_H__ */ diff --git a/mate-panel/mate-panel.desktop.in.in b/mate-panel/mate-panel.desktop.in.in new file mode 100644 index 00000000..068eaba5 --- /dev/null +++ b/mate-panel/mate-panel.desktop.in.in @@ -0,0 +1,19 @@ +[Desktop Entry] +Type=Application +_Name=Panel +_Comment=Launch other applications and provide various utilities to manage windows, show the time, etc. +Icon=mate-panel +Exec=mate-panel +StartupNotify=true +Terminal=false +X-MATE-Bugzilla-Bugzilla=MATE +X-MATE-Bugzilla-Product=mate-panel +X-MATE-Bugzilla-Component=general +X-MATE-Bugzilla-Version=@VERSION@ +Categories=MATE;GTK;Utility;Core; +OnlyShowIn=MATE; +NoDisplay=true +X-MATE-AutoRestart=true +X-MATE-Autostart-Phase=Panel +X-MATE-Provides=panel +X-MATE-Autostart-Notify=true diff --git a/mate-panel/mate-panelrc b/mate-panel/mate-panelrc new file mode 100644 index 00000000..0fb54692 --- /dev/null +++ b/mate-panel/mate-panelrc @@ -0,0 +1,4 @@ +# +# This file is intentionally left empty. You may add gtk theme +# definitions here and they will only apply to the MATE Panel. +# diff --git a/mate-panel/menu.c b/mate-panel/menu.c new file mode 100644 index 00000000..273fae86 --- /dev/null +++ b/mate-panel/menu.c @@ -0,0 +1,1914 @@ +/* + * Copyright (C) 1997 - 2000 The Free Software Foundation + * Copyright (C) 2000 Helix Code, Inc. + * Copyright (C) 2000 Eazel, Inc. + * Copyright (C) 2004 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "menu.h" + +#include + +#include +#include +#include +#include + +#include +#include + +#include "launcher.h" +#include "panel-util.h" +#include "panel.h" +#include "drawer.h" +#include "panel-config-global.h" +#include "panel-stock-icons.h" +#include "panel-action-button.h" +#include "panel-profile.h" +#include "panel-menu-button.h" +#include "panel-menu-items.h" +#include "panel-globals.h" +#include "panel-run-dialog.h" +#include "panel-lockdown.h" +#include "panel-icon-names.h" + +typedef struct { + GtkWidget *pixmap; + const char *stock_id; + GIcon *gicon; + char *image; + char *fallback_image; + GtkIconTheme *icon_theme; + GtkIconSize icon_size; +} IconToLoad; + +typedef struct { + GtkWidget *image; + const char *stock_id; + GIcon *gicon; + GdkPixbuf *pixbuf; + GtkIconSize icon_size; +} IconToAdd; + +static guint load_icons_id = 0; +static GHashTable *loaded_icons = NULL; +static GList *icons_to_load = NULL; +static GList *icons_to_add = NULL; + +static GSList *image_menu_items = NULL; + +static GtkWidget *populate_menu_from_directory (GtkWidget *menu, + MateMenuTreeDirectory *directory); + +static void panel_load_menu_image_deferred (GtkWidget *image_menu_item, + GtkIconSize icon_size, + const char *stock_id, + GIcon *gicon, + const char *image_filename, + const char *fallback_image_filename); + +static gboolean panel_menu_key_press_handler (GtkWidget *widget, + GdkEventKey *event); + +static inline gboolean desktop_is_home_dir(void) +{ + return mateconf_client_get_bool(panel_mateconf_get_client(), "/apps/caja/preferences/desktop_is_home_dir", NULL); +} + +GtkWidget * +add_menu_separator (GtkWidget *menu) +{ + GtkWidget *menuitem; + + menuitem = gtk_separator_menu_item_new (); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + return menuitem; +} + +static void +activate_app_def (GtkWidget *menuitem, + MateMenuTreeEntry *entry) +{ + const char *path; + + path = matemenu_tree_entry_get_desktop_file_path (entry); + panel_menu_item_activate_desktop_file (menuitem, path); +} + +PanelWidget * +menu_get_panel (GtkWidget *menu) +{ + PanelWidget *retval = NULL; + + g_return_val_if_fail (menu != NULL, NULL); + + if (GTK_IS_MENU_ITEM (menu)) + menu = gtk_widget_get_parent (menu); + + g_return_val_if_fail (GTK_IS_MENU (menu), NULL); + + while (menu) { + retval = g_object_get_data (G_OBJECT (menu), "menu_panel"); + if (retval) + break; + + menu = gtk_widget_get_parent (gtk_menu_get_attach_widget (GTK_MENU (menu))); + if (!GTK_IS_MENU (menu)) + break; + } + + if (retval && !PANEL_IS_WIDGET (retval)) { + g_warning ("Invalid PanelWidget associated with menu"); + retval = NULL; + } + + if (!retval) { + g_warning ("Cannot find the PanelWidget associated with menu"); + retval = panels->data; + } + + return retval; +} + +static void +setup_menu_panel (GtkWidget *menu) +{ + PanelWidget *panel; + + panel = g_object_get_data (G_OBJECT (menu), "menu_panel"); + if (panel) + return; + + panel = menu_get_panel (menu); + g_object_set_data (G_OBJECT (menu), "menu_panel", panel); + + if (panel) + gtk_menu_set_screen (GTK_MENU (menu), + gtk_widget_get_screen (GTK_WIDGET (panel))); +} + +GdkScreen * +menuitem_to_screen (GtkWidget *menuitem) +{ + PanelWidget *panel_widget; + + panel_widget = menu_get_panel (menuitem); + + return gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel)); +} + +static void +reload_image_menu_items (void) +{ + GSList* l; + + for (l = image_menu_items; l; l = l->next) { + GtkWidget *image = l->data; + gboolean is_mapped; + + is_mapped = gtk_widget_get_mapped (image); + + if (is_mapped) + gtk_widget_unmap (image); + + gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL); + + if (is_mapped) + gtk_widget_map (image); + + } +} + +static void +icon_theme_changed (GtkIconTheme *icon_theme, + gpointer data) +{ + reload_image_menu_items (); +} + +GtkWidget * +panel_create_menu (void) +{ + GtkWidget *retval; + static gboolean registered_icon_theme_changer = FALSE; + + if (!registered_icon_theme_changer) { + registered_icon_theme_changer = TRUE; + + g_signal_connect (gtk_icon_theme_get_default (), "changed", + G_CALLBACK (icon_theme_changed), NULL); + } + + retval = gtk_menu_new (); + gtk_widget_set_name (retval, "mate-panel-main-menu"); + + g_signal_connect (retval, "key_press_event", + G_CALLBACK (panel_menu_key_press_handler), + NULL); + + return retval; +} + +GtkWidget * +create_empty_menu (void) +{ + GtkWidget *retval; + + retval = panel_create_menu (); + + g_signal_connect (retval, "show", G_CALLBACK (setup_menu_panel), NULL); + + /* intercept all right button clicks makes sure they don't + go to the object itself */ + g_signal_connect (retval, "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + + return retval; +} + +static void +icon_to_load_free (IconToLoad *icon) +{ + if (!icon) + return; + + if (icon->pixmap) + g_object_unref (icon->pixmap); + icon->pixmap = NULL; + + if (icon->gicon) + g_object_unref (icon->gicon); + icon->gicon = NULL; + + g_free (icon->image); icon->image = NULL; + g_free (icon->fallback_image); icon->fallback_image = NULL; + g_free (icon); +} + +static IconToLoad * +icon_to_load_copy (IconToLoad *icon) +{ + IconToLoad *retval; + + if (!icon) + return NULL; + + retval = g_new0 (IconToLoad, 1); + + retval->pixmap = g_object_ref (icon->pixmap); + if (icon->gicon) + retval->gicon = g_object_ref (icon->gicon); + else + retval->gicon = NULL; + retval->image = g_strdup (icon->image); + retval->fallback_image = g_strdup (icon->fallback_image); + retval->stock_id = icon->stock_id; + retval->icon_size = icon->icon_size; + + return retval; +} + +static void +remove_pixmap_from_loaded (gpointer data, GObject *where_the_object_was) +{ + char *key = data; + + if (loaded_icons != NULL) + g_hash_table_remove (loaded_icons, key); + + g_free (key); +} + +GdkPixbuf * +panel_make_menu_icon (GtkIconTheme *icon_theme, + const char *icon, + const char *fallback, + int size, + gboolean *long_operation) +{ + GdkPixbuf *pb; + char *file, *key; + gboolean loaded; + + g_return_val_if_fail (size > 0, NULL); + + file = NULL; + if (icon != NULL) + file = panel_find_icon (icon_theme, icon, size); + if (file == NULL && fallback != NULL) + file = panel_find_icon (icon_theme, fallback, size); + + if (file == NULL) + return NULL; + + if (long_operation != NULL) + *long_operation = TRUE; + + pb = NULL; + + loaded = FALSE; + + key = g_strdup_printf ("%d:%s", size, file); + + if (loaded_icons != NULL && + (pb = g_hash_table_lookup (loaded_icons, key)) != NULL) { + if (pb != NULL) + g_object_ref (G_OBJECT (pb)); + } + + if (pb == NULL) { + pb = gdk_pixbuf_new_from_file (file, NULL); + if (pb) { + gint width, height; + + width = gdk_pixbuf_get_width (pb); + height = gdk_pixbuf_get_height (pb); + + /* if we want 24 and we get 22, do nothing; + * else scale */ + if (!(size - 2 <= width && width <= size && + size - 2 <= height && height <= size)) { + GdkPixbuf *tmp; + + tmp = gdk_pixbuf_scale_simple (pb, size, size, + GDK_INTERP_BILINEAR); + + g_object_unref (pb); + pb = tmp; + } + } + + /* add icon to the hash table so we don't load it again */ + loaded = TRUE; + } + + if (pb == NULL) { + g_free (file); + g_free (key); + return NULL; + } + + if (loaded && + (gdk_pixbuf_get_width (pb) != size && + gdk_pixbuf_get_height (pb) != size)) { + GdkPixbuf *pb2; + int dest_width; + int dest_height; + int width; + int height; + + width = gdk_pixbuf_get_width (pb); + height = gdk_pixbuf_get_height (pb); + + if (height > width) { + dest_width = (size * width) / height; + dest_height = size; + } else { + dest_width = size; + dest_height = (size * height) / width; + } + + pb2 = gdk_pixbuf_scale_simple (pb, dest_width, dest_height, + GDK_INTERP_BILINEAR); + g_object_unref (G_OBJECT (pb)); + pb = pb2; + } + + if (loaded) { + if (loaded_icons == NULL) + loaded_icons = g_hash_table_new_full + (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + g_hash_table_replace (loaded_icons, + g_strdup (key), + g_object_ref (G_OBJECT (pb))); + g_object_weak_ref (G_OBJECT (pb), + (GWeakNotify) remove_pixmap_from_loaded, + g_strdup (key)); + } else { + /* we didn't load from disk */ + if (long_operation != NULL) + *long_operation = FALSE; + } + + g_free (file); + g_free (key); + + return pb; +} + +static void +menu_item_style_set (GtkImage *image, + gpointer data) +{ + GtkWidget *widget; + GdkPixbuf *pixbuf; + GtkIconSize icon_size = (GtkIconSize) GPOINTER_TO_INT (data); + int icon_height; + gboolean is_mapped; + + if (!gtk_icon_size_lookup (icon_size, NULL, &icon_height)) + return; + + pixbuf = gtk_image_get_pixbuf (image); + if (!pixbuf) + return; + + if (gdk_pixbuf_get_height (pixbuf) == icon_height) + return; + + widget = GTK_WIDGET (image); + + is_mapped = gtk_widget_get_mapped (widget); + if (is_mapped) + gtk_widget_unmap (widget); + + gtk_image_set_from_pixbuf (image, NULL); + + if (is_mapped) + gtk_widget_map (widget); +} + +static void +do_icons_to_add (void) +{ + while (icons_to_add) { + IconToAdd *icon_to_add = icons_to_add->data; + + icons_to_add = g_list_delete_link (icons_to_add, icons_to_add); + + if (icon_to_add->stock_id) { + gtk_image_set_from_stock ( + GTK_IMAGE (icon_to_add->image), + icon_to_add->stock_id, + icon_to_add->icon_size); + } else if (icon_to_add->gicon) { + gtk_image_set_from_gicon ( + GTK_IMAGE (icon_to_add->image), + icon_to_add->gicon, + icon_to_add->icon_size); + } else { + g_assert (icon_to_add->pixbuf); + + gtk_image_set_from_pixbuf ( + GTK_IMAGE (icon_to_add->image), + icon_to_add->pixbuf); + + g_signal_connect (icon_to_add->image, "style-set", + G_CALLBACK (menu_item_style_set), + GINT_TO_POINTER (icon_to_add->icon_size)); + + g_object_unref (icon_to_add->pixbuf); + } + + if (icon_to_add->gicon) + g_object_unref (icon_to_add->gicon); + g_object_unref (icon_to_add->image); + g_free (icon_to_add); + } +} + +static gboolean +load_icons_handler (gpointer data) +{ + IconToLoad *icon; + gboolean long_operation = FALSE; + +load_icons_handler_again: + + if (!icons_to_load) { + load_icons_id = 0; + do_icons_to_add (); + + return FALSE; + } + + icon = icons_to_load->data; + icons_to_load->data = NULL; + /* pop */ + icons_to_load = g_list_delete_link (icons_to_load, icons_to_load); + + /* if not visible anymore, just ignore */ + if ( ! gtk_widget_get_visible (icon->pixmap)) { + icon_to_load_free (icon); + /* we didn't do anything long/hard, so just do this again, + * this is fun, don't go back to main loop */ + goto load_icons_handler_again; + } + + if (icon->stock_id || icon->gicon) { + IconToAdd *icon_to_add; + + icon_to_add = g_new (IconToAdd, 1); + icon_to_add->image = g_object_ref (icon->pixmap); + icon_to_add->stock_id = icon->stock_id; + icon_to_add->pixbuf = NULL; + icon_to_add->icon_size = icon->icon_size; + if (icon->gicon) + icon_to_add->gicon = g_object_ref (icon->gicon); + else + icon_to_add->gicon = NULL; + + icons_to_add = g_list_prepend (icons_to_add, icon_to_add); + } else { + IconToAdd *icon_to_add; + GdkPixbuf *pb; + int icon_height = PANEL_DEFAULT_MENU_ICON_SIZE; + + gtk_icon_size_lookup (icon->icon_size, NULL, &icon_height); + + pb = panel_make_menu_icon (icon->icon_theme, + icon->image, + icon->fallback_image, + icon_height, + &long_operation); + if (!pb) { + icon_to_load_free (icon); + if (long_operation) + /* this may have been a long operation so jump back to + * the main loop for a while */ + return TRUE; + else + /* we didn't do anything long/hard, so just do this again, + * this is fun, don't go back to main loop */ + goto load_icons_handler_again; + } + + icon_to_add = g_new (IconToAdd, 1); + icon_to_add->image = g_object_ref (icon->pixmap); + icon_to_add->stock_id = NULL; + icon_to_add->gicon = NULL; + icon_to_add->pixbuf = pb; + icon_to_add->icon_size = icon->icon_size; + + icons_to_add = g_list_prepend (icons_to_add, icon_to_add); + } + + icon_to_load_free (icon); + + if (!long_operation) + /* we didn't do anything long/hard, so just do this again, + * this is fun, don't go back to main loop */ + goto load_icons_handler_again; + + /* if still more we'll come back */ + return TRUE; +} + +static void +add_app_to_panel (GtkWidget *item, + MateMenuTreeEntry *entry) +{ + PanelWidget *panel_widget; + PanelToplevel *toplevel; + PanelData *pd; + int position; + + panel_widget = menu_get_panel (item); + toplevel = panel_widget->toplevel; + + pd = g_object_get_data (G_OBJECT (toplevel), "PanelData"); + position = pd ? pd->insertion_pos : -1; + + panel_launcher_create (toplevel, + position, + matemenu_tree_entry_get_desktop_file_path (entry)); +} + + +static void +add_app_to_desktop (GtkWidget *item, + MateMenuTreeEntry *entry) +{ + char *source_uri; + const char *source; + char *target_dir; + char *target_uri; + char *target; + GError *error; + + g_return_if_fail (entry != NULL); + + if (desktop_is_home_dir ()) { + target_dir = g_build_filename (g_get_home_dir (), NULL); + } else { + target_dir = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); + } + + source = matemenu_tree_entry_get_desktop_file_path (entry); + source_uri = g_filename_to_uri (source, NULL, NULL); + + target_uri = panel_make_unique_desktop_uri (target_dir, source_uri); + g_free (target_dir); + g_free (source_uri); + + g_return_if_fail (target_uri != NULL); + + target = g_filename_from_uri (target_uri, NULL, NULL); + g_free (target_uri); + + error = NULL; + panel_key_file_copy_and_mark_trusted (source, target, &error); + + g_free (target); + + if (error != NULL) { + g_warning ("Problem while copying launcher to desktop: %s", + error->message); + g_error_free (error); + } +} + + +static void add_drawers_from_dir (MateMenuTreeDirectory *directory, + int pos, + const char *toplevel_id); + +static void +add_drawers_from_alias (MateMenuTreeAlias *alias, + const char *toplevel_id) +{ + MateMenuTreeItem *aliased_item; + + aliased_item = matemenu_tree_alias_get_item (alias); + + switch (matemenu_tree_item_get_type (aliased_item)) { + case MATEMENU_TREE_ITEM_DIRECTORY: + add_drawers_from_dir (MATEMENU_TREE_DIRECTORY (aliased_item), + G_MAXINT/2, + toplevel_id); + break; + + case MATEMENU_TREE_ITEM_ENTRY: + panel_launcher_create_with_id (toplevel_id, + G_MAXINT/2, + matemenu_tree_entry_get_desktop_file_path (MATEMENU_TREE_ENTRY (aliased_item))); + break; + + default: + break; + } + + matemenu_tree_item_unref (aliased_item); +} + +static void +add_drawers_from_dir (MateMenuTreeDirectory *directory, + int pos, + const char *toplevel_id) +{ + const char *name; + const char *icon; + GSList *items; + GSList *l; + char *attached_toplevel_id; + + name = matemenu_tree_directory_get_name (directory); + icon = matemenu_tree_directory_get_icon (directory); + + attached_toplevel_id = panel_drawer_create_with_id (toplevel_id, + pos, + icon, + icon != NULL, + name); + if (!attached_toplevel_id) + return; + + items = matemenu_tree_directory_get_contents (directory); + for (l = items; l; l = l->next) { + MateMenuTreeItem *item = l->data; + + switch (matemenu_tree_item_get_type (item)) { + case MATEMENU_TREE_ITEM_ENTRY: + panel_launcher_create_with_id (attached_toplevel_id, + G_MAXINT/2, + matemenu_tree_entry_get_desktop_file_path (MATEMENU_TREE_ENTRY (item))); + break; + + case MATEMENU_TREE_ITEM_DIRECTORY: + add_drawers_from_dir (MATEMENU_TREE_DIRECTORY (item), + G_MAXINT/2, + attached_toplevel_id); + break; + + case MATEMENU_TREE_ITEM_ALIAS: + add_drawers_from_alias (MATEMENU_TREE_ALIAS (item), attached_toplevel_id); + break; + + default: + break; + } + + matemenu_tree_item_unref (item); + } + + g_slist_free (items); + + g_free (attached_toplevel_id); +} + +static void +add_menudrawer_to_panel (GtkWidget *menuitem, + MateMenuTreeEntry *entry) + +{ + MateMenuTreeDirectory *directory; + PanelWidget *panel; + PanelData *pd; + int insertion_pos; + + directory = matemenu_tree_item_get_parent (MATEMENU_TREE_ITEM (entry)); + + panel = menu_get_panel (menuitem); + + pd = g_object_get_data (G_OBJECT (panel->toplevel), "PanelData"); + insertion_pos = pd ? pd->insertion_pos : -1; + + add_drawers_from_dir (directory, + insertion_pos, + panel_profile_get_toplevel_id (panel->toplevel)); + + matemenu_tree_item_unref (directory); +} + +static void +add_menu_to_panel (GtkWidget *menuitem, + MateMenuTreeEntry *entry) +{ + MateMenuTreeDirectory *directory; + MateMenuTree *tree; + PanelWidget *panel; + PanelData *pd; + int insertion_pos; + char *menu_path; + const char *menu_filename; + + directory = matemenu_tree_item_get_parent (MATEMENU_TREE_ITEM (entry)); + if (!directory) { + g_warning ("Cannot find the filename for the menu: no directory"); + return; + } + + tree = matemenu_tree_directory_get_tree (directory); + if (!tree) { + matemenu_tree_item_unref (directory); + g_warning ("Cannot find the filename for the menu: no tree"); + return; + } + + menu_filename = matemenu_tree_get_menu_file (tree); + matemenu_tree_unref (tree); + if (!menu_filename) { + matemenu_tree_item_unref (directory); + g_warning ("Cannot find the filename for the menu: no filename"); + return; + } + + panel = menu_get_panel (menuitem); + + pd = g_object_get_data (G_OBJECT (panel->toplevel), "PanelData"); + insertion_pos = pd ? pd->insertion_pos : -1; + + menu_path = matemenu_tree_directory_make_path (directory, NULL); + + panel_menu_button_create (panel->toplevel, + insertion_pos, + menu_filename, + menu_path, + TRUE, + matemenu_tree_directory_get_name (directory)); + + g_free (menu_path); + + matemenu_tree_item_unref (directory); +} + +/*most of this function stolen from the real gtk_menu_popup*/ +static void +restore_grabs(GtkWidget *w, gpointer data) +{ + GtkWidget *menu_item = data; + GtkMenu *menu = GTK_MENU (gtk_widget_get_parent (menu_item)); + GtkWidget *xgrab_shell; + GtkWidget *parent; + + /* Find the last viewable ancestor, and make an X grab on it + */ + parent = GTK_WIDGET (menu); + xgrab_shell = NULL; + while (parent) { + gboolean viewable = TRUE; + GtkWidget *tmp = parent; + + while (tmp) { + if (!gtk_widget_get_mapped (tmp)) { + viewable = FALSE; + break; + } + tmp = gtk_widget_get_parent (tmp); + } + + if (viewable) + xgrab_shell = parent; + + parent = GTK_MENU_SHELL (parent)->parent_menu_shell; + } + + /*only grab if this HAD a grab before*/ + if (xgrab_shell && (GTK_MENU_SHELL (xgrab_shell)->have_xgrab)) + { + GdkWindow *window = gtk_widget_get_window (xgrab_shell); + + if (gdk_pointer_grab (window, TRUE, + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK, + NULL, NULL, 0) == 0) + { + if (gdk_keyboard_grab (window, TRUE, + GDK_CURRENT_TIME) == 0) + GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; + else + gdk_pointer_ungrab (GDK_CURRENT_TIME); + } + } + + gtk_grab_add (GTK_WIDGET (menu)); +} + +static void +menu_destroy_context_menu (GtkWidget *item, + GtkWidget *menu) +{ + g_signal_handlers_disconnect_by_func (menu, restore_grabs, item); + gtk_widget_destroy (menu); +} + +static GtkWidget * +create_item_context_menu (GtkWidget *item, + PanelWidget *panel_widget) +{ + MateMenuTreeEntry *entry; + MateMenuTreeDirectory *directory; + MateMenuTree *tree; + GtkWidget *menu; + GtkWidget *submenu; + GtkWidget *menuitem; + const char *menu_filename; + gboolean id_lists_writable; + + id_lists_writable = panel_profile_id_lists_are_writable (); + + entry = g_object_get_data (G_OBJECT (item), "panel-menu-tree-entry"); + if (!entry) + return NULL; + + directory = matemenu_tree_item_get_parent (MATEMENU_TREE_ITEM (entry)); + if (!directory) + return NULL; + + tree = matemenu_tree_directory_get_tree (directory); + matemenu_tree_item_unref (directory); + if (!tree) + return NULL; + + menu_filename = matemenu_tree_get_menu_file (tree); + matemenu_tree_unref (tree); + if (!menu_filename) + return NULL; + + menu = create_empty_menu (); + g_object_set_data (G_OBJECT (item), "panel-item-context-menu", menu); + g_object_set_data (G_OBJECT (menu), "menu_panel", panel_widget); + + g_signal_connect (item, "destroy", + G_CALLBACK (menu_destroy_context_menu), menu); + g_signal_connect (menu, "deactivate", + G_CALLBACK (restore_grabs), item); + + menuitem = gtk_menu_item_new_with_mnemonic (_("Add this launcher to _panel")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (add_app_to_panel), entry); + gtk_widget_set_sensitive (menuitem, id_lists_writable); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_mnemonic (_("Add this launcher to _desktop")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (add_app_to_desktop), entry); + gtk_widget_set_sensitive (menuitem, id_lists_writable); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + + + submenu = create_empty_menu (); + + g_object_set_data (G_OBJECT (submenu), "menu_panel", panel_widget); + + menuitem = gtk_menu_item_new_with_mnemonic (_("_Entire menu")); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_mnemonic (_("Add this as _drawer to panel")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (add_menudrawer_to_panel), entry); + gtk_widget_set_sensitive (menuitem, id_lists_writable); + gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_mnemonic (_("Add this as _menu to panel")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (add_menu_to_panel), entry); + gtk_widget_set_sensitive (menuitem, id_lists_writable); + gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem); + gtk_widget_show (menuitem); + + return menu; +} + +static gboolean +show_item_menu (GtkWidget *item, + GdkEventButton *bevent) +{ + PanelWidget *panel_widget; + GtkWidget *menu; + + if (panel_lockdown_get_locked_down ()) + return FALSE; + + panel_widget = menu_get_panel (item); + + menu = g_object_get_data (G_OBJECT (item), "panel-item-context-menu"); + + if (!menu) + menu = create_item_context_menu (item, panel_widget); + + if (!menu) + return FALSE; + + gtk_menu_set_screen (GTK_MENU (menu), + gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel))); + + gtk_menu_popup (GTK_MENU (menu), + NULL, NULL, NULL, NULL, + bevent->button, + bevent->time); + + return TRUE; +} + +gboolean +menu_dummy_button_press_event (GtkWidget *menuitem, + GdkEventButton *event) +{ + if (event->button == 3) + return TRUE; + + return FALSE; +} + +static gboolean +menuitem_button_press_event (GtkWidget *menuitem, + GdkEventButton *event) +{ + if (event->button == 3) + return show_item_menu (menuitem, event); + + return FALSE; +} + +static void +drag_begin_menu_cb (GtkWidget *widget, GdkDragContext *context) +{ + /* FIXME: workaround for a possible gtk+ bug + * See bugs #92085(gtk+) and #91184(panel) for details. + * Maybe it's not needed with GtkTooltip? + */ + g_object_set (widget, "has-tooltip", FALSE, NULL); +} + +/* This is a _horrible_ hack to have this here. This needs to be added to the + * GTK+ menuing code in some manner. + */ +static void +drag_end_menu_cb (GtkWidget *widget, GdkDragContext *context) +{ + GtkWidget *xgrab_shell; + GtkWidget *parent; + + /* Find the last viewable ancestor, and make an X grab on it + */ + parent = gtk_widget_get_parent (widget); + xgrab_shell = NULL; + + /* FIXME: workaround for a possible gtk+ bug + * See bugs #92085(gtk+) and #91184(panel) for details. + */ + g_object_set (widget, "has-tooltip", TRUE, NULL); + + while (parent) + { + gboolean viewable = TRUE; + GtkWidget *tmp = parent; + + while (tmp) + { + if (!gtk_widget_get_mapped (tmp)) + { + viewable = FALSE; + break; + } + tmp = gtk_widget_get_parent (tmp); + } + + if (viewable) + xgrab_shell = parent; + + parent = GTK_MENU_SHELL (parent)->parent_menu_shell; + } + + if (xgrab_shell && !gtk_menu_get_tearoff_state (GTK_MENU(xgrab_shell))) + { + GdkWindow *window = gtk_widget_get_window (xgrab_shell); + GdkCursor *cursor = gdk_cursor_new (GDK_ARROW); + + if ((gdk_pointer_grab (window, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK, + NULL, cursor, GDK_CURRENT_TIME) == 0)) + { + if (gdk_keyboard_grab (window, TRUE, + GDK_CURRENT_TIME) == 0) + GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; + else + { + gdk_pointer_ungrab (GDK_CURRENT_TIME); + } + } + + gdk_cursor_unref (cursor); + } +} + +static void +drag_data_get_menu_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + MateMenuTreeEntry *entry) +{ + const char *path; + char *uri; + char *uri_list; + + path = matemenu_tree_entry_get_desktop_file_path (entry); + uri = g_filename_to_uri (path, NULL, NULL); + uri_list = g_strconcat (uri, "\r\n", NULL); + g_free (uri); + + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), 8, (guchar *)uri_list, + strlen (uri_list)); + g_free (uri_list); +} + +static void +image_menuitem_size_request (GtkWidget *menuitem, + GtkRequisition *requisition, + gpointer data) +{ + GtkIconSize icon_size = (GtkIconSize) GPOINTER_TO_INT (data); + int icon_height; + int req_height; + + if (!gtk_icon_size_lookup (icon_size, NULL, &icon_height)) + return; + + /* If we don't have a pixmap for this menuitem + * at least make sure its the same height as + * the rest. + * This is a bit ugly, since we should keep this in sync with what's in + * gtk_menu_item_size_request() + */ + req_height = icon_height; + req_height += (gtk_container_get_border_width (GTK_CONTAINER (menuitem)) + + (gtk_widget_get_style (menuitem))->ythickness) * 2; + requisition->height = MAX (requisition->height, req_height); +} + +static char * +menu_escape_underscores_and_prepend (const char *text) +{ + GString *escaped_text; + const char *src; + int inserted; + + if (!text) + return g_strdup (text); + + escaped_text = g_string_sized_new (strlen (text) + 1); + g_string_printf (escaped_text, "_%s", text); + + src = text; + inserted = 1; + + while (*src) { + gunichar c; + + c = g_utf8_get_char (src); + + if (c == (gunichar)-1) { + g_warning ("Invalid input string for underscore escaping"); + return g_strdup (text); + } else if (c == '_') { + g_string_insert_c (escaped_text, + src - text + inserted, '_'); + inserted++; + } + + src = g_utf8_next_char (src); + } + + return g_string_free (escaped_text, FALSE); +} + +void +setup_menuitem (GtkWidget *menuitem, + GtkIconSize icon_size, + GtkWidget *image, + const char *title) + +{ + GtkWidget *label; + char *_title; + + /* this creates a label with an invisible mnemonic */ + label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL); + _title = menu_escape_underscores_and_prepend (title); + gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _title); + g_free (_title); + + gtk_label_set_pattern (GTK_LABEL (label), ""); + + gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), menuitem); + + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + + gtk_container_add (GTK_CONTAINER (menuitem), label); + + if (image) { + g_object_set_data_full (G_OBJECT (menuitem), + "Panel:Image", + g_object_ref (image), + (GDestroyNotify) g_object_unref); + gtk_widget_show (image); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), + image); + } else if (icon_size != GTK_ICON_SIZE_INVALID) + g_signal_connect (menuitem, "size_request", + G_CALLBACK (image_menuitem_size_request), + GINT_TO_POINTER (icon_size)); + + gtk_widget_show (menuitem); +} + +static void +drag_data_get_string_cb (GtkWidget *widget, GdkDragContext *context, + GtkSelectionData *selection_data, guint info, + guint time, const char *string) +{ + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), 8, (guchar *)string, + strlen(string)); +} + +void +setup_uri_drag (GtkWidget *menuitem, + const char *uri, + const char *icon) +{ + static GtkTargetEntry menu_item_targets[] = { + { "text/uri-list", 0, 0 } + }; + + if (panel_lockdown_get_locked_down ()) + return; + + gtk_drag_source_set (menuitem, + GDK_BUTTON1_MASK|GDK_BUTTON2_MASK, + menu_item_targets, 1, + GDK_ACTION_COPY); + + if (icon != NULL) + gtk_drag_source_set_icon_name (menuitem, icon); + + g_signal_connect (G_OBJECT (menuitem), "drag_begin", + G_CALLBACK (drag_begin_menu_cb), NULL); + g_signal_connect_data (G_OBJECT (menuitem), "drag_data_get", + G_CALLBACK (drag_data_get_string_cb), + g_strdup (uri), + (GClosureNotify)g_free, + 0 /* connect_flags */); + g_signal_connect (G_OBJECT (menuitem), "drag_end", + G_CALLBACK (drag_end_menu_cb), NULL); +} + +void +setup_internal_applet_drag (GtkWidget *menuitem, + PanelActionButtonType type) +{ + static GtkTargetEntry menu_item_targets[] = { + { "application/x-mate-panel-applet-internal", 0, 0 } + }; + + if (panel_lockdown_get_locked_down ()) + return; + + gtk_drag_source_set (menuitem, + GDK_BUTTON1_MASK|GDK_BUTTON2_MASK, + menu_item_targets, 1, + GDK_ACTION_COPY); + + if (panel_action_get_icon_name (type) != NULL) + gtk_drag_source_set_icon_name (menuitem, + panel_action_get_icon_name (type)); + + g_signal_connect (G_OBJECT (menuitem), "drag_begin", + G_CALLBACK (drag_begin_menu_cb), NULL); + g_signal_connect_data (G_OBJECT (menuitem), "drag_data_get", + G_CALLBACK (drag_data_get_string_cb), + g_strdup (panel_action_get_drag_id (type)), + (GClosureNotify)g_free, + 0 /* connect_flags */); + g_signal_connect (G_OBJECT (menuitem), "drag_end", + G_CALLBACK (drag_end_menu_cb), NULL); +} + +static void +submenu_to_display (GtkWidget *menu) +{ + MateMenuTree *tree; + MateMenuTreeDirectory *directory; + const char *menu_path; + void (*append_callback) (GtkWidget *, gpointer); + gpointer append_data; + + if (!g_object_get_data (G_OBJECT (menu), "panel-menu-needs-loading")) + return; + + g_object_set_data (G_OBJECT (menu), "panel-menu-needs-loading", NULL); + + directory = g_object_get_data (G_OBJECT (menu), + "panel-menu-tree-directory"); + if (!directory) { + menu_path = g_object_get_data (G_OBJECT (menu), + "panel-menu-tree-path"); + if (!menu_path) + return; + + tree = g_object_get_data (G_OBJECT (menu), "panel-menu-tree"); + if (!tree) + return; + + directory = matemenu_tree_get_directory_from_path (tree, + menu_path); + + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-tree-directory", + directory, + (GDestroyNotify) matemenu_tree_item_unref); + } + + if (directory) + populate_menu_from_directory (menu, directory); + + append_callback = g_object_get_data (G_OBJECT (menu), + "panel-menu-append-callback"); + append_data = g_object_get_data (G_OBJECT (menu), + "panel-menu-append-callback-data"); + if (append_callback) + append_callback (menu, append_data); +} + +static gboolean +submenu_to_display_in_idle (gpointer data) +{ + GtkWidget *menu = GTK_WIDGET (data); + + g_object_set_data (G_OBJECT (menu), "panel-menu-idle-id", NULL); + + submenu_to_display (menu); + + return FALSE; +} + +static void +remove_submenu_to_display_idle (gpointer data) +{ + guint idle_id = GPOINTER_TO_UINT (data); + + g_source_remove (idle_id); +} + +static GtkWidget * +create_fake_menu (MateMenuTreeDirectory *directory) +{ + GtkWidget *menu; + guint idle_id; + + menu = create_empty_menu (); + + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-tree-directory", + matemenu_tree_item_ref (directory), + (GDestroyNotify) matemenu_tree_item_unref); + + g_object_set_data (G_OBJECT (menu), + "panel-menu-needs-loading", + GUINT_TO_POINTER (TRUE)); + + g_signal_connect (menu, "show", + G_CALLBACK (submenu_to_display), NULL); + + idle_id = g_idle_add_full (G_PRIORITY_LOW, + submenu_to_display_in_idle, + menu, + NULL); + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-idle-id", + GUINT_TO_POINTER (idle_id), + remove_submenu_to_display_idle); + + g_signal_connect (menu, "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + + return menu; +} + +GtkWidget * +panel_image_menu_item_new (void) +{ + GtkWidget *menuitem; + + menuitem = gtk_image_menu_item_new (); + gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), + TRUE); + return menuitem; +} + +static GtkWidget * +create_submenu_entry (GtkWidget *menu, + MateMenuTreeDirectory *directory) +{ + GtkWidget *menuitem; + gboolean force_categories_icon; + + force_categories_icon = g_object_get_data (G_OBJECT (menu), + "panel-menu-force-icon-for-categories") != NULL; + + if (force_categories_icon) + menuitem = panel_image_menu_item_new (); + else + menuitem = gtk_image_menu_item_new (); + + panel_load_menu_image_deferred (menuitem, + panel_menu_icon_get_size (), + NULL, NULL, + matemenu_tree_directory_get_icon (directory), + PANEL_ICON_FOLDER); + + setup_menuitem (menuitem, + panel_menu_icon_get_size (), + NULL, + matemenu_tree_directory_get_name (directory)); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + gtk_widget_show (menuitem); + + return menuitem; +} + +static void +create_submenu (GtkWidget *menu, + MateMenuTreeDirectory *directory, + MateMenuTreeDirectory *alias_directory) +{ + GtkWidget *menuitem; + GtkWidget *submenu; + gboolean force_categories_icon; + + if (alias_directory) + menuitem = create_submenu_entry (menu, alias_directory); + else + menuitem = create_submenu_entry (menu, directory); + + submenu = create_fake_menu (directory); + + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + + /* Keep the infor that we force (or not) the icons to be visible */ + force_categories_icon = g_object_get_data (G_OBJECT (menu), + "panel-menu-force-icon-for-categories") != NULL; + g_object_set_data (G_OBJECT (submenu), + "panel-menu-force-icon-for-categories", + GINT_TO_POINTER (force_categories_icon)); +} + +static void +create_header (GtkWidget *menu, + MateMenuTreeHeader *header) +{ + MateMenuTreeDirectory *directory; + GtkWidget *menuitem; + + directory = matemenu_tree_header_get_directory (header); + menuitem = create_submenu_entry (menu, directory); + matemenu_tree_item_unref (directory); + + g_object_set_data_full (G_OBJECT (menuitem), + "panel-matemenu-tree.header", + matemenu_tree_item_ref (header), + (GDestroyNotify) matemenu_tree_item_unref); + + g_signal_connect (menuitem, "activate", + G_CALLBACK (gtk_false), NULL); +} + +static void +create_menuitem (GtkWidget *menu, + MateMenuTreeEntry *entry, + MateMenuTreeDirectory *alias_directory) +{ + GtkWidget *menuitem; + + menuitem = panel_image_menu_item_new (); + + g_object_set_data_full (G_OBJECT (menuitem), + "panel-menu-tree-entry", + matemenu_tree_item_ref (entry), + (GDestroyNotify) matemenu_tree_item_unref); + + if (alias_directory) + //FIXME: we should probably use this data when we do dnd or + //context menu for this menu item + g_object_set_data_full (G_OBJECT (menuitem), + "panel-menu-tree-alias-directory", + matemenu_tree_item_ref (alias_directory), + (GDestroyNotify) matemenu_tree_item_unref); + + panel_load_menu_image_deferred (menuitem, + panel_menu_icon_get_size (), + NULL, NULL, + alias_directory ? matemenu_tree_directory_get_icon (alias_directory) : + matemenu_tree_entry_get_icon (entry), + NULL); + + setup_menuitem (menuitem, + panel_menu_icon_get_size (), + NULL, + alias_directory ? matemenu_tree_directory_get_name (alias_directory) : + matemenu_tree_entry_get_display_name (entry)); + + if (alias_directory && + matemenu_tree_directory_get_comment (alias_directory)) + panel_util_set_tooltip_text (menuitem, + matemenu_tree_directory_get_comment (alias_directory)); + else if (!alias_directory && + matemenu_tree_entry_get_comment (entry)) + panel_util_set_tooltip_text (menuitem, + matemenu_tree_entry_get_comment (entry)); + else if (!alias_directory && + matemenu_tree_entry_get_generic_name (entry)) + panel_util_set_tooltip_text (menuitem, + matemenu_tree_entry_get_generic_name (entry)); + + g_signal_connect_after (menuitem, "button_press_event", + G_CALLBACK (menuitem_button_press_event), NULL); + + if (!panel_lockdown_get_locked_down ()) { + static GtkTargetEntry menu_item_targets[] = { + { "text/uri-list", 0, 0 } + }; + + gtk_drag_source_set (menuitem, + GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + menu_item_targets, 1, + GDK_ACTION_COPY); + + if (matemenu_tree_entry_get_icon (entry) != NULL) { + const char *icon; + char *icon_no_ext; + + icon = matemenu_tree_entry_get_icon (entry); + if (!g_path_is_absolute (icon)) { + icon_no_ext = panel_xdg_icon_remove_extension (icon); + gtk_drag_source_set_icon_name (menuitem, + icon_no_ext); + g_free (icon_no_ext); + } + } + + g_signal_connect (G_OBJECT (menuitem), "drag_begin", + G_CALLBACK (drag_begin_menu_cb), NULL); + g_signal_connect (menuitem, "drag_data_get", + G_CALLBACK (drag_data_get_menu_cb), entry); + g_signal_connect (menuitem, "drag_end", + G_CALLBACK (drag_end_menu_cb), NULL); + } + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + g_signal_connect (menuitem, "activate", + G_CALLBACK (activate_app_def), entry); + + gtk_widget_show (menuitem); +} + +static void +create_menuitem_from_alias (GtkWidget *menu, + MateMenuTreeAlias *alias) +{ + MateMenuTreeItem *aliased_item; + + aliased_item = matemenu_tree_alias_get_item (alias); + + switch (matemenu_tree_item_get_type (aliased_item)) { + case MATEMENU_TREE_ITEM_DIRECTORY: + create_submenu (menu, + MATEMENU_TREE_DIRECTORY (aliased_item), + matemenu_tree_alias_get_directory (alias)); + break; + + case MATEMENU_TREE_ITEM_ENTRY: + create_menuitem (menu, + MATEMENU_TREE_ENTRY (aliased_item), + matemenu_tree_alias_get_directory (alias)); + break; + + default: + break; + } + + matemenu_tree_item_unref (aliased_item); +} + +static void +handle_matemenu_tree_changed (MateMenuTree *tree, + GtkWidget *menu) +{ + guint idle_id; + + while (GTK_MENU_SHELL (menu)->children) + gtk_widget_destroy (GTK_MENU_SHELL (menu)->children->data); + + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-tree-directory", + NULL, NULL); + + g_object_set_data (G_OBJECT (menu), + "panel-menu-needs-loading", + GUINT_TO_POINTER (TRUE)); + + idle_id = g_idle_add_full (G_PRIORITY_LOW, + submenu_to_display_in_idle, + menu, + NULL); + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-idle-id", + GUINT_TO_POINTER (idle_id), + remove_submenu_to_display_idle); +} + +static void +remove_matemenu_tree_monitor (GtkWidget *menu, + MateMenuTree *tree) +{ + matemenu_tree_remove_monitor (tree, + (MateMenuTreeChangedFunc) handle_matemenu_tree_changed, + menu); +} + +GtkWidget * +create_applications_menu (const char *menu_file, + const char *menu_path, + gboolean always_show_image) +{ + MateMenuTree *tree; + GtkWidget *menu; + guint idle_id; + + menu = create_empty_menu (); + + if (always_show_image) + g_object_set_data (G_OBJECT (menu), + "panel-menu-force-icon-for-categories", + GINT_TO_POINTER (TRUE)); + + tree = matemenu_tree_lookup (menu_file, MATEMENU_TREE_FLAGS_NONE); + matemenu_tree_set_sort_key (tree, MATEMENU_TREE_SORT_DISPLAY_NAME); + + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-tree", + matemenu_tree_ref (tree), + (GDestroyNotify) matemenu_tree_unref); + + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-tree-path", + g_strdup (menu_path ? menu_path : "/"), + (GDestroyNotify) g_free); + + g_object_set_data (G_OBJECT (menu), + "panel-menu-needs-loading", + GUINT_TO_POINTER (TRUE)); + + g_signal_connect (menu, "show", + G_CALLBACK (submenu_to_display), NULL); + + idle_id = g_idle_add_full (G_PRIORITY_LOW, + submenu_to_display_in_idle, + menu, + NULL); + g_object_set_data_full (G_OBJECT (menu), + "panel-menu-idle-id", + GUINT_TO_POINTER (idle_id), + remove_submenu_to_display_idle); + + g_signal_connect (menu, "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + + matemenu_tree_add_monitor (tree, + (MateMenuTreeChangedFunc) handle_matemenu_tree_changed, + menu); + g_signal_connect (menu, "destroy", + G_CALLBACK (remove_matemenu_tree_monitor), tree); + + matemenu_tree_unref (tree); + + return menu; +} + +static GtkWidget * +populate_menu_from_directory (GtkWidget *menu, + MateMenuTreeDirectory *directory) +{ + GList *children; + GSList *l; + GSList *items; + gboolean add_separator; + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + add_separator = (children != NULL); + g_list_free (children); + + items = matemenu_tree_directory_get_contents (directory); + + for (l = items; l; l = l->next) { + MateMenuTreeItem *item = l->data; + + if (add_separator || + matemenu_tree_item_get_type (item) == MATEMENU_TREE_ITEM_SEPARATOR) { + add_menu_separator (menu); + add_separator = FALSE; + } + + switch (matemenu_tree_item_get_type (item)) { + case MATEMENU_TREE_ITEM_DIRECTORY: + create_submenu (menu, MATEMENU_TREE_DIRECTORY (item), NULL); + break; + + case MATEMENU_TREE_ITEM_ENTRY: + create_menuitem (menu, MATEMENU_TREE_ENTRY (item), NULL); + break; + + case MATEMENU_TREE_ITEM_SEPARATOR : + /* already added */ + break; + + case MATEMENU_TREE_ITEM_ALIAS: + create_menuitem_from_alias (menu, MATEMENU_TREE_ALIAS (item)); + break; + + case MATEMENU_TREE_ITEM_HEADER: + create_header (menu, MATEMENU_TREE_HEADER (item)); + break; + + default: + break; + } + + matemenu_tree_item_unref (item); + } + + g_slist_free (items); + + return menu; +} + +void +setup_menu_item_with_icon (GtkWidget *item, + GtkIconSize icon_size, + const char *icon_name, + const char *stock_id, + GIcon *gicon, + const char *title) +{ + if (icon_name || gicon || stock_id) + panel_load_menu_image_deferred (item, icon_size, + stock_id, gicon, + icon_name, NULL); + + setup_menuitem (item, icon_size, NULL, title); +} + +static void +main_menu_append (GtkWidget *main_menu, + gpointer data) +{ + PanelWidget *panel; + GtkWidget *item; + gboolean add_separator; + GList *children; + GList *last; + + panel = PANEL_WIDGET (data); + + add_separator = FALSE; + children = gtk_container_get_children (GTK_CONTAINER (main_menu)); + last = g_list_last (children); + if (last != NULL) { + add_separator = !GTK_IS_SEPARATOR (GTK_WIDGET (last->data)); + } + g_list_free (children); + + if (add_separator) + add_menu_separator (main_menu); + + item = panel_place_menu_item_new (TRUE); + panel_place_menu_item_set_panel (item, panel); + gtk_menu_shell_append (GTK_MENU_SHELL (main_menu), item); + gtk_widget_show (item); + + item = panel_desktop_menu_item_new (TRUE, FALSE); + panel_desktop_menu_item_set_panel (item, panel); + gtk_menu_shell_append (GTK_MENU_SHELL (main_menu), item); + gtk_widget_show (item); + + panel_menu_items_append_lock_logout (main_menu); +} + +GtkWidget* create_main_menu(PanelWidget* panel) +{ + GtkWidget* main_menu; + + main_menu = create_applications_menu("mate-applications.menu", NULL, TRUE); + + g_object_set_data(G_OBJECT(main_menu), "menu_panel", panel); + /* FIXME need to update the panel on parent_set */ + + g_object_set_data(G_OBJECT(main_menu), "panel-menu-append-callback", main_menu_append); + g_object_set_data(G_OBJECT(main_menu), "panel-menu-append-callback-data", panel); + + return main_menu; +} + +static GList * +find_in_load_list (GtkWidget *image) +{ + GList *li; + for (li = icons_to_load; li != NULL; li = li->next) { + IconToLoad *icon = li->data; + if (icon->pixmap == image) + return li; + } + return NULL; +} + +static void +image_menu_shown (GtkWidget *image, gpointer data) +{ + IconToLoad *new_icon; + IconToLoad *icon; + + icon = (IconToLoad *) data; + + /* if we've already handled this */ + if (gtk_image_get_storage_type (GTK_IMAGE (image)) != GTK_IMAGE_EMPTY) + return; + + if (find_in_load_list (image) == NULL) { + new_icon = icon_to_load_copy (icon); + new_icon->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (image)); + icons_to_load = g_list_append (icons_to_load, new_icon); + } + if (load_icons_id == 0) + load_icons_id = g_idle_add (load_icons_handler, NULL); +} + +static void +image_menu_destroy (GtkWidget *image, gpointer data) +{ + image_menu_items = g_slist_remove (image_menu_items, image); +} + +static void +panel_load_menu_image_deferred (GtkWidget *image_menu_item, + GtkIconSize icon_size, + const char *stock_id, + GIcon *gicon, + const char *image_filename, + const char *fallback_image_filename) +{ + IconToLoad *icon; + GtkWidget *image; + int icon_height = PANEL_DEFAULT_MENU_ICON_SIZE; + + icon = g_new (IconToLoad, 1); + + gtk_icon_size_lookup (icon_size, NULL, &icon_height); + + image = gtk_image_new (); + gtk_widget_set_size_request (image, icon_height, icon_height); + + /* this takes over the floating ref */ + icon->pixmap = g_object_ref_sink (G_OBJECT (image)); + + icon->stock_id = stock_id; + if (gicon) + icon->gicon = g_object_ref (gicon); + else + icon->gicon = NULL; + icon->image = g_strdup (image_filename); + icon->fallback_image = g_strdup (fallback_image_filename); + icon->icon_size = icon_size; + + gtk_widget_show (image); + + g_object_set_data_full (G_OBJECT (image_menu_item), + "Panel:Image", + g_object_ref (image), + (GDestroyNotify) g_object_unref); + + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (image_menu_item), + image); + + g_signal_connect_data (image, "map", + G_CALLBACK (image_menu_shown), icon, + (GClosureNotify) icon_to_load_free, 0); + + g_signal_connect (image, "destroy", + G_CALLBACK (image_menu_destroy), NULL); + + image_menu_items = g_slist_prepend (image_menu_items, image); +} + +static gboolean +panel_menu_key_press_handler (GtkWidget *widget, + GdkEventKey *event) +{ + gboolean retval = FALSE; + + if ((event->keyval == GDK_Menu) || + (event->keyval == GDK_F10 && + (event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_SHIFT_MASK)) { + GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget); + + if (menu_shell->active_menu_item && + GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL) { + GdkEventButton bevent; + + bevent.button = 3; + bevent.time = GDK_CURRENT_TIME; + retval = show_item_menu (menu_shell->active_menu_item, + &bevent); + } + + } + return retval; +} diff --git a/mate-panel/menu.h b/mate-panel/menu.h new file mode 100644 index 00000000..8638cbb8 --- /dev/null +++ b/mate-panel/menu.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 1997 - 2000 The Free Software Foundation + * Copyright (C) 2000 Helix Code, Inc. + * Copyright (C) 2000 Eazel, Inc. + * Copyright (C) 2004 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __MENU_H__ +#define __MENU_H__ + +#include "panel-widget.h" +#include "applet.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void setup_menuitem (GtkWidget *menuitem, + GtkIconSize icon_size, + GtkWidget *pixmap, + const char *title); +void setup_menu_item_with_icon (GtkWidget *item, + GtkIconSize icon_size, + const char *icon_name, + const char *stock_id, + GIcon *gicon, + const char *title); + +GtkWidget *create_empty_menu (void); +GtkWidget *create_applications_menu (const char *menu_file, + const char *menu_path, + gboolean always_show_image); +GtkWidget *create_main_menu (PanelWidget *panel); + +void setup_internal_applet_drag (GtkWidget *menuitem, + PanelActionButtonType type); +void setup_uri_drag (GtkWidget *menuitem, + const char *uri, + const char *icon); + +GtkWidget * panel_create_menu (void); + +GtkWidget * panel_image_menu_item_new (void); + +GdkPixbuf * panel_make_menu_icon (GtkIconTheme *icon_theme, + const char *icon, + const char *fallback, + int size, + gboolean *long_operation); + +GdkScreen *menuitem_to_screen (GtkWidget *menuitem); +PanelWidget *menu_get_panel (GtkWidget *menu); +GtkWidget *add_menu_separator (GtkWidget *menu); + +gboolean menu_dummy_button_press_event (GtkWidget *menuitem, + GdkEventButton *event); + + +#ifdef __cplusplus +} +#endif + +#endif /* __MENU_H__ */ diff --git a/mate-panel/nothing.cP b/mate-panel/nothing.cP new file mode 100644 index 00000000..4ce1f246 --- /dev/null +++ b/mate-panel/nothing.cP @@ -0,0 +1,1568 @@ +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CA_CHECK_VERSION +#if CA_CHECK_VERSION(0, 13) +#define HAVE_CANBERRA_GTK_MULTIHEAD_SAFE +#endif +#endif + +#include "panel-util.h" +#include "nothing.h" + +static void +pixbuf_reverse (GdkPixbuf *gp) +{ + guchar *pixels = gdk_pixbuf_get_pixels (gp); + int rs = gdk_pixbuf_get_rowstride (gp); + int w = gdk_pixbuf_get_width (gp); + int h = gdk_pixbuf_get_height (gp); + int x, y; +#define DOSWAP(x,y) tmp = x; x = y; y = tmp; + for (y = 0; y < h; y++, pixels += rs) { + guchar *p = pixels; + guchar *p2 = pixels + w*4 - 4; + for (x = 0; x < w/2; x++, p+=4, p2-=4) { + guchar tmp; + DOSWAP (p[0], p2[0]); + DOSWAP (p[1], p2[1]); + DOSWAP (p[2], p2[2]); + DOSWAP (p[3], p2[3]); + } + } +#undef DOSWAP +} + +/* This unsea's the phsh */ +/*code snippet, not to be compiled separately*/ +static gboolean goat_loaded=FALSE; +static int goat_frame=0; +static GdkPixmap *goat_pix[2] = {NULL,NULL}; +static GdkPixmap *goat_pix_rev[2] = {NULL,NULL}; +static GtkWidget *goat_darea = NULL; +static int goat_width = 0,goat_height = 0; +static int goat_timeout = 0; +static int goat_x = -1, goat_y = -1; +static int goat_accx = -1, goat_accy = -1; + +static void +destroy_egg(GtkWidget *widget, gpointer data) +{ + int i; + goat_loaded = FALSE; + if(goat_timeout) { + g_source_remove(goat_timeout); + goat_timeout = 0; + } + for (i = 0; i < 2; i++) { + if (goat_pix[i] != NULL) + g_object_unref (G_OBJECT (goat_pix[i])); + goat_pix[i] = NULL; + if (goat_pix_rev[i] != NULL) + g_object_unref (G_OBJECT (goat_pix_rev[i])); + goat_pix_rev[i] = NULL; + } + goat_x = goat_y = -1; +} + +static int +goat_timeout_func(gpointer data) +{ + GtkAllocation allocation; + cairo_t *cr; + int real_goat_frame; + gboolean sound = FALSE; + int old_x; + int old_y; + + if(!gtk_widget_get_realized(goat_darea) || + !gtk_widget_is_drawable(goat_darea)) + return TRUE; + + if (!goat_pix[0] || !goat_pix[1]) { + destroy_egg (NULL, NULL); + return FALSE; + } + + gtk_widget_get_allocation (goat_darea, &allocation); + cr = gdk_cairo_create (gtk_widget_get_window (goat_darea)); + + if(goat_x == -1) { + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + goat_x = 2; + goat_y = 2; + goat_accx = g_random_int()%4 +3; + goat_accy = g_random_int()%4 +3; + } + + old_x = goat_x; + old_y = goat_y; + goat_x += goat_accx; + goat_y += goat_accy; + + + if(goat_x>allocation.width-2-goat_width) { + goat_accx = -(g_random_int()%4 +3); + goat_x = allocation.width-2-goat_width; + sound = TRUE; + } else if(goat_x<2) { + goat_accx = g_random_int()%4 +3; + goat_x = 2; + sound = TRUE; + } + if(goat_y>allocation.height-2-goat_height) { + goat_accy = -(g_random_int()%4 +3); + goat_y = allocation.height-2-goat_height; + sound = TRUE; + } else if(goat_y<2) { + goat_accy = g_random_int()%4 +3; + goat_y = 2; + sound = TRUE; + } + + if (sound) { +#ifdef HAVE_CANBERRA_GTK_MULTIHEAD_SAFE + ca_context_cancel (ca_gtk_context_get_for_screen (gtk_widget_get_screen (goat_darea)), 42); +#else + ca_context_cancel (ca_gtk_context_get (), 42); +#endif + ca_gtk_play_for_widget (goat_darea, 42, + CA_PROP_EVENT_ID, "bell-window-system", + CA_PROP_EVENT_DESCRIPTION, "Ouch! This box is small!", + NULL); + } + + real_goat_frame = goat_frame/2; + + cairo_rectangle (cr, MIN(old_x, goat_x), MIN(old_y, goat_y), + goat_width + ABS(goat_x-old_x) + 6, + goat_height + ABS(goat_y-old_y) + 6); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + gdk_cairo_set_source_pixmap (cr, + goat_accx<0?goat_pix[real_goat_frame]: + goat_pix_rev[real_goat_frame], + goat_x,goat_y); + + cairo_paint (cr); + + if(++goat_frame == 4) + goat_frame = 0; + + cairo_destroy (cr); + + return TRUE; +} + +static int +goat_expose(GtkWidget *widget, GdkEventExpose *event) +{ + cairo_t *cr; + + if(!gtk_widget_is_drawable(widget)) + return FALSE; + + cr = gdk_cairo_create (gtk_widget_get_window (goat_darea)); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_destroy (cr); + + return FALSE; +} + +static void +goat_realize(GtkWidget *widget) +{ + GdkWindow *window; + int frame; + char *files[] = { + "mate-gegl2.png", + "mate-gegl2-2.png" + }; + if(goat_pix[0]) + return; + window = gtk_widget_get_window (widget); + for(frame=0;frame<2;frame++) { + GdkPixbuf *pb; + char *file; + int width; + int height; + cairo_t *cr; + cairo_matrix_t matrix; + cairo_pattern_t *pattern; + + file = g_strdup_printf ("%s/%s", ICONDIR, files[frame]); + if(!file) + return; + pb=gdk_pixbuf_new_from_file (file, NULL); + g_free(file); + + if(!pb) { + g_warning("Goat is not available!"); + return; + } + + width = gdk_pixbuf_get_width(pb); + height = gdk_pixbuf_get_height(pb); + + goat_pix[frame] = gdk_pixmap_new(window, + width, height, -1); + cr = gdk_cairo_create (goat_pix[frame]); + gdk_cairo_set_source_pixbuf (cr, pb, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + goat_pix_rev[frame] = gdk_pixmap_new(window, + width, height, -1); + cr = gdk_cairo_create (goat_pix_rev[frame]); + gdk_cairo_set_source_pixbuf (cr, pb, 0, 0); + + cairo_matrix_init_identity (&matrix); + cairo_matrix_translate (&matrix, width, 0); + /* scale in -X direction to flip along X */ + cairo_matrix_scale (&matrix, -1.0, 1.0); + pattern = cairo_get_source (cr); + cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + cairo_destroy (cr); + + goat_width = MAX (width, goat_width); + goat_height = MAX (height, goat_height); + + g_object_unref (pb); + } +} + +/*thy evil easter egg*/ +int +config_event(GtkWidget *widget,GdkEvent *event,GtkNotebook *nbook) +{ + static int clicks=0; + GdkEventButton *bevent; + + if (!nbook) + return FALSE; + + if(event->type != GDK_BUTTON_PRESS) + return FALSE; + + bevent = (GdkEventButton *)event; + if(bevent->button != 3) + clicks = 0; + else + clicks++; + + if(clicks<3) + return FALSE; + clicks = 0; + + if(!goat_loaded) { + goat_darea = gtk_drawing_area_new(); + + g_signal_connect (G_OBJECT(goat_darea),"destroy", + G_CALLBACK (destroy_egg),NULL); + g_signal_connect (GTK_OBJECT(goat_darea),"expose_event", + G_CALLBACK (goat_expose),NULL); + g_signal_connect_after (G_OBJECT(goat_darea),"realize", + G_CALLBACK (goat_realize),NULL); + + gtk_widget_show(goat_darea); + goat_timeout = g_timeout_add(60,goat_timeout_func,NULL); + /*the GEGL shall not be translated*/ + g_object_set (G_OBJECT (nbook), + "show_tabs", TRUE, + "show_border", TRUE, + NULL); + gtk_notebook_append_page (nbook, goat_darea, + gtk_label_new ("GEGL")); + gtk_notebook_set_current_page(nbook,-1); + goat_loaded = TRUE; + } else { + gtk_notebook_set_current_page(nbook,-1); + } + return FALSE; +} + +/* phish code */ +#define PHSHFRAMES 8 +#define PHSHORIGWIDTH 288 +#define PHSHORIGHEIGHT 22 +#define PHSHWIDTH (PHSHORIGWIDTH/PHSHFRAMES) +#define PHSHHEIGHT PHSHORIGHEIGHT +#define PHSHCHECKTIMEOUT (g_random_int()%120*1000) +#define PHSHTIMEOUT 120 +#define PHSHHIDETIMEOUT 80 +#define PHSHXS 5 +#define PHSHYS ((g_random_int() % 2) + 1) +#define PHSHXSHIDEFACTOR 2.5 +#define PHSHYSHIDEFACTOR 2.5 +#define PHSHPIXELSTOREMOVE(p) (p[3] < 55 || p[2] > 200) + +/* Some important code copied from PonG */ +typedef struct _AppletContainer AppletContainer; +struct _AppletContainer { + GdkWindow *win; + gboolean hide_mode; + int state; + int x, y, xs, ys; + int handler; + GdkPixmap *phsh[2*PHSHFRAMES]; + GdkBitmap *phsh_mask[2*PHSHFRAMES]; +}; +static AppletContainer phsh = {NULL}; + +static void +phsh_kill (void) +{ + int i; + for (i = 0; i < 2*PHSHFRAMES; i++) { + if (phsh.phsh[i] != NULL) + g_object_unref (G_OBJECT (phsh.phsh[i])); + phsh.phsh[i] = NULL; + if (phsh.phsh_mask[i] != NULL) + g_object_unref (G_OBJECT (phsh.phsh_mask[i])); + phsh.phsh_mask[i] = NULL; + } + gdk_window_destroy (phsh.win); + g_source_remove (phsh.handler); + memset (&phsh, 0, sizeof (AppletContainer)); +} + +static gboolean +phsh_move (gpointer data) +{ + int orient, state; + gboolean change = TRUE; + + phsh.x += phsh.xs; + phsh.y += phsh.ys; + if (phsh.x <= -PHSHWIDTH || + phsh.x >= gdk_screen_width ()) { + phsh_kill (); + return FALSE; + } + if (phsh.y <= 0 || + phsh.y >= gdk_screen_height () - PHSHHEIGHT || + g_random_int() % (phsh.hide_mode?10:50) == 0) + phsh.ys = -phsh.ys; + + phsh.state ++; + if (phsh.hide_mode) { + phsh.state ++; + if (phsh.state >= 2*PHSHFRAMES) + phsh.state = 0; + } else if (phsh.state >= PHSHFRAMES) + phsh.state = 0; + + if (!phsh.hide_mode || phsh.state % 2 == 0) + change = TRUE; + + state = phsh.state / (phsh.hide_mode?2:1); + orient = phsh.xs >= 0 ? 0 : 1; + + if (change) { + gdk_window_set_back_pixmap (phsh.win, phsh.phsh[orient + 2*state], FALSE); + gdk_window_shape_combine_mask (phsh.win, phsh.phsh_mask[orient + 2*state], 0, 0); + gdk_window_clear (phsh.win); + } + + gdk_window_move (phsh.win, phsh.x, phsh.y); + gdk_window_raise (phsh.win); + + return TRUE; +} + +static void +phsh_unsea(GdkPixbuf *gp) +{ + guchar *pixels = gdk_pixbuf_get_pixels (gp); + int rs = gdk_pixbuf_get_rowstride (gp); + int w = gdk_pixbuf_get_width (gp); + int h = gdk_pixbuf_get_height (gp); + int x, y; + + for (y = 0; y < h; y++, pixels += rs) { + guchar *p = pixels; + for (x = 0; x < w; x++, p+=4) { + if (PHSHPIXELSTOREMOVE(p)) + p[3] = 0; + } + } +} + +static GdkFilterReturn +phsh_filter (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) +{ + XEvent *xevent = (XEvent *)gdk_xevent; + + if (xevent->type == ButtonPress && + ! phsh.hide_mode) { + g_source_remove (phsh.handler); + phsh.handler = g_timeout_add (PHSHHIDETIMEOUT, phsh_move, NULL); + phsh.xs *= PHSHXSHIDEFACTOR; + phsh.ys *= PHSHYSHIDEFACTOR; + phsh.hide_mode = TRUE; + if (phsh.x < (gdk_screen_width () / 2)) + phsh.xs *= -1; + } + return GDK_FILTER_CONTINUE; +} + +static char * +get_phsh_file (void) +{ + char *phsh_file; + + phsh_file = g_strdup_printf ("%s/%cand%c.png", ICONDIR, 'w', 'a'); + + return phsh_file; +} + +static GdkPixbuf * +get_phsh_frame (GdkPixbuf *pb, int frame) +{ + GdkPixbuf *newpb; + + newpb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + PHSHWIDTH, PHSHHEIGHT); + gdk_pixbuf_copy_area (pb, frame * PHSHWIDTH, 0, + PHSHWIDTH, PHSHHEIGHT, newpb, 0, 0); + + return newpb; +} + +/* this checks the screen */ +static void +check_screen (void) +{ + GdkWindowAttr attributes; + char *phsh_file; + GdkPixbuf *gp, *tmp; + int i; + + if (phsh.win != NULL) + return; + + phsh_file = get_phsh_file (); + + if (phsh_file == NULL) + return; + + tmp = gdk_pixbuf_new_from_file (phsh_file, NULL); + if (tmp == NULL) + return; + + g_free (phsh_file); + + if (gdk_pixbuf_get_width (tmp) != PHSHORIGWIDTH || + gdk_pixbuf_get_height (tmp) != PHSHORIGHEIGHT) { + g_object_unref (G_OBJECT (tmp)); + return; + } + + phsh.state = 0; + phsh.hide_mode = FALSE; + phsh.x = -PHSHWIDTH; + phsh.y = (g_random_int() % (gdk_screen_height() - PHSHHEIGHT - 2)) + 1; + phsh.xs = PHSHXS; + phsh.ys = PHSHYS; + + for (i = 0; i < PHSHFRAMES; i++) { + gp = get_phsh_frame (tmp, i); + phsh_unsea (gp); + gdk_pixbuf_render_pixmap_and_mask (gp, &phsh.phsh[2*i+1], + &phsh.phsh_mask[2*i+1], 128); + pixbuf_reverse (gp); + gdk_pixbuf_render_pixmap_and_mask (gp, &phsh.phsh[2*i], + &phsh.phsh_mask[2*i], 128); + g_object_unref (G_OBJECT (gp)); + } + + g_object_unref (G_OBJECT (tmp)); + + attributes.window_type = GDK_WINDOW_TEMP; + attributes.x = phsh.x; + attributes.y = phsh.y; + attributes.width = PHSHWIDTH; + attributes.height = PHSHHEIGHT; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_rgb_get_visual(); + attributes.colormap = gdk_rgb_get_colormap(); + attributes.event_mask = GDK_BUTTON_PRESS_MASK; + + phsh.win = gdk_window_new (NULL, &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_back_pixmap (phsh.win, phsh.phsh[0], FALSE); + gdk_window_shape_combine_mask (phsh.win, phsh.phsh_mask[0], 0, 0); + + /* setup the keys filter */ + gdk_window_add_filter (phsh.win, + phsh_filter, + NULL); + + gdk_window_show (phsh.win); + phsh.handler = g_timeout_add (PHSHTIMEOUT, phsh_move, NULL); +} + +static guint screen_check_id = 0; + +static gboolean +check_screen_timeout (gpointer data) +{ + screen_check_id = 0; + + check_screen (); + + screen_check_id = g_timeout_add (PHSHCHECKTIMEOUT, + check_screen_timeout, NULL); + return FALSE; +} + +void +start_screen_check (void) +{ + if (screen_check_id > 0) + g_source_remove (screen_check_id); + + check_screen_timeout (NULL); +} + +typedef struct { + gboolean live; + int x, y; +} InvGoat; + +typedef struct { + gboolean good; + int y; + int x; +} InvShot; + + +static GtkWidget *geginv = NULL; +static GtkWidget *geginv_canvas = NULL; +static GtkWidget *geginv_label = NULL; +static GdkPixmap *geginv_pixmap = NULL; +static GdkPixmap *inv_goat1 = NULL; +static GdkPixmap *inv_goat2 = NULL; +static GdkPixmap *inv_phsh1 = NULL; +static GdkBitmap *inv_phsh1_mask = NULL; +static GdkPixmap *inv_phsh2 = NULL; +static GdkBitmap *inv_phsh2_mask = NULL; +static int inv_phsh_state = 0; +static int inv_goat_state = 0; +static int inv_width = 0; +static int inv_height = 0; +static int inv_goat_width = 0; +static int inv_goat_height = 0; +static int inv_phsh_width = 0; +static int inv_phsh_height = 0; +#define INV_ROWS 3 +#define INV_COLS 5 +static InvGoat invs[INV_COLS][INV_ROWS] = { { { FALSE, 0, 0 } } }; +static int inv_num = INV_ROWS * INV_COLS; +static double inv_factor = 1.0; +static int inv_our_x = 0; +static int inv_x = 0; +static int inv_y = 0; +static int inv_first_col = 0; +static int inv_last_col = INV_COLS-1; +static int inv_level = 0; +static int inv_lives = 0; +static gboolean inv_do_pause = FALSE; +static gboolean inv_reverse = FALSE; +static gboolean inv_game_over = FALSE; +static gboolean inv_left_pressed = FALSE; +static gboolean inv_right_pressed = FALSE; +static gboolean inv_fire_pressed = FALSE; +static gboolean inv_left_released = FALSE; +static gboolean inv_right_released = FALSE; +static gboolean inv_fire_released = FALSE; +static gboolean inv_paused = FALSE; +static GSList *inv_shots = NULL; +static guint inv_draw_idle = 0; + +static void +inv_show_status (void) +{ + gchar *s, *t, *u, *v, *w; + if (geginv == NULL) + return; + + if (inv_game_over) { + t = g_strdup_printf (_("GAME OVER at level %d!"), + inv_level+1); + u = g_strdup_printf ("%s", t); + /* Translators: the first and third strings are similar to a + * title, and the second string is a small information text. + * The spaces are there only to separate all the strings, so + try to keep them as is. */ + s = g_strdup_printf (_("%1$s %2$s %3$s"), + u, _("Press 'q' to quit"), u); + g_free (t); + g_free (u); + + } else if (inv_paused) { + t = g_strdup_printf("%s", _("Paused")); + /* Translators: the first string is a title and the second + * string is a small information text. */ + s = g_strdup_printf (_("%1$s\t%2$s"), + t, _("Press 'p' to unpause")); + g_free (t); + + } else { + t = g_strdup_printf ("%d", inv_level+1); + u = g_strdup_printf ("%d", inv_lives); + v = g_strdup_printf (_("Level: %s, Lives: %s"), t, u); + w = g_strdup_printf ("%s", v); + /* Translators: the first string is a title and the second + * string is a small information text. */ + s = g_strdup_printf (_("%1$s\t%2$s"), w, + _("Left/Right to move, Space to fire, 'p' to pause, 'q' to quit")); + g_free (t); + g_free (u); + g_free (v); + g_free (w); + + } + gtk_label_set_markup (GTK_LABEL (geginv_label), s); + + g_free (s); +} + +static gboolean +inv_draw (gpointer data) +{ + GtkStyle *style; + GdkPixmap *goat; + GSList *li; + int i, j; + + if (data != geginv) { + inv_draw_idle = 0; + return FALSE; + } + + if ( ! gtk_widget_is_drawable (geginv_canvas) || + geginv_pixmap == NULL) + return TRUE; + + style = gtk_widget_get_style (geginv_canvas); + + gdk_draw_rectangle (geginv_pixmap, + style->white_gc, + TRUE /* filled */, + 0, 0, + inv_width, inv_height); + + if (inv_goat_state == 0) + goat = inv_goat1; + else + goat = inv_goat2; + + for (i = 0; i < INV_COLS; i++) { + for (j = 0; j < INV_ROWS; j++) { + int x, y; + if ( ! invs[i][j].live) + continue; + + x = invs[i][j].x*inv_factor - inv_goat_width/2, + y = invs[i][j].y*inv_factor - inv_goat_height/2, + + gdk_draw_drawable (geginv_pixmap, + style->white_gc, + goat, + 0, 0, + x, y, + inv_goat_width, + inv_goat_height); + } + } + + for (li = inv_shots; li != NULL; li = li->next) { + InvShot *shot = li->data; + + gdk_draw_rectangle (geginv_pixmap, + style->black_gc, + TRUE /* filled */, + (shot->x-1)*inv_factor, + (shot->y-4)*inv_factor, + 3, 8); + } + + if ( ! inv_game_over) { + GdkPixmap *phsh; + GdkBitmap *mask; + + if (inv_phsh_state < 5) { + phsh = inv_phsh1; + mask = inv_phsh1_mask; + } else { + phsh = inv_phsh2; + mask = inv_phsh2_mask; + } + + gdk_gc_set_clip_origin (style->white_gc, + inv_our_x*inv_factor - inv_phsh_width/2, + 550*inv_factor - inv_phsh_height/2); + + gdk_gc_set_clip_mask (style->white_gc, + mask); + + gdk_draw_drawable (geginv_pixmap, + style->white_gc, + phsh, + 0, 0, + inv_our_x*inv_factor - inv_phsh_width/2, + 550*inv_factor - inv_phsh_height/2, + inv_phsh_width, + inv_phsh_height); + + gdk_gc_set_clip_origin (style->white_gc, 0, 0); + + gdk_gc_set_clip_mask (style->white_gc, NULL); + } + + gdk_draw_drawable (gtk_widget_get_window (geginv_canvas), + style->white_gc, + geginv_pixmap, + 0, 0, + 0, 0, + inv_width, inv_height); + + gdk_flush (); + + if (inv_do_pause) { + sleep (1); + inv_do_pause = FALSE; + } + + inv_draw_idle = 0; + return FALSE; +} + +static void +inv_queue_draw (GtkWidget *window) +{ + if (inv_draw_idle == 0) + inv_draw_idle = g_idle_add (inv_draw, window); +} + +static void +inv_draw_explosion (int x, int y) +{ + GdkWindow *window; + GtkStyle *style; + int i; + GdkColormap *cmap; + GdkColor red; + GdkGC *gc; + + if ( ! gtk_widget_is_drawable (geginv_canvas)) + return; + + window = gtk_widget_get_window (geginv_canvas); + style = gtk_widget_get_style (geginv_canvas); + + cmap = gdk_drawable_get_colormap (window); + gdk_color_parse ("red", &red); + gdk_colormap_alloc_color (cmap, &red, FALSE, TRUE); + + gc = gdk_gc_new (window); + gdk_gc_set_foreground (gc, &red); + gdk_gc_set_background (gc, &red); + + for (i = 5; i < 100; i += 5) { + gdk_draw_arc (window, + gc, + TRUE /* filled */, + x-i, y-i, + i*2, i*2, + 0, 360*64); + gdk_flush (); + g_usleep (50000); + } + + g_object_unref (G_OBJECT (gc)); + + for (i = 5; i < 100; i += 5) { + gdk_draw_arc (window, + style->white_gc, + TRUE /* filled */, + x-i, y-i, + i*2, i*2, + 0, 360*64); + gdk_flush (); + g_usleep (50000); + } + + gdk_colormap_free_colors (cmap, &red, 1); + + inv_queue_draw (geginv); +} + + +static void +inv_do_game_over (void) +{ + GSList *li; + + inv_game_over = TRUE; + + for (li = inv_shots; li != NULL; li = li->next) { + InvShot *shot = li->data; + shot->good = FALSE; + } + + inv_queue_draw (geginv); + + inv_show_status (); +} + + +static GdkPixbuf * +pb_scale (GdkPixbuf *pb, double scale) +{ + int w, h; + + if (scale == 1.0) + return (GdkPixbuf *)g_object_ref ((GObject *)pb); + + w = gdk_pixbuf_get_width (pb) * scale; + h = gdk_pixbuf_get_height (pb) * scale; + + return gdk_pixbuf_scale_simple (pb, w, h, + GDK_INTERP_BILINEAR); +} + +static void +refind_first_and_last (void) +{ + int i, j; + + for (i = 0; i < INV_COLS; i++) { + gboolean all_null = TRUE; + for (j = 0; j < INV_ROWS; j++) { + if (invs[i][j].live) { + all_null = FALSE; + break; + } + } + if ( ! all_null) { + inv_first_col = i; + break; + } + } + + for (i = INV_COLS-1; i >= 0; i--) { + gboolean all_null = TRUE; + for (j = 0; j < INV_ROWS; j++) { + if (invs[i][j].live) { + all_null = FALSE; + break; + } + } + if ( ! all_null) { + inv_last_col = i; + break; + } + } +} + +static void +whack_gegl (int i, int j) +{ + if ( ! invs[i][j].live) + return; + + invs[i][j].live = FALSE; + inv_num --; + + if (inv_num > 0) { + refind_first_and_last (); + } else { + inv_x = 70; + inv_y = 70; + inv_first_col = 0; + inv_last_col = INV_COLS-1; + inv_reverse = FALSE; + + g_slist_foreach (inv_shots, (GFunc)g_free, NULL); + g_slist_free (inv_shots); + inv_shots = NULL; + + for (i = 0; i < INV_COLS; i++) { + for (j = 0; j < INV_ROWS; j++) { + invs[i][j].live = TRUE; + invs[i][j].x = 70 + i * 100; + invs[i][j].y = 70 + j * 80; + } + } + inv_num = INV_ROWS * INV_COLS; + + inv_level ++; + + inv_show_status (); + } + + inv_queue_draw (geginv); +} + +static gboolean +geginv_timeout (gpointer data) +{ + int i, j; + int limitx1; + int limitx2; + int speed; + int shots; + int max_shots; + + if (inv_paused) + return TRUE; + + if (geginv != data || + inv_num <= 0 || + inv_y > 700) + return FALSE; + + limitx1 = 70 - (inv_first_col * 100); + limitx2 = 800 - 70 - (inv_last_col * 100); + + if (inv_game_over) { + inv_y += 30; + } else { + if (inv_num < (INV_COLS*INV_ROWS)/3) + speed = 45+2*inv_level; + else if (inv_num < (2*INV_COLS*INV_ROWS)/3) + speed = 30+2*inv_level; + else + speed = 15+2*inv_level; + + if (inv_reverse) { + inv_x -= speed; + if (inv_x < limitx1) { + inv_reverse = FALSE; + inv_x = (limitx1 + (limitx1 - inv_x)); + inv_y += 30+inv_level; + } + } else { + inv_x += speed; + if (inv_x > limitx2) { + inv_reverse = TRUE; + inv_x = (limitx2 - (inv_x - limitx2)); + inv_y += 30+inv_level; + } + } + } + + for (i = 0; i < INV_COLS; i++) { + for (j = 0; j < INV_ROWS; j++) { + if (invs[i][j].live) { + invs[i][j].x = inv_x + i * 100; + invs[i][j].y = inv_y + j * 80; + + if ( ! inv_game_over && + invs[i][j].y >= 570) { + inv_do_game_over (); + } else if ( ! inv_game_over && + invs[i][j].y >= 530 && + invs[i][j].x + 40 > inv_our_x - 25 && + invs[i][j].x - 40 < inv_our_x + 25) { + whack_gegl (i,j); + inv_lives --; + inv_draw_explosion (inv_our_x, 550); + if (inv_lives <= 0) { + inv_do_game_over (); + } else { + g_slist_foreach (inv_shots, (GFunc)g_free, NULL); + g_slist_free (inv_shots); + inv_shots = NULL; + inv_our_x = 400; + inv_do_pause = TRUE; + inv_show_status (); + } + } + } + } + } + + shots = 0; + max_shots = (g_random_int () >> 3) % (2+inv_level); + while ( ! inv_game_over && shots < MIN (max_shots, inv_num)) { + int i = (g_random_int () >> 3) % INV_COLS; + for (j = INV_ROWS-1; j >= 0; j--) { + if (invs[i][j].live) { + InvShot *shot = g_new0 (InvShot, 1); + + shot->good = FALSE; + shot->x = invs[i][j].x + (g_random_int () % 6) - 3; + shot->y = invs[i][j].y + inv_goat_height/2 + (g_random_int () % 3); + + inv_shots = g_slist_prepend (inv_shots, shot); + shots++; + break; + } + } + } + + inv_goat_state = (inv_goat_state+1) % 2; + + inv_queue_draw (geginv); + + g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv); + + return FALSE; +} + +static gboolean +find_gegls (int x, int y) +{ + int i, j; + + /* FIXME: this is stupid, we can do better */ + for (i = 0; i < INV_COLS; i++) { + for (j = 0; j < INV_ROWS; j++) { + int ix = invs[i][j].x; + int iy = invs[i][j].y; + + if ( ! invs[i][j].live) + continue; + + if (y >= iy - 30 && + y <= iy + 30 && + x >= ix - 40 && + x <= ix + 40) { + whack_gegl (i, j); + return TRUE; + } + } + } + + return FALSE; +} + + +static gboolean +geginv_move_timeout (gpointer data) +{ + GSList *li; + static int shot_inhibit = 0; + + if (inv_paused) + return TRUE; + + if (geginv != data || + inv_num <= 0 || + inv_y > 700) + return FALSE; + + inv_phsh_state = (inv_phsh_state+1)%10; + + /* we will be drawing something */ + if (inv_shots != NULL) + inv_queue_draw (geginv); + + li = inv_shots; + while (li != NULL) { + InvShot *shot = li->data; + + if (shot->good) { + shot->y -= 30; + if (find_gegls (shot->x, shot->y) || + shot->y <= 0) { + GSList *list = li; + /* we were restarted */ + if (inv_shots == NULL) + return TRUE; + li = li->next; + g_free (shot); + inv_shots = g_slist_delete_link (inv_shots, list); + continue; + } + } else /* bad */ { + shot->y += 30; + if ( ! inv_game_over && + shot->y >= 535 && + shot->y <= 565 && + shot->x >= inv_our_x - 25 && + shot->x <= inv_our_x + 25) { + inv_lives --; + inv_draw_explosion (inv_our_x, 550); + if (inv_lives <= 0) { + inv_do_game_over (); + } else { + g_slist_foreach (inv_shots, (GFunc)g_free, NULL); + g_slist_free (inv_shots); + inv_shots = NULL; + inv_our_x = 400; + inv_do_pause = TRUE; + inv_show_status (); + return TRUE; + } + } + + if (shot->y >= 600) { + GSList *list = li; + li = li->next; + g_free (shot); + inv_shots = g_slist_delete_link (inv_shots, list); + continue; + } + } + + li = li->next; + } + + if ( ! inv_game_over) { + if (inv_left_pressed && inv_our_x > 100) { + inv_our_x -= 20; + inv_queue_draw (geginv); + } else if (inv_right_pressed && inv_our_x < 700) { + inv_our_x += 20; + inv_queue_draw (geginv); + } + } + + if (shot_inhibit > 0) + shot_inhibit--; + + if ( ! inv_game_over && inv_fire_pressed && shot_inhibit == 0) { + InvShot *shot = g_new0 (InvShot, 1); + + shot->good = TRUE; + shot->x = inv_our_x; + shot->y = 540; + + inv_shots = g_slist_prepend (inv_shots, shot); + + shot_inhibit = 5; + + inv_queue_draw (geginv); + } + + if (inv_left_released) + inv_left_pressed = FALSE; + if (inv_right_released) + inv_right_pressed = FALSE; + if (inv_fire_released) + inv_fire_pressed = FALSE; + + return TRUE; +} + +static gboolean +inv_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + switch (event->keyval) { + case GDK_Left: + case GDK_KP_Left: + case GDK_Pointer_Left: + inv_left_pressed = TRUE; + inv_left_released = FALSE; + return TRUE; + case GDK_Right: + case GDK_KP_Right: + case GDK_Pointer_Right: + inv_right_pressed = TRUE; + inv_right_released = FALSE; + return TRUE; + case GDK_space: + case GDK_KP_Space: + inv_fire_pressed = TRUE; + inv_fire_released = FALSE; + return TRUE; + default: + break; + } + return FALSE; +} + +static gboolean +inv_key_release (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + switch (event->keyval) { + case GDK_Left: + case GDK_KP_Left: + case GDK_Pointer_Left: + inv_left_released = TRUE; + return TRUE; + case GDK_Right: + case GDK_KP_Right: + case GDK_Pointer_Right: + inv_right_released = TRUE; + return TRUE; + case GDK_space: + case GDK_KP_Space: + inv_fire_released = TRUE; + return TRUE; + case GDK_q: + case GDK_Q: + gtk_widget_destroy (widget); + return TRUE; + case GDK_p: + case GDK_P: + inv_paused = ! inv_paused; + inv_show_status (); + return TRUE; + default: + break; + } + return FALSE; +} + +static gboolean +ensure_creatures (void) +{ + GdkPixbuf *pb, *pb1, *phsh1, *phsh2, *goat1, *goat2; + char *phsh_file; + char *goat_file; + + if (inv_goat1 != NULL) + return TRUE; + + phsh_file = get_phsh_file (); + + if (phsh_file == NULL) + return FALSE; + + pb = gdk_pixbuf_new_from_file (phsh_file, NULL); + g_free (phsh_file); + if (pb == NULL) + return FALSE; + + pb1 = get_phsh_frame (pb, 1); + phsh1 = pb_scale (pb1, inv_factor); + g_object_unref (G_OBJECT (pb1)); + phsh_unsea (phsh1); + + pb1 = get_phsh_frame (pb, 2); + phsh2 = pb_scale (pb1, inv_factor); + g_object_unref (G_OBJECT (pb1)); + phsh_unsea (phsh2); + + g_object_unref (G_OBJECT (pb)); + + goat_file = g_strdup_printf ("%s/mate-gegl2.png", ICONDIR); + if (goat_file == NULL) { + g_object_unref (G_OBJECT (phsh1)); + g_object_unref (G_OBJECT (phsh2)); + return FALSE; + } + + pb = gdk_pixbuf_new_from_file (goat_file, NULL); + g_free (goat_file); + if (pb == NULL) { + g_object_unref (G_OBJECT (phsh1)); + g_object_unref (G_OBJECT (phsh2)); + return FALSE; + } + + goat1 = pb_scale (pb, inv_factor * 0.66); + g_object_unref (pb); + + goat_file = g_strdup_printf ("%s/mate-gegl2-2.png", ICONDIR); + if (goat_file == NULL) { + g_object_unref (G_OBJECT (goat1)); + g_object_unref (G_OBJECT (phsh1)); + g_object_unref (G_OBJECT (phsh2)); + return FALSE; + } + + pb = gdk_pixbuf_new_from_file (goat_file, NULL); + g_free (goat_file); + if (pb == NULL) { + g_object_unref (G_OBJECT (goat1)); + g_object_unref (G_OBJECT (phsh1)); + g_object_unref (G_OBJECT (phsh2)); + return FALSE; + } + + goat2 = pb_scale (pb, inv_factor * 0.66); + g_object_unref (pb); + + inv_goat_width = gdk_pixbuf_get_width (goat1); + inv_goat_height = gdk_pixbuf_get_height (goat1); + inv_phsh_width = gdk_pixbuf_get_width (phsh1); + inv_phsh_height = gdk_pixbuf_get_height (phsh1); + + gdk_pixbuf_render_pixmap_and_mask (goat1, &inv_goat1, NULL, 127); + g_object_unref (G_OBJECT (goat1)); + gdk_pixbuf_render_pixmap_and_mask (goat2, &inv_goat2, NULL, 127); + g_object_unref (G_OBJECT (goat2)); + gdk_pixbuf_render_pixmap_and_mask (phsh1, &inv_phsh1, &inv_phsh1_mask, 127); + g_object_unref (G_OBJECT (phsh1)); + gdk_pixbuf_render_pixmap_and_mask (phsh2, &inv_phsh2, &inv_phsh2_mask, 127); + g_object_unref (G_OBJECT (phsh2)); + + return TRUE; +} + +static void +geginv_destroyed (GtkWidget *w, gpointer data) +{ + geginv = NULL; + if (geginv_pixmap != NULL) + g_object_unref (G_OBJECT (geginv_pixmap)); + geginv_pixmap = NULL; +} + +static void +geginv_realized (GtkWidget *w, gpointer data) +{ + if (geginv_pixmap == NULL) + geginv_pixmap = gdk_pixmap_new (gtk_widget_get_window (w), + inv_width, inv_height, + gdk_visual_get_depth (gtk_widget_get_visual (w))); +} + +static gboolean +inv_expose (GtkWidget *widget, GdkEventExpose *event) +{ + if ( ! gtk_widget_is_drawable (widget) || + geginv_pixmap == NULL) + return FALSE; + + inv_queue_draw (geginv); + /* + gdk_draw_drawable (geginv_canvas->window, + geginv_canvas->style->white_gc, + geginv_pixmap, + event->area.x, event->area.x, + event->area.x, event->area.x, + event->area.width, event->area.height); + */ + + return FALSE; +} + +void +start_geginv (void) +{ + GtkWidget *vbox; + int i, j; + + if (geginv != NULL) { + gtk_window_present (GTK_WINDOW (geginv)); + return; + } + + inv_width = 800; + inv_height = 600; + + if (inv_width > gdk_screen_width () * 0.9) { + inv_width = gdk_screen_width () * 0.9; + inv_height = inv_width * (600.0/800.0); + } + + if (inv_height > gdk_screen_height () * 0.9) { + inv_height = gdk_screen_height () * 0.9; + inv_width = inv_height * (800.0/600.0); + } + + inv_factor = (double)inv_width / 800.0; + + if ( ! ensure_creatures ()) + return; + + geginv = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (geginv), _("Killer GEGLs from Outer Space")); + g_object_set (G_OBJECT (geginv), "resizable", FALSE, NULL); + g_signal_connect (G_OBJECT (geginv), "destroy", + G_CALLBACK (geginv_destroyed), + NULL); + + geginv_canvas = gtk_drawing_area_new (); + gtk_widget_set_double_buffered (GTK_WIDGET (geginv_canvas), FALSE); + gtk_widget_set_size_request (geginv_canvas, inv_width, inv_height); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (geginv), vbox); + gtk_box_pack_start (GTK_BOX (vbox), geginv_canvas, TRUE, TRUE, 0); + + geginv_label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (vbox), geginv_label, FALSE, FALSE, 0); + + inv_our_x = 400; + inv_x = 70; + inv_y = 70; + inv_first_col = 0; + inv_level = 0; + inv_lives = 3; + inv_last_col = INV_COLS-1; + inv_reverse = FALSE; + inv_game_over = FALSE; + inv_left_pressed = FALSE; + inv_right_pressed = FALSE; + inv_fire_pressed = FALSE; + inv_left_released = FALSE; + inv_right_released = FALSE; + inv_fire_released = FALSE; + inv_paused = FALSE; + + gtk_widget_add_events (geginv, GDK_KEY_RELEASE_MASK); + + g_signal_connect (G_OBJECT (geginv), "key_press_event", + G_CALLBACK (inv_key_press), NULL); + g_signal_connect (G_OBJECT (geginv), "key_release_event", + G_CALLBACK (inv_key_release), NULL); + g_signal_connect (G_OBJECT (geginv), "realize", + G_CALLBACK (geginv_realized), NULL); + g_signal_connect (GTK_OBJECT (geginv_canvas), "expose_event", + G_CALLBACK (inv_expose), NULL); + + g_slist_foreach (inv_shots, (GFunc)g_free, NULL); + g_slist_free (inv_shots); + inv_shots = NULL; + + for (i = 0; i < INV_COLS; i++) { + for (j = 0; j < INV_ROWS; j++) { + invs[i][j].live = TRUE; + invs[i][j].x = 70 + i * 100; + invs[i][j].y = 70 + j * 80; + } + } + inv_num = INV_ROWS * INV_COLS; + + g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv); + g_timeout_add (90, geginv_move_timeout, geginv); + + inv_show_status (); + + gtk_widget_show_all (geginv); +} + +static gboolean +move_window_handler (gpointer data) +{ + int x, y, sx, sy, wx, wy, foox, fooy; + GtkWidget *win = data; + GtkAllocation allocation; + + data = g_object_get_data (G_OBJECT (win), "move_speed_x"); + sx = GPOINTER_TO_INT (data); + data = g_object_get_data (G_OBJECT (win), "move_speed_y"); + sy = GPOINTER_TO_INT (data); + + gtk_widget_get_allocation (win, &allocation); + + gdk_window_get_pointer (NULL, &x, &y, NULL); + wx = allocation.x; + wy = allocation.y; + + foox = wx + (allocation.width / 2); + fooy = wy + (allocation.height / 2); + + if (sqrt ((foox - x)*(foox - x) + (fooy - y)*(fooy - y)) < + MAX (allocation.width, allocation.height)) { + if (foox < x) sx -= 5; + else sx += 5; + if (fooy < y) sy -= 5; + else sy += 5; + } else { + sx /= 2; + sy /= 2; + } + + if (sx > 50) sx = 50; + else if (sx < -50) sx = -50; + if (sy > 50) sy = 50; + else if (sy < -50) sy = -50; + + wx += sx; + wy += sy; + + if (wx < 0) wx = 0; + if (wy < 0) wy = 0; + if (wx + allocation.width > gdk_screen_width ()) + wx = gdk_screen_width () - allocation.width; + if (wy + allocation.height > gdk_screen_height ()) + wy = gdk_screen_height () - allocation.height; + + gtk_window_move (GTK_WINDOW (win), wx, wy); + allocation.x = wx; + allocation.y = wy; + gtk_widget_set_allocation (win, &allocation); + + data = GINT_TO_POINTER (sx); + g_object_set_data (G_OBJECT (win), "move_speed_x", data); + data = GINT_TO_POINTER (sy); + g_object_set_data (G_OBJECT (win), "move_speed_y", data); + + return TRUE; +} + +static void +move_window_destroyed (GtkWidget *win) +{ + gpointer data = g_object_get_data (G_OBJECT (win), "move_window_handler"); + int handler = GPOINTER_TO_INT (data); + + if (handler != 0) + g_source_remove (handler); + g_object_set_data (G_OBJECT (win), "move_window_handler", NULL); +} + +static void +doblah (GtkWidget *window) +{ + gpointer data = g_object_get_data (G_OBJECT (window), "move_window_handler"); + int handler = GPOINTER_TO_INT (data); + + if (handler == 0) { + handler = g_timeout_add (30, move_window_handler, window); + data = GINT_TO_POINTER (handler); + g_object_set_data (G_OBJECT (window), "move_window_handler", data); + g_signal_connect (G_OBJECT (window), "destroy", + G_CALLBACK (move_window_destroyed), + NULL); + } +} + +gboolean +panel_dialog_window_event (GtkWidget *window, + GdkEvent *event) +{ + switch (event->type) { + static int foo = 0; + case GDK_KEY_PRESS: + if((event->key.state & GDK_CONTROL_MASK) && foo < 4) { + switch (event->key.keyval) { + case GDK_r: + case GDK_R: + if(foo == 3) { doblah (window); } foo = 0; break; + case GDK_a: + case GDK_A: + if(foo == 2) { foo++; } else { foo = 0; } break; + case GDK_e: + case GDK_E: + if(foo == 1) { foo++; } else { foo = 0; } break; + case GDK_f: + case GDK_F: + if(foo == 0) { foo++; } else { foo = 0; } break; + default: + foo = 0; + } + } + default: + break; + } + + return FALSE; +} diff --git a/mate-panel/nothing.h b/mate-panel/nothing.h new file mode 100644 index 00000000..1dc7f02f --- /dev/null +++ b/mate-panel/nothing.h @@ -0,0 +1,22 @@ +#ifndef NOTHING_H +#define NOTHING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void start_screen_check (void); +void start_geginv (void); +gboolean panel_dialog_window_event (GtkWidget *window, + GdkEvent *event); +int config_event (GtkWidget *widget, + GdkEvent *event, + GtkNotebook *nbook); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mate-panel/panel-a11y.c b/mate-panel/panel-a11y.c new file mode 100644 index 00000000..0c308c4d --- /dev/null +++ b/mate-panel/panel-a11y.c @@ -0,0 +1,135 @@ +/* + * panel-a11y.c: panel accessibility support module + * + * Copyright (C) 2002, 2003 Sun Microsystems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + */ + +#include "panel-a11y.h" + +gboolean +panel_a11y_get_is_a11y_enabled (GtkWidget *widget) +{ + static gboolean initialised = FALSE; + static gboolean a11y_enabled = FALSE; + + if (!initialised) { + a11y_enabled = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (widget)); + initialised = TRUE; + } + + return a11y_enabled; +} + +void +panel_a11y_set_atk_name_desc (GtkWidget *widget, + const char *name, + const char *desc) +{ + AtkObject *aobj; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (!panel_a11y_get_is_a11y_enabled (widget)) + return; + + aobj = gtk_widget_get_accessible (widget); + + if (name) + atk_object_set_name (aobj, name); + + if (desc) + atk_object_set_description (aobj, desc); +} + +/** + * panel_a11y_set_atk_relation + * @widget : The Gtk widget which is labelled by @label + * @label : The label for the @widget. + * + * Description : This function establishes atk relation + * between a gtk widget and a label. + */ +void +panel_a11y_set_atk_relation (GtkWidget *widget, + GtkLabel *label) +{ + AtkObject *aobject; + AtkRelationSet *relation_set; + AtkRelation *relation; + AtkObject *targets [1]; + + g_return_if_fail (GTK_IS_WIDGET(widget)); + g_return_if_fail (GTK_IS_LABEL(label)); + + if (!panel_a11y_get_is_a11y_enabled (widget)) + return; + + aobject = gtk_widget_get_accessible (widget); + + gtk_label_set_mnemonic_widget (label, widget); + + targets [0] = gtk_widget_get_accessible (GTK_WIDGET (label)); + + relation_set = atk_object_ref_relation_set (aobject); + + relation = atk_relation_new (targets, 1, ATK_RELATION_LABELLED_BY); + atk_relation_set_add (relation_set, relation); + g_object_unref (relation); +} + +/** + * panel_a11y_query_accessible_parent_type + * @type: widget type + * @type_info: accessible object type info to complete + * + * Standard hack which figures out the #GType of the accessible + * object for @type's parent type. Also, fills out the class_size + * and instance_size of @type_info to match the size of the parent + * type. + * + * Basically, this is the hack to use if you want to derive from + * an accessible object implementation in gail. + * + * Returns: the #GType of @type's parent's accessible peer + */ +GType +panel_a11y_query_accessible_parent_type (GType type, + GTypeInfo *type_info) +{ + AtkObjectFactory *factory; + GType parent_type; + GType accessible_parent_type; + + g_return_val_if_fail (G_TYPE_IS_OBJECT (type), G_TYPE_INVALID); + + parent_type = g_type_parent (type); + + factory = atk_registry_get_factory (atk_get_default_registry (), parent_type); + + accessible_parent_type = atk_object_factory_get_accessible_type (factory); + + if (type_info) { + GTypeQuery query; + + g_type_query (accessible_parent_type, &query); + + type_info->class_size = query.class_size; + type_info->instance_size = query.instance_size; + } + + return atk_object_factory_get_accessible_type (factory); +} diff --git a/mate-panel/panel-a11y.h b/mate-panel/panel-a11y.h new file mode 100644 index 00000000..927698aa --- /dev/null +++ b/mate-panel/panel-a11y.h @@ -0,0 +1,43 @@ +/* + * panel-a11y.h: panel accessibility support module + * + * Copyright (C) 2002, 2003 Sun Microsystems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PANEL_A11Y_H__ +#define __PANEL_A11Y_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +gboolean panel_a11y_get_is_a11y_enabled (GtkWidget *widget); +void panel_a11y_set_atk_name_desc (GtkWidget *widget, + const char *name, + const char *desc); +void panel_a11y_set_atk_relation (GtkWidget *widget, + GtkLabel *label); +GType panel_a11y_query_accessible_parent_type (GType type, + GTypeInfo *type_info); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_A11Y_H__ */ diff --git a/mate-panel/panel-action-button.c b/mate-panel/panel-action-button.c new file mode 100644 index 00000000..04536fff --- /dev/null +++ b/mate-panel/panel-action-button.c @@ -0,0 +1,907 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * panel-action-button.c: panel "Action Button" module + * + * Copyright (C) 2002 Sun Microsystems, Inc. + * Copyright (C) 2004 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include +#include +#include + +#include "panel-action-button.h" + +#include + +#include +#include +#include +#include + +#include "applet.h" +#include "panel-config-global.h" +#include "panel-mateconf.h" +#include "panel-profile.h" +#include "panel-typebuiltins.h" +#include "panel-force-quit.h" +#include "panel-util.h" +#include "panel-session.h" +#include "panel-globals.h" +#include "panel-run-dialog.h" +#include "panel-a11y.h" +#include "panel-lockdown.h" +#include "panel-compatibility.h" +#include "panel-icon-names.h" + +G_DEFINE_TYPE (PanelActionButton, panel_action_button, BUTTON_TYPE_WIDGET) + +#define PANEL_ACTION_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_ACTION_BUTTON, PanelActionButtonPrivate)) + +#define LOGOUT_PROMPT_KEY "/apps/mate-session/options/logout_prompt" + +enum { + PROP_0, + PROP_ACTION_TYPE, + PROP_DND_ENABLED +}; + +struct _PanelActionButtonPrivate { + PanelActionButtonType type; + AppletInfo *info; + + guint mateconf_notify; + + guint dnd_enabled : 1; +}; + +static MateConfEnumStringPair panel_action_type_map [] = { + { PANEL_ACTION_NONE, "none" }, + { PANEL_ACTION_LOCK, "lock" }, + { PANEL_ACTION_LOGOUT, "logout" }, + { PANEL_ACTION_RUN, "run" }, + { PANEL_ACTION_SEARCH, "search" }, + { PANEL_ACTION_FORCE_QUIT, "force-quit" }, + { PANEL_ACTION_CONNECT_SERVER, "connect-server" }, + { PANEL_ACTION_SHUTDOWN, "shutdown" }, + /* compatibility with MATE < 2.13.90 */ + { PANEL_ACTION_SCREENSHOT, "screenshot" }, + { 0, NULL }, +}; + +/* Lock Screen + */ +static void panel_action_lock_screen(GtkWidget* widget) +{ + panel_lock_screen(gtk_widget_get_screen(widget)); +} + +static gboolean +screensaver_properties_enabled (void) +{ + if (panel_lockdown_get_locked_down () || + panel_lockdown_get_disable_lock_screen ()) + return FALSE; + + return panel_lock_screen_action_available ("prefs"); +} + +static gboolean +screensaver_enabled (void) +{ + if (panel_lockdown_get_disable_lock_screen ()) + return FALSE; + + return panel_lock_screen_action_available ("lock"); +} + +static gboolean +panel_action_lock_is_disabled (void) +{ + return !screensaver_enabled (); +} + +static void +panel_action_lock_setup_menu (PanelActionButton *button) +{ + mate_panel_applet_add_callback (button->priv->info, + "activate", + NULL, + _("_Activate Screensaver"), + screensaver_enabled); + + mate_panel_applet_add_callback (button->priv->info, + "lock", + NULL, + _("_Lock Screen"), + screensaver_enabled); + + mate_panel_applet_add_callback (button->priv->info, + "prefs", + GTK_STOCK_PROPERTIES, + _("_Properties"), + screensaver_properties_enabled); +} + +static void +panel_action_lock_invoke_menu (PanelActionButton *button, + const char *callback_name) +{ + g_return_if_fail (PANEL_IS_ACTION_BUTTON (button)); + g_return_if_fail (callback_name != NULL); + + panel_lock_screen_action (gtk_widget_get_screen (GTK_WIDGET (button)), + callback_name); +} + +/* Log Out + */ +static void +panel_action_logout (GtkWidget *widget) +{ + PanelSessionManager *manager; + gboolean not_prompt; + + not_prompt = mateconf_client_get_bool (panel_mateconf_get_client (), + LOGOUT_PROMPT_KEY, NULL); + /* this avoids handling errors from mateconf since prompting is + * safer */ + not_prompt = !not_prompt; + + manager = panel_session_manager_get (); + + if (not_prompt) + panel_session_manager_request_logout (manager, + PANEL_SESSION_MANAGER_LOGOUT_MODE_NO_CONFIRMATION); + else + /* FIXME: we need to use widget to get the screen for the + * confirmation dialog, see + * http://bugzilla.gnome.org/show_bug.cgi?id=536914 */ + panel_session_manager_request_logout (manager, + PANEL_SESSION_MANAGER_LOGOUT_MODE_NORMAL); +} + +static void +panel_action_shutdown (GtkWidget *widget) +{ + PanelSessionManager *manager; + + manager = panel_session_manager_get (); + panel_session_manager_request_shutdown (manager); +} + +static gboolean +panel_action_shutdown_reboot_is_disabled (void) +{ + PanelSessionManager *manager; + + if (panel_lockdown_get_disable_log_out()) + return TRUE; + + manager = panel_session_manager_get (); + + return (!panel_session_manager_is_shutdown_available (manager)); +} + +/* Run Application + */ +static void +panel_action_run_program (GtkWidget *widget) +{ + panel_run_dialog_present (gtk_widget_get_screen (widget), + gtk_get_current_event_time ()); +} + +/* Search For Files + */ +static void +panel_action_search (GtkWidget *widget) +{ + GdkScreen *screen; + + screen = gtk_widget_get_screen (widget); + panel_launch_desktop_file_with_fallback ("mate-search-tool.desktop", + "mate-search-tool", + screen, NULL); +} + +/* Force Quit + */ +static void +panel_action_force_quit (GtkWidget *widget) +{ + panel_force_quit (gtk_widget_get_screen (widget), + gtk_get_current_event_time ()); +} + +/* Connect Server + */ +static void +panel_action_connect_server (GtkWidget *widget) +{ + GdkScreen *screen; + GError *error; + + screen = gtk_widget_get_screen (GTK_WIDGET (widget)); + error = NULL; + + gdk_spawn_command_line_on_screen (screen, "caja-connect-server", + &error); + + if (error) { + panel_error_dialog (NULL, screen, + "cannot_connect_server", + TRUE, + _("Could not connect to server"), + error->message); + g_clear_error (&error); + } +} + +typedef struct { + PanelActionButtonType type; + char *icon_name; + char *text; + char *tooltip; + char *help_index; + char *drag_id; + void (*invoke) (GtkWidget *widget); + void (*setup_menu) (PanelActionButton *button); + void (*invoke_menu) (PanelActionButton *button, + const char *callback_name); + gboolean (*is_disabled) (void); +} PanelAction; + +/* Keep order in sync with PanelActionButtonType + */ +static PanelAction actions [] = { + { + PANEL_ACTION_NONE, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL + }, + { + PANEL_ACTION_LOCK, + PANEL_ICON_LOCKSCREEN, + N_("Lock Screen"), + N_("Protect your computer from unauthorized use"), + "gospanel-21", + "ACTION:lock:NEW", + panel_action_lock_screen, + panel_action_lock_setup_menu, + panel_action_lock_invoke_menu, + panel_action_lock_is_disabled + }, + { + PANEL_ACTION_LOGOUT, + PANEL_ICON_LOGOUT, + /* when changing one of those two strings, don't forget to + * update the ones in panel-menu-items.c (look for + * "1" (msgctxt: "panel:showusername")) */ + N_("Log Out..."), + N_("Log out of this session to log in as a different user"), + "gospanel-20", + "ACTION:logout:NEW", + panel_action_logout, NULL, NULL, + panel_lockdown_get_disable_log_out + }, + { + PANEL_ACTION_RUN, + PANEL_ICON_RUN, + N_("Run Application..."), + N_("Run an application by typing a command or choosing from a list"), + "gospanel-555", + "ACTION:run:NEW", + panel_action_run_program, NULL, NULL, + panel_lockdown_get_disable_command_line + }, + { + PANEL_ACTION_SEARCH, + PANEL_ICON_SEARCHTOOL, + N_("Search for Files..."), + N_("Locate documents and folders on this computer by name or content"), + "gospanel-554", + "ACTION:search:NEW", + panel_action_search, NULL, NULL, NULL + }, + { + PANEL_ACTION_FORCE_QUIT, + PANEL_ICON_FORCE_QUIT, + N_("Force Quit"), + N_("Force a misbehaving application to quit"), + "gospanel-563", + "ACTION:force-quit:NEW", + panel_action_force_quit, NULL, NULL, + panel_lockdown_get_disable_force_quit + }, + { + PANEL_ACTION_CONNECT_SERVER, + PANEL_ICON_REMOTE, //FIXME icon + N_("Connect to Server..."), + N_("Connect to a remote computer or shared disk"), + "caja-server-connect", + "ACTION:connect-server:NEW", + panel_action_connect_server, NULL, NULL, NULL + }, + { + PANEL_ACTION_SHUTDOWN, + PANEL_ICON_SHUTDOWN, + N_("Shut Down..."), + N_("Shut down the computer"), + "gospanel-20", + "ACTION:shutdown:NEW", + panel_action_shutdown, NULL, NULL, + panel_action_shutdown_reboot_is_disabled + }, + /* deprecated actions */ + { + PANEL_ACTION_SCREENSHOT, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL + } +}; + +static gboolean +panel_action_get_is_deprecated (PanelActionButtonType type) +{ + g_return_val_if_fail (type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, FALSE); + + return (type >= PANEL_ACTION_SCREENSHOT); +} + +gboolean +panel_action_get_is_disabled (PanelActionButtonType type) +{ + g_return_val_if_fail (type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, FALSE); + + if (panel_action_get_is_deprecated (type)) + return TRUE; + + if (actions [type].is_disabled) + return actions [type].is_disabled (); + + return FALSE; +} + +GCallback +panel_action_get_invoke (PanelActionButtonType type) +{ + g_return_val_if_fail (type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, NULL); + + g_assert (actions[type].invoke != NULL); + + return G_CALLBACK (actions[type].invoke); +} + +const char* panel_action_get_icon_name(PanelActionButtonType type) +{ + g_return_val_if_fail(type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, NULL); + + return actions[type].icon_name; +} + +const char* panel_action_get_text(PanelActionButtonType type) +{ + g_return_val_if_fail(type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, NULL); + + return _(actions[type].text); +} + +const char* panel_action_get_tooltip(PanelActionButtonType type) +{ + g_return_val_if_fail(type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, NULL); + + return _(actions[type].tooltip); +} + +const char* panel_action_get_drag_id(PanelActionButtonType type) +{ + g_return_val_if_fail(type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, NULL); + + return actions[type].drag_id; +} + +static void +panel_action_button_update_sensitivity (PanelActionButton *button) +{ + if (actions [button->priv->type].is_disabled) + button_widget_set_activatable (BUTTON_WIDGET (button), + !actions [button->priv->type].is_disabled ()); +} + +static void +panel_action_button_finalize (GObject *object) +{ + PanelActionButton *button = PANEL_ACTION_BUTTON (object); + + button->priv->info = NULL; + button->priv->type = PANEL_ACTION_NONE; + + panel_lockdown_notify_remove (G_CALLBACK (panel_action_button_update_sensitivity), + button); + + mateconf_client_notify_remove (panel_mateconf_get_client (), + button->priv->mateconf_notify); + button->priv->mateconf_notify = 0; + + G_OBJECT_CLASS (panel_action_button_parent_class)->finalize (object); +} + +static void +panel_action_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelActionButton *button; + + g_return_if_fail (PANEL_IS_ACTION_BUTTON (object)); + + button = PANEL_ACTION_BUTTON (object); + + switch (prop_id) { + case PROP_ACTION_TYPE: + g_value_set_enum (value, button->priv->type); + break; + case PROP_DND_ENABLED: + g_value_set_boolean (value, button->priv->dnd_enabled); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_action_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PanelActionButton *button; + + g_return_if_fail (PANEL_IS_ACTION_BUTTON (object)); + + button = PANEL_ACTION_BUTTON (object); + + switch (prop_id) { + case PROP_ACTION_TYPE: + panel_action_button_set_type (button, + g_value_get_enum (value)); + break; + case PROP_DND_ENABLED: + panel_action_button_set_dnd_enabled (button, + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_action_button_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + PanelActionButton *button; + char *drag_data; + + g_return_if_fail (PANEL_IS_ACTION_BUTTON (widget)); + + button = PANEL_ACTION_BUTTON (widget); + + drag_data = g_strdup_printf ("ACTION:%s:%d", + mateconf_enum_to_string (panel_action_type_map, button->priv->type), + panel_find_applet_index (widget)); + + gtk_selection_data_set ( + selection_data, gtk_selection_data_get_target (selection_data), + 8, (guchar *) drag_data, strlen (drag_data)); + + g_free (drag_data); +} + +static void +panel_action_button_clicked (GtkButton *gtk_button) +{ + PanelActionButton *button; + + g_return_if_fail (PANEL_IS_ACTION_BUTTON (gtk_button)); + + button = PANEL_ACTION_BUTTON (gtk_button); + + g_return_if_fail (button->priv->type > PANEL_ACTION_NONE); + g_return_if_fail (button->priv->type < PANEL_ACTION_LAST); + + if (panel_global_config_get_drawer_auto_close ()) { + PanelToplevel *toplevel; + + toplevel = PANEL_WIDGET (gtk_widget_get_parent (GTK_WIDGET (button)))->toplevel; + + if (panel_toplevel_get_is_attached (toplevel)) + panel_toplevel_hide (toplevel, FALSE, -1); + } + + if (actions [button->priv->type].invoke) + actions [button->priv->type].invoke (GTK_WIDGET (button)); +} + +static void +panel_action_button_class_init (PanelActionButtonClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + GtkButtonClass *button_class = (GtkButtonClass *) klass; + + gobject_class->finalize = panel_action_button_finalize; + gobject_class->get_property = panel_action_button_get_property; + gobject_class->set_property = panel_action_button_set_property; + + widget_class->drag_data_get = panel_action_button_drag_data_get; + + button_class->clicked = panel_action_button_clicked; + + g_type_class_add_private (klass, sizeof (PanelActionButtonPrivate)); + + g_object_class_install_property ( + gobject_class, + PROP_ACTION_TYPE, + g_param_spec_enum ("action-type", + "Action Type", + "The type of action this button implements", + PANEL_TYPE_ACTION_BUTTON_TYPE, + PANEL_ORIENTATION_TOP, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_DND_ENABLED, + g_param_spec_boolean ("dnd-enabled", + "Drag and drop enabled", + "Whether or not drag and drop is enabled on the widget", + TRUE, + G_PARAM_READWRITE)); +} + +static void +panel_action_button_init (PanelActionButton *button) +{ + button->priv = PANEL_ACTION_BUTTON_GET_PRIVATE (button); + + button->priv->type = PANEL_ACTION_NONE; + button->priv->info = NULL; + + button->priv->mateconf_notify = 0; + button->priv->dnd_enabled = FALSE; +} + +void +panel_action_button_set_type (PanelActionButton *button, + PanelActionButtonType type) +{ + g_return_if_fail (type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST); + + if (panel_action_get_is_deprecated (type)) + return; + + if (type == button->priv->type) + return; + + button->priv->type = type; + + if (actions [type].icon_name != NULL) + button_widget_set_icon_name (BUTTON_WIDGET (button), actions [type].icon_name); + + panel_util_set_tooltip_text (GTK_WIDGET (button), + _(actions [type].tooltip)); + panel_a11y_set_atk_name_desc (GTK_WIDGET (button), _(actions [type].tooltip), NULL); + + panel_action_button_update_sensitivity (button); +} + +static void +panel_action_button_type_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelActionButton *button) +{ + int type; + const char *action_type; + + g_return_if_fail (PANEL_IS_ACTION_BUTTON (button)); + + if (!entry->value || entry->value->type != MATECONF_VALUE_STRING) + return; + + action_type = mateconf_value_get_string (entry->value); + + if (!mateconf_string_to_enum (panel_action_type_map, action_type, &type)) + return; + + panel_action_button_set_type (button, type); +} + +static void +panel_action_button_connect_to_mateconf (PanelActionButton *button) +{ + const char *key; + + key = panel_mateconf_full_key ( + PANEL_MATECONF_OBJECTS, button->priv->info->id, "action_type"); + + button->priv->mateconf_notify = + mateconf_client_notify_add (panel_mateconf_get_client (), key, + (MateConfClientNotifyFunc) panel_action_button_type_changed, + button, NULL, NULL); + + panel_lockdown_notify_add (G_CALLBACK (panel_action_button_update_sensitivity), + button); +} + +static void +panel_action_button_style_set (PanelActionButton *button) +{ + if (actions [button->priv->type].icon_name != NULL) + button_widget_set_icon_name (BUTTON_WIDGET (button), actions [button->priv->type].icon_name); +} + +static void +panel_action_button_load (PanelActionButtonType type, + PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id, + gboolean compatibility) +{ + PanelActionButton *button; + PanelObjectType object_type; + + g_return_if_fail (panel != NULL); + + button = g_object_new (PANEL_TYPE_ACTION_BUTTON, "action-type", type, NULL); + + object_type = PANEL_OBJECT_ACTION; + + if (compatibility) + { /* Backward compatibility with MATE 2.0.x */ + if (type == PANEL_ACTION_LOCK) + { + object_type = PANEL_OBJECT_LOCK; + } + else if (type == PANEL_ACTION_LOGOUT) + { + object_type = PANEL_OBJECT_LOGOUT; + } + } + + button->priv->info = mate_panel_applet_register (GTK_WIDGET (button), + NULL, NULL, + panel, locked, position, + exactpos, object_type, id); + if (!button->priv->info) { + gtk_widget_destroy (GTK_WIDGET (button)); + return; + } + + mate_panel_applet_add_callback (button->priv->info, + "help", + GTK_STOCK_HELP, + _("_Help"), + NULL); + + panel_widget_set_applet_expandable (panel, GTK_WIDGET (button), FALSE, TRUE); + panel_widget_set_applet_size_constrained (panel, GTK_WIDGET (button), TRUE); + + if (actions [button->priv->type].setup_menu) + actions [button->priv->type].setup_menu (button); + + panel_action_button_connect_to_mateconf (button); + + g_signal_connect (button, "style-set", + G_CALLBACK (panel_action_button_style_set), NULL); +} + +void +panel_action_button_create (PanelToplevel *toplevel, + int position, + PanelActionButtonType type) +{ + MateConfClient *client; + const char *key; + char *id; + + client = panel_mateconf_get_client (); + + id = panel_profile_prepare_object (PANEL_OBJECT_ACTION, toplevel, position, FALSE); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "action_type"); + mateconf_client_set_string (client, + key, + mateconf_enum_to_string (panel_action_type_map, type), + NULL); + + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + + g_free (id); +} + +/* This is only for backwards compatibility with 2.0.x + * We load an old-style lock/logout button as an action + * button but make sure to retain the lock/logout configuration + * so logging back into 2.0.x still works. + */ +void +panel_action_button_load_compatible (PanelObjectType object_type, + PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id) +{ + PanelActionButtonType action_type; + + g_assert (object_type == PANEL_OBJECT_LOGOUT || object_type == PANEL_OBJECT_LOCK); + + action_type = object_type == PANEL_OBJECT_LOGOUT ? PANEL_ACTION_LOGOUT : PANEL_ACTION_LOCK; + + panel_action_button_load (action_type, panel, locked, position, exactpos, id, TRUE); +} + +void +panel_action_button_load_from_mateconf (PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id) +{ + int type; + const char *key; + char *action_type; + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "action_type"); + action_type = mateconf_client_get_string (panel_mateconf_get_client (), key, NULL); + + if (!mateconf_string_to_enum (panel_action_type_map, action_type, &type)) { + g_warning ("Unkown action type '%s' from %s", action_type, key); + g_free (action_type); + return; + } + + g_free (action_type); + + /* compatibility: migrate from MATE < 2.13.90 */ + if (type == PANEL_ACTION_SCREENSHOT) + panel_compatibility_migrate_screenshot_action (panel_mateconf_get_client (), + id); + else + panel_action_button_load (type, panel, locked, + position, exactpos, id, FALSE); +} + +void +panel_action_button_invoke_menu (PanelActionButton *button, + const char *callback_name) +{ + g_return_if_fail (PANEL_IS_ACTION_BUTTON (button)); + g_return_if_fail (callback_name != NULL); + g_return_if_fail (button->priv->type > PANEL_ACTION_NONE && + button->priv->type < PANEL_ACTION_LAST); + + if (!strcmp (callback_name, "help")) { + GdkScreen *screen; + + if (!actions [button->priv->type].help_index) + return; + + screen = gtk_widget_get_screen (GTK_WIDGET (button)); + + panel_show_help (screen, "user-guide", + actions [button->priv->type].help_index, NULL); + + return; + } + + if (actions [button->priv->type].invoke_menu) + actions [button->priv->type].invoke_menu (button, callback_name); +} + +gboolean +panel_action_button_load_from_drag (PanelToplevel *toplevel, + int position, + const char *drag_string, + int *old_applet_idx) +{ + PanelActionButtonType type = PANEL_ACTION_NONE; + gboolean retval = FALSE; + char **elements; + + if (strncmp (drag_string, "ACTION:", strlen ("ACTION:"))) + return retval; + + elements = g_strsplit (drag_string, ":", 0); + + g_assert (elements != NULL); + + if (!elements [1] || !elements [2]) { + g_strfreev (elements); + return retval; + } + + if (!mateconf_string_to_enum (panel_action_type_map, elements [1], (gpointer) &type)) { + g_strfreev (elements); + return retval; + } + + g_return_val_if_fail (type > PANEL_ACTION_NONE && type < PANEL_ACTION_LAST, FALSE); + + if (panel_action_get_is_deprecated (type)) + return retval; + + if (strcmp (elements [2], "NEW")) { + *old_applet_idx = strtol (elements [2], NULL, 10); + retval = TRUE; /* Remove the old applet */ + } + + g_strfreev (elements); + + panel_action_button_create (toplevel, position, type); + + return retval; +} + +void +panel_action_button_set_dnd_enabled (PanelActionButton *button, + gboolean enabled) +{ + g_return_if_fail (PANEL_IS_ACTION_BUTTON (button)); + + if (!button->priv->type) + return; /* wait until we know what type it is */ + + enabled = enabled != FALSE; + + if (button->priv->dnd_enabled == enabled) + return; + + if (enabled) { + static GtkTargetEntry dnd_targets [] = { + { "application/x-mate-panel-applet-internal", 0, 0 } + }; + + gtk_widget_set_has_window (GTK_WIDGET (button), TRUE); + gtk_drag_source_set (GTK_WIDGET (button), GDK_BUTTON1_MASK, + dnd_targets, 1, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + if (actions [button->priv->type].icon_name != NULL) + gtk_drag_source_set_icon_name (GTK_WIDGET (button), + actions [button->priv->type].icon_name); + gtk_widget_set_has_window (GTK_WIDGET (button), FALSE); + } else + gtk_drag_source_unset (GTK_WIDGET (button)); + + button->priv->dnd_enabled = enabled; + + g_object_notify (G_OBJECT (button), "dnd-enabled"); +} diff --git a/mate-panel/panel-action-button.h b/mate-panel/panel-action-button.h new file mode 100644 index 00000000..7139aef6 --- /dev/null +++ b/mate-panel/panel-action-button.h @@ -0,0 +1,103 @@ +/* + * panel-action-button.h: panel "Action Button" module + * + * Copyright (C) 2002 Sun Microsystems, Inc. + * Copyright (C) 2004 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_ACTION_BUTTON_H__ +#define __PANEL_ACTION_BUTTON_H__ + +#include +#include "button-widget.h" +#include "panel-widget.h" +#include "panel-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_ACTION_BUTTON (panel_action_button_get_type ()) +#define PANEL_ACTION_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_ACTION_BUTTON, PanelActionButton)) +#define PANEL_ACTION_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_ACTION_BUTTON, PanelActionButtonClass)) +#define PANEL_IS_ACTION_BUTTON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_ACTION_BUTTON)) +#define PANEL_IS_ACTION_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_ACTION_BUTTON)) +#define PANEL_ACTION_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_ACTION_BUTTON, PanelActionButtonClass)) + +typedef struct _PanelActionButton PanelActionButton; +typedef struct _PanelActionButtonClass PanelActionButtonClass; +typedef struct _PanelActionButtonPrivate PanelActionButtonPrivate; + +struct _PanelActionButton{ + ButtonWidget button; + + PanelActionButtonPrivate *priv; +}; + +struct _PanelActionButtonClass { + ButtonWidgetClass button_class; +}; + +GType panel_action_button_get_type (void) G_GNUC_CONST; + +void panel_action_button_create (PanelToplevel *toplevel, + int position, + PanelActionButtonType type); + +void panel_action_button_set_type (PanelActionButton *button, + PanelActionButtonType type); + +void panel_action_button_load_from_mateconf (PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id); + +void panel_action_button_load_compatible (PanelObjectType object_type, + PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id); + +void panel_action_button_invoke_menu (PanelActionButton *button, + const char *callback_name); + +void panel_action_button_set_dnd_enabled (PanelActionButton *button, + gboolean dnd_enabled); + +gboolean panel_action_button_load_from_drag (PanelToplevel *toplevel, + int position, + const char *drag_string, + int *old_applet_idx); + +gboolean panel_action_get_is_disabled (PanelActionButtonType type); +GCallback panel_action_get_invoke (PanelActionButtonType type); +const char* panel_action_get_icon_name(PanelActionButtonType type); +const char* panel_action_get_text(PanelActionButtonType type); +const char* panel_action_get_tooltip(PanelActionButtonType type); +const char* panel_action_get_drag_id(PanelActionButtonType type); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_ACTION_BUTTON_H__ */ diff --git a/mate-panel/panel-action-protocol.c b/mate-panel/panel-action-protocol.c new file mode 100644 index 00000000..3f2e3e52 --- /dev/null +++ b/mate-panel/panel-action-protocol.c @@ -0,0 +1,158 @@ +/* + * panel-action-protocol.h: _MATE_PANEL_ACTION protocol impl. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-action-protocol.h" + +#include +#include +#include + +#include "menu.h" +#include "applet.h" +#include "panel-globals.h" +#include "panel-toplevel.h" +#include "panel-util.h" +#include "panel-force-quit.h" +#include "panel-run-dialog.h" +#include "panel-menu-button.h" +#include "panel-menu-bar.h" + +static Atom atom_mate_panel_action = None; +static Atom atom_mate_panel_action_main_menu = None; +static Atom atom_mate_panel_action_run_dialog = None; +static Atom atom_mate_panel_action_kill_dialog = None; + +static void +panel_action_protocol_main_menu (GdkScreen *screen, + guint32 activate_time) +{ + PanelWidget *panel_widget; + GtkWidget *menu; + AppletInfo *info; + + info = mate_panel_applet_get_by_type (PANEL_OBJECT_MENU_BAR, screen); + if (info) { + panel_menu_bar_popup_menu (PANEL_MENU_BAR (info->widget), + activate_time); + return; + } + + info = mate_panel_applet_get_by_type (PANEL_OBJECT_MENU, screen); + if (info && !panel_menu_button_get_use_menu_path (PANEL_MENU_BUTTON (info->widget))) { + panel_menu_button_popup_menu (PANEL_MENU_BUTTON (info->widget), + 1, activate_time); + return; + } + + panel_widget = panels->data; + menu = create_main_menu (panel_widget); + + panel_toplevel_push_autohide_disabler (panel_widget->toplevel); + + gtk_menu_set_screen (GTK_MENU (menu), screen); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, + NULL, NULL, 0, activate_time); +} + +static void +panel_action_protocol_run_dialog (GdkScreen *screen, + guint32 activate_time) +{ + panel_run_dialog_present (screen, activate_time); +} + +static void +panel_action_protocol_kill_dialog (GdkScreen *screen, + guint32 activate_time) +{ + panel_force_quit (screen, activate_time); +} + +static GdkFilterReturn +panel_action_protocol_filter (GdkXEvent *gdk_xevent, + GdkEvent *event, + gpointer data) +{ + GdkWindow *window; + GdkScreen *screen; + XEvent *xevent = (XEvent *) gdk_xevent; + + if (xevent->type != ClientMessage) + return GDK_FILTER_CONTINUE; + + if (xevent->xclient.message_type != atom_mate_panel_action) + return GDK_FILTER_CONTINUE; + + window = gdk_window_lookup (xevent->xclient.window); + if (!window) + return GDK_FILTER_CONTINUE; + + screen = gdk_drawable_get_screen (window); + + if (xevent->xclient.data.l [0] == atom_mate_panel_action_main_menu) + panel_action_protocol_main_menu (screen, xevent->xclient.data.l [1]); + else if (xevent->xclient.data.l [0] == atom_mate_panel_action_run_dialog) + panel_action_protocol_run_dialog (screen, xevent->xclient.data.l [1]); + else if (xevent->xclient.data.l [0] == atom_mate_panel_action_kill_dialog) + panel_action_protocol_kill_dialog (screen, xevent->xclient.data.l [1]); + else + return GDK_FILTER_CONTINUE; + + return GDK_FILTER_REMOVE; +} + +void +panel_action_protocol_init (void) +{ + GdkDisplay *display; + GdkAtom gdk_atom_mate_panel_action; + + display = gdk_display_get_default (); + + gdk_atom_mate_panel_action = + gdk_atom_intern_static_string ("_MATE_PANEL_ACTION"); + + atom_mate_panel_action = + XInternAtom (GDK_DISPLAY_XDISPLAY (display), + "_MATE_PANEL_ACTION", + FALSE); + atom_mate_panel_action_main_menu = + XInternAtom (GDK_DISPLAY_XDISPLAY (display), + "_MATE_PANEL_ACTION_MAIN_MENU", + FALSE); + atom_mate_panel_action_run_dialog = + XInternAtom (GDK_DISPLAY_XDISPLAY (display), + "_MATE_PANEL_ACTION_RUN_DIALOG", + FALSE); + atom_mate_panel_action_kill_dialog = + XInternAtom (GDK_DISPLAY_XDISPLAY (display), + "_MATE_PANEL_ACTION_KILL_DIALOG", + FALSE); + + gdk_display_add_client_message_filter ( + display, gdk_atom_mate_panel_action, + panel_action_protocol_filter, NULL); +} diff --git a/mate-panel/panel-action-protocol.h b/mate-panel/panel-action-protocol.h new file mode 100644 index 00000000..3c90da9e --- /dev/null +++ b/mate-panel/panel-action-protocol.h @@ -0,0 +1,40 @@ +/* + * panel-action-protocol.h: _MATE_PANEL_ACTION protocol impl. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_ACTION_PROTOCOL_H__ +#define __PANEL_ACTION_PROTOCOL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_action_protocol_init (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_ACTION_PROTOCOL_H__ */ diff --git a/mate-panel/panel-addto.c b/mate-panel/panel-addto.c new file mode 100644 index 00000000..150d83de --- /dev/null +++ b/mate-panel/panel-addto.c @@ -0,0 +1,1428 @@ +/* + * panel-addto.c: + * + * Copyright (C) 2004 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include +#include + +#include + +#include + +#include +#include + +#include "launcher.h" +#include "panel.h" +#include "drawer.h" +#include "mate-panel-applets-manager.h" +#include "mate-panel-applet-frame.h" +#include "panel-action-button.h" +#include "panel-menu-bar.h" +#include "panel-separator.h" +#include "panel-toplevel.h" +#include "panel-menu-button.h" +#include "panel-globals.h" +#include "panel-lockdown.h" +#include "panel-util.h" +#include "panel-profile.h" +#include "panel-addto.h" +#include "panel-icon-names.h" + +typedef struct { + PanelWidget *panel_widget; + + GtkWidget *addto_dialog; + GtkWidget *label; + GtkWidget *search_entry; + GtkWidget *back_button; + GtkWidget *add_button; + GtkWidget *tree_view; + GtkTreeModel *applet_model; + GtkTreeModel *filter_applet_model; + GtkTreeModel *application_model; + GtkTreeModel *filter_application_model; + + MateMenuTree *menu_tree; + + GSList *applet_list; + GSList *application_list; + GSList *settings_list; + + gchar *search_text; + gchar *applet_search_text; + + guint name_notify; + + int insertion_position; +} PanelAddtoDialog; + +static GQuark panel_addto_dialog_quark = 0; + +typedef enum { + PANEL_ADDTO_APPLET, + PANEL_ADDTO_ACTION, + PANEL_ADDTO_LAUNCHER_MENU, + PANEL_ADDTO_LAUNCHER, + PANEL_ADDTO_LAUNCHER_NEW, + PANEL_ADDTO_MENU, + PANEL_ADDTO_MENUBAR, + PANEL_ADDTO_SEPARATOR, + PANEL_ADDTO_DRAWER +} PanelAddtoItemType; + +typedef struct { + PanelAddtoItemType type; + char *name; + char *description; + char *icon; + PanelActionButtonType action_type; + char *launcher_path; + char *menu_filename; + char *menu_path; + char *iid; + gboolean static_data; +} PanelAddtoItemInfo; + +typedef struct { + GSList *children; + PanelAddtoItemInfo item_info; +} PanelAddtoAppList; + +static PanelAddtoItemInfo special_addto_items [] = { + + { PANEL_ADDTO_LAUNCHER_NEW, + N_("Custom Application Launcher"), + N_("Create a new launcher"), + PANEL_ICON_LAUNCHER, + PANEL_ACTION_NONE, + NULL, + NULL, + NULL, + "LAUNCHER:ASK", + TRUE }, + + { PANEL_ADDTO_LAUNCHER_MENU, + N_("Application Launcher..."), + N_("Copy a launcher from the applications menu"), + PANEL_ICON_LAUNCHER, + PANEL_ACTION_NONE, + NULL, + NULL, + NULL, + "LAUNCHER:MENU", + TRUE } + +}; + +static PanelAddtoItemInfo internal_addto_items [] = { + + { PANEL_ADDTO_MENU, + N_("Main Menu"), + N_("The main MATE menu"), + PANEL_ICON_MAIN_MENU, + PANEL_ACTION_NONE, + NULL, + NULL, + NULL, + "MENU:MAIN", + TRUE }, + + { PANEL_ADDTO_MENUBAR, + N_("Menu Bar"), + N_("A custom menu bar"), + PANEL_ICON_MAIN_MENU, + PANEL_ACTION_NONE, + NULL, + NULL, + NULL, + "MENUBAR:NEW", + TRUE }, + + { PANEL_ADDTO_SEPARATOR, + N_("Separator"), + N_("A separator to organize the panel items"), + PANEL_ICON_SEPARATOR, + PANEL_ACTION_NONE, + NULL, + NULL, + NULL, + "SEPARATOR:NEW", + TRUE }, + + { PANEL_ADDTO_DRAWER, + N_("Drawer"), + N_("A pop out drawer to store other items in"), + PANEL_ICON_DRAWER, + PANEL_ACTION_NONE, + NULL, + NULL, + NULL, + "DRAWER:NEW", + TRUE } +}; + +enum { + COLUMN_ICON, + COLUMN_TEXT, + COLUMN_DATA, + COLUMN_SEARCH, + NUMBER_COLUMNS +}; + +enum { + PANEL_ADDTO_RESPONSE_BACK, + PANEL_ADDTO_RESPONSE_ADD +}; + +static void panel_addto_present_applications (PanelAddtoDialog *dialog); +static void panel_addto_present_applets (PanelAddtoDialog *dialog); +static gboolean panel_addto_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); + +static int +panel_addto_applet_info_sort_func (PanelAddtoItemInfo *a, + PanelAddtoItemInfo *b) +{ + return g_utf8_collate (a->name, b->name); +} + +static GSList * +panel_addto_prepend_internal_applets (GSList *list) +{ + static gboolean translated = FALSE; + int i; + + for (i = 0; i < G_N_ELEMENTS (internal_addto_items); i++) { + if (!translated) { + internal_addto_items [i].name = _(internal_addto_items [i].name); + internal_addto_items [i].description = _(internal_addto_items [i].description); + } + + list = g_slist_prepend (list, &internal_addto_items [i]); + } + + translated = TRUE; + + for (i = PANEL_ACTION_LOCK; i < PANEL_ACTION_LAST; i++) { + PanelAddtoItemInfo *info; + + if (panel_action_get_is_disabled (i)) + continue; + + info = g_new0 (PanelAddtoItemInfo, 1); + info->type = PANEL_ADDTO_ACTION; + info->action_type = i; + info->name = g_strdup (panel_action_get_text (i)); + info->description = g_strdup (panel_action_get_tooltip (i)); + info->icon = g_strdup (panel_action_get_icon_name (i)); + info->iid = g_strdup (panel_action_get_drag_id (i)); + info->static_data = FALSE; + + list = g_slist_prepend (list, info); + } + + return list; +} + +static char * +panel_addto_make_text (const char *name, + const char *desc) +{ + const char *real_name; + char *result; + + real_name = name ? name : _("(empty)"); + + if (!PANEL_GLIB_STR_EMPTY (desc)) { + result = g_markup_printf_escaped ("%s\n%s", + real_name, desc); + } else { + result = g_markup_printf_escaped ("%s", + real_name); + } + + return result; +} + +#define ICON_SIZE 32 + +static GdkPixbuf * +panel_addto_make_pixbuf (const char *filename) +{ + //FIXME: size shouldn't be fixed but should depend on the font size + return panel_load_icon (gtk_icon_theme_get_default (), + filename, + ICON_SIZE, ICON_SIZE, ICON_SIZE, + NULL); +} + +static void +panel_addto_drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + const char *string) +{ + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), 8, + (guchar *) string, strlen (string)); +} + +static void +panel_addto_drag_begin_cb (GtkWidget *widget, + GdkDragContext *context, + gpointer data) +{ + GtkTreeModel *filter_model; + GtkTreeModel *child_model; + GtkTreePath *path; + GtkTreeIter iter; + GtkTreeIter filter_iter; + GdkPixbuf *pixbuf; + + filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + + gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &path, NULL); + gtk_tree_model_get_iter (filter_model, &filter_iter, path); + gtk_tree_path_free (path); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter_model), + &iter, &filter_iter); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); + gtk_tree_model_get (child_model, &iter, + COLUMN_ICON, &pixbuf, + -1); + + gtk_drag_set_icon_pixbuf (context, pixbuf, 0, 0); + g_object_unref (pixbuf); +} + +static void +panel_addto_setup_drag (GtkTreeView *tree_view, + const GtkTargetEntry *target, + const char *text) +{ + if (!text || panel_lockdown_get_locked_down ()) + return; + + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree_view), + GDK_BUTTON1_MASK|GDK_BUTTON2_MASK, + target, 1, GDK_ACTION_COPY); + + g_signal_connect_data (G_OBJECT (tree_view), "drag_data_get", + G_CALLBACK (panel_addto_drag_data_get_cb), + g_strdup (text), + (GClosureNotify) g_free, + 0 /* connect_flags */); + g_signal_connect_after (G_OBJECT (tree_view), "drag-begin", + G_CALLBACK (panel_addto_drag_begin_cb), + NULL); +} + +static void +panel_addto_setup_launcher_drag (GtkTreeView *tree_view, + const char *path) +{ + static GtkTargetEntry target[] = { + { "text/uri-list", 0, 0 } + }; + char *uri; + char *uri_list; + + uri = g_filename_to_uri (path, NULL, NULL); + uri_list = g_strconcat (uri, "\r\n", NULL); + panel_addto_setup_drag (tree_view, target, uri_list); + g_free (uri_list); + g_free (uri); +} + +static void +panel_addto_setup_applet_drag (GtkTreeView *tree_view, + const char *iid) +{ + static GtkTargetEntry target[] = { + { "application/x-mate-panel-applet-iid", 0, 0 } + }; + + panel_addto_setup_drag (tree_view, target, iid); +} + +static void +panel_addto_setup_internal_applet_drag (GtkTreeView *tree_view, + const char *applet_type) +{ + static GtkTargetEntry target[] = { + { "application/x-mate-panel-applet-internal", 0, 0 } + }; + + panel_addto_setup_drag (tree_view, target, applet_type); +} + +static GSList * +panel_addto_query_applets (GSList *list) +{ + GList *applet_list, *l; + + applet_list = mate_panel_applets_manager_get_applets (); + + for (l = applet_list; l; l = g_list_next (l)) { + MatePanelAppletInfo *info; + const char *iid, *name, *description, *icon; + PanelAddtoItemInfo *applet; + + info = (MatePanelAppletInfo *)l->data; + + iid = mate_panel_applet_info_get_iid (info); + name = mate_panel_applet_info_get_name (info); + description = mate_panel_applet_info_get_description (info); + icon = mate_panel_applet_info_get_icon (info); + + if (!name || panel_lockdown_is_applet_disabled (iid)) { + continue; + } + + applet = g_new0 (PanelAddtoItemInfo, 1); + applet->type = PANEL_ADDTO_APPLET; + applet->name = g_strdup (name); + applet->description = g_strdup (description); + applet->icon = g_strdup (icon); + applet->iid = g_strdup (iid); + applet->static_data = FALSE; + + list = g_slist_prepend (list, applet); + } + + g_list_free (applet_list); + + return list; +} + +static void +panel_addto_append_item (PanelAddtoDialog *dialog, + GtkListStore *model, + PanelAddtoItemInfo *applet) +{ + char *text; + GdkPixbuf *pixbuf; + GtkTreeIter iter; + + if (applet == NULL) { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_ICON, NULL, + COLUMN_TEXT, NULL, + COLUMN_DATA, NULL, + COLUMN_SEARCH, NULL, + -1); + } else { + pixbuf = NULL; + + if (applet->icon != NULL) { + pixbuf = panel_addto_make_pixbuf (applet->icon); + } + + gtk_list_store_append (model, &iter); + + text = panel_addto_make_text (applet->name, + applet->description); + + gtk_list_store_set (model, &iter, + COLUMN_ICON, pixbuf, + COLUMN_TEXT, text, + COLUMN_DATA, applet, + COLUMN_SEARCH, applet->name, + -1); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (text); + } +} + +static void +panel_addto_append_special_applets (PanelAddtoDialog *dialog, + GtkListStore *model) +{ + static gboolean translated = FALSE; + int i; + + for (i = 0; i < G_N_ELEMENTS (special_addto_items); i++) { + if (!translated) { + special_addto_items [i].name = _(special_addto_items [i].name); + special_addto_items [i].description = _(special_addto_items [i].description); + } + + if (special_addto_items [i].type == PANEL_ADDTO_LAUNCHER_NEW + && panel_lockdown_get_disable_command_line ()) + continue; + + panel_addto_append_item (dialog, model, &special_addto_items [i]); + } + + translated = TRUE; +} + +static void +panel_addto_make_applet_model (PanelAddtoDialog *dialog) +{ + GtkListStore *model; + GSList *l; + + if (dialog->filter_applet_model != NULL) + return; + + if (panel_profile_id_lists_are_writable ()) { + dialog->applet_list = panel_addto_query_applets (dialog->applet_list); + dialog->applet_list = panel_addto_prepend_internal_applets (dialog->applet_list); + } + + dialog->applet_list = g_slist_sort (dialog->applet_list, + (GCompareFunc) panel_addto_applet_info_sort_func); + + model = gtk_list_store_new (NUMBER_COLUMNS, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_POINTER, + G_TYPE_STRING); + + if (panel_profile_id_lists_are_writable ()) { + panel_addto_append_special_applets (dialog, model); + if (dialog->applet_list) + panel_addto_append_item (dialog, model, NULL); + } + + for (l = dialog->applet_list; l; l = l->next) + panel_addto_append_item (dialog, model, l->data); + + dialog->applet_model = GTK_TREE_MODEL (model); + dialog->filter_applet_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->applet_model), + NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (dialog->filter_applet_model), + panel_addto_filter_func, + dialog, NULL); +} + +static void panel_addto_make_application_list (GSList **parent_list, + MateMenuTreeDirectory *directory, + const char *filename); + +static void +panel_addto_prepend_directory (GSList **parent_list, + MateMenuTreeDirectory *directory, + const char *filename) +{ + PanelAddtoAppList *data; + + data = g_new0 (PanelAddtoAppList, 1); + + data->item_info.type = PANEL_ADDTO_MENU; + data->item_info.name = g_strdup (matemenu_tree_directory_get_name (directory)); + data->item_info.description = g_strdup (matemenu_tree_directory_get_comment (directory)); + data->item_info.icon = g_strdup (matemenu_tree_directory_get_icon (directory)); + data->item_info.menu_filename = g_strdup (filename); + data->item_info.menu_path = matemenu_tree_directory_make_path (directory, NULL); + data->item_info.static_data = FALSE; + + /* We should set the iid here to something and do + * iid = g_strdup_printf ("MENU:%s", tfr->name) + * but this means we'd have to free the iid later + * and this would complexify too much the free + * function. + * So the iid is built when we select the row. + */ + + *parent_list = g_slist_prepend (*parent_list, data); + + panel_addto_make_application_list (&data->children, directory, filename); +} + +static void +panel_addto_prepend_entry (GSList **parent_list, + MateMenuTreeEntry *entry, + const char *filename) +{ + PanelAddtoAppList *data; + + data = g_new0 (PanelAddtoAppList, 1); + + data->item_info.type = PANEL_ADDTO_LAUNCHER; + data->item_info.name = g_strdup (matemenu_tree_entry_get_display_name (entry)); + data->item_info.description = g_strdup (matemenu_tree_entry_get_comment (entry)); + data->item_info.icon = g_strdup (matemenu_tree_entry_get_icon (entry)); + data->item_info.launcher_path = g_strdup (matemenu_tree_entry_get_desktop_file_path (entry)); + data->item_info.static_data = FALSE; + + *parent_list = g_slist_prepend (*parent_list, data); +} + +static void +panel_addto_prepend_alias (GSList **parent_list, + MateMenuTreeAlias *alias, + const char *filename) +{ + MateMenuTreeItem *aliased_item; + + aliased_item = matemenu_tree_alias_get_item (alias); + + switch (matemenu_tree_item_get_type (aliased_item)) { + case MATEMENU_TREE_ITEM_DIRECTORY: + panel_addto_prepend_directory (parent_list, + MATEMENU_TREE_DIRECTORY (aliased_item), + filename); + break; + + case MATEMENU_TREE_ITEM_ENTRY: + panel_addto_prepend_entry (parent_list, + MATEMENU_TREE_ENTRY (aliased_item), + filename); + break; + + default: + break; + } + + matemenu_tree_item_unref (aliased_item); +} + +static void +panel_addto_make_application_list (GSList **parent_list, + MateMenuTreeDirectory *directory, + const char *filename) +{ + GSList *items; + GSList *l; + + items = matemenu_tree_directory_get_contents (directory); + + for (l = items; l; l = l->next) { + switch (matemenu_tree_item_get_type (l->data)) { + case MATEMENU_TREE_ITEM_DIRECTORY: + panel_addto_prepend_directory (parent_list, l->data, filename); + break; + + case MATEMENU_TREE_ITEM_ENTRY: + panel_addto_prepend_entry (parent_list, l->data, filename); + break; + + case MATEMENU_TREE_ITEM_ALIAS: + panel_addto_prepend_alias (parent_list, l->data, filename); + break; + + default: + break; + } + + matemenu_tree_item_unref (l->data); + } + + g_slist_free (items); + + *parent_list = g_slist_reverse (*parent_list); +} + +static void +panel_addto_populate_application_model (GtkTreeStore *store, + GtkTreeIter *parent, + GSList *app_list) +{ + PanelAddtoAppList *data; + GtkTreeIter iter; + char *text; + GdkPixbuf *pixbuf; + GSList *app; + + for (app = app_list; app != NULL; app = app->next) { + data = app->data; + gtk_tree_store_append (store, &iter, parent); + + text = panel_addto_make_text (data->item_info.name, + data->item_info.description); + pixbuf = panel_addto_make_pixbuf (data->item_info.icon); + gtk_tree_store_set (store, &iter, + COLUMN_ICON, pixbuf, + COLUMN_TEXT, text, + COLUMN_DATA, &(data->item_info), + COLUMN_SEARCH, data->item_info.name, + -1); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (text); + + if (data->children != NULL) + panel_addto_populate_application_model (store, + &iter, + data->children); + } +} + +static void panel_addto_make_application_model(PanelAddtoDialog* dialog) +{ + GtkTreeStore* store; + MateMenuTree* tree; + MateMenuTreeDirectory* root; + + if (dialog->filter_application_model != NULL) + return; + + store = gtk_tree_store_new(NUMBER_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING); + + tree = matemenu_tree_lookup("mate-applications.menu", MATEMENU_TREE_FLAGS_NONE); + matemenu_tree_set_sort_key(tree, MATEMENU_TREE_SORT_DISPLAY_NAME); + + if ((root = matemenu_tree_get_root_directory (tree))) + { + panel_addto_make_application_list(&dialog->application_list, root, "mate-applications.menu"); + panel_addto_populate_application_model(store, NULL, dialog->application_list); + + matemenu_tree_item_unref(root); + } + + matemenu_tree_unref(tree); + + tree = matemenu_tree_lookup("mate-settings.menu", MATEMENU_TREE_FLAGS_NONE); + matemenu_tree_set_sort_key(tree, MATEMENU_TREE_SORT_DISPLAY_NAME); + + if ((root = matemenu_tree_get_root_directory(tree))) + { + GtkTreeIter iter; + + gtk_tree_store_append(store, &iter, NULL); + gtk_tree_store_set(store, &iter, COLUMN_ICON, NULL, COLUMN_TEXT, NULL, COLUMN_DATA, NULL, COLUMN_SEARCH, NULL, -1); + + panel_addto_make_application_list(&dialog->settings_list, root, "mate-settings.menu"); + panel_addto_populate_application_model(store, NULL, dialog->settings_list); + + matemenu_tree_item_unref(root); + } + + matemenu_tree_unref(tree); + + dialog->application_model = GTK_TREE_MODEL(store); + dialog->filter_application_model = gtk_tree_model_filter_new(GTK_TREE_MODEL(dialog->application_model), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(dialog->filter_application_model), panel_addto_filter_func, dialog, NULL); +} + +static void +panel_addto_add_item (PanelAddtoDialog *dialog, + PanelAddtoItemInfo *item_info) +{ + g_assert (item_info != NULL); + + switch (item_info->type) { + case PANEL_ADDTO_APPLET: + mate_panel_applet_frame_create (dialog->panel_widget->toplevel, + dialog->insertion_position, + item_info->iid); + break; + case PANEL_ADDTO_ACTION: + panel_action_button_create (dialog->panel_widget->toplevel, + dialog->insertion_position, + item_info->action_type); + break; + case PANEL_ADDTO_LAUNCHER_MENU: + panel_addto_present_applications (dialog); + break; + case PANEL_ADDTO_LAUNCHER: + panel_launcher_create (dialog->panel_widget->toplevel, + dialog->insertion_position, + item_info->launcher_path); + break; + case PANEL_ADDTO_LAUNCHER_NEW: + ask_about_launcher (NULL, dialog->panel_widget, + dialog->insertion_position, FALSE); + break; + case PANEL_ADDTO_MENU: + panel_menu_button_create (dialog->panel_widget->toplevel, + dialog->insertion_position, + item_info->menu_filename, + item_info->menu_path, + item_info->menu_path != NULL, + item_info->name); + break; + case PANEL_ADDTO_MENUBAR: + panel_menu_bar_create (dialog->panel_widget->toplevel, + dialog->insertion_position); + break; + case PANEL_ADDTO_SEPARATOR: + panel_separator_create (dialog->panel_widget->toplevel, + dialog->insertion_position); + break; + case PANEL_ADDTO_DRAWER: + panel_drawer_create (dialog->panel_widget->toplevel, + dialog->insertion_position, + NULL, FALSE, NULL); + break; + } +} + +static void +panel_addto_dialog_response (GtkWidget *widget_dialog, + guint response_id, + PanelAddtoDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeModel *filter_model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter filter_iter; + + switch (response_id) { + case GTK_RESPONSE_HELP: + panel_show_help (gtk_window_get_screen (GTK_WINDOW (dialog->addto_dialog)), + "user-guide", "gospanel-15", NULL); + break; + + case PANEL_ADDTO_RESPONSE_ADD: + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tree_view)); + if (gtk_tree_selection_get_selected (selection, &filter_model, + &filter_iter)) { + PanelAddtoItemInfo *data; + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter_model), + &iter, + &filter_iter); + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); + gtk_tree_model_get (child_model, &iter, + COLUMN_DATA, &data, -1); + + if (data != NULL) + panel_addto_add_item (dialog, data); + } + break; + + case PANEL_ADDTO_RESPONSE_BACK: + /* This response only happens when we're showing the + * application list and the user wants to go back to the + * applet list. */ + panel_addto_present_applets (dialog); + break; + + case GTK_RESPONSE_CLOSE: + gtk_widget_destroy (widget_dialog); + break; + + default: + break; + } +} + +static void +panel_addto_dialog_destroy (GtkWidget *widget_dialog, + PanelAddtoDialog *dialog) +{ + panel_toplevel_pop_autohide_disabler (PANEL_TOPLEVEL (dialog->panel_widget->toplevel)); + g_object_set_qdata (G_OBJECT (dialog->panel_widget->toplevel), + panel_addto_dialog_quark, + NULL); +} + +static void +panel_addto_present_applications (PanelAddtoDialog *dialog) +{ + if (dialog->filter_application_model == NULL) + panel_addto_make_application_model (dialog); + gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->tree_view), + dialog->filter_application_model); + gtk_window_set_focus (GTK_WINDOW (dialog->addto_dialog), + dialog->search_entry); + gtk_widget_set_sensitive (dialog->back_button, TRUE); + + if (dialog->applet_search_text) + g_free (dialog->applet_search_text); + + dialog->applet_search_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->search_entry))); + /* show everything */ + gtk_entry_set_text (GTK_ENTRY (dialog->search_entry), ""); +} + +static void +panel_addto_present_applets (PanelAddtoDialog *dialog) +{ + if (dialog->filter_applet_model == NULL) + panel_addto_make_applet_model (dialog); + gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->tree_view), + dialog->filter_applet_model); + gtk_window_set_focus (GTK_WINDOW (dialog->addto_dialog), + dialog->search_entry); + gtk_widget_set_sensitive (dialog->back_button, FALSE); + + if (dialog->applet_search_text) { + gtk_entry_set_text (GTK_ENTRY (dialog->search_entry), + dialog->applet_search_text); + gtk_editable_set_position (GTK_EDITABLE (dialog->search_entry), + -1); + + g_free (dialog->applet_search_text); + dialog->applet_search_text = NULL; + } +} + +static void +panel_addto_dialog_free_item_info (PanelAddtoItemInfo *item_info) +{ + if (item_info == NULL || item_info->static_data) + return; + + if (item_info->name != NULL) + g_free (item_info->name); + item_info->name = NULL; + + if (item_info->description != NULL) + g_free (item_info->description); + item_info->description = NULL; + + if (item_info->icon != NULL) + g_free (item_info->icon); + item_info->icon = NULL; + + if (item_info->iid != NULL) + g_free (item_info->iid); + item_info->iid = NULL; + + if (item_info->launcher_path != NULL) + g_free (item_info->launcher_path); + item_info->launcher_path = NULL; + + if (item_info->menu_filename != NULL) + g_free (item_info->menu_filename); + item_info->menu_filename = NULL; + + if (item_info->menu_path != NULL) + g_free (item_info->menu_path); + item_info->menu_path = NULL; +} + +static void +panel_addto_dialog_free_application_list (GSList *application_list) +{ + PanelAddtoAppList *data; + GSList *app; + + if (application_list == NULL) + return; + + for (app = application_list; app != NULL; app = app->next) { + data = app->data; + if (data->children) { + panel_addto_dialog_free_application_list (data->children); + } + panel_addto_dialog_free_item_info (&data->item_info); + g_free (data); + } + g_slist_free (application_list); +} + +static void +panel_addto_dialog_free (PanelAddtoDialog *dialog) +{ + MateConfClient *client; + GSList *item; + + client = panel_mateconf_get_client (); + + if (dialog->name_notify) + mateconf_client_notify_remove (client, dialog->name_notify); + dialog->name_notify = 0; + + if (dialog->search_text) + g_free (dialog->search_text); + dialog->search_text = NULL; + + if (dialog->applet_search_text) + g_free (dialog->applet_search_text); + dialog->applet_search_text = NULL; + + if (dialog->addto_dialog) + gtk_widget_destroy (dialog->addto_dialog); + dialog->addto_dialog = NULL; + + for (item = dialog->applet_list; item != NULL; item = item->next) { + PanelAddtoItemInfo *applet; + + applet = (PanelAddtoItemInfo *) item->data; + if (!applet->static_data) { + panel_addto_dialog_free_item_info (applet); + g_free (applet); + } + } + g_slist_free (dialog->applet_list); + + panel_addto_dialog_free_application_list (dialog->application_list); + panel_addto_dialog_free_application_list (dialog->settings_list); + + if (dialog->filter_applet_model) + g_object_unref (dialog->filter_applet_model); + dialog->filter_applet_model = NULL; + + if (dialog->applet_model) + g_object_unref (dialog->applet_model); + dialog->applet_model = NULL; + + if (dialog->filter_application_model) + g_object_unref (dialog->filter_application_model); + dialog->filter_application_model = NULL; + + if (dialog->application_model) + g_object_unref (dialog->application_model); + dialog->application_model = NULL; + + if (dialog->menu_tree) + matemenu_tree_unref (dialog->menu_tree); + dialog->menu_tree = NULL; + + g_free (dialog); +} + +static void +panel_addto_name_change (PanelAddtoDialog *dialog, + const char *name) +{ + char *title; + char *label; + + label = NULL; + + if (!PANEL_GLIB_STR_EMPTY (name)) + label = g_strdup_printf (_("Find an _item to add to \"%s\":"), + name); + + if (panel_toplevel_get_is_attached (dialog->panel_widget->toplevel)) { + title = g_strdup_printf (_("Add to Drawer")); + if (label == NULL) + label = g_strdup (_("Find an _item to add to the drawer:")); + } else { + title = g_strdup_printf (_("Add to Panel")); + if (label == NULL) + label = g_strdup (_("Find an _item to add to the panel:")); + } + + gtk_window_set_title (GTK_WINDOW (dialog->addto_dialog), title); + g_free (title); + + gtk_label_set_text_with_mnemonic (GTK_LABEL (dialog->label), label); + g_free (label); +} + +static void +panel_addto_name_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelAddtoDialog *dialog) +{ + MateConfValue *value; + const char *key; + const char *text = NULL; + + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + + if (strcmp (key, "name")) + return; + + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_STRING) + text = mateconf_value_get_string (value); + + if (text) + panel_addto_name_change (dialog, text); +} + +static gboolean +panel_addto_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer userdata) +{ + PanelAddtoDialog *dialog; + PanelAddtoItemInfo *data; + + dialog = (PanelAddtoDialog *) userdata; + + if (!dialog->search_text || !dialog->search_text[0]) + return TRUE; + + gtk_tree_model_get (model, iter, COLUMN_DATA, &data, -1); + + if (data == NULL) + return FALSE; + + /* This is more a workaround than anything else: show all the root + * items in a tree store */ + if (GTK_IS_TREE_STORE (model) && + gtk_tree_store_iter_depth (GTK_TREE_STORE (model), iter) == 0) + return TRUE; + + return (panel_g_utf8_strstrcase (data->name, + dialog->search_text) != NULL || + panel_g_utf8_strstrcase (data->description, + dialog->search_text) != NULL); +} + +static void +panel_addto_search_entry_changed (GtkWidget *entry, + PanelAddtoDialog *dialog) +{ + GtkTreeModel *model; + char *new_text; + GtkTreeIter iter; + GtkTreePath *path; + + new_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->search_entry))); + g_strchomp (new_text); + + if (dialog->search_text && + g_utf8_collate (new_text, dialog->search_text) == 0) { + g_free (new_text); + return; + } + + if (dialog->search_text) + g_free (dialog->search_text); + dialog->search_text = new_text; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tree_view)); + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model)); + + path = gtk_tree_path_new_first (); + if (gtk_tree_model_get_iter (model, &iter, path)) { + GtkTreeSelection *selection; + + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->tree_view), + path, NULL, FALSE, 0, 0); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tree_view)); + gtk_tree_selection_select_path (selection, path); + } + gtk_tree_path_free (path); +} + +static void +panel_addto_search_entry_activated (GtkWidget *entry, + PanelAddtoDialog *dialog) +{ + gtk_dialog_response (GTK_DIALOG (dialog->addto_dialog), + PANEL_ADDTO_RESPONSE_ADD); +} + +static void +panel_addto_selection_changed (GtkTreeSelection *selection, + PanelAddtoDialog *dialog) +{ + GtkTreeModel *filter_model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter filter_iter; + PanelAddtoItemInfo *data; + char *iid; + + if (!gtk_tree_selection_get_selected (selection, + &filter_model, + &filter_iter)) { + gtk_widget_set_sensitive (GTK_WIDGET (dialog->add_button), + FALSE); + return; + } + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter_model), + &iter, &filter_iter); + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); + gtk_tree_model_get (child_model, &iter, COLUMN_DATA, &data, -1); + + if (!data) { + gtk_widget_set_sensitive (GTK_WIDGET (dialog->add_button), + FALSE); + return; + } + + gtk_widget_set_sensitive (GTK_WIDGET (dialog->add_button), TRUE); + + if (data->type == PANEL_ADDTO_LAUNCHER_MENU) { + gtk_button_set_label (GTK_BUTTON (dialog->add_button), + GTK_STOCK_GO_FORWARD); + } else { + gtk_button_set_label (GTK_BUTTON (dialog->add_button), + GTK_STOCK_ADD); + } + gtk_button_set_use_stock (GTK_BUTTON (dialog->add_button), + TRUE); + + /* only allow dragging applets if we can add applets */ + if (panel_profile_id_lists_are_writable ()) { + switch (data->type) { + case PANEL_ADDTO_LAUNCHER: + panel_addto_setup_launcher_drag (GTK_TREE_VIEW (dialog->tree_view), + data->launcher_path); + break; + case PANEL_ADDTO_APPLET: + panel_addto_setup_applet_drag (GTK_TREE_VIEW (dialog->tree_view), + data->iid); + break; + case PANEL_ADDTO_LAUNCHER_MENU: + gtk_tree_view_unset_rows_drag_source (GTK_TREE_VIEW (dialog->tree_view)); + break; + case PANEL_ADDTO_MENU: + /* build the iid for menus other than the main menu */ + if (data->iid == NULL) { + iid = g_strdup_printf ("MENU:%s/%s", + data->menu_filename, + data->menu_path); + } else { + iid = g_strdup (data->iid); + } + panel_addto_setup_internal_applet_drag (GTK_TREE_VIEW (dialog->tree_view), + iid); + g_free (iid); + break; + default: + panel_addto_setup_internal_applet_drag (GTK_TREE_VIEW (dialog->tree_view), + data->iid); + break; + } + } +} + +static void +panel_addto_selection_activated (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PanelAddtoDialog *dialog) +{ + gtk_dialog_response (GTK_DIALOG (dialog->addto_dialog), + PANEL_ADDTO_RESPONSE_ADD); +} + +static gboolean +panel_addto_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + int column = GPOINTER_TO_INT (data); + char *text; + + gtk_tree_model_get (model, iter, column, &text, -1); + + if (!text) + return TRUE; + + g_free(text); + return FALSE; +} + +static PanelAddtoDialog * +panel_addto_dialog_new (PanelWidget *panel_widget) +{ + PanelAddtoDialog *dialog; + GtkWidget *dialog_vbox; + GtkWidget *vbox; + GtkWidget *inner_vbox; + GtkWidget *find_hbox; + GtkWidget *sw; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + + dialog = g_new0 (PanelAddtoDialog, 1); + + g_object_set_qdata_full (G_OBJECT (panel_widget->toplevel), + panel_addto_dialog_quark, + dialog, + (GDestroyNotify) panel_addto_dialog_free); + + dialog->panel_widget = panel_widget; + dialog->name_notify = + panel_profile_toplevel_notify_add ( + dialog->panel_widget->toplevel, + "name", + (MateConfClientNotifyFunc) panel_addto_name_notify, + dialog); + + + dialog->addto_dialog = gtk_dialog_new (); + gtk_dialog_add_button (GTK_DIALOG (dialog->addto_dialog), + GTK_STOCK_HELP, GTK_RESPONSE_HELP); + dialog->back_button = gtk_dialog_add_button (GTK_DIALOG (dialog->addto_dialog), + GTK_STOCK_GO_BACK, + PANEL_ADDTO_RESPONSE_BACK); + dialog->add_button = gtk_dialog_add_button (GTK_DIALOG (dialog->addto_dialog), + GTK_STOCK_ADD, + PANEL_ADDTO_RESPONSE_ADD); + gtk_dialog_add_button (GTK_DIALOG (dialog->addto_dialog), + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE); + gtk_widget_set_sensitive (GTK_WIDGET (dialog->add_button), FALSE); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog->addto_dialog), + FALSE); + gtk_dialog_set_default_response (GTK_DIALOG (dialog->addto_dialog), + PANEL_ADDTO_RESPONSE_ADD); + + gtk_container_set_border_width (GTK_CONTAINER (dialog->addto_dialog), 5); + + dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog->addto_dialog)); + gtk_box_set_spacing (GTK_BOX (dialog_vbox), 2); + + g_signal_connect (G_OBJECT (dialog->addto_dialog), "response", + G_CALLBACK (panel_addto_dialog_response), dialog); + g_signal_connect (dialog->addto_dialog, "destroy", + G_CALLBACK (panel_addto_dialog_destroy), dialog); + + vbox = gtk_vbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + gtk_container_add (GTK_CONTAINER (dialog_vbox), vbox); + + inner_vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (vbox), inner_vbox, TRUE, TRUE, 0); + + find_hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (inner_vbox), find_hbox, FALSE, FALSE, 0); + + dialog->label = gtk_label_new_with_mnemonic (""); + gtk_misc_set_alignment (GTK_MISC (dialog->label), 0.0, 0.5); + gtk_label_set_use_markup (GTK_LABEL (dialog->label), TRUE); + + gtk_box_pack_start (GTK_BOX (find_hbox), dialog->label, + FALSE, FALSE, 0); + + dialog->search_entry = gtk_entry_new (); + g_signal_connect (G_OBJECT (dialog->search_entry), "changed", + G_CALLBACK (panel_addto_search_entry_changed), dialog); + g_signal_connect (G_OBJECT (dialog->search_entry), "activate", + G_CALLBACK (panel_addto_search_entry_activated), dialog); + + gtk_box_pack_end (GTK_BOX (find_hbox), dialog->search_entry, + TRUE, TRUE, 0); + + gtk_label_set_mnemonic_widget (GTK_LABEL (dialog->label), + dialog->search_entry); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (inner_vbox), sw, TRUE, TRUE, 0); + + dialog->tree_view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->tree_view), + FALSE); + gtk_tree_view_expand_all (GTK_TREE_VIEW (dialog->tree_view)); + + renderer = g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF, + "xpad", 4, + "ypad", 4, + NULL); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (dialog->tree_view), + -1, NULL, + renderer, + "pixbuf", COLUMN_ICON, + NULL); + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (dialog->tree_view), + -1, NULL, + renderer, + "markup", COLUMN_TEXT, + NULL); + + //FIXME use the same search than the one for the search entry? + gtk_tree_view_set_search_column (GTK_TREE_VIEW (dialog->tree_view), + COLUMN_SEARCH); + + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (dialog->tree_view), + panel_addto_separator_func, + GINT_TO_POINTER (COLUMN_TEXT), + NULL); + + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tree_view)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->tree_view), + COLUMN_TEXT); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); + + g_signal_connect (selection, "changed", + G_CALLBACK (panel_addto_selection_changed), + dialog); + + g_signal_connect (dialog->tree_view, "row-activated", + G_CALLBACK (panel_addto_selection_activated), + dialog); + + gtk_container_add (GTK_CONTAINER (sw), dialog->tree_view); + + gtk_widget_show_all (vbox); + + panel_toplevel_push_autohide_disabler (dialog->panel_widget->toplevel); + panel_widget_register_open_dialog (panel_widget, + dialog->addto_dialog); + + panel_addto_name_change (dialog, + panel_toplevel_get_name (dialog->panel_widget->toplevel)); + + return dialog; +} + +#define MAX_ADDTOPANEL_HEIGHT 490 + +void +panel_addto_present (GtkMenuItem *item, + PanelWidget *panel_widget) +{ + PanelAddtoDialog *dialog; + PanelToplevel *toplevel; + PanelData *pd; + GdkScreen *screen; + gint screen_height; + gint height; + + toplevel = panel_widget->toplevel; + pd = g_object_get_data (G_OBJECT (toplevel), "PanelData"); + + if (!panel_addto_dialog_quark) + panel_addto_dialog_quark = + g_quark_from_static_string ("panel-addto-dialog"); + + dialog = g_object_get_qdata (G_OBJECT (toplevel), + panel_addto_dialog_quark); + + screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + screen_height = gdk_screen_get_height (screen); + height = MIN (MAX_ADDTOPANEL_HEIGHT, 3 * (screen_height / 4)); + + if (!dialog) { + dialog = panel_addto_dialog_new (panel_widget); + panel_addto_present_applets (dialog); + } + + dialog->insertion_position = pd ? pd->insertion_pos : -1; + gtk_window_set_screen (GTK_WINDOW (dialog->addto_dialog), screen); + gtk_window_set_default_size (GTK_WINDOW (dialog->addto_dialog), + height * 8 / 7, height); + gtk_window_present (GTK_WINDOW (dialog->addto_dialog)); +} diff --git a/mate-panel/panel-addto.h b/mate-panel/panel-addto.h new file mode 100644 index 00000000..5a2bb993 --- /dev/null +++ b/mate-panel/panel-addto.h @@ -0,0 +1,39 @@ +/* + * panel-addto.h: + * + * Copyright (C) 2004 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef __PANEL_ADDTO_H__ +#define __PANEL_ADDTO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_addto_present (GtkMenuItem *item, + PanelWidget *panel_widget); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_ADDTO_H__ */ diff --git a/mate-panel/panel-background-monitor.c b/mate-panel/panel-background-monitor.c new file mode 100644 index 00000000..1b4428dd --- /dev/null +++ b/mate-panel/panel-background-monitor.c @@ -0,0 +1,440 @@ +/* + * panel-background-monitor.c: + * + * Copyright (C) 2001, 2002 Ian McKellar + * 2002 Sun Microsystems, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Ian McKellar + * Mark McLoughlin + */ + +#include +#include +#include +#include +#include +#include + +#include "panel-background-monitor.h" +#include "panel-util.h" + +enum { + CHANGED, + LAST_SIGNAL +}; + +static void panel_background_monitor_changed (PanelBackgroundMonitor *monitor); + +static GdkFilterReturn panel_background_monitor_xevent_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data); + +struct _PanelBackgroundMonitorClass { + GObjectClass parent_class; + void (*changed) (PanelBackgroundMonitor *monitor); +}; + +struct _PanelBackgroundMonitor { + GObject parent_instance; + + GdkScreen *screen; + + Window xwindow; + GdkWindow *gdkwindow; + + Atom xatom; + GdkAtom gdkatom; + + GdkPixmap *gdkpixmap; + GdkPixbuf *gdkpixbuf; + + int width; + int height; + + gboolean display_grabbed; +}; + +G_DEFINE_TYPE (PanelBackgroundMonitor, panel_background_monitor, G_TYPE_OBJECT) + +static PanelBackgroundMonitor **global_background_monitors = NULL; + +static guint signals [LAST_SIGNAL] = { 0 }; + +static void +panel_background_monitor_finalize (GObject *object) +{ + PanelBackgroundMonitor *monitor; + + monitor = PANEL_BACKGROUND_MONITOR (object); + + gdk_window_remove_filter ( + monitor->gdkwindow, panel_background_monitor_xevent_filter, monitor); + g_signal_handlers_disconnect_by_func (monitor->screen, + panel_background_monitor_changed, monitor); + + if (monitor->gdkpixmap) + g_object_unref (monitor->gdkpixmap); + monitor->gdkpixmap = NULL; + + if (monitor->gdkpixbuf) + g_object_unref (monitor->gdkpixbuf); + monitor->gdkpixbuf = NULL; + + G_OBJECT_CLASS (panel_background_monitor_parent_class)->finalize (object); +} + +static void +panel_background_monitor_class_init (PanelBackgroundMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + signals [CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelBackgroundMonitorClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = panel_background_monitor_finalize; +} + +static void +panel_background_monitor_init (PanelBackgroundMonitor *monitor) +{ + monitor->screen = NULL; + + monitor->gdkwindow = NULL; + monitor->xwindow = None; + + monitor->gdkatom = gdk_atom_intern_static_string ("_XROOTPMAP_ID"); + monitor->xatom = gdk_x11_atom_to_xatom (monitor->gdkatom); + + monitor->gdkpixmap = NULL; + monitor->gdkpixbuf = NULL; + + monitor->display_grabbed = FALSE; +} + +static void +panel_background_monitor_connect_to_screen (PanelBackgroundMonitor *monitor, + GdkScreen *screen) +{ + if (monitor->screen != NULL && monitor->gdkwindow != NULL) { + gdk_window_remove_filter (monitor->gdkwindow, + panel_background_monitor_xevent_filter, + monitor); + } + + monitor->screen = screen; + g_signal_connect_swapped (screen, "size-changed", + G_CALLBACK (panel_background_monitor_changed), monitor); + + monitor->gdkwindow = gdk_screen_get_root_window (screen); + monitor->xwindow = gdk_x11_drawable_get_xid (monitor->gdkwindow); + + gdk_window_add_filter ( + monitor->gdkwindow, panel_background_monitor_xevent_filter, monitor); + + gdk_window_set_events ( + monitor->gdkwindow, + gdk_window_get_events (monitor->gdkwindow) | GDK_PROPERTY_CHANGE_MASK); +} + +static PanelBackgroundMonitor * +panel_background_monitor_new (GdkScreen *screen) +{ + PanelBackgroundMonitor *monitor; + + monitor = g_object_new (PANEL_TYPE_BACKGROUND_MONITOR, NULL); + + panel_background_monitor_connect_to_screen (monitor, screen); + + return monitor; +} + +PanelBackgroundMonitor * +panel_background_monitor_get_for_screen (GdkScreen *screen) +{ + int screen_number; + + screen_number = gdk_screen_get_number (screen); + + if (!global_background_monitors) { + int n_screens; + + n_screens = gdk_display_get_n_screens (gdk_display_get_default ()); + + global_background_monitors = g_new0 (PanelBackgroundMonitor *, n_screens); + } + + if (!global_background_monitors [screen_number]) { + global_background_monitors [screen_number] = + panel_background_monitor_new (screen); + + g_object_add_weak_pointer ( + G_OBJECT (global_background_monitors [screen_number]), + (void **) &global_background_monitors [screen_number]); + + return global_background_monitors [screen_number]; + } + + return g_object_ref (global_background_monitors [screen_number]); +} + +static void +panel_background_monitor_changed (PanelBackgroundMonitor *monitor) +{ + if (monitor->gdkpixmap) + g_object_unref (monitor->gdkpixmap); + monitor->gdkpixmap = NULL; + + if (monitor->gdkpixbuf) + g_object_unref (monitor->gdkpixbuf); + monitor->gdkpixbuf = NULL; + + g_signal_emit (monitor, signals [CHANGED], 0); +} + +static GdkFilterReturn +panel_background_monitor_xevent_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + PanelBackgroundMonitor *monitor; + XEvent *xev; + + g_return_val_if_fail (PANEL_IS_BACKGROUND_MONITOR (data), GDK_FILTER_CONTINUE); + + monitor = PANEL_BACKGROUND_MONITOR (data); + xev = (XEvent *) xevent; + + if (xev->type == PropertyNotify && + xev->xproperty.atom == monitor->xatom && + xev->xproperty.window == monitor->xwindow) + panel_background_monitor_changed (monitor); + + return GDK_FILTER_CONTINUE; +} + +static void +panel_background_monitor_setup_pixmap (PanelBackgroundMonitor *monitor) +{ + Pixmap *prop_data = NULL; + GdkAtom prop_type; + + g_assert (monitor->display_grabbed); + + if (!gdk_property_get ( + monitor->gdkwindow, monitor->gdkatom, + gdk_x11_xatom_to_atom (XA_PIXMAP), 0, 10, + FALSE, &prop_type, NULL, NULL, (gpointer) &prop_data)) + return; + + if ((prop_type == GDK_TARGET_PIXMAP) && prop_data && prop_data [0]) { + GdkDisplay *display; + + g_assert (monitor->gdkpixmap == NULL); + + display = gdk_screen_get_display (monitor->screen); + + monitor->gdkpixmap = gdk_pixmap_foreign_new_for_display (display, + prop_data [0]); + + if (!monitor->gdkpixmap) + g_warning ("couldn't get background pixmap\n"); + } + + g_free (prop_data); +} + +static GdkPixbuf * +panel_background_monitor_tile_background (PanelBackgroundMonitor *monitor, + int width, + int height) +{ + GdkPixbuf *retval; + int tilewidth, tileheight; + + retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); + + tilewidth = gdk_pixbuf_get_width (monitor->gdkpixbuf); + tileheight = gdk_pixbuf_get_height (monitor->gdkpixbuf); + + if (tilewidth == 1 && tileheight == 1) { + guchar *pixels; + int n_channels; + guint32 pixel = 0; + + n_channels = gdk_pixbuf_get_n_channels (monitor->gdkpixbuf); + pixels = gdk_pixbuf_get_pixels (monitor->gdkpixbuf); + + if (pixels) { + if (n_channels == 4) + pixel = ((guint32 *) pixels) [0]; + else if (n_channels == 3) + pixel = pixels [0] << 24 | pixels [1] << 16 | pixels [2] << 8; + } + + gdk_pixbuf_fill (retval, pixel); + } else { + unsigned char *data; + cairo_t *cr; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + + data = g_malloc (width * height * 4); + if (!data) + return NULL; + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_RGB24, + width, height, + width * 4); + cr = cairo_create (surface); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + gdk_cairo_set_source_pixbuf (cr, monitor->gdkpixbuf, 0, 0); + pattern = cairo_get_source (cr); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + retval = panel_util_cairo_rgbdata_to_pixbuf (data, + width, height); + + g_free (data); + } + + return retval; +} + +static void +panel_background_monitor_setup_pixbuf (PanelBackgroundMonitor *monitor) +{ + GdkColormap *colormap = NULL; + GdkDisplay *display; + int rwidth, rheight; + int pwidth, pheight; + + display = gdk_screen_get_display (monitor->screen); + + gdk_x11_display_grab (display); + monitor->display_grabbed = TRUE; + + if (!monitor->gdkpixmap) + panel_background_monitor_setup_pixmap (monitor); + + if (!monitor->gdkpixmap) { + gdk_x11_display_ungrab (display); + monitor->display_grabbed = FALSE; + return; + } + + #if GTK_CHECK_VERSION(3, 0, 0) + pwidth = gdk_window_get_width(monitor->gdkpixmap); + pheight = gdk_window_get_height(monitor->gdkpixmap); + #else + gdk_drawable_get_size(GDK_DRAWABLE(monitor->gdkpixmap), &pwidth, &pheight); + #endif + + gdk_window_get_geometry (monitor->gdkwindow, + NULL, NULL, &rwidth, &rheight, NULL); + + monitor->width = MIN (pwidth, rwidth); + monitor->height = MIN (pheight, rheight); + + colormap = gdk_drawable_get_colormap (monitor->gdkwindow); + + g_assert (monitor->gdkpixbuf == NULL); + monitor->gdkpixbuf = gdk_pixbuf_get_from_drawable ( + NULL, monitor->gdkpixmap, colormap, + 0, 0, 0, 0, + monitor->width, monitor->height); + + gdk_x11_display_ungrab (display); + monitor->display_grabbed = FALSE; + + if (monitor->gdkpixbuf == NULL) + return; + + if ((monitor->width < rwidth || monitor->height < rheight)) { + GdkPixbuf *tiled; + + tiled = panel_background_monitor_tile_background ( + monitor, rwidth, rheight); + g_object_unref (monitor->gdkpixbuf); + monitor->gdkpixbuf = tiled; + + monitor->width = rwidth; + monitor->height = rheight; + } +} + +GdkPixbuf * +panel_background_monitor_get_region (PanelBackgroundMonitor *monitor, + int x, + int y, + int width, + int height) +{ + GdkPixbuf *pixbuf, *tmpbuf; + int subwidth, subheight; + int subx, suby; + + if (!monitor->gdkpixbuf) + panel_background_monitor_setup_pixbuf (monitor); + + if (!monitor->gdkpixbuf) + return NULL; + + subwidth = MIN (width, monitor->width - x); + subheight = MIN (height, monitor->height - y); + /* if x or y are negative numbers */ + subwidth = MIN (subwidth, width + x); + subheight = MIN (subheight, height + y); + + subx = MAX (x, 0); + suby = MAX (y, 0); + + if ((subwidth <= 0) || (subheight <= 0) || + (monitor->width-x < 0) || (monitor->height-y < 0) ) + /* region is completely offscreen */ + return gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, + width, height); + + pixbuf = gdk_pixbuf_new_subpixbuf ( + monitor->gdkpixbuf, subx, suby, subwidth, subheight); + + if ((subwidth < width) || (subheight < height)) { + tmpbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, + width, height); + gdk_pixbuf_copy_area (pixbuf, 0, 0, subwidth, subheight, + tmpbuf, (x < 0) ? -x : 0, (y < 0) ? -y : 0); + g_object_unref (pixbuf); + pixbuf = tmpbuf; + } + + return pixbuf; +} diff --git a/mate-panel/panel-background-monitor.h b/mate-panel/panel-background-monitor.h new file mode 100644 index 00000000..b74f15fd --- /dev/null +++ b/mate-panel/panel-background-monitor.h @@ -0,0 +1,60 @@ +/* + * panel-background-monitor.h: + * + * Copyright (C) 2001, 2002 Ian McKellar + * 2002 Sun Microsystems, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Ian McKellar + * Mark McLoughlin + */ + +#ifndef __PANEL_BACKGROUND_MONITOR_H__ +#define __PANEL_BACKGROUND_MONITOR_H__ + +#include +#include +#include + +#define PANEL_TYPE_BACKGROUND_MONITOR (panel_background_monitor_get_type ()) +#define PANEL_BACKGROUND_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \ + PANEL_TYPE_BACKGROUND_MONITOR, \ + PanelBackgroundMonitor)) +#define PANEL_BACKGROUND_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), \ + PANEL_TYPE_BACKGROUND_MONITOR, \ + PanelBackgroundMonitorClass)) +#define PANEL_IS_BACKGROUND_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ + PANEL_TYPE_BACKGROUND_MONITOR)) +#define PANEL_IS_BACKGROUND_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), \ + PANEL_TYPE_BACKGROUND_MONITOR)) +#define PANEL_BACKGROUND_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), \ + PANEL_TYPE_BACKGROUND_MONITOR, \ + PanelBackgroundMonitorClass)) + +typedef struct _PanelBackgroundMonitorClass PanelBackgroundMonitorClass; +typedef struct _PanelBackgroundMonitor PanelBackgroundMonitor; + +GType panel_background_monitor_get_type (void); +PanelBackgroundMonitor *panel_background_monitor_get_for_screen (GdkScreen *screen); +GdkPixbuf *panel_background_monitor_get_region (PanelBackgroundMonitor *monitor, + int x, + int y, + int width, + int height); + +#endif /* __PANEL_BACKGROUND_MONITOR_H__ */ diff --git a/mate-panel/panel-background.c b/mate-panel/panel-background.c new file mode 100644 index 00000000..6341b290 --- /dev/null +++ b/mate-panel/panel-background.c @@ -0,0 +1,1156 @@ +/* + * panel-background.c: panel background rendering + * + * Copyright (C) 2002, 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-background.h" + +#include +#include +#include +#include + +#include "panel-background-monitor.h" +#include "panel-util.h" + + +static gboolean panel_background_composite (PanelBackground *background); +static void load_background_file (PanelBackground *background); + + +static void +free_prepared_resources (PanelBackground *background) +{ + background->prepared = FALSE; + + switch (background->type) { + case PANEL_BACK_NONE: + break; + case PANEL_BACK_COLOR: + if (background->has_alpha) { + if (background->pixmap) + g_object_unref (background->pixmap); + background->pixmap = NULL; + } else { + if (background->colormap && background->color.gdk.pixel) + gdk_colormap_free_colors ( + background->colormap, + &background->color.gdk, 1); + background->color.gdk.pixel = 0; + } + break; + case PANEL_BACK_IMAGE: + if (background->pixmap) + g_object_unref (background->pixmap); + background->pixmap = NULL; + break; + default: + g_assert_not_reached (); + break; + } +} + +static void +set_pixbuf_background (PanelBackground *background) +{ + g_assert (background->composited_image != NULL); + + gdk_pixbuf_render_pixmap_and_mask_for_colormap ( + background->composited_image, + background->colormap, + &background->pixmap, NULL, 128); + + gdk_window_set_back_pixmap ( + background->window, background->pixmap, FALSE); +} + +static gboolean +panel_background_prepare (PanelBackground *background) +{ + PanelBackgroundType effective_type; + GtkWidget *widget = NULL; + + if (!background->colormap || !background->transformed) + return FALSE; + + free_prepared_resources (background); + + effective_type = panel_background_effective_type (background); + + switch (effective_type) { + case PANEL_BACK_NONE: + if (background->default_pixmap) { + if (background->default_pixmap != (GdkPixmap*) GDK_PARENT_RELATIVE) + gdk_window_set_back_pixmap (background->window, + background->default_pixmap, + FALSE); + else + gdk_window_set_back_pixmap (background->window, + NULL, + TRUE); + } else + gdk_window_set_background ( + background->window, &background->default_color); + break; + case PANEL_BACK_COLOR: + if (background->has_alpha && + background->composited_image) + set_pixbuf_background (background); + else { + gdk_colormap_alloc_color ( + background->colormap, + &background->color.gdk, + FALSE, TRUE); + gdk_window_set_background ( + background->window, &background->color.gdk); + } + break; + case PANEL_BACK_IMAGE: + set_pixbuf_background (background); + break; + default: + g_assert_not_reached (); + break; + } + + /* Panel applets may use the panel's background pixmap to + * decide how to draw themselves. Therefore, we need to + * make sure that all drawing has been completed before + * the applet looks at the pixmap. */ + gdk_display_sync (gdk_drawable_get_display (background->window)); + + gdk_window_get_user_data (GDK_WINDOW (background->window), + (gpointer) &widget); + + if (GTK_IS_WIDGET (widget)) + gtk_widget_queue_draw (widget); + + background->prepared = TRUE; + + background->notify_changed (background, background->user_data); + + return TRUE; +} + +static void +free_composited_resources (PanelBackground *background) +{ + free_prepared_resources (background); + + background->composited = FALSE; + + if (background->composited_image) + g_object_unref (background->composited_image); + background->composited_image = NULL; +} + +static void +background_changed (PanelBackgroundMonitor *monitor, + PanelBackground *background) +{ + GdkPixbuf *tmp; + + tmp = background->desktop; + + background->desktop = panel_background_monitor_get_region ( + background->monitor, + background->region.x, + background->region.y, + background->region.width, + background->region.height); + + if (tmp) + g_object_unref (tmp); + + panel_background_composite (background); +} + +static GdkPixbuf * +get_desktop_pixbuf (PanelBackground *background) +{ + GdkPixbuf *desktop; + + if (!background->monitor) { + background->monitor = + panel_background_monitor_get_for_screen ( + gdk_drawable_get_screen (background->window)); + + background->monitor_signal = + g_signal_connect ( + background->monitor, "changed", + G_CALLBACK (background_changed), background); + } + + desktop = panel_background_monitor_get_region ( + background->monitor, + background->region.x, + background->region.y, + background->region.width, + background->region.height); + + return desktop; +} + +static GdkPixbuf * +composite_image_onto_desktop (PanelBackground *background) +{ + GdkPixbuf *retval; + int width, height; + unsigned char *data; + cairo_t *cr; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + + if (!background->desktop) + background->desktop = get_desktop_pixbuf (background); + + if (!background->desktop) + return NULL; + + width = gdk_pixbuf_get_width (background->desktop); + height = gdk_pixbuf_get_height (background->desktop); + + data = g_malloc (width * height * 4); + if (!data) + return NULL; + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_RGB24, + width, height, + width * 4); + cr = cairo_create (surface); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + gdk_cairo_set_source_pixbuf (cr, background->desktop, 0, 0); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + gdk_cairo_set_source_pixbuf (cr, background->transformed_image, 0, 0); + pattern = cairo_get_source (cr); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + retval = panel_util_cairo_rgbdata_to_pixbuf (data, width, height); + + g_free (data); + + return retval; +} + +static GdkPixbuf * +composite_color_onto_desktop (PanelBackground *background) +{ + guint32 color; + + if (!background->desktop) + background->desktop = get_desktop_pixbuf (background); + + if (!background->desktop) + return NULL; + + color = ((background->color.gdk.red & 0xff00) << 8) + + (background->color.gdk.green & 0xff00) + + (background->color.gdk.blue >> 8); + + return gdk_pixbuf_composite_color_simple ( + background->desktop, + gdk_pixbuf_get_width (background->desktop), + gdk_pixbuf_get_height (background->desktop), + GDK_INTERP_NEAREST, + (255 - (background->color.alpha >> 8)), + 255, color, color); +} + +static GdkPixbuf * +get_composited_pixbuf (PanelBackground *background) +{ + GdkPixbuf *retval = NULL; + + switch (background->type) { + case PANEL_BACK_NONE: + break; + case PANEL_BACK_COLOR: + retval = composite_color_onto_desktop (background); + break; + case PANEL_BACK_IMAGE: + retval = composite_image_onto_desktop (background); + if (!retval) + retval = g_object_ref (background->transformed_image); + break; + default: + g_assert_not_reached (); + break; + } + + return retval; +} + +static gboolean +panel_background_composite (PanelBackground *background) +{ + if (!background->transformed) + return FALSE; + + free_composited_resources (background); + + switch (background->type) { + case PANEL_BACK_NONE: + break; + case PANEL_BACK_COLOR: + if (background->has_alpha) + background->composited_image = + get_composited_pixbuf (background); + break; + case PANEL_BACK_IMAGE: + if (background->transformed_image) { + if (background->has_alpha) + background->composited_image = + get_composited_pixbuf (background); + else + background->composited_image = + g_object_ref (background->transformed_image); + } + break; + default: + g_assert_not_reached (); + break; + } + + background->composited = TRUE; + + panel_background_prepare (background); + + return TRUE; +} + +static void +free_transformed_resources (PanelBackground *background) +{ + free_composited_resources (background); + + background->transformed = FALSE; + + if (background->type != PANEL_BACK_IMAGE) + return; + + if (background->transformed_image) + g_object_unref (background->transformed_image); + background->transformed_image = NULL; +} + +static GdkPixbuf * +get_scaled_and_rotated_pixbuf (PanelBackground *background) +{ + GdkPixbuf *scaled; + GdkPixbuf *retval; + int orig_width, orig_height; + int panel_width, panel_height; + int width, height; + + load_background_file (background); + if (!background->loaded_image) + return NULL; + + orig_width = gdk_pixbuf_get_width (background->loaded_image); + orig_height = gdk_pixbuf_get_height (background->loaded_image); + + panel_width = background->region.width; + panel_height = background->region.height; + + width = orig_width; + height = orig_height; + + if (background->fit_image) { + switch (background->orientation) { + case GTK_ORIENTATION_HORIZONTAL: + width = orig_width * panel_height / orig_height; + height = panel_height; + break; + case GTK_ORIENTATION_VERTICAL: + if (background->rotate_image) { + width = orig_width * panel_width / orig_height; + height = panel_width; + } else { + width = panel_width; + height = orig_height * panel_width / orig_width; + } + break; + default: + g_assert_not_reached (); + break; + } + } else if (background->stretch_image) { + if (background->orientation == GTK_ORIENTATION_VERTICAL && + background->rotate_image) { + width = panel_height; + height = panel_width; + } else { + width = panel_width; + height = panel_height; + } + } else if (background->orientation == GTK_ORIENTATION_VERTICAL && + background->rotate_image) { + int tmp = width; + width = height; + height = tmp; + } + + if (width == orig_width && + height == orig_height) { + scaled = background->loaded_image; + g_object_ref (scaled); + } else { + scaled = gdk_pixbuf_scale_simple ( + background->loaded_image, + width, height, + GDK_INTERP_BILINEAR); + } + + if (background->rotate_image && + background->orientation == GTK_ORIENTATION_VERTICAL) { + if (!background->has_alpha) { + guchar *dest; + guchar *src; + int x, y; + int destrowstride; + int srcrowstride; + + retval = gdk_pixbuf_new ( + GDK_COLORSPACE_RGB, FALSE, 8, height, width); + + dest = gdk_pixbuf_get_pixels (retval); + destrowstride = gdk_pixbuf_get_rowstride (retval); + src = gdk_pixbuf_get_pixels (scaled); + srcrowstride = gdk_pixbuf_get_rowstride (scaled); + + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) { + guchar *dstptr = & ( dest [3*y + destrowstride * (width - x - 1)] ); + guchar *srcptr = & ( src [y * srcrowstride + 3*x] ); + dstptr[0] = srcptr[0]; + dstptr[1] = srcptr[1]; + dstptr[2] = srcptr[2]; + } + + g_object_unref (scaled); + } else { + guint32 *dest; + guint32 *src; + int x, y; + int destrowstride; + int srcrowstride; + + retval = gdk_pixbuf_new ( + GDK_COLORSPACE_RGB, TRUE, 8, height, width); + + dest = (guint32 *) gdk_pixbuf_get_pixels (retval); + destrowstride = gdk_pixbuf_get_rowstride (retval) / 4; + src = (guint32 *) gdk_pixbuf_get_pixels (scaled); + srcrowstride = gdk_pixbuf_get_rowstride (scaled) / 4; + + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + dest [y + destrowstride * (width - x - 1)] = + src [y * srcrowstride + x]; + + g_object_unref (scaled); + } + } else + retval = scaled; + + return retval; +} + +static gboolean +panel_background_transform (PanelBackground *background) +{ + if (background->region.width == -1) + return FALSE; + + free_transformed_resources (background); + + if (background->type == PANEL_BACK_IMAGE) + background->transformed_image = + get_scaled_and_rotated_pixbuf (background); + + background->transformed = TRUE; + + panel_background_composite (background); + + return TRUE; +} + +static void +disconnect_background_monitor (PanelBackground *background) +{ + if (background->monitor) { + g_signal_handler_disconnect ( + background->monitor, background->monitor_signal); + background->monitor_signal = -1; + g_object_unref (background->monitor); + } + background->monitor = NULL; + + if (background->desktop) + g_object_unref (background->desktop); + background->desktop = NULL; +} + +static void +panel_background_update_has_alpha (PanelBackground *background) +{ + gboolean has_alpha = FALSE; + + if (background->type == PANEL_BACK_COLOR) + has_alpha = (background->color.alpha != 0xffff); + + else if (background->type == PANEL_BACK_IMAGE && + background->loaded_image) + has_alpha = gdk_pixbuf_get_has_alpha (background->loaded_image); + + background->has_alpha = has_alpha; + + if (!has_alpha) + disconnect_background_monitor (background); +} + +static void +load_background_file (PanelBackground *background) +{ + GError *error = NULL; + + if (!g_file_test (background->image, G_FILE_TEST_IS_REGULAR)) + return; + + //FIXME add a monitor on the file so that we reload the background + //when it changes + background->loaded_image = + gdk_pixbuf_new_from_file (background->image, &error); + if (!background->loaded_image) { + g_assert (error != NULL); + g_warning (G_STRLOC ": unable to open '%s': %s", + background->image, error->message); + g_error_free (error); + } + + panel_background_update_has_alpha (background); +} + +void +panel_background_set_type (PanelBackground *background, + PanelBackgroundType type) +{ + if (background->type == type) + return; + + free_transformed_resources (background); + + background->type = type; + + panel_background_update_has_alpha (background); + + panel_background_transform (background); +} + +static void +panel_background_set_gdk_color_no_update (PanelBackground *background, + GdkColor *gdk_color) +{ + g_return_if_fail (gdk_color != NULL); + + background->color.gdk.red = gdk_color->red; + background->color.gdk.green = gdk_color->green; + background->color.gdk.blue = gdk_color->blue; +} + +void +panel_background_set_gdk_color (PanelBackground *background, + GdkColor *gdk_color) +{ + g_return_if_fail (gdk_color != NULL); + + if (background->color.gdk.red == gdk_color->red && + background->color.gdk.green == gdk_color->green && + background->color.gdk.blue == gdk_color->blue) + return; + + free_transformed_resources (background); + panel_background_set_gdk_color_no_update (background, gdk_color); + panel_background_transform (background); +} + +static void +panel_background_set_opacity_no_update (PanelBackground *background, + guint16 opacity) +{ + background->color.alpha = opacity; + panel_background_update_has_alpha (background); +} + +void +panel_background_set_opacity (PanelBackground *background, + guint16 opacity) +{ + if (background->color.alpha == opacity) + return; + + free_transformed_resources (background); + panel_background_set_opacity_no_update (background, opacity); + panel_background_transform (background); +} + +static void +panel_background_set_color_no_update (PanelBackground *background, + PanelColor *color) +{ + g_return_if_fail (color != NULL); + + panel_background_set_gdk_color_no_update (background, &(color->gdk)); + panel_background_set_opacity_no_update (background, color->alpha); +} + +void +panel_background_set_color (PanelBackground *background, + PanelColor *color) +{ + g_return_if_fail (color != NULL); + + if (background->color.gdk.red == color->gdk.red && + background->color.gdk.green == color->gdk.green && + background->color.gdk.blue == color->gdk.blue && + background->color.alpha == color->alpha) + return; + + free_transformed_resources (background); + panel_background_set_color_no_update (background, color); + panel_background_transform (background); +} + +static void +panel_background_set_image_no_update (PanelBackground *background, + const char *image) +{ + if (background->loaded_image) + g_object_unref (background->loaded_image); + background->loaded_image = NULL; + + if (background->image) + g_free (background->image); + background->image = NULL; + + if (image && image [0]) + background->image = g_strdup (image); + + panel_background_update_has_alpha (background); +} + +void +panel_background_set_image (PanelBackground *background, + const char *image) +{ + if (!background->image && !image) + return; + + if (background->image && image && !strcmp (background->image, image)) + return; + + free_transformed_resources (background); + panel_background_set_image_no_update (background, image); + panel_background_transform (background); +} + +static void +panel_background_set_fit_no_update (PanelBackground *background, + gboolean fit_image) +{ + background->fit_image = fit_image != FALSE; +} + +void +panel_background_set_fit (PanelBackground *background, + gboolean fit_image) +{ + fit_image = fit_image != FALSE; + + if (background->fit_image == fit_image) + return; + + free_transformed_resources (background); + panel_background_set_fit_no_update (background, fit_image); + panel_background_transform (background); +} + +static void +panel_background_set_stretch_no_update (PanelBackground *background, + gboolean stretch_image) +{ + background->stretch_image = stretch_image != FALSE; +} + +void +panel_background_set_stretch (PanelBackground *background, + gboolean stretch_image) +{ + stretch_image = stretch_image != FALSE; + + if (background->stretch_image == stretch_image) + return; + + free_transformed_resources (background); + panel_background_set_stretch_no_update (background, stretch_image); + panel_background_transform (background); +} + +static void +panel_background_set_rotate_no_update (PanelBackground *background, + gboolean rotate_image) +{ + background->rotate_image = rotate_image != FALSE; +} + +void +panel_background_set_rotate (PanelBackground *background, + gboolean rotate_image) +{ + rotate_image = rotate_image != FALSE; + + if (background->rotate_image == rotate_image) + return; + + free_transformed_resources (background); + panel_background_set_rotate_no_update (background, rotate_image); + panel_background_transform (background); +} + +void +panel_background_set (PanelBackground *background, + PanelBackgroundType type, + PanelColor *color, + const char *image, + gboolean fit_image, + gboolean stretch_image, + gboolean rotate_image) +{ + panel_background_set_color_no_update (background, color); + panel_background_set_image_no_update (background, image); + panel_background_set_fit_no_update (background, fit_image); + panel_background_set_stretch_no_update (background, stretch_image); + panel_background_set_rotate_no_update (background, rotate_image); + panel_background_set_type (background, type); +} + +void +panel_background_set_default_style (PanelBackground *background, + GdkColor *color, + GdkPixmap *pixmap) +{ + g_return_if_fail (color != NULL); + + background->default_color = *color; + + if (pixmap && pixmap != (GdkPixmap*) GDK_PARENT_RELATIVE) + g_object_ref (pixmap); + + if (background->default_pixmap + && background->default_pixmap != (GdkPixmap*) GDK_PARENT_RELATIVE) + g_object_unref (background->default_pixmap); + + background->default_pixmap = pixmap; + + if (background->type == PANEL_BACK_NONE) + panel_background_prepare (background); +} + +void +panel_background_realized (PanelBackground *background, + GdkWindow *window) +{ + g_return_if_fail (window != NULL); + + if (background->window && background->colormap && background->gc) + return; + + if (!background->window) + background->window = g_object_ref (window); + + if (!background->colormap) + background->colormap = + g_object_ref (gdk_drawable_get_colormap (window)); + + if (!background->gc) + background->gc = gdk_gc_new (window); + + panel_background_prepare (background); +} + +void +panel_background_unrealized (PanelBackground *background) +{ + free_prepared_resources (background); + + if (background->window) + g_object_unref (background->window); + background->window = NULL; + + if (background->colormap) + g_object_unref (background->colormap); + background->colormap = NULL; + + if (background->gc) + g_object_unref (background->gc); + background->gc = NULL; +} + +void +panel_background_change_region (PanelBackground *background, + GtkOrientation orientation, + int x, + int y, + int width, + int height) +{ + gboolean need_to_retransform = FALSE; + gboolean need_to_reprepare = FALSE; + + if (background->region.x == x && + background->region.y == y && + background->region.width == width && + background->region.height == height && + background->orientation == orientation) + return; + + /* we only need to retransform anything + on size/orientation changes if the + background is an image and some + conditions are met */ + if (background->type == PANEL_BACK_IMAGE) { + if (background->orientation != orientation && + background->rotate_image) { + /* if orientation changes and we are rotating */ + need_to_retransform = TRUE; + } else if ((background->region.width != width || + background->region.height != height) && + (background->fit_image || + background->stretch_image)) { + /* or if the size changes and we are + stretching or fitting the image */ + need_to_retransform = TRUE; + } + } + + /* if size changed, we at least need + to "prepare" the background again */ + if (background->region.width != width || + background->region.height != height) + need_to_reprepare = TRUE; + + background->region.x = x; + background->region.y = y; + background->region.width = width; + background->region.height = height; + + background->orientation = orientation; + + if (background->desktop) + g_object_unref (background->desktop); + background->desktop = NULL; + + if (need_to_retransform || ! background->transformed) + /* only retransform the background if we have in + fact changed size/orientation */ + panel_background_transform (background); + else if (background->has_alpha || ! background->composited) + /* only do compositing if we have some alpha + value to worry about */ + panel_background_composite (background); + else if (need_to_reprepare) + /* at least we must prepare the background + if the size changed */ + panel_background_prepare (background); +} + +void +panel_background_init (PanelBackground *background, + PanelBackgroundChangedNotify notify_changed, + gpointer user_data) +{ + background->type = PANEL_BACK_NONE; + background->notify_changed = notify_changed; + background->user_data = user_data; + + background->color.gdk.red = 0; + background->color.gdk.blue = 0; + background->color.gdk.green = 0; + background->color.gdk.pixel = 0; + background->color.alpha = 0xffff; + + background->image = NULL; + background->loaded_image = NULL; + + background->orientation = GTK_ORIENTATION_HORIZONTAL; + background->region.x = -1; + background->region.y = -1; + background->region.width = -1; + background->region.height = -1; + background->transformed_image = NULL; + background->composited_image = NULL; + + background->monitor = NULL; + background->desktop = NULL; + background->monitor_signal = -1; + + background->pixmap = NULL; + background->window = NULL; + background->colormap = NULL; + background->gc = NULL; + + background->default_pixmap = NULL; + background->default_color.red = 0; + background->default_color.green = 0; + background->default_color.blue = 0; + background->default_color.pixel = 0; + + background->fit_image = FALSE; + background->stretch_image = FALSE; + background->rotate_image = FALSE; + + background->has_alpha = FALSE; + + background->transformed = FALSE; + background->composited = FALSE; + background->prepared = FALSE; +} + +void +panel_background_free (PanelBackground *background) +{ + disconnect_background_monitor (background); + + free_transformed_resources (background); + + if (background->image) + g_free (background->image); + background->image = NULL; + + if (background->loaded_image) + g_object_unref (background->loaded_image); + background->loaded_image = NULL; + + if (background->monitor) + g_object_unref (background->monitor); + background->monitor = NULL; + + if (background->window) + g_object_unref (background->window); + background->window = NULL; + + if (background->colormap) + g_object_unref (background->colormap); + background->colormap = NULL; + + if (background->gc) + g_object_unref (background->gc); + background->gc = NULL; + + if (background->default_pixmap + && background->default_pixmap != (GdkPixmap*) GDK_PARENT_RELATIVE) + g_object_unref (background->default_pixmap); + background->default_pixmap = NULL; +} + +char * +panel_background_make_string (PanelBackground *background, + int x, + int y) +{ + PanelBackgroundType effective_type; + char *retval; + + retval = NULL; + + effective_type = panel_background_effective_type (background); + + if (effective_type == PANEL_BACK_IMAGE || + (effective_type == PANEL_BACK_COLOR && background->has_alpha)) { + GdkNativeWindow pixmap_xid; + + if (!background->pixmap) + return NULL; + + pixmap_xid = gdk_x11_drawable_get_xid ( + GDK_DRAWABLE (background->pixmap)); + + retval = g_strdup_printf ("pixmap:%d,%d,%d", pixmap_xid, x, y); + + } else if (effective_type == PANEL_BACK_COLOR) + retval = g_strdup_printf ( + "color:%.4x%.4x%.4x", + background->color.gdk.red, + background->color.gdk.green, + background->color.gdk.blue); + else + retval = g_strdup ("none:"); + + return retval; + +} + +PanelBackgroundType +panel_background_get_type (PanelBackground *background) +{ + return background->type; +} + +const PanelColor * +panel_background_get_color (PanelBackground *background) +{ + return &(background->color); +} + +const GdkPixmap * +panel_background_get_pixmap (PanelBackground *background) +{ + return background->pixmap; +} + + +/* What are we actually rendering - e.g. if we're supposed to + * be rendering an image, but haven't got a valid image, then + * we're rendering the default gtk background. + */ +PanelBackgroundType +panel_background_effective_type (PanelBackground *background) +{ + PanelBackgroundType retval; + + retval = background->type; + if (background->type == PANEL_BACK_IMAGE && !background->composited_image) + retval = PANEL_BACK_NONE; + + return retval; +} + +static void +panel_background_set_no_background_on_widget (PanelBackground *background, + GtkWidget *widget) +{ + GtkRcStyle *rc_style; + + gtk_widget_set_style (widget, NULL); + rc_style = gtk_rc_style_new (); + gtk_widget_modify_style (widget, rc_style); + g_object_unref (rc_style); +} + +static void +panel_background_set_image_background_on_widget (PanelBackground *background, + GtkWidget *widget) +{ + const GdkPixmap *bg_pixmap; + GtkAllocation allocation; + GdkPixmap *pixmap; + cairo_t *cr; + cairo_pattern_t *pattern; + GtkStyle *style; + + bg_pixmap = panel_background_get_pixmap (background); + if (!bg_pixmap) + return; + + gtk_widget_get_allocation (widget, &allocation); + pixmap = gdk_pixmap_new (gtk_widget_get_window (widget), + allocation.width, + allocation.height, + -1); + + cr = gdk_cairo_create (GDK_DRAWABLE (pixmap)); + gdk_cairo_set_source_pixmap (cr, (GdkPixmap *) bg_pixmap, + -allocation.x, + -allocation.y); + pattern = cairo_get_source (cr); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + + cairo_rectangle (cr, 0, 0, + allocation.width, allocation.height); + cairo_fill (cr); + + cairo_destroy (cr); + + style = gtk_style_copy (gtk_widget_get_style (widget)); + if (style->bg_pixmap[GTK_STATE_NORMAL]) + g_object_unref (style->bg_pixmap[GTK_STATE_NORMAL]); + style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref (pixmap); + gtk_widget_set_style (widget, style); + g_object_unref (style); + + g_object_unref (pixmap); +} + +static void +panel_background_set_color_background_on_widget (PanelBackground *background, + GtkWidget *widget) +{ + const PanelColor *color; + + color = panel_background_get_color (background); + if (color->alpha != 0xffff) { + panel_background_set_image_background_on_widget (background, + widget); + return; + } + + gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color->gdk); +} + +void +panel_background_change_background_on_widget (PanelBackground *background, + GtkWidget *widget) +{ + PanelBackgroundType type; + + panel_background_set_no_background_on_widget (background, widget); + + type = panel_background_get_type (background); + + switch (type) { + case PANEL_BACK_NONE: + break; + case PANEL_BACK_COLOR: + panel_background_set_color_background_on_widget (background, + widget); + break; + case PANEL_BACK_IMAGE: + panel_background_set_image_background_on_widget (background, + widget); + break; + default: + g_assert_not_reached (); + break; + } +} diff --git a/mate-panel/panel-background.h b/mate-panel/panel-background.h new file mode 100644 index 00000000..a39ae4c3 --- /dev/null +++ b/mate-panel/panel-background.h @@ -0,0 +1,133 @@ +/* + * panel-background.h: panel background rendering + * + * Copyright (C) 2002, 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_BACKGROUND_H__ +#define __PANEL_BACKGROUND_H__ + +#include +#include + +#include "panel-enums.h" +#include "panel-types.h" +#include "panel-background-monitor.h" + +typedef struct _PanelBackground PanelBackground; + +typedef void (*PanelBackgroundChangedNotify) + (PanelBackground *background, + gpointer user_data); + +struct _PanelBackground { + PanelBackgroundType type; + + PanelBackgroundChangedNotify notify_changed; + gpointer user_data; + + PanelColor color; + char *image; + GdkPixbuf *loaded_image; + + GtkOrientation orientation; + GdkRectangle region; + GdkPixbuf *transformed_image; + GdkPixbuf *composited_image; + + PanelBackgroundMonitor *monitor; + GdkPixbuf *desktop; + gulong monitor_signal; + + GdkPixmap *pixmap; + GdkWindow *window; + GdkColormap *colormap; + GdkGC *gc; + + GdkPixmap *default_pixmap; + GdkColor default_color; + + guint fit_image : 1; + guint stretch_image : 1; + guint rotate_image : 1; + + guint has_alpha : 1; + + guint loaded : 1; + guint transformed : 1; + guint composited : 1; + guint prepared : 1; +}; + +void panel_background_init (PanelBackground *background, + PanelBackgroundChangedNotify notify_changed, + gpointer user_data); +void panel_background_free (PanelBackground *background); +void panel_background_set (PanelBackground *background, + PanelBackgroundType type, + PanelColor *color, + const char *image, + gboolean fit_image, + gboolean stretch_image, + gboolean rotate_image); +void panel_background_set_type (PanelBackground *background, + PanelBackgroundType type); +void panel_background_set_gdk_color (PanelBackground *background, + GdkColor *gdk_color); +void panel_background_set_opacity (PanelBackground *background, + guint16 opacity); +void panel_background_set_color (PanelBackground *background, + PanelColor *color); +void panel_background_set_image (PanelBackground *background, + const char *image); +void panel_background_set_fit (PanelBackground *background, + gboolean fit_image); +void panel_background_set_stretch (PanelBackground *background, + gboolean stretch_image); +void panel_background_set_rotate (PanelBackground *background, + gboolean rotate_image); +void panel_background_set_default_style (PanelBackground *background, + GdkColor *color, + GdkPixmap *pixmap); +void panel_background_realized (PanelBackground *background, + GdkWindow *window); +void panel_background_unrealized (PanelBackground *background); +void panel_background_change_region (PanelBackground *background, + GtkOrientation orientation, + int x, + int y, + int width, + int height); +char *panel_background_make_string (PanelBackground *background, + int x, + int y); + +PanelBackgroundType panel_background_get_type (PanelBackground *background); +const PanelColor *panel_background_get_color (PanelBackground *background); +const GdkPixmap *panel_background_get_pixmap (PanelBackground *background); + +PanelBackgroundType + panel_background_effective_type (PanelBackground *background); + +void panel_background_change_background_on_widget (PanelBackground *background, + GtkWidget *widget); + +#endif /* __PANEL_BACKGROUND_H__ */ diff --git a/mate-panel/panel-bindings.c b/mate-panel/panel-bindings.c new file mode 100644 index 00000000..5b580005 --- /dev/null +++ b/mate-panel/panel-bindings.c @@ -0,0 +1,303 @@ +/* + * panel-bindings.c: panel keybindings support module + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-bindings.h" + +#include +#include + +#include "panel-mateconf.h" +#include "panel-profile.h" +#include "panel-xutils.h" + +#define BINDINGS_PREFIX "/apps/marco/window_keybindings" +#define MOUSE_MODIFIER_DIR "/apps/marco/general" +#define MOUSE_MODIFIER_KEY "/apps/marco/general/mouse_button_modifier" +#define DEFAULT_MOUSE_MODIFIER GDK_MOD1_MASK + +typedef struct { + char *key; + char *signal; + guint keyval; + GdkModifierType modifiers; +} PanelBinding; + +static gboolean initialised = FALSE; + +static PanelBinding bindings [] = { + { "activate_window_menu", "popup-panel-menu", 0, 0 }, + { "toggle_maximized", "toggle-expand", 0, 0 }, + { "maximize", "expand", 0, 0 }, + { "unmaximize", "unexpand", 0, 0 }, + { "toggle_shaded", "toggle-hidden", 0, 0 }, + { "begin_move", "begin-move", 0, 0 }, + { "begin_resize", "begin-resize", 0, 0 }, +}; + +static guint mouse_button_modifier_keymask = DEFAULT_MOUSE_MODIFIER; + +static void +panel_binding_set_from_string (PanelBinding *binding, + const char *str) +{ + g_assert (binding->keyval == 0); + g_assert (binding->modifiers == 0); + + if (!str || !str [0] || !strcmp (str, "disabled")) { + binding->keyval = 0; + binding->modifiers = 0; + return; + } + + gtk_accelerator_parse (str, &binding->keyval, &binding->modifiers); + if (binding->keyval == 0 && binding->modifiers == 0) { + g_warning ("Unable to parse binding '%s'\n", str); + return; + } +} + +static inline GtkBindingSet * +get_binding_set (GtkBindingSet *binding_set) +{ + if (!binding_set) { + PanelToplevelClass *toplevel_class; + + toplevel_class = g_type_class_peek (PANEL_TYPE_TOPLEVEL); + if (!toplevel_class) + return NULL; + + g_assert (PANEL_IS_TOPLEVEL_CLASS (toplevel_class)); + + binding_set = gtk_binding_set_by_class (toplevel_class); + } + + return binding_set; +} + +static void +panel_binding_clear_entry (PanelBinding *binding, + GtkBindingSet *binding_set) +{ + binding_set = get_binding_set (binding_set); + + gtk_binding_entry_remove (binding_set, binding->keyval, binding->modifiers); +} + +static void +panel_binding_set_entry (PanelBinding *binding, + GtkBindingSet *binding_set) +{ + binding_set = get_binding_set (binding_set); + + gtk_binding_entry_add_signal (binding_set, + binding->keyval, + binding->modifiers, + binding->signal, + 0); +} + +static void +panel_binding_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelBinding *binding) +{ + MateConfValue *value; + + if (binding->keyval) + panel_binding_clear_entry (binding, NULL); + + binding->keyval = 0; + binding->modifiers = 0; + + value = mateconf_entry_get_value (entry); + + if (!value || value->type != MATECONF_VALUE_STRING) + return; + + panel_binding_set_from_string (binding, mateconf_value_get_string (value)); + + if (!binding->keyval) + return; + + panel_binding_set_entry (binding, NULL); +} + +static void +panel_binding_watch (PanelBinding *binding, + const char *key) +{ + GError *error = NULL; + + mateconf_client_notify_add (panel_mateconf_get_client (), key, + (MateConfClientNotifyFunc) panel_binding_changed, + binding, NULL, &error); + if (error) { + g_warning ("Error watching mateconf key '%s': %s", + key, error->message); + g_error_free (error); + } +} + +static void +panel_bindings_mouse_modifier_set_from_string (const char *str) +{ + guint modifier_keysym; + guint modifier_keymask; + + gtk_accelerator_parse (str, &modifier_keysym, &modifier_keymask); + + if (modifier_keysym == 0 && modifier_keymask == 0) { + g_warning ("Unable to parse mouse modifier '%s'\n", str); + return; + } + + if (modifier_keymask) + mouse_button_modifier_keymask = modifier_keymask; + else + mouse_button_modifier_keymask = DEFAULT_MOUSE_MODIFIER; +} + +static void +panel_bindings_mouse_modifier_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + const char *str; + + value = mateconf_entry_get_value (entry); + + if (!value || value->type != MATECONF_VALUE_STRING) + return; + + str = mateconf_value_get_string (value); + panel_bindings_mouse_modifier_set_from_string (str); +} + +static void +panel_bindings_initialise (void) +{ + MateConfClient *client; + GError *error; + int i; + char *str; + + if (initialised) + return; + + client = panel_mateconf_get_client (); + + error = NULL; + mateconf_client_add_dir (client, BINDINGS_PREFIX, + MATECONF_CLIENT_PRELOAD_ONELEVEL, &error); + if (error) { + g_warning ("Error loading mateconf directory '%s': %s", + BINDINGS_PREFIX, error->message), + g_error_free (error); + } + + for (i = 0; i < G_N_ELEMENTS (bindings); i++) { + const char *key; + + key = panel_mateconf_sprintf ("%s/%s", BINDINGS_PREFIX, bindings [i].key); + + error = NULL; + str = mateconf_client_get_string (client, key, &error); + if (error) { + g_warning ("Error getting value for '%s': %s", + key, error->message); + g_error_free (error); + continue; + } + + panel_binding_set_from_string (&bindings [i], str); + panel_binding_watch (&bindings [i], key); + + g_free (str); + } + + /* mouse button modifier */ + error = NULL; + mateconf_client_add_dir (client, MOUSE_MODIFIER_DIR, + MATECONF_CLIENT_PRELOAD_NONE, &error); + if (error) { + g_warning ("Error loading mateconf directory '%s': %s", + MOUSE_MODIFIER_DIR, error->message), + g_error_free (error); + } + + error = NULL; + mateconf_client_notify_add (client, MOUSE_MODIFIER_KEY, + panel_bindings_mouse_modifier_changed, + NULL, NULL, &error); + if (error) { + g_warning ("Error watching mateconf key '%s': %s", + MOUSE_MODIFIER_KEY, error->message); + g_error_free (error); + } + + error = NULL; + str = mateconf_client_get_string (client, MOUSE_MODIFIER_KEY, &error); + if (error) { + g_warning ("Error getting value for '%s': %s", + MOUSE_MODIFIER_KEY, error->message); + g_error_free (error); + } else { + panel_bindings_mouse_modifier_set_from_string (str); + g_free (str); + } + + initialised = TRUE; +} + +void +panel_bindings_set_entries (GtkBindingSet *binding_set) +{ + int i; + + if (!initialised) + panel_bindings_initialise (); + + for (i = 0; i < G_N_ELEMENTS (bindings); i++) { + if (!bindings [i].keyval) + continue; + + panel_binding_set_entry (&bindings [i], binding_set); + } +} + +guint +panel_bindings_get_mouse_button_modifier_keymask (void) +{ + g_assert (mouse_button_modifier_keymask != 0); + + if (!initialised) + panel_bindings_initialise (); + + return panel_get_real_modifier_mask (mouse_button_modifier_keymask); +} diff --git a/mate-panel/panel-bindings.h b/mate-panel/panel-bindings.h new file mode 100644 index 00000000..e9b2d850 --- /dev/null +++ b/mate-panel/panel-bindings.h @@ -0,0 +1,42 @@ +/* + * panel-bindings.h: panel keybindings support module + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_BINDINGS_H__ +#define __PANEL_BINDINGS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_bindings_set_entries (GtkBindingSet *binding_set); +guint panel_bindings_get_mouse_button_modifier_keymask (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_BINDINGS_H__ */ diff --git a/mate-panel/panel-compatibility.c b/mate-panel/panel-compatibility.c new file mode 100644 index 00000000..a746f695 --- /dev/null +++ b/mate-panel/panel-compatibility.c @@ -0,0 +1,1167 @@ +/* + * panel-compatibility.c: panel backwards compatibility support + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Mark McLoughlin + */ + +#include + +#include "string.h" + +#include + +#include "panel-compatibility.h" + +#include "panel-profile.h" +#include "panel-menu-bar.h" +#include "mate-panel-applet-frame.h" +#include "mate-panel-applets-manager.h" +#include "panel-globals.h" +#include "panel-util.h" + +typedef enum { + PANEL_ORIENT_UP, + PANEL_ORIENT_DOWN, + PANEL_ORIENT_LEFT, + PANEL_ORIENT_RIGHT, +} PanelOrient; + +static MateConfEnumStringPair panel_orient_map [] = { + { PANEL_ORIENT_UP, "panel-orient-up" }, + { PANEL_ORIENT_DOWN, "panel-orient-down" }, + { PANEL_ORIENT_LEFT, "panel-orient-left" }, + { PANEL_ORIENT_RIGHT, "panel-orient-right" }, + { 0, NULL } +}; + +static gboolean +panel_compatibility_map_orient_string (const char *str, + PanelOrient *orient) +{ + int mapped; + + g_return_val_if_fail (orient != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_orient_map, str, &mapped)) + return FALSE; + + *orient = mapped; + + return TRUE; +} + +static MateConfEnumStringPair panel_orientation_map [] = { + { GTK_ORIENTATION_HORIZONTAL, "panel-orientation-horizontal" }, + { GTK_ORIENTATION_VERTICAL, "panel-orientation-vertical" }, + { 0, NULL } +}; + + +static gboolean +panel_compatibility_map_orientation_string (const char *str, + GtkOrientation *orientation) +{ + int mapped; + + g_return_val_if_fail (orientation != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_orientation_map, str, &mapped)) + return FALSE; + + *orientation = mapped; + + return TRUE; +} + +typedef enum { + BORDER_TOP, + BORDER_RIGHT, + BORDER_BOTTOM, + BORDER_LEFT +} BorderEdge; + +static MateConfEnumStringPair panel_edge_map [] = { + { BORDER_TOP, "panel-edge-top" }, + { BORDER_RIGHT, "panel-edge-right" }, + { BORDER_BOTTOM, "panel-edge-bottom" }, + { BORDER_LEFT, "panel-edge-left" }, + { 0, NULL } +}; + +static gboolean +panel_compatibility_map_edge_string (const char *str, + BorderEdge *edge) +{ + int mapped; + + g_return_val_if_fail (edge != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_edge_map, str, &mapped)) + return FALSE; + + *edge = mapped; + + return TRUE; +} + +typedef enum { + EDGE_PANEL, + DRAWER_PANEL, + ALIGNED_PANEL, + SLIDING_PANEL, + FLOATING_PANEL, + MENU_PANEL +} PanelType; + +static MateConfEnumStringPair panel_type_map [] = { + { EDGE_PANEL, "edge-panel" }, + { DRAWER_PANEL, "drawer-panel" }, + { ALIGNED_PANEL, "aligned-panel" }, + { SLIDING_PANEL, "sliding-panel" }, + { FLOATING_PANEL, "floating-panel" }, + { MENU_PANEL, "menu-panel" }, + { 0, NULL } +}; + +static gboolean +panel_compatibility_map_panel_type_string (const char *str, + PanelType *type) +{ + int mapped; + + g_return_val_if_fail (type != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_type_map, str, &mapped)) + return FALSE; + + *type = mapped; + + return TRUE; +} + +enum { + PANEL_SIZE_XX_SMALL = 12, + PANEL_SIZE_X_SMALL = 24, + PANEL_SIZE_SMALL = 36, + PANEL_SIZE_MEDIUM = 48, + PANEL_SIZE_LARGE = 64, + PANEL_SIZE_X_LARGE = 80, + PANEL_SIZE_XX_LARGE = 128 +}; + +static MateConfEnumStringPair panel_size_map [] = { + { PANEL_SIZE_XX_SMALL, "panel-size-xx-small" }, + { PANEL_SIZE_X_SMALL, "panel-size-x-small" }, + { PANEL_SIZE_SMALL, "panel-size-small" }, + { PANEL_SIZE_MEDIUM, "panel-size-medium" }, + { PANEL_SIZE_LARGE, "panel-size-large" }, + { PANEL_SIZE_X_LARGE, "panel-size-x-large" }, + { PANEL_SIZE_XX_LARGE, "panel-size-xx-large" }, + { 0, NULL } +}; + +static gboolean +panel_compatibility_map_panel_size_string (const char *str, + int *size) +{ + int mapped; + + g_return_val_if_fail (size != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_size_map, str, &mapped)) + return FALSE; + + *size = mapped; + + return TRUE; +} + +static MateConfEnumStringPair panel_background_type_map [] = { + { PANEL_BACK_NONE, "no-background" }, + { PANEL_BACK_COLOR, "color-background" }, + { PANEL_BACK_IMAGE, "pixmap-background" }, + { 0, NULL } +}; + +static gboolean +panel_compatibility_map_background_type_string (const char *str, + PanelBackgroundType *type) +{ + int mapped; + + g_return_val_if_fail (type != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_background_type_map, str, &mapped)) + return FALSE; + + *type = mapped; + + return TRUE; +} + +static void +panel_compatibility_migrate_background_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + PanelBackgroundType type; + const char *key; + char *background_dir; + char *type_str; + char *color_str; + char *image_str; + gboolean fit; + gboolean stretch; + gboolean rotate; + int opacity; + + background_dir = mateconf_concat_dir_and_key (toplevel_dir, "background"); + + /* panel_background_type -> background/type */ + key = panel_mateconf_sprintf ("%s/panel_background_type", panel_dir); + type_str = mateconf_client_get_string (client, key, NULL); + + if (panel_compatibility_map_background_type_string (type_str, &type)) { + key = panel_mateconf_sprintf ("%s/type", background_dir); + mateconf_client_set_string (client, + key, + panel_profile_map_background_type (type), + NULL); + } + + g_free (type_str); + + /* panel_background_color -> background/color */ + key = panel_mateconf_sprintf ("%s/panel_background_color", panel_dir); + color_str = mateconf_client_get_string (client, key, NULL); + + if (color_str) { + key = panel_mateconf_sprintf ("%s/color", background_dir); + mateconf_client_set_string (client, key, color_str, NULL); + } + + g_free (color_str); + + /* panel_background_color_alpha -> background/opacity */ + key = panel_mateconf_sprintf ("%s/panel_background_color_alpha", panel_dir); + opacity = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/opacity", background_dir); + mateconf_client_set_int (client, key, opacity, NULL); + + /* panel_background_pixmap -> background/image */ + key = panel_mateconf_sprintf ("%s/panel_background_pixmap", panel_dir); + image_str = mateconf_client_get_string (client, key, NULL); + + if (image_str) { + key = panel_mateconf_sprintf ("%s/image", background_dir); + mateconf_client_set_string (client, key, image_str, NULL); + } + + g_free (image_str); + + /* panel_background_pixmap_fit -> background/fit */ + key = panel_mateconf_sprintf ("%s/panel_background_pixmap_fit", panel_dir); + fit = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/fit", background_dir); + mateconf_client_set_bool (client, key, fit, NULL); + + /* panel_background_pixmap_stretch -> background/stretch */ + key = panel_mateconf_sprintf ("%s/panel_background_pixmap_stretch", panel_dir); + stretch = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/stretch", background_dir); + mateconf_client_set_bool (client, key, stretch, NULL); + + /* panel_background_pixmap_rotate -> background/rotate */ + key = panel_mateconf_sprintf ("%s/panel_background_pixmap_rotate", panel_dir); + rotate = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/rotate", background_dir); + mateconf_client_set_bool (client, key, rotate, NULL); + + g_free (background_dir); +} + +static void +panel_compatibility_migrate_edge_setting (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + BorderEdge edge; + const char *key; + char *edge_str; + + key = panel_mateconf_sprintf ("%s/screen_edge", panel_dir); + edge_str = mateconf_client_get_string (client, key, NULL); + + if (panel_compatibility_map_edge_string (edge_str, &edge)) { + PanelOrientation orientation; + + switch (edge) { + case BORDER_TOP: + orientation = PANEL_ORIENTATION_TOP; + break; + case BORDER_BOTTOM: + orientation = PANEL_ORIENTATION_BOTTOM; + break; + case BORDER_LEFT: + orientation = PANEL_ORIENTATION_LEFT; + break; + case BORDER_RIGHT: + orientation = PANEL_ORIENTATION_RIGHT; + break; + default: + orientation = 0; + g_assert_not_reached (); + break; + } + + key = panel_mateconf_sprintf ("%s/orientation", toplevel_dir); + mateconf_client_set_string (client, + key, + panel_profile_map_orientation (orientation), + NULL); + } + + g_free (edge_str); +} + +static void +panel_compatibility_migrate_edge_panel_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + const char *key; + + key = panel_mateconf_sprintf ("%s/expand", toplevel_dir); + mateconf_client_set_bool (client, key, TRUE, NULL); + + panel_compatibility_migrate_edge_setting (client, toplevel_dir, panel_dir); +} + +static void +panel_compatibility_migrate_drawer_panel_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + PanelOrient orient; + const char *key; + char *orient_str; + + key = panel_mateconf_sprintf ("%s/expand", toplevel_dir); + mateconf_client_set_bool (client, key, FALSE, NULL); + + key = panel_mateconf_sprintf ("%s/panel_orient", panel_dir); + orient_str = mateconf_client_get_string (client, key, NULL); + + if (panel_compatibility_map_orient_string (orient_str, &orient)) { + PanelOrientation orientation; + + switch (orient) { + case PANEL_ORIENT_DOWN: + orientation = PANEL_ORIENTATION_TOP; + break; + case PANEL_ORIENT_UP: + orientation = PANEL_ORIENTATION_BOTTOM; + break; + case PANEL_ORIENT_RIGHT: + orientation = PANEL_ORIENTATION_LEFT; + break; + case PANEL_ORIENT_LEFT: + orientation = PANEL_ORIENTATION_RIGHT; + break; + default: + orientation = 0; + g_assert_not_reached (); + break; + } + + key = panel_mateconf_sprintf ("%s/orientation", toplevel_dir); + mateconf_client_set_string (client, + key, + panel_profile_map_orientation (orientation), + NULL); + } + + g_free (orient_str); +} + +static void +panel_compatibility_migrate_corner_panel_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) + +{ + const char *key; + + key = panel_mateconf_sprintf ("%s/expand", toplevel_dir); + mateconf_client_set_bool (client, key, FALSE, NULL); + + /* screen edge */ + panel_compatibility_migrate_edge_setting (client, toplevel_dir, panel_dir); + + g_warning ("FIXME: implement migrating the 'panel_align' setting"); +} + +static void +panel_compatibility_migrate_sliding_panel_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + const char *key; + + key = panel_mateconf_sprintf ("%s/expand", toplevel_dir); + mateconf_client_set_bool (client, key, FALSE, NULL); + + /* screen edge */ + panel_compatibility_migrate_edge_setting (client, toplevel_dir, panel_dir); + + g_warning ("FIXME: implement migrating the 'panel_anchor' and 'panel_offset' settings"); +} + +static void +panel_compatibility_migrate_floating_panel_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + GtkOrientation orientation; + const char *key; + char *orientation_str; + int x, y; + + key = panel_mateconf_sprintf ("%s/expand", toplevel_dir); + mateconf_client_set_bool (client, key, FALSE, NULL); + + key = panel_mateconf_sprintf ("%s/panel_orient", panel_dir); + orientation_str = mateconf_client_get_string (client, key, NULL); + + if (panel_compatibility_map_orientation_string (orientation_str, &orientation)) { + PanelOrientation panel_orientation; + + switch (orientation) { + case GTK_ORIENTATION_HORIZONTAL: + panel_orientation = PANEL_ORIENTATION_TOP; + break; + case GTK_ORIENTATION_VERTICAL: + panel_orientation = PANEL_ORIENTATION_LEFT; + break; + default: + panel_orientation = 0; + g_assert_not_reached (); + break; + } + + key = panel_mateconf_sprintf ("%s/orientation", toplevel_dir); + mateconf_client_set_string (client, + key, + panel_profile_map_orientation (panel_orientation), + NULL); + } + + g_free (orientation_str); + + /* x */ + key = panel_mateconf_sprintf ("%s/panel_x_position", panel_dir); + x = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/x", toplevel_dir); + mateconf_client_set_int (client, key, x, NULL); + + /* y */ + key = panel_mateconf_sprintf ("%s/panel_y_position", panel_dir); + y = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/y", toplevel_dir); + mateconf_client_set_int (client, key, y, NULL); +} + +static void +panel_compatibility_migrate_menu_panel_settings (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir) +{ + const char *key; + const char *toplevel_id; + char *id; + + key = panel_mateconf_sprintf ("%s/expand", toplevel_dir); + mateconf_client_set_bool (client, key, TRUE, NULL); + + key = panel_mateconf_sprintf ("%s/orientation", toplevel_dir); + mateconf_client_set_string (client, key, + panel_profile_map_orientation (PANEL_ORIENTATION_TOP), + NULL); + + toplevel_id = panel_mateconf_basename (toplevel_dir); + + /* menu bar on far right corner */ + id = panel_profile_prepare_object_with_id (PANEL_OBJECT_MENU_BAR, toplevel_id, 0, FALSE); + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + g_free (id); + + /* window menu on far left corner */ + id = panel_profile_prepare_object_with_id (PANEL_OBJECT_APPLET, toplevel_id, 0, TRUE); + + key = panel_mateconf_full_key (PANEL_MATECONF_APPLETS, id, "matecomponent_iid"); + mateconf_client_set_string (client, key, "OAFIID:MATE_WindowMenuApplet", NULL); + + panel_profile_add_to_list (PANEL_MATECONF_APPLETS, id); + g_free (id); +} + +static void +panel_compatibility_migrate_panel_type (MateConfClient *client, + const char *toplevel_dir, + const char *panel_dir, + gboolean *is_drawer) +{ + PanelType type; + const char *key; + char *type_str; + + key = panel_mateconf_sprintf ("%s/panel_type", panel_dir); + type_str = mateconf_client_get_string (client, key, NULL); + + if (!panel_compatibility_map_panel_type_string (type_str, &type)) { + g_free (type_str); + return; + } + + g_free (type_str); + + switch (type) { + case EDGE_PANEL: + panel_compatibility_migrate_edge_panel_settings (client, toplevel_dir, panel_dir); + break; + case DRAWER_PANEL: + panel_compatibility_migrate_drawer_panel_settings (client, toplevel_dir, panel_dir); + *is_drawer = TRUE; + break; + case ALIGNED_PANEL: + panel_compatibility_migrate_corner_panel_settings (client, toplevel_dir, panel_dir); + break; + case SLIDING_PANEL: + panel_compatibility_migrate_sliding_panel_settings (client, toplevel_dir, panel_dir); + break; + case FLOATING_PANEL: + panel_compatibility_migrate_floating_panel_settings (client, toplevel_dir, panel_dir); + break; + case MENU_PANEL: + panel_compatibility_migrate_menu_panel_settings (client, toplevel_dir, panel_dir); + break; + default: + g_assert_not_reached (); + break; + } +} + +static char * +panel_compatibility_migrate_panel_settings (MateConfClient *client, + GSList *toplevel_id_list, + const char *panel_id, + gboolean *is_drawer) +{ + const char *key; + char *toplevel_id; + char *toplevel_dir; + char *panel_dir; + char *size_str; + int screen; + int monitor; + int size; + gboolean enable_buttons; + gboolean enable_arrows; + gboolean auto_hide; + + toplevel_id = panel_profile_find_new_id (PANEL_MATECONF_TOPLEVELS); + + toplevel_dir = g_strdup_printf (PANEL_CONFIG_DIR "/toplevels/%s", toplevel_id); + panel_dir = g_strdup_printf (PANEL_CONFIG_DIR "/panels/%s", panel_id); + + panel_mateconf_associate_schemas_in_dir ( + client, toplevel_dir, PANEL_SCHEMAS_DIR "/toplevels"); + + /* screen */ + key = panel_mateconf_sprintf ("%s/screen", panel_dir); + screen = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/screen", toplevel_dir); + mateconf_client_set_int (client, key, screen, NULL); + + /* monitor */ + key = panel_mateconf_sprintf ("%s/monitor", panel_dir); + monitor = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/monitor", toplevel_dir); + mateconf_client_set_int (client, key, monitor, NULL); + + /* size */ + key = panel_mateconf_sprintf ("%s/panel_size", panel_dir); + size_str = mateconf_client_get_string (client, key, NULL); + + if (panel_compatibility_map_panel_size_string (size_str, &size)) { + key = panel_mateconf_sprintf ("%s/size", toplevel_dir); + mateconf_client_set_int (client, key, size, NULL); + } + + g_free (size_str); + + /* enable_buttons */ + key = panel_mateconf_sprintf ("%s/hide_buttons_enabled", panel_dir); + enable_buttons = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/enable_buttons", toplevel_dir); + mateconf_client_set_bool (client, key, enable_buttons, NULL); + + /* enable_arrows */ + key = panel_mateconf_sprintf ("%s/hide_button_pixmaps_enabled", panel_dir); + enable_arrows = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/enable_arrows", toplevel_dir); + mateconf_client_set_bool (client, key, enable_arrows, NULL); + + /* auto hide */ + key = panel_mateconf_sprintf ("%s/panel_hide_mode", panel_dir); + auto_hide = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/auto_hide", toplevel_dir); + mateconf_client_set_bool (client, key, auto_hide, NULL); + + /* migrate different panel types to toplevels */ + panel_compatibility_migrate_panel_type (client, toplevel_dir, panel_dir, is_drawer); + + /* background settings */ + panel_compatibility_migrate_background_settings (client, toplevel_dir, panel_dir); + + g_free (toplevel_dir); + g_free (panel_dir); + + return toplevel_id; +} + +static gboolean +panel_compatibility_migrate_panel_id (MateConfClient *client, + PanelMateConfKeyType key_type, + const char *object_id, + GHashTable *panel_id_hash) +{ + const char *key; + char *panel_id; + char *toplevel_id; + gboolean retval = FALSE; + + /* panel_id -> toplevel_id */ + key = panel_mateconf_full_key (key_type, object_id, "panel_id"); + panel_id = mateconf_client_get_string (client, key, NULL); + + if (panel_id && (toplevel_id = g_hash_table_lookup (panel_id_hash, panel_id))) { + key = panel_mateconf_full_key (key_type, object_id, "toplevel_id"); + mateconf_client_set_string (client, key, toplevel_id, NULL); + + retval = TRUE; + } + + g_free (panel_id); + + return retval; +} + +static void +panel_compatibility_migrate_drawer_settings (MateConfClient *client, + PanelMateConfKeyType key_type, + const char *object_id, + GHashTable *panel_id_hash) +{ + const char *key; + char *toplevel_id; + char *panel_id; + char *custom_icon; + char *pixmap; + + /* unique-drawer-panel-id -> attached_toplevel_id */ + key = panel_mateconf_full_key (key_type, object_id, "attached_toplevel_id"); + toplevel_id = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_full_key (key_type, object_id, "unique-drawer-panel-id"); + panel_id = mateconf_client_get_string (client, key, NULL); + + if (!toplevel_id && panel_id && + (toplevel_id = g_hash_table_lookup (panel_id_hash, panel_id))) { + key = panel_mateconf_full_key (key_type, object_id, "attached_toplevel_id"); + mateconf_client_set_string (client, key, toplevel_id, NULL); + + toplevel_id = NULL; + } + + /* pixmap -> custom_icon */ + key = panel_mateconf_full_key (key_type, object_id, "custom_icon"); + custom_icon = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_full_key (key_type, object_id, "pixmap"); + pixmap = mateconf_client_get_string (client, key, NULL); + + if (!custom_icon && pixmap) { + key = panel_mateconf_full_key (key_type, object_id, "custom_icon"); + mateconf_client_set_string (client, key, pixmap, NULL); + + key = panel_mateconf_full_key (key_type, object_id, "use_custom_icon"); + mateconf_client_set_bool (client, key, TRUE, NULL); + } + + g_free (toplevel_id); + g_free (panel_id); + g_free (custom_icon); + g_free (pixmap); +} + +static void +panel_compatibility_migrate_menu_button_settings (MateConfClient *client, + PanelMateConfKeyType key_type, + const char *object_id) +{ + const char *key; + gboolean use_custom_icon; + gboolean use_menu_path; + char *custom_icon; + char *menu_path; + + /* custom-icon -> use_custom_icon */ + key = panel_mateconf_full_key (key_type, object_id, "custom-icon"); + use_custom_icon = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_full_key (key_type, object_id, "use_custom_icon"); + mateconf_client_set_bool (client, key, use_custom_icon, NULL); + + /* custom-icon-file -> custom_icon */ + key = panel_mateconf_full_key (key_type, object_id, "custom-icon-file"); + custom_icon = mateconf_client_get_string (client, key, NULL); + + if (custom_icon) { + key = panel_mateconf_full_key (key_type, object_id, "custom_icon"); + mateconf_client_set_string (client, key, custom_icon, NULL); + } + + /* main_menu -> ! use_menu_path */ + key = panel_mateconf_full_key (key_type, object_id, "main-menu"); + use_menu_path = ! mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_full_key (key_type, object_id, "use_menu_path"); + mateconf_client_set_bool (client, key, use_menu_path, NULL); + + /* path -> menu_path */ + key = panel_mateconf_full_key (key_type, object_id, "path"); + menu_path = mateconf_client_get_string (client, key, NULL); + + if (menu_path) { + key = panel_mateconf_full_key (key_type, object_id, "menu_path"); + mateconf_client_set_string (client, key, menu_path, NULL); + } + + g_free (custom_icon); + g_free (menu_path); +} + +static void +panel_compatibility_migrate_objects (MateConfClient *client, + PanelMateConfKeyType key_type, + GHashTable *panel_id_hash) +{ + const char *key; + GSList *l, *objects; + + key = panel_mateconf_general_key (panel_mateconf_key_type_to_id_list (key_type)); + objects = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + for (l = objects; l; l = l->next) { + const char *id = l->data; + PanelObjectType object_type; + char *object_type_str; + + if (!panel_compatibility_migrate_panel_id (client, key_type, id, panel_id_hash)) { + g_free (l->data); + continue; + } + + key = panel_mateconf_full_key (key_type, id, "object_type"); + object_type_str = mateconf_client_get_string (client, key, NULL); + + if (panel_profile_map_object_type_string (object_type_str, &object_type)) { + switch (object_type) { + case PANEL_OBJECT_DRAWER: + panel_compatibility_migrate_drawer_settings ( + client, key_type, id, panel_id_hash); + break; + case PANEL_OBJECT_MENU: + panel_compatibility_migrate_menu_button_settings ( + client, key_type, id); + break; + default: + break; + } + } + g_free (object_type_str); + g_free (l->data); + } + g_slist_free (objects); +} + +/* Major hack, but we now set toplevel_id_list in the defaults database, + * so we need to figure out if its actually set in the users database. + */ + +static MateConfEngine * +get_homedir_source (void) +{ + MateConfEngine *engine; + GError *error = NULL; + char *source; + + source = g_strdup_printf ("xml:readwrite:%s/.mateconf", g_get_home_dir ()); + + if (!(engine = mateconf_engine_get_for_address (source, &error))) { +#if 0 + g_warning ("Cannot get MateConf source '%s': %s\n", + source, error->message); +#endif + g_error_free (error); + g_free (source); + return NULL; + } + + g_free (source); + + return engine; +} + +static gboolean +is_general_key_set (MateConfEngine *engine, + const char *config_dir, + const char *general_key) +{ + MateConfEntry *entry; + const char *key; + gboolean retval; + + key = panel_mateconf_sprintf ("%s/general/%s", config_dir, general_key); + + if (!(entry = mateconf_engine_get_entry (engine, key, NULL, FALSE, NULL))) + return FALSE; + + retval = mateconf_entry_get_value (entry) != NULL || + mateconf_entry_get_schema_name (entry) != NULL; + + mateconf_entry_unref (entry); + + return retval; +} + +static gboolean +panel_compatibility_detect_needs_migration (void) +{ + MateConfEngine *engine; + gboolean needs_migration = FALSE; + + if (!(engine = get_homedir_source ())) + return FALSE; + + if (!is_general_key_set (engine, PANEL_CONFIG_DIR, "panel_id_list")) + goto no_migration; + + if (is_general_key_set (engine, PANEL_CONFIG_DIR, "toplevel_id_list")) + goto no_migration; + + needs_migration = TRUE; + + no_migration: + mateconf_engine_unref (engine); + + return needs_migration; +} + +/* If toplevel_id_list is unset, migrate all the panels in + * panel_id_list to toplevels + */ +void +panel_compatibility_migrate_panel_id_list (MateConfClient *client) +{ + GHashTable *panel_id_hash; + const char *key; + GSList *panel_id_list; + GSList *toplevel_id_list = NULL; + GSList *l; + + if (!panel_compatibility_detect_needs_migration ()) + return; + + panel_id_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + key = panel_mateconf_general_key ("panel_id_list"); + panel_id_list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + for (l = panel_id_list; l; l = l->next) { + char *new_id; + gboolean is_drawer = FALSE; + + new_id = panel_compatibility_migrate_panel_settings (client, + toplevel_id_list, + l->data, + &is_drawer); + + /* Drawer toplevels don't belong on the toplevel list */ + if (!is_drawer) + toplevel_id_list = g_slist_prepend (toplevel_id_list, new_id); + + g_hash_table_insert (panel_id_hash, l->data, new_id); + } + + key = panel_mateconf_general_key ("toplevel_id_list"); + mateconf_client_set_list (client, key, MATECONF_VALUE_STRING, toplevel_id_list, NULL); + + g_slist_free (panel_id_list); + g_slist_free (toplevel_id_list); + + panel_compatibility_migrate_objects (client, PANEL_MATECONF_OBJECTS, panel_id_hash); + panel_compatibility_migrate_objects (client, PANEL_MATECONF_APPLETS, panel_id_hash); + + g_hash_table_destroy (panel_id_hash); +} + +static void +copy_mateconf_dir (MateConfClient *client, + const char *src_dir, + const char *dest_dir) +{ + GSList *list, *l; + + list = mateconf_client_all_entries (client, src_dir, NULL); + for (l = list; l; l = l->next) { + MateConfEntry *entry = l->data; + const char *key; + char *tmp; + + tmp = g_path_get_basename (mateconf_entry_get_key (entry)); + key = panel_mateconf_sprintf ("%s/%s", dest_dir, tmp); + g_free (tmp); + + if (mateconf_entry_get_schema_name (entry)) + mateconf_engine_associate_schema (client->engine, + key, + mateconf_entry_get_schema_name (entry), + NULL); + + if (entry->value) + mateconf_client_set (client, key, entry->value, NULL); + + mateconf_entry_unref (entry); + } + g_slist_free (list); + + list = mateconf_client_all_dirs (client, src_dir, NULL); + for (l = list; l; l = l->next) { + char *subdir = l->data; + char *src_subdir; + char *dest_subdir; + char *tmp; + + tmp = g_path_get_basename (subdir); + src_subdir = mateconf_concat_dir_and_key (src_dir, tmp); + dest_subdir = mateconf_concat_dir_and_key (dest_dir, tmp); + g_free (tmp); + + copy_mateconf_dir (client, src_subdir, dest_subdir); + + g_free (src_subdir); + g_free (dest_subdir); + g_free (subdir); + } + + g_slist_free (list); +} + +void +panel_compatibility_maybe_copy_old_config (MateConfClient *client) +{ + MateConfEngine *engine; + const char *key; + + key = panel_mateconf_general_key ("profiles_migrated"); + if (mateconf_client_get_bool (client, key, NULL)) + return; + + if (!(engine = get_homedir_source ())) + goto no_migration_needed;; + + if (!is_general_key_set (engine, PANEL_OLD_CONFIG_DIR, "panel_id_list") && + !is_general_key_set (engine, PANEL_OLD_CONFIG_DIR, "toplevel_id_list") && + !is_general_key_set (engine, PANEL_OLD_CONFIG_DIR, "applet_id_list") && + !is_general_key_set (engine, PANEL_OLD_CONFIG_DIR, "object_id_list")) + goto no_migration_needed; + + copy_mateconf_dir (client, PANEL_OLD_CONFIG_DIR, PANEL_CONFIG_DIR); + + key = panel_mateconf_general_key ("profiles_migrated"); + mateconf_client_set_bool (client, key, TRUE, NULL); + + no_migration_needed: + if (engine) + mateconf_engine_unref (engine); +} + +void +panel_compatibility_migrate_applications_scheme (MateConfClient *client, + const char *key) +{ + char *location; + + location = mateconf_client_get_string (client, key, NULL); + + if (!location) + return; + + if (!strncmp (location, "applications:", strlen ("applications:")) || + !strncmp (location, "applications-all-users:", strlen ("applications-all-users:")) || + !strncmp (location, "all-applications:", strlen ("all-applications:")) || + !strncmp (location, "preferences:", strlen ("preferences:")) || + !strncmp (location, "preferences-all-users:", strlen ("preferences-all-users:")) || + !strncmp (location, "all-preferences:", strlen ("all-preferences:")) || + !strncmp (location, "system-settings:", strlen ("system-settings:")) || + !strncmp (location, "server-settings:", strlen ("server-settings:"))) { + char *basename; + char *new_location; + + basename = g_path_get_basename (location); + new_location = panel_g_lookup_in_applications_dirs (basename); + g_free (basename); + + if (new_location != NULL) { + mateconf_client_set_string (client, key, + new_location, NULL); + g_free (new_location); + } + } + + g_free (location); +} + +void +panel_compatibility_migrate_screenshot_action (MateConfClient *client, + const char *id) +{ + const char *key; + + panel_profile_remove_from_list (PANEL_MATECONF_OBJECTS, id); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, + "launcher_location"); + mateconf_client_set_string (client, key, "mate-screenshot.desktop", NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, + "object_type"); + //FIXME: ideally, we would use panel_object_type_map, but it's private + //in panel-profile.c + mateconf_client_set_string (client, key, "launcher-object", NULL); + + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); +} + +gchar * +panel_compatibility_get_applet_iid (const gchar *id) +{ + MateConfClient *client = panel_mateconf_get_client (); + MatePanelAppletInfo *info; + const char *key; + gchar *applet_iid; + gboolean needs_migration; + const char *iid; + + /* + * There are two compatibility steps here: + * + * 1) we need to migrate from matecomponent_iid to applet_iid if there's no + * value in the applet_iid key. Always. + * + * 2) we need to try to migrate the iid to a new iid. We can't assume + * that the fact that the applet_iid key was used mean anything + * since the value there could well be a matecomponent iid. + * The reason we really have to try to migrate first is this case: + * if an applet was added with the matecomponent iid but gets ported later + * to dbus, then the reference to the matecomponent iid will only be valid + * as an old reference. + * And if migration fails, we just use the iid as it is. + */ + + needs_migration = FALSE; + + key = panel_mateconf_full_key (PANEL_MATECONF_APPLETS, id, "applet_iid"); + applet_iid = mateconf_client_get_string (client, key, NULL); + + if (!applet_iid || !applet_iid[0]) { + needs_migration = TRUE; + + key = panel_mateconf_full_key (PANEL_MATECONF_APPLETS, id, "matecomponent_iid"); + applet_iid = mateconf_client_get_string (client, key, NULL); + + if (!applet_iid || !applet_iid[0]) + return NULL; + } + + info = mate_panel_applets_manager_get_applet_info_from_old_id (applet_iid); + if (!info) + info = mate_panel_applets_manager_get_applet_info (applet_iid); + + if (!info) + return NULL; + + iid = mate_panel_applet_info_get_iid (info); + + /* migrate if the iid in the configuration is different than the real + * iid that will get used */ + if (!g_str_equal (iid, applet_iid)) + needs_migration = TRUE; + + g_free (applet_iid); + + if (needs_migration) { + key = panel_mateconf_full_key (PANEL_MATECONF_APPLETS, id, "applet_iid"); + mateconf_client_set_string (client, key, iid, NULL); + } + + return g_strdup (iid); +} diff --git a/mate-panel/panel-compatibility.h b/mate-panel/panel-compatibility.h new file mode 100644 index 00000000..4413fb95 --- /dev/null +++ b/mate-panel/panel-compatibility.h @@ -0,0 +1,48 @@ +/* + * panel-compatibility.h: panel backwards compatibility support + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_COMPATIBILITY_H__ +#define __PANEL_COMPATIBILITY_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_compatibility_migrate_panel_id_list (MateConfClient *client); +void panel_compatibility_maybe_copy_old_config (MateConfClient *client); +void panel_compatibility_migrate_applications_scheme (MateConfClient *client, + const char *key); +void panel_compatibility_migrate_screenshot_action (MateConfClient *client, + const char *id); + +gchar *panel_compatibility_get_applet_iid (const gchar *id); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_MENU_BAR_H__ */ diff --git a/mate-panel/panel-compatibility.schemas b/mate-panel/panel-compatibility.schemas new file mode 100644 index 00000000..ea4a7a68 --- /dev/null +++ b/mate-panel/panel-compatibility.schemas @@ -0,0 +1,546 @@ + + + + + + + + + /schemas/apps/panel/default_profiles/medium/general/panel_id_list + panel + list + string + [00000001,00000002] + + + + + /schemas/apps/panel/default_profiles/medium/general/applet_id_list + panel + list + string + [00000001,00000002,00000003,00000004,show_desktop_button] + + + + + /schemas/apps/panel/default_profiles/medium/general/object_id_list + panel + list + string + [00000001,00000002] + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_type + panel + string + edge-panel + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_size + panel + string + panel-size-x-small + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_hide_mode + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_hide_state + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/screen + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/monitor + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/screen_edge + panel + string + panel-edge-bottom + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/hide_buttons_enabled + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/hide_button_pixmaps_enabled + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_type + panel + string + no-background + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_pixmap + panel + string + + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_pixmap_fit + panel + bool + true + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_pixmap_stretch + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_pixmap_rotate + panel + bool + true + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_color + panel + string + #ffffff + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000001/panel_background_color_alpha + panel + int + 65535 + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000001/object_type + panel + string + launcher-object + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000001/launcher_location + panel + string + applications:///caja.desktop + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000001/panel_id + panel + string + 00000002 + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000001/position + panel + int + 20 + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000001/panel_right_stick + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000002/object_type + panel + string + launcher-object + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000002/launcher_location + panel + string + applications:///System/mate-terminal.desktop + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000002/panel_id + panel + string + 00000002 + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000002/position + panel + int + 25 + + + + + /schemas/apps/panel/default_profiles/medium/objects/00000002/panel_stick + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/applets/show_desktop_button/object_type + panel + string + matecomponent-applet + + + + + /schemas/apps/panel/default_profiles/medium/applets/show_desktop_button/panel_id + panel + string + 00000001 + + + + + /schemas/apps/panel/default_profiles/medium/applets/show_desktop_button/position + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/applets/show_desktop_button/matecomponent_iid + panel + string + OAFIID:MATE_ShowDesktopApplet + + + + + /schemas/apps/panel/default_profiles/medium/applets/show_desktop_button/panel_right_stick + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000001/object_type + panel + string + matecomponent-applet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000001/panel_id + panel + string + 00000001 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000001/position + panel + int + 1 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000001/matecomponent_iid + panel + string + OAFIID:MATE_TasklistApplet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000001/panel_right_stick + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000002/object_type + panel + string + matecomponent-applet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000002/panel_id + panel + string + 00000001 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000002/position + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000002/matecomponent_iid + panel + string + OAFIID:MATE_PagerApplet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000002/panel_right_stick + panel + bool + true + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000003/object_type + panel + string + matecomponent-applet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000003/panel_id + panel + string + 00000002 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000003/position + panel + int + -1 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000003/matecomponent_iid + panel + string + OAFIID:MATE_MixerApplet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000003/panel_right_stick + panel + bool + true + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000004/object_type + panel + string + matecomponent-applet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000004/panel_id + panel + string + 00000002 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000004/position + panel + int + -1 + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000004/matecomponent_iid + panel + string + OAFIID:MATE_ClockApplet + + + + + /schemas/apps/panel/default_profiles/medium/applets/00000004/panel_right_stick + panel + bool + true + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_type + panel + string + menu-panel + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_size + panel + string + panel-size-x-small + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/screen + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/monitor + panel + int + 0 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_background_type + panel + string + no-background + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_background_pixmap + panel + string + + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_background_pixmap_fit + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_background_pixmap_stretch + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_background_pixmap_rotate + panel + bool + false + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/panel_background_color + panel + string + #000000 + + + + + /schemas/apps/panel/default_profiles/medium/panels/00000002/clock_format + panel + string + %I:%M %p + + + + + + diff --git a/mate-panel/panel-config-global.c b/mate-panel/panel-config-global.c new file mode 100644 index 00000000..1ed3348a --- /dev/null +++ b/mate-panel/panel-config-global.c @@ -0,0 +1,153 @@ +/* + * panel-config-global.c: panel global configuration module + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * Glynn Foster + */ + +#include + +#include "panel-config-global.h" + +#include +#include + +#include "panel-globals.h" +#include "panel-mateconf.h" + +typedef struct { + guint tooltips_enabled : 1; + guint enable_animations : 1; + guint drawer_auto_close : 1; + guint confirm_panel_remove : 1; + guint highlight_when_over : 1; +} GlobalConfig; + +static GlobalConfig global_config = { 0, }; +static gboolean global_config_initialised = FALSE; + +gboolean +panel_global_config_get_highlight_when_over (void) +{ + g_assert (global_config_initialised == TRUE); + + return global_config.highlight_when_over; +} + +gboolean +panel_global_config_get_enable_animations (void) +{ + g_assert (global_config_initialised == TRUE); + + return global_config.enable_animations; +} + +gboolean +panel_global_config_get_drawer_auto_close (void) +{ + g_assert (global_config_initialised == TRUE); + + return global_config.drawer_auto_close; +} + +gboolean +panel_global_config_get_tooltips_enabled (void) +{ + g_assert (global_config_initialised == TRUE); + + return global_config.tooltips_enabled; +} + +gboolean +panel_global_config_get_confirm_panel_remove (void) +{ + g_assert (global_config_initialised == TRUE); + + return global_config.confirm_panel_remove; +} + +static void +panel_global_config_set_entry (MateConfEntry *entry) +{ + MateConfValue *value; + const char *key; + + g_return_if_fail (entry != NULL); + + value = mateconf_entry_get_value (entry); + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + + if (!value || !key) + return; + + if (strcmp (key, "tooltips_enabled") == 0) + global_config.tooltips_enabled = + mateconf_value_get_bool (value); + + else if (strcmp (key, "enable_animations") == 0) + global_config.enable_animations = + mateconf_value_get_bool (value); + + else if (strcmp (key, "drawer_autoclose") == 0) + global_config.drawer_auto_close = + mateconf_value_get_bool (value); + + else if (strcmp (key, "confirm_panel_remove") == 0) + global_config.confirm_panel_remove = + mateconf_value_get_bool (value); + + else if (strcmp (key, "highlight_launchers_on_mouseover") == 0) + global_config.highlight_when_over = + mateconf_value_get_bool (value); +} + +static void +panel_global_config_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + panel_global_config_set_entry (entry); +} + +void +panel_global_config_load (void) +{ + MateConfClient *client; + GSList *l, *entries; + const char *key = "/apps/panel/global"; + + client = panel_mateconf_get_client (); + + mateconf_client_add_dir (client, key, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + entries = mateconf_client_all_entries (client, key, NULL); + + for (l = entries; l; l = l->next) { + panel_global_config_set_entry (l->data); + mateconf_entry_unref (l->data); + } + g_slist_free (entries); + + mateconf_client_notify_add (client, key, panel_global_config_notify, NULL, NULL, NULL); + + global_config_initialised = TRUE; +} diff --git a/mate-panel/panel-config-global.h b/mate-panel/panel-config-global.h new file mode 100644 index 00000000..da3f1641 --- /dev/null +++ b/mate-panel/panel-config-global.h @@ -0,0 +1,47 @@ +/* + * panel-config-global.h: panel global configuration module + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * Glynn Foster + */ + +#ifndef __PANEL_CONFIG_GLOBAL_H__ +#define __PANEL_CONFIG_GLOBAL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_global_config_load (void); + +gboolean panel_global_config_get_highlight_when_over (void); +gboolean panel_global_config_get_enable_animations (void); +gboolean panel_global_config_get_drawer_auto_close (void); +gboolean panel_global_config_get_tooltips_enabled (void); +gboolean panel_global_config_get_confirm_panel_remove (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_CONFIG_GLOBAL_H__ */ diff --git a/mate-panel/panel-context-menu.c b/mate-panel/panel-context-menu.c new file mode 100644 index 00000000..a267a140 --- /dev/null +++ b/mate-panel/panel-context-menu.c @@ -0,0 +1,307 @@ +/* + * panel-context-menu.c: context menu for the panels + * + * Copyright (C) 2004 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Most of the original code come from menu.c + * + * Authors: + * Vincent Untz + * + */ + +#include + +#include "panel-context-menu.h" + +#include + +#include +#include + +#include +#include + +#include "nothing.h" +#include "panel-util.h" +#include "panel.h" +#include "menu.h" +#include "applet.h" +#include "panel-config-global.h" +#include "panel-profile.h" +#include "panel-properties-dialog.h" +#include "panel-lockdown.h" +#include "panel-addto.h" +#include "panel-icon-names.h" + +static void +panel_context_menu_show_help (GtkWidget *w, + gpointer data) +{ + panel_show_help (gtk_widget_get_screen (w), + "user-guide", "gospanel-1", NULL); +} + +static gboolean +panel_context_menu_check_for_screen (GtkWidget *w, + GdkEvent *ev, + gpointer data) +{ + static int times = 0; + if (ev->type != GDK_KEY_PRESS) + return FALSE; + if (ev->key.keyval == GDK_f || + ev->key.keyval == GDK_F) { + times++; + if (times == 3) { + times = 0; + start_screen_check (); + } + } + return FALSE; +} + +static void +panel_context_menu_show_about_dialog (GtkWidget *menuitem) +{ + static GtkWidget *about = NULL; + char *authors [] = { + "Alex Larsson ", + "Anders Carlsson ", + "Arvind Samptur ", + "Darin Adler ", + "Elliot Lee ", + "Federico Mena ", + "George Lebl ", + "Glynn Foster ", + "Ian Main ", + "Ian McKellar ", + "Jacob Berkman ", + "Mark McLoughlin ", + "Martin Baulig ", + "Miguel de Icaza ", + "Owen Taylor ", + "Padraig O'Briain ", + "Seth Nickell ", + "Stephen Browne ", + "Tom Tromey ", + "Vincent Untz ", + N_("And many, many others..."), + NULL + }; + char *documenters[] = { + "Alexander Kirillov ", + "Dan Mueth ", + "Dave Mason ", + NULL + }; + int i; + + if (about) { + gtk_window_set_screen (GTK_WINDOW (about), + menuitem_to_screen (menuitem)); + gtk_window_present (GTK_WINDOW (about)); + return; + } + + for (i = 0; authors [i]; i++) + authors [i] = _(authors [i]); + + /* Note: we don't use gtk_show_about_dialog() since some applets can + * be loaded in this process and we don't want to share the about + * dialog */ + about = gtk_about_dialog_new (); + g_object_set (about, + "program-name", _("The MATE Panel"), + "version", VERSION, + "copyright", "Copyright \xc2\xa9 1997-2003 Free Software Foundation, Inc.", + "comments", _("This program is responsible for launching other " + "applications and provides useful utilities."), + "authors", authors, + "documenters", documenters, + "title", _("About the MATE Panel"), + "translator-credits", _("translator-credits"), + "logo-icon-name", PANEL_ICON_PANEL, + NULL); + + gtk_window_set_screen (GTK_WINDOW (about), + menuitem_to_screen (menuitem)); + g_signal_connect (about, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &about); + g_signal_connect (about, "event", + G_CALLBACK (panel_context_menu_check_for_screen), + NULL); + + g_signal_connect (about, "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + gtk_widget_show (about); +} + +static void +panel_context_menu_create_new_panel (GtkWidget *menuitem) +{ + panel_profile_create_toplevel (gtk_widget_get_screen (menuitem)); +} + +static void +panel_context_menu_delete_panel (PanelToplevel *toplevel) +{ + if (panel_toplevel_is_last_unattached (toplevel)) { + panel_error_dialog (GTK_WINDOW (toplevel), + gtk_window_get_screen (GTK_WINDOW (toplevel)), + "cannot_delete_last_panel", TRUE, + _("Cannot delete this panel"), + _("You must always have at least one panel.")); + return; + } + + panel_delete (toplevel); +} + +static void +panel_context_menu_setup_delete_panel_item (GtkWidget *menu, + GtkWidget *menuitem) +{ + PanelWidget *panel_widget; + gboolean sensitive; + + panel_widget = menu_get_panel (menu); + + g_assert (PANEL_IS_TOPLEVEL (panel_widget->toplevel)); + + sensitive = + !panel_toplevel_is_last_unattached (panel_widget->toplevel) && + !panel_lockdown_get_locked_down () && + panel_profile_id_lists_are_writable (); + + gtk_widget_set_sensitive (menuitem, sensitive); +} + +static void +panel_context_menu_build_edition (PanelWidget *panel_widget, + GtkWidget *menu) +{ + GtkWidget *menuitem; + GtkWidget *image; + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Add to Panel...")); + image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect (G_OBJECT (menuitem), "activate", + G_CALLBACK (panel_addto_present), panel_widget); + + if (!panel_profile_id_lists_are_writable ()) + gtk_widget_set_sensitive (menuitem, FALSE); + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Properties")); + image = gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect_swapped (menuitem, "activate", + G_CALLBACK (panel_properties_dialog_present), + panel_widget->toplevel); + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Delete This Panel")); + image = gtk_image_new_from_stock (GTK_STOCK_DELETE, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect_swapped (G_OBJECT (menuitem), "activate", + G_CALLBACK (panel_context_menu_delete_panel), + panel_widget->toplevel); + g_signal_connect (G_OBJECT (menu), "show", + G_CALLBACK (panel_context_menu_setup_delete_panel_item), + menuitem); + + add_menu_separator (menu); + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_New Panel")); + image = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect (menuitem, "activate", + G_CALLBACK (panel_context_menu_create_new_panel), + NULL); + gtk_widget_set_sensitive (menuitem, + panel_profile_id_lists_are_writable ()); + + add_menu_separator (menu); +} + +GtkWidget * +panel_context_menu_create (PanelWidget *panel) +{ + GtkWidget *retval; + GtkWidget *menuitem; + GtkWidget *image; + + if (panel->master_widget) { + gpointer *pointer; + AppletInfo *info; + + pointer = g_object_get_data (G_OBJECT (panel->master_widget), + "applet_info"); + + g_assert (pointer != NULL); + info = (AppletInfo *) pointer; + + if (info->menu == NULL) { + info->menu = mate_panel_applet_create_menu (info); + } + + return info->menu; + } + + retval = create_empty_menu (); + gtk_widget_set_name (retval, "mate-panel-context-menu"); + + if (!panel_lockdown_get_locked_down ()) + panel_context_menu_build_edition (panel, retval); + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Help")); + image = gtk_image_new_from_stock (GTK_STOCK_HELP, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (retval), menuitem); + g_signal_connect (menuitem, "activate", + G_CALLBACK (panel_context_menu_show_help), NULL); + + menuitem = gtk_image_menu_item_new_with_mnemonic (_("A_bout Panels")); + image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (retval), menuitem); + g_signal_connect (menuitem, "activate", + G_CALLBACK (panel_context_menu_show_about_dialog), + NULL); + + //FIXME: can we get rid of this? (needed by menu_get_panel()) + g_object_set_data (G_OBJECT (retval), "menu_panel", panel); + + return retval; +} diff --git a/mate-panel/panel-context-menu.h b/mate-panel/panel-context-menu.h new file mode 100644 index 00000000..562e530c --- /dev/null +++ b/mate-panel/panel-context-menu.h @@ -0,0 +1,33 @@ +/* + * panel-context-menu.h: context menu for the panels + * + * Copyright (C) 2004 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + */ + +#ifndef __PANEL_CONTEXT_MENU_H__ +#define __PANEL_CONTEXT_MENU_H__ + +#include "panel-widget.h" + +GtkWidget *panel_context_menu_create (PanelWidget *panel); + +#endif /* __PANEL_CONTEXT_MENU_H__ */ diff --git a/mate-panel/panel-default-setup.entries b/mate-panel/panel-default-setup.entries new file mode 100644 index 00000000..aad2f5d5 --- /dev/null +++ b/mate-panel/panel-default-setup.entries @@ -0,0 +1,657 @@ + + + + + + + + general/toplevel_id_list + /schemas/apps/panel/general/toplevel_id_list + + + + top_panel + + + bottom_panel + + + + + + + + + general/object_id_list + /schemas/apps/panel/general/object_id_list + + + + menu_bar + + + browser_launcher + + + email_launcher + + + + + + + + + general/applet_id_list + /schemas/apps/panel/general/applet_id_list + + + + window_menu + + + clock + + + notification_area + + + show_desktop_button + + + window_list + + + workspace_switcher + + + + + + + + + toplevels/top_panel/expand + /schemas/apps/panel/toplevels/expand + + true + + + + toplevels/top_panel/orientation + /schemas/apps/panel/toplevels/orientation + + top + + + + toplevels/top_panel/size + /schemas/apps/panel/toplevels/size + + 24 + + + + toplevels/top_panel/name/schemas/apps/panel/toplevels/name + toplevels/top_panel/screen/schemas/apps/panel/toplevels/screen + toplevels/top_panel/monitor/schemas/apps/panel/toplevels/monitor + toplevels/top_panel/x/schemas/apps/panel/toplevels/x + toplevels/top_panel/y/schemas/apps/panel/toplevels/y + toplevels/top_panel/x_right/schemas/apps/panel/toplevels/x_right + toplevels/top_panel/y_bottom/schemas/apps/panel/toplevels/y_bottom + toplevels/top_panel/x_centered/schemas/apps/panel/toplevels/x_centered + toplevels/top_panel/y_centered/schemas/apps/panel/toplevels/y_centered + toplevels/top_panel/auto_hide/schemas/apps/panel/toplevels/auto_hide + toplevels/top_panel/enable_animations/schemas/apps/panel/toplevels/enable_animations + toplevels/top_panel/enable_buttons/schemas/apps/panel/toplevels/enable_buttons + toplevels/top_panel/enable_arrows/schemas/apps/panel/toplevels/enable_arrows + toplevels/top_panel/hide_delay/schemas/apps/panel/toplevels/hide_delay + toplevels/top_panel/unhide_delay/schemas/apps/panel/toplevels/unhide_delay + toplevels/top_panel/auto_hide_size/schemas/apps/panel/toplevels/auto_hide_size + toplevels/top_panel/animation_speed/schemas/apps/panel/toplevels/animation_speed + toplevels/top_panel/background/type/schemas/apps/panel/toplevels/background/type + toplevels/top_panel/background/color/schemas/apps/panel/toplevels/background/color + toplevels/top_panel/background/opacity/schemas/apps/panel/toplevels/background/opacity + toplevels/top_panel/background/image/schemas/apps/panel/toplevels/background/image + toplevels/top_panel/background/fit/schemas/apps/panel/toplevels/background/fit + toplevels/top_panel/background/stretch/schemas/apps/panel/toplevels/background/stretch + toplevels/top_panel/background/rotate/schemas/apps/panel/toplevels/background/rotate + + + + + toplevels/bottom_panel/expand + /schemas/apps/panel/toplevels/expand + + true + + + + toplevels/bottom_panel/orientation + /schemas/apps/panel/toplevels/orientation + + bottom + + + + toplevels/bottom_panel/size + /schemas/apps/panel/toplevels/size + + 24 + + + + toplevels/bottom_panel/y_bottom + /schemas/apps/panel/toplevels/y_bottom + + 0 + + + + toplevels/bottom_panel/name/schemas/apps/panel/toplevels/name + toplevels/bottom_panel/screen/schemas/apps/panel/toplevels/screen + toplevels/bottom_panel/monitor/schemas/apps/panel/toplevels/monitor + toplevels/bottom_panel/x/schemas/apps/panel/toplevels/x + toplevels/bottom_panel/y/schemas/apps/panel/toplevels/y + toplevels/bottom_panel/x_right/schemas/apps/panel/toplevels/x_right + toplevels/bottom_panel/x_centered/schemas/apps/panel/toplevels/x_centered + toplevels/bottom_panel/y_centered/schemas/apps/panel/toplevels/y_centered + toplevels/bottom_panel/auto_hide/schemas/apps/panel/toplevels/auto_hide + toplevels/bottom_panel/enable_animations/schemas/apps/panel/toplevels/enable_animations + toplevels/bottom_panel/enable_buttons/schemas/apps/panel/toplevels/enable_buttons + toplevels/bottom_panel/enable_arrows/schemas/apps/panel/toplevels/enable_arrows + toplevels/bottom_panel/hide_delay/schemas/apps/panel/toplevels/hide_delay + toplevels/bottom_panel/unhide_delay/schemas/apps/panel/toplevels/unhide_delay + toplevels/bottom_panel/auto_hide_size/schemas/apps/panel/toplevels/auto_hide_size + toplevels/bottom_panel/animation_speed/schemas/apps/panel/toplevels/animation_speed + toplevels/bottom_panel/background/type/schemas/apps/panel/toplevels/background/type + toplevels/bottom_panel/background/color/schemas/apps/panel/toplevels/background/color + toplevels/bottom_panel/background/opacity/schemas/apps/panel/toplevels/background/opacity + toplevels/bottom_panel/background/image/schemas/apps/panel/toplevels/background/image + toplevels/bottom_panel/background/fit/schemas/apps/panel/toplevels/background/fit + toplevels/bottom_panel/background/stretch/schemas/apps/panel/toplevels/background/stretch + toplevels/bottom_panel/background/rotate/schemas/apps/panel/toplevels/background/rotate + + + + + objects/menu_bar/object_type + /schemas/apps/panel/objects/object_type + + menu-bar + + + + objects/menu_bar/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + top_panel + + + + objects/menu_bar/position + /schemas/apps/panel/objects/position + + 0 + + + + objects/menu_bar/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + false + + + + objects/menu_bar/locked + /schemas/apps/panel/objects/locked + + true + + + + objects/menu_bar/applet_iid/schemas/apps/panel/objects/applet_iid + objects/menu_bar/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + objects/menu_bar/tooltip/schemas/apps/panel/objects/tooltip + objects/menu_bar/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + objects/menu_bar/custom_icon/schemas/apps/panel/objects/custom_icon + objects/menu_bar/use_menu_path/schemas/apps/panel/objects/use_menu_path + objects/menu_bar/menu_path/schemas/apps/panel/objects/menu_path + objects/menu_bar/launcher_location/schemas/apps/panel/objects/launcher_location + objects/menu_bar/action_type/schemas/apps/panel/objects/action_type + + + + + objects/browser_launcher/object_type + /schemas/apps/panel/objects/object_type + + launcher-object + + + + objects/browser_launcher/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + top_panel + + + + objects/browser_launcher/position + /schemas/apps/panel/objects/position + + 1 + + + + objects/browser_launcher/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + false + + + + objects/browser_launcher/locked + /schemas/apps/panel/objects/locked + + true + + + + objects/browser_launcher/launcher_location + /schemas/apps/panel/objects/launcher_location + + firefox.desktop + + + + objects/browser_launcher/applet_iid/schemas/apps/panel/objects/applet_iid + objects/browser_launcher/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + objects/browser_launcher/tooltip/schemas/apps/panel/objects/tooltip + objects/browser_launcher/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + objects/browser_launcher/custom_icon/schemas/apps/panel/objects/custom_icon + objects/browser_launcher/use_menu_path/schemas/apps/panel/objects/use_menu_path + objects/browser_launcher/menu_path/schemas/apps/panel/objects/menu_path + objects/browser_launcher/action_type/schemas/apps/panel/objects/action_type + + + + + objects/email_launcher/object_type + /schemas/apps/panel/objects/object_type + + launcher-object + + + + objects/email_launcher/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + top_panel + + + + objects/email_launcher/position + /schemas/apps/panel/objects/position + + 2 + + + + objects/email_launcher/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + false + + + + objects/email_launcher/locked + /schemas/apps/panel/objects/locked + + true + + + + objects/email_launcher/launcher_location + /schemas/apps/panel/objects/launcher_location + + thunderbird.desktop + + + + objects/email_launcher/applet_iid/schemas/apps/panel/objects/applet_iid + objects/email_launcher/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + objects/email_launcher/tooltip/schemas/apps/panel/objects/tooltip + objects/email_launcher/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + objects/email_launcher/custom_icon/schemas/apps/panel/objects/custom_icon + objects/email_launcher/use_menu_path/schemas/apps/panel/objects/use_menu_path + objects/email_launcher/menu_path/schemas/apps/panel/objects/menu_path + objects/email_launcher/action_type/schemas/apps/panel/objects/action_type + + + + + applets/window_menu/object_type + /schemas/apps/panel/objects/object_type + + matecomponent-applet + + + + applets/window_menu/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + top_panel + + + + applets/window_menu/position + /schemas/apps/panel/objects/position + + 0 + + + + applets/window_menu/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + true + + + + applets/window_menu/locked + /schemas/apps/panel/objects/locked + + true + + + + applets/window_menu/applet_iid + /schemas/apps/panel/objects/applet_iid + + WnckletFactory::WindowMenuApplet + + + + applets/window_menu/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + applets/window_menu/tooltip/schemas/apps/panel/objects/tooltip + applets/window_menu/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + applets/window_menu/custom_icon/schemas/apps/panel/objects/custom_icon + applets/window_menu/use_menu_path/schemas/apps/panel/objects/use_menu_path + applets/window_menu/menu_path/schemas/apps/panel/objects/menu_path + applets/window_menu/launcher_location/schemas/apps/panel/objects/launcher_location + applets/window_menu/action_type/schemas/apps/panel/objects/action_type + + + + + applets/clock/object_type + /schemas/apps/panel/objects/object_type + + matecomponent-applet + + + + applets/clock/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + top_panel + + + + applets/clock/position + /schemas/apps/panel/objects/position + + 2 + + + + applets/clock/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + true + + + + applets/clock/locked + /schemas/apps/panel/objects/locked + + true + + + + applets/clock/applet_iid + /schemas/apps/panel/objects/applet_iid + + ClockAppletFactory::ClockApplet + + + + applets/clock/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + applets/clock/tooltip/schemas/apps/panel/objects/tooltip + applets/clock/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + applets/clock/custom_icon/schemas/apps/panel/objects/custom_icon + applets/clock/use_menu_path/schemas/apps/panel/objects/use_menu_path + applets/clock/menu_path/schemas/apps/panel/objects/menu_path + applets/clock/launcher_location/schemas/apps/panel/objects/launcher_location + applets/clock/action_type/schemas/apps/panel/objects/action_type + + + + + applets/notification_area/object_type + /schemas/apps/panel/objects/object_type + + matecomponent-applet + + + + applets/notification_area/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + top_panel + + + + applets/notification_area/position + /schemas/apps/panel/objects/position + + 3 + + + + applets/notification_area/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + true + + + + applets/notification_area/locked + /schemas/apps/panel/objects/locked + + true + + + + applets/notification_area/applet_iid + /schemas/apps/panel/objects/applet_iid + + NotificationAreaAppletFactory::NotificationArea + + + + applets/notification_area/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + applets/notification_area/tooltip/schemas/apps/panel/objects/tooltip + applets/notification_area/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + applets/notification_area/custom_icon/schemas/apps/panel/objects/custom_icon + applets/notification_area/use_menu_path/schemas/apps/panel/objects/use_menu_path + applets/notification_area/menu_path/schemas/apps/panel/objects/menu_path + applets/notification_area/launcher_location/schemas/apps/panel/objects/launcher_location + applets/notification_area/action_type/schemas/apps/panel/objects/action_type + + + + + applets/show_desktop_button/object_type + /schemas/apps/panel/objects/object_type + + matecomponent-applet + + + + applets/show_desktop_button/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + bottom_panel + + + + applets/show_desktop_button/position + /schemas/apps/panel/objects/position + + 0 + + + + applets/show_desktop_button/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + false + + + + applets/show_desktop_button/locked + /schemas/apps/panel/objects/locked + + true + + + + applets/show_desktop_button/applet_iid + /schemas/apps/panel/objects/applet_iid + + WnckletFactory::ShowDesktopApplet + + + + applets/show_desktop_button/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + applets/show_desktop_button/tooltip/schemas/apps/panel/objects/tooltip + applets/show_desktop_button/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + applets/show_desktop_button/custom_icon/schemas/apps/panel/objects/custom_icon + applets/show_desktop_button/use_menu_path/schemas/apps/panel/objects/use_menu_path + applets/show_desktop_button/menu_path/schemas/apps/panel/objects/menu_path + applets/show_desktop_button/launcher_location/schemas/apps/panel/objects/launcher_location + applets/show_desktop_button/action_type/schemas/apps/panel/objects/action_type + + + + + applets/window_list/object_type + /schemas/apps/panel/objects/object_type + + matecomponent-applet + + + + applets/window_list/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + bottom_panel + + + + applets/window_list/position + /schemas/apps/panel/objects/position + + 1 + + + + applets/window_list/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + false + + + + applets/window_list/locked + /schemas/apps/panel/objects/locked + + true + + + + applets/window_list/applet_iid + /schemas/apps/panel/objects/applet_iid + + WnckletFactory::WindowListApplet + + + + applets/window_list/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + applets/window_list/tooltip/schemas/apps/panel/objects/tooltip + applets/window_list/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + applets/window_list/custom_icon/schemas/apps/panel/objects/custom_icon + applets/window_list/use_menu_path/schemas/apps/panel/objects/use_menu_path + applets/window_list/menu_path/schemas/apps/panel/objects/menu_path + applets/window_list/launcher_location/schemas/apps/panel/objects/launcher_location + applets/window_list/action_type/schemas/apps/panel/objects/action_type + + + + + applets/workspace_switcher/object_type + /schemas/apps/panel/objects/object_type + + matecomponent-applet + + + + applets/workspace_switcher/toplevel_id + /schemas/apps/panel/objects/toplevel_id + + bottom_panel + + + + applets/workspace_switcher/position + /schemas/apps/panel/objects/position + + 0 + + + + applets/workspace_switcher/panel_right_stick + /schemas/apps/panel/objects/panel_right_stick + + true + + + + applets/workspace_switcher/locked + /schemas/apps/panel/objects/locked + + true + + + + applets/workspace_switcher/applet_iid + /schemas/apps/panel/objects/applet_iid + + WnckletFactory::WorkspaceSwitcherApplet + + + + applets/workspace_switcher/attached_toplevel_id/schemas/apps/panel/objects/attached_toplevel_id + applets/workspace_switcher/tooltip/schemas/apps/panel/objects/tooltip + applets/workspace_switcher/use_custom_icon/schemas/apps/panel/objects/use_custom_icon + applets/workspace_switcher/custom_icon/schemas/apps/panel/objects/custom_icon + applets/workspace_switcher/use_menu_path/schemas/apps/panel/objects/use_menu_path + applets/workspace_switcher/menu_path/schemas/apps/panel/objects/menu_path + applets/workspace_switcher/launcher_location/schemas/apps/panel/objects/launcher_location + applets/workspace_switcher/action_type/schemas/apps/panel/objects/action_type + + + + diff --git a/mate-panel/panel-ditem-editor.c b/mate-panel/panel-ditem-editor.c new file mode 100644 index 00000000..e00f124e --- /dev/null +++ b/mate-panel/panel-ditem-editor.c @@ -0,0 +1,1804 @@ +/* + * panel-ditem-editor.c: + * + * Copyright (C) 2004, 2006 Vincent Untz + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "panel-ditem-editor.h" +#include "panel-icon-names.h" +#include "panel-util.h" +#include "panel-marshal.h" + +struct _PanelDItemEditorPrivate +{ + /* we keep a ditem around, since we can never have absolutely + everything in the display so we load a file, or get a ditem, + sync the display and ref the ditem */ + GKeyFile *key_file; + gboolean free_key_file; + /* the revert ditem will only contain relevant keys */ + GKeyFile *revert_key_file; + + gboolean reverting; + gboolean dirty; + guint save_timeout; + + char *uri; /* file location */ + gboolean type_directory; + gboolean new_file; + gboolean combo_setuped; + + PanelDitemSaveUri save_uri; + gpointer save_uri_data; + + GtkWidget *table; + GtkWidget *type_label; + GtkWidget *type_combo; + GtkWidget *name_label; + GtkWidget *name_entry; + GtkWidget *command_hbox; + GtkWidget *command_label; + GtkWidget *command_entry; + GtkWidget *command_browse_button; + GtkWidget *command_browse_filechooser; + GtkWidget *comment_label; + GtkWidget *comment_entry; + GtkWidget *icon_chooser; + + GtkWidget *help_button; + GtkWidget *revert_button; + GtkWidget *close_button; + GtkWidget *cancel_button; + GtkWidget *ok_button; +}; + +/* Time in seconds after which we save the file on the disk */ +#define SAVE_FREQUENCY 2 + +enum { + REVERT_BUTTON +}; + +typedef enum { + PANEL_DITEM_EDITOR_TYPE_NULL, + PANEL_DITEM_EDITOR_TYPE_APPLICATION, + PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION, + PANEL_DITEM_EDITOR_TYPE_LINK, + PANEL_DITEM_EDITOR_TYPE_DIRECTORY +} PanelDItemEditorType; + +enum { + COLUMN_TEXT, + COLUMN_TYPE, + NUMBER_COLUMNS +}; + +typedef struct { + const char *name; + const char *show_for; + PanelDItemEditorType type; +} ComboItem; + +static ComboItem type_items [] = { + { N_("Application"), "Application", + PANEL_DITEM_EDITOR_TYPE_APPLICATION }, + { N_("Application in Terminal"), "Application", + PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION }, + { N_("Location"), "Link", + PANEL_DITEM_EDITOR_TYPE_LINK }, + /* FIXME: hack hack hack: we will remove this item from the combo + * box if we show it */ + { NULL, "Directory", + PANEL_DITEM_EDITOR_TYPE_DIRECTORY } +}; + +typedef struct { + const char *key; + GType type; + gboolean default_value; + gboolean locale; +} RevertKey; + +static RevertKey revert_keys [] = { + { "Type", G_TYPE_STRING, FALSE, FALSE }, + { "Terminal", G_TYPE_BOOLEAN, FALSE, FALSE }, + { "Exec", G_TYPE_STRING, FALSE, FALSE }, + { "URL", G_TYPE_STRING, FALSE, FALSE }, + /* locale keys */ + { "Icon", G_TYPE_STRING, FALSE, TRUE }, + { "Name", G_TYPE_STRING, FALSE, TRUE }, + { "Comment", G_TYPE_STRING, FALSE, TRUE }, + { "X-MATE-FullName", G_TYPE_STRING, FALSE, TRUE }, + /* C version of those keys */ + { "Icon", G_TYPE_STRING, FALSE, FALSE }, + { "Name", G_TYPE_STRING, FALSE, FALSE }, + { "Comment", G_TYPE_STRING, FALSE, FALSE }, + { "X-MATE-FullName", G_TYPE_STRING, FALSE, FALSE } +}; + +enum { + SAVED, + CHANGED, + NAME_CHANGED, + COMMAND_CHANGED, + COMMENT_CHANGED, + ICON_CHANGED, + ERROR_REPORTED, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_KEYFILE, + PROP_URI, + PROP_TYPEDIRECTORY +}; + +static guint ditem_edit_signals[LAST_SIGNAL] = { 0 }; + +#define PANEL_DITEM_EDITOR_GET_PRIVATE(o) (PANEL_DITEM_EDITOR (o)->priv) + +G_DEFINE_TYPE (PanelDItemEditor, panel_ditem_editor, GTK_TYPE_DIALOG) + +static void panel_ditem_editor_setup_ui (PanelDItemEditor *dialog); + +static void type_combo_changed (PanelDItemEditor *dialog); + +static void response_cb (GtkDialog *dialog, + gint response_id); + +static void setup_icon_chooser (PanelDItemEditor *dialog, + const char *icon_name); + +static gboolean panel_ditem_editor_save (PanelDItemEditor *dialog, + gboolean report_errors); +static gboolean panel_ditem_editor_save_timeout (gpointer data); +static void panel_ditem_editor_revert (PanelDItemEditor *dialog); + +static void panel_ditem_editor_key_file_loaded (PanelDItemEditor *dialog); +static gboolean panel_ditem_editor_load_uri (PanelDItemEditor *dialog, + GError **error); + +static void panel_ditem_editor_set_key_file (PanelDItemEditor *dialog, + GKeyFile *key_file); + +static gboolean panel_ditem_editor_get_type_directory (PanelDItemEditor *dialog); +static void panel_ditem_editor_set_type_directory (PanelDItemEditor *dialog, + gboolean type_directory); + + +static PanelDItemEditorType +map_type_from_desktop_item (const char *type, + gboolean terminal) +{ + if (type == NULL) + return PANEL_DITEM_EDITOR_TYPE_NULL; + else if (!strcmp (type, "Application")) { + if (terminal) + return PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION; + else + return PANEL_DITEM_EDITOR_TYPE_APPLICATION; + } else if (!strcmp (type, "Link")) + return PANEL_DITEM_EDITOR_TYPE_LINK; + else if (!strcmp (type, "Directory")) + return PANEL_DITEM_EDITOR_TYPE_DIRECTORY; + else + return PANEL_DITEM_EDITOR_TYPE_NULL; +} + +static GObject * +panel_ditem_editor_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *obj; + PanelDItemEditor *dialog; + GFile *file; + gboolean loaded; + char *desktop_type; + + obj = G_OBJECT_CLASS (panel_ditem_editor_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + + dialog = PANEL_DITEM_EDITOR (obj); + + if (dialog->priv->key_file) { + panel_ditem_editor_key_file_loaded (dialog); + dialog->priv->new_file = FALSE; + dialog->priv->free_key_file = FALSE; + loaded = TRUE; + } else { + dialog->priv->key_file = panel_key_file_new_desktop (); + if (dialog->priv->type_directory) + panel_key_file_set_string (dialog->priv->key_file, + "Type", "Directory"); + dialog->priv->free_key_file = TRUE; + loaded = FALSE; + } + + if (!loaded && dialog->priv->uri) { + file = g_file_new_for_uri (dialog->priv->uri); + if (g_file_query_exists (file, NULL)) { + //FIXME what if there's an error? + panel_ditem_editor_load_uri (dialog, NULL); + dialog->priv->new_file = FALSE; + } else { + dialog->priv->new_file = TRUE; + } + g_object_unref (file); + } else { + dialog->priv->new_file = !loaded; + } + + dialog->priv->dirty = FALSE; + + desktop_type = panel_key_file_get_string (dialog->priv->key_file, + "Type"); + if (desktop_type && !strcmp (desktop_type, "Directory")) + dialog->priv->type_directory = TRUE; + g_free (desktop_type); + + panel_ditem_editor_setup_ui (dialog); + + if (dialog->priv->new_file) + setup_icon_chooser (dialog, NULL); + + return obj; +} + +static void +panel_ditem_editor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelDItemEditor *dialog; + + g_return_if_fail (PANEL_IS_DITEM_EDITOR (object)); + + dialog = PANEL_DITEM_EDITOR (object); + + switch (prop_id) { + case PROP_KEYFILE: + g_value_set_pointer (value, panel_ditem_editor_get_key_file (dialog)); + break; + case PROP_URI: + g_value_set_string (value, panel_ditem_editor_get_uri (dialog)); + break; + case PROP_TYPEDIRECTORY: + g_value_set_boolean (value, panel_ditem_editor_get_type_directory (dialog)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_ditem_editor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PanelDItemEditor *dialog; + + g_return_if_fail (PANEL_IS_DITEM_EDITOR (object)); + + dialog = PANEL_DITEM_EDITOR (object); + + switch (prop_id) { + case PROP_KEYFILE: + panel_ditem_editor_set_key_file (dialog, + g_value_get_pointer (value)); + break; + case PROP_URI: + panel_ditem_editor_set_uri (dialog, + g_value_get_string (value)); + break; + case PROP_TYPEDIRECTORY: + panel_ditem_editor_set_type_directory (dialog, + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_ditem_editor_destroy (GtkObject *object) +{ + PanelDItemEditor *dialog; + + dialog = PANEL_DITEM_EDITOR (object); + + /* If there was a timeout, then something changed after last save, + * so we must save again now */ + if (dialog->priv->save_timeout) { + g_source_remove (dialog->priv->save_timeout); + dialog->priv->save_timeout = 0; + panel_ditem_editor_save (dialog, FALSE); + } + + /* remember, destroy can be run multiple times! */ + + if (dialog->priv->free_key_file && dialog->priv->key_file != NULL) + g_key_file_free (dialog->priv->key_file); + dialog->priv->key_file = NULL; + + if (dialog->priv->revert_key_file != NULL) + g_key_file_free (dialog->priv->revert_key_file); + dialog->priv->revert_key_file = NULL; + + if (dialog->priv->uri != NULL) + g_free (dialog->priv->uri); + dialog->priv->uri = NULL; + + GTK_OBJECT_CLASS (panel_ditem_editor_parent_class)->destroy (object); +} + +static void +panel_ditem_editor_class_init (PanelDItemEditorClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (class); + + gobject_class->constructor = panel_ditem_editor_constructor; + gobject_class->get_property = panel_ditem_editor_get_property; + gobject_class->set_property = panel_ditem_editor_set_property; + + gtkobject_class->destroy = panel_ditem_editor_destroy; + + g_type_class_add_private (class, + sizeof (PanelDItemEditorPrivate)); + + ditem_edit_signals[SAVED] = + g_signal_new ("saved", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + ditem_edit_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + ditem_edit_signals[NAME_CHANGED] = + g_signal_new ("name_changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + name_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + ditem_edit_signals[COMMAND_CHANGED] = + g_signal_new ("command_changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + command_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + ditem_edit_signals[COMMENT_CHANGED] = + g_signal_new ("comment_changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + comment_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + ditem_edit_signals[ICON_CHANGED] = + g_signal_new ("icon_changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + icon_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + ditem_edit_signals[ERROR_REPORTED] = + g_signal_new ("error_reported", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelDItemEditorClass, + error_reported), + NULL, + NULL, + panel_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, G_TYPE_STRING); + + g_object_class_install_property ( + gobject_class, + PROP_KEYFILE, + g_param_spec_pointer ("keyfile", + "Key File", + "A key file containing the data from the .desktop file", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property ( + gobject_class, + PROP_URI, + g_param_spec_string ("uri", + "URI", + "The URI of the .desktop file", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_TYPEDIRECTORY, + g_param_spec_boolean ("type-directory", + "Type Directory", + "Whether the edited file is a .directory file or not", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static GtkWidget * +label_new_with_mnemonic (const char *text) +{ + GtkWidget *label; + char *bold; + + bold = g_strdup_printf ("%s", text); + label = gtk_label_new_with_mnemonic (bold); + g_free (bold); + + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + + gtk_widget_show (label); + + return label; +} + +static inline void +table_attach_label (GtkTable *table, + GtkWidget *label, + int left, + int right, + int top, + int bottom) +{ + gtk_table_attach (table, label, left, right, top, bottom, + GTK_FILL, GTK_FILL, + 0, 0); +} + +static inline void +table_attach_entry (GtkTable *table, + GtkWidget *entry, + int left, + int right, + int top, + int bottom) +{ + gtk_table_attach (table, entry, left, right, top, bottom, + GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, + 0, 0); +} + +static void +setup_combo (GtkWidget *combo_box, + ComboItem *items, + int nb_items, + const char *for_type) +{ + GtkListStore *model; + GtkTreeIter iter; + GtkCellRenderer *renderer; + int i; + + model = gtk_list_store_new (NUMBER_COLUMNS, + G_TYPE_STRING, + G_TYPE_INT); + + gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), + GTK_TREE_MODEL (model)); + + for (i = 0; i < nb_items; i++) { + if (for_type && strcmp (for_type, items [i].show_for)) + continue; + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_TEXT, _(items [i].name), + COLUMN_TYPE, items [i].type, + -1); + } + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), + renderer, "text", COLUMN_TEXT, NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0); +} + +static PanelDItemEditorType +panel_ditem_editor_get_item_type (PanelDItemEditor *dialog) +{ + GtkTreeIter iter; + GtkTreeModel *model; + PanelDItemEditorType type; + + if (dialog->priv->type_directory) + return PANEL_DITEM_EDITOR_TYPE_DIRECTORY; + + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->priv->type_combo), + &iter)) + return PANEL_DITEM_EDITOR_TYPE_NULL; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->type_combo)); + gtk_tree_model_get (model, &iter, COLUMN_TYPE, &type, -1); + + return type; +} + +static void +panel_ditem_editor_make_ui (PanelDItemEditor *dialog) +{ + PanelDItemEditorPrivate *priv; + GtkWidget *dialog_vbox; + + priv = dialog->priv; + + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + + dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + gtk_box_set_spacing (GTK_BOX (dialog_vbox), 2); + + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + + priv->table = gtk_table_new (4, 3, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (priv->table), 5); + gtk_table_set_row_spacings (GTK_TABLE (priv->table), 6); + gtk_table_set_col_spacings (GTK_TABLE (priv->table), 12); + gtk_box_pack_start (GTK_BOX (dialog_vbox), + priv->table, TRUE, TRUE, 0); + gtk_widget_show (priv->table); + + /* Type */ + priv->type_label = label_new_with_mnemonic (_("_Type:")); + priv->type_combo = gtk_combo_box_new (); + gtk_widget_show (priv->type_combo); + gtk_label_set_mnemonic_widget (GTK_LABEL (priv->type_label), + priv->type_combo); + + /* Name */ + priv->name_label = label_new_with_mnemonic (_("_Name:")); + priv->name_entry = gtk_entry_new (); + gtk_widget_show (priv->name_entry); + gtk_label_set_mnemonic_widget (GTK_LABEL (priv->name_label), + priv->name_entry); + + /* Icon */ + priv->icon_chooser = panel_icon_chooser_new (NULL); + panel_icon_chooser_set_fallback_icon_name (PANEL_ICON_CHOOSER (priv->icon_chooser), + PANEL_ICON_LAUNCHER); + gtk_table_attach (GTK_TABLE (priv->table), priv->icon_chooser, + 0, 1, 0, 2, + 0, 0, 0, 0); + gtk_widget_show (priv->icon_chooser); + + /* Command */ + priv->command_label = label_new_with_mnemonic (""); + + priv->command_hbox = gtk_hbox_new (FALSE, 12); + gtk_widget_show (priv->command_hbox); + + priv->command_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (priv->command_hbox), + priv->command_entry, + TRUE, TRUE, 0); + gtk_widget_show (priv->command_entry); + + priv->command_browse_button = gtk_button_new_with_mnemonic (_("_Browse...")); + gtk_box_pack_start (GTK_BOX (priv->command_hbox), + priv->command_browse_button, + FALSE, FALSE, 0); + gtk_widget_show (priv->command_browse_button); + + /* Comment */ + priv->comment_label = label_new_with_mnemonic (_("Co_mment:")); + priv->comment_entry = gtk_entry_new (); + gtk_widget_show (priv->comment_entry); + gtk_label_set_mnemonic_widget (GTK_LABEL (priv->comment_label), + priv->comment_entry); + + priv->help_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_HELP, + GTK_RESPONSE_HELP); + priv->revert_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_REVERT_TO_SAVED, + REVERT_BUTTON); + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + REVERT_BUTTON, + FALSE); + priv->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE); + priv->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + priv->ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + + /* FIXME: There needs to be a way to edit ALL keys/sections */ +} + +static void +panel_ditem_editor_setup_ui (PanelDItemEditor *dialog) +{ + PanelDItemEditorPrivate *priv; + PanelDItemEditorType type; + gboolean show_combo; + GList *focus_chain; + + priv = dialog->priv; + type = panel_ditem_editor_get_item_type (dialog); + + if (priv->new_file) { + gtk_widget_hide (priv->revert_button); + gtk_widget_hide (priv->close_button); + gtk_widget_show (priv->cancel_button); + gtk_widget_show (priv->ok_button); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_OK); + + if (!priv->combo_setuped) { + setup_combo (priv->type_combo, + type_items, G_N_ELEMENTS (type_items), + NULL); + priv->combo_setuped = TRUE; + } + + gtk_combo_box_set_active (GTK_COMBO_BOX (priv->type_combo), 0); + + show_combo = !priv->type_directory; + } else { + + gtk_widget_show (priv->revert_button); + gtk_widget_show (priv->close_button); + gtk_widget_hide (priv->cancel_button); + gtk_widget_hide (priv->ok_button); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_CLOSE); + + show_combo = (type != PANEL_DITEM_EDITOR_TYPE_LINK) && + (type != PANEL_DITEM_EDITOR_TYPE_DIRECTORY); + } + + if (show_combo) { + GtkTreeIter iter; + GtkTreeModel *model; + PanelDItemEditorType buf_type; + + table_attach_label (GTK_TABLE (priv->table), priv->type_label, + 1, 2, 0, 1); + table_attach_entry (GTK_TABLE (priv->table), priv->type_combo, + 2, 3, 0, 1); + + table_attach_label (GTK_TABLE (priv->table), priv->name_label, + 1, 2, 1, 2); + table_attach_entry (GTK_TABLE (priv->table), priv->name_entry, + 2, 3, 1, 2); + + table_attach_label (GTK_TABLE (priv->table), priv->command_label, + 1, 2, 2, 3); + table_attach_entry (GTK_TABLE (priv->table), priv->command_hbox, + 2, 3, 2, 3); + + table_attach_label (GTK_TABLE (priv->table), priv->comment_label, + 1, 2, 3, 4); + table_attach_entry (GTK_TABLE (priv->table), priv->comment_entry, + 2, 3, 3, 4); + + /* FIXME: hack hack hack */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->type_combo)); + if (!gtk_tree_model_get_iter_first (model, &iter)) + g_assert_not_reached (); + do { + gtk_tree_model_get (model, &iter, + COLUMN_TYPE, &buf_type, -1); + if (buf_type == PANEL_DITEM_EDITOR_TYPE_DIRECTORY) { + gtk_list_store_remove (GTK_LIST_STORE (model), + &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); + } else if (type == PANEL_DITEM_EDITOR_TYPE_DIRECTORY) { + table_attach_label (GTK_TABLE (priv->table), priv->name_label, + 1, 2, 0, 1); + table_attach_entry (GTK_TABLE (priv->table), priv->name_entry, + 2, 3, 0, 1); + + table_attach_label (GTK_TABLE (priv->table), priv->comment_label, + 1, 2, 1, 2); + table_attach_entry (GTK_TABLE (priv->table), priv->comment_entry, + 2, 3, 1, 2); + } else { + table_attach_label (GTK_TABLE (priv->table), priv->name_label, + 1, 2, 0, 1); + table_attach_entry (GTK_TABLE (priv->table), priv->name_entry, + 2, 3, 0, 1); + + table_attach_label (GTK_TABLE (priv->table), priv->command_label, + 1, 2, 1, 2); + table_attach_entry (GTK_TABLE (priv->table), priv->command_hbox, + 2, 3, 1, 2); + + table_attach_label (GTK_TABLE (priv->table), priv->comment_label, + 1, 2, 2, 3); + table_attach_entry (GTK_TABLE (priv->table), priv->comment_entry, + 2, 3, 2, 3); + } + + type_combo_changed (dialog); + + /* set a focus chain since GTK+ doesn't want to put the icon entry + * as the first widget in the chain */ + focus_chain = NULL; + focus_chain = g_list_prepend (focus_chain, priv->icon_chooser); + focus_chain = g_list_prepend (focus_chain, priv->type_combo); + focus_chain = g_list_prepend (focus_chain, priv->name_entry); + focus_chain = g_list_prepend (focus_chain, priv->command_hbox); + focus_chain = g_list_prepend (focus_chain, priv->comment_entry); + focus_chain = g_list_reverse (focus_chain); + gtk_container_set_focus_chain (GTK_CONTAINER (priv->table), + focus_chain); + g_list_free (focus_chain); + + gtk_widget_grab_focus (priv->name_entry); +} + +/* + * Will save after SAVE_FREQUENCY milliseconds of no changes. If something is + * changed, the save is postponed to another SAVE_FREQUENCY seconds. This seems + * to be a saner behaviour than just saving every N seconds. + */ +static void +panel_ditem_editor_changed (PanelDItemEditor *dialog) +{ + if (!dialog->priv->new_file) { + if (dialog->priv->save_timeout != 0) + g_source_remove (dialog->priv->save_timeout); + + dialog->priv->save_timeout = g_timeout_add_seconds ( + SAVE_FREQUENCY, + panel_ditem_editor_save_timeout, + dialog); + + /* We can revert to the original state */ + if (dialog->priv->revert_key_file != NULL) + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + REVERT_BUTTON, + TRUE); + } + + dialog->priv->dirty = TRUE; + g_signal_emit (G_OBJECT (dialog), ditem_edit_signals[CHANGED], 0); +} + +static void +panel_ditem_editor_activated (PanelDItemEditor *dialog) +{ + if (gtk_widget_get_visible (dialog->priv->ok_button)) + gtk_dialog_response (GTK_DIALOG (dialog), + GTK_RESPONSE_OK); + else if (gtk_widget_get_visible (dialog->priv->close_button)) + gtk_dialog_response (GTK_DIALOG (dialog), + GTK_RESPONSE_CLOSE); +} + +static void +panel_ditem_editor_name_changed (PanelDItemEditor *dialog) +{ + const char *name; + + name = gtk_entry_get_text (GTK_ENTRY (dialog->priv->name_entry)); + + if (!dialog->priv->reverting) { + /* When reverting, we don't need to set the content of the key + * file; we only want to send a signal. Changing the key file + * could actually break the revert since it might overwrite the + * old Name value with the X-MATE-FullName value */ + if (name && name[0]) + panel_key_file_set_locale_string (dialog->priv->key_file, + "Name", name); + else + panel_key_file_remove_all_locale_key (dialog->priv->key_file, + "Name"); + + panel_key_file_remove_all_locale_key (dialog->priv->key_file, + "X-MATE-FullName"); + } + + g_signal_emit (G_OBJECT (dialog), ditem_edit_signals[NAME_CHANGED], 0, + name); +} + +static void +panel_ditem_editor_command_changed (PanelDItemEditor *dialog) +{ + PanelDItemEditorType type; + const char *exec_or_uri; + GtkIconTheme *icon_theme; + char *icon; + + exec_or_uri = gtk_entry_get_text (GTK_ENTRY (dialog->priv->command_entry)); + + if (exec_or_uri && exec_or_uri[0]) + type = panel_ditem_editor_get_item_type (dialog); + else + type = PANEL_DITEM_EDITOR_TYPE_NULL; + + switch (type) { + case PANEL_DITEM_EDITOR_TYPE_APPLICATION: + case PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION: + panel_key_file_remove_key (dialog->priv->key_file, "URL"); + panel_key_file_set_string (dialog->priv->key_file, "Exec", + exec_or_uri); + + icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (dialog))); + icon = guess_icon_from_exec (icon_theme, + dialog->priv->key_file); + if (icon) { + char *current; + + current = panel_key_file_get_locale_string (dialog->priv->key_file, + "Icon"); + + if (!current || strcmp (icon, current)) + setup_icon_chooser (dialog, icon); + + g_free (current); + g_free (icon); + } + break; + case PANEL_DITEM_EDITOR_TYPE_LINK: + panel_key_file_remove_key (dialog->priv->key_file, "Exec"); + panel_key_file_set_string (dialog->priv->key_file, "URL", + exec_or_uri); + break; + default: + panel_key_file_remove_key (dialog->priv->key_file, "Exec"); + panel_key_file_remove_key (dialog->priv->key_file, "URL"); + } + + g_signal_emit (G_OBJECT (dialog), ditem_edit_signals[COMMAND_CHANGED], + 0, exec_or_uri); +} + +static void +panel_ditem_editor_comment_changed (PanelDItemEditor *dialog) +{ + const char *comment; + + comment = gtk_entry_get_text (GTK_ENTRY (dialog->priv->comment_entry)); + + if (comment && comment[0]) + panel_key_file_set_locale_string (dialog->priv->key_file, + "Comment", comment); + else + panel_key_file_remove_all_locale_key (dialog->priv->key_file, + "Comment"); + + g_signal_emit (G_OBJECT (dialog), ditem_edit_signals[COMMENT_CHANGED], + 0, comment); +} + +static void +panel_ditem_editor_icon_changed (PanelDItemEditor *dialog, + const char *icon) +{ + if (icon) + panel_key_file_set_locale_string (dialog->priv->key_file, + "Icon", icon); + else + panel_key_file_remove_all_locale_key (dialog->priv->key_file, + "Icon"); + + g_signal_emit (G_OBJECT (dialog), ditem_edit_signals[ICON_CHANGED], 0, + icon); +} + +static void +command_browse_chooser_response (GtkFileChooser *chooser, + gint response_id, + PanelDItemEditor *dialog) +{ + char *uri; + char *text; + + if (response_id == GTK_RESPONSE_ACCEPT) { + switch (panel_ditem_editor_get_item_type (dialog)) { + case PANEL_DITEM_EDITOR_TYPE_APPLICATION: + case PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION: + text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); + uri = panel_util_make_exec_uri_for_desktop (text); + g_free (text); + break; + case PANEL_DITEM_EDITOR_TYPE_LINK: + uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (chooser)); + break; + default: + g_assert_not_reached (); + } + + gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), + uri); + g_free (uri); + } + + gtk_widget_destroy (GTK_WIDGET (chooser)); + dialog->priv->command_browse_filechooser = NULL; +} + +static void +update_chooser_for_type (PanelDItemEditor *dialog) +{ + const char *title; + gboolean local_only; + GtkWidget *chooser; + + if (!dialog->priv->command_browse_filechooser) + return; + + switch (panel_ditem_editor_get_item_type (dialog)) { + case PANEL_DITEM_EDITOR_TYPE_APPLICATION: + case PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION: + title = _("Choose an application..."); + local_only = TRUE; + break; + case PANEL_DITEM_EDITOR_TYPE_LINK: + title = _("Choose a file..."); + local_only = FALSE; + break; + default: + g_assert_not_reached (); + } + + chooser = dialog->priv->command_browse_filechooser; + + gtk_window_set_title (GTK_WINDOW (chooser), + title); + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), + local_only); +} + +static void +command_browse_button_clicked (PanelDItemEditor *dialog) +{ + GtkWidget *chooser; + + if (dialog->priv->command_browse_filechooser) { + gtk_window_present (GTK_WINDOW (dialog->priv->command_browse_filechooser)); + return; + } + + chooser = gtk_file_chooser_dialog_new ("", GTK_WINDOW (dialog), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, + GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE); + + g_signal_connect (chooser, "response", + G_CALLBACK (command_browse_chooser_response), dialog); + + dialog->priv->command_browse_filechooser = chooser; + update_chooser_for_type (dialog); + + gtk_widget_show (chooser); +} + +static void +panel_ditem_editor_connect_signals (PanelDItemEditor *dialog) +{ + PanelDItemEditorPrivate *priv; + + priv = dialog->priv; + +#define CONNECT_CHANGED(widget, callback) \ + g_signal_connect_swapped (G_OBJECT (widget), "changed", \ + G_CALLBACK (callback), \ + dialog); \ + g_signal_connect_swapped (G_OBJECT (widget), "changed", \ + G_CALLBACK (panel_ditem_editor_changed), \ + dialog); + + CONNECT_CHANGED (priv->type_combo, type_combo_changed); + CONNECT_CHANGED (priv->name_entry, panel_ditem_editor_name_changed); + CONNECT_CHANGED (priv->command_entry, panel_ditem_editor_command_changed); + CONNECT_CHANGED (priv->comment_entry, panel_ditem_editor_comment_changed); + CONNECT_CHANGED (priv->icon_chooser, panel_ditem_editor_icon_changed); + + g_signal_connect_swapped (priv->name_entry, "activate", + G_CALLBACK (panel_ditem_editor_activated), + dialog); + g_signal_connect_swapped (priv->command_entry, "activate", + G_CALLBACK (panel_ditem_editor_activated), + dialog); + g_signal_connect_swapped (priv->comment_entry, "activate", + G_CALLBACK (panel_ditem_editor_activated), + dialog); + + g_signal_connect_swapped (priv->command_browse_button, "clicked", + G_CALLBACK (command_browse_button_clicked), + dialog); + + /* We do a signal connection here rather than overriding the method in + * class_init because GtkDialog::response is a RUN_LAST signal. We + * want *our* handler to be run *first*, regardless of whether the user + * installs response handlers of his own. + */ + g_signal_connect (dialog, "response", G_CALLBACK (response_cb), NULL); +} + +static void +panel_ditem_editor_block_signals (PanelDItemEditor *dialog) +{ + PanelDItemEditorPrivate *priv; + + priv = dialog->priv; + +#define BLOCK_CHANGED(widget, callback) \ + g_signal_handlers_block_by_func (G_OBJECT (widget), \ + G_CALLBACK (callback), \ + dialog); \ + g_signal_handlers_block_by_func (G_OBJECT (widget), \ + G_CALLBACK (panel_ditem_editor_changed), \ + dialog); + BLOCK_CHANGED (priv->type_combo, type_combo_changed); + BLOCK_CHANGED (priv->name_entry, panel_ditem_editor_name_changed); + BLOCK_CHANGED (priv->command_entry, panel_ditem_editor_command_changed); + BLOCK_CHANGED (priv->comment_entry, panel_ditem_editor_comment_changed); + BLOCK_CHANGED (priv->icon_chooser, panel_ditem_editor_icon_changed); +} + +static void +panel_ditem_editor_unblock_signals (PanelDItemEditor *dialog) +{ + PanelDItemEditorPrivate *priv; + + priv = dialog->priv; + +#define UNBLOCK_CHANGED(widget, callback) \ + g_signal_handlers_unblock_by_func (G_OBJECT (widget), \ + G_CALLBACK (callback), \ + dialog); \ + g_signal_handlers_unblock_by_func (G_OBJECT (widget), \ + G_CALLBACK (panel_ditem_editor_changed), \ + dialog); + UNBLOCK_CHANGED (priv->type_combo, type_combo_changed); + UNBLOCK_CHANGED (priv->name_entry, panel_ditem_editor_name_changed); + UNBLOCK_CHANGED (priv->command_entry, panel_ditem_editor_command_changed); + UNBLOCK_CHANGED (priv->comment_entry, panel_ditem_editor_comment_changed); + UNBLOCK_CHANGED (priv->icon_chooser, panel_ditem_editor_icon_changed); +} + +static void +panel_ditem_editor_init (PanelDItemEditor *dialog) +{ + PanelDItemEditorPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog, + PANEL_TYPE_DITEM_EDITOR, + PanelDItemEditorPrivate); + + dialog->priv = priv; + + priv->key_file = NULL; + priv->free_key_file = FALSE; + priv->revert_key_file = NULL; + priv->reverting = FALSE; + priv->dirty = FALSE; + priv->save_timeout = 0; + priv->uri = NULL; + priv->type_directory = FALSE; + priv->new_file = TRUE; + priv->save_uri = NULL; + priv->save_uri_data = NULL; + priv->combo_setuped = FALSE; + priv->command_browse_filechooser = NULL; + + panel_ditem_editor_make_ui (dialog); + panel_ditem_editor_connect_signals (dialog); +} + +static void +type_combo_changed (PanelDItemEditor *dialog) +{ + const char *text; + char *bold; + + switch (panel_ditem_editor_get_item_type (dialog)) { + case PANEL_DITEM_EDITOR_TYPE_APPLICATION: + text = _("Comm_and:"); + if (dialog->priv->combo_setuped) { + panel_key_file_set_string (dialog->priv->key_file, + "Type", "Application"); + panel_key_file_set_boolean (dialog->priv->key_file, + "Terminal", FALSE); + } + break; + case PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION: + text = _("Comm_and:"); + if (dialog->priv->combo_setuped) { + panel_key_file_set_string (dialog->priv->key_file, + "Type", "Application"); + panel_key_file_set_boolean (dialog->priv->key_file, + "Terminal", TRUE); + } + break; + case PANEL_DITEM_EDITOR_TYPE_LINK: + text = _("_Location:"); + if (dialog->priv->combo_setuped) { + panel_key_file_set_string (dialog->priv->key_file, + "Type", "Link"); + panel_key_file_remove_key (dialog->priv->key_file, + "Terminal"); + } + break; + case PANEL_DITEM_EDITOR_TYPE_DIRECTORY: + if (dialog->priv->combo_setuped) { + panel_key_file_set_string (dialog->priv->key_file, + "Type", "Directory"); + } + return; + default: + g_assert_not_reached (); + } + + bold = g_strdup_printf ("%s", text); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (dialog->priv->command_label), + bold); + g_free (bold); + + gtk_label_set_mnemonic_widget (GTK_LABEL (dialog->priv->command_label), + dialog->priv->command_entry); + + update_chooser_for_type (dialog); +} + +static void +setup_icon_chooser (PanelDItemEditor *dialog, + const char *icon_name) +{ + char *buffer; + + if (!icon_name || icon_name[0] == '\0') { + if (dialog->priv->type_directory) { + buffer = g_strdup (PANEL_ICON_FOLDER); + } else { + buffer = g_strdup (PANEL_ICON_LAUNCHER); + } + } else { + buffer = g_strdup (icon_name); + } + + panel_icon_chooser_set_icon (PANEL_ICON_CHOOSER (dialog->priv->icon_chooser), + buffer); + + g_free (buffer); +} + +/* Conform display to ditem */ +void +panel_ditem_editor_sync_display (PanelDItemEditor *dialog) +{ + char *type; + PanelDItemEditorType editor_type; + gboolean run_in_terminal; + GKeyFile *key_file; + char *buffer; + GtkTreeIter iter; + GtkTreeModel *model; + PanelDItemEditorType buf_type; + + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + key_file = dialog->priv->key_file; + + /* Name */ + buffer = panel_key_file_get_locale_string (key_file, "X-MATE-FullName"); + if (!buffer) + buffer = panel_key_file_get_locale_string (key_file, "Name"); + gtk_entry_set_text (GTK_ENTRY (dialog->priv->name_entry), + buffer ? buffer : ""); + g_free (buffer); + + /* Type */ + type = panel_key_file_get_string (key_file, "Type"); + if (!dialog->priv->combo_setuped) { + setup_combo (dialog->priv->type_combo, + type_items, G_N_ELEMENTS (type_items), + type); + dialog->priv->combo_setuped = TRUE; + } + + run_in_terminal = panel_key_file_get_boolean (key_file, "Terminal", + FALSE); + editor_type = map_type_from_desktop_item (type, run_in_terminal); + g_free (type); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->type_combo)); + if (!gtk_tree_model_get_iter_first (model, &iter)) + g_assert_not_reached (); + do { + gtk_tree_model_get (model, &iter, COLUMN_TYPE, &buf_type, -1); + if (editor_type == buf_type) { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->type_combo), + &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); + + g_assert (editor_type == buf_type || + editor_type == PANEL_DITEM_EDITOR_TYPE_NULL); + + /* Command */ + if (editor_type == PANEL_DITEM_EDITOR_TYPE_LINK) + buffer = panel_key_file_get_string (key_file, "URL"); + else if (editor_type == PANEL_DITEM_EDITOR_TYPE_APPLICATION || + editor_type == PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION) + buffer = panel_key_file_get_string (key_file, "Exec"); + else + buffer = NULL; + + gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), + buffer ? buffer : ""); + g_free (buffer); + + /* Comment */ + buffer = panel_key_file_get_locale_string (key_file, "Comment"); + gtk_entry_set_text (GTK_ENTRY (dialog->priv->comment_entry), + buffer ? buffer : ""); + g_free (buffer); + + + /* Icon */ + buffer = panel_key_file_get_locale_string (key_file, "Icon"); + setup_icon_chooser (dialog, buffer); + g_free (buffer); + + if (dialog->priv->save_timeout != 0) { + g_source_remove (dialog->priv->save_timeout); + dialog->priv->save_timeout = 0; + } +} + +static gboolean +panel_ditem_editor_save (PanelDItemEditor *dialog, + gboolean report_errors) +{ + GKeyFile *key_file; + const char *const_buf; + GError *error; + + g_return_val_if_fail (dialog != NULL, FALSE); + g_return_val_if_fail (dialog->priv->save_uri != NULL || + dialog->priv->uri != NULL, FALSE); + + if (dialog->priv->save_timeout != 0) + g_source_remove (dialog->priv->save_timeout); + dialog->priv->save_timeout = 0; + + if (!dialog->priv->dirty) + return TRUE; + + /* Verify that the required informations are set */ + const_buf = gtk_entry_get_text (GTK_ENTRY (dialog->priv->name_entry)); + if (const_buf == NULL || const_buf [0] == '\0') { + if (report_errors) { + if (!dialog->priv->type_directory) + g_signal_emit (G_OBJECT (dialog), + ditem_edit_signals[ERROR_REPORTED], 0, + _("Could not save launcher"), + _("The name of the launcher is not set.")); + else + g_signal_emit (G_OBJECT (dialog), + ditem_edit_signals[ERROR_REPORTED], 0, + _("Could not save directory properties"), + _("The name of the directory is not set.")); + } + return FALSE; + } + + const_buf = gtk_entry_get_text (GTK_ENTRY (dialog->priv->command_entry)); + if (!dialog->priv->type_directory && + (const_buf == NULL || const_buf [0] == '\0')) { + PanelDItemEditorType type; + char *err; + + type = panel_ditem_editor_get_item_type (dialog); + + switch (type) { + case PANEL_DITEM_EDITOR_TYPE_APPLICATION: + case PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION: + err = _("The command of the launcher is not set."); + break; + case PANEL_DITEM_EDITOR_TYPE_LINK: + err = _("The location of the launcher is not set."); + break; + default: + g_assert_not_reached (); + } + + if (report_errors) + g_signal_emit (G_OBJECT (dialog), + ditem_edit_signals[ERROR_REPORTED], 0, + _("Could not save launcher"), err); + return FALSE; + } + + key_file = dialog->priv->key_file; + + panel_key_file_ensure_C_key (key_file, "Name"); + panel_key_file_ensure_C_key (key_file, "Comment"); + panel_key_file_ensure_C_key (key_file, "Icon"); + + if (dialog->priv->save_uri) { + char *uri; + + uri = dialog->priv->save_uri (dialog, + dialog->priv->save_uri_data); + + if (uri) { + panel_ditem_editor_set_uri (dialog, uri); + g_free (uri); + } + } + + /* And now, try to save */ + error = NULL; + panel_key_file_to_file (dialog->priv->key_file, + dialog->priv->uri, + &error); + if (error != NULL) { + if (report_errors) + g_signal_emit (G_OBJECT (dialog), + ditem_edit_signals[ERROR_REPORTED], 0, + _("Could not save launcher"), + error->message); + g_error_free (error); + return FALSE; + } else { + g_signal_emit (G_OBJECT (dialog), + ditem_edit_signals[SAVED], 0); + } + + dialog->priv->dirty = FALSE; + + return TRUE; +} + +static gboolean +panel_ditem_editor_save_timeout (gpointer data) +{ + PanelDItemEditor *dialog; + + dialog = PANEL_DITEM_EDITOR (data); + panel_ditem_editor_save (dialog, FALSE); + + return FALSE; +} + +static void +response_cb (GtkDialog *dialog, + gint response_id) +{ + GError *error = NULL; + + switch (response_id) { + case GTK_RESPONSE_HELP: + if (!panel_show_help (gtk_window_get_screen (GTK_WINDOW (dialog)), + "user-guide", "gospanel-52", &error)) { + g_signal_emit (G_OBJECT (dialog), + ditem_edit_signals[ERROR_REPORTED], 0, + _("Could not display help document"), + error->message); + g_error_free (error); + } + break; + case REVERT_BUTTON: + panel_ditem_editor_revert (PANEL_DITEM_EDITOR (dialog)); + gtk_dialog_set_response_sensitive (dialog, + REVERT_BUTTON, + FALSE); + break; + case GTK_RESPONSE_OK: + case GTK_RESPONSE_CLOSE: + if (panel_ditem_editor_save (PANEL_DITEM_EDITOR (dialog), TRUE)) + gtk_widget_destroy (GTK_WIDGET (dialog)); + break; + case GTK_RESPONSE_DELETE_EVENT: + if (!PANEL_DITEM_EDITOR (dialog)->priv->new_file) + /* We need to revert the changes */ + gtk_dialog_response (dialog, REVERT_BUTTON); + gtk_widget_destroy (GTK_WIDGET (dialog)); + break; + case GTK_RESPONSE_CANCEL: + gtk_widget_destroy (GTK_WIDGET (dialog)); + break; + default: + g_assert_not_reached (); + } +} + +static void +panel_ditem_editor_revert (PanelDItemEditor *dialog) +{ + int i; + char *string; + gboolean boolean; + GKeyFile *key_file; + GKeyFile *revert_key_file; + + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + dialog->priv->reverting = TRUE; + + key_file = dialog->priv->key_file; + revert_key_file = dialog->priv->revert_key_file; + + g_assert (revert_key_file != NULL); + + for (i = 0; i < G_N_ELEMENTS (revert_keys); i++) { + if (revert_keys [i].type == G_TYPE_STRING) { + if (revert_keys [i].locale) { + string = panel_key_file_get_locale_string ( + revert_key_file, + revert_keys [i].key); + if (string == NULL) + panel_key_file_remove_all_locale_key ( + key_file, + revert_keys [i].key); + else + panel_key_file_set_locale_string ( + key_file, + revert_keys [i].key, + string); + } else { + string = panel_key_file_get_string ( + revert_key_file, + revert_keys [i].key); + if (string == NULL) + panel_key_file_remove_key ( + key_file, + revert_keys [i].key); + else + panel_key_file_set_string ( + key_file, + revert_keys [i].key, + string); + } + g_free (string); + } else if (revert_keys [i].type == G_TYPE_BOOLEAN) { + boolean = panel_key_file_get_boolean ( + revert_key_file, + revert_keys [i].key, + revert_keys [i].default_value); + panel_key_file_set_boolean (key_file, + revert_keys [i].key, + boolean); + } else { + g_assert_not_reached (); + } + } + + panel_ditem_editor_sync_display (dialog); + + if (!dialog->priv->new_file) { + if (dialog->priv->save_timeout != 0) + g_source_remove (dialog->priv->save_timeout); + + dialog->priv->save_timeout = g_timeout_add_seconds ( + SAVE_FREQUENCY, + panel_ditem_editor_save_timeout, + dialog); + } + + dialog->priv->reverting = FALSE; +} + +static void +panel_ditem_editor_set_revert (PanelDItemEditor *dialog) +{ + int i; + char *string; + gboolean boolean; + GKeyFile *key_file; + GKeyFile *revert_key_file; + + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + key_file = dialog->priv->key_file; + if (dialog->priv->revert_key_file) + g_key_file_free (dialog->priv->revert_key_file); + dialog->priv->revert_key_file = g_key_file_new (); + revert_key_file = dialog->priv->revert_key_file; + + for (i = 0; i < G_N_ELEMENTS (revert_keys); i++) { + if (revert_keys [i].type == G_TYPE_STRING) { + if (revert_keys [i].locale) { + string = panel_key_file_get_locale_string ( + key_file, + revert_keys [i].key); + if (string != NULL) + panel_key_file_set_locale_string ( + revert_key_file, + revert_keys [i].key, + string); + } else { + string = panel_key_file_get_string ( + key_file, + revert_keys [i].key); + if (string != NULL) + panel_key_file_set_string ( + revert_key_file, + revert_keys [i].key, + string); + } + g_free (string); + } else if (revert_keys [i].type == G_TYPE_BOOLEAN) { + boolean = panel_key_file_get_boolean ( + key_file, + revert_keys [i].key, + revert_keys [i].default_value); + panel_key_file_set_boolean (revert_key_file, + revert_keys [i].key, + boolean); + } else { + g_assert_not_reached (); + } + } +} + +static void +panel_ditem_editor_key_file_loaded (PanelDItemEditor *dialog) +{ + /* the user is not changing any value here, so block the signals about + * changing a value */ + panel_ditem_editor_block_signals (dialog); + panel_ditem_editor_sync_display (dialog); + panel_ditem_editor_unblock_signals (dialog); + + /* This should be after panel_ditem_editor_sync_display () + * so the revert button is insensitive */ + if (dialog->priv->revert_key_file != NULL) + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + REVERT_BUTTON, + TRUE); + else + panel_ditem_editor_set_revert (dialog); +} + +static gboolean +panel_ditem_editor_load_uri (PanelDItemEditor *dialog, + GError **error) +{ + GKeyFile *key_file; + + g_return_val_if_fail (PANEL_IS_DITEM_EDITOR (dialog), FALSE); + g_return_val_if_fail (dialog->priv->uri != NULL, FALSE); + + key_file = g_key_file_new (); + + if (!panel_key_file_load_from_uri (key_file, + dialog->priv->uri, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, + error)) { + g_key_file_free (key_file); + return FALSE; + } + + if (dialog->priv->free_key_file && dialog->priv->key_file) + g_key_file_free (dialog->priv->key_file); + dialog->priv->key_file = key_file; + + panel_ditem_editor_key_file_loaded (dialog); + + return TRUE; +} + +static GtkWidget * +panel_ditem_editor_new_full (GtkWindow *parent, + GKeyFile *key_file, + const char *uri, + const char *title, + gboolean type_directory) +{ + GtkWidget *dialog; + + dialog = g_object_new (PANEL_TYPE_DITEM_EDITOR, + "title", title, + "keyfile", key_file, + "uri", uri, + "type-directory", type_directory, + NULL); + + if (parent) + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + return dialog; +} + +GtkWidget * +panel_ditem_editor_new (GtkWindow *parent, + GKeyFile *key_file, + const char *uri, + const char *title) +{ + return panel_ditem_editor_new_full (parent, key_file, uri, + title, FALSE); +} + +GtkWidget * +panel_ditem_editor_new_directory (GtkWindow *parent, + GKeyFile *key_file, + const char *uri, + const char *title) +{ + return panel_ditem_editor_new_full (parent, key_file, uri, + title, TRUE); +} + +static void +panel_ditem_editor_set_key_file (PanelDItemEditor *dialog, + GKeyFile *key_file) +{ + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + if (dialog->priv->key_file == key_file) + return; + + if (dialog->priv->free_key_file && dialog->priv->key_file) + g_key_file_free (dialog->priv->key_file); + dialog->priv->key_file = key_file; + + g_object_notify (G_OBJECT (dialog), "keyfile"); +} + +void +panel_ditem_editor_set_uri (PanelDItemEditor *dialog, + const char *uri) +{ + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + if (!dialog->priv->uri && (!uri || !uri [0])) + return; + + if (dialog->priv->uri && uri && uri [0] && + !strcmp (dialog->priv->uri, uri)) + return; + + if (dialog->priv->uri) + g_free (dialog->priv->uri); + dialog->priv->uri = NULL; + + if (uri && uri [0]) + dialog->priv->uri = g_strdup (uri); + + g_object_notify (G_OBJECT (dialog), "uri"); +} + +static void +panel_ditem_editor_set_type_directory (PanelDItemEditor *dialog, + gboolean type_directory) +{ + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + if (dialog->priv->type_directory == type_directory) + return; + + dialog->priv->type_directory = type_directory; + + g_object_notify (G_OBJECT (dialog), "type-directory"); +} + +GKeyFile * +panel_ditem_editor_get_key_file (PanelDItemEditor *dialog) +{ + g_return_val_if_fail (PANEL_IS_DITEM_EDITOR (dialog), NULL); + + return dialog->priv->key_file; +} + +GKeyFile * +panel_ditem_editor_get_revert_key_file (PanelDItemEditor *dialog) +{ + g_return_val_if_fail (PANEL_IS_DITEM_EDITOR (dialog), NULL); + + return dialog->priv->revert_key_file; +} + +const char* panel_ditem_editor_get_uri(PanelDItemEditor* dialog) +{ + g_return_val_if_fail(PANEL_IS_DITEM_EDITOR(dialog), NULL); + + return dialog->priv->uri; +} + +static gboolean +panel_ditem_editor_get_type_directory (PanelDItemEditor *dialog) +{ + g_return_val_if_fail (PANEL_IS_DITEM_EDITOR (dialog), FALSE); + + return dialog->priv->type_directory; +} + +void +panel_ditem_register_save_uri_func (PanelDItemEditor *dialog, + PanelDitemSaveUri save_uri, + gpointer data) +{ + g_return_if_fail (PANEL_IS_DITEM_EDITOR (dialog)); + + dialog->priv->save_uri = save_uri; + dialog->priv->save_uri_data = data; +} diff --git a/mate-panel/panel-ditem-editor.h b/mate-panel/panel-ditem-editor.h new file mode 100644 index 00000000..32a34923 --- /dev/null +++ b/mate-panel/panel-ditem-editor.h @@ -0,0 +1,115 @@ +/* + * panel-ditem-editor.h: + * + * Copyright (C) 2004, 2006 Vincent Untz + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef PANEL_DITEM_EDITOR_H +#define PANEL_DITEM_EDITOR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_DITEM_EDITOR (panel_ditem_editor_get_type ()) +#define PANEL_DITEM_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_DITEM_EDITOR, PanelDItemEditor)) +#define PANEL_DITEM_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_DITEM_EDITOR, PanelDItemEditorClass)) +#define PANEL_IS_DITEM_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_DITEM_EDITOR)) +#define PANEL_IS_DITEM_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_DITEM_EDITOR)) +#define PANEL_DITEM_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_DITEM_EDITOR, PanelDItemEditorClass)) + +typedef struct _PanelDItemEditor PanelDItemEditor; +typedef struct _PanelDItemEditorClass PanelDItemEditorClass; + +typedef struct _PanelDItemEditorPrivate PanelDItemEditorPrivate; + +struct _PanelDItemEditorClass +{ + GtkDialogClass parent_class; + + /* File has been saved */ + void (* saved) (PanelDItemEditor *dialog); + + /* Any information changed */ + void (* changed) (PanelDItemEditor *dialog); + + /* These more specific signals are provided since they + * will likely require a display update */ + /* The name of the item has changed. */ + void (* name_changed) (PanelDItemEditor *dialog, + const char *name); + /* The command of the item has changed. */ + void (* command_changed) (PanelDItemEditor *dialog, + const char *command); + /* The comment of the item has changed. */ + void (* comment_changed) (PanelDItemEditor *dialog, + const char *comment); + /* The icon in particular has changed. */ + void (* icon_changed) (PanelDItemEditor *dialog, + const char *icon); + + /* An error is reported. */ + void (* error_reported) (PanelDItemEditor *dialog, + const char *error); +}; + +struct _PanelDItemEditor +{ + GtkDialog parent_instance; + + PanelDItemEditorPrivate *priv; +}; + +typedef char * (*PanelDitemSaveUri) (PanelDItemEditor *dialog, gpointer data); + +GType panel_ditem_editor_get_type (void); + +GtkWidget *panel_ditem_editor_new (GtkWindow *parent, + GKeyFile *key_file, + const char *uri, + const char *title); + +GtkWidget *panel_ditem_editor_new_directory (GtkWindow *parent, + GKeyFile *key_file, + const char *uri, + const char *title); + +void panel_ditem_editor_sync_display (PanelDItemEditor *dialog); + +GKeyFile *panel_ditem_editor_get_key_file (PanelDItemEditor *dialog); +GKeyFile *panel_ditem_editor_get_revert_key_file (PanelDItemEditor *dialog); + +void panel_ditem_editor_set_uri (PanelDItemEditor *dialog, + const char *uri); + +const char* panel_ditem_editor_get_uri(PanelDItemEditor* dialog); + +void panel_ditem_register_save_uri_func (PanelDItemEditor *dialog, + PanelDitemSaveUri save_uri, + gpointer data); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_DITEM_EDITOR_H */ diff --git a/mate-panel/panel-enums.h b/mate-panel/panel-enums.h new file mode 100644 index 00000000..b9418fbb --- /dev/null +++ b/mate-panel/panel-enums.h @@ -0,0 +1,110 @@ +/* + * panel-enums.h: + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_ENUMS_H__ +#define __PANEL_ENUMS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PANEL_ORIENTATION_TOP = 1 << 0, + PANEL_ORIENTATION_RIGHT = 1 << 1, + PANEL_ORIENTATION_BOTTOM = 1 << 2, + PANEL_ORIENTATION_LEFT = 1 << 3 +} PanelOrientation; + +#define PANEL_HORIZONTAL_MASK (PANEL_ORIENTATION_TOP | PANEL_ORIENTATION_BOTTOM) +#define PANEL_VERTICAL_MASK (PANEL_ORIENTATION_LEFT | PANEL_ORIENTATION_RIGHT) + +typedef enum { + PANEL_EDGE_NONE = 0, + PANEL_EDGE_TOP = 1 << 0, + PANEL_EDGE_BOTTOM = 1 << 1, + PANEL_EDGE_LEFT = 1 << 2, + PANEL_EDGE_RIGHT = 1 << 3 +} PanelFrameEdge; + +typedef enum { + PANEL_STATE_NORMAL = 0, + PANEL_STATE_AUTO_HIDDEN = 1, + PANEL_STATE_HIDDEN_UP = 2, + PANEL_STATE_HIDDEN_DOWN = 3, + PANEL_STATE_HIDDEN_LEFT = 4, + PANEL_STATE_HIDDEN_RIGHT = 5 +} PanelState; + +typedef enum { + PANEL_ANIMATION_SLOW = 0, + PANEL_ANIMATION_MEDIUM = 1, + PANEL_ANIMATION_FAST = 2 +} PanelAnimationSpeed; + +typedef enum { + PANEL_BACK_NONE = 0, + PANEL_BACK_COLOR = 1, + PANEL_BACK_IMAGE = 2 +} PanelBackgroundType; + +typedef enum { + PANEL_MATECONF_TOPLEVELS, + PANEL_MATECONF_OBJECTS, + PANEL_MATECONF_APPLETS +} PanelMateConfKeyType; + +typedef enum { + PANEL_OBJECT_DRAWER, + PANEL_OBJECT_MENU, + PANEL_OBJECT_LAUNCHER, + PANEL_OBJECT_APPLET, + PANEL_OBJECT_ACTION, + PANEL_OBJECT_MENU_BAR, + PANEL_OBJECT_SEPARATOR, + /* The following two are for backwards compatibility with 2.0.x */ + PANEL_OBJECT_LOGOUT, + PANEL_OBJECT_LOCK +} PanelObjectType; + +typedef enum { + PANEL_ACTION_NONE = 0, + PANEL_ACTION_LOCK, + PANEL_ACTION_LOGOUT, + PANEL_ACTION_RUN, + PANEL_ACTION_SEARCH, + PANEL_ACTION_FORCE_QUIT, + PANEL_ACTION_CONNECT_SERVER, + PANEL_ACTION_SHUTDOWN, + /* compatibility with MATE < 2.13.90 */ + PANEL_ACTION_SCREENSHOT, + PANEL_ACTION_LAST +} PanelActionButtonType; + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_ENUMS_H__ */ diff --git a/mate-panel/panel-force-quit.c b/mate-panel/panel-force-quit.c new file mode 100644 index 00000000..fabad1ac --- /dev/null +++ b/mate-panel/panel-force-quit.c @@ -0,0 +1,316 @@ +/* + * panel-force-quit.c: + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-force-quit.h" + +#include +#include +#include +#include +#include + +#include "panel-icon-names.h" +#include "panel-stock-icons.h" + +static GdkFilterReturn popup_filter (GdkXEvent *gdk_xevent, + GdkEvent *event, + GtkWidget *popup); + +static Atom wm_state_atom = None; + +static GtkWidget * +display_popup_window (GdkScreen *screen) +{ + GtkWidget *retval; + GtkWidget *vbox; + GtkWidget *image; + GtkWidget *frame; + GtkWidget *label; + int screen_width, screen_height; + GtkAllocation allocation; + + retval = gtk_window_new (GTK_WINDOW_POPUP); + atk_object_set_role (gtk_widget_get_accessible (retval), ATK_ROLE_ALERT); + gtk_window_set_screen (GTK_WINDOW (retval), screen); + gtk_window_stick (GTK_WINDOW (retval)); + gtk_widget_add_events (retval, GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_add (GTK_CONTAINER (retval), frame); + gtk_widget_show (frame); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + + image = gtk_image_new_from_icon_name (PANEL_ICON_FORCE_QUIT, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), image, TRUE, TRUE, 4); + gtk_widget_show (image); + + label = gtk_label_new (_("Click on a window to force the application to quit. " + "To cancel press .")); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 4); + gtk_widget_show (label); + + gtk_widget_realize (retval); + + screen_width = gdk_screen_get_width (screen); + screen_height = gdk_screen_get_height (screen); + + gtk_widget_get_allocation (retval, &allocation); + + gtk_window_move (GTK_WINDOW (retval), + (screen_width - allocation.width) / 2, + (screen_height - allocation.height) / 2); + + gtk_widget_show (GTK_WIDGET (retval)); + + return retval; +} + +static void +remove_popup (GtkWidget *popup) +{ + GdkWindow *root; + + root = gdk_screen_get_root_window ( + gtk_window_get_screen (GTK_WINDOW (popup))); + gdk_window_remove_filter (root, (GdkFilterFunc) popup_filter, popup); + + gtk_widget_destroy (popup); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); +} + +static gboolean +wm_state_set (Display *display, + Window window) +{ + gulong nitems; + gulong bytes_after; + gulong *prop; + Atom ret_type = None; + int ret_format; + int result; + + gdk_error_trap_push (); + result = XGetWindowProperty (display, window, wm_state_atom, + 0, G_MAXLONG, False, wm_state_atom, + &ret_type, &ret_format, &nitems, + &bytes_after, (gpointer) &prop); + + if (gdk_error_trap_pop ()) + return FALSE; + + if (result != Success) + return FALSE; + + XFree (prop); + + if (ret_type != wm_state_atom) + return FALSE; + + return TRUE; +} + +static Window +find_managed_window (Display *display, + Window window) +{ + Window root; + Window parent; + Window *kids = NULL; + Window retval; + guint nkids; + int i, result; + + if (wm_state_set (display, window)) + return window; + + gdk_error_trap_push (); + result = XQueryTree (display, window, &root, &parent, &kids, &nkids); + if (gdk_error_trap_pop () || !result) + return None; + + retval = None; + + for (i = 0; i < nkids; i++) { + if (wm_state_set (display, kids [i])) { + retval = kids [i]; + break; + } + + retval = find_managed_window (display, kids [i]); + if (retval != None) + break; + } + + if (kids) + XFree (kids); + + return retval; +} + +static void +kill_window_response (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + if (response_id == GTK_RESPONSE_ACCEPT) { + Display *display; + Window window = (Window) user_data; + + display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (dialog))); + + gdk_error_trap_push (); + XKillClient (display, window); + gdk_flush (); + gdk_error_trap_pop (); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +/* From marco */ +static void +kill_window_question (gpointer window) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, 0, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + _("Force this application to exit?")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("If you choose to force an application " + "to exit, unsaved changes in any open documents " + "in it might get lost.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + PANEL_STOCK_FORCE_QUIT, + GTK_RESPONSE_ACCEPT, + NULL); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_CANCEL); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Force Quit")); + + g_signal_connect (dialog, "response", + G_CALLBACK (kill_window_response), window); + + gtk_widget_show (dialog); +} + +static void +handle_button_press_event (GtkWidget *popup, + XKeyEvent *event) +{ + Window window; + + remove_popup (popup); + + if (event->subwindow == None) + return; + + if (wm_state_atom == None) + wm_state_atom = XInternAtom (event->display, "WM_STATE", FALSE); + + window = find_managed_window (event->display, event->subwindow); + + if (window != None) { + if (!gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (event->display), window)) + kill_window_question ((gpointer) window); + } +} + +static GdkFilterReturn +popup_filter (GdkXEvent *gdk_xevent, + GdkEvent *event, + GtkWidget *popup) +{ + XEvent *xevent = (XEvent *) gdk_xevent; + + switch (xevent->type) { + case ButtonPress: + handle_button_press_event (popup, &xevent->xkey); + return GDK_FILTER_REMOVE; + case KeyPress: + if (xevent->xkey.keycode == XKeysymToKeycode (xevent->xany.display, XK_Escape)) { + remove_popup (popup); + return GDK_FILTER_REMOVE; + } + break; + default: + break; + } + + return GDK_FILTER_CONTINUE; +} + +void +panel_force_quit (GdkScreen *screen, + guint time) +{ + GdkGrabStatus status; + GdkCursor *cross; + GtkWidget *popup; + GdkWindow *root; + + popup = display_popup_window (screen); + + root = gdk_screen_get_root_window (screen); + + gdk_window_add_filter (root, (GdkFilterFunc) popup_filter, popup); + + cross = gdk_cursor_new (GDK_CROSS); + status = gdk_pointer_grab (root, FALSE, GDK_BUTTON_PRESS_MASK, + NULL, cross, time); + gdk_cursor_unref (cross); + if (status != GDK_GRAB_SUCCESS) { + g_warning ("Pointer grab failed\n"); + remove_popup (popup); + return; + } + + status = gdk_keyboard_grab (root, FALSE, time); + if (status != GDK_GRAB_SUCCESS) { + g_warning ("Keyboard grab failed\n"); + remove_popup (popup); + return; + } + + gdk_flush (); +} diff --git a/mate-panel/panel-force-quit.h b/mate-panel/panel-force-quit.h new file mode 100644 index 00000000..ac5be19e --- /dev/null +++ b/mate-panel/panel-force-quit.h @@ -0,0 +1,41 @@ +/* + * panel-force-quit.h + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_FORCE_QUIT_H__ +#define __PANEL_FORCE_QUIT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_force_quit (GdkScreen *screen, + guint time); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_FORCE_QUIT_H__ */ diff --git a/mate-panel/panel-frame.c b/mate-panel/panel-frame.c new file mode 100644 index 00000000..1716784e --- /dev/null +++ b/mate-panel/panel-frame.c @@ -0,0 +1,328 @@ +/* + * panel-frame.c: A frame which only draws certain edges. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-frame.h" + +#include "panel-typebuiltins.h" + +G_DEFINE_TYPE (PanelFrame, panel_frame, GTK_TYPE_BIN) + +enum { + PROP_0, + PROP_EDGES +}; + +static void +panel_frame_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + PanelFrame *frame = (PanelFrame *) widget; + GtkBin *bin = (GtkBin *) widget; + GtkStyle *style; + GtkWidget *child; + int border_width; + + style = gtk_widget_get_style (widget); + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + + requisition->width = 1; + requisition->height = 1; + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_request (child, requisition); + + requisition->width += border_width; + requisition->height += border_width; + + if (frame->edges & PANEL_EDGE_TOP) + requisition->height += style->xthickness; + if (frame->edges & PANEL_EDGE_BOTTOM) + requisition->height += style->xthickness; + if (frame->edges & PANEL_EDGE_LEFT) + requisition->width += style->ythickness; + if (frame->edges & PANEL_EDGE_RIGHT) + requisition->width += style->ythickness; +} + +static void +panel_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + PanelFrame *frame = (PanelFrame *) widget; + GtkBin *bin = (GtkBin *) widget; + GtkStyle *style; + GtkAllocation child_allocation; + GtkAllocation child_allocation_current; + GtkWidget *child; + int border_width; + + gtk_widget_set_allocation (widget, allocation); + + style = gtk_widget_get_style (widget); + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + + child_allocation.x = allocation->x + border_width; + child_allocation.y = allocation->y + border_width; + child_allocation.width = allocation->width - 2 * border_width; + child_allocation.height = allocation->height - 2 * border_width; + + if (frame->edges & PANEL_EDGE_LEFT) { + child_allocation.x += style->xthickness; + child_allocation.width -= style->xthickness; + } + + if (frame->edges & PANEL_EDGE_TOP) { + child_allocation.y += style->ythickness; + child_allocation.height -= style->ythickness; + } + + if (frame->edges & PANEL_EDGE_RIGHT) + child_allocation.width -= style->xthickness; + + if (frame->edges & PANEL_EDGE_BOTTOM) + child_allocation.height -= style->ythickness; + + child = gtk_bin_get_child (bin); + gtk_widget_get_allocation (child, &child_allocation_current); + + if (gtk_widget_get_mapped (widget) && + (child_allocation.x != child_allocation_current.x || + child_allocation.y != child_allocation_current.y || + child_allocation.width != child_allocation_current.width || + child_allocation.height != child_allocation_current.height)) + gdk_window_invalidate_rect (gtk_widget_get_window (widget), allocation, FALSE); + + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_allocate (child, &child_allocation); +} + +void +panel_frame_draw (GtkWidget *widget, + PanelFrameEdge edges) +{ + GdkWindow *window; + GtkStyle *style; + GtkStateType state; + GtkAllocation allocation; + GdkGC *dark, *light, *black; + int x, y, width, height; + int xthickness, ythickness; + + if (edges == PANEL_EDGE_NONE) + return; + + window = gtk_widget_get_window (widget); + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + gtk_widget_get_allocation (widget, &allocation); + + dark = style->dark_gc [state]; + light = style->light_gc [state]; + black = style->black_gc; + + xthickness = style->xthickness; + ythickness = style->ythickness; + + x = allocation.x; + y = allocation.y; + width = allocation.width; + height = allocation.height; + + /* Copied from gtk_default_draw_shadow() */ + + if (edges & PANEL_EDGE_BOTTOM && ythickness > 0) { + if (ythickness > 1) { + gdk_draw_line (window, dark, + x, y + height - 2, + x + width - 1, y + height - 2); + gdk_draw_line (window, black, + x, y + height - 1, + x + width - 1, y + height - 1); + } else + gdk_draw_line (window, dark, + x, y + height - 1, + x + width - 1, y + height - 1); + } + + if (edges & PANEL_EDGE_RIGHT && xthickness > 0) { + if (xthickness > 1) { + gdk_draw_line (window, dark, + x + width - 2, y, + x + width - 2, y + height - 1); + + gdk_draw_line (window, black, + x + width - 1, y, + x + width - 1, y + height - 1); + } else + gdk_draw_line (window, dark, + x + width - 1, y, + x + width - 1, y + height - 1); + } + + if (edges & PANEL_EDGE_TOP && ythickness > 0) { + gdk_draw_line (window, light, + x, y, x + width - 1, y); + + if (ythickness > 1) + gdk_draw_line (window, + style->bg_gc [state], + x, y + 1, x + width - 1, y + 1); + } + + if (edges & PANEL_EDGE_LEFT && xthickness > 0) { + gdk_draw_line (window, light, + x, y, x, y + height - 1); + + if (xthickness > 1) + gdk_draw_line (window, + style->bg_gc [state], + x + 1, y, x + 1, y + height - 1); + } +} + +static gboolean panel_frame_expose(GtkWidget* widget, GdkEventExpose* event) +{ + PanelFrame *frame = (PanelFrame *) widget; + gboolean retval = FALSE; + + if (!gtk_widget_is_drawable (widget)) + return retval; + + if (GTK_WIDGET_CLASS (panel_frame_parent_class)->expose_event) + { + retval = GTK_WIDGET_CLASS (panel_frame_parent_class)->expose_event (widget, event); + } + + panel_frame_draw (widget, frame->edges); + + return retval; +} + +static void +panel_frame_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PanelFrame *frame; + + g_return_if_fail (PANEL_IS_FRAME (object)); + + frame = PANEL_FRAME (object); + + switch (prop_id) { + case PROP_EDGES: + panel_frame_set_edges (frame, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_frame_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelFrame *frame; + + g_return_if_fail (PANEL_IS_FRAME (object)); + + frame = PANEL_FRAME (object); + + switch (prop_id) { + case PROP_EDGES: + g_value_set_enum (value, frame->edges); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_frame_class_init (PanelFrameClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + gobject_class->set_property = panel_frame_set_property; + gobject_class->get_property = panel_frame_get_property; + + widget_class->size_request = panel_frame_size_request; + widget_class->size_allocate = panel_frame_size_allocate; + widget_class->expose_event = panel_frame_expose; + + g_object_class_install_property ( + gobject_class, + PROP_EDGES, + g_param_spec_enum ( + "edges", + "Edges", + "Which edges to draw", + PANEL_TYPE_FRAME_EDGE, + PANEL_EDGE_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +} + +static void +panel_frame_init (PanelFrame *frame) +{ + frame->edges = PANEL_EDGE_NONE; +} + +GtkWidget * +panel_frame_new (PanelFrameEdge edges) +{ + return g_object_new (PANEL_TYPE_FRAME, "edges", edges, NULL); +} + +void +panel_frame_set_edges (PanelFrame *frame, + PanelFrameEdge edges) +{ + g_return_if_fail (PANEL_IS_FRAME (frame)); + + if (frame->edges == edges) + return; + + frame->edges = edges; + + gtk_widget_queue_resize (GTK_WIDGET (frame)); + + g_object_notify (G_OBJECT (frame), "edges"); +} + +PanelFrameEdge +panel_frame_get_edges (PanelFrame *frame) +{ + g_return_val_if_fail (PANEL_IS_FRAME (frame), 0); + + return frame->edges; +} diff --git a/mate-panel/panel-frame.h b/mate-panel/panel-frame.h new file mode 100644 index 00000000..bffef745 --- /dev/null +++ b/mate-panel/panel-frame.h @@ -0,0 +1,69 @@ +/* + * panel-frame.h: A frame which only draws certain edges. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_FRAME_H__ +#define __PANEL_FRAME_H__ + +#include +#include "panel-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_FRAME (panel_frame_get_type ()) +#define PANEL_FRAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_FRAME, PanelFrame)) +#define PANEL_FRAME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_FRAME, PanelFrameClass)) +#define PANEL_IS_FRAME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_FRAME)) +#define PANEL_IS_FRAME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_FRAME)) +#define PANEL_FRAME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_FRAME, PanelFrameClass)) + +typedef struct _PanelFrame PanelFrame; +typedef struct _PanelFrameClass PanelFrameClass; + +struct _PanelFrame { + GtkBin bin_instance; + + PanelFrameEdge edges; +}; + +struct _PanelFrameClass { + GtkBinClass bin_class; +}; + +GType panel_frame_get_type (void) G_GNUC_CONST; +GtkWidget *panel_frame_new (PanelFrameEdge edges); + +void panel_frame_set_edges (PanelFrame *toplevel, + PanelFrameEdge edges); +PanelFrameEdge panel_frame_get_edges (PanelFrame *toplevel); + +void panel_frame_draw (GtkWidget *widget, + PanelFrameEdge edges); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_FRAME_H__ */ diff --git a/mate-panel/panel-general.schemas.in b/mate-panel/panel-general.schemas.in new file mode 100644 index 00000000..1bfc2c7a --- /dev/null +++ b/mate-panel/panel-general.schemas.in @@ -0,0 +1,127 @@ + + + + + + + /schemas/apps/panel/general/enable_program_list + /apps/panel/general/enable_program_list + panel + bool + true + + Enable program list in "Run Application" dialog + + If true, the "Known Applications" listing in the "Run + Application" dialog is made available. Whether or not + the listing is expanded when the dialog is shown is + controlled by the show_program_list key. + + + + + + /schemas/apps/panel/general/show_program_list + /apps/panel/general/show_program_list + panel + bool + false + + Expand program list in "Run Application" dialog + + If true, the "Known Applications" listing in the "Run + Application" dialog is expanded when the dialog is opened. + This key is only relevant if the enable_program_list key + is true. + + + + + + /schemas/apps/panel/general/enable_autocompletion + /apps/panel/general/enable_autocompletion + panel + bool + true + + Enable autocompletion in "Run Application" dialog + + If true, autocompletion in the "Run Application" dialog is + made available. + + + + + + /schemas/apps/panel/general/toplevel_id_list + /apps/panel/general/toplevel_id_list + panel + list + string + [] + + Panel ID list + + A list of panel IDs. Each ID identifies an individual + toplevel panel. The settings for each of these panels are + stored in /apps/panel/toplevels/$(id). + + + + + + /schemas/apps/panel/general/applet_id_list + /apps/panel/general/applet_id_list + panel + string + list + [] + + Panel applet ID list + + A list of panel applet IDs. Each ID identifies an + individual panel applet. The settings for each of + these applets are stored in + /apps/panel/applets/$(id). + + + + + + /schemas/apps/panel/general/object_id_list + /apps/panel/general/object_id_list + panel + list + string + [] + + Panel object ID list + + A list of panel object IDs. Each ID identifies an individual + panel object (e.g. a launcher, action button or menu + button/bar). The settings for each of these objects are + stored in + /apps/panel/objects/$(id). + + + + + + /schemas/apps/panel/general/profiles_migrated + /apps/panel/general/profiles_migrated + panel + bool + false + + Old profiles configuration migrated + + A boolean flag to indicate whether the user's previous + configuration in /apps/panel/profiles/default has been + copied to the new location in /apps/panel. + + + + + + + diff --git a/mate-panel/panel-global.schemas.in b/mate-panel/panel-global.schemas.in new file mode 100644 index 00000000..f99c5b28 --- /dev/null +++ b/mate-panel/panel-global.schemas.in @@ -0,0 +1,276 @@ + + + + + + + + + /schemas/apps/panel/global/tooltips_enabled + /apps/panel/global/tooltips_enabled + panel + bool + true + + Enable tooltips + If true, tooltips are shown for objects in panels. + + + + + + /schemas/apps/panel/global/keep_menus_in_memory + /apps/panel/global/keep_menus_in_memory + panel + bool + true + + Deprecated + + + + + + /schemas/apps/panel/global/enable_animations + /apps/panel/global/enable_animations + panel + bool + true + + Enable animations + + + + + + /schemas/apps/panel/global/panel_minimized_size + /apps/panel/global/panel_minimized_size + panel + int + 3 + + Deprecated + + + + + + /schemas/apps/panel/global/panel_show_delay + /apps/panel/global/panel_show_delay + panel + int + 300 + + Deprecated + + + + + + /schemas/apps/panel/global/panel_animation_speed + /apps/panel/global/panel_animation_speed + panel + string + panel-speed-medium + + Deprecated + + + + + + /schemas/apps/panel/global/panel_hide_delay + /apps/panel/global/panel_hide_delay + panel + int + 500 + + Deprecated + + + + + + /schemas/apps/panel/global/enable_key_bindings + /apps/panel/global/enable_key_bindings + panel + bool + true + + Deprecated + + + + + + /schemas/apps/panel/global/menu_key + /apps/panel/global/menu_key + panel + string + <Alt>F1 + + Deprecated + + + + + + /schemas/apps/panel/global/run_key + /apps/panel/global/run_key + panel + string + <Alt>F2 + + Deprecated + + + + + + /schemas/apps/panel/global/screenshot_key + /apps/panel/global/screenshot_key + panel + string + Print + + Deprecated + + + + + + /schemas/apps/panel/global/window_screenshot_key + /apps/panel/global/window_screenshot_key + panel + string + <Alt>Print + + Deprecated + + + + + + /schemas/apps/panel/global/drawer_autoclose + /apps/panel/global/drawer_autoclose + panel + bool + true + + Autoclose drawer + If true, a drawer will automatically be closed + when the user clicks a launcher in it. + + + + + + /schemas/apps/panel/global/confirm_panel_remove + /apps/panel/global/confirm_panel_remove + panel + bool + true + + Confirm panel removal + If true, a dialog is shown asking for confirmation + if the user wants to remove a panel. + + + + + + /schemas/apps/panel/global/highlight_launchers_on_mouseover + /apps/panel/global/highlight_launchers_on_mouseover + panel + bool + true + + Highlight launchers on mouseover + If true, a launcher is highlighted when the user + moves the pointer over it. + + + + + + /schemas/apps/panel/global/locked_down + /apps/panel/global/locked_down + panel + bool + false + + Complete panel lockdown + If true, the panel will not allow any changes to + the configuration of the panel. Individual applets + may need to be locked down separately however. + The panel must be restarted for this to take effect. + + + + + + /schemas/apps/panel/global/disabled_applets + /apps/panel/global/disabled_applets + panel + list + string + [] + + Applet IIDs to disable from loading + A list of applet IIDs that the panel will ignore. This way you + can disable certain applets from loading or showing up in the menu. + For example to disable the mini-commander applet add 'OAFIID:MATE_MiniCommanderApplet' + to this list. The panel must be restarted for this to take effect. + + + + + + /schemas/apps/panel/global/disable_lock_screen + /apps/panel/global/disable_lock_screen + panel + bool + false + + Deprecated + This key is deprecated as it cannot be used to implement proper + lockdown. The /desktop/mate/lockdown/disable_lock_screen key + should be used instead. + + + + + + /schemas/apps/panel/global/disable_log_out + /apps/panel/global/disable_log_out + panel + bool + false + + Disable Logging Out + If true, the panel will not allow a user to log out, + by removing access to the log out menu entries. + + + + + + /schemas/apps/panel/global/disable_force_quit + /apps/panel/global/disable_force_quit + panel + bool + false + + Disable Force Quit + If true, the panel will not allow a user to force + an application to quit by removing access to the + force quit button. + + + + + + + diff --git a/mate-panel/panel-globals.h b/mate-panel/panel-globals.h new file mode 100644 index 00000000..fe83c237 --- /dev/null +++ b/mate-panel/panel-globals.h @@ -0,0 +1,41 @@ +/* + * panel-globals.h: panel global variables + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_GLOBALS_H__ +#define __PANEL_GLOBALS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern GSList *panels; +extern GSList *panel_list; + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_GLOBALS_H__ */ diff --git a/mate-panel/panel-icon-names.h b/mate-panel/panel-icon-names.h new file mode 100644 index 00000000..4c948b76 --- /dev/null +++ b/mate-panel/panel-icon-names.h @@ -0,0 +1,40 @@ +#ifndef PANEL_ICON_NAMES_H +#define PANEL_ICON_NAMES_H + +#define PANEL_ICON_BOOKMARKS "user-bookmarks" +#define PANEL_ICON_BURNER "caja-cd-burner" +#define PANEL_ICON_COMPUTER "computer" +#define PANEL_ICON_DESKTOP "user-desktop" +#define PANEL_ICON_DRAWER "mate-panel-drawer" +#define PANEL_ICON_FILESYSTEM "drive-harddisk" +#define PANEL_ICON_FOLDER "folder" +#define PANEL_ICON_FOLDER_DOCUMENTS "folder-documents" +#define PANEL_ICON_FOLDER_DOWNLOAD "folder-download" +#define PANEL_ICON_FOLDER_MUSIC "folder-music" +#define PANEL_ICON_FOLDER_PICTURES "folder-pictures" +#define PANEL_ICON_FOLDER_PUBLIC_SHARE "folder-publicshare" +#define PANEL_ICON_FOLDER_TEMPLATES "folder-templates" +#define PANEL_ICON_FOLDER_VIDEOS "folder-videos" +#define PANEL_ICON_FONTS "preferences-desktop-font" +#define PANEL_ICON_FORCE_QUIT "mate-panel-force-quit" +#define PANEL_ICON_HOME "user-home" +#define PANEL_ICON_LAUNCHER "mate-panel-launcher" +#define PANEL_ICON_LOCKSCREEN "system-lock-screen" +#define PANEL_ICON_LOGOUT "system-log-out" +#define PANEL_ICON_MAIN_MENU "start-here" +#define PANEL_ICON_NETWORK "network-workgroup" +#define PANEL_ICON_NETWORK_SERVER "network-server" +#define PANEL_ICON_PANEL "mate-panel" +#define PANEL_ICON_RECENT "document-open-recent" +#define PANEL_ICON_REMOTE "applications-internet" +#define PANEL_ICON_REMOVABLE_MEDIA "drive-removable-media" +#define PANEL_ICON_RUN "system-run" +#define PANEL_ICON_SEPARATOR "mate-panel-separator" +#define PANEL_ICON_SAVED_SEARCH "folder-saved-search" +#define PANEL_ICON_SEARCHTOOL "system-search" +#define PANEL_ICON_SHUTDOWN "system-shutdown" +#define PANEL_ICON_THEME "preferences-desktop-theme" +#define PANEL_ICON_TRASH "user-trash" +#define PANEL_ICON_UNKNOWN "image-missing" + +#endif /* PANEL_ICON_NAMES_H */ diff --git a/mate-panel/panel-lockdown.c b/mate-panel/panel-lockdown.c new file mode 100644 index 00000000..e484b016 --- /dev/null +++ b/mate-panel/panel-lockdown.c @@ -0,0 +1,442 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Matt Keenan + * Mark McLoughlin + */ + +#include + +#include "panel-lockdown.h" + +#include +#include "panel-mateconf.h" + +#define N_LISTENERS 6 + +#define PANEL_GLOBAL_LOCKDOWN_DIR "/apps/panel/global" +#define DESKTOP_MATE_LOCKDOWN_DIR "/desktop/mate/lockdown" +#define PANEL_GLOBAL_LOCKED_DOWN_KEY PANEL_GLOBAL_LOCKDOWN_DIR "/locked_down" +#define DISABLE_COMMAND_LINE_KEY DESKTOP_MATE_LOCKDOWN_DIR "/disable_command_line" +#define DISABLE_LOCK_SCREEN_KEY DESKTOP_MATE_LOCKDOWN_DIR "/disable_lock_screen" +#define DISABLE_LOG_OUT_KEY PANEL_GLOBAL_LOCKDOWN_DIR "/disable_log_out" +#define DISABLE_FORCE_QUIT_KEY PANEL_GLOBAL_LOCKDOWN_DIR "/disable_force_quit" +#define DISABLED_APPLETS_KEY PANEL_GLOBAL_LOCKDOWN_DIR "/disabled_applets" + +typedef struct { + guint initialized : 1; + + guint locked_down : 1; + guint disable_command_line : 1; + guint disable_lock_screen : 1; + guint disable_log_out : 1; + guint disable_force_quit : 1; + + GSList *disabled_applets; + + guint listeners [N_LISTENERS]; + + GSList *closures; +} PanelLockdown; + +static PanelLockdown panel_lockdown = { 0, }; + + +static inline void +panel_lockdown_invoke_closures (PanelLockdown *lockdown) +{ + GSList *l; + + for (l = lockdown->closures; l; l = l->next) + g_closure_invoke (l->data, NULL, 0, NULL, NULL); +} + +static void +locked_down_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelLockdown *lockdown) +{ + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + lockdown->locked_down = mateconf_value_get_bool (entry->value); + + panel_lockdown_invoke_closures (lockdown); +} + +static void +disable_command_line_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelLockdown *lockdown) +{ + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + lockdown->disable_command_line = mateconf_value_get_bool (entry->value); + + panel_lockdown_invoke_closures (lockdown); +} + +static void +disable_lock_screen_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelLockdown *lockdown) +{ + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + lockdown->disable_lock_screen = mateconf_value_get_bool (entry->value); + + panel_lockdown_invoke_closures (lockdown); +} + +static void +disable_log_out_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelLockdown *lockdown) +{ + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + lockdown->disable_log_out = mateconf_value_get_bool (entry->value); + + panel_lockdown_invoke_closures (lockdown); +} + +static void +disable_force_quit_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelLockdown *lockdown) +{ + if (!entry->value || entry->value->type != MATECONF_VALUE_BOOL) + return; + + lockdown->disable_force_quit = mateconf_value_get_bool (entry->value); + + panel_lockdown_invoke_closures (lockdown); +} + +static void +disabled_applets_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelLockdown *lockdown) +{ + GSList *l; + + if (!entry->value || entry->value->type != MATECONF_VALUE_LIST || + mateconf_value_get_list_type (entry->value) != MATECONF_VALUE_STRING) + return; + + for (l = lockdown->disabled_applets; l; l = l->next) + g_free (l->data); + g_slist_free (lockdown->disabled_applets); + lockdown->disabled_applets = NULL; + + for (l = mateconf_value_get_list (entry->value); l; l = l->next) { + const char *iid = mateconf_value_get_string (l->data); + + lockdown->disabled_applets = + g_slist_prepend (lockdown->disabled_applets, + g_strdup (iid)); + } + + panel_lockdown_invoke_closures (lockdown); +} + +static gboolean +panel_lockdown_load_bool (PanelLockdown *lockdown, + MateConfClient *client, + const char *key, + MateConfClientNotifyFunc notify_func, + int listener) +{ + GError *error = NULL; + gboolean retval; + + retval = mateconf_client_get_bool (client, key, &error); + if (error) { + g_warning ("Error getting value of '%s': %s\n", + key, error->message); + retval = FALSE; + } + + lockdown->listeners [listener] = + mateconf_client_notify_add (client, + key, + notify_func, + lockdown, + NULL, NULL); + + return retval; +} + +static GSList * +panel_lockdown_load_disabled_applets (PanelLockdown *lockdown, + MateConfClient *client, + int listener) +{ + GSList *retval; + + retval = mateconf_client_get_list (client, + DISABLED_APPLETS_KEY, + MATECONF_VALUE_STRING, + NULL); + + lockdown->listeners [listener] = + mateconf_client_notify_add (client, + DISABLED_APPLETS_KEY, + (MateConfClientNotifyFunc) disabled_applets_notify, + lockdown, + NULL, NULL); + + return retval; +} + +void +panel_lockdown_init (void) +{ + MateConfClient *client; + int i = 0; + + client = panel_mateconf_get_client (); + + mateconf_client_add_dir (client, + DESKTOP_MATE_LOCKDOWN_DIR, + MATECONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + + mateconf_client_add_dir (client, + PANEL_GLOBAL_LOCKDOWN_DIR, + MATECONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + + panel_lockdown.locked_down = + panel_lockdown_load_bool (&panel_lockdown, + client, + PANEL_GLOBAL_LOCKED_DOWN_KEY, + (MateConfClientNotifyFunc) locked_down_notify, + i++); + + panel_lockdown.disable_command_line = + panel_lockdown_load_bool (&panel_lockdown, + client, + DISABLE_COMMAND_LINE_KEY, + (MateConfClientNotifyFunc) disable_command_line_notify, + i++); + + panel_lockdown.disable_lock_screen = + panel_lockdown_load_bool (&panel_lockdown, + client, + DISABLE_LOCK_SCREEN_KEY, + (MateConfClientNotifyFunc) disable_lock_screen_notify, + i++); + + panel_lockdown.disable_log_out = + panel_lockdown_load_bool (&panel_lockdown, + client, + DISABLE_LOG_OUT_KEY, + (MateConfClientNotifyFunc) disable_log_out_notify, + i++); + + panel_lockdown.disable_force_quit = + panel_lockdown_load_bool (&panel_lockdown, + client, + DISABLE_FORCE_QUIT_KEY, + (MateConfClientNotifyFunc) disable_force_quit_notify, + i++); + + panel_lockdown.disabled_applets = + panel_lockdown_load_disabled_applets (&panel_lockdown, + client, + i++); + + g_assert (i == N_LISTENERS); + + panel_lockdown.initialized = TRUE; +} + +void +panel_lockdown_finalize (void) +{ + MateConfClient *client; + GSList *l; + int i; + + g_assert (panel_lockdown.initialized != FALSE); + + client = panel_mateconf_get_client (); + + for (l = panel_lockdown.disabled_applets; l; l = l->next) + g_free (l->data); + g_slist_free (panel_lockdown.disabled_applets); + panel_lockdown.disabled_applets = NULL; + + for (i = 0; i < N_LISTENERS; i++) { + if (panel_lockdown.listeners [i]) + mateconf_client_notify_remove (client, + panel_lockdown.listeners [i]); + panel_lockdown.listeners [i] = 0; + } + + mateconf_client_remove_dir (client, + PANEL_GLOBAL_LOCKDOWN_DIR, + NULL); + + mateconf_client_remove_dir (client, + DESKTOP_MATE_LOCKDOWN_DIR, + NULL); + + for (l = panel_lockdown.closures; l; l = l->next) + g_closure_unref (l->data); + g_slist_free (panel_lockdown.closures); + panel_lockdown.closures = NULL; + + panel_lockdown.initialized = FALSE; +} + +gboolean +panel_lockdown_get_locked_down (void) +{ + g_assert (panel_lockdown.initialized != FALSE); + + return panel_lockdown.locked_down; +} + +gboolean +panel_lockdown_get_disable_command_line (void) +{ + g_assert (panel_lockdown.initialized != FALSE); + + return panel_lockdown.disable_command_line; +} + +gboolean +panel_lockdown_get_disable_lock_screen (void) +{ + g_assert (panel_lockdown.initialized != FALSE); + + return panel_lockdown.disable_lock_screen; +} + +gboolean +panel_lockdown_get_disable_log_out (void) +{ + g_assert (panel_lockdown.initialized != FALSE); + + return panel_lockdown.disable_log_out; +} + +gboolean +panel_lockdown_get_disable_force_quit (void) +{ + g_assert (panel_lockdown.initialized != FALSE); + + return panel_lockdown.disable_force_quit; +} + +gboolean +panel_lockdown_is_applet_disabled (const char *iid) +{ + GSList *l; + + g_assert (panel_lockdown.initialized != FALSE); + + for (l = panel_lockdown.disabled_applets; l; l = l->next) + if (!strcmp (l->data, iid)) + return TRUE; + + return FALSE; +} + +static GClosure * +panel_lockdown_notify_find (GSList *closures, + GCallback callback_func, + gpointer user_data) +{ + GSList *l; + + for (l = closures; l; l = l->next) { + GCClosure *cclosure = l->data; + GClosure *closure = l->data; + + if (closure->data == user_data && + cclosure->callback == callback_func) + return closure; + } + + return NULL; +} + +static void +marshal_user_data (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + GCClosure *cclosure = (GCClosure*) closure; + + g_return_if_fail (cclosure->callback != NULL); + g_return_if_fail (n_param_values == 0); + + ((void (*) (gpointer *))cclosure->callback) (closure->data); +} + +void +panel_lockdown_notify_add (GCallback callback_func, + gpointer user_data) +{ + GClosure *closure; + + g_assert (panel_lockdown_notify_find (panel_lockdown.closures, + callback_func, + user_data) == NULL); + + closure = g_cclosure_new (callback_func, user_data, NULL); + g_closure_set_marshal (closure, marshal_user_data); + + panel_lockdown.closures = g_slist_append (panel_lockdown.closures, + closure); +} + +void +panel_lockdown_notify_remove (GCallback callback_func, + gpointer user_data) +{ + GClosure *closure; + + closure = panel_lockdown_notify_find (panel_lockdown.closures, + callback_func, + user_data); + + g_assert (closure != NULL); + + panel_lockdown.closures = g_slist_remove (panel_lockdown.closures, + closure); + + g_closure_unref (closure); +} diff --git a/mate-panel/panel-lockdown.h b/mate-panel/panel-lockdown.h new file mode 100644 index 00000000..eaf31fb9 --- /dev/null +++ b/mate-panel/panel-lockdown.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Matt Keenan + * Mark McLoughlin + */ + +#ifndef __PANEL_LOCKDOWN_H__ +#define __PANEL_LOCKDOWN_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_lockdown_init (void); +void panel_lockdown_finalize (void); + +gboolean panel_lockdown_get_locked_down (void); +gboolean panel_lockdown_get_disable_command_line (void); +gboolean panel_lockdown_get_disable_lock_screen (void); +gboolean panel_lockdown_get_disable_log_out (void); +gboolean panel_lockdown_get_disable_force_quit (void); + +gboolean panel_lockdown_is_applet_disabled (const char *iid); + +void panel_lockdown_notify_add (GCallback callback_func, + gpointer user_data); +void panel_lockdown_notify_remove (GCallback callback_func, + gpointer user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_LOCKDOWN_H__ */ diff --git a/mate-panel/panel-marshal.list b/mate-panel/panel-marshal.list new file mode 100644 index 00000000..7893b881 --- /dev/null +++ b/mate-panel/panel-marshal.list @@ -0,0 +1,3 @@ +BOOLEAN:VOID +VOID:STRING,STRING +VOID:STRING,POINTER diff --git a/mate-panel/panel-mateconf.c b/mate-panel/panel-mateconf.c new file mode 100644 index 00000000..974ddb4b --- /dev/null +++ b/mate-panel/panel-mateconf.c @@ -0,0 +1,351 @@ +/* + * panel-mateconf.c: panel mateconf utility methods + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * Glynn Foster + */ + +#include + +#include "panel-mateconf.h" + +#include +#include +#include + +#include + +#undef PANEL_MATECONF_DEBUG + +MateConfClient * +panel_mateconf_get_client (void) +{ + static MateConfClient *panel_mateconf_client = NULL; + + if (!panel_mateconf_client) { + panel_mateconf_client = mateconf_client_get_default (); + panel_cleanup_register (panel_cleanup_unref_and_nullify, + &panel_mateconf_client); + } + + return panel_mateconf_client; +} + +/* + * panel_mateconf_sprintf: + * @format: the format string. See sprintf() documentation. + * @...: the arguments to be inserted. + * + * This is a version of sprintf using a static buffer which is + * intended for use in generating the full mateconf key for all panel + * config keys. + * Note, you should not free the return value from this function and + * you should realize that the return value will get overwritten or + * freed by a subsequent call to this function. + * + * Return Value: a pointer to the static string buffer. + */ +const char * +panel_mateconf_sprintf (const char *format, + ...) +{ + static char *buffer = NULL; + static int buflen = 128; + va_list args; + int len; + + if (!buffer) + buffer = g_new (char, buflen); + + va_start (args, format); + len = g_vsnprintf (buffer, buflen, format, args); + + if (len >= buflen) { + int i; + + /* Round up length to the nearest power of 2 */ + for (i = 0; len != 1; i++, len >>= 1); + + buflen = len << (i + 1); + g_assert (buflen > 0); + + g_free (buffer); + buffer = g_new (char, buflen); + + va_start (args, format); + len = g_vsnprintf (buffer, buflen, format, args); + + g_assert (len < buflen); + } + + va_end (args); + + return buffer; +} + +const char * +panel_mateconf_key_type_to_id_list (PanelMateConfKeyType type) +{ + char *retval; + + switch (type) { + case PANEL_MATECONF_TOPLEVELS: + retval = "toplevel_id_list"; + break; + case PANEL_MATECONF_APPLETS: + retval = "applet_id_list"; + break; + case PANEL_MATECONF_OBJECTS: + retval = "object_id_list"; + break; + default: + retval = NULL; + g_assert_not_reached (); + break; + } + + return retval; +} + +const char * +panel_mateconf_global_key (const char *key) +{ + return panel_mateconf_sprintf ("/apps/panel/global/%s", key); +} + +const char * +panel_mateconf_general_key (const char *key) +{ + return panel_mateconf_sprintf (PANEL_CONFIG_DIR "/general/%s", key); +} + +const char * +panel_mateconf_full_key (PanelMateConfKeyType type, + const char *id, + const char *key) +{ + char *subdir = NULL; + + switch (type) { + case PANEL_MATECONF_TOPLEVELS: + subdir = "toplevels"; + break; + case PANEL_MATECONF_OBJECTS: + subdir = "objects"; + break; + case PANEL_MATECONF_APPLETS: + subdir = "applets"; + break; + default: + g_assert_not_reached (); + break; + } + + return panel_mateconf_sprintf (PANEL_CONFIG_DIR "/%s/%s/%s", + subdir, id, key); +} + +const char * +panel_mateconf_basename (const char *key) +{ + char *retval; + + g_return_val_if_fail (key != NULL, NULL); + + retval = strrchr (key, '/'); + + return retval ? retval + 1 : NULL; +} + +char * +panel_mateconf_dirname (const char *key) +{ + char *retval; + int len; + + g_return_val_if_fail (key != NULL, NULL); + + retval = strrchr (key, '/'); + g_assert (retval != NULL); + + len = retval - key; + g_assert (len > 0); + + retval = g_new0 (char, len + 1); + memcpy (retval, key, len); + + return retval; +} + +static void +panel_notify_object_dead (guint notify_id) +{ + MateConfClient *client; + + client = panel_mateconf_get_client (); + + mateconf_client_notify_remove (client, notify_id); +} + +guint +panel_mateconf_notify_add_while_alive (const char *key, + MateConfClientNotifyFunc notify_func, + GObject *alive_object) +{ + MateConfClient *client; + guint notify_id; + + g_return_val_if_fail (G_IS_OBJECT (alive_object), 0); + + client = panel_mateconf_get_client (); + + notify_id = mateconf_client_notify_add (client, key, notify_func, + alive_object, NULL, NULL); + + if (notify_id > 0) + g_object_weak_ref (alive_object, + (GWeakNotify) panel_notify_object_dead, + GUINT_TO_POINTER (notify_id)); + + return notify_id; +} + +void +panel_mateconf_copy_dir (MateConfClient *client, + const char *src_dir, + const char *dest_dir) +{ + GSList *list, *l; + + list = mateconf_client_all_entries (client, src_dir, NULL); + for (l = list; l; l = l->next) { + MateConfEntry *entry = l->data; + const char *key; + char *tmp; + + tmp = g_path_get_basename (mateconf_entry_get_key (entry)); + key = panel_mateconf_sprintf ("%s/%s", dest_dir, tmp); + g_free (tmp); + + mateconf_engine_associate_schema (client->engine, + key, + mateconf_entry_get_schema_name (entry), + NULL); + + if (!mateconf_entry_get_is_default (entry) && entry->value) + mateconf_client_set (client, key, entry->value, NULL); + + mateconf_entry_unref (entry); + } + g_slist_free (list); + + list = mateconf_client_all_dirs (client, src_dir, NULL); + for (l = list; l; l = l->next) { + char *subdir = l->data; + char *src_subdir; + char *dest_subdir; + char *tmp; + + tmp = g_path_get_basename (subdir); + src_subdir = mateconf_concat_dir_and_key (src_dir, tmp); + dest_subdir = mateconf_concat_dir_and_key (dest_dir, tmp); + g_free (tmp); + + panel_mateconf_copy_dir (client, src_subdir, dest_subdir); + + g_free (src_subdir); + g_free (dest_subdir); + g_free (subdir); + } + + g_slist_free (list); +} + +void +panel_mateconf_associate_schemas_in_dir (MateConfClient *client, + const char *profile_dir, + const char *schema_dir) +{ + GSList *list, *l; + +#ifdef PANEL_MATECONF_DEBUG + g_print ("associating schemas in %s to %s\n", schema_dir, profile_dir); +#endif + + list = mateconf_client_all_entries (client, schema_dir, NULL); + for (l = list; l; l = l->next) { + MateConfEntry *entry = l->data; + const char *key; + char *tmp; + + tmp = g_path_get_basename (mateconf_entry_get_key (entry)); + + key = panel_mateconf_sprintf ("%s/%s", profile_dir, tmp); + + g_free (tmp); + + mateconf_engine_associate_schema ( + client->engine, key, mateconf_entry_get_key (entry), NULL); + + mateconf_entry_unref (entry); + } + + g_slist_free (list); + + list = mateconf_client_all_dirs (client, schema_dir, NULL); + for (l = list; l; l = l->next) { + char *subdir = l->data; + char *prefs_subdir; + char *schema_subdir; + char *tmp; + + tmp = g_path_get_basename (subdir); + + prefs_subdir = g_strdup_printf ("%s/%s", profile_dir, tmp); + schema_subdir = g_strdup_printf ("%s/%s", schema_dir, tmp); + + panel_mateconf_associate_schemas_in_dir ( + client, prefs_subdir, schema_subdir); + + g_free (prefs_subdir); + g_free (schema_subdir); + g_free (subdir); + g_free (tmp); + } + + g_slist_free (list); +} + +gint +panel_mateconf_value_strcmp (gconstpointer a, + gconstpointer b) +{ + const char *str_a; + const char *str_b; + + if (a == b || !a || !b) + return 0; + + str_a = mateconf_value_get_string (a); + str_b = mateconf_value_get_string (b); + + return strcmp (str_a, str_b); +} diff --git a/mate-panel/panel-mateconf.h b/mate-panel/panel-mateconf.h new file mode 100644 index 00000000..80c49fa5 --- /dev/null +++ b/mate-panel/panel-mateconf.h @@ -0,0 +1,76 @@ +/* + * panel-mateconf.h: panel mateconf utility methods + * + * Copyright (C) 2001 - 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * Glynn Foster + */ + +#ifndef __PANEL_MATECONF_H__ +#define __PANEL_MATECONF_H__ + +#include + +#include "panel-enums.h" + +#define PANEL_CONFIG_DIR "/apps/panel" +#define PANEL_SCHEMAS_DIR "/schemas/apps/panel" +#define PANEL_DEFAULTS_DIR "/apps/panel/default_setup" +#define PANEL_OLD_CONFIG_DIR "/apps/panel/profiles/default" + +#ifdef __cplusplus +extern "C" { +#endif + +MateConfClient *panel_mateconf_get_client (void); + +const char *panel_mateconf_sprintf (const char *format, ...) G_GNUC_PRINTF (1, 2); +const char *panel_mateconf_basename (const char *key); +char *panel_mateconf_dirname (const char *key); +const char *panel_mateconf_global_key (const char *key); +const char *panel_mateconf_general_key (const char *key); +const char *panel_mateconf_full_key (PanelMateConfKeyType type, + const char *id, + const char *key); +const char *panel_mateconf_key_type_to_id_list (PanelMateConfKeyType type); + +guint panel_mateconf_notify_add (const char *key, + MateConfClientNotifyFunc notify_func, + gpointer user_data); +guint panel_mateconf_notify_add_while_alive (const char *key, + MateConfClientNotifyFunc notify_func, + GObject *alive_object); + +void panel_mateconf_copy_dir (MateConfClient *client, + const char *src_dir, + const char *dest_dir); + +void panel_mateconf_associate_schemas_in_dir (MateConfClient *client, + const char *profile_dir, + const char *schema_dir); + +gint panel_mateconf_value_strcmp (gconstpointer a, + gconstpointer b); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_MATECONF_H__ */ diff --git a/mate-panel/panel-menu-bar.c b/mate-panel/panel-menu-bar.c new file mode 100644 index 00000000..0ea27331 --- /dev/null +++ b/mate-panel/panel-menu-bar.c @@ -0,0 +1,474 @@ +/* + * panel-menu-bar.c: panel Applications/Places/Desktop menu bar + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * Copyright (C) 2004 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + * Vincent Untz + */ + +#include + +#include "panel-menu-bar.h" + +#include +#include + +#include +#include +#include + +#include "panel-util.h" +#include "panel-background.h" +#include "panel-action-button.h" +#include "applet.h" +#include "menu.h" +#include "panel-menu-items.h" +#include "panel-globals.h" +#include "panel-profile.h" +#include "panel-lockdown.h" +#include "panel-stock-icons.h" +#include "panel-typebuiltins.h" +#include "panel-icon-names.h" + +G_DEFINE_TYPE (PanelMenuBar, panel_menu_bar, GTK_TYPE_MENU_BAR) + +#define PANEL_MENU_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_MENU_BAR, PanelMenuBarPrivate)) + +struct _PanelMenuBarPrivate { + AppletInfo* info; + PanelWidget* panel; + + GtkWidget* applications_menu; + GtkWidget* applications_item; + GtkWidget* places_item; + GtkWidget* desktop_item; + + PanelOrientation orientation; +}; + +enum { + PROP_0, + PROP_ORIENTATION, +}; + +static void panel_menu_bar_update_text_gravity(PanelMenuBar* menubar); + +static gboolean panel_menu_bar_reinit_tooltip(GtkWidget* widget, PanelMenuBar* menubar) +{ + g_object_set(menubar->priv->applications_item, "has-tooltip", TRUE, NULL); + g_object_set(menubar->priv->places_item, "has-tooltip", TRUE, NULL); + g_object_set(menubar->priv->desktop_item, "has-tooltip", TRUE, NULL); + + return FALSE; +} + +static gboolean panel_menu_bar_hide_tooltip_and_focus(GtkWidget* widget, PanelMenuBar* menubar) +{ + /* remove focus that would be drawn on the currently focused child of + * the toplevel. See bug#308632. */ + gtk_window_set_focus(GTK_WINDOW(menubar->priv->panel->toplevel), NULL); + + g_object_set(widget, "has-tooltip", FALSE, NULL); + + return FALSE; +} + +static void panel_menu_bar_setup_tooltip(PanelMenuBar* menubar) +{ + panel_util_set_tooltip_text(menubar->priv->applications_item, _("Browse and run installed applications")); + panel_util_set_tooltip_text(menubar->priv->places_item, _("Access documents, folders and network places")); + panel_util_set_tooltip_text(menubar->priv->desktop_item, _("Change desktop appearance and behavior, get help, or log out")); + + //FIXME: this doesn't handle the right-click case. Sigh. + /* Hide tooltip if a menu is activated */ + g_signal_connect(menubar->priv->applications_item, "activate", G_CALLBACK (panel_menu_bar_hide_tooltip_and_focus), menubar); + g_signal_connect(menubar->priv->places_item, "activate", G_CALLBACK (panel_menu_bar_hide_tooltip_and_focus), menubar); + g_signal_connect(menubar->priv->desktop_item, "activate", G_CALLBACK (panel_menu_bar_hide_tooltip_and_focus), menubar); + + /* Reset tooltip when the menu bar is not used */ + g_signal_connect(GTK_MENU_SHELL (menubar), "deactivate", G_CALLBACK (panel_menu_bar_reinit_tooltip), menubar); +} + +static void panel_menu_bar_init(PanelMenuBar* menubar) +{ + GtkWidget* image; + + menubar->priv = PANEL_MENU_BAR_GET_PRIVATE(menubar); + + menubar->priv->info = NULL; + + + menubar->priv->applications_menu = create_applications_menu("mate-applications.menu", NULL, TRUE); + + menubar->priv->applications_item = panel_image_menu_item_new(); + gtk_menu_item_set_label(GTK_MENU_ITEM(menubar->priv->applications_item), _("Applications")); + image = gtk_image_new_from_icon_name(PANEL_ICON_MAIN_MENU, panel_menu_bar_icon_get_size()); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menubar->priv->applications_item), image); + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar->priv->applications_item), menubar->priv->applications_menu); + gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menubar->priv->applications_item); + + menubar->priv->places_item = panel_place_menu_item_new(FALSE); + gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menubar->priv->places_item); + + menubar->priv->desktop_item = panel_desktop_menu_item_new(FALSE, TRUE); + gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menubar->priv->desktop_item); + + panel_menu_bar_setup_tooltip(menubar); + + panel_menu_bar_update_text_gravity(menubar); + g_signal_connect(menubar, "screen-changed", G_CALLBACK(panel_menu_bar_update_text_gravity), NULL); +} + +static void panel_menu_bar_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +{ + PanelMenuBar* menubar; + + g_return_if_fail(PANEL_IS_MENU_BAR(object)); + + menubar = PANEL_MENU_BAR (object); + + switch (prop_id) + { + case PROP_ORIENTATION: + g_value_set_enum(value, menubar->priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void panel_menu_bar_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + PanelMenuBar* menubar; + + g_return_if_fail (PANEL_IS_MENU_BAR (object)); + + menubar = PANEL_MENU_BAR(object); + + switch (prop_id) + { + case PROP_ORIENTATION: + panel_menu_bar_set_orientation(menubar, g_value_get_enum(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void panel_menu_bar_parent_set(GtkWidget* widget, GtkWidget* previous_parent) +{ + PanelMenuBar* menubar = PANEL_MENU_BAR(widget); + GtkWidget* parent; + + parent = gtk_widget_get_parent(widget); + + g_assert(!parent || PANEL_IS_WIDGET(parent)); + + menubar->priv->panel = (PanelWidget*) parent; + + if (menubar->priv->applications_menu) + { + mate_panel_applet_menu_set_recurse(GTK_MENU(menubar->priv->applications_menu), "menu_panel", menubar->priv->panel); + } + + if (menubar->priv->places_item) + { + panel_place_menu_item_set_panel(menubar->priv->places_item, menubar->priv->panel); + } + + if (menubar->priv->desktop_item) + { + panel_desktop_menu_item_set_panel(menubar->priv->desktop_item, menubar->priv->panel); + } +} + +static void panel_menu_bar_size_allocate(GtkWidget* widget, GtkAllocation* allocation) +{ + GtkAllocation old_allocation; + GtkAllocation widget_allocation; + PanelBackground* background; + + gtk_widget_get_allocation(widget, &widget_allocation); + + old_allocation.x = widget_allocation.x; + old_allocation.y = widget_allocation.y; + old_allocation.width = widget_allocation.width; + old_allocation.height = widget_allocation.height; + + GTK_WIDGET_CLASS(panel_menu_bar_parent_class)->size_allocate (widget, allocation); + + if (old_allocation.x == allocation->x && old_allocation.y == allocation->y && old_allocation.width == allocation->width && old_allocation.height == allocation->height) + { + return; + } + + background = &PANEL_MENU_BAR(widget)->priv->panel->background; + + if (background->type == PANEL_BACK_NONE || (background->type == PANEL_BACK_COLOR && !background->has_alpha)) + { + return; + } + + panel_menu_bar_change_background(PANEL_MENU_BAR(widget)); +} + +static void panel_menu_bar_class_init(PanelMenuBarClass* klass) +{ + GObjectClass* gobject_class = (GObjectClass*) klass; + GtkWidgetClass* widget_class = (GtkWidgetClass*) klass; + + gobject_class->get_property = panel_menu_bar_get_property; + gobject_class->set_property = panel_menu_bar_set_property; + + widget_class->parent_set = panel_menu_bar_parent_set; + widget_class->size_allocate = panel_menu_bar_size_allocate; + + g_type_class_add_private(klass, sizeof(PanelMenuBarPrivate)); + + g_object_class_install_property(gobject_class, PROP_ORIENTATION, g_param_spec_enum("orientation", "Orientation", "The PanelMenuBar orientation", PANEL_TYPE_ORIENTATION, PANEL_ORIENTATION_TOP, G_PARAM_READWRITE)); + + gtk_rc_parse_string ( + "style \"panel-menubar-style\"\n" + "{\n" + " GtkMenuBar::shadow-type = none\n" + " GtkMenuBar::internal-padding = 0\n" + "}\n" + "class \"PanelMenuBar\" style \"panel-menubar-style\""); +} + +static gboolean panel_menu_bar_on_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data) +{ + PanelMenuBar* menubar = data; + + if (gtk_widget_has_focus(GTK_WIDGET(menubar))) + { + gtk_paint_focus(gtk_widget_get_style(widget), gtk_widget_get_window(widget), gtk_widget_get_state(GTK_WIDGET(menubar)), NULL, widget, "menubar-applet", 0, 0, -1, -1); + } + + return FALSE; +} + +static void panel_menu_bar_load(PanelWidget* panel, gboolean locked, int position, gboolean exactpos, const char* id) +{ + PanelMenuBar* menubar; + + g_return_if_fail (panel != NULL); + + menubar = g_object_new(PANEL_TYPE_MENU_BAR, NULL); + + menubar->priv->info = mate_panel_applet_register(GTK_WIDGET(menubar), NULL, NULL, panel, locked, position, exactpos, PANEL_OBJECT_MENU_BAR, id); + + if (!menubar->priv->info) + { + gtk_widget_destroy(GTK_WIDGET(menubar)); + return; + } + + mate_panel_applet_add_callback(menubar->priv->info, "help", GTK_STOCK_HELP, _("_Help"), NULL); + + /* Menu editors */ + if (panel_is_program_in_path("alacarte") || panel_is_program_in_path("matemenu-simple-editor")) + { + mate_panel_applet_add_callback (menubar->priv->info, "edit", NULL, _("_Edit Menus"), NULL); + } + + g_signal_connect_after(menubar, "focus-in-event", G_CALLBACK(gtk_widget_queue_draw), menubar); + g_signal_connect_after(menubar, "focus-out-event", G_CALLBACK(gtk_widget_queue_draw), menubar); + g_signal_connect_after(menubar, "expose-event", G_CALLBACK(panel_menu_bar_on_expose), menubar); + + gtk_widget_set_can_focus(GTK_WIDGET(menubar), TRUE); + + panel_widget_set_applet_expandable(panel, GTK_WIDGET(menubar), FALSE, TRUE); +} + +void panel_menu_bar_load_from_mateconf(PanelWidget* panel, gboolean locked, int position, gboolean exactpos, const char* id) +{ + panel_menu_bar_load(panel, locked, position, exactpos, id); +} + +void panel_menu_bar_create(PanelToplevel* toplevel, int position) +{ + char* id; + + id = panel_profile_prepare_object(PANEL_OBJECT_MENU_BAR, toplevel, position, FALSE); + panel_profile_add_to_list(PANEL_MATECONF_OBJECTS, id); + g_free(id); +} + +void panel_menu_bar_invoke_menu(PanelMenuBar* menubar, const char* callback_name) +{ + GdkScreen* screen; + + g_return_if_fail(PANEL_IS_MENU_BAR(menubar)); + g_return_if_fail(callback_name != NULL); + + screen = gtk_widget_get_screen(GTK_WIDGET(menubar)); + + if (!strcmp(callback_name, "help")) + { + panel_show_help(screen, "user-guide", "menubar", NULL); + + } + else if (!strcmp(callback_name, "edit")) + { + GError* error = NULL; + + panel_launch_desktop_file_with_fallback("alacarte.desktop", "alacarte", screen, &error); + + if (error) + { + g_error_free(error); + panel_launch_desktop_file_with_fallback("matemenu-simple-editor.desktop", "matemenu-simple-editor", screen, NULL); + } + } +} + +void panel_menu_bar_popup_menu(PanelMenuBar* menubar, guint32 activate_time) +{ + GtkMenu* menu; + GtkMenuShell* menu_shell; + + g_return_if_fail(PANEL_IS_MENU_BAR(menubar)); + + menu = GTK_MENU(menubar->priv->applications_menu); + + /* + * We need to call _gtk_menu_shell_activate() here as is done in + * window_key_press_handler in gtkmenubar.c which pops up menu + * when F10 is pressed. + * + * As that function is private its code is replicated here. + */ + menu_shell = GTK_MENU_SHELL(menubar); + + if (!menu_shell->active) + { + gtk_grab_add(GTK_WIDGET(menu_shell)); + + menu_shell->have_grab = TRUE; + menu_shell->active = TRUE; + } + + gtk_menu_shell_select_item(menu_shell, gtk_menu_get_attach_widget(menu)); +} + +void panel_menu_bar_change_background(PanelMenuBar* menubar) +{ + panel_background_change_background_on_widget(&menubar->priv->panel->background, GTK_WIDGET(menubar)); +} + +static void set_item_text_gravity(GtkWidget* item) +{ + GtkWidget* label; + PangoLayout* layout; + PangoContext* context; + + label = gtk_bin_get_child(GTK_BIN(item)); + layout = gtk_label_get_layout(GTK_LABEL(label)); + context = pango_layout_get_context(layout); + pango_context_set_base_gravity(context, PANGO_GRAVITY_AUTO); +} + +static void panel_menu_bar_update_text_gravity(PanelMenuBar* menubar) +{ + set_item_text_gravity(menubar->priv->applications_item); + set_item_text_gravity(menubar->priv->places_item); + set_item_text_gravity(menubar->priv->desktop_item); +} + +static void set_item_text_angle_and_alignment(GtkWidget* item, double text_angle, float xalign, float yalign) +{ + GtkWidget *label; + + label = gtk_bin_get_child (GTK_BIN (item)); + + gtk_label_set_angle (GTK_LABEL (label), text_angle); + + gtk_misc_set_alignment (GTK_MISC (label), xalign, yalign); +} + +static void panel_menu_bar_update_orientation(PanelMenuBar* menubar) +{ + GtkPackDirection pack_direction; + double text_angle; + float text_xalign; + float text_yalign; + + pack_direction = GTK_PACK_DIRECTION_LTR; + text_angle = 0.0; + text_xalign = 0.0; + text_yalign = 0.5; + + switch (menubar->priv->orientation) + { + case PANEL_ORIENTATION_TOP: + case PANEL_ORIENTATION_BOTTOM: + break; + case PANEL_ORIENTATION_LEFT: + pack_direction = GTK_PACK_DIRECTION_BTT; + text_angle = 90.0; + text_xalign = 0.5; + text_yalign = 0.0; + break; + case PANEL_ORIENTATION_RIGHT: + pack_direction = GTK_PACK_DIRECTION_TTB; + text_angle = 270.0; + text_xalign = 0.5; + text_yalign = 0.0; + break; + default: + g_assert_not_reached(); + break; + } + + gtk_menu_bar_set_pack_direction(GTK_MENU_BAR(menubar), pack_direction); + gtk_menu_bar_set_child_pack_direction(GTK_MENU_BAR(menubar), pack_direction); + + set_item_text_angle_and_alignment(menubar->priv->applications_item, text_angle, text_xalign, text_yalign); + set_item_text_angle_and_alignment(menubar->priv->places_item, text_angle, text_xalign, text_yalign); + set_item_text_angle_and_alignment(menubar->priv->desktop_item, text_angle, text_xalign, text_yalign); +} + +void panel_menu_bar_set_orientation(PanelMenuBar* menubar, PanelOrientation orientation) +{ + g_return_if_fail(PANEL_IS_MENU_BAR(menubar)); + + if (menubar->priv->orientation == orientation) + { + return; + } + + menubar->priv->orientation = orientation; + + panel_menu_bar_update_orientation(menubar); + + g_object_notify(G_OBJECT(menubar), "orientation"); +} + +PanelOrientation panel_menu_bar_get_orientation(PanelMenuBar* menubar) +{ + g_return_val_if_fail(PANEL_IS_MENU_BAR(menubar), 0); + + return menubar->priv->orientation; +} diff --git a/mate-panel/panel-menu-bar.h b/mate-panel/panel-menu-bar.h new file mode 100644 index 00000000..43672da9 --- /dev/null +++ b/mate-panel/panel-menu-bar.h @@ -0,0 +1,83 @@ +/* + * panel-menu-bar.h: panel Applications/Places/Desktop menu bar + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_MENU_BAR_H__ +#define __PANEL_MENU_BAR_H__ + +#include +#include "panel-widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_MENU_BAR (panel_menu_bar_get_type ()) +#define PANEL_MENU_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_MENU_BAR, PanelMenuBar)) +#define PANEL_MENU_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_MENU_BAR, PanelMenuBarClass)) +#define PANEL_IS_MENU_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_MENU_BAR)) +#define PANEL_IS_MENU_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_MENU_BAR)) +#define PANEL_MENU_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_MENU_BAR, PanelMenuBarClass)) + +typedef struct _PanelMenuBar PanelMenuBar; +typedef struct _PanelMenuBarClass PanelMenuBarClass; +typedef struct _PanelMenuBarPrivate PanelMenuBarPrivate; + +struct _PanelMenuBar{ + GtkMenuBar menubar; + + PanelMenuBarPrivate *priv; +}; + +struct _PanelMenuBarClass { + GtkMenuBarClass menubar_class; +}; + +GType panel_menu_bar_get_type (void) G_GNUC_CONST; + +void panel_menu_bar_create (PanelToplevel *toplevel, + int position); + +void panel_menu_bar_load_from_mateconf (PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id); + +void panel_menu_bar_invoke_menu (PanelMenuBar *menubar, + const char *callback_name); + +void panel_menu_bar_popup_menu (PanelMenuBar *menubar, + guint32 activate_time); + +void panel_menu_bar_change_background (PanelMenuBar *menubar); + +void panel_menu_bar_set_orientation (PanelMenuBar *menubar, + PanelOrientation orientation); +PanelOrientation panel_menu_bar_get_orientation (PanelMenuBar *menubar); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_MENU_BAR_H__ */ diff --git a/mate-panel/panel-menu-button.c b/mate-panel/panel-menu-button.c new file mode 100644 index 00000000..f173d0b5 --- /dev/null +++ b/mate-panel/panel-menu-button.c @@ -0,0 +1,1194 @@ +/* + * panel-menu-button.c: panel menu button + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-menu-button.h" + +#include +#include + +#include + +#include +#include +#include + +#include "applet.h" +#include "panel-widget.h" +#include "panel-util.h" +#include "panel-profile.h" +#include "panel-globals.h" +#include "menu.h" +#include "panel-lockdown.h" +#include "panel-a11y.h" +#include "panel-icon-names.h" + +G_DEFINE_TYPE (PanelMenuButton, panel_menu_button, BUTTON_TYPE_WIDGET) + +#define PANEL_MENU_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_MENU_BUTTON, PanelMenuButtonPrivate)) + +enum { + PROP_0, + PROP_MENU_PATH, + PROP_CUSTOM_ICON, + PROP_TOOLTIP, + PROP_USE_MENU_PATH, + PROP_USE_CUSTOM_ICON, + PROP_DND_ENABLED +}; + +typedef enum { + FIRST_MENU, + APPLICATIONS_MENU, +#define DEFAULT_MENU APPLICATIONS_MENU + SETTINGS_MENU, + LAST_MENU +} MenuPathRoot; + +typedef struct { + MenuPathRoot root_id; + char* scheme; + char* filename; +} MenuPathRootItem; + +static MenuPathRootItem root_items[] = { + {APPLICATIONS_MENU, "mate-applications", "mate-applications.menu"}, + {SETTINGS_MENU, "mate-settings", "mate-settings.menu"} +}; + +struct _PanelMenuButtonPrivate { + PanelToplevel *toplevel; + guint mateconf_notify; + char *applet_id; + + GtkWidget *menu; + + char *menu_path; + char *custom_icon; + char *tooltip; + + MenuPathRoot path_root; + guint use_menu_path : 1; + guint use_custom_icon : 1; + guint dnd_enabled : 1; +}; + +static void panel_menu_button_disconnect_from_mateconf (PanelMenuButton *button); +static void panel_menu_button_recreate_menu (PanelMenuButton *button); +static void panel_menu_button_set_icon (PanelMenuButton *button); + +static AtkObject *panel_menu_button_get_accessible (GtkWidget *widget); + +static const char * +panel_menu_path_root_to_filename (MenuPathRoot path_root) +{ + const char *retval; + int i; + + retval = NULL; + + for (i = 0; i < G_N_ELEMENTS (root_items); i++) { + if (root_items [i].root_id == path_root) { + retval = root_items [i].filename; + break; + } + } + + return retval; +} + +static const char * +panel_menu_filename_to_scheme (const char *filename) +{ + const char *retval; + int i; + + retval = NULL; + + if (!filename) + return retval; + + for (i = 0; i < G_N_ELEMENTS (root_items); i++) { + if (root_items [i].filename && + !strncmp (filename, root_items [i].filename, + strlen (root_items [i].filename))) { + retval = root_items [i].scheme; + break; + } + } + + return retval; +} + +static MenuPathRoot +panel_menu_scheme_to_path_root (const char *scheme) +{ + MenuPathRoot retval; + int i; + + retval = LAST_MENU; + + if (!scheme) + return retval; + + for (i = 0; i < G_N_ELEMENTS (root_items); i++) { + if (root_items [i].scheme && + !strncmp (scheme, root_items [i].scheme, + strlen (root_items [i].scheme))) { + retval = root_items [i].root_id; + break; + } + } + + return retval; +} + +static void +panel_menu_button_init (PanelMenuButton *button) +{ + button->priv = PANEL_MENU_BUTTON_GET_PRIVATE (button); + + button->priv->applet_id = NULL; + button->priv->toplevel = NULL; + button->priv->mateconf_notify = 0; + + button->priv->menu_path = NULL; + button->priv->custom_icon = NULL; + button->priv->tooltip = NULL; + + button->priv->path_root = LAST_MENU; + button->priv->use_menu_path = FALSE; + button->priv->use_custom_icon = FALSE; +} + +static void +panel_menu_button_finalize (GObject *object) +{ + PanelMenuButton *button = PANEL_MENU_BUTTON (object); + + panel_lockdown_notify_remove (G_CALLBACK (panel_menu_button_recreate_menu), + button); + + panel_menu_button_disconnect_from_mateconf (button); + + if (button->priv->menu) { + /* detaching the menu will kill our reference */ + gtk_menu_detach (GTK_MENU (button->priv->menu)); + button->priv->menu = NULL; + } + + g_free (button->priv->applet_id); + button->priv->applet_id = NULL; + + g_free (button->priv->menu_path); + button->priv->menu_path = NULL; + + g_free (button->priv->custom_icon); + button->priv->custom_icon = NULL; + + g_free (button->priv->tooltip); + button->priv->tooltip = NULL; + + G_OBJECT_CLASS (panel_menu_button_parent_class)->finalize (object); +} + +static void +panel_menu_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelMenuButton *button; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (object)); + + button = PANEL_MENU_BUTTON (object); + + switch (prop_id) { + case PROP_MENU_PATH: + g_value_set_string (value, button->priv->menu_path); + break; + case PROP_CUSTOM_ICON: + g_value_set_string (value, button->priv->custom_icon); + break; + case PROP_TOOLTIP: + g_value_set_string (value, button->priv->tooltip); + break; + case PROP_USE_MENU_PATH: + g_value_set_boolean (value, button->priv->use_menu_path); + break; + case PROP_USE_CUSTOM_ICON: + g_value_set_boolean (value, button->priv->use_custom_icon); + break; + case PROP_DND_ENABLED: + g_value_set_boolean (value, button->priv->dnd_enabled); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_menu_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PanelMenuButton *button; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (object)); + + button = PANEL_MENU_BUTTON (object); + + switch (prop_id) { + case PROP_MENU_PATH: + panel_menu_button_set_menu_path (button, g_value_get_string (value)); + break; + case PROP_CUSTOM_ICON: + panel_menu_button_set_custom_icon (button, g_value_get_string (value)); + break; + case PROP_TOOLTIP: + panel_menu_button_set_tooltip (button, g_value_get_string (value)); + break; + case PROP_USE_MENU_PATH: + panel_menu_button_set_use_menu_path (button, g_value_get_boolean (value)); + break; + case PROP_USE_CUSTOM_ICON: + panel_menu_button_set_use_custom_icon (button, g_value_get_boolean (value)); + break; + case PROP_DND_ENABLED: + panel_menu_button_set_dnd_enabled (button, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_menu_button_associate_panel (PanelMenuButton *button) +{ + PanelWidget *panel_widget = NULL; + + if (!button->priv->menu) + return; + + if (button->priv->toplevel) + panel_widget = panel_toplevel_get_panel_widget (button->priv->toplevel); + + mate_panel_applet_menu_set_recurse (GTK_MENU (button->priv->menu), "menu_panel", panel_widget); +} + +static void +panel_menu_button_parent_set (GtkWidget *widget, + GtkWidget *previous_parent) +{ + PanelMenuButton *button = PANEL_MENU_BUTTON (widget); + GtkWidget *parent; + + parent = gtk_widget_get_parent (widget); + g_return_if_fail (!parent || PANEL_IS_WIDGET (parent)); + + if (parent) + button->priv->toplevel = PANEL_WIDGET (parent)->toplevel; + else + button->priv->toplevel = NULL; + + panel_menu_button_associate_panel (button); + panel_menu_button_set_icon (button); + + if (GTK_WIDGET_CLASS (panel_menu_button_parent_class)->parent_set) + GTK_WIDGET_CLASS (panel_menu_button_parent_class)->parent_set (widget, previous_parent); +} + +static void +panel_menu_button_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + char *drag_data; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (widget)); + + drag_data = g_strdup_printf ("MENU:%d", panel_find_applet_index (widget)); + + gtk_selection_data_set ( + selection_data, gtk_selection_data_get_target (selection_data), + 8, (guchar *) drag_data, strlen (drag_data)); + + g_free (drag_data); +} + +static void +panel_menu_button_menu_deactivated (PanelMenuButton *button) +{ + panel_toplevel_pop_autohide_disabler (button->priv->toplevel); + + GTK_BUTTON (button)->in_button = FALSE; + button_widget_set_ignore_leave (BUTTON_WIDGET (button), FALSE); +} + +static void +panel_menu_button_menu_detacher (PanelMenuButton *button) +{ + /* + * just in case someone still owns a reference to the + * menu (the menu may be up or some such other nonsense) + */ + g_signal_handlers_disconnect_by_func (button->priv->menu, + G_CALLBACK (panel_menu_button_menu_deactivated), + button); + + button->priv->menu = NULL; +} + +static GtkWidget * +panel_menu_button_create_menu (PanelMenuButton *button) +{ + PanelWidget *panel_widget; + + if (button->priv->menu) + return button->priv->menu; + + if (!button->priv->toplevel) + return NULL; + + panel_widget = panel_toplevel_get_panel_widget (button->priv->toplevel); + + if (button->priv->use_menu_path && + button->priv->path_root > FIRST_MENU && + button->priv->path_root < LAST_MENU) { + const char *filename; + + filename = panel_menu_path_root_to_filename (button->priv->path_root); + button->priv->menu = create_applications_menu (filename, + button->priv->menu_path, + TRUE); + } else + button->priv->menu = create_main_menu (panel_widget); + + gtk_menu_attach_to_widget (GTK_MENU (button->priv->menu), + GTK_WIDGET (button), + (GtkMenuDetachFunc) panel_menu_button_menu_detacher); + + panel_menu_button_associate_panel (button); + + g_signal_connect_swapped (button->priv->menu, "deactivate", + G_CALLBACK (panel_menu_button_menu_deactivated), + button); + + return button->priv->menu; +} + +static void +panel_menu_button_recreate_menu (PanelMenuButton *button) +{ + if (button->priv->menu) + gtk_widget_destroy (button->priv->menu); + button->priv->menu = NULL; +} + +void +panel_menu_button_popup_menu (PanelMenuButton *button, + guint n_button, + guint32 activate_time) +{ + GdkScreen *screen; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + panel_menu_button_create_menu (button); + + panel_toplevel_push_autohide_disabler (button->priv->toplevel); + + button_widget_set_ignore_leave (BUTTON_WIDGET (button), TRUE); + + screen = gtk_window_get_screen (GTK_WINDOW (button->priv->toplevel)); + gtk_menu_set_screen (GTK_MENU (button->priv->menu), screen); + + gtk_menu_popup (GTK_MENU (button->priv->menu), + NULL, + NULL, + (GtkMenuPositionFunc) mate_panel_applet_position_menu, + GTK_WIDGET (button), + n_button, + activate_time); +} + +static void +panel_menu_button_pressed (GtkButton *gtk_button) +{ + PanelMenuButton *button; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (gtk_button)); + + button = PANEL_MENU_BUTTON (gtk_button); + + if (GTK_BUTTON_CLASS (panel_menu_button_parent_class)->pressed) + GTK_BUTTON_CLASS (panel_menu_button_parent_class)->pressed (gtk_button); + + panel_menu_button_popup_menu (button, 0, gtk_get_current_event_time()); +} + +static void +panel_menu_button_clicked (GtkButton *gtk_button) +{ + PanelMenuButton *button; + GdkEvent *event; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (gtk_button)); + + button = PANEL_MENU_BUTTON (gtk_button); + + if (GTK_BUTTON_CLASS (panel_menu_button_parent_class)->clicked) + GTK_BUTTON_CLASS (panel_menu_button_parent_class)->clicked (gtk_button); + + if ((event = gtk_get_current_event ())) { + panel_menu_button_popup_menu (button, + event->button.button, + event->button.time); + gdk_event_free (event); + } else { + panel_menu_button_popup_menu (button, 1, GDK_CURRENT_TIME); + } +} + +static void +panel_menu_button_class_init (PanelMenuButtonClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + GtkButtonClass *button_class = (GtkButtonClass *) klass; + + gobject_class->finalize = panel_menu_button_finalize; + gobject_class->get_property = panel_menu_button_get_property; + gobject_class->set_property = panel_menu_button_set_property; + + widget_class->parent_set = panel_menu_button_parent_set; + widget_class->drag_data_get = panel_menu_button_drag_data_get; + widget_class->get_accessible = panel_menu_button_get_accessible; + + button_class->clicked = panel_menu_button_clicked; + button_class->pressed = panel_menu_button_pressed; + + g_type_class_add_private (klass, sizeof (PanelMenuButtonPrivate)); + + g_object_class_install_property ( + gobject_class, + PROP_MENU_PATH, + g_param_spec_string ("menu-path", + "Menu Path", + "The path from which to construct the menu", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_CUSTOM_ICON, + g_param_spec_string ("custom-icon", + "Custom Icon", + "The custom icon for the menu", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_TOOLTIP, + g_param_spec_string ("tooltip", + "Tooltip", + "Tooltip displayed for the menu", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_USE_MENU_PATH, + g_param_spec_boolean ("use-menu-path", + "Use Menu Path", + "Use the path specified by the menu-path property", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_USE_CUSTOM_ICON, + g_param_spec_boolean ("use-custom-icon", + "Use Custom Icon", + "Use the icon specified by the custom-icon property", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + gobject_class, + PROP_DND_ENABLED, + g_param_spec_boolean ("dnd-enabled", + "Drag and drop enabled", + "Whether or not drag and drop is enabled on the widget", + FALSE, + G_PARAM_READWRITE)); +} + +static void +panel_menu_button_mateconf_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelMenuButton *button) +{ + MateConfValue *value; + const char *key; + + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + + value = entry->value; + + if (!strcmp (key, "menu_path")) { + if (value && value->type == MATECONF_VALUE_STRING) + panel_menu_button_set_menu_path (button, + mateconf_value_get_string (value)); + } else if (!strcmp (key, "custom_icon")) { + if (value && value->type == MATECONF_VALUE_STRING) + panel_menu_button_set_custom_icon (button, + mateconf_value_get_string (value)); + } else if (!strcmp (key, "tooltip")) { + if (value && value->type == MATECONF_VALUE_STRING) + panel_menu_button_set_tooltip (button, + mateconf_value_get_string (value)); + } else if (!strcmp (key, "use_menu_path")) { + if (value && value->type == MATECONF_VALUE_BOOL) + panel_menu_button_set_use_menu_path (button, + mateconf_value_get_bool (value)); + } else if (!strcmp (key, "use_custom_icon")) { + if (value && value->type == MATECONF_VALUE_BOOL) + panel_menu_button_set_use_custom_icon (button, + mateconf_value_get_bool (value)); + } +} + +static void +panel_menu_button_connect_to_mateconf (PanelMenuButton *button) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/objects/%s", + button->priv->applet_id); + mateconf_client_add_dir (client, key, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL); + button->priv->mateconf_notify = + mateconf_client_notify_add (client, key, + (MateConfClientNotifyFunc) panel_menu_button_mateconf_notify, + button, NULL, NULL); +} + +static void +panel_menu_button_disconnect_from_mateconf (PanelMenuButton *button) +{ + MateConfClient *client; + const char *key; + + if (!button->priv->mateconf_notify) + return; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/objects/%s", + button->priv->applet_id); + + mateconf_client_notify_remove (client, button->priv->mateconf_notify); + button->priv->mateconf_notify = 0; + + mateconf_client_remove_dir (client, key, NULL); +} + +static void +panel_menu_button_load (const char *menu_path, + gboolean use_menu_path, + const char *custom_icon, + gboolean use_custom_icon, + const char *tooltip, + PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id) +{ + PanelMenuButton *button; + AppletInfo *info; + + g_return_if_fail (panel != NULL); + + button = g_object_new (PANEL_TYPE_MENU_BUTTON, + "menu-path", menu_path, + "custom-icon", custom_icon, + "tooltip", tooltip, + "use-menu-path", use_menu_path, + "use-custom-icon", use_custom_icon, + "has-arrow", TRUE, + NULL); + + info = mate_panel_applet_register (GTK_WIDGET (button), NULL, NULL, + panel, locked, position, exactpos, + PANEL_OBJECT_MENU, id); + if (!info) { + gtk_widget_destroy (GTK_WIDGET (button)); + return; + } + + button->priv->applet_id = g_strdup (info->id); + + mate_panel_applet_add_callback (info, "help", GTK_STOCK_HELP, _("_Help"), NULL); + + if (panel_is_program_in_path ("alacarte") || + panel_is_program_in_path ("matemenu-simple-editor")) + mate_panel_applet_add_callback (info, "edit", NULL, + _("_Edit Menus"), NULL); + + panel_widget_set_applet_expandable (panel, GTK_WIDGET (button), FALSE, TRUE); + panel_widget_set_applet_size_constrained (panel, GTK_WIDGET (button), TRUE); + + panel_menu_button_connect_to_mateconf (button); + + panel_lockdown_notify_add (G_CALLBACK (panel_menu_button_recreate_menu), + button); +} + +static char * +panel_menu_button_get_icon (PanelMenuButton *button) +{ + MateMenuTreeDirectory *directory; + char *retval; + + retval = NULL; + + if (button->priv->use_custom_icon && + button->priv->custom_icon) + retval = g_strdup (button->priv->custom_icon); + + if (!retval && + button->priv->use_menu_path && + button->priv->menu_path && + panel_menu_button_create_menu (button)) { + directory = g_object_get_data (G_OBJECT (button->priv->menu), + "panel-menu-tree-directory"); + + if (!directory) { + MateMenuTree *tree; + + if ((tree = g_object_get_data (G_OBJECT (button->priv->menu), + "panel-menu-tree"))) { + directory = matemenu_tree_get_directory_from_path (tree, + button->priv->menu_path); + g_object_set_data_full (G_OBJECT (button->priv->menu), + "panel-menu-tree-directory", + directory, + (GDestroyNotify) matemenu_tree_item_unref); + } + } + + if (directory) + retval = g_strdup (matemenu_tree_directory_get_icon (directory)); + } + + if (!retval) + retval = g_strdup (PANEL_ICON_MAIN_MENU); + + return retval; +} + +static void +panel_menu_button_set_icon (PanelMenuButton *button) +{ + char *icon_path; + + icon_path = panel_menu_button_get_icon (button); + button_widget_set_icon_name (BUTTON_WIDGET (button), icon_path); + + g_free (icon_path); +} + +static const char * +split_menu_uri (const char *menu_uri, + char **menu_scheme) +{ + char *p; + + if (!menu_uri) + return NULL; + + p = strchr (menu_uri, ':'); + + if (!p || p == menu_uri) + return NULL; + + if (menu_scheme) + *menu_scheme = g_strndup (menu_uri, p - menu_uri); + + if (*(++p) != '/') + return NULL; + + while (*p != '\0' && *(p + 1) == '/') p++; + + return p; +} + +void +panel_menu_button_set_menu_path (PanelMenuButton *button, + const char *menu_uri) +{ + const char *menu_path; + char *scheme; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + scheme = NULL; + menu_path = split_menu_uri (menu_uri, &scheme); + + if (!scheme) + return; + + button->priv->path_root = panel_menu_scheme_to_path_root (scheme); + g_free (scheme); + + if (!button->priv->menu_path && (!menu_path || !menu_path [0])) + return; + + if (button->priv->menu_path && menu_path && + !strcmp (button->priv->menu_path, menu_path)) + return; + + g_free (button->priv->menu_path); + button->priv->menu_path = NULL; + + button->priv->menu_path = g_strdup (menu_path); + + if (button->priv->menu) + gtk_menu_detach (GTK_MENU (button->priv->menu)); + button->priv->menu = NULL; + + panel_menu_button_set_icon (button); +} + +void +panel_menu_button_set_custom_icon (PanelMenuButton *button, + const char *custom_icon) +{ + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + g_free (button->priv->custom_icon); + button->priv->custom_icon = NULL; + + if (custom_icon && custom_icon [0]) + button->priv->custom_icon = g_strdup (custom_icon); + + panel_menu_button_set_icon (button); +} + +void +panel_menu_button_set_tooltip (PanelMenuButton *button, + const char *tooltip) +{ + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + g_free (button->priv->tooltip); + button->priv->tooltip = NULL; + + if (tooltip && tooltip [0]) { + button->priv->tooltip = g_strdup (tooltip); + panel_util_set_tooltip_text (GTK_WIDGET (button), tooltip); + } +} + +void +panel_menu_button_set_use_menu_path (PanelMenuButton *button, + gboolean use_menu_path) +{ + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + use_menu_path = use_menu_path != FALSE; + + if (button->priv->use_menu_path == use_menu_path) + return; + + button->priv->use_menu_path = use_menu_path; + + if (button->priv->menu) + gtk_menu_detach (GTK_MENU (button->priv->menu)); + button->priv->menu = NULL; + + panel_menu_button_set_icon (button); +} + +gboolean +panel_menu_button_get_use_menu_path (PanelMenuButton *button) +{ + g_return_val_if_fail (PANEL_IS_MENU_BUTTON (button), FALSE); + + return button->priv->use_menu_path; +} + +void +panel_menu_button_set_use_custom_icon (PanelMenuButton *button, + gboolean use_custom_icon) +{ + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + button->priv->use_custom_icon = use_custom_icon != FALSE; + + panel_menu_button_set_icon (button); +} + +void +panel_menu_button_load_from_mateconf (PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id) +{ + MateConfClient *client; + const char *key; + char *menu_path; + char *custom_icon; + char *tooltip; + gboolean use_menu_path; + gboolean use_custom_icon; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "menu_path"); + menu_path = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "custom_icon"); + custom_icon = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "tooltip"); + tooltip = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "use_menu_path"); + use_menu_path = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "use_custom_icon"); + use_custom_icon = mateconf_client_get_bool (client, key, NULL); + + panel_menu_button_load (menu_path, + use_menu_path, + custom_icon, + use_custom_icon, + tooltip, + panel, + locked, + position, + exactpos, + id); + + g_free (menu_path); + g_free (custom_icon); + g_free (tooltip); +} + +gboolean +panel_menu_button_create (PanelToplevel *toplevel, + int position, + const char *filename, + const char *menu_path, + gboolean use_menu_path, + const char *tooltip) +{ + MateConfClient *client; + const char *scheme; + const char *key; + char *id; + + client = panel_mateconf_get_client (); + + id = panel_profile_prepare_object (PANEL_OBJECT_MENU, toplevel, position, FALSE); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "use_menu_path"); + mateconf_client_set_bool (client, key, use_menu_path, NULL); + + scheme = panel_menu_filename_to_scheme (filename); + + if (filename && !scheme) { + g_warning ("Failed to find menu scheme for %s\n", filename); + g_free (id); + return FALSE; + } + + if (use_menu_path && menu_path && menu_path [0] && scheme) { + char *menu_uri; + + menu_uri = g_strconcat (scheme, ":", menu_path, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "menu_path"); + mateconf_client_set_string (client, key, menu_uri, NULL); + + g_free (menu_uri); + } + + if (tooltip && tooltip [0]) { + key = panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, "tooltip"); + mateconf_client_set_string (client, key, tooltip, NULL); + } + + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + g_free (id); + + return TRUE; +} + +void +panel_menu_button_invoke_menu (PanelMenuButton *button, + const char *callback_name) +{ + GdkScreen *screen; + + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + g_return_if_fail (callback_name != NULL); + + screen = gtk_widget_get_screen (GTK_WIDGET (button)); + + if (!strcmp (callback_name, "help")) { + panel_show_help (screen, "user-guide", "gospanel-37", NULL); + + } else if (!strcmp (callback_name, "edit")) { + GError *error = NULL; + + panel_launch_desktop_file_with_fallback ("alacarte.desktop", + "alacarte", + screen, &error); + if (error) { + g_error_free (error); + panel_launch_desktop_file_with_fallback ( + "matemenu-simple-editor.desktop", + "matemenu-simple-editor", + screen, NULL); + } + } +} + +void +panel_menu_button_set_dnd_enabled (PanelMenuButton *button, + gboolean dnd_enabled) +{ + g_return_if_fail (PANEL_IS_MENU_BUTTON (button)); + + dnd_enabled = dnd_enabled != FALSE; + + if (button->priv->dnd_enabled == dnd_enabled) + return; + + if (dnd_enabled) { + static GtkTargetEntry dnd_targets [] = { + { "application/x-mate-panel-applet-internal", 0, 0 } + }; + char *icon; + + gtk_widget_set_has_window (GTK_WIDGET (button), TRUE); + gtk_drag_source_set (GTK_WIDGET (button), GDK_BUTTON1_MASK, + dnd_targets, 1, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + icon = panel_menu_button_get_icon (button); + if (icon != NULL) { + gtk_drag_source_set_icon_name (GTK_WIDGET (button), + icon); + g_free (icon); + } + + gtk_widget_set_has_window (GTK_WIDGET (button), FALSE); + } else + gtk_drag_source_unset (GTK_WIDGET (button)); +} + +/* + * An AtkObject implementation for PanelMenuButton. + * We need all this just so we can create the menu in ref_child() + * + * See http://bugzilla.gnome.org/show_bug.cgi?id=138535 for details + * + * If we ever remove the on-demand creation of the menu, we should + * can just remove all this again + */ + +#define PANEL_IS_MENU_BUTTON_ACCESSIBLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), panel_menu_button_accessible_get_type ())) + +static GType panel_menu_button_accessible_get_type (void); +static gpointer parent_accessible_class = NULL; + +static int +panel_menu_button_accessible_get_n_children (AtkObject *obj) +{ + g_return_val_if_fail (PANEL_IS_MENU_BUTTON_ACCESSIBLE (obj), 0); + +#if GTK_CHECK_VERSION (2, 21, 0) + return gtk_accessible_get_widget (GTK_ACCESSIBLE (obj)) ? 1 : 0; +#else + return GTK_ACCESSIBLE (obj)->widget ? 1 : 0; +#endif +} + +static AtkObject * +panel_menu_button_accessible_ref_child (AtkObject *obj, + int index) +{ + PanelMenuButton *button; + GtkWidget *menu; + + g_return_val_if_fail (PANEL_IS_MENU_BUTTON_ACCESSIBLE (obj), NULL); + + if (index != 0) + return NULL; + +#if GTK_CHECK_VERSION (2, 21, 0) + if (!(button = PANEL_MENU_BUTTON (gtk_accessible_get_widget (GTK_ACCESSIBLE (obj))))) +#else + if (!(button = PANEL_MENU_BUTTON (GTK_ACCESSIBLE (obj)->widget))) +#endif + return NULL; + + if (!(menu = panel_menu_button_create_menu (button))) + return NULL; + /* + * This ensures that the menu is populated with all menu items + */ + g_signal_emit_by_name (menu, "show", NULL); + + return g_object_ref (gtk_widget_get_accessible (menu)); +} + +static const gchar* panel_menu_button_accessible_get_name(AtkObject* obj) +{ + const char* name; + + name = ATK_OBJECT_CLASS(parent_accessible_class)->get_name(obj); + + if (name == NULL) + { + name = _("Main Menu"); + } + + return name; +} + +static void +panel_menu_button_accessible_class_init (AtkObjectClass *klass) +{ + klass->get_n_children = panel_menu_button_accessible_get_n_children; + klass->ref_child = panel_menu_button_accessible_ref_child; + klass->get_name = panel_menu_button_accessible_get_name; + + parent_accessible_class = g_type_class_peek_parent (klass); +} + +static GType +panel_menu_button_accessible_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo type_info = { 0 }; + GType accessible_parent_type; + + type_info.class_init = + (GClassInitFunc) panel_menu_button_accessible_class_init; + + accessible_parent_type = + panel_a11y_query_accessible_parent_type (PANEL_TYPE_MENU_BUTTON, + &type_info); + + type = g_type_register_static (accessible_parent_type, + "PanelMenuButtonAccessible", + &type_info, 0); + } + + return type; +} + +static AtkObject * +panel_menu_button_accessible_new (GObject *obj) +{ + AtkObject *accessible; + + g_return_val_if_fail (PANEL_IS_MENU_BUTTON (obj), NULL); + + accessible = g_object_new (panel_menu_button_accessible_get_type (), NULL); + atk_object_initialize (accessible, obj); + + return accessible; +} + +static void +panel_menu_button_accessible_factory_class_init (AtkObjectFactoryClass *klass) +{ + klass->create_accessible = panel_menu_button_accessible_new; + klass->get_accessible_type = panel_menu_button_accessible_get_type; +} + +static GType +panel_menu_button_accessible_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (AtkObjectFactoryClass), + NULL, + NULL, + (GClassInitFunc) panel_menu_button_accessible_factory_class_init, + NULL, + NULL, + sizeof (AtkObjectFactory), + 0, + NULL, + NULL + }; + + type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY, + "PanelMenuButtonAccessibleFactory", + &info, 0); + } + + return type; +} + +static AtkObject * +panel_menu_button_get_accessible (GtkWidget *widget) +{ + static gboolean first_time = TRUE; + + g_return_val_if_fail (widget != NULL, NULL); + + if (first_time && panel_a11y_get_is_a11y_enabled (widget)) + atk_registry_set_factory_type (atk_get_default_registry (), + PANEL_TYPE_MENU_BUTTON, + panel_menu_button_accessible_factory_get_type ()); + + first_time = FALSE; + + return GTK_WIDGET_CLASS (panel_menu_button_parent_class)->get_accessible (widget); +} diff --git a/mate-panel/panel-menu-button.h b/mate-panel/panel-menu-button.h new file mode 100644 index 00000000..c6c9d564 --- /dev/null +++ b/mate-panel/panel-menu-button.h @@ -0,0 +1,98 @@ +/* + * panel-menu-button.h: panel menu button + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_MENU_BUTTON_H__ +#define __PANEL_MENU_BUTTON_H__ + +#include +#include "button-widget.h" +#include "panel-widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_MENU_BUTTON (panel_menu_button_get_type ()) +#define PANEL_MENU_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_MENU_BUTTON, PanelMenuButton)) +#define PANEL_MENU_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_MENU_BUTTON, PanelMenuButtonClass)) +#define PANEL_IS_MENU_BUTTON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_MENU_BUTTON)) +#define PANEL_IS_MENU_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_MENU_BUTTON)) +#define PANEL_MENU_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_MENU_BUTTON, PanelMenuButtonClass)) + +typedef struct _PanelMenuButton PanelMenuButton; +typedef struct _PanelMenuButtonClass PanelMenuButtonClass; +typedef struct _PanelMenuButtonPrivate PanelMenuButtonPrivate; + +struct _PanelMenuButton { + ButtonWidget button; + + PanelMenuButtonPrivate *priv; +}; + +struct _PanelMenuButtonClass { + ButtonWidgetClass button_class; +}; + +GType panel_menu_button_get_type (void) G_GNUC_CONST; + +gboolean panel_menu_button_create (PanelToplevel *toplevel, + int position, + const char *filename, + const char *menu_path, + gboolean use_menu_path, + const char *tooltip); + +void panel_menu_button_set_menu_path (PanelMenuButton *button, + const char *menu_path); +void panel_menu_button_set_custom_icon (PanelMenuButton *button, + const char *custom_icon); +void panel_menu_button_set_tooltip (PanelMenuButton *button, + const char *tooltip); +void panel_menu_button_set_use_menu_path (PanelMenuButton *button, + gboolean use_menu_path); +gboolean panel_menu_button_get_use_menu_path (PanelMenuButton *button); +void panel_menu_button_set_use_custom_icon (PanelMenuButton *button, + gboolean use_custom_icon); + +void panel_menu_button_load_from_mateconf (PanelWidget *panel, + gboolean locked, + int position, + gboolean exactpos, + const char *id); + +void panel_menu_button_invoke_menu (PanelMenuButton *button, + const char *callback_name); + +void panel_menu_button_popup_menu (PanelMenuButton *button, + guint n_button, + guint32 activate_time); + +void panel_menu_button_set_dnd_enabled (PanelMenuButton *button, + gboolean dnd_enabled); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_MENU_BUTTON_H__ */ diff --git a/mate-panel/panel-menu-items.c b/mate-panel/panel-menu-items.c new file mode 100644 index 00000000..7f790676 --- /dev/null +++ b/mate-panel/panel-menu-items.c @@ -0,0 +1,1618 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2005 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + * + * Based on code from panel-menu-bar.c + */ + +/* + * TODO: + * + drag and drop loses icon for URIs + * + drag and drop of bookmarks/network places/removable media should create + * a menu button + * + if a menu is open and gets updated, it should reappear and not just + * disappear + */ + +#include + +#include "panel-menu-items.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "menu.h" +#include "panel-action-button.h" +#include "panel-globals.h" +#include "panel-icon-names.h" +#include "panel-lockdown.h" +#include "panel-recent.h" +#include "panel-stock-icons.h" +#include "panel-util.h" + +#define BOOKMARKS_FILENAME ".gtk-bookmarks" +#define DESKTOP_IS_HOME_DIR_DIR "/apps/caja/preferences" +#define DESKTOP_IS_HOME_DIR_KEY "/apps/caja/preferences/desktop_is_home_dir" +#define NAMES_DIR "/apps/caja/desktop" +#define HOME_NAME_KEY "/apps/caja/desktop/home_icon_name" +#define COMPUTER_NAME_KEY "/apps/caja/desktop/computer_icon_name" +#define MAX_ITEMS_OR_SUBMENU 5 +#define MAX_BOOKMARK_ITEMS 100 + +G_DEFINE_TYPE(PanelPlaceMenuItem, panel_place_menu_item, GTK_TYPE_IMAGE_MENU_ITEM) +G_DEFINE_TYPE(PanelDesktopMenuItem, panel_desktop_menu_item, GTK_TYPE_IMAGE_MENU_ITEM) + +#define PANEL_PLACE_MENU_ITEM_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), PANEL_TYPE_PLACE_MENU_ITEM, PanelPlaceMenuItemPrivate)) +#define PANEL_DESKTOP_MENU_ITEM_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), PANEL_TYPE_DESKTOP_MENU_ITEM, PanelDesktopMenuItemPrivate)) + +struct _PanelPlaceMenuItemPrivate { + GtkWidget *menu; + PanelWidget *panel; + + GtkRecentManager *recent_manager; + + GFileMonitor *bookmarks_monitor; + + GVolumeMonitor *volume_monitor; + gulong drive_changed_id; + gulong drive_connected_id; + gulong drive_disconnected_id; + gulong volume_added_id; + gulong volume_changed_id; + gulong volume_removed_id; + gulong mount_added_id; + gulong mount_changed_id; + gulong mount_removed_id; + + guint use_image : 1; +}; + +struct _PanelDesktopMenuItemPrivate { + GtkWidget *menu; + PanelWidget *panel; + + guint use_image : 1; + guint append_lock_logout : 1; +}; + +static void activate_uri_on_screen(const char* uri, GdkScreen* screen) +{ + panel_show_uri(screen, uri, gtk_get_current_event_time(), NULL); +} + +static void +activate_uri (GtkWidget *menuitem, + const char *uri) +{ + activate_uri_on_screen (uri, menuitem_to_screen (menuitem)); +} + +static void +activate_path (GtkWidget *menuitem, + const char *path) +{ + char *uri; + + uri = g_filename_to_uri (path, NULL, NULL); + activate_uri_on_screen (uri, menuitem_to_screen (menuitem)); + g_free (uri); +} + +static void +activate_home_uri (GtkWidget *menuitem, + gpointer data) +{ + activate_path (menuitem, g_get_home_dir ()); +} + +static void +activate_desktop_uri (GtkWidget *menuitem, + gpointer data) +{ + activate_path (menuitem, + g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); +} + +static void +panel_menu_items_append_from_desktop (GtkWidget *menu, + char *path, + char *force_name, + gboolean use_icon) +{ + GKeyFile *key_file; + gboolean loaded; + GtkWidget *item; + char *path_freeme; + char *full_path; + char *uri; + char *type; + gboolean is_application; + char *tryexec; + char *icon; + char *name; + char *comment; + + path_freeme = NULL; + + key_file = g_key_file_new (); + + if (g_path_is_absolute (path)) { + loaded = g_key_file_load_from_file (key_file, path, + G_KEY_FILE_NONE, NULL); + full_path = path; + } else { + char *lookup_file; + char *desktop_path; + + if (!g_str_has_suffix (path, ".desktop")) { + desktop_path = g_strconcat (path, ".desktop", NULL); + } else { + desktop_path = path; + } + + lookup_file = g_strconcat ("applications", G_DIR_SEPARATOR_S, + desktop_path, NULL); + loaded = g_key_file_load_from_data_dirs (key_file, lookup_file, + &path_freeme, + G_KEY_FILE_NONE, + NULL); + full_path = path_freeme; + g_free (lookup_file); + + if (desktop_path != path) + g_free (desktop_path); + } + + if (!loaded) { + g_key_file_free (key_file); + if (path_freeme) + g_free (path_freeme); + return; + } + + /* For Application desktop files, respect TryExec */ + type = panel_key_file_get_string (key_file, "Type"); + if (!type) { + g_key_file_free (key_file); + if (path_freeme) + g_free (path_freeme); + return; + } + is_application = (strcmp (type, "Application") == 0); + g_free (type); + + if (is_application) { + tryexec = panel_key_file_get_string (key_file, "TryExec"); + if (tryexec) { + char *prog; + + prog = g_find_program_in_path (tryexec); + g_free (tryexec); + + if (!prog) { + /* FIXME: we could add some file monitor magic, + * so that the menu items appears when the + * program appears, but that's really complex + * for not a huge benefit */ + g_key_file_free (key_file); + if (path_freeme) + g_free (path_freeme); + return; + } + + g_free (prog); + } + } + + /* Now, simply build the menu item */ + icon = panel_key_file_get_locale_string (key_file, "Icon"); + comment = panel_key_file_get_locale_string (key_file, "Comment"); + + if (PANEL_GLIB_STR_EMPTY (force_name)) + name = panel_key_file_get_locale_string (key_file, "Name"); + else + name = g_strdup (force_name); + + if (use_icon) { + item = panel_image_menu_item_new (); + } else { + item = gtk_image_menu_item_new (); + } + + setup_menu_item_with_icon (item, panel_menu_icon_get_size (), + icon, NULL, NULL, name); + + panel_util_set_tooltip_text (item, comment); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + g_signal_connect_data (item, "activate", + G_CALLBACK (panel_menu_item_activate_desktop_file), + g_strdup (full_path), + (GClosureNotify) g_free, 0); + g_signal_connect (G_OBJECT (item), "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + + uri = g_filename_to_uri (full_path, NULL, NULL); + + setup_uri_drag (item, uri, icon); + g_free (uri); + + g_key_file_free (key_file); + + if (icon) + g_free (icon); + + if (name) + g_free (name); + + if (comment) + g_free (comment); + + if (path_freeme) + g_free (path_freeme); +} + +static void +panel_menu_items_append_place_item (const char *icon_name, + GIcon *gicon, + const char *title, + const char *tooltip, + GtkWidget *menu, + GCallback callback, + const char *uri) +{ + GtkWidget *item; + char *user_data; + + item = panel_image_menu_item_new (); + setup_menu_item_with_icon (item, + panel_menu_icon_get_size (), + icon_name, NULL, gicon, + title); + + panel_util_set_tooltip_text (item, tooltip); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + user_data = g_strdup (uri); + g_signal_connect_data (item, "activate", callback, user_data, + (GClosureNotify) g_free, 0); + + g_signal_connect (G_OBJECT (item), "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + + setup_uri_drag (item, uri, icon_name); +} + +static GtkWidget * +panel_menu_items_create_action_item_full (PanelActionButtonType action_type, + const char *label, + const char *tooltip) +{ + GtkWidget *item; + + if (panel_action_get_is_disabled (action_type)) + return NULL; + + item = gtk_image_menu_item_new (); + setup_menu_item_with_icon (item, + panel_menu_icon_get_size (), + panel_action_get_icon_name (action_type), + NULL, NULL, + label ? label : panel_action_get_text (action_type)); + + panel_util_set_tooltip_text (item, + tooltip ? + tooltip : + panel_action_get_tooltip (action_type)); + + g_signal_connect (item, "activate", + panel_action_get_invoke (action_type), NULL); + g_signal_connect (G_OBJECT (item), "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + setup_internal_applet_drag (item, action_type); + + return item; +} + +static GtkWidget * +panel_menu_items_create_action_item (PanelActionButtonType action_type) +{ + return panel_menu_items_create_action_item_full (action_type, + NULL, NULL); +} + +static void +panel_place_menu_item_append_gtk_bookmarks (GtkWidget *menu) +{ + typedef struct { + char *full_uri; + char *label; + } PanelBookmark; + + GtkWidget *add_menu; + char *filename; + GIOChannel *io_channel; + GHashTable *table; + int i; + GSList *lines = NULL; + GSList *add_bookmarks, *l; + PanelBookmark *bookmark; + + filename = g_build_filename (g_get_home_dir (), + BOOKMARKS_FILENAME, NULL); + + io_channel = g_io_channel_new_file (filename, "r", NULL); + g_free (filename); + + if (!io_channel) + return; + + /* We use a hard limit to avoid having users shooting their + * own feet, and to avoid crashing the system if a misbehaving + * application creates a big bookmars file. + */ + for (i = 0; i < MAX_BOOKMARK_ITEMS; i++) { + char *contents; + gsize length; + gsize terminator_pos; + GIOStatus status; + + status = g_io_channel_read_line (io_channel, &contents, &length, &terminator_pos, NULL); + + if (status != G_IO_STATUS_NORMAL) + break; + + if (length == 0) + break; + + /* Clear the line terminator (\n), if any */ + if (terminator_pos > 0) + contents[terminator_pos] = '\0'; + + lines = g_slist_prepend (lines, contents); + } + + g_io_channel_shutdown (io_channel, FALSE, NULL); + g_io_channel_unref (io_channel); + + if (!lines) + return; + + lines = g_slist_reverse (lines); + + table = g_hash_table_new (g_str_hash, g_str_equal); + add_bookmarks = NULL; + + for (l = lines; l; l = l->next) { + char *line = (char*) l->data; + + if (line[0] && !g_hash_table_lookup (table, line)) { + GFile *file; + char *space; + char *label; + gboolean keep; + + g_hash_table_insert (table, line, line); + + space = strchr (line, ' '); + if (space) { + *space = '\0'; + label = g_strdup (space + 1); + } else { + label = NULL; + } + + keep = FALSE; + + if (g_str_has_prefix (line, "x-caja-search:")) + keep = TRUE; + + if (!keep) { + file = g_file_new_for_uri (line); + keep = !g_file_is_native (file) || + g_file_query_exists (file, NULL); + g_object_unref (file); + } + + if (!keep) { + if (label) + g_free (label); + continue; + } + + bookmark = g_malloc (sizeof (PanelBookmark)); + bookmark->full_uri = g_strdup (line); + bookmark->label = label; + add_bookmarks = g_slist_prepend (add_bookmarks, bookmark); + } + } + + g_hash_table_destroy (table); + g_slist_foreach (lines, (GFunc) g_free, NULL); + g_slist_free (lines); + + add_bookmarks = g_slist_reverse (add_bookmarks); + + if (g_slist_length (add_bookmarks) <= MAX_ITEMS_OR_SUBMENU) { + add_menu = menu; + } else { + GtkWidget *item; + + item = gtk_image_menu_item_new (); + setup_menu_item_with_icon (item, panel_menu_icon_get_size (), + PANEL_ICON_BOOKMARKS, NULL, NULL, + _("Bookmarks")); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + add_menu = create_empty_menu (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), add_menu); + } + + for (l = add_bookmarks; l; l = l->next) { + char *display_name; + char *tooltip; + char *label; + char *icon; + GFile *file; + GIcon *gicon; + + bookmark = l->data; + + file = g_file_new_for_uri (bookmark->full_uri); + display_name = g_file_get_parse_name (file); + g_object_unref (file); + /* Translators: %s is a URI */ + tooltip = g_strdup_printf (_("Open '%s'"), display_name); + g_free (display_name); + + label = NULL; + if (bookmark->label) { + label = g_strdup (g_strstrip (bookmark->label)); + if (!label [0]) { + g_free (label); + label = NULL; + } + } + + if (!label) { + label = panel_util_get_label_for_uri (bookmark->full_uri); + + if (!label) { + g_free (tooltip); + g_free (bookmark->full_uri); + if (bookmark->label) + g_free (bookmark->label); + g_free (bookmark); + continue; + } + } + + icon = panel_util_get_icon_for_uri (bookmark->full_uri); + /*FIXME: we should probably get a GIcon if possible, so that we + * have customized icons for cd-rom, eg */ + if (!icon) + icon = g_strdup (PANEL_ICON_FOLDER); + + gicon = g_themed_icon_new_with_default_fallbacks (icon); + + //FIXME: drag and drop will be broken for x-caja-search uris + panel_menu_items_append_place_item (icon, gicon, + label, + tooltip, + add_menu, + G_CALLBACK (activate_uri), + bookmark->full_uri); + + g_free (icon); + g_object_unref (gicon); + g_free (tooltip); + g_free (label); + g_free (bookmark->full_uri); + if (bookmark->label) + g_free (bookmark->label); + g_free (bookmark); + } + + g_slist_free (add_bookmarks); +} + +static void +drive_poll_for_media_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GdkScreen *screen; + GError *error; + char *primary; + char *name; + + error = NULL; + if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), + res, &error)) { + if (error->code != G_IO_ERROR_FAILED_HANDLED) { + screen = GDK_SCREEN (user_data); + + name = g_drive_get_name (G_DRIVE (source_object)); + primary = g_strdup_printf (_("Unable to scan %s for media changes"), + name); + g_free (name); + panel_error_dialog (NULL, screen, + "cannot_scan_drive", TRUE, + primary, error->message); + g_free (primary); + } + g_error_free (error); + } + + //FIXME: should we mount the volume and activate the root of the new + //mount? +} + +static void +panel_menu_item_rescan_drive (GtkWidget *menuitem, + GDrive *drive) +{ + g_drive_poll_for_media (drive, NULL, + drive_poll_for_media_cb, + menuitem_to_screen (menuitem)); +} + +static void +panel_menu_item_append_drive (GtkWidget *menu, + GDrive *drive) +{ + GtkWidget *item; + GIcon *icon; + char *title; + char *tooltip; + + icon = g_drive_get_icon (drive); + title = g_drive_get_name (drive); + + item = panel_image_menu_item_new (); + setup_menu_item_with_icon (item, + panel_menu_icon_get_size (), + NULL, NULL, icon, + title); + g_object_unref (icon); + + tooltip = g_strdup_printf (_("Rescan %s"), title); + panel_util_set_tooltip_text (item, tooltip); + g_free (tooltip); + + g_free (title); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + g_signal_connect_data (item, "activate", + G_CALLBACK (panel_menu_item_rescan_drive), + g_object_ref (drive), + (GClosureNotify) g_object_unref, 0); + + g_signal_connect (G_OBJECT (item), "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); +} + +typedef struct { + GdkScreen *screen; + GMountOperation *mount_op; +} PanelVolumeMountData; + +static void +volume_mount_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PanelVolumeMountData *mount_data = user_data; + GError *error; + + error = NULL; + if (!g_volume_mount_finish (G_VOLUME (source_object), res, &error)) { + char *primary; + char *name; + + if (error->code != G_IO_ERROR_FAILED_HANDLED) { + name = g_volume_get_name (G_VOLUME (source_object)); + primary = g_strdup_printf (_("Unable to mount %s"), + name); + g_free (name); + + panel_error_dialog (NULL, mount_data->screen, + "cannot_mount_volume", TRUE, + primary, error->message); + g_free (primary); + } + g_error_free (error); + } else { + GMount *mount; + GFile *root; + char *rooturi; + + mount = g_volume_get_mount (G_VOLUME (source_object)); + root = g_mount_get_root (mount); + rooturi = g_file_get_uri (root); + activate_uri_on_screen (rooturi, mount_data->screen); + g_object_unref (mount); + g_object_unref (root); + g_free (rooturi); + } + + g_object_unref (mount_data->mount_op); + g_slice_free (PanelVolumeMountData, mount_data); +} + +static void +panel_menu_item_mount_volume (GtkWidget *menuitem, + GVolume *volume) +{ + PanelVolumeMountData *mount_data; + + mount_data = g_slice_new (PanelVolumeMountData); + mount_data->screen = menuitem_to_screen (menuitem); + mount_data->mount_op = gtk_mount_operation_new (NULL); + gtk_mount_operation_set_screen (GTK_MOUNT_OPERATION (mount_data->mount_op), + mount_data->screen); + + g_volume_mount (volume, G_MOUNT_MOUNT_NONE, mount_data->mount_op, NULL, + volume_mount_cb, mount_data); +} + +static void +panel_menu_item_append_volume (GtkWidget *menu, + GVolume *volume) +{ + GtkWidget *item; + GIcon *icon; + char *title; + char *tooltip; + + icon = g_volume_get_icon (volume); + title = g_volume_get_name (volume); + + item = panel_image_menu_item_new (); + setup_menu_item_with_icon (item, + panel_menu_icon_get_size (), + NULL, NULL, icon, + title); + g_object_unref (icon); + + tooltip = g_strdup_printf (_("Mount %s"), title); + panel_util_set_tooltip_text (item, tooltip); + g_free (tooltip); + + g_free (title); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + g_signal_connect_data (item, "activate", + G_CALLBACK (panel_menu_item_mount_volume), + g_object_ref (volume), + (GClosureNotify) g_object_unref, 0); + + g_signal_connect (G_OBJECT (item), "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); +} + +static void +panel_menu_item_append_mount (GtkWidget *menu, + GMount *mount) +{ + GFile *root; + GIcon *icon; + char *display_name; + char *activation_uri; + + icon = g_mount_get_icon (mount); + display_name = g_mount_get_name (mount); + + root = g_mount_get_root (mount); + activation_uri = g_file_get_uri (root); + g_object_unref (root); + + panel_menu_items_append_place_item (NULL, icon, + display_name, + display_name, //FIXME tooltip + menu, + G_CALLBACK (activate_uri), + activation_uri); + + g_object_unref (icon); + g_free (display_name); + g_free (activation_uri); +} + +typedef enum { + PANEL_GIO_DRIVE, + PANEL_GIO_VOLUME, + PANEL_GIO_MOUNT +} PanelGioItemType; + +typedef struct { + PanelGioItemType type; + union { + GDrive *drive; + GVolume *volume; + GMount *mount; + } u; +} PanelGioItem; + +/* this is loosely based on update_places() from caja-places-sidebar.c */ +static void +panel_place_menu_item_append_local_gio (PanelPlaceMenuItem *place_item, + GtkWidget *menu) +{ + GList *l; + GList *ll; + GList *drives; + GDrive *drive; + GList *volumes; + GVolume *volume; + GList *mounts; + GMount *mount; + GSList *items; + GSList *sl; + PanelGioItem *item; + GtkWidget *add_menu; + + items = NULL; + + /* first go through all connected drives */ + drives = g_volume_monitor_get_connected_drives (place_item->priv->volume_monitor); + for (l = drives; l != NULL; l = l->next) { + drive = l->data; + + volumes = g_drive_get_volumes (drive); + if (volumes != NULL) { + for (ll = volumes; ll != NULL; ll = ll->next) { + volume = ll->data; + mount = g_volume_get_mount (volume); + item = g_slice_new (PanelGioItem); + if (mount != NULL) { + item->type = PANEL_GIO_MOUNT; + item->u.mount = mount; + } else { + /* Do show the unmounted volumes; this + * is so the user can mount it (in case + * automounting is off). + * + * Also, even if automounting is + * enabled, this gives a visual cue + * that the user should remember to + * yank out the media if he just + * unmounted it. + */ + item->type = PANEL_GIO_VOLUME; + item->u.volume = g_object_ref (volume); + } + items = g_slist_prepend (items, item); + g_object_unref (volume); + } + g_list_free (volumes); + } else { + if (g_drive_is_media_removable (drive) && + !g_drive_is_media_check_automatic (drive)) { + /* If the drive has no mountable volumes and we + * cannot detect media change.. we display the + * drive so the user can manually poll the + * drive by clicking on it..." + * + * This is mainly for drives like floppies + * where media detection doesn't work.. but + * it's also for human beings who like to turn + * off media detection in the OS to save + * battery juice. + */ + item = g_slice_new (PanelGioItem); + item->type = PANEL_GIO_DRIVE; + item->u.drive = g_object_ref (drive); + items = g_slist_prepend (items, item); + } + } + g_object_unref (drive); + } + g_list_free (drives); + + /* add all volumes that is not associated with a drive */ + volumes = g_volume_monitor_get_volumes (place_item->priv->volume_monitor); + for (l = volumes; l != NULL; l = l->next) { + volume = l->data; + drive = g_volume_get_drive (volume); + if (drive != NULL) { + g_object_unref (volume); + g_object_unref (drive); + continue; + } + mount = g_volume_get_mount (volume); + item = g_slice_new (PanelGioItem); + if (mount != NULL) { + item->type = PANEL_GIO_MOUNT; + item->u.mount = mount; + } else { + /* see comment above in why we add an icon for an + * unmounted mountable volume */ + item->type = PANEL_GIO_VOLUME; + item->u.volume = g_object_ref (volume); + } + items = g_slist_prepend (items, item); + g_object_unref (volume); + } + g_list_free (volumes); + + /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */ + mounts = g_volume_monitor_get_mounts (place_item->priv->volume_monitor); + for (l = mounts; l != NULL; l = l->next) { + GFile *root; + + mount = l->data; + + if (g_mount_is_shadowed (mount)) { + g_object_unref (mount); + continue; + } + + volume = g_mount_get_volume (mount); + if (volume != NULL) { + g_object_unref (volume); + g_object_unref (mount); + continue; + } + + root = g_mount_get_root (mount); + if (!g_file_is_native (root)) { + g_object_unref (root); + g_object_unref (mount); + continue; + } + g_object_unref (root); + + item = g_slice_new (PanelGioItem); + item->type = PANEL_GIO_MOUNT; + item->u.mount = mount; + items = g_slist_prepend (items, item); + } + g_list_free (mounts); + + /* now that we have everything, add the items inline or in a submenu */ + items = g_slist_reverse (items); + + if (g_slist_length (items) <= MAX_ITEMS_OR_SUBMENU) { + add_menu = menu; + } else { + GtkWidget *item; + + item = gtk_image_menu_item_new (); + setup_menu_item_with_icon (item, panel_menu_icon_get_size (), + PANEL_ICON_REMOVABLE_MEDIA, + NULL, NULL, + _("Removable Media")); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + add_menu = create_empty_menu (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), add_menu); + } + + for (sl = items; sl; sl = sl->next) { + item = sl->data; + switch (item->type) { + case PANEL_GIO_DRIVE: + panel_menu_item_append_drive (add_menu, item->u.drive); + g_object_unref (item->u.drive); + break; + case PANEL_GIO_VOLUME: + panel_menu_item_append_volume (add_menu, item->u.volume); + g_object_unref (item->u.volume); + break; + case PANEL_GIO_MOUNT: + panel_menu_item_append_mount (add_menu, item->u.mount); + g_object_unref (item->u.mount); + break; + default: + g_assert_not_reached (); + } + g_slice_free (PanelGioItem, item); + } + + g_slist_free (items); +} + +/* this is loosely based on update_places() from caja-places-sidebar.c */ +static void +panel_place_menu_item_append_remote_gio (PanelPlaceMenuItem *place_item, + GtkWidget *menu) +{ + GtkWidget *add_menu; + GList *mounts, *l; + GMount *mount; + GSList *add_mounts, *sl; + + /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */ + mounts = g_volume_monitor_get_mounts (place_item->priv->volume_monitor); + add_mounts = NULL; + + for (l = mounts; l; l = l->next) { + GVolume *volume; + GFile *root; + + mount = l->data; + + if (g_mount_is_shadowed (mount)) { + g_object_unref (mount); + continue; + } + + volume = g_mount_get_volume (mount); + if (volume != NULL) { + g_object_unref (volume); + g_object_unref (mount); + continue; + } + + root = g_mount_get_root (mount); + if (g_file_is_native (root)) { + g_object_unref (root); + g_object_unref (mount); + continue; + } + g_object_unref (root); + + + add_mounts = g_slist_prepend (add_mounts, mount); + } + add_mounts = g_slist_reverse (add_mounts); + + if (g_slist_length (add_mounts) <= MAX_ITEMS_OR_SUBMENU) { + add_menu = menu; + } else { + GtkWidget *item; + + item = panel_image_menu_item_new (); + setup_menu_item_with_icon (item, panel_menu_icon_get_size (), + PANEL_ICON_NETWORK_SERVER, + NULL, NULL, + _("Network Places")); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + add_menu = create_empty_menu (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), add_menu); + } + + for (sl = add_mounts; sl; sl = sl->next) { + mount = sl->data; + panel_menu_item_append_mount (add_menu, mount); + g_object_unref (mount); + } + + g_slist_free (add_mounts); + g_list_free (mounts); +} + + +static GtkWidget * +panel_place_menu_item_create_menu (PanelPlaceMenuItem *place_item) +{ + GtkWidget *places_menu; + GtkWidget *item; + char *mateconf_name; + char *name; + char *uri; + GFile *file; + + places_menu = panel_create_menu (); + + file = g_file_new_for_path (g_get_home_dir ()); + uri = g_file_get_uri (file); + name = panel_util_get_label_for_uri (uri); + g_object_unref (file); + + panel_menu_items_append_place_item (PANEL_ICON_HOME, NULL, + name, + _("Open your personal folder"), + places_menu, + G_CALLBACK (activate_home_uri), + uri); + g_free (name); + g_free (uri); + + if (!mateconf_client_get_bool (panel_mateconf_get_client (), + DESKTOP_IS_HOME_DIR_KEY, + NULL)) { + file = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); + uri = g_file_get_uri (file); + g_object_unref (file); + + panel_menu_items_append_place_item ( + PANEL_ICON_DESKTOP, NULL, + /* Translators: Desktop is used here as in + * "Desktop Folder" (this is not the Desktop + * environment). */ + C_("Desktop Folder", "Desktop"), + _("Open the contents of your desktop in a folder"), + places_menu, + G_CALLBACK (activate_desktop_uri), + /* FIXME: if the dir changes, we'd need to update the drag data since the uri is not the same */ + uri); + g_free (uri); + } + + panel_place_menu_item_append_gtk_bookmarks (places_menu); + add_menu_separator (places_menu); + + mateconf_name = mateconf_client_get_string (panel_mateconf_get_client (), + COMPUTER_NAME_KEY, + NULL); + panel_menu_items_append_from_desktop (places_menu, + "caja-computer.desktop", + mateconf_name, + TRUE); + if (mateconf_name) + g_free (mateconf_name); + + panel_place_menu_item_append_local_gio (place_item, places_menu); + add_menu_separator (places_menu); + + panel_menu_items_append_from_desktop (places_menu, + "network-scheme.desktop", + NULL, + TRUE); + panel_place_menu_item_append_remote_gio (place_item, places_menu); + + if (panel_is_program_in_path ("caja-connect-server")) { + item = panel_menu_items_create_action_item (PANEL_ACTION_CONNECT_SERVER); + if (item != NULL) + gtk_menu_shell_append (GTK_MENU_SHELL (places_menu), + item); + } + + add_menu_separator (places_menu); + + panel_menu_items_append_from_desktop (places_menu, + "mate-search-tool.desktop", + NULL, + FALSE); + + panel_recent_append_documents_menu (places_menu, + place_item->priv->recent_manager); + + return places_menu; +} + +static void +panel_place_menu_item_recreate_menu (GtkWidget *widget) +{ + PanelPlaceMenuItem *place_item; + + place_item = PANEL_PLACE_MENU_ITEM (widget); + + if (place_item->priv->menu) { + gtk_widget_destroy (place_item->priv->menu); + place_item->priv->menu = panel_place_menu_item_create_menu (place_item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (place_item), + place_item->priv->menu); + mate_panel_applet_menu_set_recurse (GTK_MENU (place_item->priv->menu), + "menu_panel", + place_item->priv->panel); + } +} + +static void +panel_place_menu_item_key_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + GtkWidget *place_item) +{ + panel_place_menu_item_recreate_menu (place_item); +} + +static void +panel_place_menu_item_gtk_bookmarks_changed (GFileMonitor *handle, + GFile *file, + GFile *other_file, + GFileMonitorEvent event, + gpointer user_data) +{ + panel_place_menu_item_recreate_menu (GTK_WIDGET (user_data)); +} + +static void +panel_place_menu_item_drives_changed (GVolumeMonitor *monitor, + GDrive *drive, + GtkWidget *place_menu) +{ + panel_place_menu_item_recreate_menu (place_menu); +} + +static void +panel_place_menu_item_volumes_changed (GVolumeMonitor *monitor, + GVolume *volume, + GtkWidget *place_menu) +{ + panel_place_menu_item_recreate_menu (place_menu); +} + +static void +panel_place_menu_item_mounts_changed (GVolumeMonitor *monitor, + GMount *mount, + GtkWidget *place_menu) +{ + panel_place_menu_item_recreate_menu (place_menu); +} + +static void +panel_desktop_menu_item_append_menu (GtkWidget *menu, + gpointer data) +{ + PanelDesktopMenuItem *parent; + gboolean add_separator; + GList *children; + GList *last; + + parent = PANEL_DESKTOP_MENU_ITEM (data); + + add_separator = FALSE; + children = gtk_container_get_children (GTK_CONTAINER (menu)); + last = g_list_last (children); + + if (last != NULL) + add_separator = !GTK_IS_SEPARATOR (GTK_WIDGET (last->data)); + + g_list_free (children); + + if (add_separator) + add_menu_separator (menu); + + panel_menu_items_append_from_desktop (menu, "yelp.desktop", NULL, FALSE); + panel_menu_items_append_from_desktop (menu, "mate-about.desktop", NULL, FALSE); + + if (parent->priv->append_lock_logout) + panel_menu_items_append_lock_logout (menu); +} + +static GtkWidget * +panel_desktop_menu_item_create_menu (PanelDesktopMenuItem *desktop_item) +{ + GtkWidget *desktop_menu; + + desktop_menu = create_applications_menu ("mate-settings.menu", NULL, FALSE); + + g_object_set_data (G_OBJECT (desktop_menu), + "panel-menu-append-callback", + panel_desktop_menu_item_append_menu); + g_object_set_data (G_OBJECT (desktop_menu), + "panel-menu-append-callback-data", + desktop_item); + + return desktop_menu; +} + +static void +panel_desktop_menu_item_recreate_menu (PanelDesktopMenuItem *desktop_item) +{ + if (desktop_item->priv->menu) { + gtk_widget_destroy (desktop_item->priv->menu); + desktop_item->priv->menu = panel_desktop_menu_item_create_menu (desktop_item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (desktop_item), + desktop_item->priv->menu); + mate_panel_applet_menu_set_recurse (GTK_MENU (desktop_item->priv->menu), + "menu_panel", + desktop_item->priv->panel); + } +} + +static void +panel_place_menu_item_finalize (GObject *object) +{ + PanelPlaceMenuItem *menuitem = (PanelPlaceMenuItem *) object; + + mateconf_client_remove_dir (panel_mateconf_get_client (), + DESKTOP_IS_HOME_DIR_DIR, + NULL); + mateconf_client_remove_dir (panel_mateconf_get_client (), + NAMES_DIR, + NULL); + + if (menuitem->priv->bookmarks_monitor != NULL) { + g_file_monitor_cancel (menuitem->priv->bookmarks_monitor); + g_object_unref (menuitem->priv->bookmarks_monitor); + } + menuitem->priv->bookmarks_monitor = NULL; + + if (menuitem->priv->drive_changed_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->drive_changed_id); + menuitem->priv->drive_changed_id = 0; + + if (menuitem->priv->drive_connected_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->drive_connected_id); + menuitem->priv->drive_connected_id = 0; + + if (menuitem->priv->drive_disconnected_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->drive_disconnected_id); + menuitem->priv->drive_disconnected_id = 0; + + if (menuitem->priv->volume_added_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->volume_added_id); + menuitem->priv->volume_added_id = 0; + + if (menuitem->priv->volume_changed_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->volume_changed_id); + menuitem->priv->volume_changed_id = 0; + + if (menuitem->priv->volume_removed_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->volume_removed_id); + menuitem->priv->volume_removed_id = 0; + + if (menuitem->priv->mount_added_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->mount_added_id); + menuitem->priv->mount_added_id = 0; + + if (menuitem->priv->mount_changed_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->mount_changed_id); + menuitem->priv->mount_changed_id = 0; + + if (menuitem->priv->mount_removed_id) + g_signal_handler_disconnect (menuitem->priv->volume_monitor, + menuitem->priv->mount_removed_id); + menuitem->priv->mount_removed_id = 0; + + if (menuitem->priv->volume_monitor != NULL) + g_object_unref (menuitem->priv->volume_monitor); + menuitem->priv->volume_monitor = NULL; + + G_OBJECT_CLASS (panel_place_menu_item_parent_class)->finalize (object); +} + +static void +panel_desktop_menu_item_finalize (GObject *object) +{ + PanelDesktopMenuItem *menuitem = (PanelDesktopMenuItem *) object; + + if (menuitem->priv->append_lock_logout) + panel_lockdown_notify_remove (G_CALLBACK (panel_desktop_menu_item_recreate_menu), + menuitem); + G_OBJECT_CLASS (panel_desktop_menu_item_parent_class)->finalize (object); +} + +static void +panel_place_menu_item_init (PanelPlaceMenuItem *menuitem) +{ + GFile *bookmark; + char *bookmarks_filename; + GError *error; + + menuitem->priv = PANEL_PLACE_MENU_ITEM_GET_PRIVATE (menuitem); + + mateconf_client_add_dir (panel_mateconf_get_client (), + DESKTOP_IS_HOME_DIR_DIR, + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + mateconf_client_add_dir (panel_mateconf_get_client (), + NAMES_DIR, + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + + panel_mateconf_notify_add_while_alive (HOME_NAME_KEY, + (MateConfClientNotifyFunc) panel_place_menu_item_key_changed, + G_OBJECT (menuitem)); + panel_mateconf_notify_add_while_alive (DESKTOP_IS_HOME_DIR_KEY, + (MateConfClientNotifyFunc) panel_place_menu_item_key_changed, + G_OBJECT (menuitem)); + panel_mateconf_notify_add_while_alive (COMPUTER_NAME_KEY, + (MateConfClientNotifyFunc) panel_place_menu_item_key_changed, + G_OBJECT (menuitem)); + + menuitem->priv->recent_manager = gtk_recent_manager_get_default (); + + bookmarks_filename = g_build_filename (g_get_home_dir (), + BOOKMARKS_FILENAME, NULL); + bookmark = g_file_new_for_path (bookmarks_filename); + + error = NULL; + menuitem->priv->bookmarks_monitor = g_file_monitor_file + (bookmark, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (error) { + g_warning ("Failed to add file monitor for %s: %s\n", + bookmarks_filename, error->message); + g_error_free (error); + } else { + g_signal_connect (G_OBJECT (menuitem->priv->bookmarks_monitor), + "changed", + (GCallback) panel_place_menu_item_gtk_bookmarks_changed, + menuitem); + } + + g_object_unref (bookmark); + g_free (bookmarks_filename); + + menuitem->priv->volume_monitor = g_volume_monitor_get (); + + menuitem->priv->drive_changed_id = g_signal_connect (menuitem->priv->volume_monitor, + "drive-changed", + G_CALLBACK (panel_place_menu_item_drives_changed), + menuitem); + menuitem->priv->drive_connected_id = g_signal_connect (menuitem->priv->volume_monitor, + "drive-connected", + G_CALLBACK (panel_place_menu_item_drives_changed), + menuitem); + menuitem->priv->drive_disconnected_id = g_signal_connect (menuitem->priv->volume_monitor, + "drive-disconnected", + G_CALLBACK (panel_place_menu_item_drives_changed), + menuitem); + menuitem->priv->volume_added_id = g_signal_connect (menuitem->priv->volume_monitor, + "volume-added", + G_CALLBACK (panel_place_menu_item_volumes_changed), + menuitem); + menuitem->priv->volume_changed_id = g_signal_connect (menuitem->priv->volume_monitor, + "volume-changed", + G_CALLBACK (panel_place_menu_item_volumes_changed), + menuitem); + menuitem->priv->volume_removed_id = g_signal_connect (menuitem->priv->volume_monitor, + "volume-removed", + G_CALLBACK (panel_place_menu_item_volumes_changed), + menuitem); + menuitem->priv->mount_added_id = g_signal_connect (menuitem->priv->volume_monitor, + "mount-added", + G_CALLBACK (panel_place_menu_item_mounts_changed), + menuitem); + menuitem->priv->mount_changed_id = g_signal_connect (menuitem->priv->volume_monitor, + "mount-changed", + G_CALLBACK (panel_place_menu_item_mounts_changed), + menuitem); + menuitem->priv->mount_removed_id = g_signal_connect (menuitem->priv->volume_monitor, + "mount-removed", + G_CALLBACK (panel_place_menu_item_mounts_changed), + menuitem); + +} + +static void +panel_desktop_menu_item_init (PanelDesktopMenuItem *menuitem) +{ + menuitem->priv = PANEL_DESKTOP_MENU_ITEM_GET_PRIVATE (menuitem); +} + +static void +panel_place_menu_item_class_init (PanelPlaceMenuItemClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = panel_place_menu_item_finalize; + + g_type_class_add_private (klass, sizeof (PanelPlaceMenuItemPrivate)); +} + +static void +panel_desktop_menu_item_class_init (PanelDesktopMenuItemClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = panel_desktop_menu_item_finalize; + + g_type_class_add_private (klass, sizeof (PanelDesktopMenuItemPrivate)); +} + +GtkWidget* panel_place_menu_item_new(gboolean use_image) +{ + PanelPlaceMenuItem* menuitem; + GtkWidget* image; + + menuitem = g_object_new(PANEL_TYPE_PLACE_MENU_ITEM, NULL); + + if (use_image) + { + image = gtk_image_new_from_icon_name(PANEL_ICON_FOLDER, panel_menu_icon_get_size()); + } + else + { + image = NULL; + } + + setup_menuitem(GTK_WIDGET(menuitem), image ? panel_menu_icon_get_size() : GTK_ICON_SIZE_INVALID, image, _("Places")); + + menuitem->priv->use_image = use_image; + + menuitem->priv->menu = panel_place_menu_item_create_menu(menuitem); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menuitem->priv->menu); + + return GTK_WIDGET(menuitem); +} + +GtkWidget * +panel_desktop_menu_item_new (gboolean use_image, + gboolean append_lock_logout) +{ + PanelDesktopMenuItem *menuitem; + GtkWidget *image; + + menuitem = g_object_new (PANEL_TYPE_DESKTOP_MENU_ITEM, NULL); + + if (use_image) + image = gtk_image_new_from_icon_name ("computer", + panel_menu_icon_get_size ()); + else + image = NULL; + + setup_menuitem (GTK_WIDGET (menuitem), + image ? panel_menu_icon_get_size () : GTK_ICON_SIZE_INVALID, + image, + _("System")); + + menuitem->priv->use_image = use_image; + + menuitem->priv->append_lock_logout = append_lock_logout; + if (append_lock_logout) + panel_lockdown_notify_add (G_CALLBACK (panel_desktop_menu_item_recreate_menu), + menuitem); + + menuitem->priv->menu = panel_desktop_menu_item_create_menu (menuitem); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), + menuitem->priv->menu); + + return GTK_WIDGET (menuitem); +} + +void +panel_place_menu_item_set_panel (GtkWidget *item, + PanelWidget *panel) +{ + PanelPlaceMenuItem *place_item; + + place_item = PANEL_PLACE_MENU_ITEM (item); + + place_item->priv->panel = panel; + mate_panel_applet_menu_set_recurse (GTK_MENU (place_item->priv->menu), + "menu_panel", panel); +} + +void +panel_desktop_menu_item_set_panel (GtkWidget *item, + PanelWidget *panel) +{ + PanelDesktopMenuItem *desktop_item; + + desktop_item = PANEL_DESKTOP_MENU_ITEM (item); + + desktop_item->priv->panel = panel; + mate_panel_applet_menu_set_recurse (GTK_MENU (desktop_item->priv->menu), + "menu_panel", panel); +} + +void +panel_menu_items_append_lock_logout (GtkWidget *menu) +{ + gboolean separator_inserted; + GList *children; + GList *last; + GtkWidget *item; + const char *translate; + char *label; + char *tooltip; + + separator_inserted = FALSE; + children = gtk_container_get_children (GTK_CONTAINER (menu)); + last = g_list_last (children); + if (last != NULL) { + separator_inserted = GTK_IS_SEPARATOR (GTK_WIDGET (last->data)); + } + g_list_free (children); + + if (panel_lock_screen_action_available("lock")) + { + item = panel_menu_items_create_action_item(PANEL_ACTION_LOCK); + + if (item != NULL) + { + if (!separator_inserted) + { + add_menu_separator(menu); + separator_inserted = TRUE; + } + + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + } + } + + if (panel_lockdown_get_disable_log_out ()) + return; + /* Below this, we only have log out/shutdown items */ + + /* Translators: translate "1" (msgctxt: "panel:showusername") to anything + * but "1" if "Log Out %s" doesn't make any sense in your + * language (where %s is a username). + */ + translate = C_("panel:showusername", "1"); + if (strcmp (translate, "1") == 0) { + const char *user_name; + + user_name = g_get_real_name (); + if (!user_name || !user_name [0]) + user_name = g_get_user_name (); + + /* keep those strings in sync with the ones in + * panel-action-button.c */ + /* Translators: this string is used ONLY if you translated + * "1" (msgctxt: "panel:showusername") to "1" */ + label = g_strdup_printf (_("Log Out %s..."), + g_get_user_name ()); + /* Translators: this string is used ONLY if you translated + * "1" (msgctxt: "panel:showusername") to "1" */ + tooltip = g_strdup_printf (_("Log out %s of this session to " + "log in as a different user"), + user_name); + } else { + label = NULL; + tooltip = NULL; + } + + item = panel_menu_items_create_action_item_full (PANEL_ACTION_LOGOUT, + label, tooltip); + g_free (label); + g_free (tooltip); + + if (item != NULL) { + if (!separator_inserted) { + add_menu_separator (menu); + separator_inserted = TRUE; + } + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + } + + item = panel_menu_items_create_action_item (PANEL_ACTION_SHUTDOWN); + if (item != NULL) { + if (!separator_inserted) + add_menu_separator (menu); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + } +} + +void +panel_menu_item_activate_desktop_file (GtkWidget *menuitem, + const char *path) +{ + panel_launch_desktop_file (path, menuitem_to_screen (menuitem), NULL); +} diff --git a/mate-panel/panel-menu-items.h b/mate-panel/panel-menu-items.h new file mode 100644 index 00000000..8f20801a --- /dev/null +++ b/mate-panel/panel-menu-items.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2005 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + + +#ifndef __PANEL_MENU_ITEMS_H__ +#define __PANEL_MENU_ITEMS_H__ + +#include +#include "panel-widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_PLACE_MENU_ITEM (panel_place_menu_item_get_type ()) +#define PANEL_PLACE_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_PLACE_MENU_ITEM, PanelPlaceMenuItem)) +#define PANEL_PLACE_MENU_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_PLACE_MENU_ITEM, PanelPlaceMenuItemClass)) +#define PANEL_IS_PLACE_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_PLACE_MENU_ITEM)) +#define PANEL_IS_PLACE_MENU_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_PLACE_MENU_ITEM)) +#define PANEL_PLACE_MENU_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_PLACE_MENU_ITEM, PanelPlaceMenuItemClass)) + +typedef struct _PanelPlaceMenuItem PanelPlaceMenuItem; +typedef struct _PanelPlaceMenuItemClass PanelPlaceMenuItemClass; +typedef struct _PanelPlaceMenuItemPrivate PanelPlaceMenuItemPrivate; + +struct _PanelPlaceMenuItem { + GtkImageMenuItem menuitem; + + PanelPlaceMenuItemPrivate *priv; +}; + +struct _PanelPlaceMenuItemClass { + GtkImageMenuItemClass menuitem_class; +}; + +GType panel_place_menu_item_get_type (void) G_GNUC_CONST; + + + +#define PANEL_TYPE_DESKTOP_MENU_ITEM (panel_desktop_menu_item_get_type ()) +#define PANEL_DESKTOP_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_DESKTOP_MENU_ITEM, PanelDesktopMenuItem)) +#define PANEL_DESKTOP_MENU_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_DESKTOP_MENU_ITEM, PanelDesktopMenuItemClass)) +#define PANEL_IS_DESKTOP_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_DESKTOP_MENU_ITEM)) +#define PANEL_IS_DESKTOP_MENU_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_DESKTOP_MENU_ITEM)) +#define PANEL_DESKTOP_MENU_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_DESKTOP_MENU_ITEM, PanelDesktopMenuItemClass)) + +typedef struct _PanelDesktopMenuItem PanelDesktopMenuItem; +typedef struct _PanelDesktopMenuItemClass PanelDesktopMenuItemClass; +typedef struct _PanelDesktopMenuItemPrivate PanelDesktopMenuItemPrivate; + +struct _PanelDesktopMenuItem{ + GtkImageMenuItem menuitem; + + PanelDesktopMenuItemPrivate *priv; +}; + +struct _PanelDesktopMenuItemClass { + GtkImageMenuItemClass menuitem_class; +}; + +GType panel_desktop_menu_item_get_type (void) G_GNUC_CONST; + + +GtkWidget* panel_place_menu_item_new(gboolean use_image); +GtkWidget* panel_desktop_menu_item_new(gboolean use_image, gboolean append_lock_logout); + +void panel_place_menu_item_set_panel (GtkWidget *item, + PanelWidget *panel); +void panel_desktop_menu_item_set_panel (GtkWidget *item, + PanelWidget *panel); + +void panel_menu_items_append_lock_logout (GtkWidget *menu); +void panel_menu_item_activate_desktop_file (GtkWidget *menuitem, + const char *path); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_MENU_ITEMS_H__ */ diff --git a/mate-panel/panel-modules.c b/mate-panel/panel-modules.c new file mode 100644 index 00000000..01c06087 --- /dev/null +++ b/mate-panel/panel-modules.c @@ -0,0 +1,86 @@ +/* + * panel-modules.c + * + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#include + +#include + +#include + +#include "mate-panel-applets-manager.h" + +#include "panel-modules.h" + +static void +panel_modules_ensure_extension_points_registered (void) +{ + static gboolean registered_extensions = FALSE; + GIOExtensionPoint *ep; + + if (!registered_extensions) { + registered_extensions = TRUE; + + ep = g_io_extension_point_register (MATE_PANEL_APPLETS_MANAGER_EXTENSION_POINT_NAME); + g_io_extension_point_set_required_type (ep, PANEL_TYPE_APPLETS_MANAGER); + } + } + +void +panel_modules_ensure_loaded (void) +{ + static gboolean loaded_dirs = FALSE; + const char *module_path; + + panel_modules_ensure_extension_points_registered (); + + if (!loaded_dirs) { + GList *modules; + loaded_dirs = TRUE; + + /* We load the modules explicitly instead of using scan_all + * so that we can leak a reference to them. This prevents them + * from getting unloaded later (something they aren't designed + * to cope with) */ + modules = g_io_modules_load_all_in_directory (PANEL_MODULES_DIR); + g_list_free (modules); + + module_path = g_getenv ("MATE_PANEL_EXTRA_MODULES"); + + if (module_path) { + gchar **paths; + int i; + + paths = g_strsplit (module_path, ":", 0); + + for (i = 0; paths[i] != NULL; i++) { + modules = g_io_modules_load_all_in_directory (paths[i]); + g_list_free (modules); + } + + g_strfreev (paths); + } + + mate_panel_applets_manager_dbus_get_type (); + } +} diff --git a/mate-panel/panel-modules.h b/mate-panel/panel-modules.h new file mode 100644 index 00000000..02ddd045 --- /dev/null +++ b/mate-panel/panel-modules.h @@ -0,0 +1,30 @@ +/* + * panel-modules.h + * + * Copyright (C) 2010 Vincent Untz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Vincent Untz + */ + +#ifndef __PANEL_MODULES_H__ +#define __PANEL_MODULES_H__ + +void panel_modules_ensure_loaded (void); + +#endif /* __PANEL_MODULES_H__ */ diff --git a/mate-panel/panel-multiscreen.c b/mate-panel/panel-multiscreen.c new file mode 100644 index 00000000..eef3ed72 --- /dev/null +++ b/mate-panel/panel-multiscreen.c @@ -0,0 +1,784 @@ +/* + * panel-multiscreen.c: Multi-screen and Xinerama support for the panel. + * + * Copyright (C) 2001 George Lebl + * 2002 Sun Microsystems Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * Authors: George Lebl , + * Mark McLoughlin + */ + +#include + +#include +#include +#include +#include + +#include "panel-multiscreen.h" + +#include + +#if defined(HAVE_CRT_EXTERNS_H) && defined(HAVE__NSGETENVIRON) +#include /* for _NSGetEnviron */ +#define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + +static int screens = 0; +static int *monitors = NULL; +static GdkRectangle **geometries = NULL; +static gboolean initialized = FALSE; +static gboolean have_randr = FALSE; +static gboolean have_randr_1_3 = FALSE; +static guint reinit_id = 0; + +#ifdef HAVE_RANDR +static gboolean +_panel_multiscreen_output_should_be_first (Display *xdisplay, + RROutput output, + XRROutputInfo *info, + RROutput primary) +{ + if (primary) + return output == primary; + + if (have_randr_1_3) { + Atom connector_type_atom; + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop; + char *connector_type; + gboolean retval; + + connector_type_atom = XInternAtom (xdisplay, "ConnectorType", False); + + if (XRRGetOutputProperty (xdisplay, output, connector_type_atom, + 0, 100, False, False, None, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop) == Success) { + if (actual_type == XA_ATOM && nitems == 1 && actual_format == 32) { + connector_type = XGetAtomName (xdisplay, prop[0]); + retval = g_strcmp0 (connector_type, "Panel") == 0; + XFree (connector_type); + return retval; + } + } + } + + /* Pre-1.3 fallback: + * "LVDS" is the oh-so-intuitive name that X gives to laptop LCDs. + * It can actually be LVDS0, LVDS-0, Lvds, etc. + */ + return (g_ascii_strncasecmp (info->name, "LVDS", strlen ("LVDS")) == 0); +} +#endif + +static gboolean +panel_multiscreen_get_randr_monitors_for_screen (GdkScreen *screen, + int *monitors_ret, + GdkRectangle **geometries_ret) +{ +#ifdef HAVE_RANDR + Display *xdisplay; + Window xroot; + XRRScreenResources *resources; + RROutput primary; + GArray *geometries; + int i; + gboolean driver_is_pre_randr_1_2; + + if (!have_randr) + return FALSE; + + /* GTK+ 2.14.x uses the Xinerama API, instead of RANDR, to get the + * monitor geometries. It does this to avoid calling + * XRRGetScreenResources(), which is slow as it re-detects all the + * monitors --- note that XRRGetScreenResourcesCurrent() had not been + * introduced yet. Using Xinerama in GTK+ has the bad side effect that + * gdk_screen_get_monitor_plug_name() will return NULL, as Xinerama + * does not provide that information, unlike RANDR. + * + * Here we need to identify the output names, so that we can put the + * built-in LCD in a laptop *before* all other outputs. This is so + * that mate-panel will normally prefer to appear on the "native" + * display rather than on an external monitor. + * + * To get the output names and geometries, we will not use + * gdk_screen_get_n_monitors() and friends, but rather we will call + * XRR*() directly. + * + * See https://bugzilla.novell.com/show_bug.cgi?id=479684 for this + * particular bug, and and + * http://bugzilla.gnome.org/show_bug.cgi?id=562944 for a more + * long-term solution. + */ + + xdisplay = GDK_SCREEN_XDISPLAY (screen); + xroot = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)); + +#if (RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3)) + if (have_randr_1_3) { + resources = XRRGetScreenResourcesCurrent (xdisplay, xroot); + if (resources->noutput == 0) { + /* This might happen if nothing tried to get randr + * resources from the server before, so we need an + * active probe. See comment #27 in + * https://bugzilla.gnome.org/show_bug.cgi?id=597101 */ + XRRFreeScreenResources (resources); + resources = XRRGetScreenResources (xdisplay, xroot); + } + } else + resources = XRRGetScreenResources (xdisplay, xroot); +#else + resources = XRRGetScreenResources (xdisplay, xroot); +#endif + + if (!resources) + return FALSE; + + primary = None; +#if (RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3)) + if (have_randr_1_3) + primary = XRRGetOutputPrimary (xdisplay, xroot); +#endif + + geometries = g_array_sized_new (FALSE, FALSE, + sizeof (GdkRectangle), + resources->noutput); + + driver_is_pre_randr_1_2 = FALSE; + + for (i = 0; i < resources->noutput; i++) { + XRROutputInfo *output; + + output = XRRGetOutputInfo (xdisplay, resources, + resources->outputs[i]); + + /* Drivers before RANDR 1.2 return "default" for the output + * name */ + if (g_strcmp0 (output->name, "default") == 0) + driver_is_pre_randr_1_2 = TRUE; + + if (output->connection != RR_Disconnected && + output->crtc != 0) { + XRRCrtcInfo *crtc; + GdkRectangle rect; + + crtc = XRRGetCrtcInfo (xdisplay, resources, + output->crtc); + + rect.x = crtc->x; + rect.y = crtc->y; + rect.width = crtc->width; + rect.height = crtc->height; + + XRRFreeCrtcInfo (crtc); + + if (_panel_multiscreen_output_should_be_first (xdisplay, + resources->outputs[i], + output, primary)) + g_array_prepend_vals (geometries, &rect, 1); + else + g_array_append_vals (geometries, &rect, 1); + } + + XRRFreeOutputInfo (output); + } + + XRRFreeScreenResources (resources); + + if (driver_is_pre_randr_1_2) { + /* Drivers before RANDR 1.2 don't provide useful info about + * outputs */ + g_array_free (geometries, TRUE); + return FALSE; + } + + if (geometries->len == 0) { + /* This can happen in at least one case: + * https://bugzilla.novell.com/show_bug.cgi?id=543876 where all + * monitors appear disconnected (possibly because the screen + * is behing a KVM switch) -- see comment #8. + * There might be other cases too, so we stay on the safe side. + */ + g_array_free (geometries, TRUE); + return FALSE; + } + + *monitors_ret = geometries->len; + *geometries_ret = (GdkRectangle *) g_array_free (geometries, FALSE); + + return TRUE; +#else + return FALSE; +#endif +} + +static void +panel_multiscreen_get_gdk_monitors_for_screen (GdkScreen *screen, + int *monitors_ret, + GdkRectangle **geometries_ret) +{ + int num_monitors; + GdkRectangle *geometries; + int i; + + num_monitors = gdk_screen_get_n_monitors (screen); + geometries = g_new (GdkRectangle, num_monitors); + + for (i = 0; i < num_monitors; i++) + gdk_screen_get_monitor_geometry (screen, i, &(geometries[i])); + + *monitors_ret = num_monitors; + *geometries_ret = geometries; +} + +static void +panel_multiscreen_get_raw_monitors_for_screen (GdkScreen *screen, + int *monitors_ret, + GdkRectangle **geometries_ret) +{ + gboolean res; + + *monitors_ret = 0; + *geometries_ret = NULL; + + res = panel_multiscreen_get_randr_monitors_for_screen (screen, + monitors_ret, + geometries_ret); + if (res && *monitors_ret > 0) + return; + + panel_multiscreen_get_gdk_monitors_for_screen (screen, + monitors_ret, + geometries_ret); +} + +static inline gboolean +rectangle_overlaps (GdkRectangle *a, + GdkRectangle *b) +{ + return gdk_rectangle_intersect (a, b, NULL); +} + +static long +pixels_in_rectangle (GdkRectangle *r) +{ + return (long) (r->width * r->height); +} + +static void +panel_multiscreen_compress_overlapping_monitors (int *num_monitors_inout, + GdkRectangle **geometries_inout) +{ + int num_monitors; + GdkRectangle *geometries; + int i; + + num_monitors = *num_monitors_inout; + geometries = *geometries_inout; + + /* http://bugzilla.gnome.org/show_bug.cgi?id=530969 + * https://bugzilla.novell.com/show_bug.cgi?id=310208 + * and many other such bugs... + * + * RANDR sometimes gives us monitors that overlap (i.e. outputs whose + * bounding rectangles overlap). This is sometimes right and sometimes + * wrong: + * + * * Right - two 1024x768 outputs at the same offset (0, 0) that show + * the same thing. Think "laptop plus projector with the same + * resolution". + * + * * Wrong - one 1280x1024 output ("laptop internal LCD") and another + * 1024x768 output ("external monitor"), both at offset (0, 0). + * There is no way for the monitor with the small resolution to + * show the complete image from the laptop's LCD, unless one uses + * panning (but nobody wants panning, right!?). + * + * With overlapping monitors, we may end up placing the panel with + * respect to the "wrong" one. This is always wrong, as the panel + * appears "in the middle of the screen" of the monitor with the + * smaller resolution, instead of at the edge. + * + * Our strategy is to find the subsets of overlapping monitors, and + * "compress" each such set to being like if there were a single + * monitor with the biggest resolution of each of that set's monitors. + * Say we have four monitors + * + * A, B, C, D + * + * where B and D overlap. In that case, we'll generate a new list that + * looks like + * + * A, MAX(B, D), C + * + * with three monitors. + * + * NOTE FOR THE FUTURE: We could avoid most of this mess if we had a + * concept of a "primary monitor". Also, we could look at each + * output's name or properties to see if it is the built-in LCD in a + * laptop. However, with GTK+ 2.14.x we don't get output names, since + * it gets the list outputs from Xinerama, not RANDR (and Xinerama + * doesn't provide output names). + */ + + for (i = 0; i < num_monitors; i++) { + long max_pixels; + int j; + + max_pixels = pixels_in_rectangle (&geometries[i]); + + j = i + 1; + + while (j < num_monitors) { + if (rectangle_overlaps (&geometries[i], + &geometries[j])) { + long pixels; + + pixels = pixels_in_rectangle (&geometries[j]); + if (pixels > max_pixels) { + max_pixels = pixels; + /* keep the maximum */ + geometries[i] = geometries[j]; + } + + /* Shift the remaining monitors to the left */ + if (num_monitors - j - 1 > 0) + memmove (&geometries[j], + &geometries[j + 1], + sizeof (geometries[0]) * (num_monitors - j - 1)); + + num_monitors--; + g_assert (num_monitors > 0); + } else + j++; + } + } + + *num_monitors_inout = num_monitors; + *geometries_inout = geometries; +} + +static void +panel_multiscreen_get_monitors_for_screen (GdkScreen *screen, + int *monitors_ret, + GdkRectangle **geometries_ret) +{ + panel_multiscreen_get_raw_monitors_for_screen (screen, + monitors_ret, + geometries_ret); + panel_multiscreen_compress_overlapping_monitors (monitors_ret, + geometries_ret); +} + +static gboolean +panel_multiscreen_reinit_idle (gpointer data) +{ + panel_multiscreen_reinit (); + reinit_id = 0; + + return FALSE; +} + +static void +panel_multiscreen_queue_reinit (void) +{ + if (reinit_id) + return; + + reinit_id = g_idle_add (panel_multiscreen_reinit_idle, NULL); +} + +static void +panel_multiscreen_init_randr (GdkDisplay *display) +{ +#ifdef HAVE_RANDR + Display *xdisplay; + int event_base, error_base; +#endif + + have_randr = FALSE; + have_randr_1_3 = FALSE; + +#ifdef HAVE_RANDR + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + /* We don't remember the event/error bases, as we expect to get "screen + * changed" events from GdkScreen instead. + */ + + if (XRRQueryExtension (xdisplay, &event_base, &error_base)) { + int major, minor; + + XRRQueryVersion (xdisplay, &major, &minor); + if ((major == 1 && minor >= 2) || major > 1) + have_randr = TRUE; + + if ((major == 1 && minor >= 3) || major > 1) + have_randr_1_3 = TRUE; + } +#endif +} + +void +panel_multiscreen_init (void) +{ + GdkDisplay *display; + int i; + + if (initialized) + return; + + display = gdk_display_get_default (); + screens = gdk_display_get_n_screens (display); + + panel_multiscreen_init_randr (display); + + monitors = g_new0 (int, screens); + geometries = g_new0 (GdkRectangle *, screens); + + for (i = 0; i < screens; i++) { + GdkScreen *screen; + + screen = gdk_display_get_screen (display, i); + + /* We connect to both signals to be on the safe side, but in + * theory, it should be enough to only connect to + * monitors-changed. Since we'll likely get two signals, we do + * the real callback in the idle loop. */ + g_signal_connect (screen, "size-changed", + G_CALLBACK (panel_multiscreen_queue_reinit), NULL); + g_signal_connect (screen, "monitors-changed", + G_CALLBACK (panel_multiscreen_queue_reinit), NULL); + + panel_multiscreen_get_monitors_for_screen (screen, + &(monitors[i]), + &(geometries[i])); + } + + initialized = TRUE; +} + +void +panel_multiscreen_reinit (void) +{ + GdkDisplay *display; + GList *toplevels, *l; + int new_screens; + int i; + + if (monitors) + g_free (monitors); + + if (geometries) { + int j; + + for (j = 0; j < screens; j++) + g_free (geometries[j]); + g_free (geometries); + } + + display = gdk_display_get_default (); + /* Don't use the screens variable since in the future, we might + * want to call this function when a screen appears/disappears. */ + new_screens = gdk_display_get_n_screens (display); + + for (i = 0; i < new_screens; i++) { + GdkScreen *screen; + + screen = gdk_display_get_screen (display, i); + g_signal_handlers_disconnect_by_func (screen, + panel_multiscreen_queue_reinit, + NULL); + } + + initialized = FALSE; + panel_multiscreen_init (); + + toplevels = gtk_window_list_toplevels (); + + for (l = toplevels; l; l = l->next) + gtk_widget_queue_resize (l->data); + + g_list_free (toplevels); +} + +int +panel_multiscreen_screens (void) +{ + return screens; +} + +int +panel_multiscreen_monitors (GdkScreen *screen) +{ + int n_screen; + + n_screen = gdk_screen_get_number (screen); + + g_return_val_if_fail (n_screen >= 0 && n_screen < screens, 1); + + return monitors [n_screen]; +} + +int +panel_multiscreen_x (GdkScreen *screen, + int monitor) +{ + int n_screen; + + n_screen = gdk_screen_get_number (screen); + + g_return_val_if_fail (n_screen >= 0 && n_screen < screens, 0); + g_return_val_if_fail (monitor >= 0 && monitor < monitors [n_screen], 0); + + return geometries [n_screen][monitor].x; +} + +int +panel_multiscreen_y (GdkScreen *screen, + int monitor) +{ + int n_screen; + + n_screen = gdk_screen_get_number (screen); + + g_return_val_if_fail (n_screen >= 0 && n_screen < screens, 0); + g_return_val_if_fail (monitor >= 0 && monitor < monitors [n_screen], 0); + + return geometries [n_screen][monitor].y; +} + +int +panel_multiscreen_width (GdkScreen *screen, + int monitor) +{ + int n_screen; + + n_screen = gdk_screen_get_number (screen); + + g_return_val_if_fail (n_screen >= 0 && n_screen < screens, 0); + g_return_val_if_fail (monitor >= 0 && monitor < monitors [n_screen], 0); + + return geometries [n_screen][monitor].width; +} + +int +panel_multiscreen_height (GdkScreen *screen, + int monitor) +{ + int n_screen; + + n_screen = gdk_screen_get_number (screen); + + g_return_val_if_fail (n_screen >= 0 && n_screen < screens, 0); + g_return_val_if_fail (monitor >= 0 && monitor < monitors [n_screen], 0); + + return geometries [n_screen][monitor].height; +} + +int +panel_multiscreen_locate_widget_monitor (GtkWidget *widget) +{ + GtkWidget *toplevel; + int retval = -1; + + toplevel = gtk_widget_get_toplevel (widget); + if (!toplevel) + return -1; + + g_object_get (toplevel, "monitor", &retval, NULL); + + return retval; +} + +static int +axis_distance (int p, int axis_start, int axis_size) +{ + if (p >= axis_start && p < axis_start + axis_size) + return 0; + else if (p < axis_start) + return (axis_start - p); + else + return (p - (axis_start + axis_size - 1)); +} + +/* The panel can't use gdk_screen_get_monitor_at_point() since it has its own + * view of which monitors are present. Look at get_monitors_for_screen() above + * to see why. */ +int +panel_multiscreen_get_monitor_at_point (GdkScreen *screen, + int x, + int y) +{ + int n_screen; + int i; + int n_monitors; + GdkRectangle *geoms; + int min_dist_squared; + int closest_monitor; + + /* not -1 as callers expect a real monitor */ + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + n_screen = gdk_screen_get_number (screen); + + n_monitors = monitors[n_screen]; + geoms = geometries[n_screen]; + + min_dist_squared = G_MAXINT32; + closest_monitor = 0; + + for (i = 0; i < n_monitors; i++) { + int dist_x, dist_y; + int dist_squared; + + dist_x = axis_distance (x, geoms[i].x, geoms[i].width); + dist_y = axis_distance (y, geoms[i].y, geoms[i].height); + + if (dist_x == 0 && dist_y == 0) + return i; + + dist_squared = dist_x * dist_x + dist_y * dist_y; + + if (dist_squared < min_dist_squared) { + min_dist_squared = dist_squared; + closest_monitor = i; + } + } + + return closest_monitor; +} + +typedef struct { + int x0; + int y0; + int x1; + int y1; +} MonitorBounds; + +static inline void +get_monitor_bounds (int n_screen, + int n_monitor, + MonitorBounds *bounds) +{ + g_assert (n_screen >= 0 && n_screen < screens); + g_assert (n_monitor >= 0 || n_monitor < monitors [n_screen]); + g_assert (bounds != NULL); + + bounds->x0 = geometries [n_screen][n_monitor].x; + bounds->y0 = geometries [n_screen][n_monitor].y; + bounds->x1 = bounds->x0 + geometries [n_screen][n_monitor].width; + bounds->y1 = bounds->y0 + geometries [n_screen][n_monitor].height; +} + +/* determines whether a given monitor is along the visible + * edge of the logical screen. + */ +void +panel_multiscreen_is_at_visible_extreme (GdkScreen *screen, + int n_monitor, + gboolean *leftmost, + gboolean *rightmost, + gboolean *topmost, + gboolean *bottommost) +{ + MonitorBounds monitor; + int n_screen, i; + + n_screen = gdk_screen_get_number (screen); + + *leftmost = TRUE; + *rightmost = TRUE; + *topmost = TRUE; + *bottommost = TRUE; + + g_return_if_fail (n_screen >= 0 && n_screen < screens); + g_return_if_fail (n_monitor >= 0 && n_monitor < monitors [n_screen]); + + get_monitor_bounds (n_screen, n_monitor, &monitor); + + /* go through each monitor and try to find one either right, + * below, above, or left of the specified monitor + */ + + for (i = 0; i < monitors [n_screen]; i++) { + MonitorBounds iter; + + if (i == n_monitor) continue; + + get_monitor_bounds (n_screen, i, &iter); + + if ((iter.y0 >= monitor.y0 && iter.y0 < monitor.y1) || + (iter.y1 > monitor.y0 && iter.y1 <= monitor.y1)) { + if (iter.x0 < monitor.x0) + *leftmost = FALSE; + if (iter.x1 > monitor.x1) + *rightmost = FALSE; + } + + if ((iter.x0 >= monitor.x0 && iter.x0 < monitor.x1) || + (iter.x1 > monitor.x0 && iter.x1 <= monitor.x1)) { + if (iter.y0 < monitor.y0) + *topmost = FALSE; + if (iter.y1 > monitor.y1) + *bottommost = FALSE; + } + } +} + +char ** +panel_make_environment_for_screen (GdkScreen *screen, + char **envp) +{ + char **retval = NULL; + char *display_name; + int display_index = -1; + int i, env_len; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + if (envp == NULL) + envp = environ; + + for (env_len = 0; envp[env_len]; env_len++) + if (strncmp (envp[env_len], "DISPLAY", strlen ("DISPLAY")) == 0) + display_index = env_len; + + retval = g_new (char *, env_len + 1); + retval[env_len] = NULL; + + display_name = gdk_screen_make_display_name (screen); + + for (i = 0; i < env_len; i++) + if (i == display_index) + retval[i] = g_strconcat ("DISPLAY=", display_name, NULL); + else + retval[i] = g_strdup (envp[i]); + + g_assert (i == env_len); + + g_free (display_name); + + return retval; +} diff --git a/mate-panel/panel-multiscreen.h b/mate-panel/panel-multiscreen.h new file mode 100644 index 00000000..dd31b89b --- /dev/null +++ b/mate-panel/panel-multiscreen.h @@ -0,0 +1,58 @@ +/* + * panel-multiscreen.h: Multi-screen and Xinerama support for the panel. + * + * Copyright (C) 2001 George Lebl + * 2002 Sun Microsystems Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * Authors: George Lebl , + * Mark McLoughlin + */ + +#ifndef __PANEL_MULTISCREEN_H__ +#define __PANEL_MULTISCREEN_H__ + +#include + +void panel_multiscreen_init (void); +void panel_multiscreen_reinit (void); + +int panel_multiscreen_screens (void); +int panel_multiscreen_monitors (GdkScreen *screen); + +int panel_multiscreen_x (GdkScreen *screen, + int monitor); +int panel_multiscreen_y (GdkScreen *screen, + int monitor); +int panel_multiscreen_width (GdkScreen *screen, + int monitor); +int panel_multiscreen_height (GdkScreen *screen, + int monitor); +int panel_multiscreen_locate_widget_monitor (GtkWidget *widget); +int panel_multiscreen_get_monitor_at_point (GdkScreen *screen, + int x, + int y); +void panel_multiscreen_is_at_visible_extreme (GdkScreen *screen, + int monitor, + gboolean *leftmost, + gboolean *rightmost, + gboolean *topmost, + gboolean *bottommost); +char **panel_make_environment_for_screen (GdkScreen *screen, + char **envp); + +#endif /* __PANEL_MULTISCREEN_H__ */ diff --git a/mate-panel/panel-object.schemas.in b/mate-panel/panel-object.schemas.in new file mode 100644 index 00000000..2039ee57 --- /dev/null +++ b/mate-panel/panel-object.schemas.in @@ -0,0 +1,247 @@ + + + + + + + + + /schemas/apps/panel/objects/object_type + panel + string + menu-object + + Panel object type + + The type of this panel object. Possible values are + "drawer-object", "menu-object", "launcher-object", + "matecomponent-applet", "action-applet" and "menu-bar". + + + + + + /schemas/apps/panel/objects/toplevel_id + panel + string + + + Toplevel panel containing object + + The identifier of the toplevel panel which contains this object. + + + + + + /schemas/apps/panel/objects/position + panel + int + 0 + + Object's position on the panel + + The position of this panel object. The position is specified + by the number of pixels from the left (or top if vertical) + panel edge. + + + + + + /schemas/apps/panel/objects/panel_right_stick + panel + bool + false + + Interpret position relative to bottom/right edge + + If true, the position of the object is interpreted relative + to the right (or bottom if vertical) edge of the panel. + + + + + + /schemas/apps/panel/objects/locked + panel + bool + false + + Lock the object to the panel + + If true, the user may not move the applet without first unlocking + the object using the "Unlock" menuitem. + + + + + + + + + /schemas/apps/panel/objects/matecomponent_iid + panel + string + + + Applet MateComponent IID + + This key is deprecated, following the migration to a new library for + applets. The MateComponent implementation ID of the applet - e.g. + "OAFIID:MATE_ClockApplet". This key is only relevant if the + object_type key is "matecomponent-applet". + + + + + + /schemas/apps/panel/objects/applet_iid + panel + string + + + Applet IID + + The implementation ID of the applet - e.g. + "ClockAppletFactory::ClockApplet". This key is only + relevant if the object_type key is "matecomponent-applet". + + + + + + + + /schemas/apps/panel/objects/attached_toplevel_id + panel + string + + + Panel attached to drawer + + The identifier of the panel attached to this drawer. This + key is only relevant if the object_type key is "drawer-object". + + + + + + /schemas/apps/panel/objects/tooltip + panel + string + + + Tooltip displayed for drawer or menu + + The text to display in a tooltip for this drawer or this menu. This + key is only relevant if the object_type key is "drawer-object" or + "menu-object". + + + + + + + + /schemas/apps/panel/objects/use_custom_icon + panel + bool + false + + Use custom icon for object's button + + If true, the custom_icon key is used as a custom icon for + the button. If false, the custom_icon key is ignored. + This key is only relevant if the object_type key is + "menu-object" or "drawer-object". + + + + + + /schemas/apps/panel/objects/custom_icon + panel + string + + + Icon used for object's button + + The location of the image file used as the icon for the + object's button. This key is only relevant if the + object_type key is "drawer-object" or "menu-object" and + the use_custom_icon key is true. + + + + + + + + /schemas/apps/panel/objects/use_menu_path + panel + bool + false + + Use custom path for menu contents + + If true, the menu_path key is used as the path from which + the menu contents should be constructed. If false, the + menu_path key is ignored. This key is only relevant + if the object_type key is "menu-object". + + + + + + /schemas/apps/panel/objects/menu_path + panel + string + applications:/ + + Menu content path + + The path from which the menu contents is contructed. This + key is only relevant if the use_menu_path key is true and + the object_type key is "menu-object". + + + + + + + + /schemas/apps/panel/objects/launcher_location + panel + string + + + Launcher location + + The location of the .desktop file describing the launcher. + This key is only relevant if the object_type key is + "launcher-object". + + + + + + + + /schemas/apps/panel/objects/action_type + panel + string + lock + + Action button type + + The action type this button represents. Possible values are + "lock", "logout", "run", "search" and "screenshot". This + key is only relevant if the object_type key is "action-applet". + + + + + + + diff --git a/mate-panel/panel-profile.c b/mate-panel/panel-profile.c new file mode 100644 index 00000000..52cb353b --- /dev/null +++ b/mate-panel/panel-profile.c @@ -0,0 +1,2647 @@ +/* + * panel-profile.c: + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-profile.h" + +#include +#include + +#include + +#include "applet.h" +#include "panel-compatibility.h" +#include "panel-mateconf.h" +#include "panel.h" +#include "panel-widget.h" +#include "panel-util.h" +#include "panel-multiscreen.h" +#include "panel-toplevel.h" +#include "panel-lockdown.h" + +typedef struct { + GdkScreen *screen; + int monitor; + int size; + int x; + int x_right; + gboolean x_centered; + int y; + int y_bottom; + gboolean y_centered; + PanelOrientation orientation; + + guint screen_changed : 1; + guint monitor_changed : 1; + guint size_changed : 1; + guint x_changed : 1; + guint x_right_changed : 1; + guint x_centered_changed : 1; + guint y_changed : 1; + guint y_bottom_changed : 1; + guint y_centered_changed : 1; + guint orientation_changed : 1; +} ToplevelLocationChange; + +typedef const char *(*PanelProfileGetIdFunc) (gpointer object); +typedef gboolean (*PanelProfileOnLoadQueue) (const char *id); +typedef void (*PanelProfileLoadFunc) (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + const char *id); +typedef void (*PanelProfileDestroyFunc) (const char *id); + +static MateConfEnumStringPair panel_orientation_map [] = { + { PANEL_ORIENTATION_TOP, "top" }, + { PANEL_ORIENTATION_BOTTOM, "bottom" }, + { PANEL_ORIENTATION_LEFT, "left" }, + { PANEL_ORIENTATION_RIGHT, "right" }, + { 0, NULL } +}; + +static MateConfEnumStringPair panel_animation_speed_map [] = { + { PANEL_ANIMATION_SLOW, "slow" }, + { PANEL_ANIMATION_MEDIUM, "medium" }, + { PANEL_ANIMATION_FAST, "fast" }, + { 0, NULL } +}; + +static MateConfEnumStringPair panel_background_type_map [] = { + { PANEL_BACK_NONE, "gtk" }, + { PANEL_BACK_COLOR, "color" }, + { PANEL_BACK_IMAGE, "image" }, + { 0, NULL } +}; + +static MateConfEnumStringPair panel_object_type_map [] = { + { PANEL_OBJECT_DRAWER, "drawer-object" }, + { PANEL_OBJECT_MENU, "menu-object" }, + { PANEL_OBJECT_LAUNCHER, "launcher-object" }, + { PANEL_OBJECT_APPLET, "matecomponent-applet" }, + { PANEL_OBJECT_ACTION, "action-applet" }, + { PANEL_OBJECT_MENU_BAR, "menu-bar" }, + { PANEL_OBJECT_SEPARATOR, "separator" }, + /* The following two are for backwards compatibility with 2.0.x */ + { PANEL_OBJECT_LOCK, "lock-object" }, + { PANEL_OBJECT_LOGOUT, "logout-object" }, + { 0, NULL } +}; + +static GQuark toplevel_id_quark = 0; +static GQuark queued_changes_quark = 0; +static GQuark commit_timeout_quark = 0; + +static void panel_profile_object_id_list_update (MateConfClient *client, + MateConfValue *value, + PanelMateConfKeyType type); + +gboolean +panel_profile_map_orientation_string (const char *str, + PanelOrientation *orientation) +{ + int mapped; + + g_return_val_if_fail (orientation != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_orientation_map, str, &mapped)) + return FALSE; + + *orientation = mapped; + + return TRUE; +} + +const char * +panel_profile_map_orientation (PanelOrientation orientation) +{ + return mateconf_enum_to_string (panel_orientation_map, orientation); +} + +gboolean +panel_profile_map_speed_string (const char *str, + PanelAnimationSpeed *speed) +{ + int mapped; + + g_return_val_if_fail (speed != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_animation_speed_map, str, &mapped)) + return FALSE; + + *speed = mapped; + + return TRUE; +} + +gboolean +panel_profile_map_background_type_string (const char *str, + PanelBackgroundType *background_type) +{ + int mapped; + + g_return_val_if_fail (background_type != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_background_type_map, str, &mapped)) + return FALSE; + + *background_type = mapped; + + return TRUE; +} + +const char * +panel_profile_map_background_type (PanelBackgroundType background_type) +{ + return mateconf_enum_to_string (panel_background_type_map, background_type); +} + +gboolean +panel_profile_map_object_type_string (const char *str, + PanelObjectType *object_type) +{ + int mapped; + + g_return_val_if_fail (object_type != NULL, FALSE); + + if (!str) + return FALSE; + + if (!mateconf_string_to_enum (panel_object_type_map, str, &mapped)) + return FALSE; + + *object_type = mapped; + + return TRUE; +} + +static void +panel_profile_set_toplevel_id (PanelToplevel *toplevel, + const char *id) +{ + if (!toplevel_id_quark) + toplevel_id_quark = g_quark_from_static_string ("panel-toplevel-id"); + + g_object_set_qdata_full (G_OBJECT (toplevel), + toplevel_id_quark, + g_strdup (id), + g_free); +} + +const char * +panel_profile_get_toplevel_id (PanelToplevel *toplevel) +{ + if (!toplevel_id_quark) + return NULL; + + return g_object_get_qdata (G_OBJECT (toplevel), toplevel_id_quark); +} + +PanelToplevel * +panel_profile_get_toplevel_by_id (const char *toplevel_id) +{ + GSList *toplevels, *l; + + if (!toplevel_id || !toplevel_id [0]) + return NULL; + + toplevels = panel_toplevel_list_toplevels (); + for (l = toplevels; l; l = l->next) + if (!strcmp (panel_profile_get_toplevel_id (l->data), toplevel_id)) + return l->data; + + return NULL; +} + +char * +panel_profile_find_new_id (PanelMateConfKeyType type) +{ + MateConfClient *client; + GSList *l, *existing_ids; + const char *key; + char *retval = NULL; + char *prefix; + char *dir; + int i; + + client = panel_mateconf_get_client (); + + switch (type) { + case PANEL_MATECONF_TOPLEVELS: + prefix = "panel"; + dir = "toplevels"; + break; + case PANEL_MATECONF_OBJECTS: + prefix = "object"; + dir = "objects"; + break; + case PANEL_MATECONF_APPLETS: + prefix = "applet"; + dir = "applets"; + break; + default: + prefix = dir = NULL; + g_assert_not_reached (); + break; + } + + key = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/%s", dir); + existing_ids = mateconf_client_all_dirs (client, key, NULL); + + for (i = 0; !retval; i++) { + retval = g_strdup_printf ("%s_%d", prefix, i); + + for (l = existing_ids; l; l = l->next) + if (!strcmp (panel_mateconf_basename (l->data), retval)) { + g_free (retval); + retval = NULL; + break; + } + } + + g_assert (retval != NULL); + + for (l = existing_ids; l; l = l->next) + g_free (l->data); + g_slist_free (existing_ids); + + return retval; +} + +static void +panel_profile_set_queued_changes (PanelToplevel *toplevel, + MateConfChangeSet *changes) +{ + if (!queued_changes_quark) + queued_changes_quark = g_quark_from_static_string ("panel-queued-changes"); + + g_object_set_qdata_full (G_OBJECT (toplevel), + queued_changes_quark, + changes, + (GDestroyNotify) mateconf_change_set_unref); +} + +static MateConfChangeSet * +panel_profile_get_queued_changes (GObject *object) +{ + if (!queued_changes_quark) + return NULL; + + return g_object_get_qdata (object, queued_changes_quark); +} + +static void +panel_profile_remove_commit_timeout (guint timeout) +{ + g_source_remove (timeout); +} + +static void +panel_profile_set_commit_timeout (PanelToplevel *toplevel, + guint timeout) +{ + GDestroyNotify destroy_notify; + + if (!commit_timeout_quark) + commit_timeout_quark = g_quark_from_static_string ("panel-queued-timeout"); + + if (timeout) + destroy_notify = (GDestroyNotify) panel_profile_remove_commit_timeout; + else + destroy_notify = NULL; + + g_object_set_qdata_full (G_OBJECT (toplevel), + commit_timeout_quark, + GUINT_TO_POINTER (timeout), + destroy_notify); +} + +static guint +panel_profile_get_commit_timeout (GObject *object) +{ + if (!commit_timeout_quark) + return 0; + + return GPOINTER_TO_UINT (g_object_get_qdata (object, commit_timeout_quark)); +} + +static const char * +panel_profile_get_toplevel_key (PanelToplevel *toplevel, + const char *key) +{ + const char *id; + + id = panel_profile_get_toplevel_id (toplevel); + + return panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, id, key); +} + +#define TOPLEVEL_IS_WRITABLE_FUNC(k, p, s) \ + gboolean \ + panel_profile_is_writable_##p##_##s (PanelToplevel *toplevel) \ + { \ + MateConfClient *client; \ + const char *key; \ + client = panel_mateconf_get_client (); \ + key = panel_profile_get_toplevel_key (toplevel, k); \ + return mateconf_client_key_is_writable (client, key, NULL); \ + } + +void +panel_profile_set_background_type (PanelToplevel *toplevel, + PanelBackgroundType background_type) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/type"); + mateconf_client_set_string (client, + key, + panel_profile_map_background_type (background_type), + NULL); +} + +PanelBackgroundType +panel_profile_get_background_type (PanelToplevel *toplevel) +{ + PanelBackgroundType background_type; + MateConfClient *client; + const char *key; + char *str; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/type"); + str = mateconf_client_get_string (client, key, NULL); + + if (!str || !panel_profile_map_background_type_string (str, &background_type)) + background_type = PANEL_BACK_NONE; + + g_free (str); + + return background_type; +} + +TOPLEVEL_IS_WRITABLE_FUNC ("background/type", background, type) + +void +panel_profile_set_background_color (PanelToplevel *toplevel, + PanelColor *color) +{ + panel_profile_set_background_gdk_color (toplevel, &color->gdk); + panel_profile_set_background_opacity (toplevel, color->alpha); +} + +void +panel_profile_get_background_color (PanelToplevel *toplevel, + PanelColor *color) +{ + panel_profile_get_background_gdk_color (toplevel, &(color->gdk)); + color->alpha = panel_profile_get_background_opacity (toplevel); +} + +TOPLEVEL_IS_WRITABLE_FUNC ("background/color", background, color) + +void +panel_profile_set_background_gdk_color (PanelToplevel *toplevel, + GdkColor *gdk_color) +{ + MateConfClient *client; + const char *key; + char *color_str; + + client = panel_mateconf_get_client (); + + color_str = g_strdup_printf ("#%02x%02x%02x", + gdk_color->red / 256, + gdk_color->green / 256, + gdk_color->blue / 256); + + key = panel_profile_get_toplevel_key (toplevel, "background/color"); + mateconf_client_set_string (client, key, color_str, NULL); + + g_free (color_str); +} + +void +panel_profile_get_background_gdk_color (PanelToplevel *toplevel, + GdkColor *gdk_color) +{ + MateConfClient *client; + const char *key; + char *color_str; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/color"); + color_str = mateconf_client_get_string (client, key, NULL); + if (!color_str || !gdk_color_parse (color_str, gdk_color)) { + gdk_color->red = 0; + gdk_color->green = 0; + gdk_color->blue = 0; + } + + g_free (color_str); +} + +void +panel_profile_set_background_opacity (PanelToplevel *toplevel, + guint16 opacity) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/opacity"); + mateconf_client_set_int (client, key, opacity, NULL); +} + +guint16 +panel_profile_get_background_opacity (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + guint16 opacity; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/opacity"); + opacity = mateconf_client_get_int (client, key, NULL); + + return opacity; +} + +TOPLEVEL_IS_WRITABLE_FUNC ("background/opacity", background, opacity) + +void +panel_profile_set_background_image (PanelToplevel *toplevel, + const char *image) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/image"); + + if (image && image [0]) + mateconf_client_set_string (client, key, image, NULL); + else + mateconf_client_unset (client, key, NULL); +} + +char * +panel_profile_get_background_image (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + char *retval; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "background/image"); + retval = mateconf_client_get_string (client, key, NULL); + + return retval; +} + +TOPLEVEL_IS_WRITABLE_FUNC ("background/image", background, image) + +void +panel_profile_set_toplevel_name (PanelToplevel *toplevel, + const char *name) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "name"); + + if (name && name [0]) + mateconf_client_set_string (client, key, name, NULL); + else + mateconf_client_unset (client, key, NULL); +} + +char * +panel_profile_get_toplevel_name (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + char *retval; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "name"); + retval = mateconf_client_get_string (client, key, NULL); + + return retval; +} + +TOPLEVEL_IS_WRITABLE_FUNC ("name", toplevel, name) + +void +panel_profile_set_toplevel_orientation (PanelToplevel *toplevel, + PanelOrientation orientation) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "orientation"); + mateconf_client_set_string (client, + key, + panel_profile_map_orientation (orientation), + NULL); +} + +PanelOrientation +panel_profile_get_toplevel_orientation (PanelToplevel *toplevel) +{ + PanelOrientation orientation; + MateConfClient *client; + const char *key; + char *str; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "orientation"); + str = mateconf_client_get_string (client, key, NULL); + + if (!panel_profile_map_orientation_string (str, &orientation)) + orientation = panel_toplevel_get_orientation (toplevel); + + g_free (str); + + return orientation; +} + +TOPLEVEL_IS_WRITABLE_FUNC ("orientation", toplevel, orientation) + +#define TOPLEVEL_GET_SET_FUNCS(k, p, t, s, a) \ + void \ + panel_profile_set_##p##_##s (PanelToplevel *toplevel, a s) \ + { \ + MateConfClient *client; \ + const char *key; \ + client = panel_mateconf_get_client (); \ + key = panel_profile_get_toplevel_key (toplevel, k); \ + mateconf_client_set_##t (client, key, s, NULL); \ + } \ + a \ + panel_profile_get_##p##_##s (PanelToplevel *toplevel) \ + { \ + MateConfClient *client; \ + const char *key; \ + a retval; \ + client = panel_mateconf_get_client (); \ + key = panel_profile_get_toplevel_key (toplevel, k); \ + retval = mateconf_client_get_##t (client, key, NULL); \ + return retval; \ + } \ + TOPLEVEL_IS_WRITABLE_FUNC(k, p, s) + +TOPLEVEL_GET_SET_FUNCS ("size", toplevel, int, size, int) +TOPLEVEL_GET_SET_FUNCS ("expand", toplevel, bool, expand, gboolean) +TOPLEVEL_GET_SET_FUNCS ("auto_hide", toplevel, bool, auto_hide, gboolean) +TOPLEVEL_GET_SET_FUNCS ("enable_buttons", toplevel, bool, enable_buttons, gboolean) +TOPLEVEL_GET_SET_FUNCS ("enable_arrows", toplevel, bool, enable_arrows, gboolean) +TOPLEVEL_GET_SET_FUNCS ("background/fit", background, bool, fit, gboolean) +TOPLEVEL_GET_SET_FUNCS ("background/stretch", background, bool, stretch, gboolean) +TOPLEVEL_GET_SET_FUNCS ("background/rotate", background, bool, rotate, gboolean) + +static const char * +panel_profile_get_attached_object_key (PanelToplevel *toplevel, + const char *key) +{ + GtkWidget *attach_widget; + const char *id; + + attach_widget = panel_toplevel_get_attach_widget (toplevel); + + id = mate_panel_applet_get_id_by_widget (attach_widget); + + if (!id) + return NULL; + + return panel_mateconf_full_key (PANEL_MATECONF_OBJECTS, id, key); +} + +void +panel_profile_set_attached_custom_icon (PanelToplevel *toplevel, + const char *custom_icon) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_attached_object_key (toplevel, "use_custom_icon"); + if (key) + mateconf_client_set_bool (client, key, custom_icon != NULL, NULL); + + key = panel_profile_get_attached_object_key (toplevel, "custom_icon"); + if (key) + mateconf_client_set_string (client, key, sure_string (custom_icon), NULL); +} + +char * +panel_profile_get_attached_custom_icon (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_attached_object_key (toplevel, "use_custom_icon"); + if (!key || !mateconf_client_get_bool (client, key, NULL)) + return NULL; + + key = panel_profile_get_attached_object_key (toplevel, "custom_icon"); + + return key ? mateconf_client_get_string (client, key, NULL) : NULL; +} + +gboolean +panel_profile_is_writable_attached_custom_icon (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_attached_object_key (toplevel, "use_custom_icon"); + if (!key) + return TRUE; + + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + key = panel_profile_get_attached_object_key (toplevel, "custom_icon"); + + return key ? mateconf_client_key_is_writable (client, key, NULL) : TRUE; +} + +void +panel_profile_set_attached_tooltip (PanelToplevel *toplevel, + const char *tooltip) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_attached_object_key (toplevel, "tooltip"); + if (key) + mateconf_client_set_string (client, key, tooltip, NULL); +} + +char * +panel_profile_get_attached_tooltip (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_attached_object_key (toplevel, "tooltip"); + + return key ? mateconf_client_get_string (client, key, NULL) : NULL; +} + +gboolean +panel_profile_is_writable_attached_tooltip (PanelToplevel *toplevel) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_attached_object_key (toplevel, "tooltip"); + + return key ? mateconf_client_key_is_writable (client, key, NULL) : TRUE; +} + +static PanelBackgroundType +get_background_type (MateConfClient *client, + const char *toplevel_dir) +{ + PanelBackgroundType background_type; + GError *error = NULL; + const char *key; + char *type_str; + + key = panel_mateconf_sprintf ("%s/background/type", toplevel_dir); + type_str = mateconf_client_get_string (client, key, &error); + if (error) { + g_warning (_("Error reading MateConf string value '%s': %s"), + key, error->message); + g_error_free (error); + return PANEL_BACK_NONE; + } + + if (!type_str || !panel_profile_map_background_type_string (type_str, &background_type)) + background_type = PANEL_BACK_NONE; + + g_free (type_str); + + return background_type; +} + +static void +get_background_color (MateConfClient *client, + const char *toplevel_dir, + PanelColor *color) +{ + GError *error; + const char *key; + char *color_str; + + error = NULL; + key = panel_mateconf_sprintf ("%s/background/color", toplevel_dir); + color_str = mateconf_client_get_string (client, key, &error); + if (error) { + g_warning (_("Error reading MateConf string value '%s': %s"), + key, error->message); + g_error_free (error); + } else if (!color_str || !gdk_color_parse (color_str, &(color->gdk))) { + color->gdk.red = 0; + color->gdk.green = 0; + color->gdk.blue = 0; + } + + g_free (color_str); + + error = NULL; + key = panel_mateconf_sprintf ("%s/background/opacity", toplevel_dir); + color->alpha = mateconf_client_get_int (client, key, &error); + if (error) { + g_warning (_("Error reading MateConf integer value '%s': %s"), + key, error->message); + g_error_free (error); + color->alpha = 65535; /* fallback to fully opaque */ + } +} + +static char * +get_background_image (MateConfClient *client, + const char *toplevel_dir, + gboolean *fit, + gboolean *stretch, + gboolean *rotate) +{ + const char *key; + GError *error = NULL; + char *image; + + key = panel_mateconf_sprintf ("%s/background/image", toplevel_dir); + image = mateconf_client_get_string (client, key, &error); + if (error) { + g_warning (_("Error reading MateConf string value '%s': %s"), + key, error->message); + g_error_free (error); + } + + key = panel_mateconf_sprintf ("%s/background/fit", toplevel_dir); + *fit = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/background/stretch", toplevel_dir); + *stretch = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/background/rotate", toplevel_dir); + *rotate = mateconf_client_get_bool (client, key, NULL); + + return image; +} + +static void +panel_profile_load_background (PanelToplevel *toplevel, + MateConfClient *client, + const char *toplevel_dir) +{ + PanelWidget *panel_widget; + PanelBackground *background; + PanelBackgroundType background_type; + PanelColor color; + char *image; + gboolean fit; + gboolean stretch; + gboolean rotate; + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + background = &panel_widget->background; + + background_type = get_background_type (client, toplevel_dir); + + get_background_color (client, toplevel_dir, &color); + + image = get_background_image (client, toplevel_dir, &fit, &stretch, &rotate); + + panel_background_set (background, + background_type, + &color, + image, + fit, + stretch, + rotate); + + g_free (image); +} + +static gboolean +panel_profile_commit_toplevel_changes (PanelToplevel *toplevel) +{ + MateConfChangeSet *queued_changes; + + queued_changes = panel_profile_get_queued_changes (G_OBJECT (toplevel)); + if (queued_changes) + mateconf_client_commit_change_set ( + panel_mateconf_get_client (), + queued_changes, FALSE, NULL); + + panel_profile_set_queued_changes (toplevel, NULL); + panel_profile_set_commit_timeout (toplevel, 0); + + return FALSE; +} + +static void +panel_profile_queue_toplevel_location_change (PanelToplevel *toplevel, + ToplevelLocationChange *change) +{ + MateConfChangeSet *queued_changes; + guint commit_timeout; + + queued_changes = panel_profile_get_queued_changes (G_OBJECT (toplevel)); + if (!queued_changes) { + queued_changes = mateconf_change_set_new (); + panel_profile_set_queued_changes (toplevel, queued_changes); + } + + if (change->screen_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "screen"), + gdk_screen_get_number (change->screen)); + + if (change->monitor_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "monitor"), + change->monitor); + + if (change->size_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "size"), + change->size); + + if (change->orientation_changed) + mateconf_change_set_set_string ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "orientation"), + mateconf_enum_to_string (panel_orientation_map, change->orientation)); + + if (!panel_toplevel_get_expand (toplevel)) { + if (change->x_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "x"), + change->x); + + if (change->x_right_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "x_right"), + change->x_right); + + if (change->x_centered_changed) + mateconf_change_set_set_bool ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "x_centered"), + change->x_centered); + + if (change->y_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "y"), + change->y); + + if (change->y_bottom_changed) + mateconf_change_set_set_int ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "y_bottom"), + change->y_bottom); + + if (change->y_centered_changed) + mateconf_change_set_set_bool ( + queued_changes, + panel_profile_get_toplevel_key (toplevel, "y_centered"), + change->y_centered); + } + + commit_timeout = panel_profile_get_commit_timeout (G_OBJECT (toplevel)); + if (!commit_timeout) { + commit_timeout = + g_timeout_add (500, + (GSourceFunc) panel_profile_commit_toplevel_changes, + toplevel); + panel_profile_set_commit_timeout (toplevel, commit_timeout); + } +} + +#define TOPLEVEL_LOCATION_CHANGED_HANDLER(c) \ + static void \ + panel_profile_toplevel_##c##_changed (PanelToplevel *toplevel) \ + { \ + ToplevelLocationChange change = { NULL }; \ + change.c##_changed = TRUE; \ + change.c = panel_toplevel_get_##c (toplevel); \ + panel_profile_queue_toplevel_location_change (toplevel, &change); \ + } + +TOPLEVEL_LOCATION_CHANGED_HANDLER(monitor) +TOPLEVEL_LOCATION_CHANGED_HANDLER(size) +TOPLEVEL_LOCATION_CHANGED_HANDLER(orientation) +TOPLEVEL_LOCATION_CHANGED_HANDLER(x_centered) +TOPLEVEL_LOCATION_CHANGED_HANDLER(y_centered) + +#define TOPLEVEL_POSITION_CHANGED_HANDLER(c) \ + static void \ + panel_profile_toplevel_##c##_changed (PanelToplevel *toplevel) \ + { \ + ToplevelLocationChange change = { NULL }; \ + int x, y, x_right, y_bottom; \ + change.c##_changed = TRUE; \ + panel_toplevel_get_position (toplevel, \ + &x, &x_right, \ + &y, &y_bottom); \ + change.c = c; \ + panel_profile_queue_toplevel_location_change (toplevel, &change); \ + } + +TOPLEVEL_POSITION_CHANGED_HANDLER(x) +TOPLEVEL_POSITION_CHANGED_HANDLER(x_right) +TOPLEVEL_POSITION_CHANGED_HANDLER(y) +TOPLEVEL_POSITION_CHANGED_HANDLER(y_bottom) + +static void +panel_profile_toplevel_screen_changed (PanelToplevel *toplevel) +{ + ToplevelLocationChange change = { NULL }; + + change.screen_changed = TRUE; + change.screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + + panel_profile_queue_toplevel_location_change (toplevel, &change); +} + +static void +panel_profile_connect_to_toplevel (PanelToplevel *toplevel) +{ + g_signal_connect (toplevel, "notify::screen", + G_CALLBACK (panel_profile_toplevel_screen_changed), NULL); + g_signal_connect (toplevel, "notify::monitor", + G_CALLBACK (panel_profile_toplevel_monitor_changed), NULL); + g_signal_connect (toplevel, "notify::size", + G_CALLBACK (panel_profile_toplevel_size_changed), NULL); + g_signal_connect (toplevel, "notify::x", + G_CALLBACK (panel_profile_toplevel_x_changed), NULL); + g_signal_connect (toplevel, "notify::x-right", + G_CALLBACK (panel_profile_toplevel_x_right_changed), NULL); + g_signal_connect (toplevel, "notify::x-centered", + G_CALLBACK (panel_profile_toplevel_x_centered_changed), NULL); + g_signal_connect (toplevel, "notify::y", + G_CALLBACK (panel_profile_toplevel_y_changed), NULL); + g_signal_connect (toplevel, "notify::y-bottom", + G_CALLBACK (panel_profile_toplevel_y_bottom_changed), NULL); + g_signal_connect (toplevel, "notify::y-centered", + G_CALLBACK (panel_profile_toplevel_y_centered_changed), NULL); + g_signal_connect (toplevel, "notify::orientation", + G_CALLBACK (panel_profile_toplevel_orientation_changed), NULL); +} + +static void +set_name_from_string (PanelToplevel *toplevel, + const char *str) +{ + if (!str) + return; + + panel_toplevel_set_name (toplevel, str); +} + +static void +set_orientation_from_string (PanelToplevel *toplevel, + const char *str) +{ + PanelOrientation orientation; + + if (!str || !panel_profile_map_orientation_string (str, &orientation)) + return; + + panel_toplevel_set_orientation (toplevel, orientation); +} + +static void +set_animation_speed_from_string (PanelToplevel *toplevel, + const char *str) +{ + PanelAnimationSpeed animation_speed; + + if (!str || !panel_profile_map_speed_string (str, &animation_speed)) + return; + + panel_toplevel_set_animation_speed (toplevel, animation_speed); +} + +static void +panel_profile_toplevel_change_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelToplevel *toplevel) +{ + MateConfValue *value; + const char *key; + + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + + if (!(value = mateconf_entry_get_value (entry))) + return; + +#define UPDATE_STRING(k, n) \ + if (!strcmp (key, k)) { \ + if (value->type == MATECONF_VALUE_STRING) \ + set_##n##_from_string (toplevel, \ + mateconf_value_get_string (value)); \ + } + +#define UPDATE_INT(k, n) \ + if (!strcmp (key, k)) { \ + if (value->type == MATECONF_VALUE_INT) \ + panel_toplevel_set_##n (toplevel, \ + mateconf_value_get_int (value)); \ + } + +#define UPDATE_BOOL(k, n) \ + if (!strcmp (key, k)) { \ + if (value->type == MATECONF_VALUE_BOOL) \ + panel_toplevel_set_##n (toplevel, \ + mateconf_value_get_bool (value)); \ + } + +#define UPDATE_POS(k, n, n2) \ + if (!strcmp (key, k)) { \ + if (value->type == MATECONF_VALUE_INT) { \ + int x, x_right, y, y_bottom; \ + panel_toplevel_get_position (toplevel, &x, &x_right, \ + &y, &y_bottom); \ + panel_toplevel_set_##n ( \ + toplevel, \ + mateconf_value_get_int (value), \ + n2, \ + panel_toplevel_get_##n##_centered (toplevel)); \ + } \ + } + +#define UPDATE_POS2(k, n, n2) \ + if (!strcmp (key, k)) { \ + if (value->type == MATECONF_VALUE_INT) { \ + int x, x_right, y, y_bottom; \ + panel_toplevel_get_position (toplevel, &x, &x_right, \ + &y, &y_bottom); \ + panel_toplevel_set_##n ( \ + toplevel, \ + n, \ + mateconf_value_get_int (value), \ + panel_toplevel_get_##n##_centered (toplevel)); \ + } \ + } + +#define UPDATE_CENTERED(k, n, n2) \ + if (!strcmp (key, k)) { \ + if (value->type == MATECONF_VALUE_BOOL) { \ + int x, x_right, y, y_bottom; \ + panel_toplevel_get_position (toplevel, &x, &x_right, \ + &y, &y_bottom); \ + panel_toplevel_set_##n ( \ + toplevel, n, n2, mateconf_value_get_bool (value)); \ + } \ + } + + if (!strcmp (key, "screen")) { + if (value->type == MATECONF_VALUE_INT) { + GdkScreen *screen; + + screen = gdk_display_get_screen ( + gdk_display_get_default (), + mateconf_value_get_int (value)); + if (screen) + gtk_window_set_screen (GTK_WINDOW (toplevel), screen); + else + /* Make sure to set the key back to an actual + * available screen so it will get loaded on + * next startup. + */ + panel_profile_toplevel_screen_changed (toplevel); + } + + } + else UPDATE_INT ("monitor", monitor) + else UPDATE_STRING ("name", name) + else UPDATE_BOOL ("expand", expand) + else UPDATE_STRING ("orientation", orientation) + else UPDATE_INT ("size", size) + else UPDATE_POS ("x", x, x_right) + else UPDATE_POS ("y", y, y_bottom) + else UPDATE_POS2 ("x_right", x, x_right) + else UPDATE_POS2 ("y_bottom", y, y_bottom) + else UPDATE_CENTERED ("x_centered", x, x_right) + else UPDATE_CENTERED ("y_centered", y, y_bottom) + else UPDATE_BOOL ("auto_hide", auto_hide) + else UPDATE_BOOL ("enable_animations", animate) + else UPDATE_BOOL ("enable_buttons", enable_buttons) + else UPDATE_BOOL ("enable_arrows", enable_arrows) + else UPDATE_INT ("hide_delay", hide_delay) + else UPDATE_INT ("unhide_delay", unhide_delay) + else UPDATE_INT ("auto_hide_size", auto_hide_size) + else UPDATE_STRING ("animation_speed", animation_speed) +} + +static void +panel_profile_background_change_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelToplevel *toplevel) +{ + PanelWidget *panel_widget; + PanelBackground *background; + MateConfValue *value; + const char *key; + + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + + if (!(value = mateconf_entry_get_value (entry))) + return; + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + background = &panel_widget->background; + + if (!strcmp (key, "type")) { + if (value->type == MATECONF_VALUE_STRING) { + PanelBackgroundType background_type; + + if (panel_profile_map_background_type_string ( + mateconf_value_get_string (value), + &background_type)) { + panel_background_set_type (background, background_type); + panel_toplevel_update_edges (toplevel); + } + } + } else if (!strcmp (key, "color")) { + if (value->type == MATECONF_VALUE_STRING) { + GdkColor gdk_color; + const char *str; + + str = mateconf_value_get_string (value); + + if (gdk_color_parse (str, &gdk_color)) + panel_background_set_gdk_color (background, &gdk_color); + } + } else if (!strcmp (key, "opacity")) { + if (value->type == MATECONF_VALUE_INT) + panel_background_set_opacity (background, + mateconf_value_get_int (value)); + } else if (!strcmp (key, "image")) { + if (value->type == MATECONF_VALUE_STRING) + panel_background_set_image (background, + mateconf_value_get_string (value)); + } else if (!strcmp (key, "fit")) { + if (value->type == MATECONF_VALUE_BOOL) + panel_background_set_fit (background, + mateconf_value_get_bool (value)); + } else if (!strcmp (key, "stretch")) { + if (value->type == MATECONF_VALUE_BOOL) + panel_background_set_stretch (background, + mateconf_value_get_bool (value)); + } else if (!strcmp (key, "rotate")) { + if (value->type == MATECONF_VALUE_BOOL) + panel_background_set_rotate (background, + mateconf_value_get_bool (value)); + } +} + +static void +panel_profile_disconnect_toplevel (PanelToplevel *toplevel, + gpointer data) +{ + MateConfClient *client; + guint notify_id = GPOINTER_TO_UINT (data); + + client = panel_mateconf_get_client (); + + mateconf_client_notify_remove (client, notify_id); +} + +guint +panel_profile_toplevel_notify_add (PanelToplevel *toplevel, + const char *key, + MateConfClientNotifyFunc func, + gpointer data) +{ + MateConfClient *client; + const char *tmp; + guint retval; + + client = panel_mateconf_get_client (); + + if (!key) + tmp = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/toplevels/%s", + panel_profile_get_toplevel_id (toplevel)); + else + tmp = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/toplevels/%s/%s", + panel_profile_get_toplevel_id (toplevel), + key); + + retval = mateconf_client_notify_add (client, tmp, func, data, NULL, NULL); + + return retval; +} + +static void +panel_profile_save_id_list (PanelMateConfKeyType type, + GSList *list, + gboolean resave) +{ + MateConfClient *client; + const char *key; + const char *id_list; + + g_assert (!(resave && list != NULL)); + + client = panel_mateconf_get_client (); + + id_list = panel_mateconf_key_type_to_id_list (type); + + key = panel_mateconf_general_key (id_list); + if (resave) + list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + else { + /* Make sure the elements in the list appear only once. We only + * do it when we save a list with new elements. */ + list = panel_g_slist_make_unique (list, + (GCompareFunc) strcmp, + TRUE); + } + + mateconf_client_set_list (client, key, MATECONF_VALUE_STRING, list, NULL); + + g_slist_foreach (list, (GFunc) g_free, NULL); + g_slist_free (list); +} + +static inline void +panel_profile_save_other_id_lists (PanelMateConfKeyType type) +{ + if (type != PANEL_MATECONF_TOPLEVELS) + panel_profile_save_id_list (PANEL_MATECONF_TOPLEVELS, NULL, TRUE); + + if (type != PANEL_MATECONF_OBJECTS) + panel_profile_save_id_list (PANEL_MATECONF_OBJECTS, NULL, TRUE); + + if (type != PANEL_MATECONF_APPLETS) + panel_profile_save_id_list (PANEL_MATECONF_APPLETS, NULL, TRUE); +} + +void +panel_profile_add_to_list (PanelMateConfKeyType type, + const char *id) +{ + MateConfClient *client; + GSList *list; + const char *key; + const char *id_list; + char *new_id; + + client = panel_mateconf_get_client (); + + id_list = panel_mateconf_key_type_to_id_list (type); + + key = panel_mateconf_general_key (id_list); + list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + new_id = id ? g_strdup (id) : panel_profile_find_new_id (type); + + list = g_slist_append (list, new_id); + + panel_profile_save_id_list (type, list, FALSE); + panel_profile_save_other_id_lists (type); +} + +void +panel_profile_remove_from_list (PanelMateConfKeyType type, + const char *id) +{ + MateConfClient *client; + GSList *list, *l; + const char *key; + const char *id_list; + + client = panel_mateconf_get_client (); + + id_list = panel_mateconf_key_type_to_id_list (type); + + key = panel_mateconf_general_key (id_list); + list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + /* Remove all occurrence of id and not just the first. We're more solid + * this way (see bug #137308 for example). */ + l = list; + while (l) { + GSList *next; + + next = l->next; + + if (!strcmp (id, l->data)) { + g_free (l->data); + list = g_slist_delete_link (list, l); + } + + l = next; + } + + panel_profile_save_id_list (type, list, FALSE); + panel_profile_save_other_id_lists (type); +} + +static gboolean +panel_profile_id_list_is_writable (PanelMateConfKeyType type) +{ + MateConfClient *client; + const char *key; + const char *id_list; + + client = panel_mateconf_get_client (); + + id_list = panel_mateconf_key_type_to_id_list (type); + + key = panel_mateconf_general_key (id_list); + return mateconf_client_key_is_writable (client, key, NULL); +} + +gboolean +panel_profile_id_lists_are_writable (void) +{ + return + panel_profile_id_list_is_writable (PANEL_MATECONF_TOPLEVELS) && + panel_profile_id_list_is_writable (PANEL_MATECONF_APPLETS) && + panel_profile_id_list_is_writable (PANEL_MATECONF_OBJECTS); +} + +static gboolean +panel_profile_find_empty_spot (GdkScreen *screen, + PanelOrientation *orientation, + int *monitor) +{ + GSList *li; + int i; + int *filled_spots; + gboolean found_a_spot = FALSE; + + *monitor = 0; + *orientation = PANEL_ORIENTATION_TOP; + + filled_spots = g_new0 (int, panel_multiscreen_monitors (screen)); + + for (li = panel_toplevel_list_toplevels (); li != NULL; li = li->next) { + PanelToplevel *toplevel = li->data; + GdkScreen *toplevel_screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + int toplevel_monitor = panel_toplevel_get_monitor (toplevel); + + if (toplevel_screen != screen || + panel_toplevel_get_is_attached (toplevel) || + toplevel_monitor < 0) + continue; + + filled_spots[toplevel_monitor] |= panel_toplevel_get_orientation (toplevel); + } + + for (i = 0; i < panel_multiscreen_monitors (screen); i++) { + /* These are ordered based on "priority" of the + orientation when picking it */ + if ( ! (filled_spots[i] & PANEL_ORIENTATION_TOP)) { + *orientation = PANEL_ORIENTATION_TOP; + *monitor = i; + found_a_spot = TRUE; + break; + } else if ( ! (filled_spots[i] & PANEL_ORIENTATION_BOTTOM)) { + *orientation = PANEL_ORIENTATION_BOTTOM; + *monitor = i; + found_a_spot = TRUE; + break; + } else if ( ! (filled_spots[i] & PANEL_ORIENTATION_RIGHT)) { + *orientation = PANEL_ORIENTATION_RIGHT; + *monitor = i; + found_a_spot = TRUE; + break; + } else if ( ! (filled_spots[i] & PANEL_ORIENTATION_LEFT)) { + *orientation = PANEL_ORIENTATION_LEFT; + *monitor = i; + found_a_spot = TRUE; + break; + } + } + + g_free (filled_spots); + + return found_a_spot; +} + +void +panel_profile_create_toplevel (GdkScreen *screen) +{ + MateConfClient *client; + const char *key; + char *id; + char *dir; + PanelOrientation orientation; + int monitor; + + g_return_if_fail (screen != NULL); + + client = panel_mateconf_get_client (); + + id = panel_profile_find_new_id (PANEL_MATECONF_TOPLEVELS); + + dir = g_strdup_printf (PANEL_CONFIG_DIR "/toplevels/%s", id); + panel_mateconf_associate_schemas_in_dir (client, dir, PANEL_SCHEMAS_DIR "/toplevels"); + g_free (dir); + + key = panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, id, "screen"); + mateconf_client_set_int (client, key, gdk_screen_get_number (screen), NULL); + + if (panel_profile_find_empty_spot (screen, &orientation, &monitor)) { + key = panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, id, "monitor"); + mateconf_client_set_int (client, key, monitor, NULL); + + key = panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, id, "orientation"); + mateconf_client_set_string (client, key, panel_profile_map_orientation (orientation), NULL); + } + + panel_profile_add_to_list (PANEL_MATECONF_TOPLEVELS, id); + + g_free (id); +} + +static void +panel_profile_delete_toplevel_objects (const char *toplevel_id, + PanelMateConfKeyType key_type) +{ + MateConfClient *client; + const char *key; + GSList *new_list = NULL,*list, *l; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_general_key (panel_mateconf_key_type_to_id_list (key_type)); + list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + for (l = list; l; l = l->next) { + char *id = l->data; + char *parent_toplevel_id; + + key = panel_mateconf_full_key (key_type, id, "toplevel_id"); + parent_toplevel_id = mateconf_client_get_string (client, key, NULL); + + if (parent_toplevel_id && !strcmp (toplevel_id, parent_toplevel_id)) { + g_free (id); + g_free (parent_toplevel_id); + continue; + } + + new_list = g_slist_prepend (new_list, id); + + g_free (parent_toplevel_id); + } + g_slist_free (list); + + key = panel_mateconf_general_key (panel_mateconf_key_type_to_id_list (key_type)); + mateconf_client_set_list (client, key, MATECONF_VALUE_STRING, new_list, NULL); + + for (l = new_list; l; l = l->next) + g_free (l->data); + g_slist_free (new_list); +} + +void +panel_profile_delete_toplevel (PanelToplevel *toplevel) +{ + const char *toplevel_id; + + toplevel_id = panel_profile_get_toplevel_id (toplevel); + + panel_profile_delete_toplevel_objects (toplevel_id, PANEL_MATECONF_OBJECTS); + panel_profile_delete_toplevel_objects (toplevel_id, PANEL_MATECONF_APPLETS); + + panel_profile_remove_from_list (PANEL_MATECONF_TOPLEVELS, toplevel_id); +} + +static GdkScreen * +get_toplevel_screen (MateConfClient *client, + const char *toplevel_dir) +{ + GError *error = NULL; + GdkDisplay *display; + const char *key; + int screen_n; + + key = panel_mateconf_sprintf ("%s/screen", toplevel_dir); + screen_n = mateconf_client_get_int (client, key, &error); + if (error) { + g_warning (_("Error reading MateConf integer value '%s': %s"), + key, error->message); + g_error_free (error); + return gdk_screen_get_default (); + } + + display = gdk_display_get_default (); + + if (screen_n < 0 || screen_n >= gdk_display_get_n_screens (display)) { +#if 0 + g_warning (_("Panel '%s' is set to be displayed on screen %d which " + "is not currently available. Not loading this panel."), + toplevel_dir, screen_n); +#endif + return NULL; + } + + return gdk_display_get_screen (display, screen_n); +} + +PanelToplevel * +panel_profile_load_toplevel (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + const char *toplevel_id) +{ + PanelToplevel *toplevel; + GdkScreen *screen; + GError *error; + const char *key; + char *toplevel_dir; + guint notify_id; + + if (!toplevel_id || !toplevel_id [0]) + return NULL; + + toplevel_dir = g_strdup_printf ("%s/toplevels/%s", profile_dir, toplevel_id); + + if (!mateconf_client_dir_exists (client, toplevel_dir, NULL)) + panel_mateconf_associate_schemas_in_dir ( + client, toplevel_dir, PANEL_SCHEMAS_DIR "/toplevels"); + + mateconf_client_add_dir (client, + toplevel_dir, + MATECONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + + key = panel_mateconf_sprintf ("%s/background", toplevel_dir); + mateconf_client_add_dir (client, + key, + MATECONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + + if (!(screen = get_toplevel_screen (client, toplevel_dir))) { + mateconf_client_remove_dir (client, key, NULL); + mateconf_client_remove_dir (client, toplevel_dir, NULL); + g_free (toplevel_dir); + return NULL; + } + + toplevel = g_object_new (PANEL_TYPE_TOPLEVEL, + "screen", screen, + NULL); + +#define GET_INT(k, fn) \ + { \ + int val; \ + error = NULL; \ + key = panel_mateconf_sprintf ("%s/" k, toplevel_dir); \ + val = mateconf_client_get_int (client, key, &error); \ + if (!error) \ + panel_toplevel_set_##fn (toplevel, val); \ + else { \ + g_warning (_("Error reading MateConf integer value '%s': %s"), \ + key, error->message); \ + g_error_free (error); \ + } \ + } + +#define GET_BOOL(k, fn) \ + { \ + gboolean val; \ + error = NULL; \ + key = panel_mateconf_sprintf ("%s/" k, toplevel_dir); \ + val = mateconf_client_get_bool (client, key, &error); \ + if (!error) \ + panel_toplevel_set_##fn (toplevel, val); \ + else { \ + g_warning (_("Error reading MateConf boolean value '%s': %s"), \ + key, error->message); \ + g_error_free (error); \ + } \ + } + +#define GET_STRING(k, fn) \ + { \ + char *val; \ + error = NULL; \ + key = panel_mateconf_sprintf ("%s/" k, toplevel_dir); \ + val = mateconf_client_get_string (client, key, &error); \ + if (!error && val) { \ + set_##fn##_from_string (toplevel, val); \ + g_free (val); \ + } else if (error) { \ + g_warning (_("Error reading MateConf string value '%s': %s"), \ + key, error->message); \ + g_error_free (error); \ + } \ + } + + GET_STRING ("name", name); + GET_INT ("monitor", monitor); + GET_BOOL ("expand", expand); + GET_STRING ("orientation", orientation); + GET_INT ("size", size); + GET_BOOL ("auto_hide", auto_hide); + GET_BOOL ("enable_animations", animate); + GET_BOOL ("enable_buttons", enable_buttons); + GET_BOOL ("enable_arrows", enable_arrows); + GET_INT ("hide_delay", hide_delay); + GET_INT ("unhide_delay", unhide_delay); + GET_INT ("auto_hide_size", auto_hide_size); + GET_STRING ("animation_speed", animation_speed); + +#define GET_POSITION(a, b, c, fn) \ + { \ + gboolean centered; \ + int position; \ + int position2; \ + key = panel_mateconf_sprintf ("%s/" c, toplevel_dir); \ + centered = mateconf_client_get_bool (client, key, &error); \ + if (!error) { \ + key = panel_mateconf_sprintf ("%s/" a, toplevel_dir); \ + position = mateconf_client_get_int (client, key, &error); \ + } \ + if (!error) { \ + MateConfValue *value; \ + key = panel_mateconf_sprintf ("%s/" b, toplevel_dir); \ + /* we need to do this since the key was added in 2.19 and \ + * the default value returned when the key is not set \ + * (for people coming from older versions) is 0, which \ + * is not what we want. */ \ + value = mateconf_client_get_without_default (client, key, &error);\ + if (value && value->type == MATECONF_VALUE_INT) \ + position2 = mateconf_value_get_int (value); \ + else \ + position2 = -1; \ + \ + if (value) \ + mateconf_value_free (value); \ + } \ + if (!error) \ + panel_toplevel_set_##fn (toplevel, position, position2, \ + centered); \ + else { \ + g_warning (_("Error reading MateConf integer value '%s': %s"), \ + key, error->message); \ + g_error_free (error); \ + } \ + } + + GET_POSITION ("x", "x_right", "x_centered", x); + GET_POSITION ("y", "y_bottom", "y_centered", y); + + panel_profile_load_background (toplevel, client, toplevel_dir); + + panel_profile_set_toplevel_id (toplevel, toplevel_id); + + panel_profile_connect_to_toplevel (toplevel); + + notify_id = panel_profile_toplevel_notify_add ( + toplevel, + NULL, + (MateConfClientNotifyFunc) panel_profile_toplevel_change_notify, + toplevel); + g_signal_connect (toplevel, "destroy", + G_CALLBACK (panel_profile_disconnect_toplevel), + GUINT_TO_POINTER (notify_id)); + + notify_id = panel_profile_toplevel_notify_add ( + toplevel, + "background", + (MateConfClientNotifyFunc) panel_profile_background_change_notify, + toplevel); + g_signal_connect (toplevel, "destroy", + G_CALLBACK (panel_profile_disconnect_toplevel), + GUINT_TO_POINTER (notify_id)); + + g_free (toplevel_dir); + + panel_setup (toplevel); + + return toplevel; +} + +static void +panel_profile_load_and_show_toplevel (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + const char *toplevel_id) +{ + PanelToplevel *toplevel; + const char *id_list; + const char *key; + MateConfValue *value; + gboolean loading_queued_applets; + + toplevel = panel_profile_load_toplevel (client, profile_dir, type, toplevel_id); + if (!toplevel) + return; + + gtk_widget_show (GTK_WIDGET (toplevel)); + + loading_queued_applets = FALSE; + + /* reload list of objects to get those that might be on the new + * toplevel */ + id_list = panel_mateconf_key_type_to_id_list (PANEL_MATECONF_OBJECTS); + key = panel_mateconf_sprintf ("%s/general/%s", profile_dir, id_list); + value = mateconf_client_get (client, key, NULL); + if (value) { + panel_profile_object_id_list_update (client, value, + PANEL_MATECONF_OBJECTS); + loading_queued_applets = TRUE; + mateconf_value_free (value); + } + + id_list = panel_mateconf_key_type_to_id_list (PANEL_MATECONF_APPLETS); + key = panel_mateconf_sprintf ("%s/general/%s", profile_dir, id_list); + value = mateconf_client_get (client, key, NULL); + if (value) { + panel_profile_object_id_list_update (client, value, + PANEL_MATECONF_APPLETS); + loading_queued_applets = TRUE; + mateconf_value_free (value); + } + + if (!loading_queued_applets) + mate_panel_applet_load_queued_applets (FALSE); +} + +static void +panel_profile_load_and_show_toplevel_startup (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + const char *toplevel_id) +{ + PanelToplevel *toplevel; + + toplevel = panel_profile_load_toplevel (client, profile_dir, type, toplevel_id); + if (toplevel) + gtk_widget_show (GTK_WIDGET (toplevel)); +} + +static void +panel_profile_destroy_toplevel (const char *id) +{ + PanelToplevel *toplevel; + + if (!(toplevel = panel_profile_get_toplevel_by_id (id))) + return; + + gtk_widget_destroy (GTK_WIDGET (toplevel)); +} + +char * +panel_profile_prepare_object_with_id (PanelObjectType object_type, + const char *toplevel_id, + int position, + gboolean right_stick) +{ + PanelMateConfKeyType key_type; + MateConfClient *client; + const char *key; + char *id; + char *dir; + + key_type = (object_type == PANEL_OBJECT_APPLET) ? PANEL_MATECONF_APPLETS : PANEL_MATECONF_OBJECTS; + + client = panel_mateconf_get_client (); + + id = panel_profile_find_new_id (key_type); + + dir = g_strdup_printf (PANEL_CONFIG_DIR "/%s/%s", + (key_type == PANEL_MATECONF_APPLETS) ? "applets" : "objects", + id); + panel_mateconf_associate_schemas_in_dir (client, dir, PANEL_SCHEMAS_DIR "/objects"); + + key = panel_mateconf_full_key (key_type, id, "object_type"); + mateconf_client_set_string (client, + key, + mateconf_enum_to_string (panel_object_type_map, object_type), + NULL); + + key = panel_mateconf_full_key (key_type, id, "toplevel_id"); + mateconf_client_set_string (client, key, toplevel_id, NULL); + + key = panel_mateconf_full_key (key_type, id, "position"); + mateconf_client_set_int (client, key, position, NULL); + + key = panel_mateconf_full_key (key_type, id, "panel_right_stick"); + mateconf_client_set_bool (client, key, right_stick, NULL); + + g_free (dir); + + return id; +} + +char * +panel_profile_prepare_object (PanelObjectType object_type, + PanelToplevel *toplevel, + int position, + gboolean right_stick) +{ + return panel_profile_prepare_object_with_id (object_type, + panel_profile_get_toplevel_id (toplevel), + position, + right_stick); +} + +void +panel_profile_delete_object (AppletInfo *applet_info) +{ + PanelMateConfKeyType type; + const char *id; + + type = (applet_info->type) == PANEL_OBJECT_APPLET ? PANEL_MATECONF_APPLETS : + PANEL_MATECONF_OBJECTS; + id = mate_panel_applet_get_id (applet_info); + + panel_profile_remove_from_list (type, id); +} + +static void +panel_profile_load_object (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + const char *id) +{ + PanelObjectType object_type; + char *object_dir; + const char *key; + char *type_string; + char *toplevel_id; + int position; + gboolean right_stick; + gboolean locked; + + object_dir = g_strdup_printf ("%s/%s/%s", + profile_dir, + type == PANEL_MATECONF_OBJECTS ? "objects" : "applets", + id); + + mateconf_client_add_dir (client, object_dir, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + key = panel_mateconf_sprintf ("%s/object_type", object_dir); + type_string = mateconf_client_get_string (client, key, NULL); + + if (!panel_profile_map_object_type_string (type_string, &object_type)) { + g_free (type_string); + mateconf_client_remove_dir (client, object_dir, NULL); + g_free (object_dir); + return; + } + + key = panel_mateconf_sprintf ("%s/position", object_dir); + position = mateconf_client_get_int (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/toplevel_id", object_dir); + toplevel_id = mateconf_client_get_string (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/panel_right_stick", object_dir); + right_stick = mateconf_client_get_bool (client, key, NULL); + + key = panel_mateconf_sprintf ("%s/locked", object_dir); + locked = mateconf_client_get_bool (client, key, NULL); + + mate_panel_applet_queue_applet_to_load (id, + object_type, + toplevel_id, + position, + right_stick, + locked); + + g_free (toplevel_id); + g_free (type_string); + g_free (object_dir); +} + +static void +panel_profile_destroy_object (const char *id) +{ + AppletInfo *info; + + info = mate_panel_applet_get_by_id (id); + + mate_panel_applet_clean (info); +} + +static void +panel_profile_delete_dir (MateConfClient *client, + PanelMateConfKeyType type, + const char *id) +{ + const char *key; + char *type_str; + + switch (type) { + case PANEL_MATECONF_TOPLEVELS: + type_str = "toplevels"; + break; + case PANEL_MATECONF_OBJECTS: + type_str = "objects"; + break; + case PANEL_MATECONF_APPLETS: + type_str = "applets"; + break; + default: + type_str = NULL; + g_assert_not_reached (); + break; + } + + if (type == PANEL_MATECONF_TOPLEVELS) { + key = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/%s/%s/background", + type_str, id); + mateconf_client_remove_dir (client, key, NULL); + } + + key = panel_mateconf_sprintf (PANEL_CONFIG_DIR "/%s/%s", + type_str, id); + mateconf_client_remove_dir (client, key, NULL); + + mateconf_client_recursive_unset (client, + key, + MATECONF_UNSET_INCLUDING_SCHEMA_NAMES, + NULL); +} + +static gboolean +panel_profile_object_exists (GSList *list, + const char *id, + PanelProfileGetIdFunc get_id_func) +{ + GSList *l; + + if (!list || !id) + return FALSE; + + for (l = list; l; l = l->next) { + const char *check_id; + + check_id = get_id_func (l->data); + g_assert (check_id != NULL); + + if (!strcmp (check_id, id)) + return TRUE; + } + + return FALSE; +} + +static gboolean +panel_profile_id_exists (GSList *id_list, + const char *id) +{ + GSList *l; + + if (!id_list || !id) + return FALSE; + + for (l = id_list; l; l = l->next) { + const char *check_id = mateconf_value_get_string (l->data); + + if (!strcmp (id, check_id)) + return TRUE; + } + + return FALSE; +} + +static void +panel_profile_load_added_ids (MateConfClient *client, + PanelMateConfKeyType type, + GSList *list, + GSList *id_list, + PanelProfileGetIdFunc get_id_func, + PanelProfileLoadFunc load_handler, + PanelProfileOnLoadQueue on_load_queue) +{ + GSList *added_ids = NULL; + GSList *l; + + for (l = id_list; l; l = l->next) { + const char *id = mateconf_value_get_string (l->data); + + if (!panel_profile_object_exists (list, id, get_id_func) && + (on_load_queue == NULL || !on_load_queue (id))) + added_ids = g_slist_prepend (added_ids, g_strdup (id)); + } + + for (l = added_ids; l; l = l->next) { + char *id; + id = (char *) l->data; + + if (id && id[0]) + load_handler (client, PANEL_CONFIG_DIR, type, id); + + g_free (l->data); + l->data = NULL; + } + + g_slist_free (added_ids); +} + +static void +panel_profile_delete_removed_ids (MateConfClient *client, + PanelMateConfKeyType type, + GSList *list, + GSList *id_list, + PanelProfileGetIdFunc get_id_func, + PanelProfileDestroyFunc destroy_handler) +{ + GSList *removed_ids = NULL; + GSList *l; + + for (l = list; l; l = l->next) { + const char *id; + + id = get_id_func (l->data); + + if (!panel_profile_id_exists (id_list, id)) + removed_ids = g_slist_prepend (removed_ids, g_strdup (id)); + } + + for (l = removed_ids; l; l = l->next) { + const char *id = l->data; + + panel_profile_delete_dir (client, type, id); + destroy_handler (id); + + g_free (l->data); + l->data = NULL; + } + g_slist_free (removed_ids); +} + +static void +panel_profile_toplevel_id_list_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry) +{ + MateConfValue *value; + GSList *l, *existing_toplevels; + GSList *toplevel_ids; + + if (!(value = mateconf_entry_get_value (entry))) + return; + + if (value->type != MATECONF_VALUE_LIST || + mateconf_value_get_list_type (value) != MATECONF_VALUE_STRING) { + mateconf_value_free (value); + return; + } + + toplevel_ids = g_slist_copy (mateconf_value_get_list (value)); + toplevel_ids = panel_g_slist_make_unique (toplevel_ids, + panel_mateconf_value_strcmp, + FALSE); + + existing_toplevels = NULL; + for (l = panel_toplevel_list_toplevels (); l; l = l->next) { + PanelToplevel *toplevel = l->data; + + /* Attached toplevels aren't on the id list */ + if (panel_toplevel_get_is_attached (toplevel)) + continue; + + existing_toplevels = g_slist_prepend (existing_toplevels, toplevel); + } + + panel_profile_load_added_ids (client, + PANEL_MATECONF_TOPLEVELS, + existing_toplevels, + toplevel_ids, + (PanelProfileGetIdFunc) panel_profile_get_toplevel_id, + (PanelProfileLoadFunc) panel_profile_load_and_show_toplevel, + (PanelProfileOnLoadQueue) NULL); + + panel_profile_delete_removed_ids (client, + PANEL_MATECONF_TOPLEVELS, + existing_toplevels, + toplevel_ids, + (PanelProfileGetIdFunc) panel_profile_get_toplevel_id, + (PanelProfileDestroyFunc) panel_profile_destroy_toplevel); + + g_slist_free (existing_toplevels); + g_slist_free (toplevel_ids); +} + +static void +panel_profile_object_id_list_update (MateConfClient *client, + MateConfValue *value, + PanelMateConfKeyType type) +{ + GSList *existing_applets; + GSList *sublist = NULL, *l; + GSList *object_ids; + + if (value->type != MATECONF_VALUE_LIST || + mateconf_value_get_list_type (value) != MATECONF_VALUE_STRING) { + mateconf_value_free (value); + return; + } + + object_ids = g_slist_copy (mateconf_value_get_list (value)); + object_ids = panel_g_slist_make_unique (object_ids, + panel_mateconf_value_strcmp, + FALSE); + + existing_applets = mate_panel_applet_list_applets (); + + for (l = existing_applets; l; l = l->next) { + AppletInfo *info = l->data; + + if ((type == PANEL_MATECONF_APPLETS && info->type == PANEL_OBJECT_APPLET) || + (type == PANEL_MATECONF_OBJECTS && info->type != PANEL_OBJECT_APPLET)) + sublist = g_slist_prepend (sublist, info); + } + + panel_profile_load_added_ids (client, + type, + sublist, + object_ids, + (PanelProfileGetIdFunc) mate_panel_applet_get_id, + (PanelProfileLoadFunc) panel_profile_load_object, + (PanelProfileOnLoadQueue) mate_panel_applet_on_load_queue); + + panel_profile_delete_removed_ids (client, + type, + sublist, + object_ids, + (PanelProfileGetIdFunc) mate_panel_applet_get_id, + (PanelProfileDestroyFunc) panel_profile_destroy_object); + + g_slist_free (sublist); + g_slist_free (object_ids); + + mate_panel_applet_load_queued_applets (FALSE); +} + +static void +panel_profile_object_id_list_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + MateConfValue *value; + PanelMateConfKeyType type = GPOINTER_TO_INT (data); + + if (!(value = mateconf_entry_get_value (entry))) + return; + + panel_profile_object_id_list_update (client, value, type); +} + +static void +panel_profile_load_list (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + PanelProfileLoadFunc load_handler, + MateConfClientNotifyFunc notify_handler) +{ + + const char *key; + GSList *list; + GSList *l; + const char *id_list; + + id_list = panel_mateconf_key_type_to_id_list (type); + + key = panel_mateconf_sprintf ("%s/general/%s", profile_dir, id_list); + + mateconf_client_notify_add (client, key, notify_handler, + GINT_TO_POINTER (type), + NULL, NULL); + + list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + list = panel_g_slist_make_unique (list, + (GCompareFunc) strcmp, + TRUE); + + for (l = list; l; l = l->next) { + char *id; + id = (char *) l->data; + + if (id && id[0]) + load_handler (client, profile_dir, type, id); + + g_free (l->data); + l->data = NULL; + } + g_slist_free (list); +} + +static GSList * +panel_profile_copy_defaults_for_screen (MateConfClient *client, + const char *profile_dir, + int screen_n, + PanelMateConfKeyType type) +{ + GSList *default_ids, *l; + GSList *new_ids = NULL; + const char *key; + const char *id_list, *type_str; + + id_list = panel_mateconf_key_type_to_id_list (type); + + switch (type) { + case PANEL_MATECONF_TOPLEVELS: + type_str = "toplevels"; + break; + case PANEL_MATECONF_OBJECTS: + type_str = "objects"; + break; + case PANEL_MATECONF_APPLETS: + type_str = "applets"; + break; + default: + type_str = NULL; + g_assert_not_reached (); + break; + } + + key = panel_mateconf_sprintf (PANEL_DEFAULTS_DIR "/general/%s", id_list); + default_ids = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + for (l = default_ids; l; l = l->next) { + char *default_id = l->data; + char *new_id; + char *src_dir; + char *dest_dir; + + new_id = g_strdup_printf ("%s_screen%d", default_id, screen_n); + + src_dir = g_strdup_printf (PANEL_DEFAULTS_DIR "/%s/%s", type_str, default_id); + dest_dir = g_strdup_printf ("%s/%s/%s", profile_dir, type_str, new_id); + + panel_mateconf_copy_dir (client, src_dir, dest_dir); + + new_ids = g_slist_prepend (new_ids, new_id); + + g_free (src_dir); + g_free (dest_dir); + g_free (l->data); + } + g_slist_free (default_ids); + + return new_ids; +} + +static void +panel_profile_append_new_ids (MateConfClient *client, + PanelMateConfKeyType type, + GSList *new_ids) +{ + GSList *list, *l; + const char *key; + const char *id_list; + + id_list = panel_mateconf_key_type_to_id_list (type); + + key = panel_mateconf_general_key (id_list); + list = mateconf_client_get_list (client, key, MATECONF_VALUE_STRING, NULL); + + for (l = new_ids; l; l = l->next) + list = g_slist_append (list, l->data); + + g_slist_free (new_ids); + + mateconf_client_set_list (client, key, MATECONF_VALUE_STRING, list, NULL); + + for (l = list; l; l = l->next) + g_free (l->data); + g_slist_free (list); +} + +static void +panel_profile_copy_default_objects_for_screen (MateConfClient *client, + const char *profile_dir, + int screen_n, + PanelMateConfKeyType type) +{ + GSList *new_objects, *l, *next; + + new_objects = panel_profile_copy_defaults_for_screen (client, profile_dir, screen_n, type); + + for (l = new_objects; l; l = next) { + char *object_id = l->data; + const char *key; + char *toplevel_id; + char *new_toplevel_id; + + next = l->next; + + key = panel_mateconf_full_key (type, object_id, "toplevel_id"); + toplevel_id = mateconf_client_get_string (client, key, NULL); + if (!toplevel_id) { + new_objects = g_slist_remove_link (new_objects, l); + g_free (l->data); + g_slist_free_1 (l); + continue; + } + + new_toplevel_id = g_strdup_printf ("%s_screen%d", toplevel_id, screen_n); + mateconf_client_set_string (client, key, new_toplevel_id, NULL); + + g_free (toplevel_id); + g_free (new_toplevel_id); + } + + panel_profile_append_new_ids (client, type, new_objects); +} + +/* FIXME: + * We might want to do something more sophisticated like hardcode + * the default panel setup as the fallback panels. + */ +static GSList * +panel_profile_create_fallback_toplevel_list (MateConfClient *client, + const char *profile_dir) +{ + char *id; + char *dir; + + id = panel_profile_find_new_id (PANEL_MATECONF_TOPLEVELS); + + dir = g_strdup_printf ("%s/toplevels/%s", profile_dir, id); + panel_mateconf_associate_schemas_in_dir (client, dir, PANEL_SCHEMAS_DIR "/toplevels"); + g_free (dir); + + return g_slist_prepend (NULL, id); +} + +static void +panel_profile_load_defaults_on_screen (MateConfClient *client, + const char *profile_dir, + GdkScreen *screen) +{ + GSList *new_toplevels, *l; + int screen_n; + + screen_n = gdk_screen_get_number (screen); + + new_toplevels = panel_profile_copy_defaults_for_screen ( + client, profile_dir, screen_n, PANEL_MATECONF_TOPLEVELS); + if (!new_toplevels) { + g_warning ("Failed to load default panel configuration. panel-default-setup.entries " + "hasn't been installed using mateconftool-2 --load ?\n"); + new_toplevels = panel_profile_create_fallback_toplevel_list (client, profile_dir); + } + + for (l = new_toplevels; l; l = l->next) { + char *toplevel_id = l->data; + const char *key; + + key = panel_mateconf_full_key (PANEL_MATECONF_TOPLEVELS, + toplevel_id, + "screen"); + mateconf_client_set_int (client, key, screen_n, NULL); + } + + panel_profile_append_new_ids (client, PANEL_MATECONF_TOPLEVELS, new_toplevels); + + panel_profile_copy_default_objects_for_screen ( + client, profile_dir, screen_n, PANEL_MATECONF_OBJECTS); + panel_profile_copy_default_objects_for_screen ( + client, profile_dir, screen_n, PANEL_MATECONF_APPLETS); +} + +static void +panel_profile_ensure_toplevel_per_screen (MateConfClient *client, + const char *profile_dir) +{ + GSList *toplevels; + GSList *empty_screens = NULL; + GSList *l; + GdkDisplay *display; + int n_screens, i; + + toplevels = panel_toplevel_list_toplevels (); + + display = gdk_display_get_default (); + + n_screens = gdk_display_get_n_screens (display); + for (i = 0; i < n_screens; i++) { + GdkScreen *screen; + + screen = gdk_display_get_screen (display, i); + + for (l = toplevels; l; l = l->next) + if (gtk_window_get_screen (l->data) == screen) + break; + + if (!l) + empty_screens = g_slist_prepend (empty_screens, screen); + } + + for (l = empty_screens; l; l = l->next) + panel_profile_load_defaults_on_screen (client, profile_dir, l->data); + + g_slist_free (empty_screens); +} + +void +panel_profile_load (void) +{ + MateConfClient *client; + + client = panel_mateconf_get_client (); + + mateconf_client_add_dir (client, PANEL_CONFIG_DIR "/general", MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + panel_compatibility_maybe_copy_old_config (client); + + panel_compatibility_migrate_panel_id_list (client); + + panel_profile_load_list (client, + PANEL_CONFIG_DIR, + PANEL_MATECONF_TOPLEVELS, + panel_profile_load_and_show_toplevel_startup, + (MateConfClientNotifyFunc) panel_profile_toplevel_id_list_notify); + panel_profile_load_list (client, + PANEL_CONFIG_DIR, + PANEL_MATECONF_OBJECTS, + panel_profile_load_object, + (MateConfClientNotifyFunc) panel_profile_object_id_list_notify); + panel_profile_load_list (client, + PANEL_CONFIG_DIR, + PANEL_MATECONF_APPLETS, + panel_profile_load_object, + (MateConfClientNotifyFunc) panel_profile_object_id_list_notify); + + panel_profile_ensure_toplevel_per_screen (client, PANEL_CONFIG_DIR); + + mate_panel_applet_load_queued_applets (TRUE); +} + +static gboolean +get_program_listing_setting (const char *setting) +{ + MateConfClient *client; + const char *key; + gboolean retval; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_general_key (setting); + retval = mateconf_client_get_bool (client, key, NULL); + + return retval; +} + +gboolean +panel_profile_get_show_program_list (void) +{ + return get_program_listing_setting ("show_program_list"); +} + +gboolean +panel_profile_get_enable_program_list (void) +{ + return get_program_listing_setting ("enable_program_list"); +} + +gboolean +panel_profile_get_enable_autocompletion (void) +{ + return get_program_listing_setting ("enable_autocompletion"); +} + +void +panel_profile_set_show_program_list (gboolean show_program_list) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_general_key ("show_program_list"); + mateconf_client_set_bool (client, key, show_program_list, NULL); +} + +gboolean +panel_profile_is_writable_show_program_list (void) +{ + MateConfClient *client; + const char *key; + + client = panel_mateconf_get_client (); + + key = panel_mateconf_general_key ("show_program_list"); + return mateconf_client_key_is_writable (client, key, NULL); +} + +gboolean +panel_profile_can_be_moved_freely (PanelToplevel *toplevel) +{ + const char *key; + MateConfClient *client; + + if (panel_lockdown_get_locked_down () || + !panel_profile_is_writable_toplevel_orientation (toplevel)) + return FALSE; + + client = panel_mateconf_get_client (); + + key = panel_profile_get_toplevel_key (toplevel, "screen"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + key = panel_profile_get_toplevel_key (toplevel, "monitor"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + /* For expanded panels we don't really have to check + x and y */ + if (panel_toplevel_get_expand (toplevel)) + return TRUE; + + key = panel_profile_get_toplevel_key (toplevel, "x"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + key = panel_profile_get_toplevel_key (toplevel, "x_right"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + key = panel_profile_get_toplevel_key (toplevel, "x_centered"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + key = panel_profile_get_toplevel_key (toplevel, "y"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + key = panel_profile_get_toplevel_key (toplevel, "y_bottom"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + key = panel_profile_get_toplevel_key (toplevel, "y_centered"); + if (!mateconf_client_key_is_writable (client, key, NULL)) + return FALSE; + + return TRUE; +} diff --git a/mate-panel/panel-profile.h b/mate-panel/panel-profile.h new file mode 100644 index 00000000..4191ef67 --- /dev/null +++ b/mate-panel/panel-profile.h @@ -0,0 +1,188 @@ +/* + * panel-profile.h: + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_PROFILE_H__ +#define __PANEL_PROFILE_H__ + +#include +#include +#include + +#include "panel-toplevel.h" +#include "panel-enums.h" +#include "panel-types.h" +#include "applet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_profile_load (void); + +const char *panel_profile_get_toplevel_id (PanelToplevel *toplevel); +PanelToplevel *panel_profile_get_toplevel_by_id (const char *toplevel_id); +char *panel_profile_find_new_id (PanelMateConfKeyType type); + + +gboolean panel_profile_get_show_program_list (void); +void panel_profile_set_show_program_list (gboolean show_program_list); +gboolean panel_profile_is_writable_show_program_list (void); +gboolean panel_profile_get_enable_program_list (void); +gboolean panel_profile_get_enable_autocompletion (void); + + +void panel_profile_add_to_list (PanelMateConfKeyType type, + const char *id); +void panel_profile_remove_from_list (PanelMateConfKeyType type, + const char *id); +gboolean panel_profile_id_lists_are_writable (void); +void panel_profile_create_toplevel (GdkScreen *screen); +PanelToplevel *panel_profile_load_toplevel (MateConfClient *client, + const char *profile_dir, + PanelMateConfKeyType type, + const char *toplevel_id); +void panel_profile_delete_toplevel (PanelToplevel *toplevel); +char *panel_profile_prepare_object (PanelObjectType object_type, + PanelToplevel *toplevel, + int position, + gboolean right_stick); +char *panel_profile_prepare_object_with_id (PanelObjectType object_type, + const char *toplevel_id, + int position, + gboolean right_stick); +void panel_profile_delete_object (AppletInfo *applet_info); + + +void panel_profile_set_toplevel_name (PanelToplevel *toplevel, + const char *name); +char *panel_profile_get_toplevel_name (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_name (PanelToplevel *toplevel); + +void panel_profile_set_toplevel_orientation (PanelToplevel *toplevel, + PanelOrientation orientation); +PanelOrientation + panel_profile_get_toplevel_orientation (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_orientation (PanelToplevel *toplevel); + +void panel_profile_set_toplevel_size (PanelToplevel *toplevel, + int size); +int panel_profile_get_toplevel_size (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_size (PanelToplevel *toplevel); + +void panel_profile_set_toplevel_expand (PanelToplevel *toplevel, + gboolean expand); +gboolean panel_profile_get_toplevel_expand (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_expand (PanelToplevel *toplevel); + +void panel_profile_set_toplevel_auto_hide (PanelToplevel *toplevel, + gboolean auto_hide); +gboolean panel_profile_get_toplevel_auto_hide (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_auto_hide (PanelToplevel *toplevel); + +void panel_profile_set_toplevel_enable_buttons (PanelToplevel *toplevel, + gboolean enable_buttons); +gboolean panel_profile_get_toplevel_enable_buttons (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_enable_buttons (PanelToplevel *toplevel); + +void panel_profile_set_toplevel_enable_arrows (PanelToplevel *toplevel, + gboolean enable_arrows); +gboolean panel_profile_get_toplevel_enable_arrows (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_toplevel_enable_arrows (PanelToplevel *toplevel); + +/* We don't set this in the panel, so there is no set accessor */ +void panel_profile_set_background_type (PanelToplevel *toplevel, + PanelBackgroundType background_type); +PanelBackgroundType + panel_profile_get_background_type (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_background_type (PanelToplevel *toplevel); + +void panel_profile_set_background_color (PanelToplevel *toplevel, + PanelColor *color); +void panel_profile_get_background_color (PanelToplevel *toplevel, + PanelColor *color); +gboolean panel_profile_is_writable_background_color (PanelToplevel *toplevel); + +void panel_profile_set_background_gdk_color (PanelToplevel *toplevel, + GdkColor *gdk_color); +void panel_profile_get_background_gdk_color (PanelToplevel *toplevel, + GdkColor *gdk_color); + +void panel_profile_set_background_opacity (PanelToplevel *toplevel, + guint16 opacity); +guint16 panel_profile_get_background_opacity (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_background_opacity (PanelToplevel *toplevel); + +void panel_profile_set_background_image (PanelToplevel *toplevel, + const char *image); +char *panel_profile_get_background_image (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_background_image (PanelToplevel *toplevel); + +void panel_profile_set_background_fit (PanelToplevel *toplevel, + gboolean fit); +gboolean panel_profile_get_background_fit (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_background_fit (PanelToplevel *toplevel); + +void panel_profile_set_background_stretch (PanelToplevel *toplevel, + gboolean stretch); +gboolean panel_profile_get_background_stretch (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_background_stretch (PanelToplevel *toplevel); + +void panel_profile_set_background_rotate (PanelToplevel *toplevel, + gboolean rotate); +gboolean panel_profile_get_background_rotate (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_background_rotate (PanelToplevel *toplevel); + +void panel_profile_set_attached_custom_icon (PanelToplevel *toplevel, + const char *custom_icon); +char *panel_profile_get_attached_custom_icon (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_attached_custom_icon (PanelToplevel *toplevel); +void panel_profile_set_attached_tooltip (PanelToplevel *toplevel, + const char *custom_icon); +char *panel_profile_get_attached_tooltip (PanelToplevel *toplevel); +gboolean panel_profile_is_writable_attached_tooltip (PanelToplevel *toplevel); + +guint panel_profile_toplevel_notify_add (PanelToplevel *toplevel, + const char *key, + MateConfClientNotifyFunc func, + gpointer data); + +const char *panel_profile_map_orientation (PanelOrientation orientation); +const char *panel_profile_map_background_type (PanelBackgroundType background_type); +gboolean panel_profile_map_orientation_string (const char *str, + PanelOrientation *orientation); +gboolean panel_profile_map_speed_string (const char *str, + PanelAnimationSpeed *speed); +gboolean panel_profile_map_background_type_string (const char *str, + PanelBackgroundType *background_type); +gboolean panel_profile_map_object_type_string (const char *str, + PanelObjectType *object_type); + +/* all keys relevant to moving are writable */ +gboolean panel_profile_can_be_moved_freely (PanelToplevel *toplevel); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_PROFILE_H__ */ diff --git a/mate-panel/panel-properties-dialog.c b/mate-panel/panel-properties-dialog.c new file mode 100644 index 00000000..0a5df0a1 --- /dev/null +++ b/mate-panel/panel-properties-dialog.c @@ -0,0 +1,999 @@ +/* + * panel-properties-dialog.c: + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-properties-dialog.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "nothing.h" +#include "panel-profile.h" +#include "panel-mateconf.h" +#include "panel-util.h" +#include "panel-globals.h" +#include "panel-icon-names.h" + +typedef struct { + PanelToplevel *toplevel; + + GtkWidget *properties_dialog; + + GtkWidget *general_table; + GtkWidget *general_vbox; + GtkWidget *orientation_combo; + GtkWidget *orientation_label; + GtkWidget *size_widgets; + GtkWidget *size_spin; + GtkWidget *size_label; + GtkWidget *size_label_pixels; + GtkWidget *icon_align; + GtkWidget *icon_chooser; + GtkWidget *icon_label; + GtkWidget *expand_toggle; + GtkWidget *autohide_toggle; + GtkWidget *hidebuttons_toggle; + GtkWidget *arrows_toggle; + GtkWidget *default_radio; + GtkWidget *color_radio; + GtkWidget *image_radio; + GtkWidget *color_widgets; + GtkWidget *image_widgets; + GtkWidget *color_button; + GtkWidget *color_label; + GtkWidget *image_chooser; + GtkWidget *opacity_scale; + GtkWidget *opacity_label; + GtkWidget *opacity_legend; + + GtkWidget *writability_warn_general; + GtkWidget *writability_warn_background; + + guint toplevel_notify; + guint background_notify; + + /* FIXME: This is a workaround for GTK+ bug #327243 */ + int selection_emitted; +} PanelPropertiesDialog; + +static GQuark panel_properties_dialog_quark = 0; + +static void +panel_properties_dialog_free (PanelPropertiesDialog *dialog) +{ + MateConfClient *client; + + client = panel_mateconf_get_client (); + + if (dialog->toplevel_notify) + mateconf_client_notify_remove (client, dialog->toplevel_notify); + dialog->toplevel_notify = 0; + + if (dialog->background_notify) + mateconf_client_notify_remove (client, dialog->background_notify); + dialog->background_notify = 0; + + if (dialog->properties_dialog) + gtk_widget_destroy (dialog->properties_dialog); + dialog->properties_dialog = NULL; + + g_free (dialog); +} + +enum { + COLUMN_TEXT, + COLUMN_ITEM, + NUMBER_COLUMNS +}; + +typedef struct { + const char *name; + PanelOrientation orientation; +} OrientationComboItem; + +static OrientationComboItem orientation_items [] = { + { NC_("Orientation", "Top"), PANEL_ORIENTATION_TOP }, + { NC_("Orientation", "Bottom"), PANEL_ORIENTATION_BOTTOM }, + { NC_("Orientation", "Left"), PANEL_ORIENTATION_LEFT }, + { NC_("Orientation", "Right"), PANEL_ORIENTATION_RIGHT } +}; + +static void +panel_properties_dialog_orientation_changed (PanelPropertiesDialog *dialog, + GtkComboBox *combo_box) +{ + GtkTreeIter iter; + GtkTreeModel *model; + OrientationComboItem *item; + + g_assert (dialog->orientation_combo == GTK_WIDGET (combo_box)); + + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) + return; + + model = gtk_combo_box_get_model (combo_box); + gtk_tree_model_get (model, &iter, COLUMN_ITEM, &item, -1); + if (item == NULL) + return; + + panel_profile_set_toplevel_orientation (dialog->toplevel, + item->orientation); +} + +static void +panel_properties_dialog_setup_orientation_combo (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + PanelOrientation orientation; + GtkListStore *model; + GtkTreeIter iter; + GtkCellRenderer *renderer; + int i; + + dialog->orientation_combo = PANEL_GTK_BUILDER_GET (gui, "orientation_combo"); + g_return_if_fail (dialog->orientation_combo != NULL); + dialog->orientation_label = PANEL_GTK_BUILDER_GET (gui, "orientation_label"); + g_return_if_fail (dialog->orientation_label != NULL); + + orientation = panel_profile_get_toplevel_orientation (dialog->toplevel); + + model = gtk_list_store_new (NUMBER_COLUMNS, + G_TYPE_STRING, + G_TYPE_POINTER); + + gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->orientation_combo), + GTK_TREE_MODEL (model)); + + for (i = 0; i < G_N_ELEMENTS (orientation_items); i++) { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_TEXT, g_dpgettext2 (NULL, "Orientation", orientation_items [i].name), + COLUMN_ITEM, &(orientation_items [i]), + -1); + if (orientation == orientation_items [i].orientation) + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->orientation_combo), + &iter); + } + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->orientation_combo), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->orientation_combo), + renderer, "text", COLUMN_TEXT, NULL); + + g_signal_connect_swapped (dialog->orientation_combo, "changed", + G_CALLBACK (panel_properties_dialog_orientation_changed), + dialog); + + if (! panel_profile_is_writable_toplevel_orientation (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->orientation_combo, FALSE); + gtk_widget_set_sensitive (dialog->orientation_label, FALSE); + gtk_widget_show (dialog->writability_warn_general); + } +} + +static void +panel_properties_dialog_size_changed (PanelPropertiesDialog *dialog, + GtkSpinButton *spin_button) +{ + panel_profile_set_toplevel_size (dialog->toplevel, + gtk_spin_button_get_value_as_int (spin_button)); +} + +static void +panel_properties_dialog_setup_size_spin (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + dialog->size_widgets = PANEL_GTK_BUILDER_GET (gui, "size_widgets"); + g_return_if_fail (dialog->size_widgets != NULL); + dialog->size_spin = PANEL_GTK_BUILDER_GET (gui, "size_spin"); + g_return_if_fail (dialog->size_spin != NULL); + dialog->size_label = PANEL_GTK_BUILDER_GET (gui, "size_label"); + g_return_if_fail (dialog->size_label != NULL); + dialog->size_label_pixels = PANEL_GTK_BUILDER_GET (gui, "size_label_pixels"); + g_return_if_fail (dialog->size_label_pixels != NULL); + + gtk_spin_button_set_range (GTK_SPIN_BUTTON (dialog->size_spin), + panel_toplevel_get_minimum_size (dialog->toplevel), + panel_toplevel_get_maximum_size (dialog->toplevel)); + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->size_spin), + panel_profile_get_toplevel_size (dialog->toplevel)); + + g_signal_connect_swapped (dialog->size_spin, "value_changed", + G_CALLBACK (panel_properties_dialog_size_changed), + dialog); + + if ( ! panel_profile_is_writable_toplevel_size (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->size_spin, FALSE); + gtk_widget_set_sensitive (dialog->size_label, FALSE); + gtk_widget_set_sensitive (dialog->size_label_pixels, FALSE); + gtk_widget_show (dialog->writability_warn_general); + } +} + +static void +panel_properties_dialog_icon_changed (PanelIconChooser *chooser, + const char *icon, + PanelPropertiesDialog *dialog) +{ + panel_profile_set_attached_custom_icon (dialog->toplevel, icon); +} + +static void +panel_properties_dialog_setup_icon_chooser (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + char *custom_icon; + + dialog->icon_align = PANEL_GTK_BUILDER_GET (gui, "icon_align"); + g_return_if_fail (dialog->icon_align != NULL); + + dialog->icon_chooser = panel_icon_chooser_new (NULL); + panel_icon_chooser_set_fallback_icon_name (PANEL_ICON_CHOOSER (dialog->icon_chooser), + PANEL_ICON_DRAWER); + gtk_widget_show (dialog->icon_chooser); + gtk_container_add (GTK_CONTAINER (dialog->icon_align), + dialog->icon_chooser); + + dialog->icon_label = PANEL_GTK_BUILDER_GET (gui, "icon_label"); + g_return_if_fail (dialog->icon_label != NULL); + + custom_icon = panel_profile_get_attached_custom_icon (dialog->toplevel); + panel_icon_chooser_set_icon (PANEL_ICON_CHOOSER (dialog->icon_chooser), + custom_icon); + g_free (custom_icon); + + g_signal_connect (dialog->icon_chooser, "changed", + G_CALLBACK (panel_properties_dialog_icon_changed), dialog); + + if (!panel_profile_is_writable_attached_custom_icon (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->icon_chooser, FALSE); + gtk_widget_set_sensitive (dialog->icon_label, FALSE); + gtk_widget_show (dialog->writability_warn_general); + } +} + +/* Note: this is only for toggle buttons on the general page, if needed for togglebuttons + elsewhere you must make this respect the writability warning thing for the right page */ +#define SETUP_TOGGLE_BUTTON(wid, n, p) \ + static void \ + panel_properties_dialog_##n (PanelPropertiesDialog *dialog, \ + GtkToggleButton *n) \ + { \ + panel_profile_set_toplevel_##p (dialog->toplevel, \ + gtk_toggle_button_get_active (n)); \ + } \ + static void \ + panel_properties_dialog_setup_##n (PanelPropertiesDialog *dialog, \ + GtkBuilder *gui) \ + { \ + dialog->n = PANEL_GTK_BUILDER_GET (gui, wid); \ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->n), \ + panel_profile_get_toplevel_##p (dialog->toplevel)); \ + g_signal_connect_swapped (dialog->n, "toggled", \ + G_CALLBACK (panel_properties_dialog_##n), dialog); \ + if ( ! panel_profile_is_writable_toplevel_##p (dialog->toplevel)) { \ + gtk_widget_set_sensitive (dialog->n, FALSE); \ + gtk_widget_show (dialog->writability_warn_general); \ + } \ + } + +SETUP_TOGGLE_BUTTON ("expand_toggle", expand_toggle, expand) +SETUP_TOGGLE_BUTTON ("autohide_toggle", autohide_toggle, auto_hide) +SETUP_TOGGLE_BUTTON ("hidebuttons_toggle", hidebuttons_toggle, enable_buttons) +SETUP_TOGGLE_BUTTON ("arrows_toggle", arrows_toggle, enable_arrows) + +static void +panel_properties_dialog_color_changed (PanelPropertiesDialog *dialog, + GtkColorButton *color_button) +{ + GdkColor color; + + g_assert (dialog->color_button == GTK_WIDGET (color_button)); + + gtk_color_button_get_color (color_button, &color); + panel_profile_set_background_gdk_color (dialog->toplevel, &color); +} + +static void +panel_properties_dialog_setup_color_button (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + PanelColor color; + + dialog->color_button = PANEL_GTK_BUILDER_GET (gui, "color_button"); + g_return_if_fail (dialog->color_button != NULL); + dialog->color_label = PANEL_GTK_BUILDER_GET (gui, "color_label"); + g_return_if_fail (dialog->color_label != NULL); + + panel_profile_get_background_color (dialog->toplevel, &color); + + gtk_color_button_set_color (GTK_COLOR_BUTTON (dialog->color_button), + &(color.gdk)); + + g_signal_connect_swapped (dialog->color_button, "color_set", + G_CALLBACK (panel_properties_dialog_color_changed), + dialog); + + if ( ! panel_profile_is_writable_background_color (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->color_button, FALSE); + gtk_widget_set_sensitive (dialog->color_label, FALSE); + gtk_widget_show (dialog->writability_warn_background); + } +} + +static void +panel_properties_dialog_image_changed (PanelPropertiesDialog *dialog) +{ + char *image; + + image = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog->image_chooser)); + + /* FIXME: This is an ugly workaround for GTK+ bug #327243. + * FIXME: Note that GTK+ 2.12 and file-set signal might help. */ + if (!dialog->selection_emitted < 2 && !image) { + dialog->selection_emitted++; + return; + } + panel_profile_set_background_image (dialog->toplevel, image); + + g_free (image); +} + +static void +panel_properties_dialog_setup_image_chooser (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + char *image; + + dialog->image_chooser = PANEL_GTK_BUILDER_GET (gui, "image_chooser"); + panel_gtk_file_chooser_add_image_preview (GTK_FILE_CHOOSER (dialog->image_chooser)); + + image = panel_profile_get_background_image (dialog->toplevel); + + if (PANEL_GLIB_STR_EMPTY (image)) + gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (dialog->image_chooser)); + else + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog->image_chooser), + image); + + if (image) + g_free (image); + + dialog->selection_emitted = 0; + g_signal_connect_swapped (dialog->image_chooser, "selection-changed", + G_CALLBACK (panel_properties_dialog_image_changed), + dialog); + + if ( ! panel_profile_is_writable_background_image (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->image_chooser, FALSE); + gtk_widget_show (dialog->writability_warn_background); + } +} + +static void +panel_properties_dialog_opacity_changed (PanelPropertiesDialog *dialog) +{ + gdouble percentage; + guint16 opacity; + + percentage = gtk_range_get_value (GTK_RANGE (dialog->opacity_scale)); + + if (percentage >= 98) + percentage = 100; + else if (percentage <= 2) + percentage = 0; + + opacity = (percentage / 100) * 65535; + + panel_profile_set_background_opacity (dialog->toplevel, opacity); +} + +static void +panel_properties_dialog_setup_opacity_scale (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + guint16 opacity; + gdouble percentage; + + dialog->opacity_scale = PANEL_GTK_BUILDER_GET (gui, "opacity_scale"); + g_return_if_fail (dialog->opacity_scale != NULL); + dialog->opacity_label = PANEL_GTK_BUILDER_GET (gui, "opacity_label"); + g_return_if_fail (dialog->opacity_label != NULL); + dialog->opacity_legend = PANEL_GTK_BUILDER_GET (gui, "opacity_legend"); + g_return_if_fail (dialog->opacity_legend != NULL); + + opacity = panel_profile_get_background_opacity (dialog->toplevel); + + percentage = (opacity * 100.0) / 65535; + + gtk_range_set_value (GTK_RANGE (dialog->opacity_scale), percentage); + + g_signal_connect_swapped (dialog->opacity_scale, "value_changed", + G_CALLBACK (panel_properties_dialog_opacity_changed), + dialog); + + if ( ! panel_profile_is_writable_background_opacity (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->opacity_scale, FALSE); + gtk_widget_set_sensitive (dialog->opacity_label, FALSE); + gtk_widget_set_sensitive (dialog->opacity_legend, FALSE); + gtk_widget_show (dialog->writability_warn_background); + } +} + +static void +panel_properties_dialog_upd_sensitivity (PanelPropertiesDialog *dialog, + PanelBackgroundType background_type) +{ + gtk_widget_set_sensitive (dialog->color_widgets, + background_type == PANEL_BACK_COLOR); + gtk_widget_set_sensitive (dialog->image_widgets, + background_type == PANEL_BACK_IMAGE); +} + +static void +panel_properties_dialog_background_toggled (PanelPropertiesDialog *dialog, + GtkWidget *radio) +{ + PanelBackgroundType background_type = PANEL_BACK_NONE; + + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio))) + return; + + if (radio == dialog->default_radio) + background_type = PANEL_BACK_NONE; + + else if (radio == dialog->color_radio) + background_type = PANEL_BACK_COLOR; + + else if (radio == dialog->image_radio) + background_type = PANEL_BACK_IMAGE; + + panel_properties_dialog_upd_sensitivity (dialog, background_type); + + panel_profile_set_background_type (dialog->toplevel, background_type); +} + +static void +panel_properties_dialog_setup_background_radios (PanelPropertiesDialog *dialog, + GtkBuilder *gui) +{ + PanelBackgroundType background_type; + GtkWidget *active_radio; + + dialog->default_radio = PANEL_GTK_BUILDER_GET (gui, "default_radio"); + dialog->color_radio = PANEL_GTK_BUILDER_GET (gui, "color_radio"); + dialog->image_radio = PANEL_GTK_BUILDER_GET (gui, "image_radio"); + dialog->color_widgets = PANEL_GTK_BUILDER_GET (gui, "color_widgets"); + dialog->image_widgets = PANEL_GTK_BUILDER_GET (gui, "image_widgets"); + + background_type = panel_profile_get_background_type (dialog->toplevel); + switch (background_type) { + case PANEL_BACK_NONE: + active_radio = dialog->default_radio; + break; + case PANEL_BACK_COLOR: + active_radio = dialog->color_radio; + break; + case PANEL_BACK_IMAGE: + active_radio = dialog->image_radio; + break; + default: + active_radio = NULL; + g_assert_not_reached (); + } + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_radio), TRUE); + + panel_properties_dialog_upd_sensitivity (dialog, background_type); + + g_signal_connect_swapped (dialog->default_radio, "toggled", + G_CALLBACK (panel_properties_dialog_background_toggled), + dialog); + g_signal_connect_swapped (dialog->color_radio, "toggled", + G_CALLBACK (panel_properties_dialog_background_toggled), + dialog); + g_signal_connect_swapped (dialog->image_radio, "toggled", + G_CALLBACK (panel_properties_dialog_background_toggled), + dialog); + + if ( ! panel_profile_is_writable_background_type (dialog->toplevel)) { + gtk_widget_set_sensitive (dialog->default_radio, FALSE); + gtk_widget_set_sensitive (dialog->color_radio, FALSE); + gtk_widget_set_sensitive (dialog->image_radio, FALSE); + gtk_widget_show (dialog->writability_warn_background); + } +} + +static void +panel_properties_update_arrows_toggle_visible (PanelPropertiesDialog *dialog, + GtkToggleButton *toggle) +{ + if (gtk_toggle_button_get_active (toggle)) + gtk_widget_set_sensitive (dialog->arrows_toggle, + panel_profile_is_writable_toplevel_enable_arrows (dialog->toplevel)); + else + gtk_widget_set_sensitive (dialog->arrows_toggle, FALSE); +} + +static void +panel_properties_dialog_response (PanelPropertiesDialog *dialog, + int response, + GtkWidget *properties_dialog) +{ + char *help_id; + + switch (response) { + case GTK_RESPONSE_CLOSE: + gtk_widget_destroy (properties_dialog); + break; + case GTK_RESPONSE_HELP: + if (panel_toplevel_get_is_attached (dialog->toplevel)) { + help_id = "gospanel-550"; + } else { + help_id = "gospanel-28"; + } + panel_show_help (gtk_window_get_screen (GTK_WINDOW (properties_dialog)), + "user-guide", help_id, NULL); + break; + default: + break; + } +} + +static void +panel_properties_dialog_destroy (PanelPropertiesDialog *dialog) +{ + panel_toplevel_pop_autohide_disabler (PANEL_TOPLEVEL (dialog->toplevel)); + g_object_set_qdata (G_OBJECT (dialog->toplevel), + panel_properties_dialog_quark, + NULL); +} + +static void +panel_properties_dialog_update_orientation (PanelPropertiesDialog *dialog, + MateConfValue *value) +{ + PanelOrientation orientation; + GtkTreeModel *model; + GtkTreeIter iter; + OrientationComboItem *item; + int max_size; + int spin_size; + int profile_size; + + if (!value || value->type != MATECONF_VALUE_STRING) + return; + + if (!panel_profile_map_orientation_string (mateconf_value_get_string (value), &orientation)) + return; + + /* change the maximum size of the panel */ + //TODO: we should also do this when the monitor size changes + max_size = panel_toplevel_get_maximum_size (dialog->toplevel); + spin_size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->size_spin)); + profile_size = panel_profile_get_toplevel_size (dialog->toplevel); + + gtk_spin_button_set_range (GTK_SPIN_BUTTON (dialog->size_spin), + panel_toplevel_get_minimum_size (dialog->toplevel), + max_size); + + if (spin_size > max_size) + gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->size_spin), + max_size); + else if (spin_size != profile_size) + gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->size_spin), + MIN (profile_size, max_size)); + + /* update the orientation combo box */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->orientation_combo)); + + if (!gtk_tree_model_get_iter_first (model, &iter)) + return; + + do { + gtk_tree_model_get (model, &iter, COLUMN_ITEM, &item, -1); + if (item != NULL && item->orientation == orientation) { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->orientation_combo), + &iter); + return; + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +panel_properties_dialog_update_size (PanelPropertiesDialog *dialog, + MateConfValue *value) +{ + if (!value || value->type != MATECONF_VALUE_INT) + return; + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->size_spin), + mateconf_value_get_int (value)); +} + +static void +panel_properties_dialog_toplevel_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelPropertiesDialog *dialog) +{ + MateConfValue *value; + const char *key; + + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + if (!key) + return; + + value = mateconf_entry_get_value (entry); + +#define UPDATE_TOGGLE(p, n) \ + if (!strcmp (key, p)) { \ + if (value && value->type == MATECONF_VALUE_BOOL) { \ + gboolean val = mateconf_value_get_bool (value); \ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->n)) != val) \ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->n), val); \ + } \ + } + + if (!strcmp (key, "orientation")) + panel_properties_dialog_update_orientation (dialog, value); + else if (!strcmp (key, "size")) + panel_properties_dialog_update_size (dialog, value); + else UPDATE_TOGGLE ("expand", expand_toggle) + else UPDATE_TOGGLE ("auto_hide", autohide_toggle) + else UPDATE_TOGGLE ("enable_buttons", hidebuttons_toggle) + else UPDATE_TOGGLE ("enable_arrows", arrows_toggle) +} + +static void +panel_properties_dialog_update_background_type (PanelPropertiesDialog *dialog, + MateConfValue *value) +{ + PanelBackgroundType background_type; + GtkWidget *active_radio; + + if (!value || value->type != MATECONF_VALUE_STRING) + return; + + if (!panel_profile_map_background_type_string (mateconf_value_get_string (value), + &background_type)) + return; + + switch (background_type) { + case PANEL_BACK_NONE: + active_radio = dialog->default_radio; + break; + case PANEL_BACK_COLOR: + active_radio = dialog->color_radio; + break; + case PANEL_BACK_IMAGE: + active_radio = dialog->image_radio; + break; + default: + active_radio = NULL; + g_assert_not_reached (); + break; + } + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_radio), TRUE); +} + +static void +panel_properties_dialog_update_background_color (PanelPropertiesDialog *dialog, + MateConfValue *value) +{ + GdkColor new_color = { 0, }; + GdkColor old_color; + + if (!value || value->type != MATECONF_VALUE_STRING) + return; + + if (!gdk_color_parse (mateconf_value_get_string (value), &new_color)) + return; + + gtk_color_button_get_color (GTK_COLOR_BUTTON (dialog->color_button), + &old_color); + + if (old_color.red != new_color.red || + old_color.green != new_color.green || + old_color.blue != new_color.blue) + gtk_color_button_set_color (GTK_COLOR_BUTTON (dialog->color_button), + &new_color); +} + +static void +panel_properties_dialog_update_background_opacity (PanelPropertiesDialog *dialog, + MateConfValue *value) +{ + gdouble percentage; + + if (!value || value->type != MATECONF_VALUE_INT) + return; + + percentage = ((gdouble) (mateconf_value_get_int (value) * 100)) / 65535; + + if ((int) gtk_range_get_value (GTK_RANGE (dialog->opacity_scale)) != (int) percentage) + gtk_range_set_value (GTK_RANGE (dialog->opacity_scale), percentage); +} + +static void +panel_properties_dialog_update_background_image (PanelPropertiesDialog *dialog, + MateConfValue *value) +{ + const char *text; + char *old_text; + + if (!value || value->type != MATECONF_VALUE_STRING) + return; + + text = mateconf_value_get_string (value); + old_text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog->image_chooser)); + + if (PANEL_GLIB_STR_EMPTY (text) && old_text) + gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (dialog->image_chooser)); + else if (!PANEL_GLIB_STR_EMPTY (text) && + (!old_text || strcmp (text, old_text))) + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog->image_chooser), + text); + + if (old_text) + g_free (old_text); +} + +static void +panel_properties_dialog_background_notify (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + PanelPropertiesDialog *dialog) +{ + MateConfValue *value; + const char *key; + + key = panel_mateconf_basename (mateconf_entry_get_key (entry)); + if (!key) + return; + + value = mateconf_entry_get_value (entry); + + if (!strcmp (key, "type")) + panel_properties_dialog_update_background_type (dialog, value); + else if (!strcmp (key, "color")) + panel_properties_dialog_update_background_color (dialog, value); + else if (!strcmp (key, "opacity")) + panel_properties_dialog_update_background_opacity (dialog, value); + else if (!strcmp (key, "image")) + panel_properties_dialog_update_background_image (dialog, value); +} + +static void +panel_properties_dialog_remove_orientation_combo (PanelPropertiesDialog *dialog) +{ + GtkContainer *container = GTK_CONTAINER (dialog->general_table); + GtkTable *table = GTK_TABLE (dialog->general_table); + + g_object_ref (dialog->size_label); + g_object_ref (dialog->size_widgets); + g_object_ref (dialog->icon_label); + g_object_ref (dialog->icon_align); + + gtk_container_remove (container, dialog->orientation_label); + gtk_container_remove (container, dialog->orientation_combo); + gtk_container_remove (container, dialog->size_label); + gtk_container_remove (container, dialog->size_widgets); + gtk_container_remove (container, dialog->icon_label); + gtk_container_remove (container, dialog->icon_align); + + gtk_table_attach_defaults (table, dialog->size_label, 0, 1, 1, 2); + gtk_table_attach_defaults (table, dialog->size_widgets, 1, 2, 1, 2); + gtk_table_attach_defaults (table, dialog->icon_label, 0, 1, 2, 3); + gtk_table_attach_defaults (table, dialog->icon_align, 1, 2, 2, 3); + + dialog->orientation_label = NULL; + dialog->orientation_combo = NULL; + g_object_unref (dialog->size_label); + g_object_unref (dialog->size_widgets); + g_object_unref (dialog->icon_label); + g_object_unref (dialog->icon_align); + + gtk_table_resize (table, 3, 2); +} + +static void +panel_properties_dialog_remove_icon_chooser (PanelPropertiesDialog *dialog) +{ + GtkContainer *container = GTK_CONTAINER (dialog->general_table); + + gtk_container_remove (container, dialog->icon_label); + gtk_container_remove (container, dialog->icon_align); + + dialog->icon_label = NULL; + dialog->icon_align = NULL; + dialog->icon_chooser = NULL; + + gtk_table_resize (GTK_TABLE (dialog->general_table), 3, 2); +} + +static void +panel_properties_dialog_remove_toggles (PanelPropertiesDialog *dialog) +{ + GtkContainer *container = GTK_CONTAINER (dialog->general_vbox); + + gtk_container_remove (container, dialog->autohide_toggle); + gtk_container_remove (container, dialog->expand_toggle); + + dialog->autohide_toggle = NULL; + dialog->expand_toggle = NULL; +} + +static void +panel_properties_dialog_update_for_attached (PanelPropertiesDialog *dialog, + gboolean attached) +{ + if (!attached) + panel_properties_dialog_remove_icon_chooser (dialog); + else { + gtk_window_set_title (GTK_WINDOW (dialog->properties_dialog), + _("Drawer Properties")); + panel_properties_dialog_remove_toggles (dialog); + panel_properties_dialog_remove_orientation_combo (dialog); + } +} + +static PanelPropertiesDialog * +panel_properties_dialog_new (PanelToplevel *toplevel, + GtkBuilder *gui) +{ + PanelPropertiesDialog *dialog; + + dialog = g_new0 (PanelPropertiesDialog, 1); + + g_object_set_qdata_full (G_OBJECT (toplevel), + panel_properties_dialog_quark, + dialog, + (GDestroyNotify) panel_properties_dialog_free); + + dialog->toplevel = toplevel; + + dialog->properties_dialog = PANEL_GTK_BUILDER_GET (gui, "panel_properties_dialog"); + g_signal_connect_swapped (dialog->properties_dialog, "response", + G_CALLBACK (panel_properties_dialog_response), dialog); + g_signal_connect_swapped (dialog->properties_dialog, "destroy", + G_CALLBACK (panel_properties_dialog_destroy), dialog); + + gtk_window_set_screen (GTK_WINDOW (dialog->properties_dialog), + gtk_window_get_screen (GTK_WINDOW (toplevel))); + + dialog->writability_warn_general = PANEL_GTK_BUILDER_GET (gui, "writability_warn_general"); + dialog->writability_warn_background = PANEL_GTK_BUILDER_GET (gui, "writability_warn_background"); + + dialog->general_vbox = PANEL_GTK_BUILDER_GET (gui, "general_vbox"); + dialog->general_table = PANEL_GTK_BUILDER_GET (gui, "general_table"); + + panel_properties_dialog_setup_orientation_combo (dialog, gui); + panel_properties_dialog_setup_size_spin (dialog, gui); + panel_properties_dialog_setup_icon_chooser (dialog, gui); + panel_properties_dialog_setup_expand_toggle (dialog, gui); + panel_properties_dialog_setup_autohide_toggle (dialog, gui); + panel_properties_dialog_setup_hidebuttons_toggle (dialog, gui); + panel_properties_dialog_setup_arrows_toggle (dialog, gui); + + panel_properties_update_arrows_toggle_visible ( + dialog, GTK_TOGGLE_BUTTON (dialog->hidebuttons_toggle)); + g_signal_connect_swapped (dialog->hidebuttons_toggle, "toggled", + G_CALLBACK (panel_properties_update_arrows_toggle_visible), + dialog); + + dialog->toplevel_notify = + panel_profile_toplevel_notify_add ( + dialog->toplevel, + NULL, + (MateConfClientNotifyFunc) panel_properties_dialog_toplevel_notify, + dialog); + + panel_properties_dialog_setup_color_button (dialog, gui); + panel_properties_dialog_setup_image_chooser (dialog, gui); + panel_properties_dialog_setup_opacity_scale (dialog, gui); + panel_properties_dialog_setup_background_radios (dialog, gui); + + dialog->background_notify = + panel_profile_toplevel_notify_add ( + dialog->toplevel, + "background", + (MateConfClientNotifyFunc) panel_properties_dialog_background_notify, + dialog); + + panel_properties_dialog_update_for_attached (dialog, + panel_toplevel_get_is_attached (dialog->toplevel)); + + panel_toplevel_push_autohide_disabler (dialog->toplevel); + panel_widget_register_open_dialog (panel_toplevel_get_panel_widget (dialog->toplevel), + dialog->properties_dialog); + + g_signal_connect (dialog->properties_dialog, "event", + G_CALLBACK (config_event), + PANEL_GTK_BUILDER_GET (gui, "notebook")); + + gtk_widget_show (dialog->properties_dialog); + + return dialog; +} + +void +panel_properties_dialog_present (PanelToplevel *toplevel) +{ + PanelPropertiesDialog *dialog; + GtkBuilder *gui; + GError *error; + + if (!panel_properties_dialog_quark) + panel_properties_dialog_quark = + g_quark_from_static_string ("panel-properties-dialog"); + + dialog = g_object_get_qdata (G_OBJECT (toplevel), panel_properties_dialog_quark); + if (dialog) { + gtk_window_set_screen (GTK_WINDOW (dialog->properties_dialog), + gtk_window_get_screen (GTK_WINDOW (toplevel))); + gtk_window_present (GTK_WINDOW (dialog->properties_dialog)); + return; + } + + gui = gtk_builder_new (); + gtk_builder_set_translation_domain (gui, GETTEXT_PACKAGE); + + error = NULL; + gtk_builder_add_from_file (gui, + BUILDERDIR "/panel-properties-dialog.ui", + &error); + + if (error) { + char *secondary; + + secondary = g_strdup_printf (_("Unable to load file '%s': %s."), + BUILDERDIR"/panel-properties-dialog.ui", + error->message); + panel_error_dialog (GTK_WINDOW (toplevel), + gtk_window_get_screen (GTK_WINDOW (toplevel)), + "cannot_display_properties_dialog", TRUE, + _("Could not display properties dialog"), + secondary); + g_free (secondary); + g_error_free (error); + g_object_unref (gui); + + return; + } + + dialog = panel_properties_dialog_new (toplevel, gui); + + g_object_unref (gui); +} diff --git a/mate-panel/panel-properties-dialog.h b/mate-panel/panel-properties-dialog.h new file mode 100644 index 00000000..31323619 --- /dev/null +++ b/mate-panel/panel-properties-dialog.h @@ -0,0 +1,40 @@ +/* + * panel-properties-dialog.h: + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_PROPERTIES_DIALOG_H__ +#define __PANEL_PROPERTIES_DIALOG_H__ + +#include "panel-toplevel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_properties_dialog_present (PanelToplevel *toplevel); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_PROPERTIES_DIALOG_H__ */ diff --git a/mate-panel/panel-properties-dialog.ui b/mate-panel/panel-properties-dialog.ui new file mode 100644 index 00000000..34feae70 --- /dev/null +++ b/mate-panel/panel-properties-dialog.ui @@ -0,0 +1,769 @@ + + + + + + 5 + Panel Properties + False + center + dialog + False + + + True + vertical + 2 + + + True + True + 5 + + + True + 12 + vertical + 6 + + + + + True + gtk-dialog-warning + + + 0 + + + + + True + Some of these properties are locked down + + + False + False + 1 + + + + + 0 + + + + + True + 3 + 2 + 12 + 6 + + + True + 0 + 0 + + + + + + 1 + 2 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + 0 + 0 + _Icon: + True + True + + + 2 + 3 + GTK_FILL + + + + + + True + 6 + + + True + True + adjustment2 + 1 + True + + + 0 + + + + + True + pixels + + + False + False + 1 + + + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + 0 + _Size: + True + size_spin + + + 1 + 2 + GTK_FILL + + + + + + True + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + 0 + _Orientation: + True + orientation_combo + + + GTK_FILL + + + + + + 1 + + + + + E_xpand + True + True + False + True + True + + + False + False + 2 + + + + + _Autohide + True + True + False + True + True + + + False + False + 3 + + + + + True + vertical + 6 + + + Show hide _buttons + True + True + False + True + True + + + False + False + 0 + + + + + True + + + True + + + + False + False + 0 + + + + + Arro_ws on hide buttons + True + True + False + True + True + + + 1 + + + + + 1 + + + + + False + 4 + + + + + False + + + + + True + General + + + False + + + + + True + 12 + vertical + 6 + + + + + True + gtk-dialog-warning + + + 0 + + + + + True + Some of these properties are locked down + + + False + False + 1 + + + + + 0 + + + + + _None (use system theme) + True + True + False + True + True + + + False + False + 1 + + + + + True + 6 + + + Solid c_olor + True + True + False + True + True + default_radio + + + 0 + + + + + False + 2 + + + + + True + + + True + + + + False + False + 0 + + + + + True + 3 + 2 + 12 + 6 + + + True + True + False + Pick a color + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + S_tyle: + True + opacity_scale + + + 1 + 2 + GTK_FILL + + + + + + True + True + adjustment1 + False + + + + + + 1 + 2 + 1 + 2 + + + + + True + 0 + Co_lor: + True + color_button + + + GTK_FILL + + + + + + True + 6 + + + True + 1 + 0 + <small>Transparent</small> + True + + + False + False + 1 + + + + + True + 0 + 0 + <small>Opaque</small> + True + + + False + False + end + 1 + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + + + + 1 + + + + + 3 + + + + + True + vertical + 6 + + + Background _image: + True + True + False + True + True + default_radio + + + False + False + 0 + + + + + True + + + True + + + + False + False + 0 + + + + + True + Select background + + + 1 + + + + + False + False + 1 + + + + + False + 4 + + + + + 1 + + + + + True + Background + + + 1 + False + + + + + 1 + + + + + True + + + gtk-help + True + True + True + False + True + + + False + False + 0 + + + + + gtk-close + True + True + True + True + False + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + helpbutton1 + closebutton1 + + + + 5 + Image Background Details + False + dialog + False + + + True + vertical + + + True + 5 + vertical + 6 + + + + + + True + vertical + 6 + + + _Tile + True + True + False + True + True + + + False + False + 0 + + + + + _Scale + True + True + False + True + True + tile_radio + + + False + False + 1 + + + + + St_retch + True + True + False + True + True + tile_radio + + + False + False + 2 + + + + + 1 + + + + + Rotate image when panel is _vertical + True + True + False + True + True + + + False + False + 2 + + + + + False + False + 1 + + + + + True + + + gtk-help + True + True + True + False + True + + + False + False + 0 + + + + + gtk-close + True + True + True + False + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + helpbutton2 + closebutton2 + + + + 33.75 + 100 + 5 + 10 + + + 12 + 12 + 120 + 1 + 12 + + diff --git a/mate-panel/panel-recent.c b/mate-panel/panel-recent.c new file mode 100644 index 00000000..3c5e94f3 --- /dev/null +++ b/mate-panel/panel-recent.c @@ -0,0 +1,243 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * panel-recent.c + * + * Copyright (C) 2002 James Willcox + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * James Willcox + */ + +#include + +#include +#include +#include + +#include +#include + +#include "menu.h" +#include "panel-util.h" +#include "panel-globals.h" +#include "panel-recent.h" +#include "panel-stock-icons.h" +#include "panel-multiscreen.h" +#include "panel-icon-names.h" + +static gboolean +show_uri (const char *uri, const char *mime_type, GdkScreen *screen, + GError **error) +{ + return panel_show_uri_force_mime_type (screen, uri, mime_type, + gtk_get_current_event_time (), + error); +} + + +static void +recent_documents_activate_cb (GtkRecentChooser *chooser, + gpointer data) +{ + GtkRecentInfo *recent_info; + const char *uri; + const char *mime_type; + GdkScreen *screen; + GError *error = NULL; + + screen = gtk_widget_get_screen (GTK_WIDGET (chooser)); + + recent_info = gtk_recent_chooser_get_current_item (chooser); + uri = gtk_recent_info_get_uri (recent_info); + mime_type = gtk_recent_info_get_mime_type (recent_info); + //FIXME gtk_recent_info_get_application_info() could be useful + + if (show_uri (uri, mime_type, screen, &error) != TRUE) { + char *uri_utf8; + + uri_utf8 = g_filename_to_utf8 (uri, -1, NULL, NULL, NULL); + //FIXME this could fail... Maybe we want gtk_recent_info_get_display_name() + + if (error) { + char *primary; + primary = g_strdup_printf (_("Could not open recently used document \"%s\""), + uri_utf8); + panel_error_dialog (NULL, screen, + "cannot_open_recent_doc", TRUE, + primary, error->message); + g_free (primary); + g_error_free (error); + } else { + char *primary; + char *secondary; + primary = g_strdup_printf (_("Could not open recently used document \"%s\""), + uri_utf8); + secondary = g_strdup_printf (_("An unknown error occurred while trying to open \"%s\"."), + uri_utf8); + panel_error_dialog (NULL, screen, + "cannot_open_recent_doc", TRUE, + primary, secondary); + g_free (primary); + g_free (secondary); + } + + g_free (uri_utf8); + } + + /* we can unref it only after having used the data we fetched from it */ + gtk_recent_info_unref (recent_info); +} + +static void +panel_recent_manager_changed_cb (GtkRecentManager *manager, + GtkWidget *menu_item) +{ + int size; + + g_object_get (manager, "size", &size, NULL); + + gtk_widget_set_sensitive (menu_item, size > 0); +} + +static GtkWidget *clear_recent_dialog = NULL; + +static void +clear_dialog_response (GtkWidget *widget, + int response, + GtkRecentManager *manager) +{ + if (response == GTK_RESPONSE_ACCEPT) + gtk_recent_manager_purge_items (manager, NULL); + + gtk_widget_destroy (widget); +} + +static void +recent_documents_clear_cb (GtkMenuItem *menuitem, + GtkRecentManager *manager) +{ + gpointer tmp; + + if (clear_recent_dialog != NULL) { + gtk_window_set_screen (GTK_WINDOW (clear_recent_dialog), + gtk_widget_get_screen (GTK_WIDGET (menuitem))); + gtk_window_present (GTK_WINDOW (clear_recent_dialog)); + return; + } + + clear_recent_dialog = gtk_message_dialog_new (NULL, + 0 /* flags */, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + _("Clear the Recent Documents list?")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (clear_recent_dialog), + _("If you clear the Recent Documents list, you clear the following:\n" + "\342\200\242 All items from the Places \342\206\222 Recent Documents menu item.\n" + "\342\200\242 All items from the recent documents list in all applications.")); + + gtk_dialog_add_buttons (GTK_DIALOG (clear_recent_dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + PANEL_STOCK_CLEAR, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_container_set_border_width (GTK_CONTAINER (clear_recent_dialog), 6); + + gtk_window_set_title (GTK_WINDOW (clear_recent_dialog), + _("Clear Recent Documents")); + + gtk_dialog_set_default_response (GTK_DIALOG (clear_recent_dialog), + GTK_RESPONSE_ACCEPT); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (clear_recent_dialog), + FALSE); + + g_signal_connect (clear_recent_dialog, "response", + G_CALLBACK (clear_dialog_response), manager); + + g_signal_connect (clear_recent_dialog, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &clear_recent_dialog); + + tmp = &clear_recent_dialog; + g_object_add_weak_pointer (G_OBJECT (clear_recent_dialog), tmp); + + gtk_window_set_screen (GTK_WINDOW (clear_recent_dialog), + gtk_widget_get_screen (GTK_WIDGET (menuitem))); + gtk_widget_show (clear_recent_dialog); +} + +void +panel_recent_append_documents_menu (GtkWidget *top_menu, + GtkRecentManager *manager) +{ + GtkWidget *recent_menu; + GtkWidget *menu_item; + int size; + + menu_item = gtk_image_menu_item_new (); + setup_menu_item_with_icon (menu_item, + panel_menu_icon_get_size (), + PANEL_ICON_RECENT, + NULL, NULL, + _("Recent Documents")); + recent_menu = gtk_recent_chooser_menu_new_for_manager (manager); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), recent_menu); + + g_signal_connect (G_OBJECT (recent_menu), "button_press_event", + G_CALLBACK (menu_dummy_button_press_event), NULL); + + gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item); + gtk_widget_show_all (menu_item); + + gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (recent_menu), + FALSE); + gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER (recent_menu), + TRUE); + gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recent_menu), + GTK_RECENT_SORT_MRU); + + g_signal_connect (GTK_RECENT_CHOOSER (recent_menu), + "item-activated", + G_CALLBACK (recent_documents_activate_cb), + NULL); + + //FIXME this is not possible with GtkRecent...: egg_recent_view_gtk_set_icon_size (view, panel_menu_icon_get_size ()); + + g_signal_connect_object (manager, "changed", + G_CALLBACK (panel_recent_manager_changed_cb), + menu_item, 0); + + size = 0; + g_object_get (manager, "size", &size, NULL); + gtk_widget_set_sensitive (menu_item, size > 0); + + add_menu_separator (recent_menu); + + menu_item = gtk_image_menu_item_new (); + setup_menu_item_with_icon (menu_item, + panel_menu_icon_get_size (), + NULL, + GTK_STOCK_CLEAR, NULL, + _("Clear Recent Documents...")); + panel_util_set_tooltip_text (menu_item, + _("Clear all items from the recent documents list")); + gtk_menu_shell_append (GTK_MENU_SHELL (recent_menu), menu_item); + + g_signal_connect (menu_item, "activate", + G_CALLBACK (recent_documents_clear_cb), + manager); +} diff --git a/mate-panel/panel-recent.h b/mate-panel/panel-recent.h new file mode 100644 index 00000000..7f1b5d7d --- /dev/null +++ b/mate-panel/panel-recent.h @@ -0,0 +1,41 @@ +/* + * panel-recent.h + * + * Copyright (C) 2002 James Willcox + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * James Willcox + */ + +#ifndef __PANEL_RECENT_H__ +#define __PANEL_RECENT_H__ + +#include "gtk/gtk.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_recent_append_documents_menu (GtkWidget *menu, + GtkRecentManager *manager); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_RECENT_H__ */ diff --git a/mate-panel/panel-reset.c b/mate-panel/panel-reset.c new file mode 100644 index 00000000..9c53c458 --- /dev/null +++ b/mate-panel/panel-reset.c @@ -0,0 +1,46 @@ +/* + * panel-reset.c + * + * Copyright (C) 2010 Perberos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __PANEL_RESET_C__ +#define __PANEL_RESET_C__ + +#include +#include "panel-reset.h" + +void panel_reset() +{ + /* En teoria, al hacer `mate-panel --reset` se podria correr este comando + * para que se reestablesca la configuracion por defecto del panel. O se + * borre para que pueda elegir una nueva. Esto ultimo solo si se desarrolla + * el dialogo de seleccion de configuracion inicial. + * + * La configuracion no se borra a travez de los archivos, por que hacer esto + * no hace que el demonio de configuracion se actualice. Obligando que se + * deba cerrar sesion antes de volver a abrir el panel. + * Es por eso que se eliminan las entradas a travez de mate-conf. + */ + system("mateconftool-2 --recursive-unset /apps/panel"); // unix like + + /* TODO: send a dbus message to mate-panel, if active, to reload the panel + * configuration */ +} + +#endif /* !__PANEL_RESET_C__ */ diff --git a/mate-panel/panel-reset.h b/mate-panel/panel-reset.h new file mode 100644 index 00000000..0d88aa44 --- /dev/null +++ b/mate-panel/panel-reset.h @@ -0,0 +1,37 @@ +/* + * panel-reset.h + * + * Copyright (C) 2010 Perberos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __PANEL_RESET_H__ +#define __PANEL_RESET_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void panel_reset(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !__PANEL_RESET_H__ */ diff --git a/mate-panel/panel-run-dialog.c b/mate-panel/panel-run-dialog.c new file mode 100644 index 00000000..866751da --- /dev/null +++ b/mate-panel/panel-run-dialog.c @@ -0,0 +1,2041 @@ +/* + * panel-run-dialog.c: + * + * Copyright (C) 2003 Frank Worsley + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Frank Worsley + * + * Based on code by: + * Havoc Pennington + * George Lebl + * Mark McLoughlin + */ + +#include + +#include "panel-run-dialog.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MATE_DESKTOP_USE_UNSTABLE_API +#include + +#include +#include +#include +#include +#include + +#include "nothing.h" +#include "panel-mateconf.h" +#include "panel-util.h" +#include "panel-globals.h" +#include "panel-enums.h" +#include "panel-profile.h" +#include "panel-stock-icons.h" +#include "panel-multiscreen.h" +#include "menu.h" +#include "panel-lockdown.h" +#include "panel-xutils.h" +#include "panel-icon-names.h" + +typedef struct { + GtkWidget *run_dialog; + + GtkWidget *main_box; + GtkWidget *program_list_box; + + GtkWidget *combobox; + GtkWidget *pixmap; + GtkWidget *run_button; + GtkWidget *file_button; + GtkWidget *list_expander; + GtkWidget *terminal_checkbox; + GtkWidget *program_label; + GtkWidget *program_list; + + long changed_id; + + GtkListStore *program_list_store; + + GHashTable *dir_hash; + GList *possible_executables; + GList *completion_items; + GCompletion *completion; + + GSList *add_icon_paths; + int add_icons_idle_id; + int add_items_idle_id; + int find_command_idle_id; + int content_notify_id; + gboolean use_program_list; + gboolean completion_started; + + char *icon_path; + char *desktop_path; + char *item_name; +} PanelRunDialog; + +enum { + COLUMN_ICON, + COLUMN_ICON_FILE, + COLUMN_NAME, + COLUMN_COMMENT, + COLUMN_PATH, + COLUMN_EXEC, + COLUMN_VISIBLE, + NUM_COLUMNS +}; + +static PanelRunDialog *static_dialog = NULL; + +static void panel_run_dialog_disconnect_pixmap (PanelRunDialog *dialog); + +#define PANEL_RUN_HISTORY_KEY "/apps/mate-settings/mate-panel/history-mate-run" +#define PANEL_RUN_MAX_HISTORY 10 + +static GtkTreeModel * +_panel_run_get_recent_programs_list (void) +{ + GtkListStore *list; + GSList *mateconf_items; + GSList *command; + int i = 0; + + list = gtk_list_store_new (1, G_TYPE_STRING); + + mateconf_items = mateconf_client_get_list (panel_mateconf_get_client (), + PANEL_RUN_HISTORY_KEY, + MATECONF_VALUE_STRING, NULL); + + for (command = mateconf_items; + command && i < PANEL_RUN_MAX_HISTORY; + command = command->next) { + GtkTreeIter iter; + gtk_list_store_prepend (list, &iter); + gtk_list_store_set (list, &iter, 0, command->data, -1); + i++; + } + + g_slist_free (mateconf_items); + + return GTK_TREE_MODEL (list); +} + +static void +_panel_run_save_recent_programs_list (GtkComboBoxEntry *entry, + char *lastcommand) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GSList *mateconf_items = NULL; + int i = 0; + + mateconf_items = g_slist_prepend (mateconf_items, lastcommand); + i++; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (entry)); + + if (gtk_tree_model_get_iter_first (model, &iter)) { + char *command; + + do { + gtk_tree_model_get (model, &iter, 0, &command, -1); + + if (strcmp (command, lastcommand) == 0) + continue; + + mateconf_items = g_slist_prepend (mateconf_items, command); + i++; + } while (gtk_tree_model_iter_next (model, &iter) && + i < PANEL_RUN_MAX_HISTORY); + } + + mateconf_client_set_list (panel_mateconf_get_client (), + PANEL_RUN_HISTORY_KEY, + MATECONF_VALUE_STRING, mateconf_items, + NULL); + + g_slist_free (mateconf_items); +} + +static void +panel_run_dialog_destroy (PanelRunDialog *dialog) +{ + GList *l; + + dialog->changed_id = 0; + + g_object_unref (dialog->program_list_box); + + g_slist_foreach (dialog->add_icon_paths, (GFunc) gtk_tree_path_free, NULL); + g_slist_free (dialog->add_icon_paths); + dialog->add_icon_paths = NULL; + + g_free (dialog->icon_path); + dialog->icon_path = NULL; + g_free (dialog->desktop_path); + dialog->desktop_path = NULL; + g_free (dialog->item_name); + dialog->item_name = NULL; + + if (dialog->add_icons_idle_id) + g_source_remove (dialog->add_icons_idle_id); + dialog->add_icons_idle_id = 0; + + if (dialog->add_items_idle_id) + g_source_remove (dialog->add_items_idle_id); + dialog->add_items_idle_id = 0; + + if (dialog->find_command_idle_id) + g_source_remove (dialog->find_command_idle_id); + dialog->find_command_idle_id = 0; + + if (dialog->content_notify_id) + mateconf_client_notify_remove (panel_mateconf_get_client (), + dialog->content_notify_id); + dialog->content_notify_id = 0; + + if (dialog->dir_hash) + g_hash_table_destroy (dialog->dir_hash); + dialog->dir_hash = NULL; + + for (l = dialog->possible_executables; l; l = l->next) + g_free (l->data); + g_list_free (dialog->possible_executables); + dialog->possible_executables = NULL; + + for (l = dialog->completion_items; l; l = l->next) + g_free (l->data); + g_list_free (dialog->completion_items); + dialog->completion_items = NULL; + + if (dialog->completion) + g_completion_free (dialog->completion); + dialog->completion = NULL; + + panel_run_dialog_disconnect_pixmap (dialog); + + g_free (dialog); +} + +static void +panel_run_dialog_set_default_icon (PanelRunDialog *dialog, gboolean set_drag) +{ + gtk_image_set_from_icon_name (GTK_IMAGE (dialog->pixmap), + PANEL_ICON_RUN, + GTK_ICON_SIZE_DIALOG); + + gtk_window_set_icon_name (GTK_WINDOW (dialog->run_dialog), + PANEL_ICON_RUN); + + if (set_drag) + gtk_drag_source_set_icon_name (dialog->run_dialog, + PANEL_ICON_LAUNCHER); +} + +static void +panel_run_dialog_set_icon (PanelRunDialog *dialog, + const char *icon_path, + gboolean force) +{ + GdkPixbuf *pixbuf = NULL; + + if (!force && icon_path && dialog->icon_path && + !strcmp (icon_path, dialog->icon_path)) + return; + + g_free (dialog->icon_path); + dialog->icon_path = NULL; + + if (icon_path) { + GdkScreen *screen; + GtkSettings *settings; + int size; + + screen = gtk_widget_get_screen (GTK_WIDGET (dialog->pixmap)); + settings = gtk_settings_get_for_screen (screen); + gtk_icon_size_lookup_for_settings (settings, + GTK_ICON_SIZE_DIALOG, + &size, NULL); + + pixbuf = panel_load_icon (gtk_icon_theme_get_default (), + icon_path, + size, + size, + size, + NULL); + } + + if (pixbuf) { + dialog->icon_path = g_strdup (icon_path); + + /* Don't bother scaling the image if it's too small. + * Scaled looks worse than a smaller image. + */ + gtk_image_set_from_pixbuf (GTK_IMAGE (dialog->pixmap), pixbuf); + + //FIXME: it'd be better to set an icon of the correct size, + //(ditto for the drag icon?) + gtk_window_set_icon (GTK_WINDOW (dialog->run_dialog), pixbuf); + + gtk_drag_source_set_icon_pixbuf (dialog->run_dialog, pixbuf); + g_object_unref (pixbuf); + } else { + panel_run_dialog_set_default_icon (dialog, TRUE); + } +} + +static gboolean +command_is_executable (const char *command, + int *argcp, + char ***argvp) +{ + gboolean result; + char **argv; + char *path; + int argc; + + result = g_shell_parse_argv (command, &argc, &argv, NULL); + + if (!result) + return FALSE; + + path = g_find_program_in_path (argv[0]); + + if (!path) { + g_strfreev (argv); + return FALSE; + } + + /* If we pass an absolute path to g_find_program it just returns + * that absolute path without checking if it is executable. Also + * make sure its a regular file so we don't try to launch + * directories or device nodes. + */ + if (!g_file_test (path, G_FILE_TEST_IS_EXECUTABLE) || + !g_file_test (path, G_FILE_TEST_IS_REGULAR)) { + g_free (path); + g_strfreev (argv); + return FALSE; + } + + g_free (path); + + if (argcp) + *argcp = argc; + if (argvp) + *argvp = argv; + + return TRUE; +} + +static gboolean +panel_run_dialog_launch_command (PanelRunDialog *dialog, + const char *command, + const char *locale_command) +{ + GdkScreen *screen; + gboolean result; + GError *error = NULL; + char **argv; + int argc; + + if (!command_is_executable (locale_command, &argc, &argv)) + return FALSE; + + screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog)); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox))) + mate_desktop_prepend_terminal_to_vector (&argc, &argv); + + result = gdk_spawn_on_screen (screen, + NULL, /* working directory */ + argv, + NULL, /* envp */ + G_SPAWN_SEARCH_PATH, + NULL, /* child setup func */ + NULL, /* user data */ + NULL, /* child pid */ + &error); + + if (!result) { + char *primary; + + primary = g_markup_printf_escaped (_("Could not run command '%s'"), + command); + panel_error_dialog (GTK_WINDOW (dialog->run_dialog), NULL, + "cannot_spawn_command", TRUE, + primary, error->message); + g_free (primary); + + g_error_free (error); + } + + g_strfreev (argv); + + return result; +} + +static void +panel_run_dialog_execute (PanelRunDialog *dialog) +{ + GError *error; + gboolean result; + char *command; + char *disk; + char *scheme; + + command = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->combobox)); + command = g_strchug (command); + + if (!command || !command [0]) { + g_free (command); + return; + } + + /* evil eggies, do not translate! */ + if (!strcmp (command, "free the fish")) { + start_screen_check (); + + g_free (command); + gtk_widget_destroy (dialog->run_dialog); + return; + } else if (!strcmp (command, "gegls from outer space")) { + start_geginv (); + + g_free (command); + gtk_widget_destroy (dialog->run_dialog); + return; + } + + error = NULL; + disk = g_locale_from_utf8 (command, -1, NULL, NULL, &error); + + if (!disk || error) { + char *primary; + + primary = g_strdup_printf (_("Could not convert '%s' from UTF-8"), + command); + panel_error_dialog (GTK_WINDOW (dialog->run_dialog), NULL, + "cannot_convert_command_from_utf8", TRUE, + primary, error->message); + g_free (primary); + + g_error_free (error); + return; + } + + result = FALSE; + + scheme = g_uri_parse_scheme (disk); + /* if it's an absolute path or not a URI, it's possibly an executable, + * so try it before displaying it */ + if (g_path_is_absolute (disk) || !scheme) + result = panel_run_dialog_launch_command (dialog, command, disk); + + if (!result) { + GFile *file; + char *uri; + GdkScreen *screen; + + file = panel_util_get_file_optional_homedir (command); + uri = g_file_get_uri (file); + g_object_unref (file); + + screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog)); + result = panel_show_uri (screen, uri, + gtk_get_current_event_time (), NULL); + + g_free (uri); + } + + if (result) { + /* only save working commands in history */ + _panel_run_save_recent_programs_list + (GTK_COMBO_BOX_ENTRY (dialog->combobox), command); + + /* only close the dialog if we successfully showed or launched + * something */ + gtk_widget_destroy (dialog->run_dialog); + } + + g_free (command); + g_free (disk); + g_free (scheme); +} + +static void +panel_run_dialog_response (PanelRunDialog *dialog, + int response, + GtkWidget *run_dialog) +{ + + dialog->completion_started = FALSE; + + switch (response) { + case GTK_RESPONSE_OK: + panel_run_dialog_execute (dialog); + break; + case GTK_RESPONSE_CANCEL: + gtk_widget_destroy (dialog->run_dialog); + break; + case GTK_RESPONSE_HELP: + panel_show_help (gtk_window_get_screen (GTK_WINDOW (run_dialog)), + "user-guide", "gospanel-23", NULL); + break; + default: + break; + } +} + +/* only quote the string if really needed */ +static char * +quote_string (const char *s) +{ + const char *p; + + for (p = s; *p != '\0'; p++) { + if ((*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9') || + strchr ("-_./=:", *p) != NULL) + ; + else + return g_shell_quote (s); + } + + return g_strdup (s); +} + +static void +panel_run_dialog_append_file_utf8 (PanelRunDialog *dialog, + const char *file) +{ + char *text; + char *quoted, *temp; + GtkWidget *entry; + + /* Don't allow filenames beginning with '-' */ + if (!file || !file[0] || file[0] == '-') + return; + + quoted = quote_string (file); + entry = gtk_bin_get_child (GTK_BIN (dialog->combobox)); + text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->combobox)); + if (text && text [0]) { + temp = g_strconcat (text, " ", quoted, NULL); + gtk_entry_set_text (GTK_ENTRY (entry), temp); + g_free (temp); + } else + gtk_entry_set_text (GTK_ENTRY (entry), quoted); + + g_free (text); + g_free (quoted); +} + +static void +panel_run_dialog_append_file (PanelRunDialog *dialog, + const char *file) +{ + char *utf8_file; + + if (!file) + return; + + utf8_file = g_filename_to_utf8 (file, -1, NULL, NULL, NULL); + + if (utf8_file) + panel_run_dialog_append_file_utf8 (dialog, utf8_file); + + g_free (utf8_file); +} + +static gboolean +fuzzy_command_match (const char *cmd1, + const char *cmd2, + gboolean *fuzzy) +{ + char **tokens; + char *word1, *word2; + + g_return_val_if_fail (cmd1 && cmd2, TRUE); + + *fuzzy = FALSE; + + if (!strcmp (cmd1, cmd2)) + return TRUE; + + /* find basename of exec from desktop item. + strip of all arguments after the initial command */ + tokens = g_strsplit (cmd1, " ", -1); + if (!tokens || !tokens [0]) { + g_strfreev (tokens); + return FALSE; + } + + word1 = g_path_get_basename (tokens [0]); + g_strfreev (tokens); + + /* same for the user command */ + tokens = g_strsplit (cmd2, " ", -1); + word2 = g_path_get_basename (tokens [0]); + if (!tokens || !tokens [0]) { + g_free (word1); + g_strfreev (tokens); + return FALSE; + } + + g_strfreev (tokens); + + if (!strcmp (word1, word2)) { + g_free (word1); + g_free (word2); + *fuzzy = TRUE; + return TRUE; + } + + g_free (word1); + g_free (word2); + + return FALSE; +} + +static gboolean +panel_run_dialog_make_all_list_visible (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + gtk_list_store_set (GTK_LIST_STORE (model), iter, + COLUMN_VISIBLE, TRUE, + -1); + + return FALSE; +} + +static gboolean +panel_run_dialog_find_command_idle (PanelRunDialog *dialog) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + char *text; + char *found_icon; + char *found_name; + gboolean fuzzy; + + model = GTK_TREE_MODEL (dialog->program_list_store); + path = gtk_tree_path_new_first (); + + if (!path || !gtk_tree_model_get_iter (model, &iter, path)) { + if (path) + gtk_tree_path_free (path); + + panel_run_dialog_set_icon (dialog, NULL, FALSE); + + dialog->find_command_idle_id = 0; + return FALSE; + } + + text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->combobox)); + found_icon = NULL; + found_name = NULL; + fuzzy = FALSE; + + do { + char *exec = NULL; + char *icon = NULL; + char *name = NULL; + char *comment = NULL; + + gtk_tree_model_get (model, &iter, + COLUMN_EXEC, &exec, + COLUMN_ICON_FILE, &icon, + COLUMN_NAME, &name, + COLUMN_COMMENT, &comment, + -1); + + if (!fuzzy && exec && icon && + fuzzy_command_match (text, exec, &fuzzy)) { + g_free (found_icon); + g_free (found_name); + + found_icon = g_strdup (icon); + found_name = g_strdup (name); + + gtk_list_store_set (dialog->program_list_store, + &iter, + COLUMN_VISIBLE, TRUE, + -1); + } else if (panel_g_utf8_strstrcase (exec, text) != NULL || + panel_g_utf8_strstrcase (name, text) != NULL || + panel_g_utf8_strstrcase (comment, text) != NULL) { + gtk_list_store_set (dialog->program_list_store, + &iter, + COLUMN_VISIBLE, TRUE, + -1); + } else { + gtk_list_store_set (dialog->program_list_store, + &iter, + COLUMN_VISIBLE, FALSE, + -1); + } + + g_free (exec); + g_free (icon); + g_free (name); + g_free (comment); + + } while (gtk_tree_model_iter_next (model, &iter)); + + if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->program_list)), + &iter, path)) + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->program_list), + path, NULL, FALSE, 0, 0); + + gtk_tree_path_free (path); + + panel_run_dialog_set_icon (dialog, found_icon, FALSE); + //FIXME update dialog->program_label + + g_free (found_icon); + g_free (text); + + g_free (dialog->item_name); + dialog->item_name = found_name; + + dialog->find_command_idle_id = 0; + return FALSE; +} + +static gboolean +panel_run_dialog_add_icon_idle (PanelRunDialog *dialog) +{ + GtkTreeIter iter; + GtkTreePath *path; + GdkPixbuf *pixbuf; + char *file; + int icon_height; + gboolean long_operation = FALSE; + + do { + if (!dialog->add_icon_paths) { + dialog->add_icons_idle_id = 0; + return FALSE; + } + + path = dialog->add_icon_paths->data; + dialog->add_icon_paths->data = NULL; + dialog->add_icon_paths = g_slist_delete_link (dialog->add_icon_paths, + dialog->add_icon_paths); + + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->program_list_store), + &iter, + path)) { + gtk_tree_path_free (path); + continue; + } + + gtk_tree_path_free (path); + + gtk_tree_model_get (GTK_TREE_MODEL (dialog->program_list_store), &iter, + COLUMN_ICON_FILE, &file, -1); + + if (!gtk_icon_size_lookup (panel_menu_icon_get_size (), NULL, &icon_height)) { + icon_height = PANEL_DEFAULT_MENU_ICON_SIZE; + } + + pixbuf = panel_make_menu_icon (gtk_icon_theme_get_default (), file, NULL, icon_height, &long_operation); + if (pixbuf) { + gtk_list_store_set (dialog->program_list_store, &iter, COLUMN_ICON, pixbuf, -1); + g_object_unref (pixbuf); + } + g_free (file); + + /* don't go back into the main loop if this wasn't very hard to do */ + } while (!long_operation); + + return TRUE; +} + +static int +compare_applications (MateMenuTreeEntry *a, + MateMenuTreeEntry *b) +{ + return g_utf8_collate (matemenu_tree_entry_get_display_name (a), + matemenu_tree_entry_get_display_name (b)); +} + +static GSList *get_all_applications_from_dir (MateMenuTreeDirectory *directory, + GSList *list); + +static GSList * +get_all_applications_from_alias (MateMenuTreeAlias *alias, + GSList *list) +{ + MateMenuTreeItem *aliased_item; + + aliased_item = matemenu_tree_alias_get_item (alias); + + switch (matemenu_tree_item_get_type (aliased_item)) { + case MATEMENU_TREE_ITEM_ENTRY: + list = g_slist_append (list, matemenu_tree_item_ref (aliased_item)); + break; + + case MATEMENU_TREE_ITEM_DIRECTORY: + list = get_all_applications_from_dir (MATEMENU_TREE_DIRECTORY (aliased_item), + list); + break; + + default: + break; + } + + matemenu_tree_item_unref (aliased_item); + + return list; +} + +static GSList * +get_all_applications_from_dir (MateMenuTreeDirectory *directory, + GSList *list) +{ + GSList *items; + GSList *l; + + items = matemenu_tree_directory_get_contents (directory); + + for (l = items; l; l = l->next) { + switch (matemenu_tree_item_get_type (l->data)) { + case MATEMENU_TREE_ITEM_ENTRY: + list = g_slist_append (list, matemenu_tree_item_ref (l->data)); + break; + + case MATEMENU_TREE_ITEM_DIRECTORY: + list = get_all_applications_from_dir (l->data, list); + break; + + case MATEMENU_TREE_ITEM_ALIAS: + list = get_all_applications_from_alias (l->data, list); + break; + + default: + break; + } + + matemenu_tree_item_unref (l->data); + } + + g_slist_free (items); + + return list; +} + +static GSList* get_all_applications(void) +{ + MateMenuTree* tree; + MateMenuTreeDirectory* root; + GSList* retval; + + tree = matemenu_tree_lookup("mate-applications.menu", MATEMENU_TREE_FLAGS_NONE); + matemenu_tree_set_sort_key(tree, MATEMENU_TREE_SORT_DISPLAY_NAME); + + root = matemenu_tree_get_root_directory(tree); + + retval = get_all_applications_from_dir(root, NULL); + + matemenu_tree_item_unref(root); + matemenu_tree_unref(tree); + + retval = g_slist_sort(retval, (GCompareFunc) compare_applications); + + return retval; +} + +static gboolean +panel_run_dialog_add_items_idle (PanelRunDialog *dialog) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeModel *model_filter; + GSList *all_applications; + GSList *l; + GSList *next; + const char *prev_name; + + /* create list store */ + dialog->program_list_store = gtk_list_store_new (NUM_COLUMNS, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + + all_applications = get_all_applications (); + + /* Strip duplicates */ + prev_name = NULL; + for (l = all_applications; l; l = next) { + MateMenuTreeEntry *entry = l->data; + const char *entry_name; + + next = l->next; + + entry_name = matemenu_tree_entry_get_display_name (entry); + if (prev_name && entry_name && strcmp (entry_name, prev_name) == 0) { + matemenu_tree_item_unref (entry); + + all_applications = g_slist_delete_link (all_applications, l); + } else { + prev_name = entry_name; + } + } + + for (l = all_applications; l; l = l->next) { + MateMenuTreeEntry *entry = l->data; + GtkTreeIter iter; + GtkTreePath *path; + + gtk_list_store_append (dialog->program_list_store, &iter); + gtk_list_store_set (dialog->program_list_store, &iter, + COLUMN_ICON, NULL, + COLUMN_ICON_FILE, matemenu_tree_entry_get_icon (entry), + COLUMN_NAME, matemenu_tree_entry_get_display_name (entry), + COLUMN_COMMENT, matemenu_tree_entry_get_comment (entry), + COLUMN_EXEC, matemenu_tree_entry_get_exec (entry), + COLUMN_PATH, matemenu_tree_entry_get_desktop_file_path (entry), + COLUMN_VISIBLE, TRUE, + -1); + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->program_list_store), &iter); + if (path != NULL) + dialog->add_icon_paths = g_slist_prepend (dialog->add_icon_paths, path); + + matemenu_tree_item_unref (entry); + } + g_slist_free (all_applications); + + model_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->program_list_store), + NULL); + gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (model_filter), + COLUMN_VISIBLE); + + gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->program_list), + model_filter); + //FIXME use the same search than the fuzzy one? + gtk_tree_view_set_search_column (GTK_TREE_VIEW (dialog->program_list), + COLUMN_NAME); + + renderer = gtk_cell_renderer_pixbuf_new (); + column = gtk_tree_view_column_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_set_attributes (column, renderer, + "pixbuf", COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_attributes (column, renderer, + "text", COLUMN_NAME, + NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->program_list), column); + + dialog->add_icon_paths = g_slist_reverse (dialog->add_icon_paths); + + if (!dialog->add_icons_idle_id) + dialog->add_icons_idle_id = + g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) panel_run_dialog_add_icon_idle, + dialog, NULL); + + dialog->add_items_idle_id = 0; + return FALSE; +} + +static char * +remove_parameters (const char *exec) +{ + GString *str; + char *retval, *p; + + str = g_string_new (exec); + + while ((p = strstr (str->str, "%"))) { + switch (p [1]) { + case '%': + g_string_erase (str, p - str->str, 1); + break; + case 'U': + case 'F': + case 'N': + case 'D': + case 'f': + case 'u': + case 'd': + case 'n': + case 'm': + case 'i': + case 'c': + case 'k': + case 'v': + g_string_erase (str, p - str->str, 2); + break; + default: + break; + } + } + + retval = str->str; + g_string_free (str, FALSE); + + return retval; +} + +static void +program_list_selection_changed (GtkTreeSelection *selection, + PanelRunDialog *dialog) +{ + GtkTreeModel *filter_model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter filter_iter; + char *temp; + char *path, *stripped; + gboolean terminal; + GKeyFile *key_file; + GtkWidget *entry; + + if (!gtk_tree_selection_get_selected (selection, &filter_model, + &filter_iter)) + return; + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter_model), + &iter, &filter_iter); + + path = NULL; + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); + gtk_tree_model_get (child_model, &iter, + COLUMN_PATH, &path, + -1); + + if (!path) + return; + + key_file = g_key_file_new (); + + if (!g_key_file_load_from_file (key_file, path, + G_KEY_FILE_NONE, NULL)) { + g_key_file_free (key_file); + g_free (path); + return; + } + + dialog->use_program_list = TRUE; + if (dialog->desktop_path) + g_free (dialog->desktop_path); + dialog->desktop_path = g_strdup (path); + if (dialog->item_name) + g_free (dialog->item_name); + dialog->item_name = NULL; + + /* Order is important here. We have to set the text first so that the + * drag source is enabled, otherwise the drag icon can't be set by + * panel_run_dialog_set_icon. + */ + entry = gtk_bin_get_child (GTK_BIN (dialog->combobox)); + temp = panel_key_file_get_string (key_file, "Exec"); + if (temp) { + stripped = remove_parameters (temp); + gtk_entry_set_text (GTK_ENTRY (entry), stripped); + g_free (stripped); + } else { + temp = panel_key_file_get_string (key_file, "URL"); + gtk_entry_set_text (GTK_ENTRY (entry), sure_string (temp)); + } + g_free (temp); + + temp = panel_key_file_get_locale_string (key_file, "Icon"); + panel_run_dialog_set_icon (dialog, temp, FALSE); + g_free (temp); + + temp = panel_key_file_get_locale_string (key_file, "Comment"); + //FIXME: if sure_string () == "", we should display "Will run..." as in entry_changed() + gtk_label_set_text (GTK_LABEL (dialog->program_label), + sure_string (temp)); + g_free (temp); + + terminal = panel_key_file_get_boolean (key_file, "Terminal", FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox), + terminal); + + g_key_file_free (key_file); + + g_free (path); +} + +static void +program_list_selection_activated (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PanelRunDialog *dialog) +{ + GtkTreeSelection *selection; + + /* update the entry with the info from the selection */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list)); + program_list_selection_changed (selection, dialog); + + /* now launch the command */ + gtk_dialog_response (GTK_DIALOG (dialog->run_dialog), GTK_RESPONSE_OK); +} + + +static void +panel_run_dialog_setup_program_list (PanelRunDialog *dialog, + GtkBuilder *gui) +{ + GtkTreeSelection *selection; + + dialog->program_list = PANEL_GTK_BUILDER_GET (gui, "program_list"); + dialog->program_list_box = PANEL_GTK_BUILDER_GET (gui, "program_list_box"); + dialog->program_label = PANEL_GTK_BUILDER_GET (gui, "program_label"); + dialog->main_box = PANEL_GTK_BUILDER_GET (gui, "main_box"); + + /* Ref the box so it doesn't get destroyed when it is + * removed from the visible area of the dialog box. + */ + g_object_ref (dialog->program_list_box); + + if (panel_profile_get_enable_program_list ()) { + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + g_signal_connect (selection, "changed", + G_CALLBACK (program_list_selection_changed), + dialog); + + g_signal_connect (dialog->program_list, "row-activated", + G_CALLBACK (program_list_selection_activated), + dialog); + + /* start loading the list of applications */ + dialog->add_items_idle_id = + g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) panel_run_dialog_add_items_idle, + dialog, NULL); + } +} + +static void +panel_run_dialog_update_content (PanelRunDialog *dialog, + gboolean show_list) +{ + if (!panel_profile_get_enable_program_list ()) { + GtkWidget *parent; + + parent = gtk_widget_get_parent (dialog->list_expander); + if (parent) + gtk_container_remove (GTK_CONTAINER (parent), + dialog->list_expander); + + gtk_window_set_resizable (GTK_WINDOW (dialog->run_dialog), FALSE); + gtk_widget_grab_focus (dialog->combobox); + + } else if (show_list) { + gtk_window_resize (GTK_WINDOW (dialog->run_dialog), 100, 300); + gtk_window_set_resizable (GTK_WINDOW (dialog->run_dialog), TRUE); + gtk_widget_grab_focus (dialog->program_list); + + } else if (!show_list) { + gtk_window_set_resizable (GTK_WINDOW (dialog->run_dialog), FALSE); + gtk_widget_grab_focus (dialog->combobox); + } +} + +static void +panel_run_dialog_content_notify (MateConfClient *client, + int notify_id, + MateConfEntry *entry, + PanelRunDialog *dialog) +{ + panel_run_dialog_update_content (dialog, mateconf_value_get_bool (entry->value)); +} + +static void +list_expander_toggled (GtkExpander *expander, + GParamSpec *pspec, + PanelRunDialog *dialog) +{ + panel_profile_set_show_program_list (gtk_expander_get_expanded (expander)); +} + +static void +panel_run_dialog_setup_list_expander (PanelRunDialog *dialog, + GtkBuilder *gui) +{ + MateConfClient *client; + const char *key; + + dialog->list_expander = PANEL_GTK_BUILDER_GET (gui, "list_expander"); + + if (panel_profile_get_enable_program_list ()) { + gtk_expander_set_expanded (GTK_EXPANDER (dialog->list_expander), + panel_profile_get_show_program_list ()); + + if ( ! panel_profile_is_writable_show_program_list ()) + gtk_widget_set_sensitive (dialog->list_expander, FALSE); + + g_signal_connect (dialog->list_expander, "notify::expanded", + G_CALLBACK (list_expander_toggled), + dialog); + + client = panel_mateconf_get_client (); + key = panel_mateconf_general_key ("show_program_list"); + + dialog->content_notify_id = + mateconf_client_notify_add (client, key, + (MateConfClientNotifyFunc) panel_run_dialog_content_notify, + dialog, NULL, NULL); + + if (!dialog->content_notify_id) + g_warning ("error setting up content change notification"); + } +} + +static void +file_button_browse_response (GtkWidget *chooser, + gint response, + PanelRunDialog *dialog) +{ + char *file; + + if (response == GTK_RESPONSE_OK) { + file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); + panel_run_dialog_append_file (dialog, file); + g_free (file); + } + + gtk_widget_destroy (chooser); + + gtk_widget_grab_focus (dialog->combobox); +} + +static void +file_button_clicked (GtkButton *button, + PanelRunDialog *dialog) +{ + GtkWidget *chooser; + + chooser = gtk_file_chooser_dialog_new (_("Choose a file to append to the command..."), + GTK_WINDOW (dialog->run_dialog), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), + g_get_home_dir ()); + + gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK); + gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE); + + g_signal_connect (chooser, "response", + G_CALLBACK (file_button_browse_response), dialog); + + gtk_window_present (GTK_WINDOW (chooser)); +} + +static void +panel_run_dialog_setup_file_button (PanelRunDialog *dialog, + GtkBuilder *gui) +{ + dialog->file_button = PANEL_GTK_BUILDER_GET (gui, "file_button"); + + g_signal_connect (dialog->file_button, "clicked", + G_CALLBACK (file_button_clicked), + dialog); +} + +static GList * +fill_files_from (const char *dirname, + const char *dirprefix, + char prefix, + GList *existing_items) +{ + GList *list; + DIR *dir; + struct dirent *dent; + + list = NULL; + dir = opendir (dirname); + + if (!dir) + return list; + + while ((dent = readdir (dir))) { + char *file; + char *item; + const char *suffix; + + if (!dent->d_name || + dent->d_name [0] != prefix) + continue; + + file = g_build_filename (dirname, dent->d_name, NULL); + + suffix = NULL; + if ( +#ifdef HAVE_STRUCT_DIRENT_D_TYPE + /* don't use g_file_test at first so we don't stat() */ + dent->d_type == DT_DIR || + (dent->d_type == DT_LNK && + g_file_test (file, G_FILE_TEST_IS_DIR)) +#else + g_file_test (file, G_FILE_TEST_IS_DIR) +#endif + ) + suffix = "/"; + + g_free (file); + + item = g_build_filename (dirprefix, dent->d_name, suffix, NULL); + + list = g_list_prepend (list, item); + } + + closedir (dir); + + return list; +} + +static GList * +fill_possible_executables (void) +{ + GList *list; + const char *path; + char **pathv; + int i; + + list = NULL; + path = g_getenv ("PATH"); + + if (!path || !path [0]) + return list; + + pathv = g_strsplit (path, ":", 0); + + for (i = 0; pathv [i]; i++) { + const char *file; + char *filename; + GDir *dir; + + dir = g_dir_open (pathv [i], 0, NULL); + + if (!dir) + continue; + + while ((file = g_dir_read_name (dir))) { + filename = g_build_filename (pathv [i], file, NULL); + list = g_list_prepend (list, filename); + } + + g_dir_close (dir); + } + + g_strfreev (pathv); + + return list; +} + +static GList * +fill_executables (GList *possible_executables, + GList *existing_items, + char prefix) +{ + GList *list; + GList *l; + + list = NULL; + + for (l = possible_executables; l; l = l->next) { + const char *filename; + char *basename; + + filename = l->data; + basename = g_path_get_basename (filename); + + if (basename [0] == prefix && + g_file_test (filename, G_FILE_TEST_IS_REGULAR) && + g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE)) { + + if (g_list_find_custom (existing_items, basename, + (GCompareFunc) strcmp)) { + g_free (basename); + return NULL; + } + + list = g_list_prepend (list, basename); + } else { + g_free (basename); + } + } + + return list; +} + +static void +panel_run_dialog_update_completion (PanelRunDialog *dialog, + const char *text) +{ + GList *list; + GList *executables; + char prefix; + char *buf; + char *dirname; + char *dirprefix; + char *key; + + g_assert (text != NULL && *text != '\0' && !g_ascii_isspace (*text)); + + list = NULL; + executables = NULL; + + if (!dialog->completion) { + dialog->completion = g_completion_new (NULL); + dialog->possible_executables = fill_possible_executables (); + dialog->dir_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, NULL); + } + + buf = g_path_get_basename (text); + prefix = buf[0]; + g_free (buf); + if (prefix == '/' || prefix == '.') + return; + + if (text [0] == '/') { + /* complete against absolute path */ + dirname = g_path_get_dirname (text); + dirprefix = g_strdup (dirname); + } else { + /* complete against relative path and executable name */ + if (!strchr (text, '/')) { + executables = fill_executables (dialog->possible_executables, + dialog->completion_items, + text [0]); + dirprefix = g_strdup (""); + } else { + dirprefix = g_path_get_dirname (text); + } + + dirname = g_build_filename (g_get_home_dir (), dirprefix, NULL); + } + + key = g_strdup_printf ("%s%c%c", dirprefix, G_DIR_SEPARATOR, prefix); + + if (!g_hash_table_lookup (dialog->dir_hash, key)) { + g_hash_table_insert (dialog->dir_hash, key, dialog); + + list = fill_files_from (dirname, dirprefix, prefix, + dialog->completion_items); + } else { + g_free (key); + } + + list = g_list_concat (list, executables); + + g_free (dirname); + g_free (dirprefix); + + if (list == NULL) + return; + + g_completion_add_items (dialog->completion, list); + + dialog->completion_items = g_list_concat (dialog->completion_items, + list); +} + +static gboolean +entry_event (GtkEditable *entry, + GdkEventKey *event, + PanelRunDialog *dialog) +{ + GtkTreeSelection *selection; + char *prefix; + char *nospace_prefix; + char *nprefix; + char *temp; + int pos, tmp; + + if (event->type != GDK_KEY_PRESS) + return FALSE; + + /* if user typed something we're not using the list anymore */ + dialog->use_program_list = FALSE; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list)); + gtk_tree_selection_unselect_all (selection); + + if (!panel_profile_get_enable_autocompletion ()) + return FALSE; + + /* tab completion */ + if (event->keyval == GDK_Tab) { + gtk_editable_get_selection_bounds (entry, &pos, &tmp); + + if (dialog->completion_started && + pos != tmp && + pos != 1 && + tmp == strlen (gtk_entry_get_text (GTK_ENTRY (entry)))) { + gtk_editable_select_region (entry, 0, 0); + gtk_editable_set_position (entry, -1); + + return TRUE; + } + } else if (event->length > 0) { + + gtk_editable_get_selection_bounds (entry, &pos, &tmp); + + if (dialog->completion_started && + pos != tmp && + pos != 0 && + tmp == strlen (gtk_entry_get_text (GTK_ENTRY (entry)))) { + temp = gtk_editable_get_chars (entry, 0, pos); + prefix = g_strconcat (temp, event->string, NULL); + g_free (temp); + } else if (pos == tmp && + tmp == strlen (gtk_entry_get_text (GTK_ENTRY (entry)))) { + prefix = g_strconcat (gtk_entry_get_text (GTK_ENTRY (entry)), + event->string, NULL); + } else { + return FALSE; + } + + nospace_prefix = prefix; + while (*nospace_prefix != '\0' && + g_ascii_isspace (*nospace_prefix)) + nospace_prefix++; + if (*nospace_prefix == '\0') + return FALSE; + + panel_run_dialog_update_completion (dialog, nospace_prefix); + + if (!dialog->completion) { + g_free (prefix); + return FALSE; + } + + pos = strlen (prefix); + nprefix = NULL; + + g_completion_complete_utf8 (dialog->completion, nospace_prefix, + &nprefix); + + if (nprefix) { + int insertpos; + insertpos = 0; + + temp = g_strndup (prefix, nospace_prefix - prefix); + g_free (prefix); + + prefix = g_strconcat (temp, nprefix, NULL); + + g_signal_handler_block (dialog->combobox, + dialog->changed_id); + gtk_editable_delete_text (entry, 0, -1); + g_signal_handler_unblock (dialog->combobox, + dialog->changed_id); + + gtk_editable_insert_text (entry, + prefix, strlen (prefix), + &insertpos); + + gtk_editable_set_position (entry, pos); + gtk_editable_select_region (entry, pos, -1); + + dialog->completion_started = TRUE; + + g_free (temp); + g_free (nprefix); + g_free (prefix); + + return TRUE; + } + + g_free (prefix); + } + + return FALSE; +} + +static void +combobox_changed (GtkComboBox *combobox, + PanelRunDialog *dialog) +{ + char *text; + char *start; + char *msg; + + text = gtk_combo_box_get_active_text (combobox); + + start = text; + while (*start != '\0' && g_ascii_isspace (*start)) + start++; + + /* update item name to use for dnd */ + if (!dialog->use_program_list) { + if (dialog->desktop_path) { + g_free (dialog->desktop_path); + dialog->desktop_path = NULL; + } + if (dialog->item_name) { + g_free (dialog->item_name); + dialog->item_name = NULL; + } + } + + /* desensitize run button if no text entered */ + if (!start || !start [0]) { + g_free (text); + + gtk_widget_set_sensitive (dialog->run_button, FALSE); + gtk_drag_source_unset (dialog->run_dialog); + + if (panel_profile_get_enable_program_list ()) + gtk_label_set_text (GTK_LABEL (dialog->program_label), + _("Select an application to view its description.")); + + panel_run_dialog_set_default_icon (dialog, FALSE); + + if (dialog->find_command_idle_id) { + g_source_remove (dialog->find_command_idle_id); + dialog->find_command_idle_id = 0; + } + + if (panel_profile_get_enable_program_list ()) { + GtkTreeIter iter; + GtkTreePath *path; + + gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->program_list_store), + panel_run_dialog_make_all_list_visible, + NULL); + + path = gtk_tree_path_new_first (); + if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->program_list)), + &iter, path)) + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->program_list), + path, NULL, + FALSE, 0, 0); + gtk_tree_path_free (path); + } + + return; + } + + gtk_widget_set_sensitive (dialog->run_button, TRUE); + gtk_drag_source_set (dialog->run_dialog, + GDK_BUTTON1_MASK, + NULL, 0, + GDK_ACTION_COPY); + gtk_drag_source_add_uri_targets (dialog->run_dialog); + + if (panel_profile_get_enable_program_list () && + !dialog->use_program_list) { + msg = g_strdup_printf (_("Will run command: '%s'"), + start); + gtk_label_set_text (GTK_LABEL (dialog->program_label), msg); + g_free (msg); + } + + /* look up icon for the command */ + if (panel_profile_get_enable_program_list () && + !dialog->use_program_list && + !dialog->find_command_idle_id) + dialog->find_command_idle_id = + g_idle_add_full (G_PRIORITY_LOW, + (GSourceFunc) panel_run_dialog_find_command_idle, + dialog, NULL); + + g_free (text); +} + +static void +entry_drag_data_received (GtkEditable *entry, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint32 time, + PanelRunDialog *dialog) +{ + char **uris; + char *file; + int i; + + if (gtk_selection_data_get_format (selection_data) != 8 || gtk_selection_data_get_length (selection_data) == 0) { + g_warning (_("URI list dropped on run dialog had wrong format (%d) or length (%d)\n"), + gtk_selection_data_get_format (selection_data), + gtk_selection_data_get_length (selection_data)); + return; + } + + uris = g_uri_list_extract_uris ((const char *)gtk_selection_data_get_data (selection_data)); + + if (!uris) { + gtk_drag_finish (context, FALSE, FALSE, time); + return; + } + + for (i = 0; uris [i]; i++) { + if (!uris [i] || !uris [i][0]) + continue; + + file = g_filename_from_uri (uris [i], NULL, NULL); + + /* FIXME: I assume the file is in utf8 encoding if coming from a URI? */ + if (file) { + panel_run_dialog_append_file_utf8 (dialog, file); + g_free (file); + } else + panel_run_dialog_append_file_utf8 (dialog, uris [i]); + } + + g_strfreev (uris); + gtk_drag_finish (context, TRUE, FALSE, time); +} + +static void +panel_run_dialog_setup_entry (PanelRunDialog *dialog, + GtkBuilder *gui) +{ + GdkScreen *screen; + int width_request; + GtkWidget *entry; + + dialog->combobox = PANEL_GTK_BUILDER_GET (gui, "comboboxentry"); + + entry = gtk_bin_get_child (GTK_BIN (dialog->combobox)); + gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); + + gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox), + _panel_run_get_recent_programs_list ()); + gtk_combo_box_entry_set_text_column + (GTK_COMBO_BOX_ENTRY (dialog->combobox), 0); + + screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog)); + + /* 1/4 the width of the first monitor should be a good value */ + width_request = panel_multiscreen_width (screen, 0) / 4; + g_object_set (G_OBJECT (dialog->combobox), + "width_request", width_request, + NULL); + + g_signal_connect (entry, "key-press-event", + G_CALLBACK (entry_event), dialog); + + dialog->changed_id = g_signal_connect (dialog->combobox, "changed", + G_CALLBACK (combobox_changed), + dialog); + + gtk_drag_dest_unset (dialog->combobox); + + gtk_drag_dest_set (dialog->combobox, + GTK_DEST_DEFAULT_MOTION|GTK_DEST_DEFAULT_HIGHLIGHT, + NULL, 0, + GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets (dialog->combobox); + + g_signal_connect (dialog->combobox, "drag_data_received", + G_CALLBACK (entry_drag_data_received), dialog); +} + +static char * +panel_run_dialog_create_desktop_file (PanelRunDialog *dialog) +{ + GKeyFile *key_file; + gboolean exec = FALSE; + char *text; + char *name; + char *disk; + char *scheme; + char *save_uri; + + text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->combobox)); + + if (!text || !text [0]) { + g_free (text); + return NULL; + } + + key_file = panel_key_file_new_desktop (); + disk = g_locale_from_utf8 (text, -1, NULL, NULL, NULL); + + scheme = g_uri_parse_scheme (disk); + /* if it's an absolute path or not a URI, it's possibly an executable */ + if (g_path_is_absolute (disk) || !scheme) + exec = command_is_executable (disk, NULL, NULL); + g_free (scheme); + + if (exec) { + panel_key_file_set_string (key_file, "Type", "Application"); + panel_key_file_set_string (key_file, "Exec", text); + name = g_strdup (text); + } else { + GFile *file; + char *uri; + + file = panel_util_get_file_optional_homedir (disk); + uri = g_file_get_uri (file); + g_object_unref (file); + + panel_key_file_set_string (key_file, "Type", "Link"); + panel_key_file_set_string (key_file, "URL", uri); + name = uri; + } + + g_free (disk); + + panel_key_file_set_locale_string (key_file, "Name", + (dialog->item_name) ? + dialog->item_name : text); + + panel_key_file_set_boolean (key_file, "Terminal", + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox))); + + if (dialog->icon_path) + panel_key_file_set_locale_string (key_file, "Icon", + dialog->icon_path); + else + panel_key_file_set_locale_string (key_file, "Icon", + PANEL_ICON_LAUNCHER); + + save_uri = panel_make_unique_desktop_uri (g_get_tmp_dir (), name); + disk = g_filename_from_uri (save_uri, NULL, NULL); + + if (!disk || !panel_key_file_to_file (key_file, disk, NULL)) { + g_free (save_uri); + save_uri = NULL; + } + + g_key_file_free (key_file); + g_free (disk); + g_free (name); + g_free (text); + + return save_uri; +} + +static void +pixmap_drag_data_get (GtkWidget *run_dialog, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + PanelRunDialog *dialog) +{ + char *uri; + + if (dialog->use_program_list && dialog->desktop_path) + uri = g_filename_to_uri (dialog->desktop_path, NULL, NULL); + else + uri = panel_run_dialog_create_desktop_file (dialog); + + if (uri) { + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), 8, + (unsigned char *) uri, strlen (uri)); + g_free (uri); + } +} + +static void +panel_run_dialog_style_set (GtkWidget *widget, + GtkStyle *prev_style, + PanelRunDialog *dialog) +{ + if (dialog->icon_path) { + char *icon_path; + + icon_path = g_strdup (dialog->icon_path); + panel_run_dialog_set_icon (dialog, icon_path, TRUE); + g_free (icon_path); + } +} + +static void +panel_run_dialog_screen_changed (GtkWidget *widget, + GdkScreen *prev_screen, + PanelRunDialog *dialog) +{ + if (dialog->icon_path) { + char *icon_path; + + icon_path = g_strdup (dialog->icon_path); + panel_run_dialog_set_icon (dialog, icon_path, TRUE); + g_free (icon_path); + } +} + +static void +panel_run_dialog_setup_pixmap (PanelRunDialog *dialog, + GtkBuilder *gui) +{ + dialog->pixmap = PANEL_GTK_BUILDER_GET (gui, "icon_pixmap"); + + g_signal_connect (dialog->pixmap, "style-set", + G_CALLBACK (panel_run_dialog_style_set), + dialog); + g_signal_connect (dialog->pixmap, "screen-changed", + G_CALLBACK (panel_run_dialog_screen_changed), + dialog); + + g_signal_connect (dialog->run_dialog, "drag_data_get", + G_CALLBACK (pixmap_drag_data_get), + dialog); +} + +static PanelRunDialog * +panel_run_dialog_new (GdkScreen *screen, + GtkBuilder *gui, + guint32 activate_time) +{ + PanelRunDialog *dialog; + + dialog = g_new0 (PanelRunDialog, 1); + + dialog->run_dialog = PANEL_GTK_BUILDER_GET (gui, "panel_run_dialog"); + + g_signal_connect_swapped (dialog->run_dialog, "response", + G_CALLBACK (panel_run_dialog_response), dialog); + + g_signal_connect_swapped (dialog->run_dialog, "destroy", + G_CALLBACK (panel_run_dialog_destroy), dialog); + + dialog->run_button = PANEL_GTK_BUILDER_GET (gui, "run_button"); + dialog->terminal_checkbox = PANEL_GTK_BUILDER_GET (gui, "terminal_checkbox"); + + panel_run_dialog_setup_pixmap (dialog, gui); + panel_run_dialog_setup_entry (dialog, gui); + panel_run_dialog_setup_file_button (dialog, gui); + panel_run_dialog_setup_program_list (dialog, gui); + panel_run_dialog_setup_list_expander (dialog, gui); + + panel_run_dialog_set_default_icon (dialog, FALSE); + + panel_run_dialog_update_content (dialog, panel_profile_get_show_program_list ()); + + gtk_widget_set_sensitive (dialog->run_button, FALSE); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog->run_dialog), + GTK_RESPONSE_OK); + + gtk_window_set_screen (GTK_WINDOW (dialog->run_dialog), screen); + + gtk_widget_grab_focus (dialog->combobox); + gtk_widget_realize (dialog->run_dialog); + gdk_x11_window_set_user_time (gtk_widget_get_window (dialog->run_dialog), + activate_time); + gtk_widget_show (dialog->run_dialog); + + return dialog; +} + +static void +panel_run_dialog_disconnect_pixmap (PanelRunDialog *dialog) +{ + g_signal_handlers_disconnect_by_func (dialog->pixmap, + G_CALLBACK (panel_run_dialog_style_set), + dialog); + g_signal_handlers_disconnect_by_func (dialog->pixmap, + G_CALLBACK (panel_run_dialog_screen_changed), + dialog); +} + +static void +panel_run_dialog_static_dialog_destroyed (PanelRunDialog *dialog) +{ + /* just reset the static dialog to NULL for next time */ + static_dialog = NULL; +} + +void +panel_run_dialog_present (GdkScreen *screen, + guint32 activate_time) +{ + GtkBuilder *gui; + GError *error; + + if (panel_lockdown_get_disable_command_line ()) + return; + + if (static_dialog) { + gtk_window_set_screen (GTK_WINDOW (static_dialog->run_dialog), screen); + gtk_window_present_with_time (GTK_WINDOW (static_dialog->run_dialog), + activate_time); + gtk_widget_grab_focus (static_dialog->combobox); + return; + } + + gui = gtk_builder_new (); + gtk_builder_set_translation_domain (gui, GETTEXT_PACKAGE); + + error = NULL; + gtk_builder_add_from_file (gui, + BUILDERDIR "/panel-run-dialog.ui", + &error); + + if (error) { + char *secondary; + + secondary = g_strdup_printf (_("Unable to load file '%s': %s."), + BUILDERDIR"/panel-run-dialog.ui", + error->message); + panel_error_dialog (NULL, screen, "cannot_display_run_dialog", + TRUE, + _("Could not display run dialog"), + secondary); + g_free (secondary); + g_error_free (error); + g_object_unref (gui); + + return; + } + + static_dialog = panel_run_dialog_new (screen, gui, activate_time); + + g_signal_connect_swapped (static_dialog->run_dialog, "destroy", + G_CALLBACK (panel_run_dialog_static_dialog_destroyed), + static_dialog); + + g_object_unref (gui); +} diff --git a/mate-panel/panel-run-dialog.h b/mate-panel/panel-run-dialog.h new file mode 100644 index 00000000..fcd3c244 --- /dev/null +++ b/mate-panel/panel-run-dialog.h @@ -0,0 +1,41 @@ +/* + * panel-run-dialog.h: + * + * Copyright (C) 2003 Frank Worsley + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Frank Worsley + */ + +#ifndef __PANEL_RUN_DIALOG_H__ +#define __PANEL_RUN_DIALOG_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_run_dialog_present (GdkScreen *screen, + guint32 activate_time); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_RUN_DIALOG_H__ */ diff --git a/mate-panel/panel-run-dialog.ui b/mate-panel/panel-run-dialog.ui new file mode 100644 index 00000000..d2bb2a86 --- /dev/null +++ b/mate-panel/panel-run-dialog.ui @@ -0,0 +1,270 @@ + + + + + + 5 + Run Application + False + center + dialog + False + + + True + vertical + 2 + + + True + 5 + vertical + 6 + + + True + + + True + 0 + 0 + 0 + 0 + + + True + 0 + 0 + gtk-missing-image + + + Command icon + The icon of the command to be run. + + + + + + + False + False + 10 + 0 + + + + + True + vertical + 6 + + + True + + + 0 + + + + + True + 12 + + + Run in _terminal + True + True + False + True + True + + + Select this box to run the command in a terminal window. + + + + + 0 + + + + + Run with _file... + True + True + False + True + + + Click this button to browse for a file whose name to append to the command string. + + + + + False + False + 1 + + + + + 1 + + + + + 1 + + + + + False + 0 + + + + + True + True + True + + + True + vertical + 6 + + + True + True + automatic + automatic + in + + + True + True + False + + + List of known applications + + + + + + + 0 + + + + + True + True + 0 + 0 + Select an application to view its description. + True + True + + + False + False + 1 + + + + + + + True + 0 + 0 + Show list of known _applications + True + + + + + 1 + + + + + 1 + + + + + True + + + gtk-help + True + True + True + False + True + + + False + False + 0 + + + + + gtk-cancel + True + True + True + False + True + + + False + False + 1 + + + + + _Run + True + True + True + True + False + run_button_image + True + + + Click this button to run the selected application or the command in the command entry field. + + + + + False + False + 2 + + + + + False + end + 0 + + + + + + help_button + cancel_button + run_button + + + + True + gtk-execute + + diff --git a/mate-panel/panel-separator.c b/mate-panel/panel-separator.c new file mode 100644 index 00000000..9a8e7186 --- /dev/null +++ b/mate-panel/panel-separator.c @@ -0,0 +1,250 @@ +/* + * panel-separator.c: panel "Separator" module + * + * Copyright (C) 2005 Carlos Garcia Campos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Carlos Garcia Campos + */ + +#include + +#include "panel-separator.h" +#include "panel-background.h" +#include "panel-profile.h" + +#define SEPARATOR_SIZE 10 + +#define PANEL_SEPARATOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_SEPARATOR, PanelSeparatorPrivate)) + +struct _PanelSeparatorPrivate { + AppletInfo *info; + PanelWidget *panel; + + GtkOrientation orientation; +}; + +G_DEFINE_TYPE (PanelSeparator, panel_separator, GTK_TYPE_EVENT_BOX) + +static void +panel_separator_paint (GtkWidget *widget, + GdkRectangle *area) +{ + PanelSeparator *separator; + GdkWindow *window; + GtkStyle *style; + GtkAllocation allocation; + + separator = PANEL_SEPARATOR (widget); + + window = gtk_widget_get_window (widget); + style = gtk_widget_get_style (widget); + gtk_widget_get_allocation (widget, &allocation); + + if (separator->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { + gtk_paint_vline (style, window, + gtk_widget_get_state (widget), + area, widget, "separator", + style->xthickness, + allocation.height - style->xthickness, + (allocation.width - style->xthickness) / 2); + } else { + gtk_paint_hline (style, window, + gtk_widget_get_state (widget), + area, widget, "separator", + style->ythickness, + allocation.width - style->ythickness, + (allocation.height - style->ythickness) / 2); + } +} + +static gboolean panel_separator_expose_event(GtkWidget* widget, GdkEventExpose* event) +{ + if (gtk_widget_is_drawable(widget)) + { + GTK_WIDGET_CLASS(panel_separator_parent_class)->expose_event(widget, event); + + panel_separator_paint(widget, &event->area); + } + + return FALSE; +} + +static void +panel_separator_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + PanelSeparator *separator; + int size; + + separator = PANEL_SEPARATOR (widget); + + size = panel_toplevel_get_size (separator->priv->panel->toplevel); + + if (separator->priv->orientation == GTK_ORIENTATION_VERTICAL) { + requisition->width = size; + requisition->height = SEPARATOR_SIZE; + } else { + requisition->width = SEPARATOR_SIZE; + requisition->height = size; + } +} + +static void +panel_separator_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkAllocation old_allocation; + GtkAllocation widget_allocation; + PanelBackground *background; + + gtk_widget_get_allocation (widget, &widget_allocation); + + old_allocation.x = widget_allocation.x; + old_allocation.y = widget_allocation.y; + old_allocation.width = widget_allocation.width; + old_allocation.height = widget_allocation.height; + + GTK_WIDGET_CLASS (panel_separator_parent_class)->size_allocate (widget, allocation); + + if (old_allocation.x == allocation->x && + old_allocation.y == allocation->y && + old_allocation.width == allocation->width && + old_allocation.height == allocation->height) + return; + + background = &PANEL_SEPARATOR (widget)->priv->panel->background; + + if (background->type == PANEL_BACK_NONE || + (background->type == PANEL_BACK_COLOR && !background->has_alpha)) + return; + + panel_separator_change_background (PANEL_SEPARATOR (widget)); +} + +static void +panel_separator_parent_set (GtkWidget *widget, + GtkWidget *previous_parent) +{ + PanelSeparator *separator; + GtkWidget *parent; + + separator = PANEL_SEPARATOR (widget); + + parent = gtk_widget_get_parent (widget); + g_assert (!parent || PANEL_IS_WIDGET (parent)); + + separator->priv->panel = (PanelWidget *) parent; +} + +static void +panel_separator_class_init (PanelSeparatorClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->expose_event = panel_separator_expose_event; + widget_class->size_request = panel_separator_size_request; + widget_class->size_allocate = panel_separator_size_allocate; + widget_class->parent_set = panel_separator_parent_set; + + g_type_class_add_private (klass, sizeof (PanelSeparatorPrivate)); +} + +static void +panel_separator_init (PanelSeparator *separator) +{ + separator->priv = PANEL_SEPARATOR_GET_PRIVATE (separator); + + separator->priv->info = NULL; + separator->priv->panel = NULL; + separator->priv->orientation = GTK_ORIENTATION_HORIZONTAL; +} + +void +panel_separator_set_orientation (PanelSeparator *separator, + PanelOrientation orientation) +{ + GtkOrientation orient = GTK_ORIENTATION_HORIZONTAL; + + g_return_if_fail (PANEL_IS_SEPARATOR (separator)); + + switch (orientation) { + case PANEL_ORIENTATION_TOP: + case PANEL_ORIENTATION_BOTTOM: + orient = GTK_ORIENTATION_HORIZONTAL; + break; + case PANEL_ORIENTATION_RIGHT: + case PANEL_ORIENTATION_LEFT: + orient = GTK_ORIENTATION_VERTICAL; + break; + } + + if (orient == separator->priv->orientation) + return; + + separator->priv->orientation = orient; + + gtk_widget_queue_draw (GTK_WIDGET (separator)); +} + +void +panel_separator_load_from_mateconf (PanelWidget *panel, + gboolean locked, + int position, + const char *id) +{ + PanelSeparator *separator; + + separator = g_object_new (PANEL_TYPE_SEPARATOR, NULL); + + separator->priv->info = mate_panel_applet_register (GTK_WIDGET (separator), + NULL, NULL, + panel, locked, position, + TRUE, + PANEL_OBJECT_SEPARATOR, + id); + + if (!separator->priv->info) { + gtk_widget_destroy (GTK_WIDGET (separator)); + return; + } + + panel_widget_set_applet_expandable (panel, GTK_WIDGET (separator), + FALSE, TRUE); + panel_widget_set_applet_size_constrained (panel, + GTK_WIDGET (separator), TRUE); +} + +void +panel_separator_create (PanelToplevel *toplevel, + int position) +{ + char *id; + + id = panel_profile_prepare_object (PANEL_OBJECT_SEPARATOR, + toplevel, position, FALSE); + panel_profile_add_to_list (PANEL_MATECONF_OBJECTS, id); + g_free (id); +} + +void +panel_separator_change_background (PanelSeparator *separator) +{ + panel_background_change_background_on_widget (&separator->priv->panel->background, + GTK_WIDGET (separator)); +} diff --git a/mate-panel/panel-separator.h b/mate-panel/panel-separator.h new file mode 100644 index 00000000..a7c699b8 --- /dev/null +++ b/mate-panel/panel-separator.h @@ -0,0 +1,71 @@ +/* + * panel-separator.h: panel "Separator" module + * + * Copyright (C) 2005 Carlos Garcia Campos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Carlos Garcia Campos + */ + +#ifndef PANEL_SEPARATOR_H +#define PANEL_SEPARATOR_H + +#include "applet.h" +#include "panel-widget.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_SEPARATOR (panel_separator_get_type ()) +#define PANEL_SEPARATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_SEPARATOR, PanelSeparator)) +#define PANEL_SEPARATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_SEPARATOR, PanelSeparatorClass)) +#define PANEL_IS_SEPARATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_SEPARATOR)) +#define PANEL_IS_SEPARATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_SEPARATOR)) +#define PANEL_SEPARATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_SEPARATOR, PanelSeparatorClass)) + +typedef struct _PanelSeparator PanelSeparator; +typedef struct _PanelSeparatorClass PanelSeparatorClass; +typedef struct _PanelSeparatorPrivate PanelSeparatorPrivate; + +struct _PanelSeparator { + GtkEventBox parent; + + PanelSeparatorPrivate *priv; +}; + +struct _PanelSeparatorClass { + GtkEventBoxClass parent_class; +}; + +GType panel_separator_get_type (void) G_GNUC_CONST; +void panel_separator_create (PanelToplevel *toplevel, + int position); +void panel_separator_load_from_mateconf (PanelWidget *panel_widget, + gboolean locked, + gint position, + const char *id); +void panel_separator_set_orientation (PanelSeparator *separator, + PanelOrientation orientation); +void panel_separator_change_background (PanelSeparator *separator); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_SEPARATOR_H */ diff --git a/mate-panel/panel-session.c b/mate-panel/panel-session.c new file mode 100644 index 00000000..1175b3dc --- /dev/null +++ b/mate-panel/panel-session.c @@ -0,0 +1,80 @@ +/* + * panel-session.c: panel session management routines + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include + +#include + +#include + +#include "panel-shell.h" + +#include "panel-session.h" + +static gboolean do_not_restart = FALSE; + +static void +panel_session_handle_quit (EggSMClient *client, + gpointer data) +{ + panel_shell_quit (); +} + +void +panel_session_do_not_restart (void) +{ + do_not_restart = TRUE; + + if (egg_sm_client_get_mode () != EGG_SM_CLIENT_MODE_DISABLED) + egg_sm_client_set_mode (EGG_SM_CLIENT_MODE_NO_RESTART); +} + +void +panel_session_init (void) +{ + EggSMClientMode mode; + EggSMClient *client; + + /* Explicitly tell the session manager we're ready -- we don't do it + * before. Note: this depends on setting the mode to DISABLED early + * during startup. */ + + if (do_not_restart || getenv ("MATE_PANEL_DEBUG")) + mode = EGG_SM_CLIENT_MODE_NO_RESTART; + else + mode = EGG_SM_CLIENT_MODE_NORMAL; + + egg_sm_client_set_mode (mode); + + client = egg_sm_client_get (); + + g_signal_connect (client, "quit", + G_CALLBACK (panel_session_handle_quit), NULL); + + /* We don't want the WM to try and save/restore our + * window position */ + gdk_set_sm_client_id (NULL); +} diff --git a/mate-panel/panel-session.h b/mate-panel/panel-session.h new file mode 100644 index 00000000..528d9059 --- /dev/null +++ b/mate-panel/panel-session.h @@ -0,0 +1,39 @@ +/* + * panel-session.h: panel session management routines + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_SESSION_H__ +#define __PANEL_SESSION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void panel_session_init (void); +void panel_session_do_not_restart (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_SESSION_H__ */ diff --git a/mate-panel/panel-shell.c b/mate-panel/panel-shell.c new file mode 100644 index 00000000..d54da4b9 --- /dev/null +++ b/mate-panel/panel-shell.c @@ -0,0 +1,164 @@ +/* + * panel-shell.c: panel shell interface implementation + * + * Copyright (C) 2001 Ximian, Inc. + * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * Copyright (C) 2010 Carlos Garcia Campos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Jacob Berkman + * Colin Walters + * Vincent Untz + */ + +#include +#include + +#include + +#include "panel-profile.h" +#include "panel-session.h" + +#include "panel-shell.h" + +#define PANEL_DBUS_SERVICE "org.mate.Panel" + +static GDBusConnection *dbus_connection = NULL; + +static void +panel_shell_on_name_lost (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + /* We lost our DBus name, and there is something replacing us. + * Tell the SM not to restart us automatically, then exit. */ + g_printerr ("Panel leaving: a new panel shell is starting.\n"); + + panel_session_do_not_restart (); + panel_shell_quit (); +} + +static void +panel_shell_cleanup (gpointer data) +{ + if (dbus_connection != NULL) { + g_object_unref (dbus_connection); + dbus_connection = NULL; + } +} + +gboolean +panel_shell_register (gboolean replace) +{ + GBusNameOwnerFlags flags; + guint32 request_name_reply; + GVariant *result; + gboolean retval = FALSE; + GError *error = NULL; + + if (dbus_connection != NULL) + return TRUE; + + panel_cleanup_register (PANEL_CLEAN_FUNC (panel_shell_cleanup), NULL); + + /* There isn't a sync version of g_bus_own_name, so we have to requeste + * the name manually here. There's no ui yet so it's safe to use this + * sync api */ + dbus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (dbus_connection == NULL) { + g_warning ("Cannot register the panel shell: %s", error->message); + goto register_out; + } + + flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT; + if (replace) + flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE; + + result = g_dbus_connection_call_sync (dbus_connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "RequestName", + g_variant_new ("(su)", + PANEL_DBUS_SERVICE, + flags), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (!result) { + g_warning ("Cannot register the panel shell: %s", + error->message); + g_error_free (error); + + goto register_out; + } + + g_variant_get (result, "(u)", &request_name_reply); + g_variant_unref (result); + + switch (request_name_reply) { + case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */ + case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */ + retval = TRUE; + g_dbus_connection_signal_subscribe (dbus_connection, + "org.freedesktop.DBus", + "org.freedesktop.DBus", + "NameLost", + "/org/freedesktop/DBus", + PANEL_DBUS_SERVICE, + G_DBUS_SIGNAL_FLAGS_NONE, + (GDBusSignalCallback)panel_shell_on_name_lost, + NULL, NULL); + break; + case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */ + case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */ + g_printerr ("Cannot register the panel shell: there is " + "already one running.\n"); + break; + default: + g_warning ("Cannot register the panel shell: unhandled " + "reply %u from RequestName", request_name_reply); + } + +register_out: + + if (!retval) { + panel_session_do_not_restart (); + panel_shell_cleanup (NULL); + } + + return retval; +} + +void +panel_shell_quit (void) +{ + GSList *toplevels_to_destroy, *l; + + toplevels_to_destroy = g_slist_copy (panel_toplevel_list_toplevels ()); + for (l = toplevels_to_destroy; l; l = l->next) + gtk_widget_destroy (l->data); + g_slist_free (toplevels_to_destroy); + + gtk_main_quit (); +} diff --git a/mate-panel/panel-shell.h b/mate-panel/panel-shell.h new file mode 100644 index 00000000..a779c815 --- /dev/null +++ b/mate-panel/panel-shell.h @@ -0,0 +1,37 @@ +/* + * panel-shell.h: panel shell interface implementation + * + * Copyright (C) 2001 Ximian, Inc. + * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Jacob Berkman + * Colin Walters + * Vincent Untz + */ + +#ifndef __PANEL_SHELL_H__ +#define __PANEL_SHELL_H__ + +#include + +gboolean panel_shell_register (gboolean replace); +void panel_shell_quit (void); + +#endif /* __PANEL_SHELL_H__ */ diff --git a/mate-panel/panel-stock-icons.c b/mate-panel/panel-stock-icons.c new file mode 100644 index 00000000..f7621a77 --- /dev/null +++ b/mate-panel/panel-stock-icons.c @@ -0,0 +1,141 @@ +/* + * panel-stock-icons.c panel stock icons registration + * + * Copyright (C) 2002 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include "config.h" + +#include "panel-stock-icons.h" + +#include +#include + +#include "panel-icon-names.h" + +static GtkIconSize panel_menu_icon_size = 0; +static GtkIconSize panel_menu_bar_icon_size = 0; + +GtkIconSize +panel_menu_icon_get_size (void) +{ + return panel_menu_icon_size; +} + +GtkIconSize +panel_menu_bar_icon_get_size (void) +{ + return panel_menu_bar_icon_size; +} + +typedef struct { + char *stock_id; + char *icon; +} PanelStockIcon; + +static PanelStockIcon stock_icons [] = { + { PANEL_STOCK_FORCE_QUIT, PANEL_ICON_FORCE_QUIT } +}; + +static void +panel_init_stock_icons (GtkIconFactory *factory) +{ + GtkIconSource *source; + int i; + + + source = gtk_icon_source_new (); + + for (i = 0; i < G_N_ELEMENTS (stock_icons); i++) { + GtkIconSet *set; + + gtk_icon_source_set_icon_name (source, stock_icons [i].icon); + + set = gtk_icon_set_new (); + gtk_icon_set_add_source (set, source); + + gtk_icon_factory_add (factory, stock_icons [i].stock_id, set); + gtk_icon_set_unref (set); + } + + gtk_icon_source_free (source); + +} + +typedef struct { + char *stock_id; + char *stock_icon_id; + char *label; +} PanelStockItem; + +static PanelStockItem stock_items [] = { + { PANEL_STOCK_EXECUTE, GTK_STOCK_EXECUTE, N_("_Run") }, + { PANEL_STOCK_FORCE_QUIT, PANEL_STOCK_FORCE_QUIT, N_("_Force quit") }, + { PANEL_STOCK_CLEAR, GTK_STOCK_CLEAR, N_("C_lear") }, + { PANEL_STOCK_DONT_DELETE, GTK_STOCK_CANCEL, N_("D_on't Delete") } +}; + +static void +panel_init_stock_items (GtkIconFactory *factory) +{ + GtkStockItem *items; + int i; + + items = g_new (GtkStockItem, G_N_ELEMENTS (stock_items)); + + for (i = 0; i < G_N_ELEMENTS (stock_items); i++) { + GtkIconSet *icon_set; + + items [i].stock_id = g_strdup (stock_items [i].stock_id); + items [i].label = g_strdup (stock_items [i].label); + items [i].modifier = 0; + items [i].keyval = 0; + items [i].translation_domain = g_strdup (GETTEXT_PACKAGE); + + /* FIXME: does this take into account the theme? */ + icon_set = gtk_icon_factory_lookup_default (stock_items [i].stock_icon_id); + gtk_icon_factory_add (factory, stock_items [i].stock_id, icon_set); + } + + gtk_stock_add_static (items, G_N_ELEMENTS (stock_items)); +} + +void +panel_init_stock_icons_and_items (void) +{ + GtkIconFactory *factory; + + panel_menu_icon_size = gtk_icon_size_register ("panel-menu", + PANEL_DEFAULT_MENU_ICON_SIZE, + PANEL_DEFAULT_MENU_ICON_SIZE); + + panel_menu_bar_icon_size = gtk_icon_size_register ("panel-foobar", + PANEL_DEFAULT_MENU_BAR_ICON_SIZE, + PANEL_DEFAULT_MENU_BAR_ICON_SIZE); + + factory = gtk_icon_factory_new (); + gtk_icon_factory_add_default (factory); + + panel_init_stock_icons (factory); + panel_init_stock_items (factory); + + g_object_unref (factory); +} diff --git a/mate-panel/panel-stock-icons.h b/mate-panel/panel-stock-icons.h new file mode 100644 index 00000000..cb6085f4 --- /dev/null +++ b/mate-panel/panel-stock-icons.h @@ -0,0 +1,60 @@ +/* + * panel-stock-icons.h: panel stock icons registration + * + * Copyright (C) 2002 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_STOCK_ICONS_H__ +#define __PANEL_STOCK_ICONS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* themeable size - "panel-menu" -- This is used for the icons in the menus */ +#define PANEL_DEFAULT_MENU_ICON_SIZE 24 +/* themeable size - "panel-foobar" -- This is only used for the icon of the + * Applications item in the menu bar */ +#define PANEL_DEFAULT_MENU_BAR_ICON_SIZE 24 + +/* stock icons */ +#define PANEL_STOCK_FORCE_QUIT "mate-panel-force-quit" + +/* stock items - no point in theme the icons one these, + * they use stock gtk icons and just modify the text + * for the stock item. + */ +#define PANEL_STOCK_EXECUTE "panel-execute" +#define PANEL_STOCK_CLEAR "panel-clear" +#define PANEL_STOCK_DONT_DELETE "panel-dont-delete" + +void panel_init_stock_icons_and_items (void); +GtkIconSize panel_menu_icon_get_size (void); +GtkIconSize panel_menu_bar_icon_get_size (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_STOCK_ICONS_H__ */ diff --git a/mate-panel/panel-struts.c b/mate-panel/panel-struts.c new file mode 100644 index 00000000..b75bf704 --- /dev/null +++ b/mate-panel/panel-struts.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2003 Sun Microsystems, Inc. + * Copyright (C) 2003,2004 Rob Adams + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-struts.h" + +#include "panel-multiscreen.h" +#include "panel-xutils.h" + + +typedef struct { + PanelToplevel *toplevel; + + GdkScreen *screen; + int monitor; + + PanelOrientation orientation; + GdkRectangle geometry; + int strut_size; + int strut_start; + int strut_end; + + GdkRectangle allocated_geometry; + int allocated_strut_size; + int allocated_strut_start; + int allocated_strut_end; +} PanelStrut; + + +static GSList *panel_struts_list = NULL; + + +static inline PanelStrut * +panel_struts_find_strut (PanelToplevel *toplevel) +{ + GSList *l; + + for (l = panel_struts_list; l; l = l->next) { + PanelStrut *strut = l->data; + + if (strut->toplevel == toplevel) + break; + } + + return l ? l->data : NULL; +} + +static void +panel_struts_get_monitor_geometry (GdkScreen *screen, + int monitor, + int *x, + int *y, + int *width, + int *height) +{ + *x = panel_multiscreen_x (screen, monitor); + *y = panel_multiscreen_y (screen, monitor); + *width = panel_multiscreen_width (screen, monitor); + *height = panel_multiscreen_height (screen, monitor); +} + +static PanelStrut * +panel_struts_intersect (GSList *struts, + GdkRectangle *geometry, + int skip) +{ + GSList *l; + int i; + + i = 0; + for (l = struts; l; l = l->next) { + PanelStrut *strut = l->data; + int x1, y1, x2, y2; + + x1 = MAX (strut->allocated_geometry.x, geometry->x); + y1 = MAX (strut->allocated_geometry.y, geometry->y); + + x2 = MIN (strut->allocated_geometry.x + strut->allocated_geometry.width, + geometry->x + geometry->width); + y2 = MIN (strut->allocated_geometry.y + strut->allocated_geometry.height, + geometry->y + geometry->height); + + if (x2 - x1 > 0 && y2 - y1 > 0 && ++i > skip) + break; + } + + return l ? l->data : NULL; +} + +static int +panel_struts_allocation_overlapped (PanelStrut *strut, + PanelStrut *overlap, + GdkRectangle *geometry, + gboolean *moved_down, + int skip) +{ + int overlap_x1, overlap_y1, overlap_x2, overlap_y2; + + overlap_x1 = overlap->allocated_geometry.x; + overlap_y1 = overlap->allocated_geometry.y; + overlap_x2 = overlap->allocated_geometry.x + overlap->allocated_geometry.width; + overlap_y2 = overlap->allocated_geometry.y + overlap->allocated_geometry.height; + + if (strut->orientation == overlap->orientation) { + int old_x, old_y; + + old_x = geometry->x; + old_y = geometry->y; + + switch (strut->orientation) { + case PANEL_ORIENTATION_TOP: + geometry->y = overlap_y2; + strut->allocated_strut_size += geometry->y - old_y; + break; + case PANEL_ORIENTATION_BOTTOM: + geometry->y = overlap_y1 - geometry->height; + strut->allocated_strut_size += old_y - geometry->y; + break; + case PANEL_ORIENTATION_LEFT: + geometry->x = overlap_x2; + strut->allocated_strut_size += geometry->x - old_x; + break; + case PANEL_ORIENTATION_RIGHT: + geometry->x = overlap_x1 - geometry->width; + strut->allocated_strut_size += old_x - geometry->x; + break; + default: + g_assert_not_reached (); + break; + } + } else { + if (strut->orientation & PANEL_HORIZONTAL_MASK || + overlap->orientation & PANEL_VERTICAL_MASK) + return ++skip; + + switch (overlap->orientation) { + case PANEL_ORIENTATION_TOP: + geometry->y = overlap_y2; + *moved_down = TRUE; + break; + case PANEL_ORIENTATION_BOTTOM: + if (!*moved_down) + geometry->y = overlap_y1 - geometry->height; + else if (overlap_y1 > geometry->y) + geometry->height = overlap_y1 - geometry->y; + else + return ++skip; + break; + default: + g_assert_not_reached (); + break; + } + + strut->allocated_strut_start = geometry->y; + strut->allocated_strut_end = geometry->y + geometry->height - 1; + } + + return skip; +} + +static gboolean +panel_struts_allocate_struts (PanelToplevel *toplevel, + GdkScreen *screen, + int monitor) +{ + GSList *allocated = NULL; + GSList *l; + gboolean toplevel_changed = FALSE; + + for (l = panel_struts_list; l; l = l->next) { + PanelStrut *strut = l->data; + PanelStrut *overlap; + GdkRectangle geometry; + int monitor_x, monitor_y; + int monitor_width, monitor_height; + gboolean moved_down; + int skip; + + if (strut->screen != screen || strut->monitor != monitor) + continue; + + panel_struts_get_monitor_geometry (strut->screen, strut->monitor, + &monitor_x, &monitor_y, + &monitor_width, &monitor_height); + + strut->allocated_strut_size = strut->strut_size; + strut->allocated_strut_start = strut->strut_start; + strut->allocated_strut_end = strut->strut_end; + + geometry = strut->geometry; + + moved_down = FALSE; + skip = 0; + while ((overlap = panel_struts_intersect (allocated, &geometry, skip))) + skip = panel_struts_allocation_overlapped ( + strut, overlap, &geometry, &moved_down, skip); + + if (strut->orientation & PANEL_VERTICAL_MASK) { + if (geometry.y < monitor_y) { + geometry.height = geometry.y + geometry.height - monitor_y; + geometry.y = monitor_y; + } + + if (geometry.y + geometry.height > monitor_y + monitor_height) + geometry.height = monitor_y + monitor_height - geometry.y; + } + + if (strut->allocated_geometry.x != geometry.x || + strut->allocated_geometry.y != geometry.y || + strut->allocated_geometry.width != geometry.width || + strut->allocated_geometry.height != geometry.height) { + strut->allocated_geometry = geometry; + + if (strut->toplevel == toplevel) + toplevel_changed = TRUE; + else + gtk_widget_queue_resize (GTK_WIDGET (strut->toplevel)); + } + + allocated = g_slist_append (allocated, strut); + } + + g_slist_free (allocated); + + return toplevel_changed; +} + +void +panel_struts_set_window_hint (PanelToplevel *toplevel) +{ + GtkWidget *widget; + PanelStrut *strut; + int strut_size; + int monitor_x, monitor_y, monitor_width, monitor_height; + int screen_width, screen_height; + int leftmost, rightmost, topmost, bottommost; + + widget = GTK_WIDGET (toplevel); + + if (!gtk_widget_get_realized (widget)) + return; + + if (!(strut = panel_struts_find_strut (toplevel))) { + panel_struts_unset_window_hint (toplevel); + return; + } + + strut_size = strut->allocated_strut_size; + + screen_width = gdk_screen_get_width (strut->screen); + screen_height = gdk_screen_get_height (strut->screen); + + panel_struts_get_monitor_geometry (strut->screen, + strut->monitor, + &monitor_x, + &monitor_y, + &monitor_width, + &monitor_height); + + panel_multiscreen_is_at_visible_extreme (strut->screen, + strut->monitor, + &leftmost, + &rightmost, + &topmost, + &bottommost); + + switch (strut->orientation) { + case PANEL_ORIENTATION_TOP: + if (monitor_y > 0) + strut_size += monitor_y; + if (!topmost) strut_size = 0; + break; + case PANEL_ORIENTATION_BOTTOM: + if (monitor_y + monitor_height < screen_height) + strut_size += screen_height - (monitor_y + monitor_height); + if (!bottommost) strut_size = 0; + break; + case PANEL_ORIENTATION_LEFT: + if (leftmost && monitor_x > 0) + strut_size += monitor_x; + if (!leftmost) strut_size = 0; + break; + case PANEL_ORIENTATION_RIGHT: + if (monitor_x + monitor_width < screen_width) + strut_size += screen_width - (monitor_x + monitor_width); + if (!rightmost) strut_size = 0; + break; + default: + g_assert_not_reached (); + break; + } + + panel_xutils_set_strut (gtk_widget_get_window (widget), + strut->orientation, + strut_size, + strut->allocated_strut_start, + strut->allocated_strut_end); +} + +void +panel_struts_unset_window_hint (PanelToplevel *toplevel) +{ + if (!gtk_widget_get_realized (GTK_WIDGET (toplevel))) + return; + + panel_xutils_set_strut (gtk_widget_get_window (GTK_WIDGET (toplevel)), 0, 0, 0, 0); +} + +static inline int +orientation_to_order (PanelOrientation orientation) +{ + switch (orientation) { + case PANEL_ORIENTATION_TOP: + return 1; + case PANEL_ORIENTATION_BOTTOM: + return 2; + case PANEL_ORIENTATION_LEFT: + return 3; + case PANEL_ORIENTATION_RIGHT: + return 4; + default: + g_assert_not_reached (); + return -1; + } +} + +static inline int +get_toplevel_depth (PanelToplevel *toplevel) +{ + int depth = 0; + + while ((toplevel = panel_toplevel_get_attach_toplevel (toplevel))) + depth++; + + return depth; +} + +/* Sort in order of + * 1) screen + * 2) monitor + * 3) depth (for drawers) + * 4) top, bottom, left, right + * 5) strut_start ascending + * 6) strut_end descending + */ +static int +panel_struts_compare (const PanelStrut *s1, + const PanelStrut *s2) +{ + int s1_depth; + int s2_depth; + + if (s1->screen != s2->screen) + return gdk_screen_get_number (s1->screen) - + gdk_screen_get_number (s2->screen); + + if (s1->monitor != s2->monitor) + return s1->monitor - s2->monitor; + + s1_depth = get_toplevel_depth (s1->toplevel); + s2_depth = get_toplevel_depth (s2->toplevel); + if (s1_depth != s2_depth) + return s2_depth - s1_depth; + + if (s1->orientation != s2->orientation) + return orientation_to_order (s1->orientation) - + orientation_to_order (s2->orientation); + + if (s1->strut_start != s2->strut_start) + return s1->strut_start - s2->strut_start; + + if (s1->strut_end != s2->strut_end) + return s2->strut_end - s1->strut_end; + + return 0; +} + +gboolean +panel_struts_register_strut (PanelToplevel *toplevel, + GdkScreen *screen, + int monitor, + PanelOrientation orientation, + int strut_size, + int strut_start, + int strut_end) +{ + PanelStrut *strut; + gboolean new_strut = FALSE; + int monitor_x, monitor_y, monitor_width, monitor_height; + + if (!(strut = panel_struts_find_strut (toplevel))) { + strut = g_new0 (PanelStrut, 1); + new_strut = TRUE; + + } else if (strut->toplevel == toplevel && + strut->orientation == orientation && + strut->screen == screen && + strut->monitor == monitor && + strut->strut_size == strut_size && + strut->strut_start == strut_start && + strut->strut_end == strut_end) + return FALSE; + + strut->toplevel = toplevel; + strut->orientation = orientation; + strut->screen = screen; + strut->monitor = monitor; + strut->strut_size = strut_size; + strut->strut_start = strut_start; + strut->strut_end = strut_end; + + panel_struts_get_monitor_geometry (screen, monitor, + &monitor_x, &monitor_y, + &monitor_width, &monitor_height); + + switch (strut->orientation) { + case PANEL_ORIENTATION_TOP: + strut->geometry.x = strut->strut_start; + strut->geometry.y = monitor_y; + strut->geometry.width = strut->strut_end - strut->strut_start + 1; + strut->geometry.height = strut->strut_size; + break; + case PANEL_ORIENTATION_BOTTOM: + strut->geometry.x = strut->strut_start; + strut->geometry.y = monitor_y + monitor_height - strut->strut_size; + strut->geometry.width = strut->strut_end - strut->strut_start + 1; + strut->geometry.height = strut->strut_size; + break; + case PANEL_ORIENTATION_LEFT: + strut->geometry.x = monitor_x; + strut->geometry.y = strut->strut_start; + strut->geometry.width = strut->strut_size; + strut->geometry.height = strut->strut_end - strut->strut_start + 1; + break; + case PANEL_ORIENTATION_RIGHT: + strut->geometry.x = monitor_x + monitor_width - strut->strut_size; + strut->geometry.y = strut->strut_start; + strut->geometry.width = strut->strut_size; + strut->geometry.height = strut->strut_end - strut->strut_start + 1; + break; + } + + if (new_strut) + panel_struts_list = g_slist_append (panel_struts_list, strut); + + panel_struts_list = g_slist_sort (panel_struts_list, + (GCompareFunc) panel_struts_compare); + + return panel_struts_allocate_struts (toplevel, screen, monitor); +} + +void +panel_struts_unregister_strut (PanelToplevel *toplevel) +{ + PanelStrut *strut; + GdkScreen *screen; + int monitor; + + if (!(strut = panel_struts_find_strut (toplevel))) + return; + + screen = strut->screen; + monitor = strut->monitor; + + panel_struts_list = g_slist_remove (panel_struts_list, strut); + g_free (strut); + + panel_struts_allocate_struts (toplevel, screen, monitor); +} + +gboolean +panel_struts_update_toplevel_geometry (PanelToplevel *toplevel, + int *x, + int *y, + int *width, + int *height) +{ + PanelStrut *strut; + + g_return_val_if_fail (x != NULL, FALSE); + g_return_val_if_fail (y != NULL, FALSE); + + if (!(strut = panel_struts_find_strut (toplevel))) + return FALSE; + + *x += strut->allocated_geometry.x - strut->geometry.x; + *y += strut->allocated_geometry.y - strut->geometry.y; + + if (width != NULL && *width != -1) + *width += strut->allocated_geometry.width - strut->geometry.width; + if (height != NULL && *height != -1) + *height += strut->allocated_geometry.height - strut->geometry.height; + + return TRUE; +} diff --git a/mate-panel/panel-struts.h b/mate-panel/panel-struts.h new file mode 100644 index 00000000..e7ef420d --- /dev/null +++ b/mate-panel/panel-struts.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_STRUTS_H__ +#define __PANEL_STRUTS_H__ + +#include +#include "panel-toplevel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +gboolean panel_struts_register_strut (PanelToplevel *toplevel, + GdkScreen *screen, + int monitor, + PanelOrientation orientation, + int strut_size, + int strut_start, + int strut_end); + +void panel_struts_unregister_strut (PanelToplevel *toplevel); + +void panel_struts_set_window_hint (PanelToplevel *toplevel); +void panel_struts_unset_window_hint (PanelToplevel *toplevel); + +gboolean panel_struts_update_toplevel_geometry (PanelToplevel *toplevel, + int *x, + int *y, + int *w, + int *h); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_STRUTS_H__ */ diff --git a/mate-panel/panel-test-applets.c b/mate-panel/panel-test-applets.c new file mode 100644 index 00000000..ed844c89 --- /dev/null +++ b/mate-panel/panel-test-applets.c @@ -0,0 +1,388 @@ +/* + * panel-test-applets.c: + * + * Authors: + * Mark McLoughlin + * + * Copyright 2002 Sun Microsystems, Inc. + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "panel-modules.h" + +G_GNUC_UNUSED void on_execute_button_clicked (GtkButton *button, gpointer dummy); + +static GtkWidget *win = NULL; +static GtkWidget *applet_combo = NULL; +static GtkWidget *prefs_dir_entry = NULL; +static GtkWidget *orient_combo = NULL; +static GtkWidget *size_combo = NULL; + +static char *cli_iid = NULL; +static char *cli_prefs_dir = NULL; +static char *cli_size = NULL; +static char *cli_orient = NULL; + +static const GOptionEntry options [] = { + { "iid", 0, 0, G_OPTION_ARG_STRING, &cli_iid, N_("Specify an applet IID to load"), NULL}, + { "prefs-dir", 0, 0, G_OPTION_ARG_STRING, &cli_prefs_dir, N_("Specify a mateconf location in which the applet preferences should be stored"), NULL}, + { "size", 0, 0, G_OPTION_ARG_STRING, &cli_size, N_("Specify the initial size of the applet (xx-small, medium, large etc.)"), NULL}, + { "orient", 0, 0, G_OPTION_ARG_STRING, &cli_orient, N_("Specify the initial orientation of the applet (top, bottom, left or right)"), NULL}, + { NULL} +}; + +enum { + COLUMN_TEXT, + COLUMN_ITEM, + NUMBER_COLUMNS +}; + +typedef struct { + const char *name; + guint value; +} ComboItem; + +static ComboItem orient_items [] = { + { NC_("Orientation", "Top"), PANEL_ORIENTATION_TOP }, + { NC_("Orientation", "Bottom"), PANEL_ORIENTATION_BOTTOM }, + { NC_("Orientation", "Left"), PANEL_ORIENTATION_LEFT }, + { NC_("Orientation", "Right"), PANEL_ORIENTATION_RIGHT } +}; + + +static ComboItem size_items [] = { + { NC_("Size", "XX Small"), 12 }, + { NC_("Size", "X Small"), 24 }, + { NC_("Size", "Small"), 36 }, + { NC_("Size", "Medium"), 48 }, + { NC_("Size", "Large"), 64 }, + { NC_("Size", "X Large"), 80 }, + { NC_("Size", "XX Large"), 128 } +}; + +static guint +get_combo_value (GtkWidget *combo_box) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint value; + + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter)) + return 0; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + gtk_tree_model_get (model, &iter, COLUMN_ITEM, &value, -1); + + return value; +} + +static gchar * +get_combo_applet_id (GtkWidget *combo_box) +{ + GtkTreeIter iter; + GtkTreeModel *model; + char *value; + + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter)) + return NULL; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + gtk_tree_model_get (model, &iter, COLUMN_ITEM, &value, -1); + + return value; +} + +static void +applet_broken_cb (GtkWidget *container, + GtkWidget *window) +{ + gtk_widget_destroy (window); +} + +static void +applet_activated_cb (GObject *source_object, + GAsyncResult *res, + GtkWidget *applet_window) +{ + GError *error = NULL; + + if (!mate_panel_applet_container_add_finish (MATE_PANEL_APPLET_CONTAINER (source_object), + res, &error)) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (applet_window), + GTK_DIALOG_MODAL| + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Failed to load applet %s"), + error->message); // FIXME + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + return; + } + + gtk_widget_show (applet_window); +} + +static void +load_applet_into_window (const char *title, + const char *prefs_key, + guint size, + guint orientation) +{ + GtkWidget *container; + GtkWidget *applet_window; + GVariantBuilder builder; + + container = mate_panel_applet_container_new (); + + applet_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + //FIXME: we could set the window icon with the applet icon + gtk_window_set_title (GTK_WINDOW (applet_window), title); + gtk_container_add (GTK_CONTAINER (applet_window), container); + gtk_widget_show (container); + + g_signal_connect (container, "applet-broken", + G_CALLBACK (applet_broken_cb), + applet_window); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", + "prefs-key", g_variant_new_string (prefs_key)); + g_variant_builder_add (&builder, "{sv}", + "size", g_variant_new_uint32 (size)); + g_variant_builder_add (&builder, "{sv}", + "orient", g_variant_new_uint32 (orientation)); + mate_panel_applet_container_add (MATE_PANEL_APPLET_CONTAINER (container), + title, NULL, + (GAsyncReadyCallback)applet_activated_cb, + applet_window, + g_variant_builder_end (&builder)); +} + +static void +load_applet_from_command_line (void) +{ + guint size = 24, orient = PANEL_ORIENTATION_TOP; + gint i; + + g_assert (cli_iid != NULL); + + if (cli_size || cli_orient) { + if (cli_size) { + for (i = 0; i < G_N_ELEMENTS (size_items); i++) { + if (strcmp (g_dpgettext2 (NULL, "Size", size_items[i].name), cli_size) == 0) { + size = size_items[i].value; + break; + } + } + } + + if (cli_orient) { + for (i = 0; i < G_N_ELEMENTS (orient_items); i++) { + if (strcmp (g_dpgettext2 (NULL, "Orientation", orient_items[i].name), cli_orient) == 0) { + orient = orient_items[i].value; + break; + } + } + } + } + + g_print ("Loading %s\n", cli_iid); + + load_applet_into_window (cli_iid, cli_prefs_dir, size, orient); +} + +G_GNUC_UNUSED void +on_execute_button_clicked (GtkButton *button, + gpointer dummy) +{ + char *title; + + title = get_combo_applet_id (applet_combo); + + load_applet_into_window (title, + gtk_entry_get_text (GTK_ENTRY (prefs_dir_entry)), + get_combo_value (size_combo), + get_combo_value (orient_combo)); + g_free (title); +} + +static void +setup_combo (GtkWidget *combo_box, + ComboItem *items, + const char *context, + int nb_items) +{ + GtkListStore *model; + GtkTreeIter iter; + GtkCellRenderer *renderer; + int i; + + model = gtk_list_store_new (NUMBER_COLUMNS, + G_TYPE_STRING, + G_TYPE_INT); + + gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), + GTK_TREE_MODEL (model)); + + + for (i = 0; i < nb_items; i++) { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_TEXT, g_dpgettext2 (NULL, context, items [i].name), + COLUMN_ITEM, items [i].value, + -1); + } + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), + renderer, "text", COLUMN_TEXT, NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0); +} + +static void +setup_options (void) +{ + MatePanelAppletsManager *manager; + GList *applet_list, *l; + int i; + char *prefs_dir; + char *unique_key; + GtkListStore *model; + GtkTreeIter iter; + GtkCellRenderer *renderer; + + model = gtk_list_store_new (NUMBER_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_combo_box_set_model (GTK_COMBO_BOX (applet_combo), + GTK_TREE_MODEL (model)); + + manager = g_object_new (PANEL_TYPE_APPLETS_MANAGER_DBUS, NULL); + applet_list = MATE_PANEL_APPLETS_MANAGER_GET_CLASS (manager)->get_applets (manager); + for (l = applet_list, i = 1; l; l = g_list_next (l), i++) { + MatePanelAppletInfo *info = (MatePanelAppletInfo *)l->data; + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_TEXT, g_strdup (mate_panel_applet_info_get_name (info)), + COLUMN_ITEM, g_strdup (mate_panel_applet_info_get_iid (info)), + -1); + } + g_list_free (applet_list); + g_object_unref (manager); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (applet_combo), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (applet_combo), + renderer, "text", COLUMN_TEXT, NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (applet_combo), 0); + + setup_combo (size_combo, size_items, "Size", + G_N_ELEMENTS (size_items)); + setup_combo (orient_combo, orient_items, "Orientation", + G_N_ELEMENTS (orient_items)); + + unique_key = mateconf_unique_key (); + prefs_dir = g_strdup_printf ("/tmp/%s", unique_key); + g_free (unique_key); + gtk_entry_set_text (GTK_ENTRY (prefs_dir_entry), prefs_dir); + g_free (prefs_dir); +} + +int +main (int argc, char **argv) +{ + GtkBuilder *builder; + char *uifile; + char *applets_dir; + GError *error; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + error = NULL; + if (!gtk_init_with_args (&argc, &argv, + "", (GOptionEntry *) options, GETTEXT_PACKAGE, + &error)) { + if (error) { + g_printerr ("%s\n", error->message); + g_error_free (error); + } else + g_printerr ("Cannot initiliaze GTK+.\n"); + + return 1; + } + + panel_modules_ensure_loaded (); + + if (g_file_test ("../libmate-panel-applet", G_FILE_TEST_IS_DIR)) { + applets_dir = g_strdup_printf ("%s:../libmate-panel-applet", MATE_PANEL_APPLETS_DIR); + g_setenv ("MATE_PANEL_APPLETS_DIR", applets_dir, FALSE); + g_free (applets_dir); + } + + if (cli_iid) { + load_applet_from_command_line (); + gtk_main (); + panel_cleanup_do (); + + return 0; + } + + builder = gtk_builder_new (); + gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE); + + uifile = BUILDERDIR "/panel-test-applets.ui"; + gtk_builder_add_from_file (builder, uifile, &error); + + if (error) { + g_warning ("Error loading \"%s\": %s", uifile, error->message); + g_error_free (error); + panel_cleanup_do (); + + return 1; + } + + gtk_builder_connect_signals (builder, NULL); + + win = GTK_WIDGET (gtk_builder_get_object (builder, + "toplevel")); + applet_combo = GTK_WIDGET (gtk_builder_get_object (builder, + "applet-combo")); + prefs_dir_entry = GTK_WIDGET (gtk_builder_get_object (builder, + "prefs-dir-entry")); + orient_combo = GTK_WIDGET (gtk_builder_get_object (builder, + "orient-combo")); + size_combo = GTK_WIDGET (gtk_builder_get_object (builder, + "size-combo")); + g_object_unref (builder); + + setup_options (); + + gtk_widget_show (win); + + gtk_main (); + + panel_cleanup_do (); + + return 0; +} diff --git a/mate-panel/panel-test-applets.ui b/mate-panel/panel-test-applets.ui new file mode 100644 index 00000000..05916cf5 --- /dev/null +++ b/mate-panel/panel-test-applets.ui @@ -0,0 +1,203 @@ + + + + + + True + Test applet utility + False + dialog + False + + + + True + vertical + 8 + + + True + 2 + 5 + 2 + 4 + 4 + + + True + 1 + _Size: + True + center + size-combo + + + 4 + 5 + GTK_FILL + + + + + + True + 1 + _Applet: + True + center + applet-combo + + + GTK_FILL + + + + + + True + 1 + _Orientation: + True + center + orient-combo + + + 3 + 4 + GTK_FILL + + + + + + True + 1 + _Prefs Dir: + True + center + prefs-dir-entry + + + 2 + 3 + GTK_FILL + + + + + + True + True + + + 1 + 2 + 2 + 3 + + + + + + True + + + 1 + 2 + GTK_FILL + + + + + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + + + 2 + 1 + 2 + GTK_FILL + + + + + False + False + 1 + + + + + True + end + + + gtk-execute + True + True + True + False + True + + + + False + False + 0 + + + + + gtk-close + True + True + True + False + True + + + + False + False + 1 + + + + + False + False + end + 0 + + + + + + ok-button + button1 + + + diff --git a/mate-panel/panel-toplevel.c b/mate-panel/panel-toplevel.c new file mode 100644 index 00000000..043e2e26 --- /dev/null +++ b/mate-panel/panel-toplevel.c @@ -0,0 +1,5298 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * panel-toplevel.c: The panel's toplevel window object. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * Copyright (C) 2004 Rob Adams + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "panel-toplevel.h" + +#include +#include + +#include +#include +#include + +#include "panel-profile.h" +#include "panel-frame.h" +#include "panel-xutils.h" +#include "panel-multiscreen.h" +#include "panel-a11y.h" +#include "panel-typebuiltins.h" +#include "panel-marshal.h" +#include "panel-widget.h" +#include "panel-bindings.h" +#include "panel-struts.h" +#include "panel-config-global.h" +#include "panel-lockdown.h" + +G_DEFINE_TYPE (PanelToplevel, panel_toplevel, GTK_TYPE_WINDOW) + +#define PANEL_TOPLEVEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_TOPLEVEL, PanelToplevelPrivate)) + +#define DEFAULT_SIZE 48 +#define DEFAULT_AUTO_HIDE_SIZE 1 +#define DEFAULT_HIDE_DELAY 300 +#define DEFAULT_UNHIDE_DELAY 100 +#define DEFAULT_DND_THRESHOLD 8 +#define MINIMUM_WIDTH 100 +#define MAXIMUM_SIZE_SCREEN_RATIO 5 +#define SNAP_TOLERANCE_FACTOR 6 +#define DEFAULT_ARROW_SIZE 20 +#define HANDLE_SIZE 10 +#define N_ATTACH_TOPLEVEL_SIGNALS 5 +#define N_ATTACH_WIDGET_SIGNALS 5 + +typedef enum { + PANEL_GRAB_OP_NONE, + PANEL_GRAB_OP_MOVE, + PANEL_GRAB_OP_RESIZE, + PANEL_GRAB_OP_RESIZE_UP, + PANEL_GRAB_OP_RESIZE_DOWN, + PANEL_GRAB_OP_RESIZE_LEFT, + PANEL_GRAB_OP_RESIZE_RIGHT +} PanelGrabOpType; + +struct _PanelToplevelPrivate { + gboolean expand; + PanelOrientation orientation; + int size; + + /* relative to the monitor origin */ + int x; + int y; + /* relative to the bottom right corner, -1 to ignore and use x, y*/ + int x_right; + int y_bottom; + + int monitor; + /* this is used when the configured monitor is missing. We keep it so + * we can move the toplevel to the right monitor when it becomes + * available */ + int configured_monitor; + + int hide_delay; + int unhide_delay; + int auto_hide_size; + PanelAnimationSpeed animation_speed; + + int snap_tolerance; + GtkSettings *gtk_settings; + + PanelState state; + + char *name; + char *description; + + guint hide_timeout; + guint unhide_timeout; + + GdkRectangle geometry; + PanelFrameEdge edges; + + int original_width; + int original_height; + + PanelGrabOpType grab_op; + + /* The offset within the panel from which the panel + * drag was initiated relative to the screen origin. + */ + int drag_offset_x; + int drag_offset_y; + + /* Saved state before for cancelled grab op */ + int orig_monitor; + int orig_x; + int orig_y; + int orig_x_right; + int orig_y_bottom; + int orig_size; + int orig_orientation; + + /* relative to the monitor origin */ + int animation_end_x; + int animation_end_y; + int animation_end_width; + int animation_end_height; + GTimeVal animation_start_time; + GTimeVal animation_end_time; + guint animation_timeout; + + PanelWidget *panel_widget; + PanelFrame *inner_frame; + GtkWidget *table; + GtkWidget *hide_button_top; + GtkWidget *hide_button_bottom; + GtkWidget *hide_button_left; + GtkWidget *hide_button_right; + + PanelToplevel *attach_toplevel; + gulong attach_toplevel_signals [N_ATTACH_TOPLEVEL_SIGNALS]; + GtkWidget *attach_widget; + gulong attach_widget_signals [N_ATTACH_WIDGET_SIGNALS]; + gint n_autohide_disablers; + + guint auto_hide : 1; + guint animate : 1; + guint buttons_enabled : 1; + guint arrows_enabled : 1; + + /* The co-ordinates are relative to center screen */ + guint x_centered : 1; + guint y_centered : 1; + + /* The panel is not lined up with th screen edge */ + guint floating : 1; + + /* We are currently animating a hide/show */ + guint animating : 1; + + /* This is a keyboard initiated grab operation */ + guint grab_is_keyboard : 1; + + /* The x-y co-ordinates temporarily specify the panel center. + * This is used when the panel is rotating, because the width/height + * of the toplevel might change, so we need to compute new values for + * those. */ + guint position_centered : 1; + + /* The toplevel is "attached" to another widget */ + guint attached : 1; + + /* Hidden temporarily because the attach_toplevel was hidden */ + guint attach_hidden : 1; + + /* More saved grab op state */ + guint orig_x_centered : 1; + guint orig_y_centered : 1; + + /* flag to see if we have already done geometry updating, + if not then we're still loading and can ignore many things */ + guint updated_geometry_initial : 1; + /* flag to see if we have done the initial animation */ + guint initial_animation_done : 1; +}; + +enum { + HIDE_SIGNAL, + UNHIDE_SIGNAL, + POPUP_PANEL_MENU_SIGNAL, + TOGGLE_EXPAND_SIGNAL, + EXPAND_SIGNAL, + UNEXPAND_SIGNAL, + TOGGLE_HIDDEN_SIGNAL, + BEGIN_MOVE_SIGNAL, + BEGIN_RESIZE_SIGNAL, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_NAME, + PROP_EXPAND, + PROP_ORIENTATION, + PROP_SIZE, + PROP_X, + PROP_X_RIGHT, + PROP_X_CENTERED, + PROP_Y, + PROP_Y_BOTTOM, + PROP_Y_CENTERED, + PROP_MONITOR, + PROP_AUTOHIDE, + PROP_HIDE_DELAY, + PROP_UNHIDE_DELAY, + PROP_AUTOHIDE_SIZE, + PROP_ANIMATE, + PROP_ANIMATION_SPEED, + PROP_BUTTONS_ENABLED, + PROP_ARROWS_ENABLED +}; + +static guint toplevel_signals[LAST_SIGNAL] = {0}; +static GSList* toplevel_list = NULL; + +static void panel_toplevel_calculate_animation_end_geometry(PanelToplevel *toplevel); + +static void panel_toplevel_update_monitor(PanelToplevel* toplevel); +static void panel_toplevel_set_monitor_internal(PanelToplevel* toplevel, int monitor, gboolean force_resize); + + +GSList* panel_toplevel_list_toplevels(void) +{ + return toplevel_list; +} + +/* Is this the last un-attached toplevel? */ +gboolean panel_toplevel_is_last_unattached(PanelToplevel* toplevel) +{ + GSList* l; + + if (panel_toplevel_get_is_attached(toplevel)) + { + return FALSE; + } + + for (l = toplevel_list; l; l = l->next) + { + PanelToplevel* t = l->data; + + if (t != toplevel && !panel_toplevel_get_is_attached(t)) + { + return FALSE; + } + } + + return TRUE; +} + + +static GdkScreen* panel_toplevel_get_screen_geometry(PanelToplevel* toplevel, int* width, int* height) +{ + GdkScreen* screen; + + g_return_val_if_fail(PANEL_IS_TOPLEVEL (toplevel), NULL); + g_return_val_if_fail(width != NULL && height != NULL, NULL); + + screen = gtk_window_get_screen(GTK_WINDOW(toplevel)); + + *width = gdk_screen_get_width(screen); + *height = gdk_screen_get_height(screen); + + return screen; +} + +static GdkScreen* panel_toplevel_get_monitor_geometry(PanelToplevel* toplevel, int* x, int* y, int* width, int* height) +{ + GdkScreen* screen; + + g_return_val_if_fail(PANEL_IS_TOPLEVEL(toplevel), NULL); + g_return_val_if_fail(width != NULL && height != NULL, NULL); + + screen = gtk_window_get_screen(GTK_WINDOW(toplevel)); + + if (x) *x = panel_multiscreen_x(screen, toplevel->priv->monitor); + if (y) *y = panel_multiscreen_y(screen, toplevel->priv->monitor); + + if (width) + { + *width = panel_multiscreen_width(screen, toplevel->priv->monitor); + } + + if (height) + { + *height = panel_multiscreen_height(screen, toplevel->priv->monitor); + } + + return screen; +} + +static GdkCursorType panel_toplevel_grab_op_cursor(PanelToplevel* toplevel, PanelGrabOpType grab_op) +{ + GdkCursorType retval = -1; + + switch (grab_op) { + case PANEL_GRAB_OP_MOVE: + case PANEL_GRAB_OP_RESIZE: + if (toplevel->priv->grab_is_keyboard) + retval = GDK_CROSS; + else + retval = GDK_FLEUR; + break; + break; + case PANEL_GRAB_OP_RESIZE_UP: + retval = GDK_TOP_SIDE; + break; + case PANEL_GRAB_OP_RESIZE_DOWN: + retval = GDK_BOTTOM_SIDE; + break; + case PANEL_GRAB_OP_RESIZE_LEFT: + retval = GDK_LEFT_SIDE; + break; + case PANEL_GRAB_OP_RESIZE_RIGHT: + retval = GDK_RIGHT_SIDE; + break; + default: + g_assert_not_reached (); + break; + } + + return retval; +} + +static void panel_toplevel_init_resize_drag_offsets(PanelToplevel* toplevel, PanelGrabOpType grab_op) +{ + toplevel->priv->drag_offset_x = 0; + toplevel->priv->drag_offset_y = 0; + + switch (grab_op) { + case PANEL_GRAB_OP_RESIZE_DOWN: + toplevel->priv->drag_offset_y = toplevel->priv->geometry.y; + break; + case PANEL_GRAB_OP_RESIZE_UP: + toplevel->priv->drag_offset_y = + toplevel->priv->geometry.y + toplevel->priv->geometry.height; + break; + case PANEL_GRAB_OP_RESIZE_RIGHT: + toplevel->priv->drag_offset_x = toplevel->priv->geometry.x; + break; + case PANEL_GRAB_OP_RESIZE_LEFT: + toplevel->priv->drag_offset_x = + toplevel->priv->geometry.x + toplevel->priv->geometry.width; + break; + default: + g_assert_not_reached (); + break; + } +} + +static void panel_toplevel_warp_pointer(PanelToplevel* toplevel) +{ + GtkWidget *widget; + GdkRectangle geometry; + int x, y; + + widget = GTK_WIDGET (toplevel); + + geometry = toplevel->priv->geometry; + + x = y = 0; + + switch (toplevel->priv->grab_op) { + case PANEL_GRAB_OP_MOVE: + case PANEL_GRAB_OP_RESIZE: + x = (geometry.width / 2); + y = (geometry.height / 2); + break; + case PANEL_GRAB_OP_RESIZE_UP: + x = (geometry.width / 2); + break; + case PANEL_GRAB_OP_RESIZE_DOWN: + x = (geometry.width / 2); + y = geometry.height; + break; + case PANEL_GRAB_OP_RESIZE_LEFT: + y = (geometry.height / 2); + break; + case PANEL_GRAB_OP_RESIZE_RIGHT: + x = geometry.width; + y = (geometry.height / 2); + break; + default: + g_assert_not_reached (); + break; + } + + if (toplevel->priv->grab_op == PANEL_GRAB_OP_MOVE || + toplevel->priv->grab_op == PANEL_GRAB_OP_RESIZE) { + toplevel->priv->drag_offset_x = x; + toplevel->priv->drag_offset_y = y; + } else + panel_toplevel_init_resize_drag_offsets (toplevel, toplevel->priv->grab_op); + + panel_warp_pointer (gtk_widget_get_window (widget), x, y); +} + +static void panel_toplevel_begin_attached_move(PanelToplevel* toplevel, gboolean is_keyboard, guint32 time_) +{ + PanelWidget *attached_panel_widget; + + attached_panel_widget = panel_toplevel_get_panel_widget (toplevel->priv->attach_toplevel); + + panel_widget_applet_drag_start (attached_panel_widget, + toplevel->priv->attach_widget, + is_keyboard ? PW_DRAG_OFF_CENTER : PW_DRAG_OFF_CURSOR, + time_); +} + +static void panel_toplevel_begin_grab_op(PanelToplevel* toplevel, PanelGrabOpType op_type, gboolean grab_keyboard, guint32 time_) +{ + GtkWidget *widget; + GdkWindow *window; + GdkCursorType cursor_type; + GdkCursor *cursor; + + if (toplevel->priv->state != PANEL_STATE_NORMAL || + toplevel->priv->grab_op != PANEL_GRAB_OP_NONE) + return; + + if (panel_lockdown_get_locked_down ()) + return; + + /* If any of the position/orientation are not writable, + then we can't really move freely */ + if (op_type == PANEL_GRAB_OP_MOVE && + ! panel_profile_can_be_moved_freely (toplevel)) + return; + + /* If size is not writable, then we can't resize */ + if ((op_type == PANEL_GRAB_OP_RESIZE || + op_type == PANEL_GRAB_OP_RESIZE_UP || + op_type == PANEL_GRAB_OP_RESIZE_DOWN || + op_type == PANEL_GRAB_OP_RESIZE_LEFT || + op_type == PANEL_GRAB_OP_RESIZE_RIGHT) && + ! panel_profile_is_writable_toplevel_size (toplevel)) + return; + + if (toplevel->priv->attached && op_type == PANEL_GRAB_OP_MOVE) { + panel_toplevel_begin_attached_move (toplevel, grab_keyboard, time_); + return; + } + + widget = GTK_WIDGET (toplevel); + window = gtk_widget_get_window (widget); + + toplevel->priv->grab_op = op_type; + toplevel->priv->grab_is_keyboard = grab_keyboard; + + toplevel->priv->orig_monitor = toplevel->priv->monitor; + toplevel->priv->orig_x = toplevel->priv->x; + toplevel->priv->orig_x_right = toplevel->priv->x_right; + toplevel->priv->orig_x_centered = toplevel->priv->x_centered; + toplevel->priv->orig_y = toplevel->priv->y; + toplevel->priv->orig_y_bottom = toplevel->priv->y_bottom; + toplevel->priv->orig_y_centered = toplevel->priv->y_centered; + toplevel->priv->orig_size = toplevel->priv->size; + toplevel->priv->orig_orientation = toplevel->priv->orientation; + + gtk_grab_add (widget); + + if (toplevel->priv->grab_is_keyboard) + panel_toplevel_warp_pointer (toplevel); + + cursor_type = panel_toplevel_grab_op_cursor ( + toplevel, toplevel->priv->grab_op); + + cursor = gdk_cursor_new (cursor_type); + gdk_pointer_grab (window, FALSE, + GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, + NULL, cursor, time_); + gdk_cursor_unref (cursor); + + if (grab_keyboard) + gdk_keyboard_grab (window, FALSE, time_); +} + +static void panel_toplevel_end_grab_op (PanelToplevel* toplevel, guint32 time_) +{ + GtkWidget *widget; + + g_return_if_fail (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE); + + widget = GTK_WIDGET (toplevel); + + toplevel->priv->grab_op = PANEL_GRAB_OP_NONE; + toplevel->priv->grab_is_keyboard = FALSE; + + gtk_grab_remove (widget); + + gdk_pointer_ungrab (time_); + gdk_keyboard_ungrab (time_); +} + +static void panel_toplevel_cancel_grab_op(PanelToplevel* toplevel, guint32 time_) +{ + panel_toplevel_set_orientation (toplevel, toplevel->priv->orig_orientation); + panel_toplevel_set_monitor (toplevel, toplevel->priv->orig_monitor); + panel_toplevel_set_size (toplevel, toplevel->priv->orig_size); + panel_toplevel_set_x (toplevel, + toplevel->priv->orig_x, + toplevel->priv->orig_x_right, + toplevel->priv->orig_x_centered); + panel_toplevel_set_y (toplevel, + toplevel->priv->orig_y, + toplevel->priv->orig_y_bottom, + toplevel->priv->orig_y_centered); +} + +static void panel_toplevel_resize_to_pointer(PanelToplevel* toplevel, int x, int y) +{ + int new_size; + int new_x, new_y; + int new_x_right, new_y_bottom; + int new_x_centered, new_y_centered; + int monitor_width, monitor_height; + + new_size = toplevel->priv->size; + new_x = toplevel->priv->x; + new_y = toplevel->priv->y; + new_x_right = toplevel->priv->x_right; + new_y_bottom = toplevel->priv->y_bottom; + new_x_centered = toplevel->priv->x_centered; + new_y_centered = toplevel->priv->y_centered; + + panel_toplevel_get_monitor_geometry (toplevel, NULL, NULL, &monitor_width, &monitor_height); + + switch (toplevel->priv->grab_op) { + case PANEL_GRAB_OP_RESIZE_UP: + new_size = toplevel->priv->drag_offset_y - y; + new_size = CLAMP (new_size, 0, monitor_height / 4); + new_y -= (new_size - toplevel->priv->size); + if (!toplevel->priv->y_centered && (new_y + new_size / 2) > monitor_height / 2) + new_y_bottom = monitor_height - (new_y + new_size); + else + new_y_bottom = -1; + break; + case PANEL_GRAB_OP_RESIZE_DOWN: + new_size = y - toplevel->priv->drag_offset_y; + new_size = CLAMP (new_size, 0, monitor_height / 4); + if (!toplevel->priv->y_centered && (new_y + new_size / 2) > monitor_height / 2) + new_y_bottom = monitor_height - (new_y + new_size); + else + new_y_bottom = -1; + break; + case PANEL_GRAB_OP_RESIZE_LEFT: + new_size = toplevel->priv->drag_offset_x - x; + new_size = CLAMP (new_size, 0, monitor_width / 4); + new_x -= (new_size - toplevel->priv->size); + if (!toplevel->priv->x_centered && (new_x + new_size / 2) > monitor_width / 2) + new_x_right = monitor_width - (new_x + new_size); + else + new_x_right = -1; + break; + case PANEL_GRAB_OP_RESIZE_RIGHT: + new_size = x - toplevel->priv->drag_offset_x; + new_size = CLAMP (new_size, 0, monitor_width / 4); + if (!toplevel->priv->x_centered && (new_x + new_size / 2) > monitor_width / 2) + new_x_right = monitor_width - (new_x + new_size); + else + new_x_right = -1; + break; + default: + g_assert_not_reached (); + break; + } + + if (new_size == 0) + return; + + panel_toplevel_set_x (toplevel, new_x, new_x_right, new_x_centered); + panel_toplevel_set_y (toplevel, new_y, new_y_bottom, new_y_centered); + panel_toplevel_set_size (toplevel, new_size); +} + +/* this is called for expanded panels that are dragged around */ +static void panel_toplevel_calc_new_orientation(PanelToplevel* toplevel, int pointer_x, int pointer_y) +{ + PanelOrientation new_orientation; + GdkScreen *screen; + int hborder, vborder; + int monitor; + int monitor_width, monitor_height; + int new_x, new_y; + + screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + + monitor = panel_multiscreen_get_monitor_at_point (screen, pointer_x, pointer_y); + + if (toplevel->priv->geometry.height < toplevel->priv->geometry.width) + vborder = hborder = (3 * toplevel->priv->geometry.height) >> 1; + else + vborder = hborder = (3 * toplevel->priv->geometry.width) >> 1; + + new_x = pointer_x - panel_multiscreen_x (screen, monitor); + new_y = pointer_y - panel_multiscreen_y (screen, monitor); + monitor_width = panel_multiscreen_width (screen, monitor); + monitor_height = panel_multiscreen_height (screen, monitor); + + new_orientation = toplevel->priv->orientation; + + switch (toplevel->priv->orientation) { + case PANEL_ORIENTATION_TOP: + if (new_y > (monitor_height - hborder)) + new_orientation = PANEL_ORIENTATION_BOTTOM; + + else if (new_y > hborder) { + if (new_x > (monitor_width - vborder)) + new_orientation = PANEL_ORIENTATION_RIGHT; + else if (new_x < vborder) + new_orientation = PANEL_ORIENTATION_LEFT; + } + break; + case PANEL_ORIENTATION_BOTTOM: + if (new_y < hborder) + new_orientation = PANEL_ORIENTATION_TOP; + + else if (new_y < (monitor_height - hborder)) { + if (new_x > (monitor_width - vborder)) + new_orientation = PANEL_ORIENTATION_RIGHT; + else if (new_x < vborder) + new_orientation = PANEL_ORIENTATION_LEFT; + } + break; + case PANEL_ORIENTATION_LEFT: + if (new_x > (monitor_width - vborder)) + new_orientation = PANEL_ORIENTATION_RIGHT; + + else if (new_x > vborder) { + if (new_y > (monitor_height - hborder)) + new_orientation = PANEL_ORIENTATION_BOTTOM; + else if (new_y < hborder) + new_orientation = PANEL_ORIENTATION_TOP; + } + break; + case PANEL_ORIENTATION_RIGHT: + if (new_x < vborder) + new_orientation = PANEL_ORIENTATION_LEFT; + + else if (new_x < (monitor_width - vborder)) { + if (new_y > (monitor_height - hborder)) + new_orientation = PANEL_ORIENTATION_BOTTOM; + else if (new_y < hborder) + new_orientation = PANEL_ORIENTATION_TOP; + } + break; + default: + g_assert_not_reached (); + break; + } + + panel_toplevel_set_monitor (toplevel, monitor); + panel_toplevel_set_orientation (toplevel, new_orientation); +} + +static void panel_toplevel_move_to(PanelToplevel* toplevel, int new_x, int new_y) +{ + GdkScreen *screen; + PanelOrientation new_orientation; + gboolean x_centered, y_centered; + int screen_width, screen_height; + int monitor_width, monitor_height; + int width, height; + int new_monitor; + int x, y, x_right, y_bottom; + int snap_tolerance; + + screen = panel_toplevel_get_screen_geometry ( + toplevel, &screen_width, &screen_height); + + width = toplevel->priv->geometry.width; + height = toplevel->priv->geometry.height; + + snap_tolerance = toplevel->priv->snap_tolerance; + + new_x = CLAMP (new_x, 0, screen_width - width); + new_y = CLAMP (new_y, 0, screen_height - height); + + new_orientation = toplevel->priv->orientation; + + if (new_x <= snap_tolerance && + toplevel->priv->orientation & PANEL_VERTICAL_MASK) + new_orientation = PANEL_ORIENTATION_LEFT; + + else if ((new_x + width) >= (screen_width - snap_tolerance) && + toplevel->priv->orientation & PANEL_VERTICAL_MASK) + new_orientation = PANEL_ORIENTATION_RIGHT; + + if (new_y <= snap_tolerance && + toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + new_orientation = PANEL_ORIENTATION_TOP; + + else if ((new_y + height) >= (screen_height - snap_tolerance) && + toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + new_orientation = PANEL_ORIENTATION_BOTTOM; + + new_monitor = panel_multiscreen_get_monitor_at_point (screen, new_x, new_y); + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + x_centered = toplevel->priv->x_centered; + y_centered = toplevel->priv->y_centered; + + x = new_x - panel_multiscreen_x (screen, new_monitor); + y = new_y - panel_multiscreen_y (screen, new_monitor); + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) { + y_centered = FALSE; + if (new_y <= snap_tolerance || + new_y + height >= screen_height - snap_tolerance) + x_centered = abs (x - ((monitor_width - width) / 2)) + <= snap_tolerance; + else + x_centered = FALSE; + } else { + x_centered = FALSE; + if (new_x <= snap_tolerance || + new_x + width >= screen_width - snap_tolerance) + y_centered = abs (y - ((monitor_height - height) / 2)) + <= snap_tolerance; + else + y_centered = FALSE; + } + + if (x_centered) + x = (monitor_width - width) / 2; + if (y_centered) + y = (monitor_height - height) / 2; + + if (!x_centered && (x + width / 2) > monitor_width / 2) + x_right = monitor_width - (x + width); + else + x_right = -1; + + if (!y_centered && (y + height / 2) > monitor_height / 2) + y_bottom = monitor_height - (y + height); + else + y_bottom = -1; + + panel_toplevel_set_monitor (toplevel, new_monitor); + panel_toplevel_set_orientation (toplevel, new_orientation); + panel_toplevel_set_x (toplevel, x, x_right, x_centered); + panel_toplevel_set_y (toplevel, y, y_bottom, y_centered); +} + +static void panel_toplevel_move_to_pointer(PanelToplevel* toplevel, int pointer_x, int pointer_y) +{ + int new_x, new_y; + + new_x = pointer_x - toplevel->priv->drag_offset_x; + new_y = pointer_y - toplevel->priv->drag_offset_y; + + panel_toplevel_move_to (toplevel, new_x, new_y); +} + +static void panel_toplevel_rotate_to_pointer(PanelToplevel* toplevel, int pointer_x, int pointer_y) +{ + int x_diff, y_diff; + int x, y; + int snap_tolerance; + + x = toplevel->priv->geometry.x; + y = toplevel->priv->geometry.y; + snap_tolerance = toplevel->priv->snap_tolerance; + + x_diff = pointer_x - (x + toplevel->priv->geometry.width / 2); + y_diff = pointer_y - (y + toplevel->priv->geometry.height / 2); + + if (((-y_diff > x_diff + snap_tolerance) && x_diff > 0 && y_diff < 0) || + (( y_diff < x_diff + snap_tolerance) && x_diff < 0 && y_diff < 0)) + panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_RIGHT); + + else if (((-x_diff < y_diff - snap_tolerance) && x_diff > 0 && y_diff < 0) || + (( x_diff > y_diff - snap_tolerance) && x_diff > 0 && y_diff > 0)) + panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_BOTTOM); + + else if ((( y_diff > x_diff + snap_tolerance) && x_diff > 0 && y_diff > 0) || + ((-y_diff < x_diff + snap_tolerance) && x_diff < 0 && y_diff > 0)) + panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_LEFT); + + else if (((-x_diff > y_diff - snap_tolerance) && x_diff < 0 && y_diff > 0) || + (( x_diff < y_diff - snap_tolerance) && x_diff < 0 && y_diff < 0)) + panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_TOP); +} + +static gboolean panel_toplevel_warp_pointer_increment(PanelToplevel* toplevel, int keyval, int increment) +{ + GdkScreen *screen; + GdkWindow *root_window; + int new_x, new_y; + + screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + root_window = gdk_screen_get_root_window (screen); + + gdk_window_get_pointer (root_window, &new_x, &new_y, NULL); + + switch (keyval) { + case GDK_Up: + case GDK_KP_Up: + new_y -= increment; + break; + case GDK_Left: + case GDK_KP_Left: + new_x -= increment; + break; + case GDK_Down: + case GDK_KP_Down: + new_y += increment; + break; + case GDK_Right: + case GDK_KP_Right: + new_x += increment; + break; + default: + g_assert_not_reached (); + return FALSE; + } + + panel_warp_pointer (root_window, new_x, new_y); + + return TRUE; +} + +static gboolean panel_toplevel_move_keyboard_floating(PanelToplevel* toplevel, GdkEventKey* event) +{ +#define SMALL_INCREMENT 1 +#define NORMAL_INCREMENT 10 + + int increment = NORMAL_INCREMENT; + + if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_SHIFT_MASK) + increment = SMALL_INCREMENT; + + return panel_toplevel_warp_pointer_increment ( + toplevel, event->keyval, increment); + +#undef SMALL_INCREMENT +#undef NORMAL_INCREMENT +} + +static gboolean panel_toplevel_move_keyboard_expanded(PanelToplevel* toplevel, GdkEventKey* event) +{ + PanelOrientation new_orientation; + + switch (event->keyval) { + case GDK_Up: + case GDK_KP_Up: + new_orientation = PANEL_ORIENTATION_TOP; + break; + case GDK_Left: + case GDK_KP_Left: + new_orientation = PANEL_ORIENTATION_LEFT; + break; + case GDK_Down: + case GDK_KP_Down: + new_orientation = PANEL_ORIENTATION_BOTTOM; + break; + case GDK_Right: + case GDK_KP_Right: + new_orientation = PANEL_ORIENTATION_RIGHT; + break; + default: + g_assert_not_reached (); + return FALSE; + } + + panel_toplevel_set_orientation (toplevel, new_orientation); + + return TRUE; +} + +static gboolean panel_toplevel_initial_resize_keypress(PanelToplevel* toplevel, GdkEventKey* event) +{ + PanelGrabOpType grab_op; + + switch (event->keyval) { + case GDK_Up: + case GDK_KP_Up: + if (!(toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)) + return FALSE; + grab_op = PANEL_GRAB_OP_RESIZE_UP; + break; + case GDK_Left: + case GDK_KP_Left: + if (!(toplevel->priv->orientation & PANEL_VERTICAL_MASK)) + return FALSE; + grab_op = PANEL_GRAB_OP_RESIZE_LEFT; + break; + case GDK_Down: + case GDK_KP_Down: + if (!(toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)) + return FALSE; + grab_op = PANEL_GRAB_OP_RESIZE_DOWN; + break; + case GDK_Right: + case GDK_KP_Right: + if (!(toplevel->priv->orientation & PANEL_VERTICAL_MASK)) + return FALSE; + grab_op = PANEL_GRAB_OP_RESIZE_RIGHT; + break; + default: + g_assert_not_reached (); + return FALSE; + } + + panel_toplevel_end_grab_op (toplevel, event->time); + panel_toplevel_begin_grab_op (toplevel, grab_op, TRUE, event->time); + + return TRUE; +} + +static gboolean panel_toplevel_handle_grab_op_key_event(PanelToplevel* toplevel, GdkEventKey* event) +{ + gboolean retval = FALSE; + + switch (event->keyval) { + case GDK_Up: + case GDK_KP_Up: + case GDK_Left: + case GDK_KP_Left: + case GDK_Down: + case GDK_KP_Down: + case GDK_Right: + case GDK_KP_Right: + switch (toplevel->priv->grab_op) { + case PANEL_GRAB_OP_MOVE: + if (toplevel->priv->expand) + retval = panel_toplevel_move_keyboard_expanded ( + toplevel, event); + else + retval = panel_toplevel_move_keyboard_floating ( + toplevel, event); + break; + case PANEL_GRAB_OP_RESIZE: + retval = panel_toplevel_initial_resize_keypress (toplevel, event); + break; + case PANEL_GRAB_OP_RESIZE_UP: + case PANEL_GRAB_OP_RESIZE_DOWN: + case PANEL_GRAB_OP_RESIZE_LEFT: + case PANEL_GRAB_OP_RESIZE_RIGHT: + retval = panel_toplevel_warp_pointer_increment ( + toplevel, event->keyval, 1); + break; + default: + g_assert_not_reached (); + break; + } + break; + case GDK_Escape: + panel_toplevel_cancel_grab_op (toplevel, event->time); + case GDK_Return: /* drop through*/ + case GDK_KP_Enter: + case GDK_space: + case GDK_KP_Space: + panel_toplevel_end_grab_op (toplevel, event->time); + retval = TRUE; + default: /* drop through*/ + break; + } + + return retval; +} + +static gboolean panel_toplevel_handle_grab_op_motion_event(PanelToplevel* toplevel, GdkEventMotion* event) +{ + switch (toplevel->priv->grab_op) { + case PANEL_GRAB_OP_MOVE: + if (toplevel->priv->expand) + panel_toplevel_calc_new_orientation ( + toplevel, event->x_root, event->y_root); + + else if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK) + panel_toplevel_rotate_to_pointer ( + toplevel, event->x_root, event->y_root); + + else + panel_toplevel_move_to_pointer ( + toplevel, event->x_root, event->y_root); + return TRUE; + case PANEL_GRAB_OP_RESIZE_UP: + case PANEL_GRAB_OP_RESIZE_DOWN: + case PANEL_GRAB_OP_RESIZE_LEFT: + case PANEL_GRAB_OP_RESIZE_RIGHT: + panel_toplevel_resize_to_pointer (toplevel, event->x_root, event->y_root); + return TRUE; + default: + break; + } + + return FALSE; +} + +static void panel_toplevel_calc_floating(PanelToplevel* toplevel) +{ + int screen_width, screen_height; + int monitor_x, monitor_y; + int monitor_width, monitor_height; + int x, y; + int snap_tolerance; + + if (toplevel->priv->expand) { + toplevel->priv->floating = FALSE; + return; + } + + panel_toplevel_get_screen_geometry (toplevel, + &screen_width, &screen_height); + panel_toplevel_get_monitor_geometry (toplevel, &monitor_x, &monitor_y, + &monitor_width, &monitor_height); + + if (toplevel->priv->x_right == -1) + x = monitor_x + toplevel->priv->x; + else + x = monitor_x + (monitor_width - (toplevel->priv->x_right + toplevel->priv->geometry.width)); + if (toplevel->priv->y_bottom == -1) + y = monitor_y + toplevel->priv->y; + else + y = monitor_y + (monitor_height - (toplevel->priv->y_bottom + toplevel->priv->geometry.height)); + + snap_tolerance = toplevel->priv->snap_tolerance; + + //FIXME? everywhere else, snap_tolerance is relative to the monitor, + //not the screen + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + toplevel->priv->floating = + (y > snap_tolerance) && (y < (screen_height - toplevel->priv->geometry.height - snap_tolerance)); + else + toplevel->priv->floating = + (x > snap_tolerance) && (x < (screen_width - toplevel->priv->geometry.width - snap_tolerance)); +} + +void panel_toplevel_push_autohide_disabler(PanelToplevel* toplevel) +{ + g_return_if_fail (toplevel != NULL); + + if (!toplevel->priv->n_autohide_disablers++) + panel_toplevel_queue_auto_hide (toplevel); +} + +void panel_toplevel_pop_autohide_disabler(PanelToplevel* toplevel) +{ + g_return_if_fail (toplevel != NULL); + g_return_if_fail (toplevel->priv->n_autohide_disablers > 0); + + if (!--toplevel->priv->n_autohide_disablers) + panel_toplevel_queue_auto_hide (toplevel); +} + +static gboolean panel_toplevel_get_autohide_disabled(PanelToplevel* toplevel) +{ + return toplevel->priv->n_autohide_disablers > 0 ? TRUE : FALSE; +} + +static gboolean panel_toplevel_hide_button_event(PanelToplevel* toplevel, GdkEventButton* event, GtkButton* button) +{ + if (event->button == 1) + return FALSE; + + return gtk_widget_event (GTK_WIDGET (toplevel), (GdkEvent *) event); +} + +static void panel_toplevel_hide_button_clicked(PanelToplevel* toplevel, GtkButton* button) +{ + GtkArrowType arrow_type; + gboolean ltr; + + if (toplevel->priv->animating || + toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) + return; + + ltr = gtk_widget_get_direction (GTK_WIDGET (toplevel)) == GTK_TEXT_DIR_LTR; + arrow_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "arrow-type")); + + if (toplevel->priv->state == PANEL_STATE_NORMAL) { + GtkDirectionType direction = -1; + + switch (arrow_type) { + case GTK_ARROW_UP: + direction = GTK_DIR_UP; + break; + case GTK_ARROW_DOWN: + direction = GTK_DIR_DOWN; + break; + case GTK_ARROW_LEFT: + direction = ltr ? GTK_DIR_LEFT : GTK_DIR_RIGHT; + break; + case GTK_ARROW_RIGHT: + direction = ltr ? GTK_DIR_RIGHT : GTK_DIR_LEFT; + break; + default: + g_assert_not_reached (); + break; + } + + panel_toplevel_hide (toplevel, FALSE, direction); + } else + panel_toplevel_unhide (toplevel); +} + +static GtkWidget * +panel_toplevel_add_hide_button (PanelToplevel *toplevel, + GtkArrowType arrow_type, + int left_attach, + int right_attach, + int top_attach, + int bottom_attach) +{ + GtkWidget *button; + AtkObject *obj; + GtkWidget *arrow; + int arrow_size; + + button = gtk_button_new (); + obj = gtk_widget_get_accessible (button); + atk_object_set_name (obj, _("Hide Panel")); + gtk_widget_set_can_default (button, FALSE); + + gtk_widget_style_get (GTK_WIDGET (toplevel), + "arrow-size", &arrow_size, + NULL); + + switch (arrow_type) { + case GTK_ARROW_UP: + gtk_widget_set_size_request (button, -1, arrow_size); + break; + case GTK_ARROW_DOWN: + gtk_widget_set_size_request (button, -1, arrow_size); + break; + case GTK_ARROW_LEFT: + gtk_widget_set_size_request (button, arrow_size, -1); + break; + case GTK_ARROW_RIGHT: + gtk_widget_set_size_request (button, arrow_size, -1); + break; + default: + g_assert_not_reached (); + break; + } + + arrow = gtk_arrow_new (arrow_type, GTK_SHADOW_NONE); + gtk_misc_set_padding (GTK_MISC (arrow), 0, 0); + gtk_container_add (GTK_CONTAINER (button), arrow); + gtk_widget_show (arrow); + + g_object_set_data (G_OBJECT (button), + "arrow-type", + GINT_TO_POINTER (arrow_type)); + + g_signal_connect_swapped (button, "clicked", + G_CALLBACK (panel_toplevel_hide_button_clicked), toplevel); + g_signal_connect_swapped (button, "button_press_event", + G_CALLBACK (panel_toplevel_hide_button_event), toplevel); + g_signal_connect_swapped (button, "button_release_event", + G_CALLBACK (panel_toplevel_hide_button_event), toplevel); + + gtk_table_attach (GTK_TABLE (toplevel->priv->table), + button, + left_attach, + right_attach, + top_attach, + bottom_attach, + GTK_FILL, + GTK_FILL, + 0, + 0); + + return button; +} + +static void panel_toplevel_update_buttons_showing(PanelToplevel* toplevel) +{ + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) { + gtk_widget_hide (toplevel->priv->hide_button_top); + gtk_widget_hide (toplevel->priv->hide_button_bottom); + gtk_widget_show (toplevel->priv->hide_button_left); + gtk_widget_show (toplevel->priv->hide_button_right); + } else { + gtk_widget_show (toplevel->priv->hide_button_top); + gtk_widget_show (toplevel->priv->hide_button_bottom); + gtk_widget_hide (toplevel->priv->hide_button_left); + gtk_widget_hide (toplevel->priv->hide_button_right); + } + + if (toplevel->priv->attached) { + switch (panel_toplevel_get_orientation (toplevel->priv->attach_toplevel)) { + case PANEL_ORIENTATION_TOP: + gtk_widget_hide (toplevel->priv->hide_button_top); + break; + case PANEL_ORIENTATION_BOTTOM: + gtk_widget_hide (toplevel->priv->hide_button_bottom); + break; + case PANEL_ORIENTATION_LEFT: + gtk_widget_hide (toplevel->priv->hide_button_left); + break; + case PANEL_ORIENTATION_RIGHT: + gtk_widget_hide (toplevel->priv->hide_button_right); + break; + default: + g_assert_not_reached (); + break; + } + } +} + +static void panel_toplevel_update_hide_buttons(PanelToplevel* toplevel) +{ + if (toplevel->priv->buttons_enabled) + panel_toplevel_update_buttons_showing (toplevel); + else { + g_object_set ( + G_OBJECT (toplevel->priv->hide_button_top), + "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_DOWN, + NULL); + g_object_set ( + G_OBJECT (toplevel->priv->hide_button_bottom), + "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_UP, + NULL); + g_object_set ( + G_OBJECT (toplevel->priv->hide_button_left), + "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_RIGHT, + NULL); + g_object_set ( + G_OBJECT (toplevel->priv->hide_button_right), + "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_LEFT, + NULL); + } + + if (toplevel->priv->arrows_enabled) { + int arrow_size; + + gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_top))); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_bottom))); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_left))); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_right))); + + gtk_widget_style_get (GTK_WIDGET (toplevel), + "arrow-size", &arrow_size, + NULL); + + gtk_widget_set_size_request (toplevel->priv->hide_button_top, + -1, arrow_size); + gtk_widget_set_size_request (toplevel->priv->hide_button_bottom, + -1, arrow_size); + gtk_widget_set_size_request (toplevel->priv->hide_button_left, + arrow_size, -1); + gtk_widget_set_size_request (toplevel->priv->hide_button_right, + arrow_size, -1); + } else { + gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_top))); + gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_bottom))); + gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_left))); + gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_right))); + + gtk_widget_set_size_request (toplevel->priv->hide_button_top, -1, -1); + gtk_widget_set_size_request (toplevel->priv->hide_button_bottom, -1, -1); + gtk_widget_set_size_request (toplevel->priv->hide_button_left, -1, -1); + gtk_widget_set_size_request (toplevel->priv->hide_button_right, -1, -1); + } +} + +static gboolean panel_toplevel_contains_pointer(PanelToplevel* toplevel) +{ + GdkDisplay *display; + GdkScreen *screen; + GtkWidget *widget; + int x, y; + + display = gdk_display_get_default (); + widget = GTK_WIDGET (toplevel); + + if (!gtk_widget_get_realized (widget)) + return FALSE; + + screen = NULL; + x = y = -1; + gdk_display_get_pointer (display, &screen, &x, &y, NULL); + + if (screen != gtk_window_get_screen (GTK_WINDOW (toplevel))) + return FALSE; + + if (x == -1 || y == -1) + return FALSE; + + if (x < toplevel->priv->geometry.x || x >= (toplevel->priv->geometry.x + toplevel->priv->geometry.width) || + y < toplevel->priv->geometry.y || y >= (toplevel->priv->geometry.y + toplevel->priv->geometry.height)) + return FALSE; + + return TRUE; +} + +static inline int panel_toplevel_get_effective_auto_hide_size(PanelToplevel* toplevel) +{ + int size; + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + size = CLAMP (toplevel->priv->auto_hide_size, + 1, toplevel->priv->original_height / 2); + else + size = CLAMP (toplevel->priv->auto_hide_size, + 1, toplevel->priv->original_width / 2); + + /* paranoia */ + return (size <= 0) ? DEFAULT_AUTO_HIDE_SIZE : size; +} + +static gboolean panel_toplevel_update_struts(PanelToplevel* toplevel, gboolean end_of_animation) +{ + PanelOrientation orientation; + GdkScreen *screen; + gboolean geometry_changed = FALSE; + int strut, strut_start, strut_end; + int x, y, width, height; + int monitor_x, monitor_y; + int monitor_width, monitor_height; + + if (!toplevel->priv->updated_geometry_initial) + return FALSE; + + if (toplevel->priv->attached) { + panel_struts_unregister_strut (toplevel); + panel_struts_set_window_hint (toplevel); + return FALSE; + } + + /* In the case of the initial animation, we really want the struts to + * represent what is at the end of the animation, to avoid desktop + * icons jumping around. */ + if (!toplevel->priv->initial_animation_done) { + end_of_animation = TRUE; + + /* We've not started the animation yet, so we have to compute + * where we want to end. Note that we don't want to compute + * this everytime, since the struts conflict resolution will be + * overridden if we do so */ + if (!toplevel->priv->animating) + panel_toplevel_calculate_animation_end_geometry (toplevel); + } + + screen = panel_toplevel_get_monitor_geometry (toplevel, + &monitor_x, + &monitor_y, + &monitor_width, + &monitor_height); + + if (end_of_animation) { + x = toplevel->priv->animation_end_x; + y = toplevel->priv->animation_end_y; + x += panel_multiscreen_x (screen, toplevel->priv->monitor); + y += panel_multiscreen_y (screen, toplevel->priv->monitor); + if (toplevel->priv->animation_end_width != -1) + width = toplevel->priv->animation_end_width; + else + width = toplevel->priv->geometry.width; + if (toplevel->priv->animation_end_height != -1) + height = toplevel->priv->animation_end_height; + else + height = toplevel->priv->geometry.height; + } else { + x = toplevel->priv->geometry.x; + y = toplevel->priv->geometry.y; + width = toplevel->priv->geometry.width; + height = toplevel->priv->geometry.height; + } + + orientation = toplevel->priv->orientation; + + strut = strut_start = strut_end = 0; + + if (orientation & PANEL_HORIZONTAL_MASK) { + if (y <= monitor_y) { + orientation = PANEL_ORIENTATION_TOP; + strut = y + height - monitor_y; + } else if (y >= monitor_y + monitor_height - height) { + orientation = PANEL_ORIENTATION_BOTTOM; + strut = monitor_y + monitor_height - y; + } + + if (strut > 0) { + strut_start = MAX (x, monitor_x); + strut_end = MIN (x + width, monitor_x + monitor_width) - 1; + } + } else { + if (x <= monitor_x) { + orientation = PANEL_ORIENTATION_LEFT; + strut = x + width - monitor_x; + } else if (x >= monitor_x + monitor_width - width) { + orientation = PANEL_ORIENTATION_RIGHT; + strut = monitor_x + monitor_width - x; + } + + if (strut > 0) { + strut_start = MAX (y, monitor_y); + strut_end = MIN (y + height, monitor_y + monitor_height) - 1; + } + } + + if (orientation != toplevel->priv->orientation) { + toplevel->priv->orientation = orientation; + g_object_notify (G_OBJECT (toplevel), "orientation"); + } + + if (toplevel->priv->auto_hide && strut > 0) + strut = panel_toplevel_get_effective_auto_hide_size (toplevel); + + if (strut > 0) + geometry_changed = panel_struts_register_strut (toplevel, + screen, + toplevel->priv->monitor, + orientation, + strut, + strut_start, + strut_end); + else + panel_struts_unregister_strut (toplevel); + + if (toplevel->priv->state == PANEL_STATE_NORMAL || + toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN || + toplevel->priv->animating) + panel_struts_set_window_hint (toplevel); + else + panel_struts_unset_window_hint (toplevel); + + return geometry_changed; +} + +void panel_toplevel_update_edges(PanelToplevel* toplevel) +{ + GtkWidget *widget; + PanelFrameEdge edges; + PanelFrameEdge inner_edges; + PanelFrameEdge outer_edges; + PanelBackground *background; + int monitor_width, monitor_height; + int width, height; + gboolean inner_frame = FALSE; + + widget = GTK_WIDGET (toplevel); + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + width = toplevel->priv->geometry.width; + height = toplevel->priv->geometry.height; + + edges = PANEL_EDGE_NONE; + + background = &toplevel->priv->panel_widget->background; + + /* We don't want any bevels with a color/image background */ + if (panel_background_effective_type (background) == PANEL_BACK_NONE) { + if (toplevel->priv->geometry.y > 0) + edges |= PANEL_EDGE_TOP; + + if (toplevel->priv->geometry.x > 0) + edges |= PANEL_EDGE_LEFT; + + if (toplevel->priv->geometry.y < (monitor_height - height)) + edges |= PANEL_EDGE_BOTTOM; + + if (toplevel->priv->geometry.x < (monitor_width - width)) + edges |= PANEL_EDGE_RIGHT; + + /* There is a conflict in the position algorithm when a + * non-expanded centered panel is nearly the size of the + * screen. This is similar to the one we have in + * panel_toplevel_update_position(). A simple solution is + * to keep the bevels in this case. */ + if (!toplevel->priv->expand && + toplevel->priv->orientation & PANEL_HORIZONTAL_MASK && + toplevel->priv->x_centered) + edges |= PANEL_EDGE_LEFT | PANEL_EDGE_RIGHT; + + if (!toplevel->priv->expand && + toplevel->priv->orientation & PANEL_VERTICAL_MASK && + toplevel->priv->y_centered) + edges |= PANEL_EDGE_TOP | PANEL_EDGE_BOTTOM; + + if (gtk_widget_get_visible (toplevel->priv->hide_button_left) || + gtk_widget_get_visible (toplevel->priv->hide_button_right)) { + inner_frame = TRUE; + edges |= PANEL_EDGE_LEFT | PANEL_EDGE_RIGHT; + } + + if (gtk_widget_get_visible (toplevel->priv->hide_button_top) || + gtk_widget_get_visible (toplevel->priv->hide_button_bottom)) { + inner_frame = TRUE; + edges |= PANEL_EDGE_TOP | PANEL_EDGE_BOTTOM; + } + } + + if (!inner_frame) { + inner_edges = PANEL_EDGE_NONE; + outer_edges = edges; + } else { + inner_edges = edges; + outer_edges = PANEL_EDGE_NONE; + } + + panel_frame_set_edges (toplevel->priv->inner_frame, inner_edges); + + if (toplevel->priv->edges != outer_edges) { + toplevel->priv->edges = outer_edges; + gtk_widget_queue_resize (widget); + } +} + +static const char* panel_toplevel_construct_description(PanelToplevel *toplevel) +{ + int orientation, type; + + static const char *description[4][4] = { + { + /* translators: these string will be shown in MetaCity's switch window + * popup when you pass the focus to a panel */ + N_("Top Expanded Edge Panel"), + N_("Top Centered Panel"), + N_("Top Floating Panel"), + N_("Top Edge Panel"), + }, + + { + N_("Bottom Expanded Edge Panel"), + N_("Bottom Centered Panel"), + N_("Bottom Floating Panel"), + N_("Bottom Edge Panel"), + }, + + { + N_("Left Expanded Edge Panel"), + N_("Left Centered Panel"), + N_("Left Floating Panel"), + N_("Left Edge Panel"), + }, + + { + N_("Right Expanded Edge Panel"), + N_("Right Centered Panel"), + N_("Right Floating Panel"), + N_("Right Edge Panel"), + }, + }; + + if (toplevel->priv->attached) + return N_("Drawer"); + + switch (toplevel->priv->orientation) { + case PANEL_ORIENTATION_TOP: + orientation = 0; + break; + case PANEL_ORIENTATION_BOTTOM: + orientation = 1; + break; + case PANEL_ORIENTATION_LEFT: + orientation = 2; + break; + case PANEL_ORIENTATION_RIGHT: + orientation = 3; + break; + default: + orientation = 0; + g_assert_not_reached (); + break; + } + + if (toplevel->priv->expand) + type = 0; + else if (toplevel->priv->x_centered || + toplevel->priv->y_centered) + type = 1; + else if (toplevel->priv->floating) + type = 2; + else + type = 3; + + return description[orientation][type]; +} + +static void panel_toplevel_update_description(PanelToplevel* toplevel) +{ + const char *description; + + description = panel_toplevel_construct_description (toplevel); + + if (toplevel->priv->description && + !strcmp (toplevel->priv->description, description)) + return; + + if (toplevel->priv->description) + g_free (toplevel->priv->description); + toplevel->priv->description = g_strdup (_(description)); + + if (!toplevel->priv->name) + gtk_window_set_title (GTK_WINDOW (toplevel), + toplevel->priv->description); + + panel_a11y_set_atk_name_desc ( + GTK_WIDGET (toplevel->priv->panel_widget), + toplevel->priv->name ? toplevel->priv->name : + _(toplevel->priv->description), + _(toplevel->priv->description)); +} + +static void panel_toplevel_update_attached_position(PanelToplevel* toplevel, gboolean hidden, int* x, int* y, int* w, int* h) +{ + GtkAllocation attach_allocation; + PanelOrientation attach_orientation; + GdkRectangle toplevel_box; + GdkRectangle parent_box; + GdkRectangle attach_box; + int x_origin = 0, y_origin = 0; + int monitor_x, monitor_y; + int monitor_width, monitor_height; + + if (!gtk_widget_get_realized (GTK_WIDGET (toplevel->priv->attach_toplevel)) || + !gtk_widget_get_realized (toplevel->priv->attach_widget)) + return; + + gtk_widget_get_allocation (GTK_WIDGET (toplevel->priv->attach_widget), &attach_allocation); + + toplevel_box = toplevel->priv->geometry; + parent_box = toplevel->priv->attach_toplevel->priv->geometry; + attach_box = attach_allocation; + + if (attach_box.x != -1) { + gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (toplevel->priv->attach_widget)), + &x_origin, &y_origin); + + attach_box.x += x_origin; + attach_box.y += y_origin; + } else { + /* attach_widget isn't allocated. Put the toplevel + * off screen. + */ + attach_box.x = -toplevel_box.width; + attach_box.y = -toplevel_box.height; + } + + attach_orientation = panel_toplevel_get_orientation ( + toplevel->priv->attach_toplevel); + + if (attach_orientation & PANEL_HORIZONTAL_MASK) + *x = attach_box.x + attach_box.width / 2 - toplevel_box.width / 2; + else + *y = attach_box.y + attach_box.height / 2 - toplevel_box.height / 2; + + switch (attach_orientation) { + case PANEL_ORIENTATION_TOP: + *y = parent_box.y; + if (!hidden) + *y += parent_box.height; + else + *h = parent_box.height; + break; + case PANEL_ORIENTATION_BOTTOM: + *y = parent_box.y; + if (!hidden) + *y -= toplevel_box.height; + else + *h = parent_box.height; + break; + case PANEL_ORIENTATION_LEFT: + *x = parent_box.x; + if (!hidden) + *x += parent_box.width; + else + *w = parent_box.width; + break; + case PANEL_ORIENTATION_RIGHT: + *x = parent_box.x; + if (!hidden) + *x -= toplevel_box.width; + else + *w = parent_box.width; + break; + default: + g_assert_not_reached (); + break; + } + + panel_toplevel_get_monitor_geometry (toplevel, + &monitor_x, + &monitor_y, + &monitor_width, + &monitor_height); + + *x -= monitor_x; + *y -= monitor_y; + + if (toplevel->priv->orientation & PANEL_VERTICAL_MASK) + *x = CLAMP (*x, 0, monitor_width - toplevel->priv->original_width); + else + *y = CLAMP (*y, 0, monitor_height - toplevel->priv->original_height); +} + +static void panel_toplevel_update_normal_position(PanelToplevel* toplevel, int* x, int* y, int* w, int* h) +{ + int monitor_width, monitor_height; + int width, height; + int snap_tolerance; + + g_assert (x != NULL && y != NULL); + + if (toplevel->priv->attached) { + panel_toplevel_update_attached_position (toplevel, FALSE, x, y, w, h); + return; + } + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + width = toplevel->priv->original_width; + height = toplevel->priv->original_height; + snap_tolerance = toplevel->priv->snap_tolerance; + + *x = CLAMP (*x, 0, monitor_width - width); + *y = CLAMP (*y, 0, monitor_height - height); + + if (toplevel->priv->x <= snap_tolerance && + toplevel->priv->x_right == -1 && + !toplevel->priv->x_centered) + *x = 0; + else if (toplevel->priv->x_right != -1 && + toplevel->priv->x_right <= snap_tolerance && + !toplevel->priv->x_centered) + *x = monitor_width - width; + + if (toplevel->priv->y <= snap_tolerance && + toplevel->priv->y_bottom == -1 && + !toplevel->priv->y_centered) + *y = 0; + else if (toplevel->priv->y_bottom != -1 && + toplevel->priv->y_bottom <= snap_tolerance && + !toplevel->priv->y_centered) + *y = monitor_height - height; +} + +static void +panel_toplevel_update_auto_hide_position (PanelToplevel *toplevel, + int *x, + int *y, + int *w, + int *h, + gboolean for_end_position) +{ + int width, height; + int monitor_width, monitor_height; + int auto_hide_size; + int snap_tolerance; + + g_assert (x != NULL && y != NULL); + + if (toplevel->priv->floating) { + panel_toplevel_update_normal_position (toplevel, x, y, w, h); + return; + } + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + width = toplevel->priv->original_width; + height = toplevel->priv->original_height; + snap_tolerance = toplevel->priv->snap_tolerance; + + /* For the initial animation, we animate from outside the screen, and + * so we don't want the toplevel to be visible at all. But when the + * request is for the end position, then we give the real result (it's + * useful for struts) */ + if (for_end_position || toplevel->priv->initial_animation_done) { + auto_hide_size = panel_toplevel_get_effective_auto_hide_size (toplevel); + } else { + auto_hide_size = 0; + } + + switch (toplevel->priv->orientation) { + case PANEL_ORIENTATION_TOP: + *y = - (height - auto_hide_size); + break; + case PANEL_ORIENTATION_BOTTOM: + *y = monitor_height - auto_hide_size; + break; + case PANEL_ORIENTATION_LEFT: + *x = - (width - auto_hide_size); + break; + case PANEL_ORIENTATION_RIGHT: + *x = monitor_width - auto_hide_size; + break; + default: + g_assert_not_reached (); + break; + } + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) { + if (toplevel->priv->x <= snap_tolerance && + toplevel->priv->x_right == -1 && + !toplevel->priv->x_centered) + *x = 0; + else if (toplevel->priv->x_right != -1 && + toplevel->priv->x_right <= snap_tolerance && + !toplevel->priv->x_centered) + *x = monitor_width - width; + } else /* if (toplevel->priv->orientation & PANEL_VERTICAL_MASK) */ { + if (toplevel->priv->y <= snap_tolerance && + toplevel->priv->y_bottom == -1 && + !toplevel->priv->y_centered) + *y = 0; + else if (toplevel->priv->y_bottom != -1 && + toplevel->priv->y_bottom <= snap_tolerance && + !toplevel->priv->y_centered) + *y = monitor_height - height; + } +} + +/* FIXME: this is wrong for Xinerama. In the Xinerama case + * I think if hiding it requires it to go onto the + * next monitor then it should just move it on to + * the next monitor and set its state back to normal + */ +static void +panel_toplevel_update_hidden_position (PanelToplevel *toplevel, + int *x, + int *y, + int *w, + int *h) +{ + int width, height; + int min_hide_size; + int monitor_height, monitor_width; + GtkAllocation hide_allocation; + + g_assert (x != NULL && y != NULL); + + g_assert (toplevel->priv->state == PANEL_STATE_HIDDEN_UP || + toplevel->priv->state == PANEL_STATE_HIDDEN_DOWN || + toplevel->priv->state == PANEL_STATE_HIDDEN_LEFT || + toplevel->priv->state == PANEL_STATE_HIDDEN_RIGHT); + + if (toplevel->priv->attached) { + panel_toplevel_update_attached_position (toplevel, TRUE, x, y, w, h); + return; + } + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + width = toplevel->priv->original_width; + height = toplevel->priv->original_height; + + //FIXME should find a better default + min_hide_size = DEFAULT_AUTO_HIDE_SIZE; + + switch (toplevel->priv->state) { + case PANEL_STATE_HIDDEN_UP: + gtk_widget_get_allocation (toplevel->priv->hide_button_bottom, + &hide_allocation); + *y = - (height - MAX (hide_allocation.height, min_hide_size)); + break; + case PANEL_STATE_HIDDEN_DOWN: + gtk_widget_get_allocation (toplevel->priv->hide_button_top, + &hide_allocation); + *y = monitor_height - MAX (hide_allocation.height, min_hide_size); + break; + case PANEL_STATE_HIDDEN_LEFT: + gtk_widget_get_allocation (toplevel->priv->hide_button_right, + &hide_allocation); + *x = - (width - MAX (hide_allocation.width, min_hide_size)); + break; + case PANEL_STATE_HIDDEN_RIGHT: + gtk_widget_get_allocation (toplevel->priv->hide_button_left, + &hide_allocation); + *x = monitor_width - MAX (hide_allocation.width, min_hide_size); + break; + default: + g_assert_not_reached (); + break; + } +} + +/* + * This is "almost" like the double sine movement + * from the original panel except that it uses + * a cubic (twice again). I suppose it looks less + * mathematical now :) -- _v_ + */ +static int +get_delta (int src, + int dest, + GTimeVal *start_time, + GTimeVal *end_time, + GTimeVal *cur_time) +{ + double x, s, n, d, percentage; + + s = start_time->tv_sec + ((double)start_time->tv_usec / G_USEC_PER_SEC); + n = cur_time->tv_sec + ((double)cur_time->tv_usec / G_USEC_PER_SEC); + d = end_time->tv_sec + ((double)end_time->tv_usec / G_USEC_PER_SEC); + + n -= s; + d -= s; + + if (abs (dest - src) <= 1 || n >= d) + return dest - src; + + /* The cubic is: p(x) = (-2) x^2 (x-1.5) */ + /* running p(p(x)) to make it more "pronounced", + * effectively making it a ninth-degree polynomial */ + + x = (double)n/d; + x = -2 * (x*x) * (x-1.5); + /* run it again */ + percentage = -2 * (x*x) * (x-1.5); + + percentage = CLAMP (percentage, 0.0, 1.0); + + return ((dest - src) * percentage); +} + +static void +panel_toplevel_update_animating_position (PanelToplevel *toplevel) +{ + GdkScreen *screen; + GTimeVal time_val; + int deltax, deltay, deltaw = 0, deltah = 0; + int monitor_offset_x, monitor_offset_y; + + g_get_current_time (&time_val); + + screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + + monitor_offset_x = panel_multiscreen_x (screen, toplevel->priv->monitor); + monitor_offset_y = panel_multiscreen_y (screen, toplevel->priv->monitor); + + if (toplevel->priv->animation_end_width != -1) + deltaw = get_delta (toplevel->priv->geometry.width, + toplevel->priv->animation_end_width, + &toplevel->priv->animation_start_time, + &toplevel->priv->animation_end_time, + &time_val); + + if (toplevel->priv->animation_end_height != -1) + deltah = get_delta (toplevel->priv->geometry.height, + toplevel->priv->animation_end_height, + &toplevel->priv->animation_start_time, + &toplevel->priv->animation_end_time, + &time_val); + + deltax = get_delta (toplevel->priv->geometry.x - monitor_offset_x, + toplevel->priv->animation_end_x, + &toplevel->priv->animation_start_time, + &toplevel->priv->animation_end_time, + &time_val); + + deltay = get_delta (toplevel->priv->geometry.y - monitor_offset_y, + toplevel->priv->animation_end_y, + &toplevel->priv->animation_start_time, + &toplevel->priv->animation_end_time, + &time_val); + + if (deltaw != 0 && abs (deltaw) > abs (deltax)) + deltax = deltaw; + if (deltah != 0 && abs (deltah) > abs (deltay)) + deltay = deltah; + + toplevel->priv->geometry.x += deltax; + toplevel->priv->geometry.y += deltay; + + toplevel->priv->geometry.width += deltaw; + toplevel->priv->geometry.height += deltah; + + if (toplevel->priv->geometry.x - monitor_offset_x == toplevel->priv->animation_end_x && + toplevel->priv->geometry.y - monitor_offset_y == toplevel->priv->animation_end_y) { + toplevel->priv->animating = FALSE; + /* Note: it's important to set initial_animation_done to TRUE + * as soon as possible (hence, here) since we don't want to + * have a wrong value in a size request event */ + toplevel->priv->initial_animation_done = TRUE; + + if (toplevel->priv->attached && panel_toplevel_get_is_hidden (toplevel)) + gtk_widget_unmap (GTK_WIDGET (toplevel)); + else + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + if (toplevel->priv->state == PANEL_STATE_NORMAL) + g_signal_emit (toplevel, toplevel_signals [UNHIDE_SIGNAL], 0); + } +} + +static void +panel_toplevel_update_expanded_position (PanelToplevel *toplevel) +{ + GdkScreen *screen; + int monitor_width, monitor_height; + int screen_width, screen_height; + int monitor_x, monitor_y; + int x, y; + int x_right, y_bottom; + int monitor; + + if (!toplevel->priv->expand) + return; + + screen = panel_toplevel_get_screen_geometry (toplevel, + &screen_width, + &screen_height); + + panel_toplevel_get_monitor_geometry (toplevel, &monitor_x, &monitor_y, + &monitor_width, &monitor_height); + + x = -1; + y = -1; + x_right = -1; + y_bottom = -1; + + switch (toplevel->priv->orientation) { + case PANEL_ORIENTATION_TOP: + x = monitor_x; + y = monitor_y; + break; + case PANEL_ORIENTATION_LEFT: + x = monitor_x; + y = monitor_y; + break; + case PANEL_ORIENTATION_BOTTOM: + x = monitor_x; + y = monitor_y + monitor_height - toplevel->priv->geometry.height; + y_bottom = 0; + break; + case PANEL_ORIENTATION_RIGHT: + x = monitor_x + monitor_width - toplevel->priv->geometry.width; + y = monitor_y; + x_right = 0; + break; + default: + g_assert_not_reached (); + break; + } + + monitor = panel_multiscreen_get_monitor_at_point (screen, x, y); + + panel_toplevel_set_monitor_internal (toplevel, monitor, TRUE); + + x -= panel_multiscreen_x (screen, monitor); + y -= panel_multiscreen_y (screen, monitor); + + g_object_freeze_notify (G_OBJECT (toplevel)); + + if (toplevel->priv->x != x) { + toplevel->priv->x = x; + g_object_notify (G_OBJECT (toplevel), "x"); + } + + if (toplevel->priv->y != y) { + toplevel->priv->y = y; + g_object_notify (G_OBJECT (toplevel), "y"); + } + + if (toplevel->priv->x_right != x_right) { + toplevel->priv->x_right = x_right; + g_object_notify (G_OBJECT (toplevel), "x_right"); + } + + if (toplevel->priv->y_bottom != y_bottom) { + toplevel->priv->y_bottom = y_bottom; + g_object_notify (G_OBJECT (toplevel), "y_bottom"); + } + + g_object_thaw_notify (G_OBJECT (toplevel)); +} + +static void +panel_toplevel_update_position (PanelToplevel *toplevel) +{ + PanelBackground *background; + GdkScreen *screen; + int x, y; + int w, h; + int screen_width, screen_height; + int monitor_width, monitor_height; + + screen = panel_toplevel_get_screen_geometry ( + toplevel, &screen_width, &screen_height); + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + if (toplevel->priv->animating) { + panel_toplevel_update_animating_position (toplevel); + return; + } + + if (toplevel->priv->position_centered) { + toplevel->priv->position_centered = FALSE; + + g_object_freeze_notify (G_OBJECT (toplevel)); + + if (!toplevel->priv->x_centered) { + int x_right; + + toplevel->priv->x -= toplevel->priv->geometry.width / 2; + g_object_notify (G_OBJECT (toplevel), "x"); + + if ((toplevel->priv->x + toplevel->priv->geometry.width / 2) > monitor_width / 2) + x_right = monitor_width - (toplevel->priv->x + toplevel->priv->geometry.width); + else + x_right = -1; + if (toplevel->priv->x_right != x_right) { + toplevel->priv->x_right = x_right; + g_object_notify (G_OBJECT (toplevel), + "x-right"); + } + } + + if (!toplevel->priv->y_centered) { + int y_bottom; + + toplevel->priv->y -= toplevel->priv->geometry.height / 2; + g_object_notify (G_OBJECT (toplevel), "y"); + + if ((toplevel->priv->y + toplevel->priv->geometry.height / 2) > monitor_height / 2) + y_bottom = monitor_height - (toplevel->priv->y + toplevel->priv->geometry.height); + else + y_bottom = -1; + if (toplevel->priv->y_bottom != y_bottom) { + toplevel->priv->y_bottom = y_bottom; + g_object_notify (G_OBJECT (toplevel), + "y-bottom"); + } + } + + g_object_thaw_notify (G_OBJECT (toplevel)); + } + + panel_toplevel_update_expanded_position (toplevel); + panel_toplevel_calc_floating (toplevel); //FIXME should probably be done after panel_toplevel_update_normal_position() too + + if (toplevel->priv->x_right == -1) + x = toplevel->priv->x; + else + x = monitor_width - (toplevel->priv->x_right + toplevel->priv->geometry.width); + if (toplevel->priv->y_bottom == -1) + y = toplevel->priv->y; + else + y = monitor_height - (toplevel->priv->y_bottom + toplevel->priv->geometry.height); + + if (!toplevel->priv->expand) { + if (toplevel->priv->x_centered) + x = (monitor_width - toplevel->priv->geometry.width) / 2; + if (toplevel->priv->y_centered) + y = (monitor_height - toplevel->priv->geometry.height) / 2; + } + + w = h = -1; + + if (toplevel->priv->state == PANEL_STATE_NORMAL) + panel_toplevel_update_normal_position (toplevel, &x, &y, &w, &h); + + else if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) + panel_toplevel_update_auto_hide_position (toplevel, &x, &y, &w, &h, FALSE); + + else + panel_toplevel_update_hidden_position (toplevel, &x, &y, &w, &h); + + if (w != -1) + toplevel->priv->geometry.width = w; + if (h != -1) + toplevel->priv->geometry.height = h; + + /* This is some kind of snap: there's a possibility of an infinite loop + * because of the bevels of the frame that are set in + * panel_toplevel_update_edges(). The bevels change the width/height of + * the toplevel. The typical loop is: + * x = 1 => outer bevel => x = 0 => no outer bevel = > x = 1 => ... + * FIXME: maybe the real bug is that we enter into this loop (see bug + * #160748 to learn how to reproduce.) */ + background = &toplevel->priv->panel_widget->background; + /* There's no bevels with a color/image background */ + if (panel_background_effective_type (background) == PANEL_BACK_NONE) { + GtkStyle *style; + GdkRectangle *geometry; + int max_size; + + style = gtk_widget_get_style (GTK_WIDGET (toplevel->priv->inner_frame)); + geometry = &toplevel->priv->geometry; + + if (x <= style->xthickness && x > 0 && + !toplevel->priv->x_centered) + x = 0; + + if (y <= style->ythickness && y > 0 && + !toplevel->priv->y_centered) + y = 0; + + max_size = monitor_width - geometry->width - style->xthickness; + if (x + style->xthickness >= max_size && x < max_size && + !toplevel->priv->x_centered) + x = max_size; + + max_size = monitor_height - geometry->height - style->ythickness; + if (y + style->ythickness >= max_size && y < max_size && + !toplevel->priv->y_centered) + y = max_size; + } + + x += panel_multiscreen_x (screen, toplevel->priv->monitor); + y += panel_multiscreen_y (screen, toplevel->priv->monitor); + + toplevel->priv->geometry.x = x; + toplevel->priv->geometry.y = y; +} + +static int +calculate_minimum_height (GtkWidget *widget, + PanelOrientation orientation) +{ + GtkStyle *style; + PangoContext *context; + PangoFontMetrics *metrics; + int focus_width = 0; + int focus_pad = 0; + int ascent; + int descent; + int thickness; + + style = gtk_widget_get_style (widget); + context = gtk_widget_get_pango_context (widget); + metrics = pango_context_get_metrics (context, + style->font_desc, + pango_context_get_language (context)); + + ascent = pango_font_metrics_get_ascent (metrics); + descent = pango_font_metrics_get_descent (metrics); + + pango_font_metrics_unref (metrics); + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + thickness = orientation & PANEL_HORIZONTAL_MASK ? + style->ythickness : + style->xthickness; + + return PANGO_PIXELS (ascent + descent) + 2 * (focus_width + focus_pad + thickness); +} + +static int +panel_toplevel_update_size_from_hints (PanelToplevel *toplevel, + int requisition_size, + int monitor_size, + int non_panel_widget_size) +{ + int nb_size_hints; + AppletSizeHints *applets_hints; + AppletSizeHintsAlloc *using_hint; + + int i; + int total_size; + int full_hints; + + total_size = non_panel_widget_size + requisition_size; + + nb_size_hints = toplevel->priv->panel_widget->nb_applets_size_hints; + if (nb_size_hints <= 0) + return total_size; + + applets_hints = toplevel->priv->panel_widget->applets_hints; + using_hint = toplevel->priv->panel_widget->applets_using_hint; + + for (i = 0; i < nb_size_hints; i++) { + using_hint[i].index = applets_hints[i].len - 2; + using_hint[i].size = applets_hints[i].hints[applets_hints[i].len - 1]; + total_size += using_hint[i].size; + } + + if (total_size > monitor_size) + return monitor_size; + + full_hints = 0; + while (full_hints != nb_size_hints && total_size < monitor_size) { + int bonus; + int extra_bonus; + + bonus = (monitor_size - total_size) + / (nb_size_hints - full_hints); + extra_bonus = (monitor_size - total_size) + % (nb_size_hints - full_hints); + full_hints = 0; + + for (i = 0; i < nb_size_hints; i++) { + int new_size; + int current_bonus; + + current_bonus = bonus; + + while (using_hint[i].index > 0 && applets_hints[i].hints[using_hint[i].index - 1] < using_hint[i].size + current_bonus) { + new_size = applets_hints[i].hints[using_hint[i].index - 1]; + current_bonus = using_hint[i].size + + current_bonus - new_size; + total_size = total_size - using_hint[i].size + + new_size; + + using_hint[i].index -= 2; + using_hint[i].size = new_size; + } + + new_size = MIN (applets_hints[i].hints[using_hint[i].index], + using_hint[i].size + current_bonus); + if (new_size > using_hint[i].size) { + total_size += (new_size - using_hint[i].size); + using_hint[i].size = new_size; + } + + if (extra_bonus > 0) { + new_size = MIN (applets_hints[i].hints[using_hint[i].index], + using_hint[i].size + extra_bonus); + if (new_size > using_hint[i].size) { + total_size += (new_size + - using_hint[i].size); + extra_bonus -= (new_size + - using_hint[i].size); + using_hint[i].size = new_size; + } + } + + if (using_hint[i].size == applets_hints[i].hints[using_hint[i].index]) + full_hints++; + } + } + + return total_size; +} + +static void +panel_toplevel_update_size (PanelToplevel *toplevel, + GtkRequisition *requisition) +{ + GtkWidget *widget; + GtkStyle *style; + int monitor_width, monitor_height; + int width, height; + int minimum_height; + int non_panel_widget_size; + + if (toplevel->priv->animating) + return; + + widget = GTK_WIDGET (toplevel); + style = gtk_widget_get_style (widget); + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + width = requisition->width; + height = requisition->height; + + if (!toplevel->priv->expand && + !toplevel->priv->buttons_enabled && !toplevel->priv->attached) + non_panel_widget_size = 2 * HANDLE_SIZE; + else + non_panel_widget_size = 0; + + minimum_height = calculate_minimum_height (GTK_WIDGET (toplevel), + toplevel->priv->orientation); + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) { + + height = MAX (MIN (MAX (height, toplevel->priv->size), + panel_toplevel_get_maximum_size (toplevel)), + minimum_height); + + if (toplevel->priv->expand) + width = monitor_width; + else { + int max_width; + + if (!toplevel->priv->attached) + max_width = monitor_width; + else { + if (panel_toplevel_get_orientation (toplevel->priv->attach_toplevel) == PANEL_ORIENTATION_LEFT) + max_width = monitor_width + - toplevel->priv->geometry.x; + else + max_width = toplevel->priv->geometry.x + + toplevel->priv->geometry.width; + } + + width = panel_toplevel_update_size_from_hints ( + toplevel, + requisition->width, + max_width, + non_panel_widget_size); + } + + width = MAX (MINIMUM_WIDTH, width); + } else { + width = MAX (MIN (MAX (width, toplevel->priv->size), + panel_toplevel_get_maximum_size (toplevel)), + minimum_height); + + if (toplevel->priv->expand) + height = monitor_height; + else { + int max_height; + + if (!toplevel->priv->attached) + max_height = monitor_height; + else { + if (panel_toplevel_get_orientation (toplevel->priv->attach_toplevel) == PANEL_ORIENTATION_TOP) + max_height = monitor_height + - toplevel->priv->geometry.y; + else + max_height = toplevel->priv->geometry.y + + toplevel->priv->geometry.height; + } + + height = panel_toplevel_update_size_from_hints ( + toplevel, + requisition->height, + max_height, + non_panel_widget_size); + } + + height = MAX (MINIMUM_WIDTH, height); + } + + if (toplevel->priv->edges & PANEL_EDGE_TOP) + height += style->ythickness; + if (toplevel->priv->edges & PANEL_EDGE_BOTTOM) + height += style->ythickness; + if (toplevel->priv->edges & PANEL_EDGE_LEFT) + width += style->ythickness; + if (toplevel->priv->edges & PANEL_EDGE_RIGHT) + width += style->ythickness; + + toplevel->priv->geometry.width = CLAMP (width, 0, monitor_width); + toplevel->priv->geometry.height = CLAMP (height, 0, monitor_height); + toplevel->priv->original_width = toplevel->priv->geometry.width; + toplevel->priv->original_height = toplevel->priv->geometry.height; +} + +static void +panel_toplevel_update_geometry (PanelToplevel *toplevel, + GtkRequisition *requisition) +{ + toplevel->priv->updated_geometry_initial = TRUE; + panel_toplevel_update_size (toplevel, requisition); + panel_toplevel_update_position (toplevel); + + panel_toplevel_update_struts (toplevel, FALSE); + + if (toplevel->priv->state == PANEL_STATE_NORMAL || + toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) { + panel_struts_update_toplevel_geometry (toplevel, + &toplevel->priv->geometry.x, + &toplevel->priv->geometry.y, + &toplevel->priv->geometry.width, + &toplevel->priv->geometry.height); + } else { + panel_struts_update_toplevel_geometry (toplevel, + &toplevel->priv->geometry.x, + &toplevel->priv->geometry.y, + NULL, NULL); + } + + panel_toplevel_update_edges (toplevel); + panel_toplevel_update_description (toplevel); +} + +static void +panel_toplevel_attach_widget_destroyed (PanelToplevel *toplevel) +{ + panel_toplevel_detach (toplevel); +} + +static gboolean +panel_toplevel_attach_widget_configure (PanelToplevel *toplevel) +{ + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + return FALSE; +} + +static void +panel_toplevel_update_attach_orientation (PanelToplevel *toplevel) +{ + PanelOrientation attach_orientation; + PanelOrientation orientation; + + attach_orientation = + panel_toplevel_get_orientation (toplevel->priv->attach_toplevel); + + orientation = toplevel->priv->orientation; + + switch (attach_orientation) { + case PANEL_ORIENTATION_TOP: + orientation = PANEL_ORIENTATION_LEFT; + break; + case PANEL_ORIENTATION_BOTTOM: + orientation = PANEL_ORIENTATION_RIGHT; + break; + case PANEL_ORIENTATION_LEFT: + orientation = PANEL_ORIENTATION_TOP; + break; + case PANEL_ORIENTATION_RIGHT: + orientation = PANEL_ORIENTATION_BOTTOM; + break; + default: + g_assert_not_reached (); + break; + } + + panel_toplevel_set_orientation (toplevel, orientation); +} + +static void +panel_toplevel_attach_widget_parent_set (PanelToplevel *toplevel, + GtkWidget *previous_parent, + GtkWidget *attach_widget) +{ + GtkWidget *panel_widget; + + panel_widget = gtk_widget_get_parent (GTK_WIDGET (attach_widget)); + if (!panel_widget) + return; + + g_assert (PANEL_IS_WIDGET (panel_widget)); + + toplevel->priv->attach_toplevel = PANEL_WIDGET (panel_widget)->toplevel; + panel_toplevel_update_attach_orientation (toplevel); + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); +} + +static void +panel_toplevel_attach_toplevel_hiding (PanelToplevel *toplevel) +{ + if (!panel_toplevel_get_is_hidden (toplevel)) { + panel_toplevel_hide (toplevel, FALSE, -1); + + toplevel->priv->attach_hidden = TRUE; + } +} + +static void +panel_toplevel_attach_toplevel_unhiding (PanelToplevel *toplevel) +{ + if (!toplevel->priv->attach_hidden) + return; + + toplevel->priv->attach_hidden = FALSE; + + panel_toplevel_unhide (toplevel); +} + +static void +panel_toplevel_reverse_arrow (PanelToplevel *toplevel, + GtkWidget *button) +{ + GtkArrowType arrow_type; + + arrow_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "arrow-type")); + + switch (arrow_type) { + case GTK_ARROW_UP: + arrow_type = GTK_ARROW_DOWN; + break; + case GTK_ARROW_DOWN: + arrow_type = GTK_ARROW_UP; + break; + case GTK_ARROW_LEFT: + arrow_type = GTK_ARROW_RIGHT; + break; + case GTK_ARROW_RIGHT: + arrow_type = GTK_ARROW_LEFT; + break; + default: + g_assert_not_reached (); + break; + } + + g_object_set_data (G_OBJECT (button), "arrow-type", GINT_TO_POINTER (arrow_type)); + + gtk_arrow_set (GTK_ARROW (gtk_bin_get_child (GTK_BIN (button))), arrow_type, GTK_SHADOW_NONE); +} + +static void +panel_toplevel_reverse_arrows (PanelToplevel *toplevel) +{ + panel_toplevel_reverse_arrow (toplevel, toplevel->priv->hide_button_top); + panel_toplevel_reverse_arrow (toplevel, toplevel->priv->hide_button_bottom); + panel_toplevel_reverse_arrow (toplevel, toplevel->priv->hide_button_left); + panel_toplevel_reverse_arrow (toplevel, toplevel->priv->hide_button_right); +} + +static void +panel_toplevel_disconnect_attached (PanelToplevel *toplevel) +{ + int i; + + for (i = 0; i < N_ATTACH_TOPLEVEL_SIGNALS; i++) { + if (!toplevel->priv->attach_toplevel_signals [i]) + continue; + + g_signal_handler_disconnect ( + toplevel->priv->attach_toplevel, + toplevel->priv->attach_toplevel_signals [i]); + toplevel->priv->attach_toplevel_signals [i] = 0; + } + + for (i = 0; i < N_ATTACH_WIDGET_SIGNALS; i++) { + if (!toplevel->priv->attach_widget_signals [i]) + continue; + + g_signal_handler_disconnect ( + toplevel->priv->attach_widget, + toplevel->priv->attach_widget_signals [i]); + toplevel->priv->attach_widget_signals [i] = 0; + } +} + +static void +panel_toplevel_connect_attached (PanelToplevel *toplevel) +{ + gulong *signals; + int i = 0; + + signals = toplevel->priv->attach_toplevel_signals; + + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_toplevel, "destroy", + G_CALLBACK (panel_toplevel_attach_widget_destroyed), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_toplevel, "notify::orientation", + G_CALLBACK (panel_toplevel_update_attach_orientation), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_toplevel, "configure-event", + G_CALLBACK (panel_toplevel_attach_widget_configure), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_toplevel, "hiding", + G_CALLBACK (panel_toplevel_attach_toplevel_hiding), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_toplevel, "unhiding", + G_CALLBACK (panel_toplevel_attach_toplevel_unhiding), toplevel); + + g_assert (i == N_ATTACH_TOPLEVEL_SIGNALS); + + signals = toplevel->priv->attach_widget_signals; + i = 0; + + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_widget, "destroy", + G_CALLBACK (panel_toplevel_attach_widget_destroyed), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_widget, "configure-event", + G_CALLBACK (panel_toplevel_attach_widget_configure), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_widget, "parent-set", + G_CALLBACK (panel_toplevel_attach_widget_parent_set), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_widget, "show", + G_CALLBACK (gtk_widget_show), toplevel); + signals [i++] = g_signal_connect_swapped ( + toplevel->priv->attach_widget, "hide", + G_CALLBACK (gtk_widget_hide), toplevel); + + g_assert (i == N_ATTACH_WIDGET_SIGNALS); +} + +void +panel_toplevel_attach_to_widget (PanelToplevel *toplevel, + PanelToplevel *attach_toplevel, + GtkWidget *attach_widget) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + g_return_if_fail (PANEL_IS_TOPLEVEL (attach_toplevel)); + g_return_if_fail (GTK_IS_WIDGET (attach_widget)); + + if (toplevel->priv->attached) + panel_toplevel_disconnect_attached (toplevel); + + toplevel->priv->attached = TRUE; + + /* Cancelling the initial animation for drawers in + * panel_toplevel_initially_hide() is not enough, since this will + * happen only when the toplevel is realized, which might be too late + * for drawers (since it's realized when the drawer is clicked) */ + toplevel->priv->initial_animation_done = TRUE; + + toplevel->priv->attach_toplevel = attach_toplevel; + toplevel->priv->attach_widget = attach_widget; + + panel_toplevel_connect_attached (toplevel); + + panel_toplevel_reverse_arrows (toplevel); + panel_toplevel_set_expand (toplevel, FALSE); + panel_toplevel_update_attach_orientation (toplevel); + panel_toplevel_update_hide_buttons (toplevel); + + gtk_window_set_screen (GTK_WINDOW (toplevel), + gtk_widget_get_screen (GTK_WIDGET (attach_toplevel))); + panel_toplevel_set_monitor (toplevel, + panel_toplevel_get_monitor (attach_toplevel)); + if (toplevel->priv->state == PANEL_STATE_NORMAL) + panel_toplevel_push_autohide_disabler (toplevel->priv->attach_toplevel); + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); +} + +void +panel_toplevel_detach (PanelToplevel *toplevel) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (!toplevel->priv->attached) + return; + + if (toplevel->priv->state == PANEL_STATE_NORMAL) + panel_toplevel_pop_autohide_disabler (toplevel->priv->attach_toplevel); + + panel_toplevel_disconnect_attached (toplevel); + + panel_toplevel_reverse_arrows (toplevel); + + toplevel->priv->attached = FALSE; + + toplevel->priv->attach_toplevel = NULL; + toplevel->priv->attach_widget = NULL; + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); +} + +gboolean +panel_toplevel_get_is_attached (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->attached; +} + +PanelToplevel * +panel_toplevel_get_attach_toplevel (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL); + + return toplevel->priv->attach_toplevel; +} + +GtkWidget * +panel_toplevel_get_attach_widget (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL); + + return toplevel->priv->attach_widget; +} + +static gboolean +panel_toplevel_popup_panel_menu (PanelToplevel *toplevel) +{ + gboolean retval = FALSE; + + g_signal_emit_by_name (toplevel, "popup_menu", &retval); + + return retval; +} + +static gboolean +panel_toplevel_toggle_expand (PanelToplevel *toplevel) +{ + panel_toplevel_set_expand (toplevel, !toplevel->priv->expand); + + return TRUE; +} + +static gboolean +panel_toplevel_expand (PanelToplevel *toplevel) +{ + panel_toplevel_set_expand (toplevel, TRUE); + + return TRUE; +} + +static gboolean +panel_toplevel_unexpand (PanelToplevel *toplevel) +{ + panel_toplevel_set_expand (toplevel, FALSE); + + return TRUE; +} + +static gboolean +panel_toplevel_toggle_hidden (PanelToplevel *toplevel) +{ + if (toplevel->priv->state == PANEL_STATE_NORMAL) + panel_toplevel_hide (toplevel, toplevel->priv->auto_hide, -1); + else + panel_toplevel_unhide (toplevel); + + return FALSE; +} + +static gboolean +panel_toplevel_begin_move (PanelToplevel *toplevel) +{ + if (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE) + return FALSE; + + panel_toplevel_begin_grab_op ( + toplevel, PANEL_GRAB_OP_MOVE, TRUE, GDK_CURRENT_TIME); + + return TRUE; +} + +static gboolean +panel_toplevel_begin_resize (PanelToplevel *toplevel) +{ + if (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE) + return FALSE; + + panel_toplevel_begin_grab_op ( + toplevel, PANEL_GRAB_OP_RESIZE, TRUE, GDK_CURRENT_TIME); + + return TRUE; +} + +static void +panel_toplevel_move_resize_window (PanelToplevel *toplevel, + gboolean move, + gboolean resize) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (toplevel); + + g_assert (gtk_widget_get_realized (widget)); + + if (move && resize) + gdk_window_move_resize (gtk_widget_get_window (widget), + toplevel->priv->geometry.x, + toplevel->priv->geometry.y, + toplevel->priv->geometry.width, + toplevel->priv->geometry.height); + else if (move) + gdk_window_move (gtk_widget_get_window (widget), + toplevel->priv->geometry.x, + toplevel->priv->geometry.y); + else if (resize) + gdk_window_resize (gtk_widget_get_window (widget), + toplevel->priv->geometry.width, + toplevel->priv->geometry.height); +} + +static void +panel_toplevel_initially_hide (PanelToplevel *toplevel) +{ + if (!toplevel->priv->attached) { + toplevel->priv->initial_animation_done = FALSE; + + /* We start the panel off hidden until all the applets are + * loaded, and then finally slide it down when it's ready to be + * used */ + toplevel->priv->state = PANEL_STATE_AUTO_HIDDEN; + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + } else + toplevel->priv->initial_animation_done = TRUE; +} + +static void +panel_toplevel_realize (GtkWidget *widget) +{ + PanelToplevel *toplevel = (PanelToplevel *) widget; + GdkWindow *window; + + gtk_window_set_decorated (GTK_WINDOW (widget), FALSE); + gtk_window_stick (GTK_WINDOW (widget)); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->realize) + GTK_WIDGET_CLASS (panel_toplevel_parent_class)->realize (widget); + + window = gtk_widget_get_window (widget); + + panel_struts_set_window_hint (toplevel); + panel_xutils_set_window_type (window, PANEL_XUTILS_TYPE_DOCK); + + gdk_window_set_group (window, window); + gdk_window_set_geometry_hints (window, NULL, GDK_HINT_POS); + + panel_toplevel_initially_hide (toplevel); + + panel_toplevel_move_resize_window (toplevel, TRUE, TRUE); +} + +static void +panel_toplevel_disconnect_timeouts (PanelToplevel *toplevel) +{ + if (toplevel->priv->hide_timeout) + g_source_remove (toplevel->priv->hide_timeout); + toplevel->priv->hide_timeout = 0; + + if (toplevel->priv->unhide_timeout) + g_source_remove (toplevel->priv->unhide_timeout); + toplevel->priv->unhide_timeout = 0; + + if (toplevel->priv->animation_timeout) + g_source_remove (toplevel->priv->animation_timeout); + toplevel->priv->animation_timeout = 0; +} + +static void +panel_toplevel_unrealize (GtkWidget *widget) +{ + panel_toplevel_disconnect_timeouts (PANEL_TOPLEVEL (widget)); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->unrealize) + GTK_WIDGET_CLASS (panel_toplevel_parent_class)->unrealize (widget); +} + +static void +panel_toplevel_destroy (GtkObject *widget) +{ + PanelToplevel *toplevel = (PanelToplevel *) widget; + + if (toplevel->priv->attached) { + panel_toplevel_disconnect_attached (toplevel); + toplevel->priv->attached = FALSE; + + toplevel->priv->attach_toplevel = NULL; + toplevel->priv->attach_widget = NULL; + } + + panel_toplevel_disconnect_timeouts (toplevel); + + if (GTK_OBJECT_CLASS (panel_toplevel_parent_class)->destroy) + GTK_OBJECT_CLASS (panel_toplevel_parent_class)->destroy (widget); +} + +static void +panel_toplevel_check_resize (GtkContainer *container) +{ + GtkAllocation allocation; + GtkAllocation widget_allocation; + GtkRequisition requisition; + GtkWidget *widget; + + widget = GTK_WIDGET (container); + + if (!gtk_widget_get_visible (widget)) + return; + + requisition.width = -1; + requisition.height = -1; + + gtk_widget_size_request (widget, &requisition); + gtk_widget_get_allocation (widget, &widget_allocation); + + if (widget_allocation.width != requisition.width || + widget_allocation.height != requisition.height) + return; + + allocation = widget_allocation; + gtk_widget_size_allocate (widget, &allocation); +} + +static void +panel_toplevel_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + PanelToplevel *toplevel; + GtkBin *bin; + GtkWidget *child; + GdkRectangle old_geometry; + int position_changed = FALSE; + int size_changed = FALSE; + + toplevel = PANEL_TOPLEVEL (widget); + bin = GTK_BIN (widget); + + /* we get a size request when there are new monitors, so first try to + * see if we need to move to a new monitor */ + panel_toplevel_update_monitor (toplevel); + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_request (child, requisition); + + old_geometry = toplevel->priv->geometry; + + panel_toplevel_update_geometry (toplevel, requisition); + + requisition->width = toplevel->priv->geometry.width; + requisition->height = toplevel->priv->geometry.height; + + if (!gtk_widget_get_realized (widget)) + return; + + if (old_geometry.width != toplevel->priv->geometry.width || + old_geometry.height != toplevel->priv->geometry.height) + size_changed = TRUE; + + if (old_geometry.x != toplevel->priv->geometry.x || + old_geometry.y != toplevel->priv->geometry.y) + position_changed = TRUE; + + panel_toplevel_move_resize_window (toplevel, position_changed, size_changed); +} + +static void +panel_toplevel_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + PanelToplevel *toplevel = (PanelToplevel *) widget; + GtkBin *bin = (GtkBin *) widget; + GtkStyle *style; + GtkWidget *child; + GtkAllocation challoc; + GtkAllocation child_allocation; + + gtk_widget_set_allocation (widget, allocation); + + if (toplevel->priv->expand || + toplevel->priv->buttons_enabled || + toplevel->priv->attached) + challoc = *allocation; + else { + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) { + challoc.x = HANDLE_SIZE; + challoc.y = 0; + challoc.width = allocation->width - 2 * HANDLE_SIZE; + challoc.height = allocation->height; + } else { + challoc.x = 0; + challoc.y = HANDLE_SIZE; + challoc.width = allocation->width; + challoc.height = allocation->height - 2 * HANDLE_SIZE; + } + } + + style = gtk_widget_get_style (widget); + + if (toplevel->priv->edges & PANEL_EDGE_TOP) { + challoc.y += style->ythickness; + challoc.height -= style->ythickness; + } + + if (toplevel->priv->edges & PANEL_EDGE_LEFT) { + challoc.x += style->xthickness; + challoc.width -= style->xthickness; + } + + if (toplevel->priv->edges & PANEL_EDGE_BOTTOM) + challoc.height -= style->ythickness; + + if (toplevel->priv->edges & PANEL_EDGE_RIGHT) + challoc.width -= style->xthickness; + + challoc.width = MAX (1, challoc.width); + challoc.height = MAX (1, challoc.height); + + child = gtk_bin_get_child (bin); + gtk_widget_get_allocation (child, &child_allocation); + + if (gtk_widget_get_mapped (widget) && + (challoc.x != child_allocation.x || + challoc.y != child_allocation.y || + challoc.width != child_allocation.width || + challoc.height != child_allocation.height)) { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + gdk_window_invalidate_rect (gtk_widget_get_window (widget), &allocation, FALSE); + } + + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_allocate (child, &challoc); +} + +static gboolean panel_toplevel_expose(GtkWidget* widget, GdkEventExpose* event) +{ + PanelToplevel* toplevel = (PanelToplevel*) widget; + PanelFrameEdge edges; + gboolean retval = FALSE; + GdkWindow *window; + GtkStyle *style; + GtkStateType state; + GtkAllocation allocation; + + if (!gtk_widget_is_drawable (widget)) + return retval; + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->expose_event) + retval = GTK_WIDGET_CLASS (panel_toplevel_parent_class)->expose_event (widget, event); + + edges = toplevel->priv->edges; + panel_frame_draw (widget, edges); + + if (toplevel->priv->expand || + toplevel->priv->buttons_enabled || + toplevel->priv->attached) + return retval; + + window = gtk_widget_get_window (widget); + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + gtk_widget_get_allocation (widget, &allocation); + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) { + int x, y, width, height; + int xthickness, ythickness; + + x = allocation.x; + y = allocation.y; + width = HANDLE_SIZE; + height = allocation.height; + + xthickness = style->xthickness; + ythickness = style->ythickness; + + if (edges & PANEL_EDGE_TOP) { + y += ythickness; + height -= ythickness; + } + if (edges & PANEL_EDGE_BOTTOM) + height -= ythickness; + if (edges & PANEL_EDGE_LEFT) + x += xthickness; + + gtk_paint_handle (style, window, state, + GTK_SHADOW_OUT, + &event->area, widget, "handlebox", + x, y, width, height, + GTK_ORIENTATION_VERTICAL); + + x = allocation.width - HANDLE_SIZE; + if (edges & PANEL_EDGE_RIGHT) + x -= xthickness; + + gtk_paint_handle (style, window, state, + GTK_SHADOW_OUT, + &event->area, widget, "handlebox", + x, y, width, height, + GTK_ORIENTATION_VERTICAL); + } else { + int x, y, width, height; + int xthickness, ythickness; + + x = allocation.x; + y = allocation.y; + width = allocation.width; + height = HANDLE_SIZE; + + xthickness = style->xthickness; + ythickness = style->ythickness; + + if (edges & PANEL_EDGE_LEFT) { + x += xthickness; + width -= xthickness; + } + if (edges & PANEL_EDGE_RIGHT) + width -= xthickness; + if (edges & PANEL_EDGE_TOP) + y += ythickness; + + gtk_paint_handle (style, window, state, + GTK_SHADOW_OUT, + &event->area, widget, "handlebox", + x, y, width, height, + GTK_ORIENTATION_HORIZONTAL); + + y = allocation.height - HANDLE_SIZE; + if (edges & PANEL_EDGE_BOTTOM) + y -= ythickness; + + gtk_paint_handle (style, window, state, + GTK_SHADOW_OUT, + &event->area, widget, "handlebox", + x, y, width, height, + GTK_ORIENTATION_HORIZONTAL); + } + + return retval; +} + +static gboolean +panel_toplevel_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + PanelToplevel *toplevel; + GtkWidget *event_widget; + + g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE); + + toplevel = PANEL_TOPLEVEL (widget); + + if (event->button != 1 && event->button != 2) + return FALSE; + + if (toplevel->priv->animating) + return FALSE; + + /* Get the mouse-button modifier from marco so that only intentional + * moves are considered. We don't this for non-expanded panels since we + * only have the handles that the user can grab. */ + if ((toplevel->priv->expand || toplevel->priv->attached) && + (event->state & GDK_MODIFIER_MASK) != panel_bindings_get_mouse_button_modifier_keymask ()) + return FALSE; + + gdk_window_get_user_data (event->window, (gpointer)&event_widget); + g_assert (GTK_IS_WIDGET (event_widget)); + gtk_widget_translate_coordinates (event_widget, + widget, + event->x, + event->y, + &toplevel->priv->drag_offset_x, + &toplevel->priv->drag_offset_y); + + panel_toplevel_begin_grab_op (toplevel, PANEL_GRAB_OP_MOVE, FALSE, event->time); + + return TRUE; +} + +static gboolean +panel_toplevel_button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + PanelToplevel *toplevel; + + if (event->button != 1 && event->button != 2) + return FALSE; + + toplevel = PANEL_TOPLEVEL (widget); + + if (toplevel->priv->grab_op == PANEL_GRAB_OP_NONE) + return FALSE; + + if (toplevel->priv->grab_is_keyboard) + return FALSE; + + panel_toplevel_end_grab_op (toplevel, event->time); + + return TRUE; +} + +static gboolean +panel_toplevel_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + PanelToplevel *toplevel = (PanelToplevel *) widget; + + if (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE && + panel_toplevel_handle_grab_op_key_event (toplevel, event)) + return TRUE; + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->key_press_event) + return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->key_press_event (widget, event); + + return FALSE; +} + +static gboolean +panel_toplevel_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event) +{ + if (gdk_event_get_screen ((GdkEvent *)event) == + gtk_window_get_screen (GTK_WINDOW (widget))) + return panel_toplevel_handle_grab_op_motion_event ( + PANEL_TOPLEVEL (widget), event); + else + return FALSE; +} + +static gboolean +panel_toplevel_animation_timeout (PanelToplevel *toplevel) +{ + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + if (!toplevel->priv->animating) { + toplevel->priv->animation_end_x = 0xdead; + toplevel->priv->animation_end_y = 0xdead; + toplevel->priv->animation_end_width = 0xdead; + toplevel->priv->animation_end_height = 0xdead; + toplevel->priv->animation_start_time.tv_sec = 0xdead; + toplevel->priv->animation_start_time.tv_usec = 0xdead; + toplevel->priv->animation_end_time.tv_sec = 0xdead; + toplevel->priv->animation_end_time.tv_usec = 0xdead; + toplevel->priv->animation_timeout = 0; + toplevel->priv->initial_animation_done = TRUE; + } + + return toplevel->priv->animating; +} + +static long +panel_toplevel_get_animation_time (PanelToplevel *toplevel) +{ + /* The number of seconds to complete the animation. + */ +#define ANIMATION_TIME_FAST 0.4 +#define ANIMATION_TIME_MEDIUM 1.2 +#define ANIMATION_TIME_SLOW 2.0 + + long t; + + switch (toplevel->priv->animation_speed) { + case PANEL_ANIMATION_SLOW: + t = ANIMATION_TIME_SLOW * G_USEC_PER_SEC; + break; + case PANEL_ANIMATION_MEDIUM: + t = ANIMATION_TIME_MEDIUM * G_USEC_PER_SEC; + break; + case PANEL_ANIMATION_FAST: + t = ANIMATION_TIME_FAST * G_USEC_PER_SEC; + break; + default: + g_assert_not_reached (); + break; + } + + return t; + +#undef ANIMATION_TIME_FAST +#undef ANIMATION_TIME_MEDIUM +#undef ANIMATION_TIME_SLOW +} + +static void +panel_toplevel_calculate_animation_end_geometry (PanelToplevel *toplevel) +{ + GdkScreen *screen; + int monitor_width, monitor_height; + + toplevel->priv->animation_end_x = toplevel->priv->x; + toplevel->priv->animation_end_y = toplevel->priv->y; + toplevel->priv->animation_end_width = -1; + toplevel->priv->animation_end_height = -1; + + screen = panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + if (!toplevel->priv->expand) { + + if (toplevel->priv->x_centered) + toplevel->priv->animation_end_x = + (monitor_width - toplevel->priv->geometry.width) / 2; + if (toplevel->priv->y_centered) + toplevel->priv->animation_end_y = + (monitor_height - toplevel->priv->geometry.height) / 2; + } + + /* we consider the toplevels which are in the initial animation stage + * as in a normal state */ + if (toplevel->priv->state == PANEL_STATE_NORMAL || + (!toplevel->priv->initial_animation_done && + !toplevel->priv->auto_hide)) + panel_toplevel_update_normal_position (toplevel, + &toplevel->priv->animation_end_x, + &toplevel->priv->animation_end_y, + &toplevel->priv->animation_end_width, + &toplevel->priv->animation_end_height); + + else if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) + panel_toplevel_update_auto_hide_position (toplevel, + &toplevel->priv->animation_end_x, + &toplevel->priv->animation_end_y, + &toplevel->priv->animation_end_width, + &toplevel->priv->animation_end_height, + TRUE); + else + panel_toplevel_update_hidden_position (toplevel, + &toplevel->priv->animation_end_x, + &toplevel->priv->animation_end_y, + &toplevel->priv->animation_end_width, + &toplevel->priv->animation_end_height); +} + +static void +panel_toplevel_start_animation (PanelToplevel *toplevel) +{ + GdkScreen *screen; + GtkRequisition requisition; + int deltax, deltay, deltaw = 0, deltah = 0; + int cur_x = -1, cur_y = -1; + long t; + + panel_toplevel_calculate_animation_end_geometry (toplevel); + + toplevel->priv->animating = TRUE; + + panel_toplevel_update_struts (toplevel, TRUE); + panel_struts_update_toplevel_geometry (toplevel, + &toplevel->priv->animation_end_x, + &toplevel->priv->animation_end_y, + &toplevel->priv->animation_end_width, + &toplevel->priv->animation_end_height); + panel_toplevel_update_struts (toplevel, FALSE); + + gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (toplevel)), &cur_x, &cur_y); + + screen = gtk_widget_get_screen (GTK_WIDGET (toplevel)); + + cur_x -= panel_multiscreen_x (screen, toplevel->priv->monitor); + cur_y -= panel_multiscreen_y (screen, toplevel->priv->monitor); + + deltax = toplevel->priv->animation_end_x - cur_x; + deltay = toplevel->priv->animation_end_y - cur_y; + + gtk_widget_get_requisition (GTK_WIDGET (toplevel), &requisition); + + if (toplevel->priv->animation_end_width != -1) + deltaw = toplevel->priv->animation_end_width - requisition.width; + + if (toplevel->priv->animation_end_height != -1) + deltah = toplevel->priv->animation_end_height - requisition.height; + + if (deltax == 0 && deltay == 0 && deltaw == 0 && deltah == 0) { + toplevel->priv->animation_end_x = -1; + toplevel->priv->animation_end_y = -1; + toplevel->priv->animation_end_width = -1; + toplevel->priv->animation_end_height = -1; + toplevel->priv->animating = FALSE; + return; + } + + if (toplevel->priv->attached) { + /* Re-map unmapped attached toplevels */ + if (!gtk_widget_get_mapped (GTK_WIDGET (toplevel))) + gtk_widget_map (GTK_WIDGET (toplevel)); + + gtk_window_present (GTK_WINDOW (toplevel->priv->attach_toplevel)); + } + + g_get_current_time (&toplevel->priv->animation_start_time); + + t = panel_toplevel_get_animation_time (toplevel); + g_get_current_time (&toplevel->priv->animation_end_time); + g_time_val_add (&toplevel->priv->animation_end_time, t); + + if (!toplevel->priv->animation_timeout) + toplevel->priv->animation_timeout = + g_timeout_add (20, (GSourceFunc) panel_toplevel_animation_timeout, toplevel); +} + +void +panel_toplevel_hide (PanelToplevel *toplevel, + gboolean auto_hide, + GtkDirectionType direction) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->state != PANEL_STATE_NORMAL) + return; + + g_signal_emit (toplevel, toplevel_signals [HIDE_SIGNAL], 0); + + if (toplevel->priv->attach_toplevel) + panel_toplevel_pop_autohide_disabler (toplevel->priv->attach_toplevel); + + if (auto_hide) + toplevel->priv->state = PANEL_STATE_AUTO_HIDDEN; + else { + if (direction == -1) { + if (toplevel->priv->orientation & PANEL_VERTICAL_MASK) + direction = GTK_DIR_UP; + else + direction = GTK_DIR_LEFT; + } + + switch (direction) { + case GTK_DIR_UP: + g_return_if_fail (toplevel->priv->orientation & PANEL_VERTICAL_MASK); + toplevel->priv->state = PANEL_STATE_HIDDEN_UP; + break; + case GTK_DIR_DOWN: + g_return_if_fail (toplevel->priv->orientation & PANEL_VERTICAL_MASK); + toplevel->priv->state = PANEL_STATE_HIDDEN_DOWN; + break; + case GTK_DIR_LEFT: + g_return_if_fail (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK); + toplevel->priv->state = PANEL_STATE_HIDDEN_LEFT; + break; + case GTK_DIR_RIGHT: + g_return_if_fail (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK); + toplevel->priv->state = PANEL_STATE_HIDDEN_RIGHT; + break; + default: + g_assert_not_reached (); + break; + } + + panel_toplevel_update_hide_buttons (toplevel); + } + + if (toplevel->priv->animate && gtk_widget_get_realized (GTK_WIDGET (toplevel))) + panel_toplevel_start_animation (toplevel); + else if (toplevel->priv->attached) + gtk_widget_hide (GTK_WIDGET (toplevel)); + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); +} + +static gboolean +panel_toplevel_auto_hide_timeout_handler (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + if (panel_toplevel_get_autohide_disabled (toplevel)) { + toplevel->priv->hide_timeout = 0; + return FALSE; + } + + /* keep coming back until the animation has finished. + * FIXME: we should really remove the timeout/idle + * completely and re-instate it when the + * animation has finished. + */ + if (toplevel->priv->animating) + return TRUE; + + panel_toplevel_hide (toplevel, TRUE, -1); + + toplevel->priv->hide_timeout = 0; + + return FALSE; +} + +void +panel_toplevel_unhide (PanelToplevel *toplevel) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->state == PANEL_STATE_NORMAL) + return; + + toplevel->priv->state = PANEL_STATE_NORMAL; + + panel_toplevel_update_hide_buttons (toplevel); + + if (toplevel->priv->attach_toplevel) + panel_toplevel_push_autohide_disabler (toplevel->priv->attach_toplevel); + + if (toplevel->priv->animate && gtk_widget_get_realized (GTK_WIDGET (toplevel))) + panel_toplevel_start_animation (toplevel); + else if (toplevel->priv->attached) + gtk_widget_show (GTK_WIDGET (toplevel)); + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + if (!toplevel->priv->animate) + g_signal_emit (toplevel, toplevel_signals [UNHIDE_SIGNAL], 0); +} + +static gboolean +panel_toplevel_auto_unhide_timeout_handler (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + /* keep coming back until the animation has finished. + * FIXME: we should really remove the timeout/idle + * completely and re-instate it when the + * animation has finished. + */ + if (toplevel->priv->animating) + return TRUE; + + if (!toplevel->priv->animate) + toplevel->priv->initial_animation_done = TRUE; + + /* initial animation for auto-hidden panels: we need to unhide and hide + * again to get at the right size */ + if (!toplevel->priv->initial_animation_done && + toplevel->priv->auto_hide) { + toplevel->priv->unhide_timeout = 0; + panel_toplevel_unhide (toplevel); + panel_toplevel_hide (toplevel, TRUE, -1); + return FALSE; + } + + if (!panel_toplevel_contains_pointer (toplevel) && + toplevel->priv->auto_hide) { + toplevel->priv->unhide_timeout = 0; + return FALSE; + } + + panel_toplevel_unhide (toplevel); + + toplevel->priv->unhide_timeout = 0; + + return FALSE; +} + +void +panel_toplevel_queue_auto_hide (PanelToplevel *toplevel) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (!toplevel->priv->auto_hide || + panel_toplevel_contains_pointer (toplevel) || + panel_toplevel_get_autohide_disabled (toplevel)) + return; + + if (toplevel->priv->unhide_timeout) + g_source_remove (toplevel->priv->unhide_timeout); + toplevel->priv->unhide_timeout = 0; + + if (toplevel->priv->hide_timeout || + toplevel->priv->state != PANEL_STATE_NORMAL) + return; + + if (toplevel->priv->hide_delay > 0) + toplevel->priv->hide_timeout = + g_timeout_add (toplevel->priv->hide_delay, + (GSourceFunc) panel_toplevel_auto_hide_timeout_handler, + toplevel); + else + toplevel->priv->hide_timeout = + g_idle_add ((GSourceFunc) panel_toplevel_auto_hide_timeout_handler, + toplevel); +} + +void +panel_toplevel_queue_auto_unhide (PanelToplevel *toplevel) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->unhide_timeout) + return; + + if (toplevel->priv->hide_timeout) + g_source_remove (toplevel->priv->hide_timeout); + toplevel->priv->hide_timeout = 0; + + if (toplevel->priv->state != PANEL_STATE_AUTO_HIDDEN) + return; + + if (toplevel->priv->unhide_delay > 0) + toplevel->priv->unhide_timeout = + g_timeout_add (toplevel->priv->unhide_delay, + (GSourceFunc) panel_toplevel_auto_unhide_timeout_handler, + toplevel); + else + toplevel->priv->unhide_timeout = + g_idle_add ((GSourceFunc) panel_toplevel_auto_unhide_timeout_handler, + toplevel); +} + +void +panel_toplevel_queue_initial_unhide (PanelToplevel *toplevel) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->initial_animation_done) + return; + + if (toplevel->priv->unhide_timeout) + return; + + toplevel->priv->unhide_timeout = + g_idle_add ((GSourceFunc) panel_toplevel_auto_unhide_timeout_handler, + toplevel); +} + +static gboolean +panel_toplevel_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + PanelToplevel *toplevel; + + g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE); + + toplevel = PANEL_TOPLEVEL (widget); + + if (toplevel->priv->auto_hide && event->detail != GDK_NOTIFY_INFERIOR) + panel_toplevel_queue_auto_unhide (toplevel); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->enter_notify_event) + return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->enter_notify_event (widget, event); + + return FALSE; +} + +static gboolean +panel_toplevel_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + PanelToplevel *toplevel; + + g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE); + + toplevel = PANEL_TOPLEVEL (widget); + + if (toplevel->priv->auto_hide && event->detail != GDK_NOTIFY_INFERIOR) + panel_toplevel_queue_auto_hide (toplevel); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->leave_notify_event) + return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->leave_notify_event (widget, event); + + return FALSE; +} + +static gboolean +panel_toplevel_focus_in_event (GtkWidget *widget, + GdkEventFocus *event) +{ + PanelToplevel *toplevel = PANEL_TOPLEVEL (widget); + + if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) + panel_toplevel_unhide (toplevel); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_in_event) + return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_in_event (widget, event); + + return FALSE; +} + +static gboolean +panel_toplevel_focus_out_event (GtkWidget *widget, + GdkEventFocus *event) +{ + PanelToplevel *toplevel = PANEL_TOPLEVEL (widget); + + /* It appears that sometimes we don't get a leave notify event, + but just a focus in/out, so queue the autohide in that case. + If the pointer is inside the panel then obviously we won't hide */ + if (toplevel->priv->auto_hide) + panel_toplevel_queue_auto_hide (toplevel); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_out_event) + return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_out_event (widget, event); + + return FALSE; +} + +static void +panel_toplevel_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + panel_toplevel_update_hide_buttons (PANEL_TOPLEVEL (widget)); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->style_set) + GTK_WIDGET_CLASS (panel_toplevel_parent_class)->style_set (widget, previous_style); +} + +static void +panel_toplevel_drag_threshold_changed (PanelToplevel *toplevel) +{ + int threshold; + + threshold = 0; + g_object_get (G_OBJECT (toplevel->priv->gtk_settings), + "gtk-dnd-drag-threshold", &threshold, + NULL); + + if (threshold) + toplevel->priv->snap_tolerance = threshold * SNAP_TOLERANCE_FACTOR; +} + +static void +panel_toplevel_update_gtk_settings (PanelToplevel *toplevel) +{ + if (toplevel->priv->gtk_settings) + g_signal_handlers_disconnect_by_func (toplevel->priv->gtk_settings, + G_CALLBACK (panel_toplevel_drag_threshold_changed), + toplevel); + + toplevel->priv->gtk_settings = gtk_widget_get_settings (GTK_WIDGET (toplevel->priv->panel_widget)); + + g_signal_connect_swapped (G_OBJECT (toplevel->priv->gtk_settings), + "notify::gtk-dnd-drag-threshold", + G_CALLBACK (panel_toplevel_drag_threshold_changed), + toplevel); + + panel_toplevel_drag_threshold_changed (toplevel); +} + +static void +panel_toplevel_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen) +{ + panel_toplevel_update_gtk_settings (PANEL_TOPLEVEL (widget)); + + if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->screen_changed) + GTK_WIDGET_CLASS (panel_toplevel_parent_class)->screen_changed (widget, previous_screen); + + gtk_widget_queue_resize (widget); +} + +static void +panel_toplevel_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PanelToplevel *toplevel; + + g_return_if_fail (PANEL_IS_TOPLEVEL (object)); + + toplevel = PANEL_TOPLEVEL (object); + + switch (prop_id) { + case PROP_NAME: + panel_toplevel_set_name (toplevel, g_value_get_string (value)); + break; + case PROP_EXPAND: + panel_toplevel_set_expand (toplevel, g_value_get_boolean (value)); + break; + case PROP_ORIENTATION: + panel_toplevel_set_orientation (toplevel, g_value_get_enum (value)); + break; + case PROP_SIZE: + panel_toplevel_set_size (toplevel, g_value_get_int (value)); + break; + case PROP_X: + panel_toplevel_set_x (toplevel, + g_value_get_int (value), + toplevel->priv->x_right, + toplevel->priv->x_centered); + break; + case PROP_X_RIGHT: + panel_toplevel_set_x (toplevel, + toplevel->priv->x, + g_value_get_int (value), + toplevel->priv->x_centered); + break; + case PROP_X_CENTERED: + panel_toplevel_set_x (toplevel, + toplevel->priv->x, + toplevel->priv->x_right, + g_value_get_boolean (value)); + break; + case PROP_Y: + panel_toplevel_set_y (toplevel, + g_value_get_int (value), + toplevel->priv->y_bottom, + toplevel->priv->y_centered); + break; + case PROP_Y_BOTTOM: + panel_toplevel_set_y (toplevel, + toplevel->priv->y, + g_value_get_int (value), + toplevel->priv->y_centered); + break; + case PROP_Y_CENTERED: + panel_toplevel_set_y (toplevel, + toplevel->priv->y, + toplevel->priv->y_bottom, + g_value_get_boolean (value)); + break; + case PROP_MONITOR: + panel_toplevel_set_monitor (toplevel, g_value_get_int (value)); + break; + case PROP_AUTOHIDE: + panel_toplevel_set_auto_hide (toplevel, g_value_get_boolean (value)); + break; + case PROP_HIDE_DELAY: + panel_toplevel_set_hide_delay (toplevel, g_value_get_int (value)); + break; + case PROP_UNHIDE_DELAY: + panel_toplevel_set_unhide_delay (toplevel, g_value_get_int (value)); + break; + case PROP_AUTOHIDE_SIZE: + panel_toplevel_set_auto_hide_size (toplevel, g_value_get_int (value)); + break; + case PROP_ANIMATE: + panel_toplevel_set_animate (toplevel, g_value_get_boolean (value)); + break; + case PROP_ANIMATION_SPEED: + panel_toplevel_set_animation_speed (toplevel, g_value_get_enum (value)); + break; + case PROP_BUTTONS_ENABLED: + panel_toplevel_set_enable_buttons (toplevel, g_value_get_boolean (value)); + break; + case PROP_ARROWS_ENABLED: + panel_toplevel_set_enable_arrows (toplevel, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_toplevel_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PanelToplevel *toplevel; + + g_return_if_fail (PANEL_IS_TOPLEVEL (object)); + + toplevel = PANEL_TOPLEVEL (object); + + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, panel_toplevel_get_name (toplevel)); + break; + case PROP_EXPAND: + g_value_set_boolean (value, toplevel->priv->expand); + break; + case PROP_ORIENTATION: + g_value_set_enum (value, toplevel->priv->orientation); + break; + case PROP_SIZE: + g_value_set_int (value, toplevel->priv->size); + break; + case PROP_X: + g_value_set_int (value, toplevel->priv->x); + break; + case PROP_X_RIGHT: + g_value_set_int (value, toplevel->priv->x_right); + break; + case PROP_X_CENTERED: + g_value_set_boolean (value, toplevel->priv->x_centered); + break; + case PROP_Y: + g_value_set_int (value, toplevel->priv->y); + break; + case PROP_Y_BOTTOM: + g_value_set_int (value, toplevel->priv->y_bottom); + break; + case PROP_Y_CENTERED: + g_value_set_boolean (value, toplevel->priv->y_centered); + break; + case PROP_MONITOR: + g_value_set_int (value, toplevel->priv->monitor); + break; + case PROP_AUTOHIDE: + g_value_set_boolean (value, toplevel->priv->auto_hide); + break; + case PROP_HIDE_DELAY: + g_value_set_int (value, toplevel->priv->hide_delay); + break; + case PROP_UNHIDE_DELAY: + g_value_set_int (value, toplevel->priv->unhide_delay); + break; + case PROP_AUTOHIDE_SIZE: + g_value_set_int (value, toplevel->priv->auto_hide_size); + break; + case PROP_ANIMATE: + g_value_set_boolean (value, toplevel->priv->animate); + break; + case PROP_ANIMATION_SPEED: + g_value_set_enum (value, toplevel->priv->animation_speed); + break; + case PROP_BUTTONS_ENABLED: + g_value_set_boolean (value, toplevel->priv->buttons_enabled); + break; + case PROP_ARROWS_ENABLED: + g_value_set_boolean (value, toplevel->priv->arrows_enabled); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +panel_toplevel_finalize (GObject *object) +{ + PanelToplevel *toplevel = (PanelToplevel *) object; + + panel_struts_unregister_strut (toplevel); + + toplevel_list = g_slist_remove (toplevel_list, toplevel); + + if (toplevel->priv->gtk_settings) { + g_signal_handlers_disconnect_by_func (toplevel->priv->gtk_settings, + G_CALLBACK (panel_toplevel_drag_threshold_changed), + toplevel); + toplevel->priv->gtk_settings = NULL; + } + + if (toplevel->priv->attached) { + panel_toplevel_disconnect_attached (toplevel); + + toplevel->priv->attached = FALSE; + + toplevel->priv->attach_toplevel = NULL; + toplevel->priv->attach_widget = NULL; + } + + if (toplevel->priv->description) + g_free (toplevel->priv->description); + toplevel->priv->description = NULL; + + if (toplevel->priv->name) + g_free (toplevel->priv->name); + toplevel->priv->name = NULL; + + G_OBJECT_CLASS (panel_toplevel_parent_class)->finalize (object); +} + +static void +panel_toplevel_class_init (PanelToplevelClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkObjectClass *gtkobject_class = (GtkObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + GtkContainerClass *container_class = (GtkContainerClass *) klass; + GtkBindingSet *binding_set; + + binding_set = gtk_binding_set_by_class (klass); + + gobject_class->set_property = panel_toplevel_set_property; + gobject_class->get_property = panel_toplevel_get_property; + gobject_class->finalize = panel_toplevel_finalize; + + gtkobject_class->destroy = panel_toplevel_destroy; + + widget_class->realize = panel_toplevel_realize; + widget_class->unrealize = panel_toplevel_unrealize; + widget_class->size_request = panel_toplevel_size_request; + widget_class->size_allocate = panel_toplevel_size_allocate; + widget_class->expose_event = panel_toplevel_expose; + widget_class->button_press_event = panel_toplevel_button_press_event; + widget_class->button_release_event = panel_toplevel_button_release_event; + widget_class->key_press_event = panel_toplevel_key_press_event; + widget_class->motion_notify_event = panel_toplevel_motion_notify_event; + widget_class->enter_notify_event = panel_toplevel_enter_notify_event; + widget_class->leave_notify_event = panel_toplevel_leave_notify_event; + widget_class->screen_changed = panel_toplevel_screen_changed; + widget_class->focus_in_event = panel_toplevel_focus_in_event; + widget_class->focus_out_event = panel_toplevel_focus_out_event; + widget_class->style_set = panel_toplevel_style_set; + + container_class->check_resize = panel_toplevel_check_resize; + + klass->hiding = NULL; + klass->unhiding = NULL; + klass->popup_panel_menu = panel_toplevel_popup_panel_menu; + klass->toggle_expand = panel_toplevel_toggle_expand; + klass->expand = panel_toplevel_expand; + klass->unexpand = panel_toplevel_unexpand; + klass->toggle_hidden = panel_toplevel_toggle_hidden; + klass->begin_move = panel_toplevel_begin_move; + klass->begin_resize = panel_toplevel_begin_resize; + + g_type_class_add_private (klass, sizeof (PanelToplevelPrivate)); + + g_object_class_install_property ( + gobject_class, + PROP_NAME, + g_param_spec_string ( + "name", + "Name", + "The name of this panel", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_EXPAND, + g_param_spec_boolean ( + "expand", + "Expand", + "Expand to take up the full monitor width/height", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_ORIENTATION, + g_param_spec_enum ( + "orientation", + "Orientation", + "The orientation of the panel", + PANEL_TYPE_ORIENTATION, + PANEL_ORIENTATION_TOP, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_SIZE, + g_param_spec_int ( + "size", + "Size", + "The height (or width when vertical) of the panel", + 0, + G_MAXINT, + DEFAULT_SIZE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + + g_object_class_install_property ( + gobject_class, + PROP_X, + g_param_spec_int ( + "x", + "X position", + "The X position of the panel", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_X_RIGHT, + g_param_spec_int ( + "x-right", + "X position, from the right", + "The X position of the panel, starting from the right of the screen", + -1, + G_MAXINT, + -1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_X_CENTERED, + g_param_spec_boolean ( + "x-centered", + "X centered", + "The x co-ordinate is relative to center screen", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_Y, + g_param_spec_int ( + "y", + "Y position", + "The Y position of the panel", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_Y_BOTTOM, + g_param_spec_int ( + "y_bottom", + "Y position, from the bottom", + "The Y position of the panel, starting from the bottom of the screen", + -1, + G_MAXINT, + -1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_Y_CENTERED, + g_param_spec_boolean ( + "y-centered", + "Y centered", + "The y co-ordinate is relative to center screen", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_MONITOR, + g_param_spec_int ( + "monitor", + "Xinerama monitor", + "The monitor (in terms of Xinerama) which the panel is on", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_AUTOHIDE, + g_param_spec_boolean ( + "auto-hide", + "Auto hide", + "Automatically hide the panel when the mouse leaves the panel", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_HIDE_DELAY, + g_param_spec_int ( + "hide-delay", + "Hide delay", + "The number of milliseconds to delay before automatically hiding", + 0, + G_MAXINT, + DEFAULT_HIDE_DELAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_UNHIDE_DELAY, + g_param_spec_int ( + "unhide-delay", + "Un-hide delay", + "The number of milliseconds to delay before automatically un-hiding", + 0, + G_MAXINT, + DEFAULT_UNHIDE_DELAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_AUTOHIDE_SIZE, + g_param_spec_int ( + "auto-hide-size", + "Auto-hide size", + "The number of pixels visible when the panel has been automatically hidden", + 1, + G_MAXINT, + DEFAULT_AUTO_HIDE_SIZE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_ANIMATE, + g_param_spec_boolean ( + "animate", + "Animate", + "Enable hiding/showing animations", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_ANIMATION_SPEED, + g_param_spec_enum ( + "animation-speed", + "Animation Speed", + "The speed at which to animate panel hiding/showing", + PANEL_TYPE_ANIMATION_SPEED, + PANEL_ANIMATION_MEDIUM, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_BUTTONS_ENABLED, + g_param_spec_boolean ( + "buttons-enabled", + "Buttons Enabled", + "Enable hide/show buttons", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + gobject_class, + PROP_ARROWS_ENABLED, + g_param_spec_boolean ( + "arrows-enabled", + "Arrows Enabled", + "Enable arrows on hide/show buttons", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + gtk_widget_class_install_style_property ( + widget_class, + g_param_spec_int ( + "arrow-size", + "Arrow Size", + "The size of the arrows on the hide/show buttons", + 0, + G_MAXINT, + DEFAULT_ARROW_SIZE, + G_PARAM_READABLE)); + + toplevel_signals [HIDE_SIGNAL] = + g_signal_new ("hiding", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, hiding), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + toplevel_signals [UNHIDE_SIGNAL] = + g_signal_new ("unhiding", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, unhiding), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + toplevel_signals [POPUP_PANEL_MENU_SIGNAL] = + g_signal_new ("popup-panel-menu", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, popup_panel_menu), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + toplevel_signals [TOGGLE_EXPAND_SIGNAL] = + g_signal_new ("toggle-expand", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, toggle_expand), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + toplevel_signals [EXPAND_SIGNAL] = + g_signal_new ("expand", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, expand), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + toplevel_signals [UNEXPAND_SIGNAL] = + g_signal_new ("unexpand", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, unexpand), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + toplevel_signals [TOGGLE_HIDDEN_SIGNAL] = + g_signal_new ("toggle-hidden", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, toggle_hidden), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + toplevel_signals [BEGIN_MOVE_SIGNAL] = + g_signal_new ("begin-move", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, begin_move), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + toplevel_signals [BEGIN_RESIZE_SIGNAL] = + g_signal_new ("begin-resize", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelToplevelClass, begin_resize), + NULL, + NULL, + panel_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + + gtk_binding_entry_add_signal (binding_set, GDK_F10, GDK_CONTROL_MASK, + "popup_panel_menu", 0); + + panel_bindings_set_entries (binding_set); +} + +static void +panel_toplevel_setup_widgets (PanelToplevel *toplevel) +{ + GtkWidget* container; + + toplevel->priv->table = gtk_table_new(3, 3, FALSE); + + toplevel->priv->hide_button_top = panel_toplevel_add_hide_button(toplevel, GTK_ARROW_UP, 1, 2, 0, 1); + + toplevel->priv->hide_button_bottom = panel_toplevel_add_hide_button(toplevel, GTK_ARROW_DOWN, 1, 2, 2, 3); + + toplevel->priv->hide_button_left = panel_toplevel_add_hide_button(toplevel, GTK_ARROW_LEFT, 0, 1, 1, 2); + + toplevel->priv->hide_button_right = panel_toplevel_add_hide_button(toplevel, GTK_ARROW_RIGHT, 2, 3, 1, 2); + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + { + gtk_widget_show(toplevel->priv->hide_button_left); + gtk_widget_show(toplevel->priv->hide_button_right); + } + else + { + gtk_widget_show(toplevel->priv->hide_button_top); + gtk_widget_show(toplevel->priv->hide_button_bottom); + } + + toplevel->priv->inner_frame = g_object_new(PANEL_TYPE_FRAME, NULL); + + gtk_table_attach (GTK_TABLE (toplevel->priv->table), + GTK_WIDGET (toplevel->priv->inner_frame), + 1, 2, + 1, 2, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + 0, 0); + gtk_widget_show (GTK_WIDGET (toplevel->priv->inner_frame)); + + container = panel_widget_new (toplevel, + !toplevel->priv->expand, + toplevel->priv->orientation & PANEL_HORIZONTAL_MASK ? + GTK_ORIENTATION_HORIZONTAL : + GTK_ORIENTATION_VERTICAL, + toplevel->priv->size); + + toplevel->priv->panel_widget = PANEL_WIDGET(container); + + gtk_container_add(GTK_CONTAINER(toplevel->priv->inner_frame), container); + gtk_widget_show(container); + + gtk_container_add(GTK_CONTAINER(toplevel), toplevel->priv->table); + gtk_widget_show(toplevel->priv->table); +} + +static void +panel_toplevel_init (PanelToplevel *toplevel) +{ + int i; + + /* This is a hack for the default resize grip on Ubuntu. + * Once again, thank you Ubuntu. + * + * We need to add a --enable-ubuntu for this. + */ + #ifdef UBUNTU + gtk_window_set_has_resize_grip(&toplevel->window_instance, FALSE); + #endif + toplevel->priv = PANEL_TOPLEVEL_GET_PRIVATE (toplevel); + + toplevel->priv->expand = TRUE; + toplevel->priv->orientation = PANEL_ORIENTATION_BOTTOM; + toplevel->priv->size = DEFAULT_SIZE; + toplevel->priv->x = 0; + toplevel->priv->y = 0; + toplevel->priv->x_right = -1; + toplevel->priv->y_bottom = -1; + toplevel->priv->monitor = 0; + toplevel->priv->configured_monitor = -1; + toplevel->priv->hide_delay = DEFAULT_HIDE_DELAY; + toplevel->priv->unhide_delay = DEFAULT_UNHIDE_DELAY; + toplevel->priv->auto_hide_size = DEFAULT_AUTO_HIDE_SIZE; + toplevel->priv->animation_speed = PANEL_ANIMATION_FAST; + + toplevel->priv->snap_tolerance = DEFAULT_DND_THRESHOLD * SNAP_TOLERANCE_FACTOR; + toplevel->priv->gtk_settings = NULL; + + toplevel->priv->state = PANEL_STATE_NORMAL; + + toplevel->priv->name = NULL; + toplevel->priv->description = NULL; + + toplevel->priv->hide_timeout = 0; + toplevel->priv->unhide_timeout = 0; + + toplevel->priv->geometry.x = -1; + toplevel->priv->geometry.y = -1; + toplevel->priv->geometry.width = -1; + toplevel->priv->geometry.height = -1; + + toplevel->priv->original_width = -1; + toplevel->priv->original_height = -1; + + toplevel->priv->grab_op = PANEL_GRAB_OP_NONE; + + toplevel->priv->drag_offset_x = 0; + toplevel->priv->drag_offset_y = 0; + + toplevel->priv->animation_end_x = 0; + toplevel->priv->animation_end_y = 0; + toplevel->priv->animation_end_width = 0; + toplevel->priv->animation_end_height = 0; + toplevel->priv->animation_start_time.tv_sec = 0; + toplevel->priv->animation_start_time.tv_usec = 0; + toplevel->priv->animation_end_time.tv_sec = 0; + toplevel->priv->animation_end_time.tv_usec = 0; + toplevel->priv->animation_timeout = 0; + + toplevel->priv->panel_widget = NULL; + toplevel->priv->inner_frame = NULL; + toplevel->priv->table = NULL; + toplevel->priv->hide_button_top = NULL; + toplevel->priv->hide_button_bottom = NULL; + toplevel->priv->hide_button_left = NULL; + toplevel->priv->hide_button_right = NULL; + + toplevel->priv->attach_toplevel = NULL; + toplevel->priv->attach_widget = NULL; + toplevel->priv->n_autohide_disablers = 0; + + for (i = 0; i < N_ATTACH_TOPLEVEL_SIGNALS; i++) + toplevel->priv->attach_toplevel_signals [i] = 0; + for (i = 0; i < N_ATTACH_WIDGET_SIGNALS; i++) + toplevel->priv->attach_widget_signals [i] = 0; + + toplevel->priv->auto_hide = FALSE; + toplevel->priv->buttons_enabled = TRUE; + toplevel->priv->arrows_enabled = TRUE; + toplevel->priv->x_centered = FALSE; + toplevel->priv->y_centered = FALSE; + toplevel->priv->animating = FALSE; + toplevel->priv->grab_is_keyboard = FALSE; + toplevel->priv->position_centered = FALSE; + toplevel->priv->attached = FALSE; + toplevel->priv->attach_hidden = FALSE; + toplevel->priv->updated_geometry_initial = FALSE; + toplevel->priv->initial_animation_done = FALSE; + + gtk_widget_add_events (GTK_WIDGET (toplevel), + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + panel_toplevel_setup_widgets (toplevel); + panel_toplevel_update_description (toplevel); + panel_toplevel_update_gtk_settings (toplevel); + + toplevel_list = g_slist_prepend (toplevel_list, toplevel); + + /* Prevent the window from being deleted via Alt+F4 by accident. This + * happens with "alternative" window managers such as Sawfish or XFWM4. + */ + g_signal_connect(GTK_WIDGET(toplevel), "delete-event", G_CALLBACK(gtk_true), NULL); +} + +PanelWidget * +panel_toplevel_get_panel_widget (PanelToplevel *toplevel) +{ + + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL); + + return toplevel->priv->panel_widget; +} + +static void +panel_toplevel_update_name (PanelToplevel *toplevel) +{ + char *title; + + g_assert (toplevel->priv->description != NULL); + + title = toplevel->priv->name ? toplevel->priv->name : toplevel->priv->description; + + gtk_window_set_title (GTK_WINDOW (toplevel), title); + + panel_a11y_set_atk_name_desc ( + GTK_WIDGET (toplevel->priv->panel_widget), + title, toplevel->priv->description); +} + +void +panel_toplevel_set_name (PanelToplevel *toplevel, + const char *name) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (!toplevel->priv->name && (!name || !name [0])) + return; + + if (toplevel->priv->name && name && name [0] && + !strcmp (toplevel->priv->name, name)) + return; + + if (toplevel->priv->name) + g_free (toplevel->priv->name); + toplevel->priv->name = NULL; + + if (name && name [0]) + toplevel->priv->name = g_strdup (name); + + panel_toplevel_update_name (toplevel); + + g_object_notify (G_OBJECT (toplevel), "name"); +} + +const char* panel_toplevel_get_name(PanelToplevel* toplevel) +{ + g_return_val_if_fail(PANEL_IS_TOPLEVEL(toplevel), NULL); + + return toplevel->priv->name; +} + +const char* panel_toplevel_get_description(PanelToplevel* toplevel) +{ + g_return_val_if_fail(PANEL_IS_TOPLEVEL(toplevel), NULL); + + return toplevel->priv->description; +} + +void +panel_toplevel_set_expand (PanelToplevel *toplevel, + gboolean expand) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + expand = expand != FALSE; + + if (toplevel->priv->expand == expand) + return; + + toplevel->priv->expand = expand; + + if (!toplevel->priv->expand) { + switch (toplevel->priv->orientation) { + case PANEL_ORIENTATION_TOP: + panel_toplevel_set_x (toplevel, 0, -1, TRUE); + break; + case PANEL_ORIENTATION_BOTTOM: + panel_toplevel_set_x (toplevel, 0, 0, TRUE); + break; + case PANEL_ORIENTATION_LEFT: + panel_toplevel_set_y (toplevel, 0, -1, TRUE); + break; + case PANEL_ORIENTATION_RIGHT: + panel_toplevel_set_y (toplevel, 0, 0, TRUE); + break; + default: + g_assert_not_reached (); + break; + } + } + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + panel_widget_set_packed (toplevel->priv->panel_widget, !toplevel->priv->expand); + + g_object_notify (G_OBJECT (toplevel), "expand"); +} + +gboolean +panel_toplevel_get_expand (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), TRUE); + + return toplevel->priv->expand; +} + +gboolean +panel_toplevel_get_is_floating (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), TRUE); + + return toplevel->priv->floating; +} + +void +panel_toplevel_set_orientation (PanelToplevel *toplevel, + PanelOrientation orientation) +{ + gboolean rotate; + int monitor_width; + int monitor_height; + + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->orientation == orientation) + return; + + g_object_freeze_notify (G_OBJECT (toplevel)); + + panel_toplevel_get_monitor_geometry ( + toplevel, NULL, NULL, &monitor_width, &monitor_height); + + /* Un-snap from center if no longer along screen edge */ + if (toplevel->priv->x_centered && + (orientation & PANEL_VERTICAL_MASK)) { + toplevel->priv->x_centered = FALSE; + toplevel->priv->x = (monitor_width - toplevel->priv->geometry.width) / 2; + g_object_notify (G_OBJECT (toplevel), "x"); + g_object_notify (G_OBJECT (toplevel), "x-centered"); + + if (toplevel->priv->x_right != -1) { + toplevel->priv->x_right = -1; + g_object_notify (G_OBJECT (toplevel), "x-right"); + } + } + + if (toplevel->priv->y_centered && + (orientation & PANEL_HORIZONTAL_MASK)) { + toplevel->priv->y_centered = FALSE; + toplevel->priv->y = (monitor_height - toplevel->priv->geometry.height) / 2; + g_object_notify (G_OBJECT (toplevel), "y"); + g_object_notify (G_OBJECT (toplevel), "y-centered"); + + if (toplevel->priv->y_bottom != -1) { + toplevel->priv->y_bottom = -1; + g_object_notify (G_OBJECT (toplevel), "y-bottom"); + } + } + + rotate = FALSE; + if ((orientation & PANEL_HORIZONTAL_MASK) && + (toplevel->priv->orientation & PANEL_VERTICAL_MASK)) + rotate = TRUE; + else if ((orientation & PANEL_VERTICAL_MASK) && + (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)) + rotate = TRUE; + + /* rotate around the center */ + if (rotate && !toplevel->priv->position_centered && !toplevel->priv->expand && + toplevel->priv->updated_geometry_initial) { + toplevel->priv->position_centered = TRUE; + + /* x, y temporary refer to the panel center, so we don't care + * about x_right, y_bottom. Those will get updated in + * panel_toplevel_update_position() accordingly. */ + if (!toplevel->priv->x_centered) { + toplevel->priv->x += toplevel->priv->geometry.width / 2; + g_object_notify (G_OBJECT (toplevel), "x"); + } + + if (!toplevel->priv->y_centered) { + toplevel->priv->y += toplevel->priv->geometry.height / 2; + g_object_notify (G_OBJECT (toplevel), "y"); + } + + } + + toplevel->priv->orientation = orientation; + + panel_toplevel_update_hide_buttons (toplevel); + + panel_widget_set_orientation ( + toplevel->priv->panel_widget, + toplevel->priv->orientation & PANEL_HORIZONTAL_MASK ? + GTK_ORIENTATION_HORIZONTAL : + GTK_ORIENTATION_VERTICAL); + + switch (toplevel->priv->state) { + case PANEL_STATE_HIDDEN_UP: + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + toplevel->priv->state = PANEL_STATE_HIDDEN_LEFT; + break; + case PANEL_STATE_HIDDEN_DOWN: + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + toplevel->priv->state = PANEL_STATE_HIDDEN_RIGHT; + break; + case PANEL_STATE_HIDDEN_LEFT: + if (toplevel->priv->orientation & PANEL_VERTICAL_MASK) + toplevel->priv->state = PANEL_STATE_HIDDEN_UP; + break; + case PANEL_STATE_HIDDEN_RIGHT: + if (toplevel->priv->orientation & PANEL_VERTICAL_MASK) + toplevel->priv->state = PANEL_STATE_HIDDEN_DOWN; + break; + default: + break; + } + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + g_object_notify (G_OBJECT (toplevel), "orientation"); + + g_object_thaw_notify (G_OBJECT (toplevel)); +} + +PanelOrientation +panel_toplevel_get_orientation (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), GTK_ORIENTATION_HORIZONTAL); + + return toplevel->priv->orientation; +} + +void +panel_toplevel_set_size (PanelToplevel *toplevel, + int size) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + g_return_if_fail (size >= 0); + + if (toplevel->priv->size == size) + return; + + toplevel->priv->size = size; + + panel_widget_set_size (toplevel->priv->panel_widget, toplevel->priv->size); + + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + g_object_notify (G_OBJECT (toplevel), "size"); +} + +int +panel_toplevel_get_size (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), DEFAULT_SIZE); + + return toplevel->priv->size; +} + +void +panel_toplevel_set_auto_hide_size (PanelToplevel *toplevel, + int auto_hide_size) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->auto_hide_size == auto_hide_size) + return; + + toplevel->priv->auto_hide_size = auto_hide_size; + + if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) { + if (panel_toplevel_update_struts (toplevel, FALSE)) { + if (toplevel->priv->animate) { + panel_toplevel_unhide (toplevel); + panel_toplevel_hide (toplevel, TRUE, -1); + } else + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + } + } + + g_object_notify (G_OBJECT (toplevel), "auto-hide-size"); +} + +int +panel_toplevel_get_auto_hide_size (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), DEFAULT_AUTO_HIDE_SIZE); + + return toplevel->priv->auto_hide_size; +} + +void +panel_toplevel_set_x (PanelToplevel *toplevel, + int x, + int x_right, + gboolean x_centered) +{ + gboolean changed = FALSE; + + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + x_centered = x_centered != FALSE; + + g_object_freeze_notify (G_OBJECT (toplevel)); + + if (toplevel->priv->x != x) { + toplevel->priv->x = x; + changed = TRUE; + g_object_notify (G_OBJECT (toplevel), "x"); + } + + if (toplevel->priv->x_right != x_right) { + toplevel->priv->x_right = x_right; + changed = TRUE; + g_object_notify (G_OBJECT (toplevel), "x-right"); + } + + if (toplevel->priv->x_centered != x_centered) { + toplevel->priv->x_centered = x_centered; + changed = TRUE; + g_object_notify (G_OBJECT (toplevel), "x-centered"); + } + + if (changed) + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + g_object_thaw_notify (G_OBJECT (toplevel)); +} + +void +panel_toplevel_set_y (PanelToplevel *toplevel, + int y, + int y_bottom, + gboolean y_centered) +{ + gboolean changed = FALSE; + + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + y_centered = y_centered != FALSE; + + g_object_freeze_notify (G_OBJECT (toplevel)); + + if (toplevel->priv->y != y) { + toplevel->priv->y = y; + changed = TRUE; + g_object_notify (G_OBJECT (toplevel), "y"); + } + + if (toplevel->priv->y_bottom != y_bottom) { + toplevel->priv->y_bottom = y_bottom; + changed = TRUE; + g_object_notify (G_OBJECT (toplevel), "y-bottom"); + } + + if (toplevel->priv->y_centered != y_centered) { + toplevel->priv->y_centered = y_centered; + changed = TRUE; + g_object_notify (G_OBJECT (toplevel), "y-centered"); + } + + if (changed) + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + g_object_thaw_notify (G_OBJECT (toplevel)); +} + +void +panel_toplevel_get_position (PanelToplevel *toplevel, + int *x, + int *x_right, + int *y, + int *y_bottom) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (x) + *x = toplevel->priv->x; + + if (y) + *y = toplevel->priv->y; + + if (x_right) + *x_right = toplevel->priv->x_right; + + if (y_bottom) + *y_bottom = toplevel->priv->y_bottom; +} + +gboolean +panel_toplevel_get_x_centered (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->x_centered; +} + +gboolean +panel_toplevel_get_y_centered (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->y_centered; +} + +/** + * panel_toplevel_set_monitor_internal: + * + * Sets the monitor of the toplevel, but only the internal state. We need to + * make the difference between the internal state and the configuration of the + * user because internal constraints might affect the monitor of the toplevel. + * + * panel_toplevel_set_monitor_internal() won't update the configuration of the + * user. + **/ +static void +panel_toplevel_set_monitor_internal (PanelToplevel *toplevel, + int monitor, + gboolean force_resize) +{ + if (toplevel->priv->monitor == monitor) + return; + + toplevel->priv->monitor = monitor; + + if (force_resize) + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); +} + +/** + * panel_toplevel_update_monitor: + * + * Moves the toplevel to its configured monitor or the first one, if needed. + * This generally happens when the configured monitor was non-existing before, + * and it appeared at runtime, or if it was existing and disappeared. + * + * This must only be called at the beginning of the size request of the + * toplevel because it doesn't queue a size request. + **/ +static void +panel_toplevel_update_monitor (PanelToplevel *toplevel) +{ + GdkScreen *screen; + + screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + + /* If we were not using the configured monitor, can we use it now? */ + if ((toplevel->priv->configured_monitor != -1) && + (toplevel->priv->configured_monitor != toplevel->priv->monitor) && + toplevel->priv->configured_monitor < panel_multiscreen_monitors (screen)) { + panel_toplevel_set_monitor_internal (toplevel, + toplevel->priv->configured_monitor, + FALSE); + + /* else, can we still use the monitor we were using? */ + } else if (toplevel->priv->monitor >= panel_multiscreen_monitors (screen)) { + panel_toplevel_set_monitor_internal (toplevel, + 0, + FALSE); + } +} + +void +panel_toplevel_set_monitor (PanelToplevel *toplevel, + int monitor) +{ + GdkScreen *screen; + + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->configured_monitor == monitor) + return; + + toplevel->priv->configured_monitor = monitor; + + /* Only use the configured monitor if it's existing. Else, we ignore + * the non-existing monitor, and keep the old one. The main use case is + * when logging in after having used a multiscreen environment. + * We will put the panel on the monitor 0 for this session, and it will + * move back to the right monitor next time. */ + screen = gtk_window_get_screen (GTK_WINDOW (toplevel)); + if (monitor < panel_multiscreen_monitors (screen)) + panel_toplevel_set_monitor_internal (toplevel, monitor, TRUE); + + g_object_notify (G_OBJECT (toplevel), "monitor"); +} + +int +panel_toplevel_get_monitor (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), -1); + + return toplevel->priv->monitor; +} + +void +panel_toplevel_set_auto_hide (PanelToplevel *toplevel, + gboolean auto_hide) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + auto_hide = auto_hide != FALSE; + + if (toplevel->priv->auto_hide == auto_hide) + return; + + toplevel->priv->auto_hide = auto_hide; + + if (toplevel->priv->auto_hide) + panel_toplevel_queue_auto_hide (toplevel); + else + panel_toplevel_queue_auto_unhide (toplevel); + + if (panel_toplevel_update_struts (toplevel, FALSE)) + gtk_widget_queue_resize (GTK_WIDGET (toplevel)); + + g_object_notify (G_OBJECT (toplevel), "auto-hide"); +} + +gboolean +panel_toplevel_get_auto_hide (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->auto_hide; +} + +void +panel_toplevel_set_hide_delay (PanelToplevel *toplevel, + int hide_delay) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->hide_delay == hide_delay) + return; + + toplevel->priv->hide_delay = hide_delay; + + g_object_notify (G_OBJECT (toplevel), "hide-delay"); +} + +int +panel_toplevel_get_hide_delay (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), -1); + + return toplevel->priv->hide_delay; +} + +void +panel_toplevel_set_unhide_delay (PanelToplevel *toplevel, + int unhide_delay) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->unhide_delay == unhide_delay) + return; + + toplevel->priv->unhide_delay = unhide_delay; + + g_object_notify (G_OBJECT (toplevel), "unhide-delay"); +} + +int +panel_toplevel_get_unhide_delay (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), -1); + + return toplevel->priv->unhide_delay; +} + +void +panel_toplevel_set_animate (PanelToplevel *toplevel, + gboolean animate) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + animate = animate != FALSE; + + if (toplevel->priv->animate == animate) + return; + + toplevel->priv->animate = animate; + + g_object_notify (G_OBJECT (toplevel), "animate"); +} + +gboolean +panel_toplevel_get_animate (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->animate; +} + +void +panel_toplevel_set_animation_speed (PanelToplevel *toplevel, + PanelAnimationSpeed animation_speed) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + if (toplevel->priv->animation_speed == animation_speed) + return; + + toplevel->priv->animation_speed = animation_speed; + + g_object_notify (G_OBJECT (toplevel), "animation-speed"); +} + +PanelAnimationSpeed +panel_toplevel_get_animation_speed (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), 0); + + return toplevel->priv->animation_speed; +} + +void +panel_toplevel_set_enable_buttons (PanelToplevel *toplevel, + gboolean enable_buttons) +{ + enable_buttons = enable_buttons != FALSE; + + if (toplevel->priv->buttons_enabled == enable_buttons) + return; + + toplevel->priv->buttons_enabled = enable_buttons; + + panel_toplevel_update_hide_buttons (toplevel); + + g_object_notify (G_OBJECT (toplevel), "buttons-enabled"); +} + +gboolean +panel_toplevel_get_enable_buttons (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->buttons_enabled; +} + +void +panel_toplevel_set_enable_arrows (PanelToplevel *toplevel, + gboolean enable_arrows) +{ + g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel)); + + enable_arrows = enable_arrows != FALSE; + + if (toplevel->priv->arrows_enabled == enable_arrows) + return; + + toplevel->priv->arrows_enabled = enable_arrows; + + panel_toplevel_update_hide_buttons (toplevel); + + g_object_notify (G_OBJECT (toplevel), "arrows-enabled"); +} + +gboolean +panel_toplevel_get_enable_arrows (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + return toplevel->priv->arrows_enabled; +} + +void +panel_toplevel_rotate (PanelToplevel *toplevel, + gboolean clockwise) +{ + PanelOrientation orientation; + + /* Relies on PanelOrientation definition: + * + * typedef enum { + * PANEL_ORIENTATION_TOP = 1 << 0, + * PANEL_ORIENTATION_RIGHT = 1 << 1, + * PANEL_ORIENTATION_BOTTOM = 1 << 2, + * PANEL_ORIENTATION_LEFT = 1 << 3 + * } PanelOrientation; + */ + + orientation = toplevel->priv->orientation; + + if (clockwise) + orientation <<= 1; + else + orientation >>= 1; + + if (orientation == 0) + orientation = PANEL_ORIENTATION_LEFT; + + else if (orientation > PANEL_ORIENTATION_LEFT) + orientation = PANEL_ORIENTATION_TOP; + + panel_toplevel_set_orientation (toplevel, orientation); +} + +PanelState +panel_toplevel_get_state (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), 0); + + return toplevel->priv->state; +} + +gboolean +panel_toplevel_get_is_hidden (PanelToplevel *toplevel) +{ + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE); + + if (toplevel->priv->state == PANEL_STATE_HIDDEN_UP || + toplevel->priv->state == PANEL_STATE_HIDDEN_DOWN || + toplevel->priv->state == PANEL_STATE_HIDDEN_LEFT || + toplevel->priv->state == PANEL_STATE_HIDDEN_RIGHT) + return TRUE; + + return FALSE; +} + +int +panel_toplevel_get_minimum_size (PanelToplevel *toplevel) +{ + return calculate_minimum_height (GTK_WIDGET (toplevel), + toplevel->priv->orientation); +} + +int +panel_toplevel_get_maximum_size (PanelToplevel *toplevel) +{ + int monitor_width, monitor_height; + + panel_toplevel_get_monitor_geometry (toplevel, NULL, NULL, + &monitor_width, &monitor_height); + + if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) + return monitor_height / MAXIMUM_SIZE_SCREEN_RATIO; + else + return monitor_width / MAXIMUM_SIZE_SCREEN_RATIO; +} diff --git a/mate-panel/panel-toplevel.h b/mate-panel/panel-toplevel.h new file mode 100644 index 00000000..2c08a4aa --- /dev/null +++ b/mate-panel/panel-toplevel.h @@ -0,0 +1,179 @@ +/* + * panel-toplevel.h: The panel's toplevel window object. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_TOPLEVEL_H__ +#define __PANEL_TOPLEVEL_H__ + +#include + +#include "panel-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* We need PanelWidget type but don't want to include + the panel-widget.h */ +#ifndef TYPEDEF_PANEL_WIDGET +typedef struct _PanelWidget PanelWidget; +#define TYPEDEF_PANEL_WIDGET +#endif /* TYPEDEF_PANEL_WIDGET */ + +#define PANEL_TYPE_TOPLEVEL (panel_toplevel_get_type ()) +#define PANEL_TOPLEVEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PANEL_TYPE_TOPLEVEL, PanelToplevel)) +#define PANEL_TOPLEVEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PANEL_TYPE_TOPLEVEL, PanelToplevelClass)) +#define PANEL_IS_TOPLEVEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PANEL_TYPE_TOPLEVEL)) +#define PANEL_IS_TOPLEVEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PANEL_TYPE_TOPLEVEL)) +#define PANEL_TOPLEVEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PANEL_TYPE_TOPLEVEL, PanelToplevelClass)) + +typedef struct _PanelToplevel PanelToplevel; +typedef struct _PanelToplevelClass PanelToplevelClass; +typedef struct _PanelToplevelPrivate PanelToplevelPrivate; + +struct _PanelToplevel { + GtkWindow window_instance; + + PanelToplevelPrivate *priv; +}; + +struct _PanelToplevelClass { + GtkWindowClass window_class; + + /* key bindings */ + gboolean (*popup_panel_menu) (PanelToplevel *toplevel); + gboolean (*toggle_expand) (PanelToplevel *toplevel); + gboolean (*expand) (PanelToplevel *toplevel); + gboolean (*unexpand) (PanelToplevel *toplevel); + gboolean (*toggle_hidden) (PanelToplevel *toplevel); + gboolean (*begin_move) (PanelToplevel *toplevel); + gboolean (*begin_resize) (PanelToplevel *toplevel); + + /* signals */ + void (*hiding) (PanelToplevel *toplevel); + void (*unhiding) (PanelToplevel *toplevel); +}; + +GType panel_toplevel_get_type (void) G_GNUC_CONST; + +PanelWidget *panel_toplevel_get_panel_widget (PanelToplevel *toplevel); + +void panel_toplevel_set_name (PanelToplevel *toplevel, + const char *name); +const char* panel_toplevel_get_name(PanelToplevel* toplevel); +const char* panel_toplevel_get_description(PanelToplevel* toplevel); +void panel_toplevel_set_expand (PanelToplevel *toplevel, + gboolean expand); +gboolean panel_toplevel_get_expand (PanelToplevel *toplevel); +void panel_toplevel_set_orientation (PanelToplevel *toplevel, + PanelOrientation orientation); +PanelOrientation panel_toplevel_get_orientation (PanelToplevel *toplevel); +void panel_toplevel_set_size (PanelToplevel *toplevel, + int size); +int panel_toplevel_get_size (PanelToplevel *toplevel); +void panel_toplevel_set_monitor (PanelToplevel *toplevel, + int monitor); +int panel_toplevel_get_monitor (PanelToplevel *toplevel); +void panel_toplevel_set_auto_hide_size (PanelToplevel *toplevel, + int autohide_size); +int panel_toplevel_get_auto_hide_size (PanelToplevel *toplevel); +void panel_toplevel_set_x (PanelToplevel *toplevel, + int x, + int x_right, + gboolean x_centered); +void panel_toplevel_set_y (PanelToplevel *toplevel, + int y, + int y_bottom, + gboolean y_centered); +void panel_toplevel_get_position (PanelToplevel *toplevel, + int *x, + int *x_right, + int *y, + int *y_bottom); +gboolean panel_toplevel_get_x_centered (PanelToplevel *toplevel); +gboolean panel_toplevel_get_y_centered (PanelToplevel *toplevel); +void panel_toplevel_set_monitor (PanelToplevel *toplevel, + int monitor); +int panel_toplevel_get_monitor (PanelToplevel *toplevel); + +void panel_toplevel_rotate (PanelToplevel *toplevel, + gboolean clockwise); + +void panel_toplevel_attach_to_widget (PanelToplevel *toplevel, + PanelToplevel *attach_toplevel, + GtkWidget *attach_widget); +void panel_toplevel_detach (PanelToplevel *toplevel); +gboolean panel_toplevel_get_is_attached (PanelToplevel *toplevel); +PanelToplevel *panel_toplevel_get_attach_toplevel (PanelToplevel *toplevel); +GtkWidget *panel_toplevel_get_attach_widget (PanelToplevel *toplevel); + +gboolean panel_toplevel_get_is_floating (PanelToplevel *toplevel); + +gboolean panel_toplevel_get_is_hidden (PanelToplevel *toplevel); +PanelState panel_toplevel_get_state (PanelToplevel *toplevel); + +void panel_toplevel_hide (PanelToplevel *toplevel, + gboolean auto_hide, + GtkDirectionType direction); +void panel_toplevel_unhide (PanelToplevel *toplevel); +void panel_toplevel_queue_auto_hide (PanelToplevel *toplevel); +void panel_toplevel_queue_auto_unhide (PanelToplevel *toplevel); +void panel_toplevel_queue_initial_unhide (PanelToplevel *toplevel); +void panel_toplevel_push_autohide_disabler (PanelToplevel *toplevel); +void panel_toplevel_pop_autohide_disabler (PanelToplevel *toplevel); + +void panel_toplevel_set_auto_hide (PanelToplevel *toplevel, + gboolean autohide); +gboolean panel_toplevel_get_auto_hide (PanelToplevel *toplevel); +void panel_toplevel_set_hide_delay (PanelToplevel *toplevel, + int hide_delay); +int panel_toplevel_get_hide_delay (PanelToplevel *toplevel); +void panel_toplevel_set_unhide_delay (PanelToplevel *toplevel, + int unhide_delay); +int panel_toplevel_get_unhide_delay (PanelToplevel *toplevel); + +void panel_toplevel_set_animate (PanelToplevel *toplevel, + gboolean animate); +gboolean panel_toplevel_get_animate (PanelToplevel *toplevel); +void panel_toplevel_set_animation_speed (PanelToplevel *toplevel, + PanelAnimationSpeed animation_speed); +PanelAnimationSpeed panel_toplevel_get_animation_speed (PanelToplevel *toplevel); + +void panel_toplevel_set_enable_buttons (PanelToplevel *toplevel, + gboolean enable_buttons); +gboolean panel_toplevel_get_enable_buttons (PanelToplevel *toplevel); +void panel_toplevel_set_enable_arrows (PanelToplevel *toplevel, + gboolean enable_arrows); +gboolean panel_toplevel_get_enable_arrows (PanelToplevel *toplevel); +void panel_toplevel_update_edges (PanelToplevel *toplevel); + +gboolean panel_toplevel_is_last_unattached (PanelToplevel *toplevel); +int panel_toplevel_get_minimum_size (PanelToplevel *toplevel); +int panel_toplevel_get_maximum_size (PanelToplevel *toplevel); +GSList *panel_toplevel_list_toplevels (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_TOPLEVEL_H__ */ diff --git a/mate-panel/panel-toplevel.schemas.in b/mate-panel/panel-toplevel.schemas.in new file mode 100644 index 00000000..90d3ca3f --- /dev/null +++ b/mate-panel/panel-toplevel.schemas.in @@ -0,0 +1,434 @@ + + + + + + + /schemas/apps/panel/toplevels/name + panel + string + + + Name to identify panel + + This is a human readable name which you can use to identify + a panel. Its main purpose is to serve as the panel's window + title which is useful when navigating between panels. + + + + + + /schemas/apps/panel/toplevels/screen + panel + int + 0 + + X screen where the panel is displayed + + With a multi-screen setup, you may have panels on each + individual screen. This key identifies the current screen + the panel is displayed on. + + + + + + /schemas/apps/panel/toplevels/monitor + panel + int + 0 + + Xinerama monitor where the panel is displayed + + In a Xinerama setup, you may have panels on each individual + monitor. This key identifies the current monitor the panel + is displayed on. + + + + + + /schemas/apps/panel/toplevels/expand + panel + bool + true + + Expand to occupy entire screen width + + If true, the panel will occupy the entire screen width + (height if this is a vertical panel). In this mode the panel + can only be placed at a screen edge. If false, the panel + will only be large enough to accommodate the applets, + launchers and buttons on the panel. + + + + + + /schemas/apps/panel/toplevels/orientation + panel + string + top + + Panel orientation + + The orientation of the panel. Possible values are "top", + "bottom", "left", "right". In expanded mode the key + specifies which screen edge the panel is on. In un-expanded + mode the difference between "top" and "bottom" is less + important - both indicate that this is a horizontal panel - + but still give a useful hint as to how some panel objects + should behave. For example, on a "top" panel a menu button + will pop up its menu below the panel, whereas on a "bottom" + panel the menu will be popped up above the panel. + + + + + + /schemas/apps/panel/toplevels/size + panel + int + 24 + + Panel size + + The height (width for a vertical panel) of the panel. The + panel will determine at runtime a minimum size based on + the font size and other indicators. The maximum size is + fixed at one quarter of the screen height (or width). + + + + + + /schemas/apps/panel/toplevels/x + panel + int + 0 + + X co-ordinate of panel + + The location of the panel along the x-axis. This key is + only relevant in un-expanded mode. In expanded mode this + key is ignored and the panel is placed at the screen edge + specified by the orientation key. + + + + + + /schemas/apps/panel/toplevels/y + panel + int + 0 + + Y co-ordinate of panel + + The location of the panel along the y-axis. This key is + only relevant in un-expanded mode. In expanded mode this + key is ignored and the panel is placed at the screen edge + specified by the orientation key. + + + + + + /schemas/apps/panel/toplevels/x_right + panel + int + -1 + + X co-ordinate of panel, starting from the right of the screen + + The location of the panel along the x-axis, starting from the right of + the screen. If set to -1, the value is ignored and the value of the x + key is used. If the value is greater than 0, then the value of the x + key is ignored. + This key is only relevant in un-expanded mode. In expanded mode this + key is ignored and the panel is placed at the screen edge + specified by the orientation key. + + + + + + /schemas/apps/panel/toplevels/y_bottom + panel + int + -1 + + Y co-ordinate of panel, starting from the bottom of the screen + + The location of the panel along the y-axis, starting from the bottom of + the screen. If set to -1, the value is ignored and the value of the y + key is used. If the value is greater than 0, then the value of the y + key is ignored. + This key is only relevant in un-expanded mode. In expanded mode this + key is ignored and the panel is placed at the screen edge + specified by the orientation key. + + + + + + /schemas/apps/panel/toplevels/x_centered + panel + bool + false + + Center panel on x-axis + + If true, the x and x_right keys are ignored and the panel is placed at + the center of the x-axis of the screen. If the panel is + resized it will remain at that position - i.e. the panel + will grow on both sides. If false, the x and x_right keys specify + the location of the panel. + + + + + + /schemas/apps/panel/toplevels/y_centered + panel + bool + false + + Center panel on y-axis + + If true, the y and y_bottom keys are ignored and the panel is placed at + the center of the y-axis of the screen. If the panel is + resized it will remain at that position - i.e. the panel + will grow on both sides. If false, the y and y_bottom keys specify + the location of the panel. + + + + + + /schemas/apps/panel/toplevels/auto_hide + panel + bool + false + + Automatically hide panel into corner + + If true, the panel is automatically hidden into a corner + of the screen when the pointer leaves the panel area. Moving the + pointer to that corner again will cause the panel to re-appear. + + + + + + /schemas/apps/panel/toplevels/enable_animations + panel + bool + true + + Enable animations + + If true, hiding and un-hiding of this panel will be animated + rather than happening instantly. + + + + + + /schemas/apps/panel/toplevels/enable_buttons + panel + bool + false + + Enable hide buttons + + If true, buttons will be placed on each side of the panel + which may be used to move the panel to edge of the screen, + leaving only a button showing. + + + + + + /schemas/apps/panel/toplevels/enable_arrows + panel + bool + true + + Enable arrows on hide buttons + + If true, arrows will be placed on the hide buttons. This + key is only relevant if the enable_buttons key is true. + + + + + + /schemas/apps/panel/toplevels/hide_delay + panel + int + 300 + + Panel autohide delay + + Specifies the number of milliseconds delay after the pointer + leaves the panel area before the panel is automatically hidden. + This key is only relevant if the auto_hide key is true. + + + + + + /schemas/apps/panel/toplevels/unhide_delay + panel + int + 100 + + Panel autounhide delay + + Specifies the number of milliseconds delay after the pointer + enters the panel area before the panel is automatically + re-shown. This key is only relevant if the auto_hide key is + true. + + + + + + /schemas/apps/panel/toplevels/auto_hide_size + panel + int + 1 + + Visible pixels when hidden + + Specifies the number of pixels visible when the panel is + automatically hidden into a corner. This key is only + relevant if the auto_hide key is true. + + + + + + /schemas/apps/panel/toplevels/animation_speed + panel + string + fast + + Animation speed + + The speed in which panel animations should occur. Possible + values are "slow", "medium" and "fast". This key is only + relevant if the enable_animations key is true. + + + + + + /schemas/apps/panel/toplevels/background/type + panel + string + gtk + + Background type + + Which type of background should be used for this panel. + Possible values are "gtk" - the default GTK+ widget + background will be used, "color" - the color key will + be used as background color or "image" - the image + specified by the image key will be used as background. + + + + + + /schemas/apps/panel/toplevels/background/color + panel + string + #ffffff + + Background color + + Specifies the background color for the panel in #RGB + format. + + + + + + /schemas/apps/panel/toplevels/background/opacity + panel + int + 6000 + + Background color opacity + + Specifies the opacity of the background color format. If the + color is not completely opaque (a value of less than 65535), + the color will be composited onto the desktop background + image. + + + + + + /schemas/apps/panel/toplevels/background/image + panel + string + + + Background image + + Specifies the file to be used for the background image. If + the image contains an alpha channel it will be composited + onto the desktop background image. + + + + + + /schemas/apps/panel/toplevels/background/fit + panel + bool + false + + Fit image to panel + + If true, the image will be scaled (retaining the aspect + ratio of the image) to the panel height (if horizontal). + + + + + + /schemas/apps/panel/toplevels/background/stretch + panel + bool + false + + Stretch image to panel + + If true, the image will be scaled to the panel dimensions. + The aspect ratio of the image will not be maintained. + + + + + + /schemas/apps/panel/toplevels/background/rotate + panel + bool + false + + Rotate image on vertical panels + + If true, the background image will be rotated when the panel + is oriented vertically. + + + + + + + diff --git a/mate-panel/panel-types.h b/mate-panel/panel-types.h new file mode 100644 index 00000000..e71549ae --- /dev/null +++ b/mate-panel/panel-types.h @@ -0,0 +1,19 @@ +/*global type definitions*/ +#ifndef PANEL_TYPES_H +#define PANEL_TYPES_H + +#include +#include + +typedef enum { + PANEL_SPEED_SLOW, + PANEL_SPEED_MEDIUM, + PANEL_SPEED_FAST +} PanelSpeed; + +typedef struct { + GdkColor gdk; + guint16 alpha; +} PanelColor; + +#endif diff --git a/mate-panel/panel-util.c b/mate-panel/panel-util.c new file mode 100644 index 00000000..9148eb0c --- /dev/null +++ b/mate-panel/panel-util.c @@ -0,0 +1,1210 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * MATE panel utils + * (C) 1997, 1998, 1999, 2000 The Free Software Foundation + * Copyright 2000 Helix Code, Inc. + * Copyright 2000,2001 Eazel, Inc. + * Copyright 2001 George Lebl + * Copyright 2002 Sun Microsystems Inc. + * + * Authors: George Lebl + * Jacob Berkman + * Mark McLoughlin + */ + +#include + +#include "panel-util.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "applet.h" +#include "nothing.h" +#include "xstuff.h" +#include "panel-config-global.h" +#include "panel-mateconf.h" +#include "panel-globals.h" +#include "launcher.h" +#include "panel-icon-names.h" +#include "panel-lockdown.h" + +char * +panel_util_make_exec_uri_for_desktop (const char *exec) +{ + GString *str; + const char *c; + + if (!exec) + return g_strdup (""); + + if (!strchr (exec, ' ')) + return g_strdup (exec); + + str = g_string_new_len (NULL, strlen (exec)); + + str = g_string_append_c (str, '"'); + for (c = exec; *c != '\0'; c++) { + /* FIXME: GKeyFile will add an additional backslach so we'll + * end up with toto\\" instead of toto\" + * We could use g_key_file_set_value(), but then we don't + * benefit from the other escaping that glib is doing... + */ + if (*c == '"') + str = g_string_append (str, "\\\""); + else + str = g_string_append_c (str, *c); + } + str = g_string_append_c (str, '"'); + + return g_string_free (str, FALSE); +} + +int +panel_find_applet_index (GtkWidget *widget) +{ + GSList *applet_list, *l; + int i; + + applet_list = mate_panel_applet_list_applets (); + + for (i = 0, l = applet_list; l; i++, l = l->next) { + AppletInfo *info = l->data; + + if (info->widget == widget) + return i; + } + + return i; +} + +void +panel_push_window_busy (GtkWidget *window) +{ + int busy = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), + "Panel:WindowBusy")); + + busy ++; + + if (busy == 1) { + GdkWindow *win; + + gtk_widget_set_sensitive (window, FALSE); + + win = gtk_widget_get_window (window); + if (win != NULL) { + GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (win, cursor); + gdk_cursor_unref (cursor); + gdk_flush (); + } + } + + g_object_set_data (G_OBJECT (window), "Panel:WindowBusy", + GINT_TO_POINTER (busy)); +} + +void +panel_pop_window_busy (GtkWidget *window) +{ + int busy = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), + "Panel:WindowBusy")); + busy --; + + if (busy <= 0) { + GdkWindow *win; + + gtk_widget_set_sensitive (window, TRUE); + + win = gtk_widget_get_window (window); + if (win != NULL) + gdk_window_set_cursor (win, NULL); + + g_object_set_data (G_OBJECT (window), + "Panel:WindowBusy", NULL); + } else { + g_object_set_data (G_OBJECT (window), "Panel:WindowBusy", + GINT_TO_POINTER (busy)); + } +} + +gboolean +panel_is_program_in_path (const char *program) +{ + char *tmp = g_find_program_in_path (program); + if (tmp != NULL) { + g_free (tmp); + return TRUE; + } else { + return FALSE; + } +} + +static gboolean +panel_ensure_dir (const char *dirname) +{ + char *parsed, *p; + + if (dirname == NULL) + return FALSE; + + parsed = g_strdup (dirname); + + if (g_file_test (parsed, G_FILE_TEST_IS_DIR)) { + g_free (parsed); + return TRUE; + } + + p = strchr (parsed, '/'); + if (p == parsed) + p = strchr (p+1, '/'); + + while (p != NULL) { + *p = '\0'; + if (g_mkdir (parsed, 0700) != 0 && + errno != EEXIST && errno != ENOSYS) { + g_free (parsed); + return FALSE; + } + *p = '/'; + p = strchr (p+1, '/'); + } + + if (g_mkdir (parsed, 0700) != 0 && + errno != EEXIST && errno != ENOSYS) { + g_free (parsed); + return FALSE; + } + + g_free (parsed); + return TRUE; +} + +gboolean +panel_is_uri_writable (const char *uri) +{ + GFile *file; + GFileInfo *info; + gboolean retval; + + g_return_val_if_fail (uri != NULL, FALSE); + + retval = FALSE; + + file = g_file_new_for_uri (uri); + + if (!g_file_query_exists (file, NULL)) { + GFile *parent; + + parent = g_file_get_parent (file); + g_object_unref (file); + + if (!g_file_query_exists (parent, NULL)) { + g_object_unref (parent); + return FALSE; + } + + file = parent; + } + + info = g_file_query_info (file, "access::*", + G_FILE_QUERY_INFO_NONE, NULL, NULL); + g_object_unref (file); + + if (info) { + retval = g_file_info_get_attribute_boolean (info, + G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE); + g_object_unref (info); + } + + return retval; +} + +gboolean +panel_uri_exists (const char *uri) +{ + GFile *suri; + gboolean ret; + + g_return_val_if_fail (uri != NULL, FALSE); + + suri = g_file_new_for_uri (uri); + ret = g_file_query_exists (suri, NULL); + g_object_unref (suri); + + return ret; +} + +char * +panel_find_icon (GtkIconTheme *icon_theme, + const char *icon_name, + gint size) +{ + GtkIconInfo *info; + char *retval; + char *icon_no_extension; + + if (icon_name == NULL || strcmp (icon_name, "") == 0) + return NULL; + + if (g_path_is_absolute (icon_name)) { + if (g_file_test (icon_name, G_FILE_TEST_EXISTS)) { + return g_strdup (icon_name); + } else { + char *basename; + + basename = g_path_get_basename (icon_name); + retval = panel_find_icon (icon_theme, basename, + size); + g_free (basename); + + return retval; + } + } + + /* This is needed because some .desktop files have an icon name *and* + * an extension as icon */ + icon_no_extension = panel_xdg_icon_remove_extension (icon_name); + + info = gtk_icon_theme_lookup_icon (icon_theme, icon_no_extension, + size, 0); + + g_free (icon_no_extension); + + if (info) { + retval = g_strdup (gtk_icon_info_get_filename (info)); + gtk_icon_info_free (info); + } else + retval = NULL; + + return retval; +} + +GdkPixbuf * +panel_load_icon (GtkIconTheme *icon_theme, + const char *icon_name, + int size, + int desired_width, + int desired_height, + char **error_msg) +{ + GdkPixbuf *retval; + char *file; + GError *error; + + g_return_val_if_fail (error_msg == NULL || *error_msg == NULL, NULL); + + file = panel_find_icon (icon_theme, icon_name, size); + if (!file) { + if (error_msg) + *error_msg = g_strdup_printf (_("Icon '%s' not found"), + icon_name); + + return NULL; + } + + error = NULL; + retval = gdk_pixbuf_new_from_file_at_size (file, + desired_width, + desired_height, + &error); + if (error) { + if (error_msg) + *error_msg = g_strdup (error->message); + g_error_free (error); + } + + g_free (file); + + return retval; +} + +static char* panel_lock_screen_action_get_command(const char* action) +{ + char* command = NULL; + gboolean use_gscreensaver = FALSE; + + if (panel_is_program_in_path("mate-screensaver-command") && panel_is_program_in_path("mate-screensaver-preferences")) + { + use_gscreensaver = TRUE; + } + else if (!panel_is_program_in_path("xscreensaver-command")) + { + return NULL; + } + + if (strcmp (action, "prefs") == 0) + { + if (use_gscreensaver) + { + command = g_strdup ("mate-screensaver-preferences"); + } + else if (panel_is_program_in_path ("xscreensaver-demo")) + { + command = g_strdup ("xscreensaver-demo"); + } + else + { + command = NULL; + } + } + else if (strcmp (action, "activate") == 0 || strcmp(action, "lock") == 0) + { + /* Neither mate-screensaver or xscreensaver allow root + * to lock the screen */ + if (geteuid () == 0) + { + command = NULL; + } + else + { + if (use_gscreensaver) + { + command = g_strdup_printf("mate-screensaver-command --%s", action); + } + else + { + command = g_strdup_printf("xscreensaver-command -%s", action); + } + } + } + + return command; +} + +gboolean +panel_lock_screen_action_available (const char *action) +{ + char *command; + gboolean enabled = FALSE; + + g_return_val_if_fail (action != NULL, FALSE); + + if (strcmp (action, "prefs") != 0 && + panel_lockdown_get_disable_lock_screen ()) + return FALSE; + + command = panel_lock_screen_action_get_command (action); + if (command) + enabled = TRUE; + + g_free (command); + + return enabled; +} + +void panel_lock_screen_action(GdkScreen* screen, const char* action) +{ + GError* error = NULL; + char* command = NULL; + + g_return_if_fail(GDK_IS_SCREEN (screen)); + g_return_if_fail(action != NULL); + + if (strcmp(action, "prefs") != 0 && panel_lockdown_get_disable_lock_screen()) + { + return; + } + + command = panel_lock_screen_action_get_command(action); + + if (!command) + { + return; + } + + if (!gdk_spawn_command_line_on_screen(screen, command, &error)) + { + char* primary = g_strdup_printf(_("Could not execute '%s'"), command); + panel_error_dialog (NULL, screen, "cannot_exec_screensaver", TRUE, primary, error->message); + g_free(primary); + g_error_free(error); + } + + g_free(command); +} + +void panel_lock_screen(GdkScreen* screen) +{ + panel_lock_screen_action(screen, "lock"); +} + + +#define PANEL_LAUNCHER_PERSONAL_PATH "panel2.d/default/launchers" + +static char * +panel_launcher_get_personal_path (void) +{ + return g_build_filename (g_get_home_dir (), ".mate2", + PANEL_LAUNCHER_PERSONAL_PATH, NULL); +} + +gboolean +panel_launcher_is_in_personal_path (const char *location) +{ + GFile *file; + GFile *launchers_dir; + char *launchers_path; + gboolean retval; + + if (!location) + return FALSE; + + launchers_path = panel_launcher_get_personal_path (); + launchers_dir = g_file_new_for_path (launchers_path); + g_free (launchers_path); + + file = panel_launcher_get_gfile (location); + + retval = g_file_has_prefix (file, launchers_dir); + + g_object_unref (file); + g_object_unref (launchers_dir); + + return retval; +} + +GFile * +panel_launcher_get_gfile (const char *location) +{ + char *path; + GFile *file; + + if (!g_ascii_strncasecmp (location, "file:", strlen ("file:"))) + return g_file_new_for_uri (location); + + if (g_path_is_absolute (location)) + return g_file_new_for_path (location); + + path = panel_make_full_path (NULL, location); + file = g_file_new_for_path (path); + g_free (path); + + return file; +} + +char * +panel_launcher_get_uri (const char *location) +{ + char *path; + char *uri; + + if (!g_ascii_strncasecmp (location, "file:", strlen ("file:"))) + return g_strdup (location); + + if (!g_path_is_absolute (location)) + path = panel_make_full_path (NULL, location); + else + path = g_strdup (location); + + uri = g_filename_to_uri (path, NULL, NULL); + g_free (path); + + return uri; +} + +char * +panel_launcher_get_filename (const char *location) +{ + GFile *file; + GFile *launchers_dir; + char *launchers_path; + char *retval; + + if (!g_path_is_absolute (location) && + g_ascii_strncasecmp (location, "file:", strlen ("file:"))) + /* this is not a local URI */ + return NULL; + + launchers_path = panel_launcher_get_personal_path (); + launchers_dir = g_file_new_for_path (launchers_path); + g_free (launchers_path); + + file = panel_launcher_get_gfile (location); + + retval = g_file_get_relative_path (launchers_dir, file); + + g_object_unref (file); + g_object_unref (launchers_dir); + + return retval; +} + +char * +panel_make_full_path (const char *dir, + const char *filename) +{ + char *retval; + char *freeme = NULL; + + g_return_val_if_fail (filename != NULL, NULL); + + if (!dir) { + freeme = panel_launcher_get_personal_path (); + dir = freeme; + } + + /* Make sure the launcher directory exists */ + if (!g_file_test (dir, G_FILE_TEST_EXISTS)) + panel_ensure_dir (dir); + + retval = g_build_filename (dir, filename, NULL); + + g_free (freeme); + + return retval; +} + +char * +panel_make_unique_desktop_path_from_name (const char *dir, + const char *name) +{ + int num = 1; + char *path = NULL; +#ifndef NAME_MAX +/* sigh: some OS don't have NAME_MAX (which is POSIX). */ +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#else +#define NAME_MAX 255 +#endif +#endif + char filename[NAME_MAX]; + +/* g_file_set_contents() use "%s.XXXXXX" + * FIXME: waiting for http://bugzilla.gnome.org/show_bug.cgi?id=437977 */ +#define LENGTH_FOR_TMPFILE_EXT 7 + + g_snprintf (filename, + sizeof (filename) - strlen (".desktop") - LENGTH_FOR_TMPFILE_EXT, + "%s", name); + g_strlcat (filename, ".desktop", sizeof (filename)); + path = panel_make_full_path (dir, filename); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + return path; + g_free (path); + + while (TRUE) { + char *buf; + + buf = g_strdup_printf ("-%d.desktop", num); + g_snprintf (filename, + sizeof (filename) - strlen (buf) - LENGTH_FOR_TMPFILE_EXT, + "%s", name); + g_strlcat (filename, buf, sizeof (filename)); + g_free (buf); + + path = panel_make_full_path (dir, filename); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + return path; + g_free (path); + + num++; + } + + return NULL; +} + +char * +panel_make_unique_desktop_uri (const char *dir, + const char *source) +{ + char *name, *p; + char *uri; + char *path = NULL; + + /* Accept NULL source. Using an emptry string makes our life easier + * than keeping NULL. */ + if (!source) + source = ""; + + /* source may be an exec string, a path, or a URI. We truncate + * it at the first space (to get just the command name if it's + * an exec string), strip the path/URI, and remove the suffix + * if it's ".desktop". + */ + name = g_strndup (source, strcspn (source, " ")); + p = strrchr (name, '/'); + while (p && !*(p + 1)) { + *p = '\0'; + p = strrchr (name, '/'); + } + if (p) + memmove (name, p + 1, strlen (p + 1) + 1); + p = strrchr (name, '.'); + if (p && !strcmp (p, ".desktop")) { + *p = '\0'; + + /* also remove the -%d that might be at the end of the name */ + p = strrchr (name, '-'); + if (p) { + char *end; + strtol ((p + 1), &end, 10); + if (!*end) + *p = '\0'; + } + } + + if (name[0] == '\0') { + g_free (name); + name = g_strdup (_("file")); + } + + path = panel_make_unique_desktop_path_from_name (dir, name); + g_free (name); + + uri = g_filename_to_uri (path, NULL, NULL); + g_free (path); + + return uri; +} + +GdkPixbuf * +panel_util_cairo_rgbdata_to_pixbuf (unsigned char *data, + int width, + int height) +{ + GdkPixbuf *retval; + unsigned char *dstptr; + unsigned char *srcptr; + int align; + + g_assert (width > 0 && height > 0); + + if (!data) + return NULL; + + retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); + if (!retval) + return NULL; + + dstptr = gdk_pixbuf_get_pixels (retval); + srcptr = data; + align = gdk_pixbuf_get_rowstride (retval) - (width * 3); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +/* cairo == 00RRGGBB */ +#define CAIRO_RED 2 +#define CAIRO_GREEN 1 +#define CAIRO_BLUE 0 +#else +/* cairo == BBGGRR00 */ +#define CAIRO_RED 1 +#define CAIRO_GREEN 2 +#define CAIRO_BLUE 3 +#endif + + while (height--) { + int x = width; + while (x--) { + /* pixbuf == BBGGRR */ + dstptr[0] = srcptr[CAIRO_RED]; + dstptr[1] = srcptr[CAIRO_GREEN]; + dstptr[2] = srcptr[CAIRO_BLUE]; + + dstptr += 3; + srcptr += 4; + } + + dstptr += align; + } +#undef CAIRO_RED +#undef CAIRO_GREEN +#undef CAIRO_BLUE + + return retval; +} + +char * +guess_icon_from_exec (GtkIconTheme *icon_theme, + GKeyFile *key_file) +{ + char *exec; + char *icon_name; + char *path; + + exec = panel_key_file_get_string (key_file, "Exec"); + if (!exec || !exec [0]) { + g_free (exec); + return NULL; + } + + icon_name = g_path_get_basename (exec); + g_free (exec); + + path = panel_find_icon (icon_theme, icon_name, 48); + if (!path) { + g_free (icon_name); + return NULL; + } + + return icon_name; +} + +static GFile * +panel_util_get_gfile_root (GFile *file) +{ + GFile *parent; + GFile *parent_old; + + /* search for the root on the URI */ + parent_old = g_object_ref (file); + parent = g_file_get_parent (file); + while (parent != NULL) { + g_object_unref (parent_old); + parent_old = parent; + parent = g_file_get_parent (parent); + } + + return parent_old; +} + +static char * +panel_util_get_icon_name_from_g_icon (GIcon *gicon) +{ + const char * const *names; + GtkIconTheme *icon_theme; + int i; + + if (!G_IS_THEMED_ICON (gicon)) + return NULL; + + names = g_themed_icon_get_names (G_THEMED_ICON (gicon)); + icon_theme = gtk_icon_theme_get_default (); + + for (i = 0; names[i] != NULL; i++) { + if (gtk_icon_theme_has_icon (icon_theme, names[i])) + return g_strdup (names[i]); + } + + return NULL; +} + +static char * +panel_util_get_file_display_name_if_mount (GFile *file) +{ + GFile *compare; + GVolumeMonitor *monitor; + GList *mounts, *l; + char *ret; + + ret = NULL; + + /* compare with all mounts */ + monitor = g_volume_monitor_get (); + mounts = g_volume_monitor_get_mounts (monitor); + for (l = mounts; l != NULL; l = l->next) { + GMount *mount; + mount = G_MOUNT (l->data); + compare = g_mount_get_root (mount); + if (!ret && g_file_equal (file, compare)) + ret = g_mount_get_name (mount); + g_object_unref (mount); + } + g_list_free (mounts); + g_object_unref (monitor); + + return ret; +} + +#define HOME_NAME_KEY "/apps/caja/desktop/home_icon_name" +static char * +panel_util_get_file_display_for_common_files (GFile *file) +{ + GFile *compare; + + compare = g_file_new_for_path (g_get_home_dir ()); + if (g_file_equal (file, compare)) { + char *mateconf_name; + + g_object_unref (compare); + + mateconf_name = mateconf_client_get_string (panel_mateconf_get_client (), + HOME_NAME_KEY, + NULL); + if (PANEL_GLIB_STR_EMPTY (mateconf_name)) { + g_free (mateconf_name); + return g_strdup (_("Home Folder")); + } else { + return mateconf_name; + } + } + g_object_unref (compare); + + compare = g_file_new_for_path ("/"); + if (g_file_equal (file, compare)) { + g_object_unref (compare); + /* Translators: this is the same string as the one found in + * caja */ + return g_strdup (_("File System")); + } + g_object_unref (compare); + + return NULL; +} + +static char * +panel_util_get_file_description (GFile *file) +{ + GFileInfo *info; + char *ret; + + ret = NULL; + + info = g_file_query_info (file, "standard::description", + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, NULL); + + if (info) { + ret = g_strdup (g_file_info_get_attribute_string (info, + G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION)); + g_object_unref (info); + } + + return ret; +} + +static char * +panel_util_get_file_display_name (GFile *file, + gboolean use_fallback) +{ + GFileInfo *info; + char *ret; + + ret = NULL; + + info = g_file_query_info (file, "standard::display-name", + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, NULL); + + if (info) { + ret = g_strdup (g_file_info_get_display_name (info)); + g_object_unref (info); + } + + if (!ret && use_fallback) { + /* can happen with URI schemes non supported by gvfs */ + char *basename; + + basename = g_file_get_basename (file); + ret = g_filename_display_name (basename); + g_free (basename); + } + + return ret; +} + +static char * +panel_util_get_file_icon_name_if_mount (GFile *file) +{ + GFile *compare; + GVolumeMonitor *monitor; + GList *mounts, *l; + char *ret; + + ret = NULL; + + /* compare with all mounts */ + monitor = g_volume_monitor_get (); + mounts = g_volume_monitor_get_mounts (monitor); + for (l = mounts; l != NULL; l = l->next) { + GMount *mount; + mount = G_MOUNT (l->data); + compare = g_mount_get_root (mount); + if (!ret && g_file_equal (file, compare)) { + GIcon *gicon; + gicon = g_mount_get_icon (mount); + ret = panel_util_get_icon_name_from_g_icon (gicon); + g_object_unref (gicon); + } + g_object_unref (mount); + } + g_list_free (mounts); + g_object_unref (monitor); + + return ret; +} + +/* TODO: convert this to a simple call to g_file_query_info? */ +static const char * +panel_util_get_icon_for_uri_known_folders (const char *uri) +{ + const char *icon; + char *path; + int len; + + icon = NULL; + + if (!g_str_has_prefix (uri, "file:")) + return NULL; + + path = g_filename_from_uri (uri, NULL, NULL); + + /* Sanity check. We may be given a broken URI. */ + if (path == NULL) + return NULL; + + len = strlen (path); + if (path[len] == '/') + path[len] = '\0'; + + if (strcmp (path, "/") == 0) + icon = PANEL_ICON_FILESYSTEM; + else if (strcmp (path, g_get_home_dir ()) == 0) + icon = PANEL_ICON_HOME; + else if (strcmp (path, + g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0) + icon = PANEL_ICON_DESKTOP; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)) == 0) + icon = PANEL_ICON_FOLDER_DOCUMENTS; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)) == 0) + icon = PANEL_ICON_FOLDER_DOWNLOAD; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_MUSIC)) == 0) + icon = PANEL_ICON_FOLDER_MUSIC; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)) == 0) + icon = PANEL_ICON_FOLDER_PICTURES; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE)) == 0) + icon = PANEL_ICON_FOLDER_PUBLIC_SHARE; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)) == 0) + icon = PANEL_ICON_FOLDER_TEMPLATES; + else if (g_strcmp0 (path, + g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS)) == 0) + icon = PANEL_ICON_FOLDER_VIDEOS; + + g_free (path); + + return icon; +} + +/* This is based on caja_compute_title_for_uri() and + * caja_file_get_display_name_nocopy() */ +char * +panel_util_get_label_for_uri (const char *text_uri) +{ + GFile *file; + char *label; + GFile *root; + char *root_display; + + /* Here's what we do: + * + x-caja-search: URI + * + check if the URI is a mount + * + if file: URI: + * - check for known file: URI + * - check for description of the GFile + * - use display name of the GFile + * + else: + * - check for description of the GFile + * - if the URI is a root: "root displayname" + * - else: "root displayname: displayname" + */ + + label = NULL; + + //FIXME: see caja_query_to_readable_string() to have a nice name + if (g_str_has_prefix (text_uri, "x-caja-search:")) + return g_strdup (_("Search")); + + file = g_file_new_for_uri (text_uri); + + label = panel_util_get_file_display_name_if_mount (file); + if (label) { + g_object_unref (file); + return label; + } + + if (g_str_has_prefix (text_uri, "file:")) { + label = panel_util_get_file_display_for_common_files (file); + if (!label) + label = panel_util_get_file_description (file); + if (!label) + label = panel_util_get_file_display_name (file, TRUE); + g_object_unref (file); + + return label; + } + + label = panel_util_get_file_description (file); + if (label) { + g_object_unref (file); + return label; + } + + root = panel_util_get_gfile_root (file); + root_display = panel_util_get_file_description (root); + if (!root_display) + root_display = panel_util_get_file_display_name (root, FALSE); + if (!root_display) + /* can happen with URI schemes non supported by gvfs */ + root_display = g_file_get_uri_scheme (root); + + if (g_file_equal (file, root)) + label = root_display; + else { + char *displayname; + + displayname = panel_util_get_file_display_name (file, TRUE); + /* Translators: the first string is the name of a gvfs + * method, and the second string is a path. For + * example, "Trash: some-directory". It means that the + * directory called "some-directory" is in the trash. + */ + label = g_strdup_printf (_("%1$s: %2$s"), + root_display, displayname); + g_free (root_display); + g_free (displayname); + } + + g_object_unref (root); + g_object_unref (file); + + return label; +} + +/* FIXME: we probably want to return a GIcon, that would be built with + * g_themed_icon_new_with_default_fallbacks() since we can get an icon like + * "folder-music", where "folder" is the safe fallback. */ +char * +panel_util_get_icon_for_uri (const char *text_uri) +{ + const char *icon; + GFile *file; + GFileInfo *info; + GIcon *gicon; + char *retval; + + /* Here's what we do: + * + check for known file: URI + * + x-caja-search: URI + * + override burn: URI icon + * + check if the URI is a mount + * + override trash: URI icon for subfolders + * + check for application/x-mate-saved-search mime type and override + * icon of the GFile + * + use icon of the GFile + */ + + /* this only checks file: URI */ + icon = panel_util_get_icon_for_uri_known_folders (text_uri); + if (icon) + return g_strdup (icon); + + if (g_str_has_prefix (text_uri, "x-caja-search:")) + return g_strdup (PANEL_ICON_SAVED_SEARCH); + /* gvfs doesn't give us a nice icon, so overriding */ + if (g_str_has_prefix (text_uri, "burn:")) + return g_strdup (PANEL_ICON_BURNER); + + file = g_file_new_for_uri (text_uri); + + retval = panel_util_get_file_icon_name_if_mount (file); + if (retval) + return retval; + + /* gvfs doesn't give us a nice icon for subfolders of the trash, so + * overriding */ + if (g_str_has_prefix (text_uri, "trash:")) { + GFile *root; + + root = panel_util_get_gfile_root (file); + g_object_unref (file); + file = root; + } + + info = g_file_query_info (file, "standard::icon", + G_FILE_QUERY_INFO_NONE, NULL, NULL); + g_object_unref (file); + + if (!info) + return NULL; + + gicon = g_file_info_get_icon (info); + retval = panel_util_get_icon_name_from_g_icon (gicon); + g_object_unref (info); + + return retval; +} + +static gboolean +panel_util_query_tooltip_cb (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tip, + GtkTooltip *tooltip, + const char *text) +{ + if (!panel_global_config_get_tooltips_enabled ()) + return FALSE; + + gtk_tooltip_set_text (tooltip, text); + return TRUE; +} + +void +panel_util_set_tooltip_text (GtkWidget *widget, + const char *text) +{ + g_signal_handlers_disconnect_matched (widget, + G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, + panel_util_query_tooltip_cb, + NULL); + + if (PANEL_GLIB_STR_EMPTY (text)) { + g_object_set (widget, "has-tooltip", FALSE, NULL); + return; + } + + g_object_set (widget, "has-tooltip", TRUE, NULL); + g_signal_connect_data (widget, "query-tooltip", + G_CALLBACK (panel_util_query_tooltip_cb), + g_strdup (text), (GClosureNotify) g_free, 0); +} + +/* This is similar to what g_file_new_for_commandline_arg() does, but + * we end up with something relative to $HOME instead of the current working + * directory */ +GFile * +panel_util_get_file_optional_homedir (const char *location) +{ + GFile *file; + char *path; + char *scheme; + + if (g_path_is_absolute (location)) + return g_file_new_for_path (location); + + scheme = g_uri_parse_scheme (location); + if (scheme) { + file = g_file_new_for_uri (location); + g_free (scheme); + return file; + } + + path = g_build_filename (g_get_home_dir (), location, NULL); + file = g_file_new_for_path (path); + g_free (path); + + return file; +} diff --git a/mate-panel/panel-util.h b/mate-panel/panel-util.h new file mode 100644 index 00000000..364e8b57 --- /dev/null +++ b/mate-panel/panel-util.h @@ -0,0 +1,72 @@ +#ifndef PANEL_UTIL_H +#define PANEL_UTIL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define sure_string(s) ((const char *)((s)!=NULL?(s):"")) + +char * panel_util_make_exec_uri_for_desktop (const char *exec); + +int panel_find_applet_index (GtkWidget *widget); + +void panel_push_window_busy (GtkWidget *window); +void panel_pop_window_busy (GtkWidget *window); + +gboolean panel_is_program_in_path (const char *program); + +gboolean panel_is_uri_writable (const char *uri); +gboolean panel_uri_exists (const char *uri); + +void panel_lock_screen (GdkScreen *screen); +void panel_lock_screen_action (GdkScreen *screen, + const char *action); +gboolean panel_lock_screen_action_available (const char *action); + +char * panel_find_icon (GtkIconTheme *icon_theme, + const char *icon_name, + int size); +GdkPixbuf * panel_load_icon (GtkIconTheme *icon_theme, + const char *icon_name, + int size, + int desired_width, + int desired_height, + char **error_msg); + +GFile *panel_launcher_get_gfile (const char *location); +char *panel_launcher_get_uri (const char *location); +char *panel_launcher_get_filename (const char *location); +gboolean panel_launcher_is_in_personal_path (const char *location); + +char *panel_make_full_path (const char *dir, + const char *filename); +char *panel_make_unique_desktop_path_from_name (const char *dir, + const char *name); +char *panel_make_unique_desktop_uri (const char *dir, + const char *source); + +GdkPixbuf *panel_util_cairo_rgbdata_to_pixbuf (unsigned char *data, + int width, + int height); + +char *guess_icon_from_exec (GtkIconTheme *icon_theme, + GKeyFile *key_file); + +const char *panel_util_get_vfs_method_display_name (const char *method); +char *panel_util_get_label_for_uri (const char *text_uri); +char *panel_util_get_icon_for_uri (const char *text_uri); + +void panel_util_set_tooltip_text (GtkWidget *widget, + const char *text); + +GFile *panel_util_get_file_optional_homedir (const char *location); + +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_UTIL_H */ diff --git a/mate-panel/panel-widget.c b/mate-panel/panel-widget.c new file mode 100644 index 00000000..1800a7b5 --- /dev/null +++ b/mate-panel/panel-widget.c @@ -0,0 +1,3010 @@ +/* Mate panel: panel widget + * (C) 1997,1998,1999,2000 the Free Software Foundation + * (C) 2000 Eazel, Inc. + * + * Authors: George Lebl + */ +#include +#include +#include +#include + +#include +#include + +#include + +#include "applet.h" +#include "panel-widget.h" +#include "button-widget.h" +#include "panel.h" +#include "panel-util.h" +#include "panel-marshal.h" +#include "panel-typebuiltins.h" +#include "mate-panel-applet-frame.h" +#include "panel-globals.h" +#include "panel-profile.h" +#include "panel-lockdown.h" + +#define MOVE_INCREMENT 1 + +typedef enum { + PANEL_SWITCH_MOVE = 0, + PANEL_FREE_MOVE, + PANEL_PUSH_MOVE +} PanelMovementType; + +G_DEFINE_TYPE (PanelWidget, panel_widget, GTK_TYPE_FIXED); + +enum { + SIZE_CHANGE_SIGNAL, + BACK_CHANGE_SIGNAL, + APPLET_MOVE_SIGNAL, + APPLET_ADDED_SIGNAL, + APPLET_REMOVED_SIGNAL, + PUSH_MOVE_SIGNAL, + SWITCH_MOVE_SIGNAL, + FREE_MOVE_SIGNAL, + TAB_MOVE_SIGNAL, + END_MOVE_SIGNAL, + POPUP_PANEL_MENU_SIGNAL, + LAST_SIGNAL +}; + +static guint panel_widget_signals [LAST_SIGNAL] = {0}; + +/*define for some debug output*/ +#undef PANEL_WIDGET_DEBUG + +static gboolean mate_panel_applet_in_drag = FALSE; +static GtkWidget *saved_focus_widget = NULL; + +static void panel_widget_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void panel_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void panel_widget_cadd (GtkContainer *container, + GtkWidget *widget); +static void panel_widget_cremove (GtkContainer *container, + GtkWidget *widget); +static void panel_widget_destroy (GtkObject *obj); +static void panel_widget_finalize (GObject *obj); +static void panel_widget_realize (GtkWidget *widget); +static void panel_widget_unrealize (GtkWidget *panel); +static void panel_widget_state_changed (GtkWidget *widget, + GtkStateType previous_state); +static void panel_widget_style_set (GtkWidget *widget, + GtkStyle *previous_style); + +static void panel_widget_background_changed (PanelBackground *background, + PanelWidget *panel); + +static void panel_widget_push_move_applet (PanelWidget *panel, + GtkDirectionType dir); +static void panel_widget_switch_move_applet (PanelWidget *panel, + GtkDirectionType dir); +static void panel_widget_free_move_applet (PanelWidget *panel, + GtkDirectionType dir); +static void panel_widget_tab_move (PanelWidget *panel, + gboolean next); +static void panel_widget_end_move (PanelWidget *panel); +static gboolean panel_widget_real_focus (GtkWidget *widget, + GtkDirectionType direction); + +static gboolean panel_widget_push_applet_right (PanelWidget *panel, + GList *list, + int push); +static gboolean panel_widget_push_applet_left (PanelWidget *panel, + GList *list, + int push); + +/************************ + convenience functions + ************************/ +static int +applet_data_compare (AppletData *ad1, AppletData *ad2) +{ + return ad1->pos - ad2->pos; +} + +static void +emit_applet_moved (PanelWidget *panel_widget, + AppletData *applet) +{ + g_signal_emit (panel_widget, + panel_widget_signals [APPLET_MOVE_SIGNAL], 0, + applet->applet); +} + +/************************ + widget core + ************************/ + +static void +add_tab_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + gboolean next) +{ + gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers, + "tab_move", 1, + G_TYPE_BOOLEAN, next); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers, + "tab_move", 1, + G_TYPE_BOOLEAN, next); +} + +static void +add_move_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + const gchar *name) +{ + gtk_binding_entry_add_signal (binding_set, GDK_Up, modifiers, + name, 1, + GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP); + gtk_binding_entry_add_signal (binding_set, GDK_Down, modifiers, + name, 1, + GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN); + gtk_binding_entry_add_signal (binding_set, GDK_Left, modifiers, + name, 1, + GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT); + gtk_binding_entry_add_signal (binding_set, GDK_Right, modifiers, + name, 1, + GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT); +} + +static void +add_all_move_bindings (PanelWidget *panel) +{ + GtkWidgetClass *class; + GtkBindingSet *binding_set; + GtkWidget *focus_widget; + + class = GTK_WIDGET_GET_CLASS (panel); + + binding_set = gtk_binding_set_by_class (class); + + add_move_bindings (binding_set, GDK_SHIFT_MASK, "push_move"); + add_move_bindings (binding_set, GDK_CONTROL_MASK, "switch_move"); + add_move_bindings (binding_set, GDK_MOD1_MASK, "free_move"); + add_move_bindings (binding_set, 0, "free_move"); + + add_tab_bindings (binding_set, 0, TRUE); + add_tab_bindings (binding_set, GDK_SHIFT_MASK, FALSE); + + gtk_binding_entry_add_signal (binding_set, + GDK_Escape, 0, + "end_move", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Enter, 0, + "end_move", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_Return, 0, + "end_move", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Space, 0, + "end_move", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_space, 0, + "end_move", 0); + + focus_widget = gtk_window_get_focus (GTK_WINDOW (panel->toplevel)); + if (GTK_IS_SOCKET (focus_widget)) { + /* + * If the focus widget is a GtkSocket, i.e. the + * focus is in an applet in another process then + * key bindings do not work. We get around this by + * by setting the focus to the PanelWidget for the + * duration of the move. + */ + gtk_widget_set_can_focus (GTK_WIDGET (panel), TRUE); + gtk_widget_grab_focus (GTK_WIDGET (panel)); + saved_focus_widget = focus_widget; + } +} + +static void +panel_widget_force_grab_focus (GtkWidget *widget) +{ + gboolean can_focus = gtk_widget_get_can_focus (widget); + /* + * This follows what gtk_socket_claim_focus() does + */ + if (!can_focus) + gtk_widget_set_can_focus (widget, TRUE); + gtk_widget_grab_focus (widget); + if (!can_focus) + gtk_widget_set_can_focus (widget, FALSE); +} + +static void +panel_widget_reset_saved_focus (PanelWidget *panel) +{ + if (saved_focus_widget) { + gtk_widget_set_can_focus (GTK_WIDGET (panel), FALSE); + panel_widget_force_grab_focus (saved_focus_widget); + saved_focus_widget = NULL; + } +} + +static void +remove_tab_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + gboolean next) +{ + gtk_binding_entry_remove (binding_set, GDK_Tab, modifiers); + gtk_binding_entry_remove (binding_set, GDK_KP_Tab, modifiers); +} + +static void +remove_move_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers) +{ + gtk_binding_entry_remove (binding_set, GDK_Up, modifiers); + gtk_binding_entry_remove (binding_set, GDK_Down, modifiers); + gtk_binding_entry_remove (binding_set, GDK_Left, modifiers); + gtk_binding_entry_remove (binding_set, GDK_Right, modifiers); +} + +static void +remove_all_move_bindings (PanelWidget *panel) +{ + GtkWidgetClass *class; + GtkBindingSet *binding_set; + + class = GTK_WIDGET_GET_CLASS (panel); + + binding_set = gtk_binding_set_by_class (class); + + panel_widget_reset_saved_focus (panel); + + remove_move_bindings (binding_set, GDK_SHIFT_MASK); + remove_move_bindings (binding_set, GDK_CONTROL_MASK); + remove_move_bindings (binding_set, GDK_MOD1_MASK); + remove_move_bindings (binding_set, 0); + remove_tab_bindings (binding_set, 0, TRUE); + remove_tab_bindings (binding_set, GDK_SHIFT_MASK, FALSE); + + gtk_binding_entry_remove (binding_set, GDK_Escape, 0); + gtk_binding_entry_remove (binding_set, GDK_KP_Enter, 0); + gtk_binding_entry_remove (binding_set, GDK_Return, 0); + gtk_binding_entry_remove (binding_set, GDK_KP_Space, 0); + gtk_binding_entry_remove (binding_set, GDK_space, 0); +} + +static void +panel_widget_class_init (PanelWidgetClass *class) +{ + GtkObjectClass *object_class = (GtkObjectClass*) class; + GObjectClass *gobject_class = (GObjectClass*) class; + GtkWidgetClass *widget_class = (GtkWidgetClass*) class; + GtkContainerClass *container_class = (GtkContainerClass*) class; + + panel_widget_signals[SIZE_CHANGE_SIGNAL] = + g_signal_new ("size_change", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelWidgetClass, size_change), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + panel_widget_signals[BACK_CHANGE_SIGNAL] = + g_signal_new ("back_change", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelWidgetClass, back_change), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + panel_widget_signals[APPLET_MOVE_SIGNAL] = + g_signal_new ("applet_move", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelWidgetClass, applet_move), + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + panel_widget_signals[APPLET_ADDED_SIGNAL] = + g_signal_new ("applet_added", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelWidgetClass, applet_added), + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + panel_widget_signals[APPLET_REMOVED_SIGNAL] = + g_signal_new ("applet_removed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PanelWidgetClass, applet_removed), + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + panel_widget_signals[PUSH_MOVE_SIGNAL] = + g_signal_new ("push_move", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelWidgetClass, push_move), + NULL, + NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, + 1, + GTK_TYPE_DIRECTION_TYPE); + + panel_widget_signals[SWITCH_MOVE_SIGNAL] = + g_signal_new ("switch_move", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelWidgetClass, switch_move), + NULL, + NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, + 1, + GTK_TYPE_DIRECTION_TYPE); + + panel_widget_signals[FREE_MOVE_SIGNAL] = + g_signal_new ("free_move", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelWidgetClass, free_move), + NULL, + NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, + 1, + GTK_TYPE_DIRECTION_TYPE); + + panel_widget_signals[TAB_MOVE_SIGNAL] = + g_signal_new ("tab_move", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelWidgetClass, tab_move), + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + + panel_widget_signals[END_MOVE_SIGNAL] = + g_signal_new ("end_move", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (PanelWidgetClass, end_move), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + class->size_change = NULL; + class->back_change = NULL; + class->applet_move = NULL; + class->applet_added = NULL; + class->applet_removed = NULL; + class->push_move = panel_widget_push_move_applet; + class->switch_move = panel_widget_switch_move_applet; + class->free_move = panel_widget_free_move_applet; + class->tab_move = panel_widget_tab_move; + class->end_move = panel_widget_end_move; + + object_class->destroy = panel_widget_destroy; + gobject_class->finalize = panel_widget_finalize; + + widget_class->size_request = panel_widget_size_request; + widget_class->size_allocate = panel_widget_size_allocate; + widget_class->realize = panel_widget_realize; + widget_class->unrealize = panel_widget_unrealize; + widget_class->focus = panel_widget_real_focus; + widget_class->state_changed = panel_widget_state_changed; + widget_class->style_set = panel_widget_style_set; + + container_class->add = panel_widget_cadd; + container_class->remove = panel_widget_cremove; +} + +static void +remove_panel_from_forbidden(PanelWidget *panel, PanelWidget *r) +{ + GSList *list; + GtkWidget *parent_panel; + + g_return_if_fail(PANEL_IS_WIDGET(panel)); + g_return_if_fail(PANEL_IS_WIDGET(r)); + + if(!panel->master_widget) + return; + + list = g_object_get_data (G_OBJECT(panel->master_widget), + MATE_PANEL_APPLET_FORBIDDEN_PANELS); + if(list) { + list = g_slist_remove(list,r); + g_object_set_data (G_OBJECT(panel->master_widget), + MATE_PANEL_APPLET_FORBIDDEN_PANELS, + list); + } + parent_panel = gtk_widget_get_parent (panel->master_widget); + if (parent_panel) + remove_panel_from_forbidden(PANEL_WIDGET(parent_panel), r); +} + +static void +add_panel_to_forbidden(PanelWidget *panel, PanelWidget *r) +{ + GSList *list; + GtkWidget *parent_panel; + + g_return_if_fail(PANEL_IS_WIDGET(panel)); + g_return_if_fail(PANEL_IS_WIDGET(r)); + + if(!panel->master_widget) + return; + + list = g_object_get_data (G_OBJECT(panel->master_widget), + MATE_PANEL_APPLET_FORBIDDEN_PANELS); + if(g_slist_find(list,r)==NULL) { + list = g_slist_prepend(list,r); + + g_object_set_data (G_OBJECT(panel->master_widget), + MATE_PANEL_APPLET_FORBIDDEN_PANELS, + list); + } + parent_panel = gtk_widget_get_parent (panel->master_widget); + if (parent_panel) + add_panel_to_forbidden(PANEL_WIDGET(parent_panel), r); +} + +static void +run_up_forbidden(PanelWidget *panel, + void (*runfunc)(PanelWidget *,PanelWidget *)) +{ + GList *list; + + g_return_if_fail(PANEL_IS_WIDGET(panel)); + + for(list = panel->applet_list;list!=NULL;list = g_list_next(list)) { + AppletData *ad = list->data; + PanelWidget *p = + g_object_get_data (G_OBJECT(ad->applet), + MATE_PANEL_APPLET_ASSOC_PANEL_KEY); + if(p) + run_up_forbidden(p,runfunc); + } + (*runfunc)(panel,panel); +} + +static void +panel_widget_reset_focus (GtkContainer *container, + GtkWidget *widget) +{ + PanelWidget *panel = PANEL_WIDGET (container); + + if (gtk_container_get_focus_child (container) == widget) { + GList *children; + + children = gtk_container_get_children (container); + + /* More than one element on the list */ + if (children && children->next) { + GList *l; + + /* There are still object on the panel */ + for (l = children; l; l = l->next) { + GtkWidget *child_widget; + + child_widget = l->data; + if (child_widget == widget) + break; + } + if (l) { + GtkWidget *next_widget; + + if (l->next) + next_widget = l->next->data; + else + next_widget = l->prev->data; + + gtk_widget_child_focus (next_widget, + GTK_DIR_TAB_FORWARD); + } + } else + panel_widget_focus (panel); + + g_list_free (children); + } +} + +static void +panel_widget_cadd (GtkContainer *container, + GtkWidget *widget) +{ + PanelWidget *p; + + g_return_if_fail (PANEL_IS_WIDGET (container)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + panel_widget_add (PANEL_WIDGET (container), widget, FALSE, 0, FALSE); + + p = g_object_get_data (G_OBJECT(widget), + MATE_PANEL_APPLET_ASSOC_PANEL_KEY); + if (p) { + panel_toplevel_attach_to_widget (p->toplevel, + PANEL_WIDGET (container)->toplevel, + widget); + run_up_forbidden (p, add_panel_to_forbidden); + } +} + +static void +panel_widget_cremove (GtkContainer *container, GtkWidget *widget) +{ + AppletData *ad; + PanelWidget *p; + PanelWidget *panel; + + g_return_if_fail (PANEL_IS_WIDGET (container)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + panel = PANEL_WIDGET (container); + + ad = g_object_get_data (G_OBJECT (widget), MATE_PANEL_APPLET_DATA); + p = g_object_get_data (G_OBJECT (widget), + MATE_PANEL_APPLET_ASSOC_PANEL_KEY); + + if (p != NULL) { + panel_toplevel_detach (p->toplevel); + run_up_forbidden (p, remove_panel_from_forbidden); + } + + panel_widget_reset_focus (container, widget); + + if(panel->currently_dragged_applet == ad) + panel_widget_applet_drag_end(panel); + + g_object_ref (widget); + if (GTK_CONTAINER_CLASS (panel_widget_parent_class)->remove) + (* GTK_CONTAINER_CLASS (panel_widget_parent_class)->remove) (container, + widget); + if (ad) + panel->applet_list = g_list_remove (panel->applet_list, ad); + + g_signal_emit (G_OBJECT (container), + panel_widget_signals[APPLET_REMOVED_SIGNAL], + 0, widget); + g_object_unref (widget); +} + + +/*get the list item of the data on the position pos*/ +static GList * +get_applet_list_pos (PanelWidget *panel, + int pos) +{ + GList *l; + + g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL); + + for (l = panel->applet_list; l; l = l->next) { + AppletData *ad = l->data; + + if (ad->pos <= pos) { + if (ad->pos + ad->cells > pos) + return l; + } else + return NULL; + } + + return NULL; +} + +/*tells us if an applet is "stuck" on the right side*/ +int +panel_widget_is_applet_stuck (PanelWidget *panel_widget, + GtkWidget *widget) +{ + AppletData *applet; + + g_return_val_if_fail (PANEL_IS_WIDGET (panel_widget), FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + applet = g_object_get_data (G_OBJECT (widget), MATE_PANEL_APPLET_DATA); + if (applet) { + GList *applet_list, *l; + int end_pos = -1; + + applet_list = g_list_find (panel_widget->applet_list, applet); + + for (l = applet_list; l; l = l->next) { + applet = l->data; + + if (end_pos != -1 && applet->pos != end_pos) + break; + + end_pos = applet->pos + applet->cells; + if (end_pos >= panel_widget->size) + return TRUE; + } + } + + return FALSE; +} + +static int +get_size_from_hints (AppletData *ad, int cells) +{ + int i; + + for (i = 0; i < ad->size_hints_len; i += 2) { + if (cells > ad->size_hints[i]) { + /* Clip to top */ + cells = ad->size_hints[i]; + break; + } + if (cells <= ad->size_hints[i] && + cells >= ad->size_hints[i+1]) { + /* Keep cell size */ + break; + } + } + + return MAX (cells, ad->min_cells); +} + +static void +panel_widget_jump_applet_right (PanelWidget *panel, + GList *list, + GList *next, + int pos) +{ + AppletData *ad; + AppletData *nad = NULL; + + ad = list->data; + if (next) + nad = next->data; + + if (pos >= panel->size) + return; + + if (!nad || nad->constrained >= pos + ad->min_cells) + goto jump_right; + + if (!panel_widget_push_applet_right (panel, next, pos + ad->min_cells - nad->constrained)) { + panel_widget_jump_applet_right (panel, + list, + next->next, + nad->constrained + nad->min_cells); + return; + } + + jump_right: + ad->pos = ad->constrained = pos; + panel->applet_list = g_list_remove_link (panel->applet_list, list); + panel->applet_list = panel_g_list_insert_before (panel->applet_list, next, list); + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); +} + +static void +panel_widget_switch_applet_right (PanelWidget *panel, + GList *list) +{ + AppletData *ad; + AppletData *nad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (ad->constrained + ad->min_cells >= panel->size) + return; + + if (list->next) + nad = list->next->data; + + if (!nad || nad->constrained >= ad->constrained + ad->min_cells + MOVE_INCREMENT) { + ad->pos = ad->constrained += MOVE_INCREMENT; + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); + return; + } + + if (nad->locked) { + panel_widget_jump_applet_right (panel, + list, + list->next->next, + nad->constrained + nad->min_cells); + return; + } + + nad->constrained = nad->pos = ad->constrained; + ad->constrained = ad->pos = ad->constrained + nad->min_cells; + panel->applet_list = panel_g_list_swap_next (panel->applet_list, list); + + gtk_widget_queue_resize (GTK_WIDGET (panel)); + + emit_applet_moved (panel, ad); + emit_applet_moved (panel, nad); +} + +static void +panel_widget_jump_applet_left (PanelWidget *panel, + GList *list, + GList *prev, + int pos) +{ + AppletData *ad; + AppletData *pad = NULL; + + ad = list->data; + if (prev) + pad = prev->data; + + if (pos < 0) + return; + + if (!pad || pad->constrained + pad->min_cells <= pos) + goto jump_left; + + if (!panel_widget_push_applet_left (panel, prev, pad->constrained + pad->min_cells - pos)) { + panel_widget_jump_applet_left (panel, + list, + prev->prev, + pad->constrained - ad->min_cells); + return; + } + + jump_left: + ad->pos = ad->constrained = pos; + panel->applet_list = g_list_remove_link (panel->applet_list, list); + panel->applet_list = panel_g_list_insert_after (panel->applet_list, prev, list); + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); +} + +static void +panel_widget_switch_applet_left (PanelWidget *panel, + GList *list) +{ + AppletData *ad; + AppletData *pad = NULL; + + ad = list->data; + if (ad->constrained <= 0) + return; + + if (list->prev) + pad = list->prev->data; + + if (!pad || pad->constrained + pad->min_cells <= ad->constrained - MOVE_INCREMENT) { + ad->pos = ad->constrained -= MOVE_INCREMENT; + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); + return; + } + + if (pad->locked) { + panel_widget_jump_applet_left (panel, + list, + list->prev->prev, + pad->constrained - ad->min_cells); + return; + } + + ad->constrained = ad->pos = pad->constrained; + pad->constrained = pad->pos = ad->constrained + ad->min_cells; + panel->applet_list = panel_g_list_swap_prev (panel->applet_list, list); + + gtk_widget_queue_resize (GTK_WIDGET (panel)); + + emit_applet_moved (panel, ad); + emit_applet_moved (panel, pad); +} + +static gboolean +panel_widget_try_push_right (PanelWidget *panel, + GList *list, + int push) +{ + AppletData *ad; + AppletData *nad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (list->next) + nad = list->next->data; + + if (ad->locked) + return FALSE; + + if (ad->constrained + ad->min_cells + push >= panel->size) + return FALSE; + + if (!nad || nad->constrained >= ad->constrained + ad->min_cells + push) + return TRUE; + + return panel_widget_try_push_right (panel, list->next, push); +} + +static int +panel_widget_get_right_jump_pos (PanelWidget *panel, + AppletData *ad, + GList *next, + int pos) +{ + AppletData *nad = NULL; + + if (next) + nad = next->data; + + if (!nad || nad->constrained >= pos + ad->min_cells) + return pos; + + if (panel_widget_try_push_right (panel, next, pos + ad->min_cells - nad->constrained)) + return pos; + + return panel_widget_get_right_jump_pos (panel, + ad, + next->next, + nad->constrained + nad->min_cells); +} + +static int +panel_widget_get_right_switch_pos (PanelWidget *panel, + GList *list) +{ + AppletData *ad; + AppletData *nad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (list->next) + nad = list->next->data; + + if (!nad || nad->constrained >= ad->constrained + ad->min_cells + MOVE_INCREMENT) + return ad->constrained + MOVE_INCREMENT; + + if (nad->locked) + return panel_widget_get_right_jump_pos (panel, + ad, + list->next->next, + nad->constrained + nad->min_cells); + + return nad->constrained + nad->min_cells - ad->cells; +} + +static gboolean +panel_widget_try_push_left (PanelWidget *panel, + GList *list, + int push) +{ + AppletData *ad; + AppletData *pad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (list->prev) + pad = list->prev->data; + + if (ad->locked) + return FALSE; + + if (ad->constrained - push < 0) + return FALSE; + + if (!pad || pad->constrained + pad->min_cells <= ad->constrained - push) + return TRUE; + + return panel_widget_try_push_left (panel, list->prev, push); +} + +static int +panel_widget_get_left_jump_pos (PanelWidget *panel, + AppletData *ad, + GList *prev, + int pos) +{ + AppletData *pad = NULL; + + if (prev) + pad = prev->data; + + if (!pad || pad->constrained + pad->min_cells <= pos) + return pos; + + if (panel_widget_try_push_left (panel, prev, pad->constrained + pad->min_cells - pos)) + return pos; + + return panel_widget_get_left_jump_pos (panel, + ad, + prev->prev, + pad->constrained - ad->min_cells); +} + +static int +panel_widget_get_left_switch_pos (PanelWidget *panel, + GList *list) +{ + AppletData *ad; + AppletData *pad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (list->prev) + pad = list->prev->data; + + if (!pad || pad->constrained + pad->min_cells <= ad->constrained - MOVE_INCREMENT) + return ad->constrained - MOVE_INCREMENT; + + if (pad->locked) + return panel_widget_get_left_jump_pos (panel, + ad, + list->prev->prev, + pad->constrained - ad->min_cells); + + return pad->constrained; +} + +static void +panel_widget_switch_move (PanelWidget *panel, + AppletData *ad, + int moveby) +{ + GList *list; + int finalpos; + int pos; + + g_return_if_fail (ad != NULL); + g_return_if_fail (PANEL_IS_WIDGET (panel)); + + if (moveby == 0) + return; + + list = g_list_find (panel->applet_list, ad); + g_return_if_fail (list != NULL); + + finalpos = ad->constrained + moveby; + + if (ad->constrained < finalpos) { + AppletData *pad; + + if (list->prev) { + pad = list->prev->data; + if (pad->expand_major) + gtk_widget_queue_resize (GTK_WIDGET (panel)); + } + + while (ad->constrained < finalpos) { + pos = panel_widget_get_right_switch_pos (panel, list); + + if (abs (pos - finalpos) >= abs (ad->constrained - finalpos) || + pos + ad->min_cells > panel->size) + break; + + panel_widget_switch_applet_right (panel, list); + } + + if (list->prev) { + pad = list->prev->data; + if (pad->expand_major) + gtk_widget_queue_resize (GTK_WIDGET (panel)); + } + } else { + AppletData *nad; + + if (list->next) { + nad = list->next->data; + if (nad->expand_major) + gtk_widget_queue_resize (GTK_WIDGET (panel)); + } + + while (ad->constrained > finalpos) { + pos = panel_widget_get_left_switch_pos (panel, list); + + if (abs (pos - finalpos) >= abs (ad->constrained - finalpos) || pos < 0) + break; + + panel_widget_switch_applet_left (panel, list); + } + + } +} + +static int +panel_widget_push_applet_right (PanelWidget *panel, + GList *list, + int push) +{ + AppletData *ad; + AppletData *nad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (ad->constrained + ad->min_cells + push >= panel->size) + return FALSE; + + if (ad->locked) + return FALSE; + + if (list->next) + nad = list->next->data; + + if (!nad || nad->constrained >= ad->constrained + ad->min_cells + push) { + ad->pos = ad->constrained += push; + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); + return TRUE; + } + + g_assert (list->next != NULL); + + if (!panel_widget_push_applet_right (panel, list->next, push)) + return FALSE; + + ad->pos = ad->constrained += push;; + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); + + return TRUE; +} + +static int +panel_widget_push_applet_left (PanelWidget *panel, + GList *list, + int push) +{ + AppletData *ad; + AppletData *pad = NULL; + + g_assert (list != NULL); + + ad = list->data; + if (ad->constrained - push < 0) + return FALSE; + + if (ad->locked) + return FALSE; + + if (list->prev) + pad = list->prev->data; + + if (!pad || pad->constrained + pad->min_cells <= ad->constrained - push) { + ad->pos = ad->constrained -= push; + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); + return TRUE; + } + + g_assert (list->prev != NULL); + + if (!panel_widget_push_applet_left (panel, list->prev, push)) + return FALSE; + + ad->pos = ad->constrained -= push; + gtk_widget_queue_resize (GTK_WIDGET (panel)); + emit_applet_moved (panel, ad); + + return TRUE; +} + +static void +panel_widget_push_move (PanelWidget *panel, + AppletData *ad, + int moveby) +{ + AppletData *pad; + int finalpos; + GList *list; + + g_return_if_fail (ad != NULL); + g_return_if_fail (PANEL_IS_WIDGET (panel)); + + if (moveby == 0) + return; + + list = g_list_find (panel->applet_list, ad); + g_return_if_fail (list != NULL); + + finalpos = ad->constrained + moveby; + + if (ad->constrained < finalpos) { + while (ad->constrained < finalpos) + if (!panel_widget_push_applet_right (panel, list, 1)) + break; + + if (list->prev) { + pad = list->prev->data; + if (pad->expand_major) + gtk_widget_queue_resize (GTK_WIDGET (panel)); + } + } else { + while (ad->constrained > finalpos) + if (!panel_widget_push_applet_left (panel, list, 1)) + break; + } +} + + +/*this is a special function and may fail if called improperly, it works +only under special circumstance when we know there is nothing from +old_size to panel->size*/ +static void +panel_widget_right_stick(PanelWidget *panel,int old_size) +{ + int i,pos; + GList *list,*prev; + AppletData *ad; + + g_return_if_fail(PANEL_IS_WIDGET(panel)); + g_return_if_fail(old_size>=0); + + if(old_size>=panel->size || + panel->packed) + return; + + list = get_applet_list_pos(panel,old_size-1); + + if(!list) + return; + + pos = panel->size-1; + + ad = list->data; + do { + i = ad->pos; + ad->pos = ad->constrained = pos--; + ad->cells = 1; + prev = list; + list = g_list_previous(list); + if(!list) + break; + ad = list->data; + } while(ad->pos + ad->cells == i); + + for (list = prev; list; list = list->next) + emit_applet_moved (panel, list->data); +} + +static void +panel_widget_size_request(GtkWidget *widget, GtkRequisition *requisition) +{ + PanelWidget *panel; + GList *list; + GList *ad_with_hints; + gboolean dont_fill; + + g_return_if_fail(PANEL_IS_WIDGET(widget)); + g_return_if_fail(requisition!=NULL); + + panel = PANEL_WIDGET(widget); + + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) { + requisition->width = 0; + requisition->height = panel->sz; + } else { + requisition->height = 0; + requisition->width = panel->sz; + } + + ad_with_hints = NULL; + + for(list = panel->applet_list; list!=NULL; list = g_list_next(list)) { + AppletData *ad = list->data; + GtkRequisition chreq; + gtk_widget_size_request(ad->applet,&chreq); + + if (panel->orient == GTK_ORIENTATION_HORIZONTAL) { + if (requisition->height < chreq.height && !ad->size_constrained) + requisition->height = chreq.height; + + if (panel->packed && ad->expand_major && ad->size_hints) + ad_with_hints = g_list_prepend (ad_with_hints, + ad); + + else if (panel->packed) + requisition->width += chreq.width; + } else { + if (requisition->width < chreq.width && !ad->size_constrained) + requisition->width = chreq.width; + + if (panel->packed && ad->expand_major && ad->size_hints) + ad_with_hints = g_list_prepend (ad_with_hints, + ad); + + else if (panel->packed) + requisition->height += chreq.height; + } + } + + + panel->nb_applets_size_hints = 0; + if (panel->applets_hints != NULL) + g_free (panel->applets_hints); + panel->applets_hints = NULL; + if (panel->applets_using_hint != NULL) + g_free (panel->applets_using_hint); + panel->applets_using_hint = NULL; + + if(!panel->packed) { + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) { + requisition->width = panel->size; + } else { + requisition->height = panel->size; + } + } else { + /* put the list in the correct order: this is important + * since we'll use this order in the size_allocate() */ + ad_with_hints = g_list_reverse (ad_with_hints); + + panel->nb_applets_size_hints = g_list_length (ad_with_hints); + if (panel->nb_applets_size_hints > 0) { + int i; + panel->applets_hints = g_new0 (AppletSizeHints, panel->nb_applets_size_hints); + + i = 0; + for (list = ad_with_hints; + list != NULL; + list = g_list_next (list)) { + AppletData *ad = list->data; + + panel->applets_hints[i].hints = ad->size_hints; + panel->applets_hints[i].len = ad->size_hints_len; + i++; + } + + panel->applets_using_hint = g_new0 (AppletSizeHintsAlloc, panel->nb_applets_size_hints); + } + } + + dont_fill = panel->packed && panel->nb_applets_size_hints != 0; + + if (panel->orient == GTK_ORIENTATION_HORIZONTAL) { + if (requisition->width < 12 && !dont_fill) + requisition->width = 12; + if (requisition->height < 12) + requisition->height = 12; + } else { + if (requisition->width < 12) + requisition->width = 12; + if (requisition->height < 12 && !dont_fill) + requisition->height = 12; + } +} + +static void +queue_resize_on_all_applets(PanelWidget *panel) +{ + GList *li; + for(li = panel->applet_list; li != NULL; + li = g_list_next(li)) { + AppletData *ad = li->data; + gtk_widget_queue_resize (ad->applet); + } +} + +static void +panel_widget_set_background_region (PanelWidget *panel) +{ + GtkWidget *widget; + int origin_x = -1, origin_y = -1; + GtkAllocation allocation; + + widget = GTK_WIDGET (panel); + + if (!gtk_widget_get_realized (widget)) + return; + + gdk_window_get_origin (gtk_widget_get_window (widget), &origin_x, &origin_y); + + gtk_widget_get_allocation (widget, &allocation); + + panel_background_change_region ( + &panel->background, panel->orient, + origin_x, origin_y, + allocation.width, + allocation.height); +} + +static void +panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation) +{ + PanelWidget *panel; + GList *list; + int i; + int old_size; + gboolean ltr; + + g_return_if_fail(PANEL_IS_WIDGET(widget)); + g_return_if_fail(allocation!=NULL); + + panel = PANEL_WIDGET(widget); + + old_size = panel->size; + ltr = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR; + + gtk_widget_set_allocation (widget, allocation); + if (gtk_widget_get_realized (widget)) + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) + panel->size = allocation->width; + else + panel->size = allocation->height; + if(old_sizesize) + panel_widget_right_stick(panel,old_size); + + if (panel->packed) { + /* we're assuming the order is the same as the one that was + * in size_request() */ + int applet_using_hint_index = 0; + + i = 0; + for(list = panel->applet_list; + list!=NULL; + list = g_list_next(list)) { + AppletData *ad = list->data; + GtkAllocation challoc; + GtkRequisition chreq; + gtk_widget_get_child_requisition(ad->applet,&chreq); + + ad->constrained = i; + + challoc.width = chreq.width; + challoc.height = chreq.height; + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) { + if (ad->expand_minor) + challoc.height = allocation->height; + + if (ad->expand_major && ad->size_hints) { + int width = panel->applets_using_hint[applet_using_hint_index].size; + applet_using_hint_index++; + challoc.width = MIN (width, allocation->width - i); + } + + ad->cells = challoc.width; + challoc.x = ltr ? ad->constrained : panel->size - ad->constrained - challoc.width; + challoc.y = allocation->height / 2 - challoc.height / 2; + } else { + if (ad->expand_minor) + challoc.width = allocation->width; + + if (ad->expand_major && ad->size_hints) { + int height = panel->applets_using_hint[applet_using_hint_index].size; + applet_using_hint_index++; + challoc.height = MIN (height, allocation->height - i); + } + + ad->cells = challoc.height; + challoc.x = allocation->width / 2 - challoc.width / 2; + challoc.y = ad->constrained; + } + ad->min_cells = ad->cells; + gtk_widget_size_allocate(ad->applet,&challoc); + i += ad->cells; + } + + /* EEEEK, there might be not enough room and we don't handle + * it: all the applets at the right well be unusable */ + + } else { /*not packed*/ + + /* First make sure there's enough room on the left */ + i = 0; + for (list = panel->applet_list; + list != NULL; + list = g_list_next (list)) { + AppletData *ad = list->data; + GtkRequisition chreq; + + gtk_widget_get_child_requisition(ad->applet,&chreq); + + if (!ad->expand_major || !ad->size_hints) { + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) + ad->cells = chreq.width; + else + ad->cells = chreq.height; + + ad->min_cells = ad->cells; + } else { + ad->cells = ad->size_hints [ad->size_hints_len - 1]; + ad->min_cells = ad->size_hints [ad->size_hints_len - 1]; + } + + ad->constrained = ad->pos; + + if (ad->constrained < i) + ad->constrained = i; + + i = ad->constrained + ad->cells; + } + + /* Now expand from the right */ + i = panel->size; + for(list = g_list_last(panel->applet_list); + list!=NULL; + list = g_list_previous(list)) { + AppletData *ad = list->data; + int cells; + + if (ad->constrained + ad->min_cells > i) + ad->constrained = MAX (i - ad->min_cells, 0); + + if (ad->expand_major) { + cells = (i - ad->constrained) - 1; + + if (ad->size_hints) + cells = get_size_from_hints (ad, cells); + cells = MAX (cells, ad->min_cells); + cells = MIN (cells, panel->size); + + ad->cells = cells; + } + + i = ad->constrained; + } + + /* EEEEK, there's not enough room, so shift applets even + * at the expense of perhaps running out of room on the + * right if there is no free space in the middle */ + if(i < 0) { + i = 0; + for(list = panel->applet_list; + list!=NULL; + list = g_list_next(list)) { + AppletData *ad = list->data; + + if (ad->constrained < i) + ad->constrained = i; + + i = ad->constrained + ad->cells; + } + } + + for(list = panel->applet_list; + list!=NULL; + list = g_list_next(list)) { + AppletData *ad = list->data; + GtkAllocation challoc; + GtkRequisition chreq; + gtk_widget_get_child_requisition(ad->applet,&chreq); + challoc.width = chreq.width; + challoc.height = chreq.height; + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) { + challoc.width = ad->cells; + if (ad->expand_minor) { + challoc.height = allocation->height; + } + challoc.x = ltr ? ad->constrained : panel->size - ad->constrained - challoc.width; + challoc.y = allocation->height / 2 - challoc.height / 2; + } else { + challoc.height = ad->cells; + if (ad->expand_minor) { + challoc.width = allocation->width; + } + challoc.x = allocation->width / 2 - challoc.width / 2; + challoc.y = ad->constrained; + } + + gtk_widget_size_allocate(ad->applet,&challoc); + } + } + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) + panel->thick = allocation->height; + else + panel->thick = allocation->width; + + panel_widget_set_background_region (panel); +} + +gboolean +panel_widget_is_cursor(PanelWidget *panel, int overlap) +{ + GtkWidget *widget; + GtkAllocation allocation; + int x,y; + int w,h; + + g_return_val_if_fail(PANEL_IS_WIDGET(panel),FALSE); + + widget = panel->drop_widget; + + if(!widget || + !GTK_IS_WIDGET(widget) || + !gtk_widget_get_visible(widget)) + return FALSE; + + gtk_widget_get_pointer(widget, &x, &y); + + gtk_widget_get_allocation (widget, &allocation); + w = allocation.width; + h = allocation.height; + + if((x+overlap)>=0 && + (x-overlap)<=w && + (y+overlap)>=0 && + (y-overlap)<=h) + return TRUE; + return FALSE; +} + +static void +panel_widget_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + GtkStyle *style; + GtkStateType state; + + if (gtk_widget_get_realized (widget)) { + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + + panel_background_set_default_style ( + &PANEL_WIDGET (widget)->background, + &style->bg [state], + style->bg_pixmap [state]); + } +} + +static void +panel_widget_state_changed (GtkWidget *widget, + GtkStateType previous_state) +{ + GtkStyle *style; + GtkStateType state; + + if (gtk_widget_get_realized (widget)) { + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + + panel_background_set_default_style ( + &PANEL_WIDGET (widget)->background, + &style->bg [state], + style->bg_pixmap [state]); + } +} + +static gboolean +toplevel_configure_event (GtkWidget *widget, + GdkEventConfigure *event, + PanelWidget *panel) +{ + panel_widget_set_background_region (panel); + + return FALSE; +} + +static void +panel_widget_realize (GtkWidget *widget) +{ + PanelWidget *panel = (PanelWidget *) widget; + GdkWindow *window; + GtkStyle *style; + GtkStateType state; + + g_signal_connect (panel->toplevel, "configure-event", + G_CALLBACK (toplevel_configure_event), panel); + + GTK_WIDGET_CLASS (panel_widget_parent_class)->realize (widget); + + window = gtk_widget_get_window (widget); + style = gtk_widget_get_style (widget); + state = gtk_widget_get_state (widget); + + /* For auto-hidden panels with a colored background, we need native + * windows to avoid some uglyness on unhide */ + gdk_window_ensure_native (window); + + panel_background_set_default_style ( + &panel->background, + &style->bg [state], + style->bg_pixmap [state]); + + panel_background_realized (&panel->background, window); +} + +static void +panel_widget_unrealize (GtkWidget *widget) +{ + PanelWidget *panel = (PanelWidget *) widget; + + panel_background_unrealized (&panel->background); + + g_signal_handlers_disconnect_by_func ( + panel->toplevel, + G_CALLBACK (toplevel_configure_event), + panel); + + GTK_WIDGET_CLASS (panel_widget_parent_class)->unrealize (widget); +} + +static void +panel_widget_finalize (GObject *obj) +{ + PanelWidget *panel; + + g_return_if_fail (PANEL_IS_WIDGET (obj)); + + panel = PANEL_WIDGET (obj); + + panel_background_free (&panel->background); + + if (panel->applets_hints != NULL) + g_free (panel->applets_hints); + panel->applets_hints = NULL; + if (panel->applets_using_hint != NULL) + g_free (panel->applets_using_hint); + panel->applets_using_hint = NULL; + + + G_OBJECT_CLASS (panel_widget_parent_class)->finalize (obj); +} + +static void +panel_widget_open_dialog_destroyed (PanelWidget *panel_widget, + GtkWidget *dialog) +{ + g_return_if_fail (panel_widget->open_dialogs != NULL); + + panel_widget->open_dialogs = g_slist_remove (panel_widget->open_dialogs, dialog); +} + +static void +panel_widget_destroy_open_dialogs (PanelWidget *panel_widget) +{ + GSList *l, *list; + + list = panel_widget->open_dialogs; + panel_widget->open_dialogs = NULL; + + for (l = list; l; l = l->next) { + g_signal_handlers_disconnect_by_func (G_OBJECT (l->data), + G_CALLBACK (panel_widget_open_dialog_destroyed), + panel_widget); + gtk_widget_destroy (l->data); + } + g_slist_free (list); + +} + +static void +panel_widget_destroy (GtkObject *obj) +{ + PanelWidget *panel; + + g_return_if_fail (PANEL_IS_WIDGET (obj)); + + panel = PANEL_WIDGET (obj); + + panels = g_slist_remove (panels, panel); + + panel_widget_destroy_open_dialogs (panel); + + if (panel->master_widget != NULL) { + g_object_set_data (G_OBJECT (panel->master_widget), + MATE_PANEL_APPLET_ASSOC_PANEL_KEY, + NULL); + g_object_remove_weak_pointer (G_OBJECT (panel->master_widget), + (gpointer *) &panel->master_widget); + panel->master_widget = NULL; + } + + if (GTK_OBJECT_CLASS (panel_widget_parent_class)->destroy) + GTK_OBJECT_CLASS (panel_widget_parent_class)->destroy (obj); +} + +static void +panel_widget_init (PanelWidget *panel) +{ + GtkWidget *widget = (GtkWidget *) panel; + + gtk_widget_set_events ( + widget, + gtk_widget_get_events (widget) | GDK_BUTTON_RELEASE_MASK); + + panel->packed = FALSE; + panel->orient = GTK_ORIENTATION_HORIZONTAL; + panel->thick = PANEL_MINIMUM_WIDTH; + panel->size = G_MAXINT; + panel->applet_list = NULL; + panel->master_widget = NULL; + panel->drop_widget = widget; + panel->open_dialogs = NULL; + + panel->nb_applets_size_hints = 0; + panel->applets_hints = NULL; + panel->applets_using_hint = NULL; + + panel_background_init (&panel->background, + (PanelBackgroundChangedNotify) panel_widget_background_changed, + panel); + + panels = g_slist_append (panels, panel); +} + +GtkWidget * +panel_widget_new (PanelToplevel *toplevel, + gboolean packed, + GtkOrientation orient, + int sz) +{ + PanelWidget *panel; + + panel = g_object_new (PANEL_TYPE_WIDGET, NULL); + + gtk_widget_set_has_window (GTK_WIDGET (panel), TRUE); + gtk_widget_set_can_focus (GTK_WIDGET (panel), TRUE); + + panel->orient = orient; + panel->sz = sz; + + panel->packed = packed; + if (packed) + panel->size = 0; + else + panel->size = G_MAXINT; + + panel->toplevel = toplevel; + panel->drop_widget = GTK_WIDGET (toplevel); + + return GTK_WIDGET (panel); +} + +static guint moving_timeout = 0; +static gboolean been_moved = FALSE; +static gboolean repeat_if_outside = FALSE; + +static gboolean +panel_widget_applet_drag_start_no_grab (PanelWidget *panel, + GtkWidget *applet, + int drag_off) +{ + AppletData *ad; + AppletInfo *info; + + g_return_val_if_fail (PANEL_IS_WIDGET (panel), FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (panel), FALSE); + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + g_return_val_if_fail (ad != NULL, FALSE); + + if (ad->locked) + return FALSE; + + /* Check if we can actually move this object in the + configuration */ + info = g_object_get_data (G_OBJECT (applet), "applet_info"); + if (info != NULL && + ! mate_panel_applet_can_freely_move (info)) + return FALSE; + + if (moving_timeout != 0) { + g_source_remove (moving_timeout); + moving_timeout = 0; + been_moved = FALSE; + } + +#ifdef PANEL_WIDGET_DEBUG + g_message("Starting drag on a %s at %p\n", + g_type_name(G_TYPE_FROM_INSTANCE (applet)), applet); +#endif + panel->currently_dragged_applet = ad; + if (drag_off == PW_DRAG_OFF_CURSOR) + ad->drag_off = panel_widget_get_cursorloc (panel) - ad->constrained; + else if (drag_off == PW_DRAG_OFF_CENTER) + ad->drag_off = ad->cells / 2; + else + ad->drag_off = drag_off; + + add_all_move_bindings (panel); + + mate_panel_applet_in_drag = TRUE; + + return TRUE; +} + + +static void +panel_widget_applet_drag_end_no_grab (PanelWidget *panel) +{ + g_return_if_fail (panel != NULL); + g_return_if_fail (PANEL_IS_WIDGET (panel)); + +#ifdef PANEL_WIDGET_DEBUG + g_message("Ending drag\n"); +#endif + panel->currently_dragged_applet = NULL; + mate_panel_applet_in_drag = FALSE; + + remove_all_move_bindings (panel); + if (moving_timeout != 0) { + g_source_remove (moving_timeout); + moving_timeout = 0; + been_moved = FALSE; + } +} + +void +panel_widget_applet_drag_start (PanelWidget *panel, + GtkWidget *applet, + int drag_off, + guint32 time_) +{ + GdkWindow *window; + + g_return_if_fail (PANEL_IS_WIDGET (panel)); + g_return_if_fail (GTK_IS_WIDGET (applet)); + +#ifdef PANEL_WIDGET_DEBUG + g_message("Starting drag [grabbed] on a %s at %p\n", + g_type_name(G_TYPE_FROM_INSTANCE(applet)), applet); +#endif + + if (!panel_widget_applet_drag_start_no_grab (panel, applet, drag_off)) + return; + + panel_toplevel_push_autohide_disabler (panel->toplevel); + + gtk_grab_add (applet); + + window = gtk_widget_get_window (applet); + if (window) { + GdkGrabStatus status; + GdkCursor *fleur_cursor; + + fleur_cursor = gdk_cursor_new (GDK_FLEUR); + + status = gdk_pointer_grab (window, FALSE, + APPLET_EVENT_MASK, NULL, + fleur_cursor, time_); + + gdk_cursor_unref (fleur_cursor); + gdk_flush (); + + if (status != GDK_GRAB_SUCCESS) { + g_warning (G_STRLOC ": failed to grab pointer (errorcode: %d)", + status); + panel_widget_applet_drag_end (panel); + } + } +} + +void +panel_widget_applet_drag_end (PanelWidget *panel) +{ + g_return_if_fail (PANEL_IS_WIDGET (panel)); + + if (panel->currently_dragged_applet == NULL) + return; + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gtk_grab_remove (panel->currently_dragged_applet->applet); + panel_widget_applet_drag_end_no_grab (panel); + panel_toplevel_pop_autohide_disabler (panel->toplevel); + gdk_flush (); +} + +/*get pos of the cursor location in panel coordinates*/ +int +panel_widget_get_cursorloc (PanelWidget *panel) +{ + int x, y; + gboolean rtl; + + g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1); + + gtk_widget_get_pointer (GTK_WIDGET (panel), &x, &y); + rtl = gtk_widget_get_direction (GTK_WIDGET (panel)) == GTK_TEXT_DIR_RTL; + + if (panel->orient == GTK_ORIENTATION_HORIZONTAL) + return (rtl ? panel->size - x : x); + else + return y; +} + +/*calculates the value to move the applet by*/ +static int +panel_widget_get_moveby (PanelWidget *panel, int pos, int offset) +{ + g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1); + + return panel_widget_get_cursorloc (panel) - offset - pos; +} + +static GList * +walk_up_to (int pos, GList *list) +{ + AppletData *ad; + + g_return_val_if_fail (list != NULL, NULL); + + ad = list->data; + + if (ad->constrained <= pos && + ad->constrained + ad->cells > pos) + return list; + while (list->next != NULL && + ad->constrained + ad->cells <= pos) { + list = list->next; + ad = list->data; + } + while (list->prev != NULL && + ad->constrained > pos) { + list = list->prev; + ad = list->data; + } + return list; +} + +static GtkWidget * +is_in_applet (int pos, AppletData *ad) +{ + g_return_val_if_fail (ad != NULL, NULL); + + if (ad->constrained <= pos && + ad->constrained + ad->min_cells > pos) + return ad->applet; + return NULL; +} + +static int +panel_widget_get_free_spot (PanelWidget *panel, + AppletData *ad, + int place) +{ + int i, e; + int start; + int right = -1, left = -1; + GList *list; + + g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1); + g_return_val_if_fail (ad != NULL, -1); + + if (ad->constrained >= panel->size) + return -1; + + if (panel->applet_list == NULL) { + if (place + ad->min_cells > panel->size) + return panel->size-ad->min_cells; + else + return place; + } + + list = panel->applet_list; + + start = place - ad->drag_off; + if (start < 0) + start = 0; + for (e = 0, i = start; i < panel->size; i++) { + GtkWidget *applet; + list = walk_up_to (i, list); + applet = is_in_applet (i, list->data); + if (applet == NULL || + applet == ad->applet) { + e++; + if (e >= ad->min_cells) { + right = i - e + 1; + break; + } + } else { + e = 0; + } + } + + start = place + ad->drag_off; + if (start >= panel->size) + start = panel->size - 1; + for (e = 0, i = start; i >= 0; i--) { + GtkWidget *applet; + list = walk_up_to (i, list); + applet = is_in_applet (i, list->data); + if (applet == NULL || + applet == ad->applet) { + e++; + if (e >= ad->min_cells) { + left = i; + break; + } + } else { + e=0; + } + } + + start = place - ad->drag_off; + + if (left == -1) { + if (right == -1) + return -1; + else + return right; + } else { + if (right == -1) + return left; + else + return abs (left - start) > abs (right - start) ? + right : left; + } +} + +static void +panel_widget_nice_move (PanelWidget *panel, + AppletData *ad, + int pos) +{ + g_return_if_fail (PANEL_IS_WIDGET (panel)); + g_return_if_fail (ad != NULL); + + pos = panel_widget_get_free_spot (panel, ad, pos); + if (pos < 0 || pos == ad->pos) + return; + + ad->pos = ad->constrained = pos; + + panel->applet_list = + panel_g_list_resort_item (panel->applet_list, ad, + (GCompareFunc)applet_data_compare); + + gtk_widget_queue_resize (GTK_WIDGET (panel)); + + emit_applet_moved (panel, ad); +} + +/* schedule to run the below function */ +static void schedule_try_move (PanelWidget *panel, gboolean repeater); + +/*find the cursor position and move the applet to that position*/ +static void +panel_widget_applet_move_to_cursor (PanelWidget *panel) +{ + int moveby; + int pos; + int movement; + GtkWidget *applet; + GSList *forb; + GdkModifierType mods; + AppletData *ad; + + g_return_if_fail(PANEL_IS_WIDGET(panel)); + + if (panel->currently_dragged_applet == NULL) + return; + + ad = panel->currently_dragged_applet; + + pos = ad->constrained; + + applet = ad->applet; + g_assert(GTK_IS_WIDGET(applet)); + forb = g_object_get_data (G_OBJECT(applet), + MATE_PANEL_APPLET_FORBIDDEN_PANELS); + + if(!panel_widget_is_cursor(panel,10)) { + GSList *list; + + for(list=panels; + list!=NULL; + list=g_slist_next(list)) { + PanelWidget *new_panel = + PANEL_WIDGET(list->data); + + if (panel != new_panel && + panel_widget_is_cursor (new_panel,10) && + panel_screen_from_panel_widget (panel) == + panel_screen_from_panel_widget (new_panel) && + !g_slist_find (forb, new_panel) && + !panel_lockdown_get_locked_down ()) { + pos = panel_widget_get_moveby (new_panel, 0, ad->drag_off); + + if (pos < 0) pos = 0; + + panel_widget_applet_drag_end (panel); + + /*disable reentrancy into this function*/ + if (!panel_widget_reparent (panel, new_panel, applet, pos)) { + panel_widget_applet_drag_start ( + panel, applet, ad->drag_off, GDK_CURRENT_TIME); + continue; + } + + panel_widget_applet_drag_start ( + new_panel, applet, ad->drag_off, GDK_CURRENT_TIME); + schedule_try_move (new_panel, TRUE); + + return; + } + } + } + + gdk_window_get_pointer(gtk_widget_get_window (GTK_WIDGET(panel)), + NULL,NULL,&mods); + + movement = PANEL_SWITCH_MOVE; + + if (panel->packed) { + movement = PANEL_SWITCH_MOVE; + } else { + if (mods & GDK_CONTROL_MASK) + movement = PANEL_SWITCH_MOVE; + else if (mods & GDK_SHIFT_MASK) + movement = PANEL_PUSH_MOVE; + else if (mods & GDK_MOD1_MASK) + movement = PANEL_FREE_MOVE; + } + + switch (movement) { + case PANEL_SWITCH_MOVE: + moveby = panel_widget_get_moveby (panel, pos, ad->drag_off); + panel_widget_switch_move (panel, ad, moveby); + break; + case PANEL_FREE_MOVE: + panel_widget_nice_move (panel, ad, panel_widget_get_cursorloc (panel)); + break; + case PANEL_PUSH_MOVE: + moveby = panel_widget_get_moveby (panel, pos, ad->drag_off); + panel_widget_push_move (panel, ad, moveby); + break; + } +} + +static int +move_timeout_handler(gpointer data) +{ + PanelWidget *panel = data; + + g_return_val_if_fail(PANEL_IS_WIDGET(data),FALSE); + + if(been_moved && + panel->currently_dragged_applet) { + panel_widget_applet_move_to_cursor(panel); + been_moved = FALSE; + return TRUE; + } + been_moved = FALSE; + + if(panel->currently_dragged_applet && repeat_if_outside) { + GtkWidget *widget; + GtkAllocation allocation; + int x,y; + int w,h; + + widget = panel->currently_dragged_applet->applet; + + gtk_widget_get_pointer(widget, &x, &y); + + gtk_widget_get_allocation (widget, &allocation); + w = allocation.width; + h = allocation.height; + + /* if NOT inside return TRUE, this means we will be + * kept inside the timeout until we hit the damn widget + * or the drag ends */ + if(!(x>=0 && x<=w && y>=0 && y<=h)) + return TRUE; + } + + moving_timeout = 0; + + return FALSE; +} + +static void +schedule_try_move(PanelWidget *panel, gboolean repeater) +{ + if (!panel->currently_dragged_applet) + return; + repeat_if_outside = repeater; + if(moving_timeout == 0) { + been_moved = FALSE; + panel_widget_applet_move_to_cursor(panel); + moving_timeout = + g_timeout_add (50, move_timeout_handler, panel); + } else + been_moved = TRUE; +} + +static gboolean +panel_widget_applet_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + GtkWidget *parent; + PanelWidget *panel; + guint32 event_time; + + parent = gtk_widget_get_parent (widget); + + g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE); + + panel = PANEL_WIDGET (parent); + + /* don't propagate this event */ + if (panel->currently_dragged_applet) { + g_signal_stop_emission (G_OBJECT (widget), + g_signal_lookup ("button-press-event", + G_OBJECT_TYPE (widget)), + 0); + return TRUE; + } + + /* Begin drag if the middle mouse button is pressed, unless the panel + * is locked down or a grab is active (meaning a menu is open) */ + if (panel_lockdown_get_locked_down () || event->button != 2 || + gtk_grab_get_current() != NULL) + return FALSE; + + /* time on sent events seems to be bogus */ + event_time = event->time; + if (event->send_event) + event_time = GDK_CURRENT_TIME; + + panel_widget_applet_drag_start (panel, widget, PW_DRAG_OFF_CURSOR, event_time); + + return TRUE; +} + +static gboolean +panel_widget_applet_button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + GtkWidget *parent; + PanelWidget *panel; + + parent = gtk_widget_get_parent (widget); + + g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE); + + panel = PANEL_WIDGET (parent); + + /* don't propagate this event */ + if (panel->currently_dragged_applet) { + g_signal_stop_emission (G_OBJECT (widget), + g_signal_lookup ("button-release-event", + G_OBJECT_TYPE (widget)), + 0); + panel_widget_applet_drag_end (panel); + return TRUE; + } + + return FALSE; +} + +static gboolean +panel_widget_applet_motion_notify_event (GtkWidget *widget, + GdkEvent *event) +{ + GtkWidget *parent; + PanelWidget *panel; + + parent = gtk_widget_get_parent (widget); + + g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE); + + if (gdk_event_get_screen (event) != gtk_widget_get_screen (widget)) + return FALSE; + + panel = PANEL_WIDGET (parent); + + schedule_try_move (panel, FALSE); + + return FALSE; +} + +static gboolean +panel_widget_applet_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + GtkWidget *parent; + PanelWidget *panel; + + parent = gtk_widget_get_parent (widget); + + g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE); + + panel = PANEL_WIDGET (parent); + + if (!mate_panel_applet_in_drag) + return FALSE; + + return gtk_bindings_activate (GTK_OBJECT (panel), + ((GdkEventKey *)event)->keyval, + ((GdkEventKey *)event)->state); +} + +static int +panel_sub_event_handler(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE); + g_return_val_if_fail(event!=NULL,FALSE); + + switch (event->type) { + /*pass these to the parent!*/ + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_MOTION_NOTIFY: { + GdkEventButton *bevent = (GdkEventButton *)event; + + if (bevent->button != 1 || mate_panel_applet_in_drag) + return gtk_widget_event (data, event); + + } + break; + case GDK_KEY_PRESS: + if (mate_panel_applet_in_drag) + return gtk_widget_event(data, event); + break; + default: + break; + } + + return FALSE; +} + + +static void +bind_applet_events(GtkWidget *widget, gpointer data) +{ + g_return_if_fail(GTK_IS_WIDGET(widget)); + + /* XXX: This is more or less a hack. We need to be able to + * capture events over applets so that we can drag them with + * the mouse and such. So we need to force the applet's + * widgets to recursively send the events back to their parent + * until the event gets to the applet wrapper (the + * GtkEventBox) for processing by us. + */ + + if (gtk_widget_get_has_window (widget)) + g_signal_connect (G_OBJECT(widget), "event", + G_CALLBACK (panel_sub_event_handler), + data); + + if (GTK_IS_CONTAINER(widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + bind_applet_events, data); +} + +static void +panel_widget_applet_destroy (GtkWidget *applet, gpointer data) +{ + AppletData *ad; + GtkWidget *parent; + + g_return_if_fail (GTK_IS_WIDGET (applet)); + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + g_object_set_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA, NULL); + + parent = gtk_widget_get_parent (applet); + /*if it wasn't yet removed*/ + if(parent) { + PanelWidget *panel = PANEL_WIDGET (parent); + + if (panel->currently_dragged_applet == ad) + panel_widget_applet_drag_end (panel); + + panel->applet_list = g_list_remove (panel->applet_list,ad); + } + + g_free (ad->size_hints); + + g_free (ad); +} + +static void +bind_top_applet_events (GtkWidget *widget) +{ + g_return_if_fail(GTK_IS_WIDGET(widget)); + + g_signal_connect (G_OBJECT(widget), "destroy", + G_CALLBACK (panel_widget_applet_destroy), + NULL); + + g_signal_connect (widget, "button-press-event", + G_CALLBACK (panel_widget_applet_button_press_event), + NULL); + + g_signal_connect (widget, "button-release-event", + G_CALLBACK (panel_widget_applet_button_release_event), + NULL); + g_signal_connect (widget, "motion-notify-event", + G_CALLBACK (panel_widget_applet_motion_notify_event), + NULL); + g_signal_connect (widget, "key-press-event", + G_CALLBACK (panel_widget_applet_key_press_event), + NULL); + + /* XXX: This is more or less a hack. We need to be able to + * capture events over applets so that we can drag them with + * the mouse and such. So we need to force the applet's + * widgets to recursively send the events back to their parent + * until the event gets to the applet wrapper (the + * GtkEventBox) for processing by us. + */ + + if (GTK_IS_CONTAINER(widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + bind_applet_events, widget); +} + +static int +panel_widget_find_empty_pos(PanelWidget *panel, int pos) +{ + int i; + int right=-1,left=-1; + GList *list; + + g_return_val_if_fail(PANEL_IS_WIDGET(panel),-1); + + if(pos>=panel->size) + pos = panel->size-1; + + if (pos <= 0) + pos = 0; + + if(!panel->applet_list) + return pos; + + list = panel->applet_list; + + for (i = pos; i < panel->size; i++) { + list = walk_up_to (i, list); + if ( ! is_in_applet (i, list->data)) { + right = i; + break; + } + } + + for(i = pos; i >= 0; i--) { + list = walk_up_to (i, list); + if ( ! is_in_applet (i, list->data)) { + left = i; + break; + } + } + + if (left == -1) { + if (right == -1) + return -1; + else + return right; + } else { + if (right == -1) + return left; + else + return abs (left - pos) > abs (right - pos) ? + right : left; + } +} + +void +panel_widget_add_forbidden (PanelWidget *panel) +{ + g_return_if_fail (panel != NULL); + g_return_if_fail (PANEL_IS_WIDGET (panel)); + + add_panel_to_forbidden (panel, panel); +} + +int +panel_widget_add (PanelWidget *panel, + GtkWidget *applet, + gboolean locked, + int pos, + gboolean insert_at_pos) +{ + AppletData *ad = NULL; + + g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1); + g_return_val_if_fail (GTK_IS_WIDGET (applet), -1); + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + + if (ad != NULL) + pos = ad->pos; + + if (!insert_at_pos || pos < 0) { + if (panel->packed) { + if (get_applet_list_pos (panel, pos)) + /*this is a slight hack so that this applet + is inserted AFTER an applet with this pos + number*/ + pos++; + } else { + int newpos = panel_widget_find_empty_pos (panel, pos); + if (newpos >= 0) + pos = newpos; + else if (get_applet_list_pos (panel, pos)) + /*this is a slight hack so that this applet + is inserted AFTER an applet with this pos + number*/ + pos++; + } + } + + if(pos==-1) return -1; + + if (ad == NULL) { + ad = g_new (AppletData, 1); + ad->applet = applet; + ad->cells = 1; + ad->min_cells = 1; + ad->pos = pos; + ad->constrained = pos; + ad->drag_off = 0; + ad->no_die = 0; + ad->size_constrained = FALSE; + ad->expand_major = FALSE; + ad->expand_minor = FALSE; + ad->locked = locked; + ad->size_hints = NULL; + g_object_set_data (G_OBJECT (applet), + MATE_PANEL_APPLET_DATA, ad); + + /*this is a completely new applet, which was not yet bound*/ + bind_top_applet_events (applet); + } + + panel->applet_list = + g_list_insert_sorted(panel->applet_list,ad, + (GCompareFunc)applet_data_compare); + + /*this will get done right on size allocate!*/ + if(panel->orient == GTK_ORIENTATION_HORIZONTAL) + gtk_fixed_put(GTK_FIXED(panel),applet, + pos,0); + else + gtk_fixed_put(GTK_FIXED(panel),applet, + 0,pos); + + + gtk_widget_queue_resize(GTK_WIDGET(panel)); + + g_signal_emit (G_OBJECT(panel), + panel_widget_signals[APPLET_ADDED_SIGNAL], + 0, applet); + + /*NOTE: forbidden list is not updated on addition, use the + function above for the panel*/ + + return pos; +} + +gboolean +panel_widget_reparent (PanelWidget *old_panel, + PanelWidget *new_panel, + GtkWidget *applet, + int pos) +{ + AppletData *ad; + GtkWidget *focus_widget = NULL; + AppletInfo* info; + + g_return_val_if_fail(PANEL_IS_WIDGET(old_panel), FALSE); + g_return_val_if_fail(PANEL_IS_WIDGET(new_panel), FALSE); + g_return_val_if_fail(GTK_IS_WIDGET(applet), FALSE); + g_return_val_if_fail(pos>=0, FALSE); + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + g_return_val_if_fail(ad!=NULL, FALSE); + + /* Don't try and reparent to an explicitly hidden panel, + * very confusing for the user ... + */ + if (panel_toplevel_get_is_hidden (new_panel->toplevel)) + return FALSE; + + info = g_object_get_data (G_OBJECT (ad->applet), "applet_info"); + + ad->pos = ad->constrained = panel_widget_get_free_spot (new_panel, ad, pos); + if (ad->pos == -1) + ad->pos = ad->constrained = 0; + + gtk_widget_queue_resize (GTK_WIDGET (new_panel)); + gtk_widget_queue_resize (GTK_WIDGET (old_panel)); + + ad->no_die++; + + panel_widget_reset_saved_focus (old_panel); + if (gtk_container_get_focus_child (GTK_CONTAINER (old_panel)) == applet) + focus_widget = gtk_window_get_focus (GTK_WINDOW (old_panel->toplevel)); + gtk_widget_reparent (applet, GTK_WIDGET (new_panel)); + + if (info && info->type == PANEL_OBJECT_APPLET) + mate_panel_applet_frame_set_panel (MATE_PANEL_APPLET_FRAME (ad->applet), new_panel); + + if (gtk_widget_get_can_focus (GTK_WIDGET (new_panel))) + gtk_widget_set_can_focus (GTK_WIDGET (new_panel), FALSE); + if (focus_widget) { + panel_widget_force_grab_focus (focus_widget); + } else { + gboolean return_val; + + g_signal_emit_by_name (applet, "focus", + GTK_DIR_TAB_FORWARD, + &return_val); + } + gtk_window_present (GTK_WINDOW (new_panel->toplevel)); + + gdk_flush(); + + ad->no_die--; + + emit_applet_moved (new_panel, ad); + + return TRUE; +} + +void +panel_widget_set_packed (PanelWidget *panel_widget, + gboolean packed) +{ + panel_widget->packed = packed; + + gtk_widget_queue_resize (GTK_WIDGET (panel_widget)); +} + +void +panel_widget_set_orientation (PanelWidget *panel_widget, + GtkOrientation orientation) +{ + panel_widget->orient = orientation; + + gtk_widget_queue_resize (GTK_WIDGET (panel_widget)); +} + +void +panel_widget_set_size (PanelWidget *panel_widget, + int size) +{ + g_return_if_fail (PANEL_IS_WIDGET (panel_widget)); + + if (size == panel_widget->sz) + return; + + panel_widget->sz = size; + + queue_resize_on_all_applets (panel_widget); + + g_signal_emit (panel_widget, panel_widget_signals [SIZE_CHANGE_SIGNAL], 0); + + gtk_widget_queue_resize (GTK_WIDGET (panel_widget)); +} + +static void +panel_widget_background_changed (PanelBackground *background, + PanelWidget *panel) +{ + g_return_if_fail (PANEL_IS_WIDGET (panel)); + panel_toplevel_update_edges (panel->toplevel); + g_signal_emit (G_OBJECT (panel), + panel_widget_signals [BACK_CHANGE_SIGNAL], + 0); +} + +static void +panel_widget_push_move_applet (PanelWidget *panel, + GtkDirectionType dir) +{ + AppletData *applet; + int increment = 0; + + applet = panel->currently_dragged_applet; + g_return_if_fail (applet); + + switch (dir) { + case GTK_DIR_LEFT: + case GTK_DIR_UP: + increment = -MOVE_INCREMENT; + break; + case GTK_DIR_RIGHT: + case GTK_DIR_DOWN: + increment = MOVE_INCREMENT; + break; + default: + return; + } + + panel_widget_push_move (panel, applet, increment); +} + +static void +panel_widget_switch_move_applet (PanelWidget *panel, + GtkDirectionType dir) +{ + AppletData *applet; + GList *list; + + applet = panel->currently_dragged_applet; + g_return_if_fail (applet != NULL); + + list = g_list_find (panel->applet_list, applet); + g_return_if_fail (list != NULL); + + switch (dir) { + case GTK_DIR_LEFT: + case GTK_DIR_UP: + panel_widget_switch_applet_left (panel, list); + break; + case GTK_DIR_RIGHT: + case GTK_DIR_DOWN: + panel_widget_switch_applet_right (panel, list); + break; + default: + return; + } +} + +static void +panel_widget_free_move_applet (PanelWidget *panel, + GtkDirectionType dir) +{ + AppletData *ad; + gint increment = MOVE_INCREMENT; + + ad = panel->currently_dragged_applet; + + g_return_if_fail (ad); + + switch (dir) { + case GTK_DIR_LEFT: + case GTK_DIR_UP: + increment = -increment; + break; + case GTK_DIR_RIGHT: + case GTK_DIR_DOWN: + break; + default: + return; + } + + panel_widget_nice_move (panel, ad, increment + ad->constrained + ad->drag_off); +} + +static void +panel_widget_tab_move (PanelWidget *panel, + gboolean next) +{ + PanelWidget *new_panel = NULL; + PanelWidget *previous_panel = NULL; + AppletData *ad; + GSList *l; + + ad = panel->currently_dragged_applet; + + if (!ad) + return; + + for (l = panels; l; l = l->next) { + PanelWidget *panel_in_list = l->data; + + if (panel_in_list == panel) { + if (next) { + if (l->next) + new_panel = l->next->data; + else + new_panel = ((GSList *)panels)->data; + + } else { + if (previous_panel) + new_panel = previous_panel; + else + continue; + } + break; + } else { + if (!next) + previous_panel = panel_in_list; + } + } + + g_return_if_fail (l != NULL); + + if (!new_panel && previous_panel) + new_panel = previous_panel; + + if (new_panel && + (new_panel != panel) && + !panel_lockdown_get_locked_down ()) + panel_widget_reparent (panel, new_panel, ad->applet, 0); +} + +static void +panel_widget_end_move (PanelWidget *panel) +{ + panel_widget_applet_drag_end (panel); +} + +static gboolean +panel_widget_real_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + if (gtk_widget_get_can_focus (widget) && gtk_container_get_children (GTK_CONTAINER (widget))) { + gtk_widget_set_can_focus (widget, FALSE); + } + return GTK_WIDGET_CLASS (panel_widget_parent_class)->focus (widget, direction); +} + +void +panel_widget_focus (PanelWidget *panel_widget) +{ + if (panel_toplevel_get_is_attached (panel_widget->toplevel)) + return; + + /* + * Set the focus back on the panel; we unset the focus child so that + * the next time focus is inside the panel we do not remember the + * previously focused child. We also need to set GTK_CAN_FOCUS flag + * on the panel as it is unset when this function is called. + */ + gtk_container_set_focus_child (GTK_CONTAINER (panel_widget), NULL); + gtk_widget_set_can_focus (GTK_WIDGET (panel_widget), TRUE); + gtk_widget_grab_focus (GTK_WIDGET (panel_widget)); +} + + +PanelOrientation +panel_widget_get_applet_orientation (PanelWidget *panel) +{ + g_return_val_if_fail (PANEL_IS_WIDGET (panel), PANEL_ORIENTATION_TOP); + g_return_val_if_fail (PANEL_IS_TOPLEVEL (panel->toplevel), PANEL_ORIENTATION_TOP); + + return panel_toplevel_get_orientation (panel->toplevel); +} + +void +panel_widget_set_applet_size_constrained (PanelWidget *panel, + GtkWidget *applet, + gboolean size_constrained) +{ + AppletData *ad; + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + if (!ad) + return; + + size_constrained = size_constrained != FALSE; + + if (ad->size_constrained == size_constrained) + return; + + ad->size_constrained = size_constrained; + + gtk_widget_queue_resize (GTK_WIDGET (panel)); +} + +void +panel_widget_set_applet_expandable (PanelWidget *panel, + GtkWidget *applet, + gboolean major, + gboolean minor) +{ + AppletData *ad; + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + if (!ad) + return; + + major = major != FALSE; + minor = minor != FALSE; + + if (ad->expand_major == major && ad->expand_minor == minor) + return; + + ad->expand_major = major; + ad->expand_minor = minor; + + gtk_widget_queue_resize (GTK_WIDGET (panel)); +} + +void +panel_widget_set_applet_size_hints (PanelWidget *panel, + GtkWidget *applet, + int *size_hints, + int size_hints_len) +{ + AppletData *ad; + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + if (!ad) + return; + + g_free (ad->size_hints); + + if (size_hints_len > 0 && (size_hints_len % 2 == 0)) { + ad->size_hints = size_hints; + ad->size_hints_len = size_hints_len; + } else { + g_free (size_hints); + ad->size_hints = NULL; + } + + gtk_widget_queue_resize (GTK_WIDGET (panel)); +} + +void +panel_widget_set_applet_locked (PanelWidget *panel, + GtkWidget *applet, + gboolean locked) +{ + AppletData *ad; + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + if (!ad) + return; + + ad->locked = locked; +} + +gboolean +panel_widget_get_applet_locked (PanelWidget *panel, + GtkWidget *applet) +{ + AppletData *ad; + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + if (!ad) + return FALSE; + + return ad->locked; +} + +gboolean +panel_widget_toggle_applet_locked (PanelWidget *panel, + GtkWidget *applet) +{ + AppletData *ad; + + ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA); + if (!ad) + return FALSE; + + return ad->locked = !ad->locked; +} + +gboolean +mate_panel_applet_is_in_drag (void) +{ + return mate_panel_applet_in_drag; +} + +void +panel_widget_register_open_dialog (PanelWidget *panel, + GtkWidget *dialog) +{ + /* the window is for a panel, so it should be shown in the taskbar. See + * HIG: An alert should not appear in the panel window list unless it + * is, or may be, the only window shown by an application. */ + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE); + + panel->open_dialogs = g_slist_append (panel->open_dialogs, + dialog); + + g_signal_connect_object (dialog, "destroy", + G_CALLBACK (panel_widget_open_dialog_destroyed), + panel, + G_CONNECT_SWAPPED); +} diff --git a/mate-panel/panel-widget.h b/mate-panel/panel-widget.h new file mode 100644 index 00000000..c844b217 --- /dev/null +++ b/mate-panel/panel-widget.h @@ -0,0 +1,242 @@ +/* Mate panel: panel widget + * (C) 1997-1998 the Free Software Foundation + * + * Authors: George Lebl + */ +/* This widget, although slightly written as a general purpose widget, it + has MANY interdependencies, which makes it almost impossible to use in + anything else but the panel, what it would need is some serious + cleaning up*/ +#ifndef PANEL_WIDGET_H +#define PANEL_WIDGET_H + + +#include +#include +#include "button-widget.h" +#include "panel-types.h" +#include "panel-background.h" +#include "panel-toplevel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PANEL_TYPE_WIDGET \ + (panel_widget_get_type()) +#define PANEL_WIDGET(object) \ + (G_TYPE_CHECK_INSTANCE_CAST((object), PANEL_TYPE_WIDGET, PanelWidget)) +#define PANEL_WIDGET_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), PANEL_TYPE_WIDGET, PanelWidgetClass)) +#define PANEL_IS_WIDGET(object) \ + (G_TYPE_CHECK_INSTANCE_TYPE((object), PANEL_TYPE_WIDGET)) + +#define PANEL_MINIMUM_WIDTH 12 + +#define MATE_PANEL_APPLET_ASSOC_PANEL_KEY "mate_panel_applet_assoc_panel_key" +#define MATE_PANEL_APPLET_FORBIDDEN_PANELS "mate_panel_applet_forbidden_panels" +#define MATE_PANEL_APPLET_DATA "mate_panel_applet_data" + +#ifndef TYPEDEF_PANEL_WIDGET +typedef struct _PanelWidget PanelWidget; +#define TYPEDEF_PANEL_WIDGET +#endif /* TYPEDEF_PANEL_WIDGET */ + +typedef struct _PanelWidgetClass PanelWidgetClass; + +typedef struct _AppletRecord AppletRecord; +typedef struct _AppletData AppletData; +typedef struct _DNDRecord DNDRecord; + +typedef struct _AppletSizeHints AppletSizeHints; +typedef struct _AppletSizeHintsAlloc AppletSizeHintsAlloc; + +struct _AppletSizeHints { + int *hints; + int len; +}; + +struct _AppletSizeHintsAlloc { + int index; + int size; +}; + +struct _AppletData +{ + GtkWidget * applet; + int pos; + int constrained; + int cells; + int min_cells; + + int drag_off; /* offset on the applet where drag + was started */ + + int no_die; /* if >0 never send the about to die + signal, an int and not a bool for + nesting reasons */ + + /* Valid size ranges for expanded applets */ + int * size_hints; + int size_hints_len; + + guint size_constrained : 1; + guint expand_major : 1; + guint expand_minor : 1; + guint locked : 1; + +}; + +struct _PanelWidget +{ + GtkFixed fixed; + + GList *applet_list; + + GSList *open_dialogs; + + int size; + GtkOrientation orient; + int sz; + + AppletData *currently_dragged_applet; + + int thick; + + PanelBackground background; + + GtkWidget *master_widget; + + GtkWidget *drop_widget; /* widget that the panel checks for + * the cursor on drops usually the + * panel widget itself + */ + + PanelToplevel *toplevel; + + GdkEventKey *key_event; + + /* helpers to get a good size in packed panels with applets using + * size hints */ + int nb_applets_size_hints; + AppletSizeHints *applets_hints; + AppletSizeHintsAlloc *applets_using_hint; + + guint packed : 1; +}; + +struct _PanelWidgetClass +{ + GtkFixedClass parent_class; + + void (* size_change) (PanelWidget *panel); + void (* back_change) (PanelWidget *panel); + void (* applet_move) (PanelWidget *panel, + GtkWidget *applet); + void (* applet_added) (PanelWidget *panel, + GtkWidget *applet); + void (* applet_removed) (PanelWidget *panel, + GtkWidget *applet); + void (* push_move) (PanelWidget *panel, + GtkDirectionType dir); + void (* switch_move) (PanelWidget *panel, + GtkDirectionType dir); + void (* free_move) (PanelWidget *panel, + GtkDirectionType dir); + void (* tab_move) (PanelWidget *panel, + gboolean next); + void (* end_move) (PanelWidget *panel); +}; + +GType panel_widget_get_type (void) G_GNUC_CONST; + +GtkWidget * panel_widget_new (PanelToplevel *toplevel, + gboolean packed, + GtkOrientation orient, + int sz); +/*add an applet to the panel, preferably at position pos, if insert_at_pos + is on, we REALLY want to insert at the pos given by pos*/ +int panel_widget_add (PanelWidget *panel, + GtkWidget *applet, + gboolean locked, + int pos, + gboolean insert_at_pos); + +/*needs to be called for drawers after add*/ +void panel_widget_add_forbidden (PanelWidget *panel); + +/*move applet to a different panel*/ +int panel_widget_reparent (PanelWidget *old_panel, + PanelWidget *new_panel, + GtkWidget *applet, + int pos); + +/* use these for drag_off for special cases */ +#define PW_DRAG_OFF_CURSOR -1 +#define PW_DRAG_OFF_CENTER -2 + +/*drag*/ +gboolean mate_panel_applet_is_in_drag (void); +void panel_widget_applet_drag_start (PanelWidget *panel, + GtkWidget *applet, + int drag_off, + guint32 time_); +void panel_widget_applet_drag_end (PanelWidget *panel); + +void panel_widget_set_packed (PanelWidget *panel_widget, + gboolean packed); +void panel_widget_set_orientation (PanelWidget *panel_widget, + GtkOrientation orientation); +void panel_widget_set_size (PanelWidget *panel_widget, + int size); + +/*draw EVERYTHING (meaning icons)*/ +void panel_widget_draw_all (PanelWidget *panel, + GdkRectangle *area); +/*draw just one icon (applet has to be an icon of course)*/ +void panel_widget_draw_icon (PanelWidget *panel, + ButtonWidget *applet); + + +/*tells us if an applet is "stuck" on the right side*/ +int panel_widget_is_applet_stuck (PanelWidget *panel, + GtkWidget *applet); +/*get pos of the cursor location in panel coordinates*/ +int panel_widget_get_cursorloc (PanelWidget *panel); + +/*needed for other panel types*/ +gboolean panel_widget_is_cursor (PanelWidget *panel, + int overlap); +/* set the focus on the panel */ +void panel_widget_focus (PanelWidget *panel); + +PanelOrientation panel_widget_get_applet_orientation (PanelWidget *panel); + + +void panel_widget_set_applet_size_constrained (PanelWidget *panel, + GtkWidget *applet, + gboolean size_constrained); +void panel_widget_set_applet_expandable (PanelWidget *panel, + GtkWidget *applet, + gboolean major, + gboolean minor); +void panel_widget_set_applet_size_hints (PanelWidget *panel, + GtkWidget *applet, + int *size_hints, + int size_hints_len); + +void panel_widget_set_applet_locked (PanelWidget *panel, + GtkWidget *applet, + gboolean locked); +gboolean panel_widget_get_applet_locked (PanelWidget *panel, + GtkWidget *applet); +gboolean panel_widget_toggle_applet_locked (PanelWidget *panel, + GtkWidget *applet); + +void panel_widget_register_open_dialog (PanelWidget *panel, + GtkWidget *dialog); +#ifdef __cplusplus +} +#endif + +#endif /* PANEL_WIDGET_H */ diff --git a/mate-panel/panel-xutils.c b/mate-panel/panel-xutils.c new file mode 100644 index 00000000..4480f193 --- /dev/null +++ b/mate-panel/panel-xutils.c @@ -0,0 +1,258 @@ +/* + * panel-xutils.c: X related utility methods. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#include "config.h" + +#include "panel-xutils.h" + +#include +#include +#include +#include +#include + +static Atom net_wm_window_type = None; +static Atom net_wm_window_type_dock = None; +static Atom net_wm_window_type_normal = None; +static Atom net_wm_strut = None; +static Atom net_wm_strut_partial = None; + +void +panel_xutils_set_window_type (GdkWindow *gdk_window, + PanelXUtilsWindowType type) +{ + Display *display; + Window window; + Atom atoms [2]; + int i = 0; + + g_return_if_fail (GDK_IS_WINDOW (gdk_window)); + + display = GDK_WINDOW_XDISPLAY (gdk_window); + window = GDK_WINDOW_XWINDOW (gdk_window); + + if (net_wm_window_type == None) + net_wm_window_type = XInternAtom (display, + "_NET_WM_WINDOW_TYPE", + False); + + switch (type) { + case PANEL_XUTILS_TYPE_DOCK: + if (net_wm_window_type_dock == None) + net_wm_window_type_dock = XInternAtom (display, + "_NET_WM_WINDOW_TYPE_DOCK", + False); + atoms [i++] = net_wm_window_type_dock; + break; + case PANEL_XUTILS_TYPE_NORMAL: + if (net_wm_window_type_normal == None) + net_wm_window_type_normal = XInternAtom (display, + "_NET_WM_WINDOW_TYPE_NORMAL", + False); + atoms [i++] = net_wm_window_type_normal; + break; + default: + g_assert_not_reached (); + break; + } + + gdk_error_trap_push (); + XChangeProperty (display, window, net_wm_window_type, + XA_ATOM, 32, PropModeReplace, + (guchar *) &atoms, i); + gdk_error_trap_pop (); +} + +enum { + STRUT_LEFT = 0, + STRUT_RIGHT = 1, + STRUT_TOP = 2, + STRUT_BOTTOM = 3, + STRUT_LEFT_START = 4, + STRUT_LEFT_END = 5, + STRUT_RIGHT_START = 6, + STRUT_RIGHT_END = 7, + STRUT_TOP_START = 8, + STRUT_TOP_END = 9, + STRUT_BOTTOM_START = 10, + STRUT_BOTTOM_END = 11 +}; + +void +panel_xutils_set_strut (GdkWindow *gdk_window, + PanelOrientation orientation, + guint32 strut, + guint32 strut_start, + guint32 strut_end) + { + Display *display; + Window window; + gulong struts [12] = { 0, }; + + g_return_if_fail (GDK_IS_WINDOW (gdk_window)); + + display = GDK_WINDOW_XDISPLAY (gdk_window); + window = GDK_WINDOW_XWINDOW (gdk_window); + + if (net_wm_strut == None) + net_wm_strut = XInternAtom (display, "_NET_WM_STRUT", False); + if (net_wm_strut_partial == None) + net_wm_strut_partial = XInternAtom (display, "_NET_WM_STRUT_PARTIAL", False); + + switch (orientation) { + case PANEL_ORIENTATION_LEFT: + struts [STRUT_LEFT] = strut; + struts [STRUT_LEFT_START] = strut_start; + struts [STRUT_LEFT_END] = strut_end; + break; + case PANEL_ORIENTATION_RIGHT: + struts [STRUT_RIGHT] = strut; + struts [STRUT_RIGHT_START] = strut_start; + struts [STRUT_RIGHT_END] = strut_end; + break; + case PANEL_ORIENTATION_TOP: + struts [STRUT_TOP] = strut; + struts [STRUT_TOP_START] = strut_start; + struts [STRUT_TOP_END] = strut_end; + break; + case PANEL_ORIENTATION_BOTTOM: + struts [STRUT_BOTTOM] = strut; + struts [STRUT_BOTTOM_START] = strut_start; + struts [STRUT_BOTTOM_END] = strut_end; + break; + } + + gdk_error_trap_push (); + XChangeProperty (display, window, net_wm_strut, + XA_CARDINAL, 32, PropModeReplace, + (guchar *) &struts, 4); + XChangeProperty (display, window, net_wm_strut_partial, + XA_CARDINAL, 32, PropModeReplace, + (guchar *) &struts, 12); + gdk_error_trap_pop (); +} + +void +panel_warp_pointer (GdkWindow *gdk_window, + int x, + int y) +{ + Display *display; + Window window; + + g_return_if_fail (GDK_IS_WINDOW (gdk_window)); + + display = GDK_WINDOW_XDISPLAY (gdk_window); + window = GDK_WINDOW_XWINDOW (gdk_window); + + gdk_error_trap_push (); + XWarpPointer (display, None, window, 0, 0, 0, 0, x, y); + gdk_error_trap_pop (); +} + +guint +panel_get_real_modifier_mask (guint mask) +{ + guint real_mask; + Display *display; + int i, min_keycode, max_keycode, keysyms_per_keycode; + int max_keycodes_per_modifier; + KeySym *keysyms_for_keycodes; + XModifierKeymap *modifier_keymap; + + real_mask = mask & ((Mod5Mask << 1) - 1); + + /* Already real */ + if (mask == real_mask) { + return mask; + } + + display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + + XDisplayKeycodes (display, &min_keycode, &max_keycode); + keysyms_for_keycodes = XGetKeyboardMapping (display, + min_keycode, + max_keycode - min_keycode + 1, + &keysyms_per_keycode); + + modifier_keymap = XGetModifierMapping (display); + max_keycodes_per_modifier = modifier_keymap->max_keypermod; + + /* Loop through all the modifiers and find out which "real" + * (Mod2..Mod5) modifiers Super, Hyper, and Meta are mapped to. + * Note, Mod1 is used by the Alt modifier */ + for (i = Mod2MapIndex * max_keycodes_per_modifier; + i < (Mod5MapIndex + 1) * max_keycodes_per_modifier; + i++) { + int keycode; + int j; + KeySym *keysyms_for_keycode; + int map_index; + int map_mask; + + keycode = modifier_keymap->modifiermap[i]; + + /* The array is sparse, there may be some + * empty entries. Filter those out + * (along with any invalid entries) */ + if (keycode < min_keycode || keycode > max_keycode) + continue; + + keysyms_for_keycode = keysyms_for_keycodes + + (keycode - min_keycode) * keysyms_per_keycode; + + map_index = i / max_keycodes_per_modifier; + + g_assert (map_index <= Mod5MapIndex); + + map_mask = 1 << map_index; + + for (j = 0; j < keysyms_per_keycode; j++) { + switch (keysyms_for_keycode[j]) { + case XK_Super_L: + case XK_Super_R: + if (mask & GDK_SUPER_MASK) + real_mask |= map_mask; + break; + case XK_Hyper_L: + case XK_Hyper_R: + if (mask & GDK_HYPER_MASK) + real_mask |= map_mask; + break; + case XK_Meta_L: + case XK_Meta_R: + if (mask & GDK_META_MASK) + real_mask |= map_mask; + break; + default: + break; + } + } + } + + XFreeModifiermap (modifier_keymap); + XFree (keysyms_for_keycodes); + + return real_mask; +} diff --git a/mate-panel/panel-xutils.h b/mate-panel/panel-xutils.h new file mode 100644 index 00000000..76c559c8 --- /dev/null +++ b/mate-panel/panel-xutils.h @@ -0,0 +1,64 @@ +/* + * panel-xutils.h: X related utility methods. + * + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __PANEL_XUTILS_H__ +#define __PANEL_XUTILS_H__ + +#include +#include +#include + +#include + +#include "panel-enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PANEL_XUTILS_TYPE_NORMAL, + PANEL_XUTILS_TYPE_DOCK +} PanelXUtilsWindowType; + +void panel_xutils_set_window_type (GdkWindow *gdk_window, + PanelXUtilsWindowType type); + +void panel_xutils_set_strut (GdkWindow *gdk_window, + PanelOrientation orientation, + guint32 strut, + guint32 strut_start, + guint32 strut_end); + +void panel_warp_pointer (GdkWindow *gdk_window, + int x, + int y); + +guint panel_get_real_modifier_mask (guint modifier_mask); + +#ifdef __cplusplus +} +#endif + +#endif /* __PANEL_XUTILS_H__ */ diff --git a/mate-panel/panel.c b/mate-panel/panel.c new file mode 100644 index 00000000..5f2a9666 --- /dev/null +++ b/mate-panel/panel.c @@ -0,0 +1,1403 @@ +/* Mate panel: Initialization routines + * (C) 1997,1998,1999,2000 the Free Software Foundation + * (C) 2000 Eazel, Inc. + * + * Authors: Federico Mena + * Miguel de Icaza + * George Lebl + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "panel.h" + +#include "applet.h" +#include "drawer.h" +#include "button-widget.h" +#include "launcher.h" +#include "panel-context-menu.h" +#include "panel-util.h" +#include "panel-config-global.h" +#include "panel-mateconf.h" +#include "panel-profile.h" +#include "mate-panel-applet-frame.h" +#include "panel-action-button.h" +#include "panel-menu-bar.h" +#include "panel-separator.h" +#include "panel-compatibility.h" +#include "panel-multiscreen.h" +#include "panel-toplevel.h" +#include "panel-menu-button.h" +#include "panel-globals.h" +#include "panel-lockdown.h" +#include "panel-icon-names.h" + +enum { + TARGET_URL, + TARGET_NETSCAPE_URL, + TARGET_DIRECTORY, + TARGET_COLOR, + TARGET_APPLET, + TARGET_APPLET_INTERNAL, + TARGET_ICON_INTERNAL, + TARGET_BGIMAGE, + TARGET_BACKGROUND_RESET +}; + +/*we call this recursively*/ +static void orient_change_foreach(GtkWidget *w, gpointer data); + +void +orientation_change (AppletInfo *info, + PanelWidget *panel) +{ + PanelOrientation orientation; + + orientation = panel_widget_get_applet_orientation (panel); + + switch (info->type) { + case PANEL_OBJECT_APPLET: + mate_panel_applet_frame_change_orientation ( + MATE_PANEL_APPLET_FRAME (info->widget), orientation); + break; + case PANEL_OBJECT_MENU: + case PANEL_OBJECT_LAUNCHER: + case PANEL_OBJECT_ACTION: + button_widget_set_orientation (BUTTON_WIDGET (info->widget), orientation); + break; + case PANEL_OBJECT_MENU_BAR: + panel_menu_bar_set_orientation (PANEL_MENU_BAR (info->widget), orientation); + break; + case PANEL_OBJECT_DRAWER: { + Drawer *drawer = info->data; + PanelWidget *panel_widget; + + panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel); + + button_widget_set_orientation (BUTTON_WIDGET (info->widget), orientation); + + gtk_widget_queue_resize (GTK_WIDGET (drawer->toplevel)); + gtk_container_foreach (GTK_CONTAINER (panel_widget), + orient_change_foreach, + panel_widget); + } + break; + case PANEL_OBJECT_SEPARATOR: + panel_separator_set_orientation (PANEL_SEPARATOR (info->widget), + orientation); + break; + default: + break; + } +} + +static void +orient_change_foreach(GtkWidget *w, gpointer data) +{ + AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info"); + PanelWidget *panel = data; + + orientation_change(info,panel); +} + + +static void +panel_orient_change (GtkWidget *widget, gpointer data) +{ + gtk_container_foreach(GTK_CONTAINER(widget), + orient_change_foreach, + widget); +} + +/*we call this recursively*/ +static void size_change_foreach(GtkWidget *w, gpointer data); + +void +size_change (AppletInfo *info, + PanelWidget *panel) +{ + if (info->type == PANEL_OBJECT_APPLET) + mate_panel_applet_frame_change_size ( + MATE_PANEL_APPLET_FRAME (info->widget), panel->sz); +} + +static void +size_change_foreach(GtkWidget *w, gpointer data) +{ + AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info"); + PanelWidget *panel = data; + + size_change(info,panel); +} + + +static void +panel_size_change (GtkWidget *widget, gpointer data) +{ + gtk_container_foreach(GTK_CONTAINER(widget), size_change_foreach, + widget); +} + +void +back_change (AppletInfo *info, + PanelWidget *panel) +{ + switch (info->type) { + case PANEL_OBJECT_APPLET: + mate_panel_applet_frame_change_background ( + MATE_PANEL_APPLET_FRAME (info->widget), panel->background.type); + break; + case PANEL_OBJECT_MENU_BAR: + panel_menu_bar_change_background (PANEL_MENU_BAR (info->widget)); + break; + case PANEL_OBJECT_SEPARATOR: + panel_separator_change_background (PANEL_SEPARATOR (info->widget)); + break; + default: + break; + } +} + +static void +back_change_foreach (GtkWidget *widget, + PanelWidget *panel) +{ + AppletInfo *info; + + info = g_object_get_data (G_OBJECT (widget), "applet_info"); + + back_change (info, panel); +} + +static void +panel_back_change (GtkWidget *widget, gpointer data) +{ + gtk_container_foreach (GTK_CONTAINER (widget), + (GtkCallback) back_change_foreach, + widget); + +#ifdef FIXME_FOR_NEW_CONFIG + /*update the configuration box if it is displayed*/ + update_config_back(PANEL_WIDGET(widget)); +#endif /* FIXME_FOR_NEW_CONFIG */ +} + +static void +mate_panel_applet_added(GtkWidget *widget, GtkWidget *applet, gpointer data) +{ + AppletInfo *info; + + info = g_object_get_data (G_OBJECT (applet), "applet_info"); + + orientation_change(info,PANEL_WIDGET(widget)); + size_change(info,PANEL_WIDGET(widget)); + back_change(info,PANEL_WIDGET(widget)); +} + +static void +mate_panel_applet_removed(GtkWidget *widget, GtkWidget *applet, gpointer data) +{ + PanelToplevel *toplevel; + AppletInfo *info; + + toplevel = PANEL_WIDGET (widget)->toplevel; + info = g_object_get_data (G_OBJECT (applet), "applet_info"); + + if (info->type == PANEL_OBJECT_DRAWER) { + Drawer *drawer = info->data; + + if (drawer->toplevel) + panel_toplevel_queue_auto_hide (toplevel); + } +} + +static gboolean +deactivate_idle (gpointer data) +{ + PanelData *pd = data; + pd->deactivate_idle = 0; + + pd->insertion_pos = -1; + + return FALSE; +} + +static void +context_menu_deactivate (GtkWidget *w, + PanelData *pd) +{ + if (pd->deactivate_idle == 0) + pd->deactivate_idle = g_idle_add (deactivate_idle, pd); + + panel_toplevel_pop_autohide_disabler (PANEL_TOPLEVEL (pd->panel)); +} + +static void +context_menu_show (GtkWidget *w, + PanelData *pd) +{ + panel_toplevel_push_autohide_disabler (PANEL_TOPLEVEL (pd->panel)); +} + +static void +panel_recreate_context_menu (PanelData *pd) +{ + if (pd->menu) + g_object_unref (pd->menu); + pd->menu = NULL; +} + +static void +panel_destroy (PanelToplevel *toplevel, + PanelData *pd) +{ + panel_lockdown_notify_remove (G_CALLBACK (panel_recreate_context_menu), + pd); + + if (pd->menu) { + g_signal_handlers_disconnect_by_func (pd->menu, + context_menu_deactivate, + pd); + g_object_unref (pd->menu); + } + pd->menu = NULL; + + pd->panel = NULL; + + if (pd->deactivate_idle != 0) + g_source_remove (pd->deactivate_idle); + pd->deactivate_idle = 0; + + g_object_set_data (G_OBJECT (toplevel), "PanelData", NULL); + + panel_list = g_slist_remove (panel_list, pd); + g_free (pd); +} + +static void +mate_panel_applet_move(PanelWidget *panel, GtkWidget *widget, gpointer data) +{ + AppletInfo *info; + + info = g_object_get_data (G_OBJECT (widget), "applet_info"); + + g_return_if_fail (info); + + mate_panel_applet_save_position (info, info->id, FALSE); +} + +static GtkWidget * +panel_menu_get (PanelWidget *panel, PanelData *pd) +{ + if (!pd->menu) { + pd->menu = g_object_ref_sink (panel_context_menu_create (panel)); + g_signal_connect (pd->menu, "deactivate", + G_CALLBACK (context_menu_deactivate), + pd); + g_signal_connect (pd->menu, "show", + G_CALLBACK (context_menu_show), pd); + } + + return pd->menu; +} + +static GtkWidget * +make_popup_panel_menu (PanelWidget *panel_widget) +{ + PanelData *pd; + GtkWidget *menu; + + if (!panel_widget) { + PanelToplevel *toplevel; + + toplevel = PANEL_TOPLEVEL (((PanelData *) panel_list->data)->panel); + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + } + + pd = g_object_get_data (G_OBJECT (panel_widget->toplevel), "PanelData"); + menu = panel_menu_get (panel_widget, pd); + g_object_set_data (G_OBJECT (menu), "menu_panel", panel_widget); + + return menu; +} + +static gboolean +panel_popup_menu (PanelToplevel *toplevel, + guint button, + guint32 activate_time) +{ + PanelWidget *panel_widget; + GtkWidget *menu; + PanelData *panel_data; + GdkEvent *current_event; + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + panel_data = g_object_get_data (G_OBJECT (toplevel), "PanelData"); + + current_event = gtk_get_current_event (); + if (current_event->type == GDK_BUTTON_PRESS) + panel_data->insertion_pos = panel_widget_get_cursorloc (panel_widget); + else + panel_data->insertion_pos = -1; + + menu = make_popup_panel_menu (panel_widget); + if (!menu) + return FALSE; + + gtk_menu_set_screen (GTK_MENU (menu), + gtk_window_get_screen (GTK_WINDOW (toplevel))); + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, activate_time); + + return TRUE; +} + +static gboolean +panel_popup_menu_signal (PanelToplevel *toplevel) +{ + return panel_popup_menu (toplevel, 3, GDK_CURRENT_TIME); +} + +static gboolean +panel_button_press_event (PanelToplevel *toplevel, + GdkEventButton *event) +{ + if (event->button != 3) + return FALSE; + + return panel_popup_menu (toplevel, event->button, event->time); +} + +static gboolean +panel_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + /* + * If the focus widget is a GtkSocket, i.e. the + * focus is in an applet in another process, then key + * bindings do not work. We get around this by + * activating the key bindings here. + */ + if (GTK_IS_SOCKET (gtk_window_get_focus (GTK_WINDOW (widget))) && + event->keyval == GDK_F10 && + (event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK) + return gtk_bindings_activate (GTK_OBJECT (widget), + event->keyval, + event->state); + + return FALSE; +} + +static gboolean +set_background_image_from_uri (PanelToplevel *toplevel, + const char *uri) +{ + char *image; + + if ( ! panel_profile_is_writable_background_type (toplevel) || + ! panel_profile_is_writable_background_image (toplevel)) + return FALSE; + + if (!(image = g_filename_from_uri (uri, NULL, NULL))) + return FALSE; + + panel_profile_set_background_image (toplevel, image); + panel_profile_set_background_type (toplevel, PANEL_BACK_IMAGE); + + g_free (image); + + return FALSE; +} + +static gboolean +set_background_color (PanelToplevel *toplevel, + guint16 *dropped) +{ + PanelColor color; + + if (!dropped) + return FALSE; + + if ( ! panel_profile_is_writable_background_type (toplevel) || + ! panel_profile_is_writable_background_color (toplevel)) + return FALSE; + + color.gdk.red = dropped [0]; + color.gdk.green = dropped [1]; + color.gdk.blue = dropped [2]; + color.alpha = 65535; + + panel_profile_set_background_color (toplevel, &color); + panel_profile_set_background_type (toplevel, PANEL_BACK_COLOR); + + return TRUE; +} + +static gboolean +drop_url (PanelWidget *panel, + int position, + const char *url) +{ + enum { + NETSCAPE_URL_URL, + NETSCAPE_URL_NAME + }; + char **netscape_url; + char *name; + char *comment; + + g_return_val_if_fail (url != NULL, FALSE); + + if (!panel_profile_id_lists_are_writable ()) + return FALSE; + + netscape_url = g_strsplit (url, "\n", 2); + if (!netscape_url || + PANEL_GLIB_STR_EMPTY (netscape_url[NETSCAPE_URL_URL])) { + g_strfreev (netscape_url); + return FALSE; + } + + comment = g_strdup_printf (_("Open URL: %s"), + netscape_url[NETSCAPE_URL_URL]); + + if (PANEL_GLIB_STR_EMPTY (netscape_url[NETSCAPE_URL_NAME])) + name = netscape_url[NETSCAPE_URL_URL]; + else + name = netscape_url[NETSCAPE_URL_NAME]; + + panel_launcher_create_from_info (panel->toplevel, position, FALSE, + netscape_url[NETSCAPE_URL_URL], + name, comment, PANEL_ICON_REMOTE); + + g_free (comment); + g_strfreev (netscape_url); + + return TRUE; +} + +static gboolean +drop_menu (PanelWidget *panel, + int position, + const char *menu_filename, + const char *menu_path) +{ + if (!panel_profile_id_lists_are_writable ()) + return FALSE; + + return panel_menu_button_create (panel->toplevel, + position, + menu_filename, + menu_path, + menu_path != NULL, + NULL); + +} + +static gboolean +drop_uri (PanelWidget *panel, + int position, + const char *uri, + const char *fallback_icon) +{ + char *name; + char *comment; + char *buf; + char *icon; + GFile *file; + + if (!panel_profile_id_lists_are_writable ()) + return FALSE; + + name = panel_util_get_label_for_uri (uri); + icon = panel_util_get_icon_for_uri (uri); + if (!icon) + icon = g_strdup (fallback_icon); + + /* FIXME: we might get icons like "folder-music" that might not exist in + * the icon theme. This would usually be okay if we could use fallback + * icons (and get "folder" this way). However, this is not possible for + * launchers: this could be an application that uses an icon named + * folder-magic-app, for which we don't want fallbacks. We just want to + * go to hicolor. */ + + file = g_file_new_for_uri (uri); + buf = g_file_get_parse_name (file); + g_object_unref (file); + /* Translators: %s is a URI */ + comment = g_strdup_printf (_("Open '%s'"), buf); + g_free (buf); + + panel_launcher_create_from_info (panel->toplevel, position, FALSE, + uri, name, comment, icon); + + g_free (name); + g_free (comment); + g_free (icon); + + return TRUE; +} + +static gboolean +drop_caja_desktop_uri (PanelWidget *panel, + int pos, + const char *uri) +{ + gboolean success; + const char *id; + const char *basename; + + if (g_ascii_strncasecmp (uri, "x-caja-desktop:///", + strlen ("x-caja-desktop:///")) != 0) + return FALSE; + + success = TRUE; + id = panel_profile_get_toplevel_id (panel->toplevel); + basename = uri + strlen ("x-caja-desktop:///"); + + if (strncmp (basename, "trash", strlen ("trash")) == 0) + mate_panel_applet_frame_create (panel->toplevel, pos, + "OAFIID:MATE_Panel_TrashApplet"); + else if (strncmp (basename, "home", strlen ("home")) == 0) + panel_launcher_create_with_id (id, pos, + "caja-home.desktop"); + else if (strncmp (basename, "computer", strlen ("computer")) == 0) + panel_launcher_create_with_id (id, pos, + "caja-computer.desktop"); + else if (strncmp (basename, "network", strlen ("network")) == 0) + panel_launcher_create_with_id (id, pos, + "caja-scheme.desktop"); + else + success = FALSE; + + return success; +} + +static gboolean +drop_urilist (PanelWidget *panel, + int pos, + char *urilist) +{ + char **uris; + gboolean success; + int i; + + uris = g_uri_list_extract_uris (urilist); + + success = TRUE; + for (i = 0; uris[i]; i++) { + GFile *file; + GFileInfo *info; + const char *uri; + + uri = uris[i]; + + if (g_ascii_strncasecmp (uri, "http:", strlen ("http:")) == 0 || + g_ascii_strncasecmp (uri, "https:", strlen ("https:")) == 0 || + g_ascii_strncasecmp (uri, "ftp:", strlen ("ftp:")) == 0 || + g_ascii_strncasecmp (uri, "gopher:", strlen ("gopher:")) == 0 || + g_ascii_strncasecmp (uri, "ghelp:", strlen ("ghelp:")) == 0 || + g_ascii_strncasecmp (uri, "man:", strlen ("man:")) == 0 || + g_ascii_strncasecmp (uri, "info:", strlen ("info:")) == 0) { + /* FIXME: probably do this only on link, + * in fact, on link always set up a link, + * on copy do all the other stuff. Or something. */ + if ( ! drop_url (panel, pos, uri)) + success = FALSE; + continue; + } + + if (g_ascii_strncasecmp (uri, "x-caja-desktop:", + strlen ("x-caja-desktop:")) == 0) { + success = drop_caja_desktop_uri (panel, pos, uri); + continue; + } + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, + "standard::type," + "standard::content-type," + "access::can-execute", + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + + if (info) { + const char *mime; + GFileType type; + gboolean can_exec; + + mime = g_file_info_get_content_type (info); + type = g_file_info_get_file_type (info); + can_exec = g_file_info_get_attribute_boolean (info, + G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE); + + if (mime && + g_str_has_prefix (mime, "image")) { + if (!set_background_image_from_uri (panel->toplevel, uri)) + success = FALSE; + } else if (mime && + (!strcmp (mime, "application/x-mate-app-info") || + !strcmp (mime, "application/x-desktop") || + !strcmp (mime, "application/x-kde-app-info"))) { + if (panel_profile_id_lists_are_writable ()) + panel_launcher_create (panel->toplevel, pos, uri); + else + success = FALSE; + } else if (type != G_FILE_TYPE_DIRECTORY && can_exec) { + char *filename; + + filename = g_file_get_path (file); + + if (panel_profile_id_lists_are_writable ()) + /* executable and local, so add a + * launcher with it */ + ask_about_launcher (filename, panel, + pos, TRUE); + else + success = FALSE; + g_free (filename); + } else { + if (!drop_uri (panel, pos, uri, + PANEL_ICON_UNKNOWN)) + success = FALSE; + } + } else { + if (!drop_uri (panel, pos, uri, PANEL_ICON_UNKNOWN)) + success = FALSE; + } + + g_object_unref (info); + g_object_unref (file); + } + + g_strfreev (uris); + + return success; +} + +static gboolean +drop_internal_icon (PanelWidget *panel, + int pos, + const char *icon_name, + int action) +{ + Launcher *old_launcher = NULL; + + if (!icon_name) + return FALSE; + + if (!panel_profile_id_lists_are_writable ()) + return FALSE; + + if (action == GDK_ACTION_MOVE) + old_launcher = find_launcher (icon_name); + + if (!panel_launcher_create_copy (panel->toplevel, pos, icon_name)) + return FALSE; + + if (old_launcher && old_launcher->button) { + if (old_launcher->prop_dialog) { + g_signal_handler_disconnect (old_launcher->button, + old_launcher->destroy_handler); + launcher_properties_destroy (old_launcher); + } + panel_profile_delete_object (old_launcher->info); + } + + return TRUE; +} + +static gboolean +move_applet (PanelWidget *panel, int pos, int applet_index) +{ + GSList *applet_list; + AppletInfo *info; + GtkWidget *parent; + + applet_list = mate_panel_applet_list_applets (); + + info = g_slist_nth_data (applet_list, applet_index); + + if ( ! mate_panel_applet_can_freely_move (info)) + return FALSE; + + if (pos < 0) + pos = 0; + + parent = gtk_widget_get_parent (info->widget); + + if (info != NULL && + info->widget != NULL && + parent != NULL && + PANEL_IS_WIDGET (parent)) { + GSList *forb; + forb = g_object_get_data (G_OBJECT (info->widget), + MATE_PANEL_APPLET_FORBIDDEN_PANELS); + if ( ! g_slist_find (forb, panel)) + panel_widget_reparent (PANEL_WIDGET (parent), + panel, + info->widget, + pos); + } + + return TRUE; +} + +static gboolean +drop_internal_applet (PanelWidget *panel, int pos, const char *applet_type, + int action) +{ + int applet_index = -1; + gboolean remove_applet = FALSE; + gboolean success = FALSE; + + if (applet_type == NULL) + return FALSE; + + if (sscanf (applet_type, "MENU:%d", &applet_index) == 1 || + sscanf (applet_type, "DRAWER:%d", &applet_index) == 1) { + if (action != GDK_ACTION_MOVE) + g_warning ("Only MOVE supported for menus/drawers"); + success = move_applet (panel, pos, applet_index); + + } else if (strncmp (applet_type, "MENU:", strlen ("MENU:")) == 0) { + const char *menu; + const char *menu_path; + + menu = &applet_type[strlen ("MENU:")]; + menu_path = strchr (menu, '/'); + + if (!menu_path) { + if (strncmp (menu, "MAIN", strlen ("MAIN")) == 0) + success = drop_menu (panel, pos, NULL, NULL); + else + success = drop_menu (panel, pos, menu, NULL); + } else { + char *menu_filename; + + menu_filename = g_strndup (menu, menu_path - menu); + menu_path++; + success = drop_menu (panel, pos, + menu_filename, menu_path); + g_free (menu_filename); + } + + } else if (!strcmp (applet_type, "DRAWER:NEW")) { + if (panel_profile_id_lists_are_writable ()) { + panel_drawer_create (panel->toplevel, pos, NULL, FALSE, NULL); + success = TRUE; + } else { + success = FALSE; + } + + } else if (!strncmp (applet_type, "ACTION:", strlen ("ACTION:"))) { + if (panel_profile_id_lists_are_writable ()) { + remove_applet = panel_action_button_load_from_drag ( + panel->toplevel, + pos, + applet_type, + &applet_index); + success = TRUE; + } else { + success = FALSE; + } + + } else if (!strcmp (applet_type, "MENUBAR:NEW")) { + if (panel_profile_id_lists_are_writable ()) { + panel_menu_bar_create (panel->toplevel, pos); + success = TRUE; + } else { + success = FALSE; + } + + } else if (!strcmp(applet_type,"SEPARATOR:NEW")) { + if (panel_profile_id_lists_are_writable ()) { + panel_separator_create (panel->toplevel, pos); + success = TRUE; + } else { + success = FALSE; + } + + } else if (!strcmp(applet_type,"LAUNCHER:ASK")) { + if (panel_profile_id_lists_are_writable ()) { + ask_about_launcher (NULL, panel, pos, TRUE); + success = TRUE; + } else { + success = FALSE; + } + } + + if (remove_applet && + action == GDK_ACTION_MOVE) { + AppletInfo *info; + GSList *applet_list; + + applet_list = mate_panel_applet_list_applets (); + + info = g_slist_nth_data (applet_list, applet_index); + + if (info) + panel_profile_delete_object (info); + } + + return success; +} + +static GtkTargetList * +get_target_list (void) +{ + static GtkTargetEntry drop_types [] = { + { "text/uri-list", 0, TARGET_URL }, + { "x-url/http", 0, TARGET_NETSCAPE_URL }, + { "x-url/ftp", 0, TARGET_NETSCAPE_URL }, + { "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL }, + { "application/x-panel-directory", 0, TARGET_DIRECTORY }, + { "application/x-mate-panel-applet-iid", 0, TARGET_APPLET }, + { "application/x-mate-panel-applet-internal", 0, TARGET_APPLET_INTERNAL }, + { "application/x-panel-icon-internal", 0, TARGET_ICON_INTERNAL }, + { "application/x-color", 0, TARGET_COLOR }, + { "property/bgimage", 0, TARGET_BGIMAGE }, + { "x-special/mate-reset-background", 0, TARGET_BACKGROUND_RESET }, + }; + static GtkTargetList *target_list = NULL; + + if (!target_list) { + gint length = sizeof (drop_types) / sizeof (drop_types [0]); + + target_list = gtk_target_list_new (drop_types, length); + } + + return target_list; +} + +gboolean +panel_check_dnd_target_data (GtkWidget *widget, + GdkDragContext *context, + guint *ret_info, + GdkAtom *ret_atom) +{ + GList *l; + + g_return_val_if_fail (widget, FALSE); + + if (!PANEL_IS_TOPLEVEL (widget) && + !BUTTON_IS_WIDGET (widget)) + return FALSE; + + if (!(gdk_drag_context_get_actions (context) & (GDK_ACTION_COPY|GDK_ACTION_MOVE))) + return FALSE; + + for (l = gdk_drag_context_list_targets (context); l; l = l->next) { + GdkAtom atom; + guint info; + + atom = GDK_POINTER_TO_ATOM (l->data); + + if (gtk_target_list_find (get_target_list (), atom, &info)) { + if (ret_info) + *ret_info = info; + + if (ret_atom) + *ret_atom = atom; + break; + } + } + + return l ? TRUE : FALSE; +} + +static void +do_highlight (GtkWidget *widget, gboolean highlight) +{ + gboolean have_drag; + + /* FIXME: what's going on here ? How are we highlighting + * the toplevel widget ? I don't think we are ... + */ + + have_drag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), + "have-drag")); + if(highlight) { + if(!have_drag) { + g_object_set_data (G_OBJECT (widget), "have-drag", + GINT_TO_POINTER (TRUE)); + gtk_drag_highlight (widget); + } + } else { + if(have_drag) { + g_object_set_data (G_OBJECT (widget), + "have-drag", NULL); + gtk_drag_unhighlight (widget); + } + } +} + +gboolean +panel_check_drop_forbidden (PanelWidget *panel, + GdkDragContext *context, + guint info, + guint time_) +{ + if (!panel) + return FALSE; + + if (panel_lockdown_get_locked_down ()) + return FALSE; + + if (info == TARGET_APPLET_INTERNAL) { + GtkWidget *source_widget; + + source_widget = gtk_drag_get_source_widget (context); + + if (BUTTON_IS_WIDGET (source_widget)) { + GSList *forb; + + forb = g_object_get_data (G_OBJECT (source_widget), + MATE_PANEL_APPLET_FORBIDDEN_PANELS); + + if (g_slist_find (forb, panel)) + return FALSE; + } + } + + if (info == TARGET_ICON_INTERNAL || + info == TARGET_APPLET_INTERNAL) { + if (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) + gdk_drag_status (context, GDK_ACTION_MOVE, time_); + else + gdk_drag_status (context, + gdk_drag_context_get_suggested_action (context), + time_); + + } else if (gdk_drag_context_get_actions (context) & GDK_ACTION_COPY) + gdk_drag_status (context, GDK_ACTION_COPY, time_); + else + gdk_drag_status (context, + gdk_drag_context_get_suggested_action (context), + time_); + + return TRUE; + +} + +static gboolean +drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + PanelToplevel *toplevel; + PanelWidget *panel_widget; + guint info; + + g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE); + + if (!panel_check_dnd_target_data (widget, context, &info, NULL)) + return FALSE; + + toplevel = PANEL_TOPLEVEL (widget); + panel_widget = panel_toplevel_get_panel_widget (toplevel); + + if (!panel_check_drop_forbidden (panel_widget, context, info, time)) + return FALSE; + + do_highlight (widget, TRUE); + + panel_toplevel_unhide (toplevel); + + return TRUE; +} + +static gboolean +drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + Launcher *launcher) +{ + GdkAtom ret_atom = NULL; + + if (!panel_check_dnd_target_data (widget, context, NULL, &ret_atom)) + return FALSE; + + gtk_drag_get_data (widget, context, ret_atom, time); + + return TRUE; +} + +static void +drag_leave_cb (GtkWidget *widget, + GdkDragContext *context, + guint time, + Launcher *launcher) +{ + PanelToplevel *toplevel; + + do_highlight (widget, FALSE); + + toplevel = PANEL_TOPLEVEL (widget); + panel_toplevel_queue_auto_hide (toplevel); +} + +void +panel_receive_dnd_data (PanelWidget *panel, + guint info, + int pos, + GtkSelectionData *selection_data, + GdkDragContext *context, + guint time_) +{ + const guchar *data; + gboolean success = FALSE; + + if (panel_lockdown_get_locked_down ()) { + gtk_drag_finish (context, FALSE, FALSE, time_); + return; + } + + data = gtk_selection_data_get_data (selection_data); + + switch (info) { + case TARGET_URL: + success = drop_urilist (panel, pos, (char *)data); + break; + case TARGET_NETSCAPE_URL: + success = drop_url (panel, pos, (char *)data); + break; + case TARGET_COLOR: + success = set_background_color (panel->toplevel, (guint16 *) data); + break; + case TARGET_BGIMAGE: + success = set_background_image_from_uri (panel->toplevel, (char *) data); + break; + case TARGET_BACKGROUND_RESET: + if (panel_profile_is_writable_background_type (panel->toplevel)) { + panel_profile_set_background_type (panel->toplevel, PANEL_BACK_NONE); + success = TRUE; + } else { + success = FALSE; + } + break; + case TARGET_DIRECTORY: + success = drop_uri (panel, pos, (char *)data, + PANEL_ICON_FOLDER); + break; + case TARGET_APPLET: + if (!gtk_selection_data_get_data (selection_data)) { + gtk_drag_finish (context, FALSE, FALSE, time_); + return; + } + if (panel_profile_id_lists_are_writable ()) { + mate_panel_applet_frame_create (panel->toplevel, pos, (char *) data); + success = TRUE; + } else { + success = FALSE; + } + break; + case TARGET_APPLET_INTERNAL: + success = drop_internal_applet (panel, pos, (char *)data, + gdk_drag_context_get_selected_action (context)); + break; + case TARGET_ICON_INTERNAL: + success = drop_internal_icon (panel, pos, (char *)data, + gdk_drag_context_get_selected_action (context)); + break; + default: + gtk_drag_finish (context, FALSE, FALSE, time_); + return; + } + + gtk_drag_finish (context, success, FALSE, time_); +} + +static void +drag_data_recieved_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + PanelWidget *panel_widget; + int pos; + + g_return_if_fail (PANEL_IS_TOPLEVEL (widget)); + + /* we use this only to really find out the info, we already + know this is an ok drop site and the info that got passed + to us is bogus (it's always 0 in fact) */ + if (!panel_check_dnd_target_data (widget, context, &info, NULL)) { + gtk_drag_finish (context, FALSE, FALSE, time); + return; + } + + panel_widget = panel_toplevel_get_panel_widget (PANEL_TOPLEVEL (widget)); + + pos = panel_widget_get_cursorloc (panel_widget); + + /* + * -1 passed to mate_panel_applet_register will turn on + * the insert_at_pos flag for panel_widget_add_full, + * which will not place it after the first applet. + */ + if(pos < 0) + pos = -1; + else if(pos > panel_widget->size) + pos = panel_widget->size; + + panel_receive_dnd_data ( + panel_widget, info, pos, selection_data, context, time); +} + +static void +panel_widget_setup(PanelWidget *panel) +{ + g_signal_connect (G_OBJECT(panel), + "applet_added", + G_CALLBACK(mate_panel_applet_added), + NULL); + g_signal_connect (G_OBJECT(panel), + "applet_removed", + G_CALLBACK(mate_panel_applet_removed), + NULL); + g_signal_connect (G_OBJECT(panel), + "applet_move", + G_CALLBACK(mate_panel_applet_move), + NULL); + g_signal_connect (G_OBJECT (panel), + "back_change", + G_CALLBACK (panel_back_change), + NULL); + g_signal_connect (G_OBJECT (panel), + "size_change", + G_CALLBACK (panel_size_change), + NULL); +} + +PanelData * +panel_setup (PanelToplevel *toplevel) +{ + PanelWidget *panel_widget; + PanelData *pd; + + g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL); + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + + pd = g_new0 (PanelData,1); + pd->menu = NULL; + pd->panel = GTK_WIDGET (toplevel); + pd->insertion_pos = -1; + pd->deactivate_idle = 0; + + panel_list = g_slist_append (panel_list, pd); + + g_object_set_data (G_OBJECT (toplevel), "PanelData", pd); + + panel_lockdown_notify_add (G_CALLBACK (panel_recreate_context_menu), + pd); + + panel_widget_setup (panel_widget); + + g_signal_connect (toplevel, "drag_data_received", + G_CALLBACK (drag_data_recieved_cb), NULL); + g_signal_connect (toplevel, "drag_motion", + G_CALLBACK (drag_motion_cb), NULL); + g_signal_connect (toplevel, "drag_leave", + G_CALLBACK (drag_leave_cb), NULL); + g_signal_connect (toplevel, "drag_drop", + G_CALLBACK (drag_drop_cb), NULL); + + gtk_drag_dest_set (GTK_WIDGET (toplevel), 0, NULL, 0, 0); + + g_signal_connect (toplevel, "key-press-event", + G_CALLBACK (panel_key_press_event), NULL); + g_signal_connect (toplevel, "button-press-event", + G_CALLBACK (panel_button_press_event), NULL); + g_signal_connect (toplevel, "popup-menu", + G_CALLBACK (panel_popup_menu_signal), NULL); + + g_signal_connect_swapped (toplevel, "notify::orientation", + G_CALLBACK (panel_orient_change), panel_widget); + + g_signal_connect (toplevel, "destroy", G_CALLBACK (panel_destroy), pd); + + return pd; +} + +GdkScreen * +panel_screen_from_panel_widget (PanelWidget *panel) +{ + g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL); + g_return_val_if_fail (PANEL_IS_TOPLEVEL (panel->toplevel), NULL); + + return gtk_window_get_screen (GTK_WINDOW (panel->toplevel)); +} + +gboolean +panel_is_applet_right_stick (GtkWidget *applet) +{ + GtkWidget *parent; + PanelWidget *panel_widget; + + g_return_val_if_fail (GTK_IS_WIDGET (applet), FALSE); + + parent = gtk_widget_get_parent (applet); + + g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE); + + panel_widget = PANEL_WIDGET (parent); + + if (!panel_toplevel_get_expand (panel_widget->toplevel)) + return FALSE; + + return panel_widget_is_applet_stuck (panel_widget, applet); +} + +static void +panel_delete_without_query (PanelToplevel *toplevel) +{ + PanelWidget *panel_widget; + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + + if (panel_toplevel_get_is_attached (toplevel) && + panel_widget->master_widget) { + AppletInfo *info; + + info = g_object_get_data (G_OBJECT (panel_widget->master_widget), + "applet_info"); + + panel_profile_delete_object (info); + } else + panel_profile_delete_toplevel (toplevel); +} + +static void +panel_deletion_response (GtkWidget *dialog, + int response, + PanelToplevel *toplevel) +{ + if (response == GTK_RESPONSE_OK) { + panel_push_window_busy (dialog); + panel_delete_without_query (toplevel); + panel_pop_window_busy (dialog); + } + + gtk_widget_destroy (dialog); +} + +static void +panel_deletion_destroy_dialog (GtkWidget *widget, + PanelToplevel *toplevel) +{ + panel_toplevel_pop_autohide_disabler (toplevel); + g_object_set_data (G_OBJECT (toplevel), "panel-delete-dialog", NULL); +} + +GtkWidget * +panel_deletion_dialog (PanelToplevel *toplevel) +{ + + GtkWidget *dialog; + char *text1; + char *text2; + + if (panel_toplevel_get_is_attached (toplevel)) { + text1 = _("Delete this drawer?"); + text2 = _("When a drawer is deleted, the drawer and its\n" + "settings are lost."); + } else { + text1 = _("Delete this panel?"); + text2 = _("When a panel is deleted, the panel and its\n" + "settings are lost."); + } + + dialog = gtk_message_dialog_new ( + GTK_WINDOW (toplevel), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + "%s", text1); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", text2); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_DELETE, GTK_RESPONSE_OK, + NULL); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + gtk_window_set_screen (GTK_WINDOW (dialog), + gtk_window_get_screen (GTK_WINDOW (toplevel))); + + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); + + g_signal_connect (dialog, "destroy", + G_CALLBACK (panel_deletion_destroy_dialog), + toplevel); + + g_object_set_data (G_OBJECT (toplevel), "panel-delete-dialog", dialog); + panel_toplevel_push_autohide_disabler (toplevel); + + return dialog; +} + +static void +panel_query_deletion (PanelToplevel *toplevel) +{ + GtkWidget *dialog; + + dialog = g_object_get_data (G_OBJECT (toplevel), "panel-delete-dialog"); + + if (dialog) { + gtk_window_present (GTK_WINDOW (dialog)); + return; + } + + dialog = panel_deletion_dialog (toplevel); + + g_signal_connect (dialog, "response", + G_CALLBACK (panel_deletion_response), + toplevel); + + g_signal_connect_object (toplevel, "destroy", + G_CALLBACK (gtk_widget_destroy), + dialog, + G_CONNECT_SWAPPED); + + gtk_widget_show_all (dialog); +} + +void +panel_delete (PanelToplevel *toplevel) +{ + PanelWidget *panel_widget; + + panel_widget = panel_toplevel_get_panel_widget (toplevel); + + if (!panel_global_config_get_confirm_panel_remove () || + !g_list_length (panel_widget->applet_list)) { + panel_delete_without_query (toplevel); + return; + } + + panel_query_deletion (toplevel); +} diff --git a/mate-panel/panel.h b/mate-panel/panel.h new file mode 100644 index 00000000..3cb773a6 --- /dev/null +++ b/mate-panel/panel.h @@ -0,0 +1,57 @@ +#ifndef PANEL_H +#define PANEL_H + +#include +#include "panel-toplevel.h" +#include "panel-widget.h" +#include "applet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _PanelData PanelData; +struct _PanelData { + GtkWidget *panel; + GtkWidget *menu; + int insertion_pos; + guint deactivate_idle; +}; + +void orientation_change(AppletInfo *info, PanelWidget *panel); +void size_change(AppletInfo *info, PanelWidget *panel); +void back_change(AppletInfo *info, PanelWidget *panel); + +PanelData *panel_setup (PanelToplevel *toplevel); + +GdkScreen *panel_screen_from_panel_widget (PanelWidget *panel); + +gboolean panel_is_applet_right_stick (GtkWidget *applet); + + +gboolean panel_check_dnd_target_data (GtkWidget *widget, + GdkDragContext *context, + guint *ret_info, + GdkAtom *ret_atom); + +void panel_receive_dnd_data (PanelWidget *panel, + guint info, + int pos, + GtkSelectionData *selection_data, + GdkDragContext *context, + guint time_); + +gboolean panel_check_drop_forbidden (PanelWidget *panel, + GdkDragContext *context, + guint info, + guint time_); + +void panel_delete (PanelToplevel *toplevel); + +GtkWidget *panel_deletion_dialog (PanelToplevel *toplevel); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mate-panel/xstuff.c b/mate-panel/xstuff.c new file mode 100644 index 00000000..6bcc3396 --- /dev/null +++ b/mate-panel/xstuff.c @@ -0,0 +1,736 @@ +/* + * MATE panel x stuff + * + * Copyright (C) 2000, 2001 Eazel, Inc. + * 2002 Sun Microsystems Inc. + * + * Authors: George Lebl + * Mark McLoughlin + * + * Contains code from the Window Maker window manager + * + * Copyright (c) 1997-2002 Alfredo K. Kojima + + */ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "panel-enums.h" +#include "xstuff.h" + +static int (* xstuff_old_xio_error_handler) (Display *) = NULL; +static int (* xstuff_old_x_error_handler) (Display *, XErrorEvent *); +static gboolean xstuff_display_is_dead = FALSE; + +static Atom +panel_atom_get (const char *atom_name) +{ + static GHashTable *atom_hash; + Display *xdisplay; + Atom retval; + + g_return_val_if_fail (atom_name != NULL, None); + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + + if (!atom_hash) + atom_hash = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, NULL); + + retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name)); + if (!retval) { + retval = XInternAtom (xdisplay, atom_name, FALSE); + + if (retval != None) + g_hash_table_insert (atom_hash, g_strdup (atom_name), + GUINT_TO_POINTER (retval)); + } + + return retval; +} + +/* Stolen from deskguide */ +static gpointer +get_typed_property_data (Display *xdisplay, + Window xwindow, + Atom property, + Atom requested_type, + gint *size_p, + guint expected_format) +{ + static const guint prop_buffer_lengh = 1024 * 1024; + unsigned char *prop_data = NULL; + Atom type_returned = 0; + unsigned long nitems_return = 0, bytes_after_return = 0; + int format_returned = 0; + gpointer data = NULL; + gboolean abort = FALSE; + + g_return_val_if_fail (size_p != NULL, NULL); + *size_p = 0; + + gdk_error_trap_push (); + + abort = XGetWindowProperty (xdisplay, + xwindow, + property, + 0, prop_buffer_lengh, + False, + requested_type, + &type_returned, &format_returned, + &nitems_return, + &bytes_after_return, + &prop_data) != Success; + if (gdk_error_trap_pop () || + type_returned == None) + abort++; + if (!abort && + requested_type != AnyPropertyType && + requested_type != type_returned) + { + g_warning ("%s(): Property has wrong type, probably on crack", G_STRFUNC); + abort++; + } + if (!abort && bytes_after_return) + { + g_warning ("%s(): Eeek, property has more than %u bytes, stored on harddisk?", + G_STRFUNC, prop_buffer_lengh); + abort++; + } + if (!abort && expected_format && expected_format != format_returned) + { + g_warning ("%s(): Expected format (%u) unmatched (%d), programmer was drunk?", + G_STRFUNC, expected_format, format_returned); + abort++; + } + if (!abort && prop_data && nitems_return && format_returned) + { + switch (format_returned) + { + case 32: + *size_p = nitems_return * 4; + if (sizeof (gulong) == 8) + { + guint32 i, *mem = g_malloc0 (*size_p + 1); + gulong *prop_longs = (gulong*) prop_data; + + for (i = 0; i < *size_p / 4; i++) + mem[i] = prop_longs[i]; + data = mem; + } + break; + case 16: + *size_p = nitems_return * 2; + break; + case 8: + *size_p = nitems_return; + break; + default: + g_warning ("Unknown property data format with %d bits (extraterrestrial?)", + format_returned); + break; + } + if (!data && *size_p) + { + guint8 *mem = g_malloc (*size_p + 1); + + memcpy (mem, prop_data, *size_p); + mem[*size_p] = 0; + data = mem; + } + } + + if (prop_data) + XFree (prop_data); + + return data; +} + +gboolean +xstuff_is_compliant_wm (void) +{ + Display *xdisplay; + Window root_window; + gpointer data; + int size; + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + root_window = GDK_WINDOW_XWINDOW ( + gdk_get_default_root_window ()); + + /* FIXME this is totally broken; should be using + * gdk_net_wm_supports() on particular hints when we rely + * on those particular hints + */ + data = get_typed_property_data ( + xdisplay, root_window, + panel_atom_get ("_NET_SUPPORTED"), + XA_ATOM, &size, 32); + + if (!data) + return FALSE; + + /* Actually checks for some of these */ + g_free (data); + return TRUE; +} + +gboolean +xstuff_net_wm_supports (const char *hint) +{ + return gdk_net_wm_supports (gdk_atom_intern (hint, FALSE)); +} + +/* This is such a broken stupid function. */ +void +xstuff_set_pos_size (GdkWindow *window, int x, int y, int w, int h) +{ + XSizeHints size_hints; + int old_x, old_y, old_w, old_h; + + old_x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-x")); + old_y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-y")); + old_w = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-w")); + old_h = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "xstuff-cached-h")); + + if (x == old_x && y == old_y && w == old_w && h == old_h) + return; + + /* Do not add USPosition / USSize here, fix the damn WM */ + size_hints.flags = PPosition | PSize | PMaxSize | PMinSize; + size_hints.x = 0; /* window managers aren't supposed to and */ + size_hints.y = 0; /* don't use these fields */ + size_hints.width = w; + size_hints.height = h; + size_hints.min_width = w; + size_hints.min_height = h; + size_hints.max_width = w; + size_hints.max_height = h; + + gdk_error_trap_push (); + + XSetWMNormalHints (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + &size_hints); + + gdk_window_move_resize (window, x, y, w, h); + + gdk_flush (); + gdk_error_trap_pop (); + + g_object_set_data (G_OBJECT (window), "xstuff-cached-x", GINT_TO_POINTER (x)); + g_object_set_data (G_OBJECT (window), "xstuff-cached-y", GINT_TO_POINTER (y)); + g_object_set_data (G_OBJECT (window), "xstuff-cached-w", GINT_TO_POINTER (w)); + g_object_set_data (G_OBJECT (window), "xstuff-cached-h", GINT_TO_POINTER (h)); +} + +void +xstuff_set_wmspec_dock_hints (GdkWindow *window, + gboolean autohide) +{ + Atom atoms [2] = { None, None }; + + if (!autohide) + atoms [0] = panel_atom_get ("_NET_WM_WINDOW_TYPE_DOCK"); + else { + atoms [0] = panel_atom_get ("_MATE_WINDOW_TYPE_AUTOHIDE_PANEL"); + atoms [1] = panel_atom_get ("_NET_WM_WINDOW_TYPE_DOCK"); + } + + XChangeProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + panel_atom_get ("_NET_WM_WINDOW_TYPE"), + XA_ATOM, 32, PropModeReplace, + (unsigned char *) atoms, + autohide ? 2 : 1); +} + +void +xstuff_set_wmspec_strut (GdkWindow *window, + int left, + int right, + int top, + int bottom) +{ + long vals [4]; + + vals [0] = left; + vals [1] = right; + vals [2] = top; + vals [3] = bottom; + + XChangeProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XWINDOW (window), + panel_atom_get ("_NET_WM_STRUT"), + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *) vals, 4); +} + +void +xstuff_delete_property (GdkWindow *window, const char *name) +{ + Display *xdisplay = GDK_WINDOW_XDISPLAY (window); + Window xwindow = GDK_WINDOW_XWINDOW (window); + + XDeleteProperty (xdisplay, xwindow, + panel_atom_get (name)); +} + +/* Zoom animation */ +#define MINIATURIZE_ANIMATION_FRAMES_Z 1 +#define MINIATURIZE_ANIMATION_STEPS_Z 6 +/* the delay per draw */ +#define MINIATURIZE_ANIMATION_DELAY_Z 10 + +/* zoom factor, steps and delay if composited (factor must be odd) */ +#define ZOOM_FACTOR 5 +#define ZOOM_STEPS 14 +#define ZOOM_DELAY 10 + +typedef struct { + int size; + int size_start; + int size_end; + PanelOrientation orientation; + double opacity; + GdkPixbuf *pixbuf; + guint timeout_id; +} CompositedZoomData; + +static gboolean +zoom_timeout (GtkWidget *window) +{ + gtk_widget_queue_draw (window); + return TRUE; +} + +static gboolean +zoom_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + CompositedZoomData *zoom; + + zoom = user_data; + + if (zoom->size >= zoom->size_end) { + if (zoom->timeout_id) + g_source_remove (zoom->timeout_id); + zoom->timeout_id = 0; + + g_object_unref (zoom->pixbuf); + zoom->pixbuf = NULL; + + g_slice_free (CompositedZoomData, zoom); + + gtk_widget_destroy (widget); + } else { + GdkPixbuf *scaled; + int width, height; + int x = 0, y = 0; + cairo_t *cr; + + gtk_window_get_size (GTK_WINDOW (widget), &width, &height); + + zoom->size += MAX ((zoom->size_end - zoom->size_start) / ZOOM_STEPS, 1); + zoom->opacity -= 1.0 / ((double) ZOOM_STEPS + 1); + + scaled = gdk_pixbuf_scale_simple (zoom->pixbuf, + zoom->size, zoom->size, + GDK_INTERP_BILINEAR); + + switch (zoom->orientation) { + case PANEL_ORIENTATION_TOP: + x = (width - gdk_pixbuf_get_width (scaled)) / 2; + y = 0; + break; + + case PANEL_ORIENTATION_RIGHT: + x = width - gdk_pixbuf_get_width (scaled); + y = (height - gdk_pixbuf_get_height (scaled)) / 2; + break; + + case PANEL_ORIENTATION_BOTTOM: + x = (width - gdk_pixbuf_get_width (scaled)) / 2; + y = height - gdk_pixbuf_get_height (scaled); + break; + + case PANEL_ORIENTATION_LEFT: + x = 0; + y = (height - gdk_pixbuf_get_height (scaled)) / 2; + break; + } + + + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0, 0, 0, 0.0); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + gdk_cairo_set_source_pixbuf (cr, scaled, x, y); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint_with_alpha (cr, MAX (zoom->opacity, 0)); + + cairo_destroy (cr); + g_object_unref (scaled); + } + + return FALSE; +} + +static void +draw_zoom_animation_composited (GdkScreen *gscreen, + int x, int y, int w, int h, + GdkPixbuf *pixbuf, + PanelOrientation orientation) +{ + GtkWidget *win; + CompositedZoomData *zoom; + int wx = 0, wy = 0; + + w += 2; + h += 2; + + zoom = g_slice_new (CompositedZoomData); + zoom->size = w; + zoom->size_start = w; + zoom->size_end = w * ZOOM_FACTOR; + zoom->orientation = orientation; + zoom->opacity = 1.0; + zoom->pixbuf = g_object_ref (pixbuf); + zoom->timeout_id = 0; + + win = gtk_window_new (GTK_WINDOW_POPUP); + + gtk_window_set_screen (GTK_WINDOW (win), gscreen); + gtk_window_set_keep_above (GTK_WINDOW (win), TRUE); + gtk_window_set_decorated (GTK_WINDOW (win), FALSE); + gtk_widget_set_app_paintable(win, TRUE); + gtk_widget_set_colormap (win, gdk_screen_get_rgba_colormap (gscreen)); + + gtk_window_set_gravity (GTK_WINDOW (win), GDK_GRAVITY_STATIC); + gtk_window_set_default_size (GTK_WINDOW (win), + w * ZOOM_FACTOR, h * ZOOM_FACTOR); + + switch (zoom->orientation) { + case PANEL_ORIENTATION_TOP: + wx = x - w * (ZOOM_FACTOR / 2); + wy = y; + break; + + case PANEL_ORIENTATION_RIGHT: + wx = x - w * (ZOOM_FACTOR - 1); + wy = y - h * (ZOOM_FACTOR / 2); + break; + + case PANEL_ORIENTATION_BOTTOM: + wx = x - w * (ZOOM_FACTOR / 2); + wy = y - h * (ZOOM_FACTOR - 1); + break; + + case PANEL_ORIENTATION_LEFT: + wx = x; + wy = y - h * (ZOOM_FACTOR / 2); + break; + } + + gtk_window_move (GTK_WINDOW (win), wx, wy); + + g_signal_connect (G_OBJECT (win), "expose-event", + G_CALLBACK (zoom_expose), zoom); + + /* see doc for gtk_widget_set_app_paintable() */ + gtk_widget_realize (win); + gdk_window_set_back_pixmap (gtk_widget_get_window (win), NULL, FALSE); + gtk_widget_show (win); + + zoom->timeout_id = g_timeout_add (ZOOM_DELAY, + (GSourceFunc) zoom_timeout, + win); +} + +static void +draw_zoom_animation (GdkScreen *gscreen, + int x, int y, int w, int h, + int fx, int fy, int fw, int fh, + int steps) +{ +#define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z) + float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES]; + int cxi[FRAMES], cyi[FRAMES], cwi[FRAMES], chi[FRAMES]; + float xstep, ystep, wstep, hstep; + int i, j; + GC frame_gc; + XGCValues gcv; + GdkColor color = { 65535, 65535, 65535 }; + Display *dpy; + Window root_win; + int screen; + int depth; + + dpy = gdk_x11_display_get_xdisplay (gdk_screen_get_display (gscreen)); + root_win = gdk_x11_drawable_get_xid (gdk_screen_get_root_window (gscreen)); + screen = gdk_screen_get_number (gscreen); + depth = gdk_drawable_get_depth (gdk_screen_get_root_window (gscreen)); + + /* frame GC */ + gdk_colormap_alloc_color ( + gdk_screen_get_system_colormap (gscreen), &color, FALSE, TRUE); + gcv.function = GXxor; + /* this will raise the probability of the XORed color being different + * of the original color in PseudoColor when not all color cells are + * initialized */ + if (DefaultVisual(dpy, screen)->class==PseudoColor) + gcv.plane_mask = (1<<(depth-1))|1; + else + gcv.plane_mask = AllPlanes; + gcv.foreground = color.pixel; + if (gcv.foreground == 0) + gcv.foreground = 1; + gcv.line_width = 1; + gcv.subwindow_mode = IncludeInferiors; + gcv.graphics_exposures = False; + + frame_gc = XCreateGC(dpy, root_win, GCForeground|GCGraphicsExposures + |GCFunction|GCSubwindowMode|GCLineWidth + |GCPlaneMask, &gcv); + + xstep = (float)(fx-x)/steps; + ystep = (float)(fy-y)/steps; + wstep = (float)(fw-w)/steps; + hstep = (float)(fh-h)/steps; + + for (j=0; j 0) + usleep(MINIATURIZE_ANIMATION_DELAY_Z); +#else + usleep(10); +#endif + for (j=0; j 0) + usleep(MINIATURIZE_ANIMATION_DELAY_Z); +#else + usleep(10); +#endif + for (j=0; jerror_code) + return 0; + + /* If we got a BadDrawable or a BadWindow, we ignore it for now. + * FIXME: We need to somehow distinguish real errors from + * X-server-induced errors. Keeping a list of windows for which we will + * ignore BadDrawables would be a good idea. */ + if (error->error_code == BadDrawable || + error->error_code == BadWindow) + return 0; + + return xstuff_old_x_error_handler (display, error); +} + +void +xstuff_init (void) +{ + xstuff_old_xio_error_handler = XSetIOErrorHandler (xstuff_xio_error_handler); + xstuff_old_x_error_handler = XSetErrorHandler (xstuff_x_error_handler); +} diff --git a/mate-panel/xstuff.h b/mate-panel/xstuff.h new file mode 100644 index 00000000..0bd5f92b --- /dev/null +++ b/mate-panel/xstuff.h @@ -0,0 +1,39 @@ +#ifndef __XSTUFF_H__ +#define __XSTUFF_H__ + +#include +#include + +void xstuff_delete_property (GdkWindow *window, + const char *name); +gboolean xstuff_is_compliant_wm (void); +gboolean xstuff_net_wm_supports (const char *hint); + +void xstuff_unsetup_desktop_area (void); +void xstuff_set_pos_size (GdkWindow *window, + int x, int y, + int w, int h); +void xstuff_set_wmspec_dock_hints (GdkWindow *window, + gboolean autohide); +void xstuff_set_wmspec_strut (GdkWindow *window, + int left, + int right, + int top, + int bottom); + +void xstuff_zoom_animate (GtkWidget *widget, + GdkPixbuf *pixbuf, + PanelOrientation orientation, + GdkRectangle *opt_src_rect); + +int xstuff_get_current_workspace (GdkScreen *screen); + +void xstuff_grab_key_on_all_screens (int keycode, + guint modifiers, + gboolean grab); + +gboolean xstuff_is_display_dead (void); + +void xstuff_init (void); + +#endif /* __XSTUFF_H__ */ -- cgit v1.2.1