예제 #1
0
파일: backendmenu.go 프로젝트: sqp/godock
// AddButtonsEntry adds an item with button entries to the menu.
//
func (m *DockMenu) AddButtonsEntry(label string, btns ...MenuBtn) *menus.ButtonsEntry {
	entry := m.Menu.AddButtonsEntry(label)

	for _, btnID := range btns {
		switch btnID {
		case MenuWindowClose:
			entry.AddButton(
				tran.Slate("Close")+actionMiddleClick(m.Icon, 1),
				globals.DirShareData("icons", "icon-close.svg"),
				m.Icon.CallbackActionWindow((cdglobal.Window).Close))

		case MenuWindowCloseAll:
			entry.AddButton(
				tran.Slate("Close all")+actionMiddleClick(m.Icon, 1),
				globals.DirShareData("icons", "icon-close.svg"),
				m.Icon.CallbackActionSubWindows((cdglobal.Window).Close))

		case MenuWindowMax:
			max := m.Icon.Window().IsMaximized()
			entry.AddButton(
				ternary.String(max, tran.Slate("Unmaximise"), tran.Slate("Maximise")),
				globals.DirShareData("icons", ternary.String(max, "icon-restore.svg", "icon-maximize.svg")),
				m.Icon.CallbackActionWindowToggle((cdglobal.Window).Maximize, (cdglobal.Window).IsMaximized))

		case MenuWindowMin:
			entry.AddButton(
				tran.Slate("Minimise")+actionMiddleClick(m.Icon, 2),
				globals.DirShareData("icons", "icon-minimize.svg"),
				m.Icon.CallbackActionWindow((cdglobal.Window).Minimize))

		case MenuWindowMinAll:
			entry.AddButton(
				tran.Slate("Minimise all")+actionMiddleClick(m.Icon, 2),
				globals.DirShareData("icons", "icon-minimize.svg"),
				m.Icon.CallbackActionSubWindows((cdglobal.Window).Minimize))

		case MenuWindowShow:
			entry.AddButton(
				tran.Slate("Show"),
				globals.IconNameFind,
				m.Icon.CallbackActionWindow((cdglobal.Window).Show))

		case MenuWindowShowAll:
			entry.AddButton(
				tran.Slate("Show all"),
				globals.IconNameFind,
				m.Icon.CallbackActionSubWindows((cdglobal.Window).Show))

		default:
			log.NewWarn(fmt.Sprintf("invalid id: %d", btnID), "AddButtonsEntry")
		}
	}
	return entry
}
예제 #2
0
파일: withdock.go 프로젝트: sqp/godock
func init() {
	dirShareData = globals.DirShareData()

	iconCore = globals.FileCairoDockIcon()

	AppletInfo = func(log cdtype.Logger, name string) (dir, icon string) {
		mod := gldi.ModuleGet(name)
		if mod == nil {
			return "", ""
		}
		vc := mod.VisitCard()
		return vc.GetShareDataDir(), vc.GetIconFilePath()
	}

	AppletRestart = func(name string) {
		mod := gldi.ModuleGet(name)
		if mod == nil {
			return
		}
		for _, mi := range mod.InstancesList() {
			gldi.ObjectDelete(mi)
		}
		mod.Activate()
	}

	CloseGui = backendgui.CloseGui

}
예제 #3
0
파일: maindock.go 프로젝트: sqp/godock
func getChangelog() string {
	changelogPath := globals.DirShareData(cdglobal.FileChangelog)
	msg := ""
	e := config.GetFromFile(log, changelogPath, func(cfg cdtype.ConfUpdater) {
		major, minor, micro := globals.VersionSplit()

		// Get first line
		strver := fmt.Sprintf("%d.%d.%d", major, minor, micro) // version without "alpha", "beta", "rc", etc.
		msg = cfg.Valuer("ChangeLog", strver).String()
		if msg == "" {
			log.Debug("changelog", "no info for version", globals.Version())
			return
		}
		msg = tran.Slate(msg)

		// Add all changelog lines for that version.
		i := 0
		for {
			strver := fmt.Sprintf("%d.%d.%d.%d", major, minor, micro, i)
			sub := cfg.Valuer("ChangeLog", strver).String()
			msg += "\n " + tran.Slate(sub)
			i++
		}
	})
	log.Err(e, "load changelog", changelogPath)
	return msg
}
예제 #4
0
파일: mgrgldi.go 프로젝트: sqp/godock
func (o *AppManager) registerApplets() {
	dir := globals.DirShareData(cdglobal.ConfigDirAppletsGo)
	packs, e := packages.ListFromDir(o.log, dir, packages.TypeGoInternal, packages.SourceApplet)
	if o.log.Err(e, "registerapplets") {
		return
	}
	for _, pack := range packs {
		if cdtype.Applets.GetNewFunc(pack.DisplayedName) != nil {
			o.registerOneApplet(pack)
		}
	}
}
예제 #5
0
파일: maindock.go 프로젝트: sqp/godock
func createConfigDir(settings *DockSettings) {
	log.Info("creating configuration directory", globals.DirDockData())

	themeName := "Default-Single"

	if os.Getenv("DESKTOP_SESSION") == "cairo-dock" { // We're using the CD session for the first time
		themeName = "Default-Panel"
		settings.sessionWasUsed = true
		updateHiddenFile("cd session", true)
	}

	files.CopyDir(globals.DirShareData(cdglobal.ConfigDirDockThemes, themeName), globals.CurrentThemePath())
}
예제 #6
0
파일: confown.go 프로젝트: sqp/godock
// Init will try to load the own config data from the file, and create it if missing.
//
func Init(log cdtype.Logger, file string, e error) error {
	if e != nil {
		return e
	}

	// Create file if needed.
	if !files.IsExist(file) {
		source := globals.DirShareData(GuiFilename)
		e := files.CopyFile(source, file, os.FileMode(0644))
		if e != nil {
			return e
		}
		log.Info("created config file", file)
	}

	// Create our user settings
	Settings = ConfigSettings{
		File: file,
		log:  log,
	}
	return Settings.Load()
}
예제 #7
0
파일: maindock.go 프로젝트: sqp/godock
// Init is the first step to initialize the dock.
//
func (settings *DockSettings) Init() {
	confdir := cdglobal.ConfigDirDock(settings.UserDefinedDataDir)
	settings.isFirstLaunch = !files.IsExist(confdir) // TODO: need test is dir.

	hidden := loadHidden(confdir)

	settings.isNewVersion = hidden.LastVersion != globals.Version()
	settings.sessionWasUsed = hidden.SessionWasUsed

	// MISSING
	// //\___________________ build the command line used to respawn, and check if we have been launched from another life.

	// mute all output messages if CD is not launched from a terminal
	// if (getenv("TERM") == NULL)  /// why not isatty(stdout) ?...
	// 	g_set_print_handler(PrintMuteFunc);

	gldi.DbusGThreadInit() // it's a wrapper: it will use dbus_threads_init_default ();

	gtk.Init(nil)

	//\___________________ C dock log.
	if settings.Verbosity != "" {
		gldi.LogSetLevelFromName(settings.Verbosity)
	}

	if settings.ForceColor {
		gldi.LogForceUseColor()
	}

	//\___________________ delay the startup if specified.
	if settings.Delay > 0 {
		<-time.After(time.Duration(settings.Delay) * time.Second)
	}

	//\___________________ initialize libgldi.

	var rendering gldi.RenderingMethod
	switch {
	case settings.ForceOpenGL:
		rendering = gldi.RenderingOpenGL

	case settings.ForceCairo:
		rendering = gldi.RenderingCairo

	default:
		rendering = gldi.RenderingDefault
	}
	gldi.Init(int(rendering))

	//\___________________ set custom user options.

	if settings.KeepAbove {
		gldi.ForceDocksAbove()
	}

	if settings.NoSticky {
		gldi.SetContainersNonSticky()
	}

	if settings.MetacityWorkaround {
		gldi.DisableContainersOpacity()
	}

	env := DesktopEnvironment(settings.Env)
	if env != gldi.DeskEnvUnknown {
		gldi.FMForceDeskEnv(env)
	}

	if settings.IndirectOpenGL {
		gldi.GLBackendForceIndirectRendering()
	}

	if settings.ThemeServer == "" {
		settings.ThemeServer = cdglobal.DownloadServerURL
	}
	gldi.SetPaths(confdir, // will later be available as DirDockData  (g_cCairoDockDataDir)
		cdglobal.ConfigDirExtras,
		cdglobal.ConfigDirDockThemes,
		cdglobal.ConfigDirCurrentTheme,
		cdglobal.CairoDockShareThemesDir,
		cdglobal.DockThemeServerTag,
		settings.ThemeServer)

	about.Img = globals.DirShareData(cdglobal.ConfigDirDockImages, cdglobal.FileCairoDockLogo)

	//\___________________ Check that OpenGL is safely usable, if not ask the user what to do.

	// Unsafe OpenGL requires to be confirmed to use (need forced in conf or user validation).
	if settings.AskBackend || (gldi.GLBackendIsUsed() && !gldi.GLBackendIsSafe() && !settings.ForceOpenGL && !settings.IndirectOpenGL) {
		if settings.AskBackend || hidden.DefaultBackend == "" { // no backend defined.
			dialogAskBackend()
		} else if hidden.DefaultBackend != "opengl" { // disable opengl if unused, revert to cairo.
			gldi.GLBackendDeactivate()
		}
	}

	// Remove excluded applets.
	for _, name := range settings.Exclude {
		cdtype.Applets.Unregister(name)
	}

	//\___________________ load plug-ins (must be done after everything is initialized).
	if !settings.SafeMode {
		err := gldi.ModulesNewFromDirectory("")
		log.Err(err, "no module will be available")

		if settings.ModulesDir != "" {
			err := gldi.ModulesNewFromDirectory(settings.ModulesDir)
			log.Err(err, "no additionnal module will be available")
		}
	}
}
예제 #8
0
파일: maindock.go 프로젝트: sqp/godock
func firstLaunchSetup() {
	log.Info("firstLaunchScript", globals.DirShareData("scripts", "initial-setup.sh"))
	log.ExecShow(globals.DirShareData("scripts", "initial-setup.sh"))
}
예제 #9
0
파일: confdata.go 프로젝트: sqp/godock
// ListIcons builds the list of all icons.
//
func (Data) ListIcons() *datatype.ListIcon {
	list := datatype.NewListIcon()

	// Add icons in docks.
	taskbarSet := false
	for _, dock := range gldi.GetAllAvailableDocks(nil, nil) {
		// for _, dock := range gldi.ListDocksRoot() {

		var found []datatype.Iconer
		for _, icon := range dock.Icons() {
			if dock.GetRefCount() == 0 { // Maindocks.

				// Group taskbar icons and separators.
				if icon.ConfigPath() == "" || icon.IsSeparatorAuto() {
					// if icon.IsTaskbar() || icon.IsSeparatorAuto() {
					if !taskbarSet {
						taskbarSet = true
						ic := datatype.NewIconSimple(
							globals.ConfigFile(),
							datatype.FieldTaskBar,
							datatype.TitleTaskBar,
							globals.DirShareData("icons/icon-taskbar.png"))

						ic.Taskbar = true

						found = append(found, ic)
					}

				} else {
					found = append(found, &IconConf{icon})
				}

			} else { // Subdock.
				parentName := icon.GetParentDockName()
				list.Subdocks[parentName] = append(list.Subdocks[parentName], &IconConf{icon})
			}
		}

		if len(found) > 0 {
			var file, group string

			if dock.IsMainDock() {
				// Only maindocks after the first one have a config file.
				// So the first maindock use a custom group.
				group = datatype.KeyMainDock

			} else {
				// Other maindocks have a dedicated config file.
				// So the group is empty to load all of them (auto find).
				file = globals.CurrentThemePath(dock.GetDockName() + ".conf")
			}
			container := datatype.NewIconSimple(
				file,
				group,
				dock.GetReadableName(),
				"") // TODO: maybe get an icon for the maindock.

			list.Add(container, found)
		}
	}

	// Add modules in desklets.
	var desklets []datatype.Iconer
	for _, desklet := range docklist.Desklet() {
		icon := desklet.GetIcon()
		if icon != nil {
			desklets = append(desklets, &IconConf{icon})
		}
	}

	if len(desklets) > 0 {
		container := datatype.NewIconSimple(
			globals.ConfigFile(),
			datatype.GroupDesklets,
			datatype.TitleDesklets,
			"") // TODO: maybe get an icon for the desklets group.

		list.Add(container, desklets)
	}

	// Add other modules (not in a dock or a desklet) : plug-in or detached applet.
	// We need to create custom icons for them.
	var services []datatype.Iconer
	for _, mod := range docklist.Module() {
		cat := mod.VisitCard().GetCategory()

		if cat != gldi.CategoryBehavior && cat != gldi.CategoryTheme && !mod.IsAutoLoaded() {
			for _, mi := range mod.InstancesList() {

				if mi.Icon() == nil || (mi.Dock() != nil && mi.Icon().GetContainer() == nil) {
					icon := datatype.NewIconSimple(
						mi.GetConfFilePath(),
						"", // no group, we need all of them for an applet.
						mod.VisitCard().GetTitle(),
						mod.VisitCard().GetIconFilePath())

					services = append(services, icon)
				}
			}
		}
	}
	if len(services) > 0 {
		container := datatype.NewIconSimple(
			"", // no config file available.
			datatype.GroupServices, // so we set a custom group.
			tran.Slate(datatype.TitleServices),
			"") // TODO: maybe get an icon for the services group.

		list.Add(container, services)
	}

	return list
}
예제 #10
0
파일: confdata.go 프로젝트: sqp/godock
// DirShareData returns the path to the shared data dir.
func (Data) DirShareData(path ...string) string {
	return globals.DirShareData(path...)
}
예제 #11
0
파일: confdata.go 프로젝트: sqp/godock
func (v *dockTheme) IconState() string            { return globals.DirShareData(v.AppletPackage.IconState()) }
예제 #12
0
파일: confdata.go 프로젝트: sqp/godock
// IconState returns the icon location for the state for the applet.
//
func (v *AppletDownload) IconState() string {
	return globals.DirShareData(v.AppletPackage.IconState())
}
예제 #13
0
파일: backendmenu.go 프로젝트: sqp/godock
// Entry adds a defined entry to the menu. Returns if a separator is needed.
//
func (m *DockMenu) Entry(entry MenuEntry) bool {
	switch entry {

	case MenuAbout:
		m.AddEntry(
			tran.Slate("About"),
			globals.IconNameAbout,
			about.New,
		)

	case MenuAddApplet:
		m.AddEntry(
			tran.Slate("Applet"),
			globals.IconNameAdd,
			backendgui.ShowAddons)

	case MenuAddLauncher:
		m.AddEntry(
			tran.Slate("Custom launcher"),
			globals.IconNameAdd,
			func() {
				newIcon := gldi.LauncherAddNew("", m.Dock, nextOrder(m.Icon, m.Dock))
				if newIcon == nil {
					// TODO: use log
					println("Couldn't create create the icon.\nCheck that you have writing permissions on ~/.config/cairo-dock and its sub-folders")
				} else {
					backendgui.ShowItems(newIcon, nil, nil, -1)
				}
			},
		).SetTooltipText(tran.Slate("Usually you would drag a launcher from the menu and drop it on the dock."))

	case MenuAddMainDock:
		m.AddEntry(
			tran.Slate("Main dock"),
			globals.IconNameAdd,
			func() {
				key := gldi.DockAddConfFile()
				gldi.DockNew(key)

				backendgui.ReloadItems()

				// g_timeout_add_seconds (1, (GSourceFunc)_show_new_dock_msg, cDockName);  // delai, car sa fenetre n'est pas encore bien placee (0,0).
			})

	case MenuAddSeparator:
		m.AddEntry(
			tran.Slate("Separator"),
			globals.IconNameAdd,
			func() {
				newIcon := gldi.SeparatorIconAddNew(m.Dock, nextOrder(m.Icon, m.Dock))
				if newIcon == nil {
					// TODO: use log
					println("Couldn't create create the icon.\nCheck that you have writing permissions on ~/.config/cairo-dock and its sub-folders")
				}
			})

	case MenuAddSubDock:
		m.AddEntry(
			tran.Slate("Sub-dock"),
			globals.IconNameAdd,
			func() {
				newIcon := gldi.StackIconAddNew(m.Dock, nextOrder(m.Icon, m.Dock))
				if newIcon == nil {
					// TODO: use log
					println("Couldn't create create the icon.\nCheck that you have writing permissions on ~/.config/cairo-dock and its sub-folders")
				}
			})

	case MenuClassItems:
		//\_________________________ class actions.
		items := m.Icon.GetClass().MenuItems()
		for _, it := range items {
			cmd := strings.Fields(it[1])
			m.AddEntry(
				it[0], // name
				it[2], // icon
				func() { log.ExecAsync(cmd[0], cmd[1:]...) }) // was gldi.LaunchCommand(cmd)
		}
		return len(items) > 0

	case MenuConfigure:
		m.AddEntry(
			tran.Slate("Configure"),
			globals.IconNamePreferences,
			backendgui.ShowMainGui,
		).SetTooltipText(tran.Slate("Configure behaviour, appearance, and applets."))

	case MenuCustomIconRemove:
		classIcon := m.Icon.GetClass().Icon()
		if classIcon == "" {
			classIcon = m.Icon.GetClass().String()
		}

		path := filepath.Join(globals.DirCurrentIcons(), classIcon+".png")
		if _, e := os.Stat(path); e != nil {
			path = filepath.Join(globals.DirCurrentIcons(), classIcon+".svg")
			if _, e := os.Stat(path); e != nil {
				path = ""
			}
		}

		// println("custom icon", path)

		if path != "" {
			m.AddEntry(
				tran.Slate("Remove custom icon"),
				globals.IconNameRemove,
				func() {
					C._cairo_dock_remove_custom_appli_icon((*C.Icon)(unsafe.Pointer(m.Icon.ToNative())), (*C.CairoDock)(unsafe.Pointer(m.Dock.Ptr)))
				})
		}

	case MenuCustomIconSet:
		m.AddEntry(
			tran.Slate("Set a custom icon"),
			globals.IconNameSelectColor,
			func() {
				C._cairo_dock_set_custom_appli_icon((*C.Icon)(unsafe.Pointer(m.Icon.ToNative())), (*C.CairoDock)(unsafe.Pointer(m.Dock.Ptr)))
			})

	case MenuDeleteDock:
		m.AddEntry(
			tran.Slate("Delete this dock"),
			globals.IconNameDelete,
			func() {
				if m.Dock.GetRefCount() != 0 {
					dialog.ShowWithQuestion("Delete this dock?",
						m.Dock.GetPointedIcon(),
						m.Container,
						globals.FileCairoDockIcon(),
						cbDialogIsOK(func() {
							gldi.ObjectDelete(m.Dock)
						}))
				}
			})

	case MenuDeskletLock:
		desklet := m.Container.ToDesklet()
		m.AddCheckEntry(
			tran.Slate("Lock position"),
			desklet.PositionLocked(),
			func(c *gtk.CheckMenuItem) {
				desklet.LockPosition(c.GetActive())
				backendgui.UpdateDeskletVisibility(desklet)
			})

	case MenuDeskletSticky:
		desklet := m.Container.ToDesklet()
		m.AddCheckEntry(
			tran.Slate("On all desktops"),
			m.Container.ToDesklet().IsSticky(),
			func(c *gtk.CheckMenuItem) {
				desklet.SetSticky(c.GetActive())

				// TODO: check why SetSticky isn't working...
				println("get stick", desklet.IsSticky())

				backendgui.UpdateDeskletVisibility(desklet)
			})

	case MenuDeskletVisibility:
		submenu := m.AddSubMenu(tran.Slate("Visibility"), globals.IconNameFind)

		desklet := m.Container.ToDesklet()

		callback := func(radio *gtk.RadioMenuItem, val cdtype.DeskletVisibility) {
			if radio.GetActive() {
				desklet.SetVisibility(val, true) // with true, also save to conf.
				backendgui.UpdateDeskletVisibility(desklet)
			}
		}

		group := 42
		visibility := desklet.Visibility()
		addRadio := func(vis cdtype.DeskletVisibility, label string) {
			radio := submenu.AddRadioEntry(label, visibility == vis, group, nil)
			radio.Connect("toggled", callback, vis)
		}

		addRadio(cdtype.DeskletVisibilityNormal, tran.Slate("Normal"))
		addRadio(cdtype.DeskletVisibilityKeepAbove, tran.Slate("Always on top"))
		addRadio(cdtype.DeskletVisibilityKeepBelow, tran.Slate("Always below"))
		if gldi.CanSetOnWidgetLayer() {
			addRadio(cdtype.DeskletVisibilityWidgetLayer, tran.Slate("Widget Layer"))
		}
		addRadio(cdtype.DeskletVisibilityReserveSpace, tran.Slate("Reserve space"))

	case MenuDetachApplet:
		m.AddEntry(
			ternary.String(m.Dock != nil, tran.Slate("Detach"), tran.Slate("Return to the dock")),
			ternary.String(m.Dock != nil, globals.IconNameGotoTop, globals.IconNameGotoBottom),
			func() {
				// if (CAIRO_DOCK_IS_DESKLET (pContainer))
				// 	icon = (CAIRO_DESKLET (pContainer))->pIcon;  // l'icone cliquee du desklet n'est pas forcement celle qui contient le module !
				// g_return_if_fail (CAIRO_DOCK_IS_APPLET (icon));

				m.Icon.ModuleInstance().Detach()
			})

	case MenuDuplicateApplet:
		m.AddEntry(
			tran.Slate("Duplicate"),
			globals.IconNameAdd,
			func() {
				// if (CAIRO_DOCK_IS_DESKLET (pContainer))
				// 	icon = (CAIRO_DESKLET (pContainer))->pIcon;  // l'icone cliquee du desklet n'est pas forcement celle qui contient le module !
				// g_return_if_fail (CAIRO_DOCK_IS_APPLET (icon));

				m.Icon.ModuleInstance().Module().AddInstance()
				// gldi_module_add_instance (icon->pModuleInstance->pModule);
			})

	case MenuEditApplet:
		m.AddEntry(
			tran.Slate("Edit"),
			globals.IconNameEdit,
			func() {
				// if (CAIRO_DOCK_IS_DESKLET (pContainer))
				// 	icon = (CAIRO_DESKLET (pContainer))->pIcon;  // l'icone cliquee du desklet n'est pas forcement celle qui contient le module.
				// g_return_if_fail (CAIRO_DOCK_IS_APPLET (icon));
				backendgui.ShowItems(m.Icon, nil, nil, -1)
			})

	case MenuEditDock:
		m.AddEntry(
			tran.Slate("Configure this dock"),
			globals.IconNameExecute,
			func() { backendgui.ShowItems(nil, m.Container, nil, 0) },
		).SetTooltipText(tran.Slate("Customize the position, visibility and appearance of this main dock."))

	case MenuEditIcon:
		m.AddEntry(tran.Slate(
			tran.Slate("Edit")),
			globals.IconNameEdit,
			func() {
				switch m.Icon.GetDesktopFileName() {
				case "", "none":
					dialog.ShowTemporaryWithIcon("Sorry, this icon doesn't have a configuration file.", m.Icon, m.Container, 4000, "same icon")

				default:
					backendgui.ShowItems(m.Icon, nil, nil, -1)
				}
			})

	case MenuEditTarget:
		_, img := m.Icon.DefaultNameIcon()
		m.AddEntry(
			tran.Slate("Edit icon"),
			img,
			func() {
				// if (CAIRO_DOCK_IS_DESKLET (pContainer))
				// 	icon = (CAIRO_DESKLET (pContainer))->pIcon;  // l'icone cliquee du desklet n'est pas forcement celle qui contient le module.
				// g_return_if_fail (CAIRO_DOCK_IS_APPLET (icon));
				backendgui.ShowItems(m.Icon, nil, nil, -1)
			})

	case MenuHandbook:
		m.AddEntry(
			tran.Slate("Applet's handbook"),
			globals.IconNameAbout,
			m.Icon.ModuleInstance().PopupAboutApplet)

		// handbook + 5x to facto
		// picon := icon
		// if container.IsDesklet() {
		// 	picon = container.Icon()
		// 	icon = (CAIRO_DESKLET (pContainer))->pIcon;  // l'icone cliquee du desklet n'est pas forcement celle qui contient le module !
		// }

	case MenuHelp:
		m.AddEntry(
			tran.Slate("Help"),
			globals.IconNameHelp,
			func() { backendgui.ShowModuleGui("Help") },
		).SetTooltipText(tran.Slate("There are no problems, only solutions (and a lot of useful hints!)"))

	case MenuLaunchNew:
		m.AddEntry(
			tran.Slate("Launch a new (Shift+clic)"),
			globals.IconNameAdd,
			func() { m.Icon.LaunchCommand(log) })

	case MenuLockIcons:
		m.AddCheckEntry(
			tran.Slate("Lock icons position"),
			current.Docks.LockIcons(),
			func() {
				current.Docks.LockIcons(!current.Docks.LockIcons())
				config.UpdateFile(log, globals.ConfigFile(), "Accessibility", "lock icons", current.Docks.LockIcons())
			},
		).SetTooltipText(tran.Slate("This will (un)lock the position of the icons."))

	case MenuMakeLauncher:
		m.AddEntry(
			tran.Slate("Make it a launcher"),
			globals.IconNameNew,
			func() {
				C._cairo_dock_make_launcher_from_appli((*C.Icon)(unsafe.Pointer(m.Icon.ToNative())), (*C.CairoDock)(unsafe.Pointer(m.Dock.Ptr)))
			})

	case MenuMoveToDesktopClass:
		m.moveToDesktop(true)

	case MenuMoveToDesktopWindow:
		m.moveToDesktop(false)

	case MenuMoveToDock:
		sub := m.AddSubMenu(tran.Slate("Move to another dock"), globals.IconNameJumpTo)

		docks := gldi.GetAllAvailableDocks(m.Icon.GetContainer().ToCairoDock(), m.Icon.GetSubDock())
		docks = append(docks, nil)
		for _, dock := range docks {
			name := ""
			key := ""
			icon := ""
			if dock == nil {
				name = tran.Slate("New main dock")
				icon = globals.IconNameAdd // globals.IconNameNew
			} else {
				name = ternary.String(dock.GetReadableName() != "", dock.GetReadableName(), dock.GetDockName())
				key = dock.GetDockName()

				if dock.GetRefCount() == 0 { // Maindocks icon
					switch dock.Container().ScreenBorder() {
					case cdtype.ContainerPositionBottom:
						icon = "go-down"
					case cdtype.ContainerPositionTop:
						icon = "go-up"
					case cdtype.ContainerPositionLeft:
						icon = "go-previous"
					case cdtype.ContainerPositionRight:
						icon = "go-next"
					}
				} else { // Subdocks icon.
					dockicon := dock.SearchIconPointingOnDock(nil)
					if dockicon != nil {
						icon = dockicon.GetFileName()
					}
				}

			}
			sub.AddEntry(
				name,
				icon,
				func() {
					if key == "" {
						key = gldi.DockAddConfFile()
					}

					m.Icon.WriteContainerNameInConfFile(key) // Update icon conf file.

					if m.Icon.IsLauncher() || m.Icon.IsStackIcon() || m.Icon.IsSeparator() { // Reload icon (creating the dock).
						gldi.ObjectReload(m.Icon)

					} else if m.Icon.IsApplet() {
						gldi.ObjectReload(m.Icon.ModuleInstance())
					}

					newdock := gldi.DockGet(key)
					if newdock != nil && newdock.GetRefCount() == 0 && len(newdock.Icons()) == 1 {
						str := tran.Slate("The new dock has been created.\nYou can customize it by right-clicking on it -> cairo-dock -> configure this dock.")
						dialog.ShowGeneralMessage(str, 8000) // we don't show it on the new dock as its window isn't positioned yet (0,0).
					}
				})
		}

	case MenuQuickHide:
		m.AddEntry(
			tran.Slate("Quick-Hide"),
			globals.IconNameGotoBottom,
			gldi.QuickHideAllDocks,
		).SetTooltipText(tran.Slate("This will hide the dock until you hover over it with the mouse."))

	case MenuQuit:
		item := m.AddEntry(
			tran.Slate("Quit"),
			globals.IconNameQuit,
			func() {
				backendgui.CloseGui()

				// gtk.MainQuit() // TODO: remove SQP HACK, easy quit no confirm for tests.

				dialog.ShowWithQuestion("Quit Cairo-Dock?",
					GetIconForDesklet(m.Icon, m.Container),
					m.Container,
					globals.FileCairoDockIcon(),
					cbDialogIsOK(gtk.MainQuit))
			})

		// const gchar *cDesktopSession = g_getenv ("DESKTOP_SESSION");
		// gboolean bIsCairoDockSession = cDesktopSession && g_str_has_prefix (cDesktopSession, "cairo-dock");

		// 	// if we're using a Cairo-Dock session and we quit the dock we have... nothing to relaunch it!
		// 	if bIsCairoDockSession {

		// item.SetSensitive(false)
		// item.SetTooltipText("You're using a Cairo-Dock Session!\nIt's not advised to quit the dock but you can press Shift to unlock this menu entry.")

		// static void _cairo_dock_set_sensitive_quit_menu (G_GNUC_UNUSED GtkWidget *pMenuItem, GdkEventKey *pKey, GtkWidget *pQuitEntry)
		// {
		// pMenuItem not used because we want to only modify one entry
		// 	if (pKey->type == GDK_KEY_PRESS &&
		// 		(pKey->keyval == GDK_KEY_Shift_L ||
		// 		pKey->keyval == GDK_KEY_Shift_R)) // pressed
		// 		gtk_widget_set_sensitive (pQuitEntry, TRUE); // unlocked
		// 	else if (pKey->state & GDK_SHIFT_MASK) // released
		// 		gtk_widget_set_sensitive (pQuitEntry, FALSE); // locked)
		// }
		cbSensitive := func(_ *gtk.CheckMenuItem, event *gdk.Event) {
			key := &gdk.EventKey{Event: event}

			println("key", key.KeyVal())

			if key.KeyVal() == uint(C.GDK_KEY_Shift_R) { // pressed.
				item.SetSensitive(true)

			} else if gdk.ModifierType(key.State())&gdk.GDK_SHIFT_MASK > 0 { // released.
				item.SetSensitive(false)
			}
		}

		_, e := item.Connect("key-press-event", cbSensitive)
		if e != nil {
			println((e.Error()))
		}
		item.Connect("key-release-event", cbSensitive)

		// 		gtk_widget_set_sensitive (pMenuItem, FALSE); // locked
		// 		gtk_widget_set_tooltip_text (pMenuItem, _("You're using a Cairo-Dock Session!\nIt's not advised to quit the dock but you can press Shift to unlock this menu entry."));
		// 		// signal to unlock the entry (signal monitored only in the submenu)
		// 		g_signal_connect (pSubMenu, "key-press-event", G_CALLBACK (_cairo_dock_set_sensitive_quit_menu), pMenuItem);
		// 		g_signal_connect (pSubMenu, "key-release-event", G_CALLBACK (_cairo_dock_set_sensitive_quit_menu), pMenuItem);
		// 	}

		// case MenuAutostart:

		// 	gchar *cCairoAutoStartDirPath = g_strdup_printf ("%s/.config/autostart", g_getenv ("HOME"));
		// 	gchar *cCairoAutoStartEntryPath = g_strdup_printf ("%s/cairo-dock.desktop", cCairoAutoStartDirPath);
		// 	gchar *cCairoAutoStartEntryPath2 = g_strdup_printf ("%s/cairo-dock-cairo.desktop", cCairoAutoStartDirPath);
		// 	if (! bIsCairoDockSession && ! g_file_test (cCairoAutoStartEntryPath, G_FILE_TEST_EXISTS) && ! g_file_test (cCairoAutoStartEntryPath2, G_FILE_TEST_EXISTS))
		// 	{
		// 		cairo_dock_add_in_menu_with_stock_and_data (_("Launch Cairo-Dock on startup"),
		// 			GLDI_ICON_NAME_ADD,
		// 			G_CALLBACK (_cairo_dock_add_autostart),
		// 			pSubMenu,
		// 			NULL);
		// 	}
		// 	g_free (cCairoAutoStartEntryPath);
		// 	g_free (cCairoAutoStartEntryPath2);
		// 	g_free (cCairoAutoStartDirPath);

		// case MenuThirdParty:

		// 	pMenuItem = cairo_dock_add_in_menu_with_stock_and_data (_("Get more applets!"),
		// 		GLDI_ICON_NAME_ADD,
		// 		G_CALLBACK (_cairo_dock_show_third_party_applets),
		// 		pSubMenu,
		// 		NULL);
		// 	gtk_widget_set_tooltip_text (pMenuItem, _("Third-party applets provide integration with many programs, like Pidgin"));

	case MenuRemoveApplet:
		m.AddEntry(
			tran.Slate("Remove"),
			globals.IconNameRemove,
			func() {
				// if (CAIRO_DOCK_IS_DESKLET (pContainer))
				// 	icon = (CAIRO_DESKLET (pContainer))->pIcon;  // l'icone cliquee du desklet n'est pas forcement celle qui contient le module !
				// g_return_if_fail (CAIRO_DOCK_IS_APPLET (icon));

				dialog.ShowWithQuestion(
					fmt.Sprintf("You're about to remove this applet (%s) from the dock. Are you sure?", m.Icon.ModuleInstance().Module().VisitCard().GetTitle()),
					m.Icon,
					m.Container,
					"same icon",
					cbDialogIsOK(func() {
						gldi.ObjectDelete(m.Icon.ModuleInstance())
					}))
			})

	case MenuRemoveIcon:
		m.AddEntry(
			tran.Slate("Remove"),
			globals.IconNameRemove,
			func() {
				name := ternary.String(m.Icon.GetInitialName() != "", m.Icon.GetInitialName(), m.Icon.GetName())
				if name == "" {
					name = ternary.String(m.Icon.IsSeparator(), tran.Slate("separator"), "no name")
				}
				dialog.ShowWithQuestion(
					fmt.Sprintf(tran.Slate("You're about to remove this icon (%s) from the dock. Are you sure?"), name),
					m.Icon,
					m.Container,
					"same icon",
					cbDialogIsOK(func() {
						if m.Icon.IsStackIcon() && m.Icon.GetSubDock() != nil && len(m.Icon.GetSubDock().Icons()) > 0 {
							dialog.ShowWithQuestion(
								tran.Slate("Do you want to re-dispatch the icons contained inside this container into the dock?\n(otherwise they will be destroyed)"),
								m.Icon,
								m.Container,
								globals.FileCairoDockIcon(),
								cbDialogIsOK(func() {
									m.Icon.RemoveIconsFromSubdock(m.Dock)
								}))
						}

						m.Icon.RemoveFromDock()
					}))
			}).SetTooltipText(tran.Slate("You can remove a launcher by dragging it out of the dock with the mouse ."))

	case MenuThemes:
		// 		pMenuItem = cairo_dock_add_in_menu_with_stock_and_data (_("Manage themes"),
		// 			CAIRO_DOCK_SHARE_DATA_DIR"/icons/icon-appearance.svg",
		// 			G_CALLBACK (_cairo_dock_initiate_theme_management),
		// 			pSubMenu,
		// 			NULL);
		// 		gtk_widget_set_tooltip_text (pMenuItem, _("Choose from amongst many themes on the server or save your current theme."));

	case MenuWindowAbove:
		flag := m.Icon.Window().IsAbove()
		m.AddEntry(
			ternary.String(flag, tran.Slate("Don't keep above"), tran.Slate("Keep above")),
			ternary.String(flag, globals.IconNameGotoBottom, globals.IconNameGotoTop),
			m.Icon.CallbackActionWindowToggle((cdglobal.Window).SetAbove, (cdglobal.Window).IsAbove))

	case MenuWindowBelow:
		if !m.Icon.Window().IsHidden() { // this could be a button in the menu, if we find an icon that doesn't look too much like the "minimise" one
			m.AddEntry(
				tran.Slate("Below other windows")+actionMiddleClick(m.Icon, 4),
				globals.DirShareData("icons", "icon-lower.svg"),
				m.Icon.CallbackActionWindow((cdglobal.Window).Lower))
		}

	case MenuWindowFullScreen:
		flag := m.Icon.Window().IsFullScreen()
		m.AddEntry(
			ternary.String(flag, tran.Slate("Not Fullscreen"), tran.Slate("Fullscreen")),
			ternary.String(flag, globals.IconNameLeaveFullScreen, globals.IconNameFullScreen),
			m.Icon.CallbackActionWindowToggle((cdglobal.Window).SetFullScreen, (cdglobal.Window).IsFullScreen))

	case MenuWindowKill:
		m.AddEntry(
			tran.Slate("Kill"),
			globals.IconNameClose,
			m.Icon.CallbackActionWindow((cdglobal.Window).Kill))

	case MenuWindowMoveAllHere:
		m.AddEntry(
			tran.Slate("Move all to this desktop"),
			globals.IconNameJumpTo,
			m.Icon.CallbackActionSubWindows((cdglobal.Window).MoveToCurrentDesktop))

	case MenuWindowMoveHere:
		var callback func()
		if !m.Icon.Window().IsOnCurrentDesktop() {
			callback = m.Icon.CallbackActionWindow(func(win cdglobal.Window) {
				win.MoveToCurrentDesktop()
				if !win.IsHidden() {
					win.Show()
				}
			})
		}
		m.AddEntry(tran.Slate("Move to this desktop"), globals.IconNameJumpTo, callback)

	case MenuWindowSticky:
		m.AddEntry(
			ternary.String(m.Icon.Window().IsSticky(), tran.Slate("Visible only on this desktop"), tran.Slate("Visible on all desktops")),
			globals.IconNameJumpTo,
			m.Icon.CallbackActionWindowToggle((cdglobal.Window).SetSticky, (cdglobal.Window).IsSticky))

	}
	return notif.AnswerLetPass
}