User Tools

Site Tools


New submenu for GNOME

Let's show it on the real example:

I want to create a new submenu for an abandonware games which I love. However, I've got many of them. So, my goal is to create a new menu: Applications → Games → Old Games. A tool for an automatic creation of menu entries would be also nice.

Create a new menu

New menus should be created in /etc/xdg/menus/applications-merged/. I've created file old-games.menu here:

<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
  <Name>Applications</Name>
 
  <!-- Games -->
  <Menu>
    <Name>Games</Name>
    <Directory>Game.directory</Directory>
    <Include>
      <And>
        <Category>Game</Category>
      </And>
    </Include>
 
  <Menu> <!-- Old Games -->
    <Name>old-games</Name>
    <Directory>old-games.directory</Directory>
    <Include>
      <Category>OldGame</Category>
    </Include>
  </Menu> <!-- End Old Games -->
 
  </Menu> <!-- End Games -->
 
</Menu> <!-- End Applications -->

The next step is to create a specification for the new submenu. The default location is in /usr/share/desktop-directories. My old-games.directory:

[Desktop Entry]
Type=Directory
Name=Old games
Name[sk]=Klasické hry
Icon=folder

If you modify Icon property, you can set some nice icon for your submenu

Adding items

A item of our new submenu should look like this:

[Desktop Entry]
Encoding=UTF-8
Name=Sample app
Comment=Its comment
Exec=dosbox /home/old-games/app/app.exe -fullscreen -exit
Icon=dosbox
Terminal=false
Type=Application
Categories=OldGame;

Because I love using apps with nice GUI and I need to generate many .desktop files the simple application in python & PyGTK was created:

genarator.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import os
import sys
 
try:
	import pygtk
	pygtk.require("2.0")
	import gtk
except:
	os.stderr.write("Application needs at least PyGTK 2.0")
	os.exit(1)
 
class DesktopFileGenerator:
	def __init__(self):
		""" Prepare GUI """
 
		self.window = gtk.Window()
		self.window.connect("destroy", gtk.main_quit)
		self.window.set_border_width(10)
		self.window.set_title("Generator of Desktop Files")
 
		# Vertical layout
		vbox = gtk.VBox(spacing = 10)
 
		# Heading
		heading = gtk.Label("<b>Generator of Desktop Files</b>")
		heading.set_use_markup(True)
		vbox.pack_start(heading)
 
		# Defining inputs
		input = []
 
		input.append( ('File to execute', gtk.FileChooserButton("Choose File to Execute")) )
 
 
		boxFileName  = gtk.HBox()
		entryFileName = gtk.Entry()
		boxFileName.pack_start(entryFileName)
 
		sufixFileName = gtk.Label(".desktop")
		boxFileName.pack_start(sufixFileName)
 
		input.append( ('Filename', boxFileName) )
		input.append( ('Application name', gtk.Entry()) )
		input.append( ('Comment', gtk.Entry()) )
		input.append( ('Icon', gtk.FileChooserButton("Choose Icon for the application")) )
 
		# Table of input fields
		table = gtk.Table(rows = len(input), columns = 2)
		self.fields = {}
		for line, field in enumerate(input):
			name = field[0] + ":"
			nameLabel = gtk.Label(name)
			table.attach(nameLabel, 0, 1, line, line+1)
			table.attach(field[1], 1, 2, line, line+1)
 
			# Nasty hack
			if field[0] == "Filename":
				self.fields[ field[0] ] = entryFileName
			else:
				self.fields[ field[0] ] = field[1]
 
 
		vbox.pack_start(table)
 
		# Buttons
		buttonBox = gtk.HButtonBox()
		buttonBox.set_layout(gtk.BUTTONBOX_END)
 
		createButton = gtk.Button(stock = gtk.STOCK_SAVE)
		createButton.connect("clicked", self._generateFile)
		buttonBox.pack_start(createButton)
 
		quitButton = gtk.Button(stock = gtk.STOCK_CLOSE)
		quitButton.connect("clicked", gtk.main_quit)
		buttonBox.pack_start(quitButton)
 
		vbox.pack_start(buttonBox)
 
		self.window.add(vbox)
		self.window.show_all()
 
	def run(self):
		""" Run application """
 
		gtk.main()
 
	def _generateFile(self, button):
		""" Generate a desktop file """
 
		try:
			name = self.fields['Application name'].get_text().strip()
			if not name:
				raise Exception, "You have to input the name of the application"
 
			comment = self.fields['Comment'].get_text().strip()
			if not comment:
				raise Exception, "You have to input the comment of the application"
 
			execFile = self.fields['File to execute'].get_filename()
			if not execFile:
				raise Exception, "You have to choose some file"
 
			icon = self.fields['Icon'].get_filename()
			if not icon:
				icon = "dosbox"
 
			fileName = self.fields['Filename'].get_text().strip() + ".desktop"
			if not fileName:
				raise Exception, "You have to enter name of generated file"
 
			file = open(fileName, "w")
			file.write("""[Desktop Entry]
Encoding=UTF-8
Name=%s
Comment=%s
Exec=dosbox %s -fullscreen -exit
Icon=%s
Terminal=false
Type=Application
Categories=Application;Game;OldGame;
""" % (name, comment, execFile, icon) )
			file.close()
 
		except: # Any error
			message = "Caught error =>\n\t%s" % str(sys.exc_value)
			errorMessage = gtk.MessageDialog(parent = self.window, 
				flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
				type = gtk.MESSAGE_ERROR,
				buttons = gtk.BUTTONS_OK,
				message_format = message)
 
			errorMessage.set_title("Error!")
			errorMessage.run()
			errorMessage.destroy()
			return
 
		message = "File '%s' successfully generated!" % fileName
		reportMessage = gtk.MessageDialog(parent = self.window, 
			flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
			type = gtk.MESSAGE_INFO,
			buttons = gtk.BUTTONS_OK,
			message_format = message)
		reportMessage.set_title("File generated")
		reportMessage.run()
		reportMessage.destroy()
 
 
		# Cleaning
		for name, object in self.fields.iteritems():
			if isinstance(object, gtk.Entry):
				object.set_text("")
 
		self.fields['File to execute'].grab_focus()
 
 
if __name__ == "__main__":
	generator = DesktopFileGenerator()
	generator.run()

I run this application in empty directory. I generate desktop file for each program. Afterwards I copy these files into /usr/share/applications.

Log Out && Log In

To apply these changes you have to log out and afterwards log in. The new submenu should wait for you.

Sources

howto/gnome-menu-edit.txt · Last modified: 2011/07/16 22:37 (external edit)