"A Study of Linux Kernel Internals and GNOME Development" (Feb.2003-July 2003) by Rajalaxmi Mishra & Sarita Mohanty under the guidance of Dr. Samar Abbas as partial fulfillment of the requirements for the M.Tech. degree in Computer Science, Utkal University, Bhubaneshwar. CHAPTER- 1 Introduction to Linux 1.1.Introduction Linux is a multi-user and multitasking operating system. As a multitasking system, one can ask the system to perform several tasks at the same time. While one task is being executed, one can work on another. For example, one can edit a file while another file is being printed. As a multi-user system, several users can log in to the system at the same time, each interacting with the system through their own terminal. Linux is an operating system for PC computers and workstations that now features a fully functional graphical user Interface(GUI). Linus Torvalds developed Linux in the early 1990s, along with other programmers around the world. As an operating system, Linux performs many of the same functions as Unix, Mac, Windows and Windows NT. Now with both Gnome (GNU Object Model Environment) and KDE (K Desktop Environment), Linux also provides GUI interfaces with a high level of flexibility and power. Linux is free including the network servers and GUI desktop. Unlike the official Unix operating system, Linux is distributed freely under a GNU general public license as specified by the Free Software Foundation making it available to any one who wants to use it. 1.2.Defining an operating system When computers were first created 40 or 50 years ago, every thing the computer needed to do was hard wired, meaning that instructions were arranged in the wires and other components that made up the computer. Because of this, a computer was able to complete only a single task, the one that it was hard wired to perform. The example, a computer might be designed to add or subtract two numbers, but not have any other capability. As more powerful computer hardware became available, programmers began to demand more flexibility. The result was software .The term software refers to the programs that control the physical components, providing instructions for completing a task. Unlike a hard-wired system software can be changed without disassembling the computer itself obviously, this was real progress. Early software everything the computer needed to complete a task. Before long however, programmer decided it was more efficient to create one kind of software that provided core functionality and then to create applications that built upon those basic functions. An application is a program that provides a service to a person using the computer, rather than simply managing the computer’s resources. For example word processors and accounting software are applications. The core functionality was designed to send instructions to the hardware. Applications could then use the core functionality for more specific tasks .For example, one core function might be the ability to print characters on the monitor. An application could then use this functionality to print specific characters for a spread-sheet, a word processor or other programs. This set of core functionality is called as the operating system. Although operating systems have advanced a great deal in the last 30 years, the basic purpose remains the same. An operating system is the program that contains the set of core functionality for other programs, proving both the interfaces between other programs and the hardware, and the interface between other programs and the user sitting at the computer. 1.2.1 Commonly used operating systems Some of the better known operating systems that are or have been used around the world are described here. Many other operating systems besides those mentioned here are still in use. The Disk Operating system DOS was created in about 1980. Despite very limited functionality, it gained widespread acceptance when IBM introduced the first personal computer, the IBM PC, in August 1981.DOS was designed to make efficient use of very limited hardware resources for a single user on the computer. Neither UNIX nor DOS included a graphical interface of any kind. The operating system provided only character-based screens, which required the user to type a series of commands. At a time several graphical interfaces were developed for each operating system. These graphical interfaces provided additional core functionality that other programs could draw upon. The leading graphical interface for UNIX was called the X Window System. This system is still in use today and is also used for graphical displays on the Linux operating system. The leading graphical interface for DOS became Microsoft Windows. In 1984 Apple computer introduced the Macintosh system, which integrated the operating system and the graphical interface so that users remained essentially unaware of the operating system. Rather than having to type complicated text commands, users feel comfortable. Although the popularity of the MacIntosh never equaled that of Microsoft Windows perhaps because handing the operation system from novice users took root. In August 199 Microsoft introduced the Windows both updated many times since earlier versions. In this new version of window the user had no need to know about the operating system that provided the functionality for all the Windows programs running the system. While all this was happening in the world of personal computers, businesses continued to use UNIX systems and other specialized operating systems. These operating systems were much more powerful than DOS, Windows, or Macintosh systems, but they were also very expensive and only can on costly computer hardware. Microsoft continued development of its operating systems by creating a business-oriented product called Windows NT. Unlike the earlier version of windows, Windows NT did not include DOS as an underlying operating system. Instead, Windows NT was built on the VMS operating system, a business-oriented operating system that had been used for years on expensive minicomputers. A minicomputer, which is a multi user computer midway between a personal computer and a mainframe, cost between about, 20,000 and s 100,000 in the early 1990s. Windows NT developers sought to include UNIX features to capture the market of business users who wanted more power than a MacIntosh or windows 98 system provided. 1.3.The Arrival of Linux Into this fray, Linux arrived as a relative newcomer with a strange background .In 1991 a college student in Helsinki, Finland named Linus Thorvalds, began to create an operating system kernel as a school project. He wanted to use a UNIX like operating system. UNIX has always been popular on many college and university campuses, but he couldn’t his own UNIX system. Instead he began to clone, or duplicate ,the functionality of a UNIX kernel; for his IBM- compatible PC .This in itself would not be different from the efforts of many other students working to create something useful to save a few dollars. But the efforts of Linus Torvalds blossomed into something much bigger because of the work of many people with goals similar to his. The next section describes how Torvalds and others working around the world were able to finish a complete clone of the UNIX operating system by about 1993 , and why that operating system, dubbed Linux in honor of Linus, has had such a surprising impact in recent years. 1.4.Operating System and Linux An OS is a set of programs that manages computer hardware and software for the user. Operating systems were originally designed to perform repetitive hardware tasks. These tasks centered on managing files, running programs and receiving commands from a user. The user only needs to send instruction to the operating system to perform tasks, such as reading a file, printing a document, etc. An operating system also manages software applications. To perform different tasks, such as editing documents or performing calculations, specific software applications is needed. An editor is an example of a software application, which enables one to edit a document, making changes and adding new text. The editor itself is a program consisting of instructions to be executed by the computer. To use the program, it must first be loaded into computer memory, and then its instructions are executed. Operating systems were originally designed to support hardware efficiency. When computers were first developed, their capabilities were limited and the operating system had to make the most of them. In this respect, operating systems were designed with the hardware in mind, not the user. Linux, on the other hand, is designed to be flexible, reacting its UNIX roots. As a version of UNIX, Linux shares the same flexibility designed for UNIX. Ken Thompson at AT&T Bell Laboratories developed the UNIX operating system in the late 1960s and early 1970s. The UNIX system incorporated many new developments in operating system design. Originally, UNIX was designed as an operating system for researchers. 1.5.History of Linux and UNIX Linux was originally designed specifically for Intel based personal computers. Linux started out as a personal project of a computer science student named Linus Torvalds at the University of Helsinki. At that time, students were making use of an OS called minix, which highlighted different UNIX features. Minix was created by Professor Andrew Tannenbaum and widely distributed over the Internet to students around the world. Linus’s intention was to create an effective PC version of UNIX for Minix users. He called it Linux, and in 1991,Linus released version 0.11. Linux was widely distributed over the Internet and, in the following years, other programmers refined and added to it, incorporating most of the applications and features now found in standard UNIX systems. Although Linux has developed in the free and open environment of the INTERNET, it adheres to official UNIX standards. Because of the proliferation of UNIX versions in the previous decades, the institutes of Electrical and Electronics engineers IEEE developed an independent UNIX is called the portable operating system interface for computer Environments POSIX. The standard defines how a UNIX like system needs to operate specifying details such as system calls and interface. POSIX defines a universal standard to which all UNIX versions must ad-here. Most popular versions of UNIX are now POSIX-complaint. Linux was developed from the beginning according to the POSIX standard. Linux was developed from the beginning according to the POSIX standard. Linux also adheres to the Linus file system standard FASTENED, which specifies the location of files and directories in the Linux file structure. 1.6. Linux Overview Like UNIX, Linux can be generally divided into three major components; the kernel, the shell, the file structure. The kernel is the core programs and manages hardware devices, such as disks and printers. The environment provides an interface for the user. It receives commands from the user and sends those commands to the kernel for execution. The file structure organizes the way files are stored on a storage device, such as a disk. Files are organized into directories. Each directory may contain any number of subdirectories, each holding files. Together, the kernel, the environment, and the file structure form the basic operating system structure. With these three, one can run programs, manage files and interact with the system. An environment provides an interface between the kernel and the user. It can be described as an interpreter. An environment interprets commands entered by the user and sends them to the kernel. Linus provides several kinds of environments, desktops, window managers, and command line shells. Each user on a Linux system has own user interface. Users can tailor their environments to their own special needs, whether they be shell, window managers, or desktops. In this sense, for the user, the operating system functions more as an operating environment, which the user can control. The shell interface is simple and usually consists of a prompt at which user type a command and then presses ENTER. In a sense, users are typing the command on a line; this line is often referred to as the command line. One will find the commands entered on the command line can become quite compels. Over the years, several different kinds of shells have been developed and currently three major shells exist. 1.7. Linux Software Linux was developed as a cooperative effort over the INTERNET, so no company or institution controls Linux. Lately, major software companies are also developing Linux versions of their most popular applications. Netscape provides a Linux version of its popular web browser, which is now, included as standard on most Linux distributions. Corel has developed a Linux version of word perfect, while oracle provides a Linus version of its oracle database. (At present, no plans seem in the works for Microsoft applications.) Until recently however, many of these lacked a true desktop interface, but this has changed dramatically both the introduction of KDE and Gnome. These desktops are not merely interfaces; they both provide extensive, flexible, and powerful development libraries that software developers can use to create almost any kind of application. One of the most important features of Linux, as well as all UNIX systems, is its set of INTERNET clients and servers. The INTERNET was designed and developed on UNIX systems, and INTERNET clients and servers, such as those for FTP and the Web, were first implemented on BSD versions of UNIX. DARPANET, the precursor to the INTERNET, was set up to link UNIX systems at different universities across the nation. Linux contains a full set of INTERNET clients and servers including mail, news, FTP and web, as well as proxy clients and servers. 1.8. Documentation Linux documentation has also been developed over the INTERNET. Much of the documentation currently available for Linux can be downloaded from INTERNET FTP sites. A special Linux project called the Linux documentation project(LDP),headed by Matt Welsh, is currently developing a complete set of Linux manuals. The documentation, at its current level, is available at the LDP home site at www.linuxdoc.org. In addition too FTP sites, Linux Usenet newsgroups are also available. Through the INTERNET connection, one can access Linux newsgroups to read the comments of other Linux users and to post own messages. Several Linux newsgroups exist, each beginning with comp.os. Linux. One of particular interest to the beginner is comp.os.linux.help, where one can post questions. Various tables list the different Linux newsgroups available on Usenet. 1.9. The Spirit Of Linux Several factors were working in favor of Linus Torvalds as he sought to create an operating system for his PC. Finland had (and has) excellent INTERNET access, especially on its college campuses. This gave Torvalds access to a worldwide network of people who could help him develop Linux. As a computer science student, Torvalds (and those who helped him) could draw on 40 years of shared experience with the UNIX operating system. All of the design and experimentation that had gone into creating UNIS could be implemented in the kernel that Torvalds created from scratch. Torvalds was working as an individual, with other individuals. Decisions about how to do things could be based on technical considerations rather than on market needs, a fact that often drives the actions of commercial software companies, sometimes to the detriment of those using the software. The most popular operating system at the time (that is, from 19961to 1996) was Microsoft windows. Many Windows users were becoming frustrated with some of its features and with its lack of stability. They were also frustrated by delays in Microsoft’s promised upgrades to windows. Torvalds decided to base the software license for the Linux kernel on a model used by Richard Stallman and the Free Software Foundation. The fact that the license to a piece of software would be so important in its history is unusual and bears more explanation. 1.9.1 The Linux Software License A software license is a legal definition of who can use the software and how it can be used. The programmer who develops a piece of software decides how the software will be licensed. Licenses for commercial software usually state that user can use one copy of the software ( the one user paid for), that one may not copy the software, that company is not responsible for how user use it ,and so forth. The license for Linux is quite different, as one will learn in the following sections. 1.10. The free software foundation and the GNU project In 1983 Richard Stallman at the Massachusetts institute of technology founded an organization called the free software foundation (FSF).Stallmans motivating idea was that software should be freely available, without restrictions on copying. He proposed that companies could make money nu caging for services and customization, but that the software itself should nor be restricted in its distribution by a standard commercial license agreement. To backup his opinions, Stallman and those working with the FSF created hundreds of utilities that run on the UNIX operating system and distributed them freely around the world. This efforts was called the GNU project. The GNU project intended to created a completely free UNIX- like operating system. When almost the entire project was finished , Linus Torvalds appeared with the final crucial piece; the kernel .The software created by the GNU project is still used by millions of people and is included with every Linux distribution. One of the best known products of the GNU project is the C language compiler called gcc. This is a software program for converting C language programming instructions into code Thant a computer can execute .The gcc compiler is the most widely used, highly regarded compiler in the world. The explanation given here for the work of the free software foundation is necessarily simplistic. Much more information about both the philosophy of free software and the relationship between GNU and Linux is available at www.fsf.org. The GNU General public license (GPL): The license that Richard Stallman designed for the programs created by the GNU project is called the GNU general public license, often abbreviated as the GPL. Torvalds eventually released the Linux kernel under the GPL .The allowed Linux to develop rapidly but it is an unusual license in several ways. It includes the following points. A programmer who decides to license a piece of software under the GPI gives away the source code to the software. The source code is the set of human readable programming instructions used to create the program. Normally, only the machine readable binary code used to execute a program is distributed. Including the source code makes it possible for anyone to modify the original program. 1.11. How Linux is developed Linux kernel development follows the model of most GPL or Open source projects. To begin a project a person identifies a need and then begins writing a program. At some point, the developer announces the work on the INTERNET. Developers who share an interest in that project respond, and soon they begin to work together on different parts of the project. This process works well and in fact is exactly how Linus .Torvald started to create the linux kernel. After a certain level of completion has been reached , the project’s source code is released on the INTERNET (Since the inception of Linux, the source code has been distributed via the INTERNET site ftp; fpt.funet.fi, based in Finland.) At this point, thousands of people download the source code and begin to try it out. Some of those people send back information about problems they have encountered (soft-ware bugs).The core team of developers tries to fix the bugs ,occasionally working with other developers who have submitted bug fixes or specific enhancements to the software. Linus Torvalds continues to work on the Linux kernel , along with a core group of developers who control what is included in Linux. Some commercial users of Linux have posed the unpleasant question of what will happen to Linux if something happens to Linus Torvalds take over. Each member of that team is a recognized expert in Linux torvalds leads them now , but he could conceivably retire from that position, leaving another qualified individual to continue the work. 1.12. Linux Distributions The Linux kernel originally created by Linux Torvald’s did not provide the functionality of a full-blown commercial operating system. To be really useful for the majority of organizations, Linux also requires. • Networking utilities. • System administration utilities. • Documentation • Installation tools. • Technical support information • Hardware drivers. • A graphical environment (like the X Window) • Graphical tools • Personal productivity applications such as word processors or spreadsheets Given the way that Linux is developed ( With developers all over the world creating and documenting its various parts), user might wonder how the many pieces of Linux could be combined into a complete operating system. Such a productized version of Linux, which includes many software components installation tools documentation and so forth is called a Linux distribution. A Linux distribution Has the Linux kernel at its core along with hundreds or thousands or thousands of additional programs that run on Linux. Most of these are related to managing the Linux system in other words they are system utilities. The system utilities are drawn largely from the GNU project of the FSF. For this reason many propel refer to Linux distribution as the GNU/Linux operating system.When taken as a whole, a Linux distribution makes it possible for non programmers to install and use Linux. 1.13. Distribution in the marketplace Many new companies are attempting to meet the need for a Linux system that is ready to use. In accordance with the GPL, the companies include in their distributions the source code for the Linux kernel, as well as many other utilities. They can charge as much as they choose for their Linux distributions because the software is freely available from other sources, the distributor essentially functions as a kind of packaging service that saves users the trouble of downloading a large number of files from the IN-TERNET. Thus distention prices have generally been quite low-between $2 and $100. The Linux kernel and utilities offered by the many Linux vender’s are practically identical, thus vendors often add commercial components or other software to make their distribution more attractive to consumers. Chapter 2 ARCHITECTURE OF LINUX SYSTEM 2.1. Introduction Architecture of Linux System The hardware is at the center. The operating system interacts directly with the hardware, providing common services to programs and insulating them from hardware idiosyncrasies. Viewing the system as a set of layers, the operating system is commonly called the system kernel or just the kernel. Because the programs are independent of the underlying hardware, it is easy to move them between LINUX systems running on different hardware. Programs such as the shell and editors (ed and vi) present in the outer layer, interact with the kernel by invoking a well defined set of system calls. The system calls instruct the kernel to do various operations for the calling program and exchange data between the kernel and the program. Many applications provide high-level view of the system. They all use lower level services ultimately provided by the kernel, and they avail themselves these services via the set of system calls. User programs trap user level kernel level Kernel level Hardware level The above figure shows three level : user, kernel and hardware. This gives a block diagram of the kernel, showing various modules and their relationships with each other. It shows the file subsystem and process control subsystem, the two major components of the kernel. System calls look like ordinary function calls in C programs and libraries map these function calls to the primitive needed to enter the operating system. Assembly language program may invoke system calls directly without system call library. Programs frequently use other libraries such as the standard IO library to provide a more sophisticated use of the system calls. The libraries are linked with the programs at compile time and are thus a part of the user program. The figure partition the system calls into the sets, those interact with the file subsystem and those interact with the process control subsystem. The file subsystem manages files, allocating file space, administering free space, controlling access to files, and retrieving data for users. Processes interact with the file subsystem via a specific set of system calls, such as open( to open a file for reading or writing), close, read, write, stat(query the attributes of a file), chown(change the record of who owns the file), and chmod (change the access permission of a file). The file subsystem access file data using a buffering mechanism that regulates data flow between the kernel and secondary storage devices. The buffering mechanism interacts with the block I/O device drivers to initiate data transfer to and from the kernel. Device drivers are the kernel modules that control the operation of peripheral devices. Block I/O devices are random access storage devices. The process control subsystem is responsible for process synchronization, inter process communication, memory management and process scheduling. The file subsystem and the process subsystem interact when loading a file into memory for execution. The memory management module controls the allocation of memory. If at any time the system does not have enough physical memory for all processes, the kernel moves them between main memory and secondary memory so that all processes get a fair chance to execute. The scheduler modules allocate the CPU to processes. It schedules them to run in turn until they voluntarily relinquish the CPU while awaiting a resource or until the kernel preempts them when their recent run time exceeds a time quantum. The scheduler then chooses the highest priority eligible process to run; the original process will run again when it is the highest priority eligible process available. There are several forms of inter process communication, ranging from asynchronous signaling of events to synchronous transmission of messages between processes. Finally, the hardware control is responsible for handling interrupts and for communicating with the machine. Devices such as disks or terminals may interrupt the CPU while a process is executing. If so, the kernel may resume execution of the interrupted process after servicing the interrupt. Interrupts are not serviced by special processes but by special functions in the kernel, called in the context of the currently running process. 2.2. File Subsystem The internal representation of a file is given by an inode or indexe node, which contains a description of the disk layout of the file data and other information such as the file owner, access permissions, and access times. Every file has one inode, but it may have several names all of which map into the inode. Each name is called a link. When a process refers to a file by name, the kernel parses the file name one component at a time, checks that the process has permission to search the directories in the path, and eventually retrieves the inode of the file. When a process creates a new file, the kernel assigns it an unused inode. Inodes are stored in the file system, but the kernel reads them into an in-core inode table when manipulating files. The kernel contains two other data structures, the file table and the user file descriptor table. The file table is the global kernel structure, but the user file descriptor table is allocated per process. When a process opens or creates a file, the kernel allocates an entry from each table, corresponding to the file’s inode. Entries in the three structures – user file descriptor table, file table, and the inode table – maintain the state of the file and the user’s access to it. The file table keeps track of the byte offset in the file where the user’s next read/write will start, and the access rights allowed to the opening process. The user file descriptor table identifies all open files for a process. User file Descriptor File Inode Table Table Table The kernel returns a file descriptor for the open and creat system calls, which is an index into the user file descriptor table. When executing read/write system calls, the kernel uses the file descriptor to access the user file descriptor table, follows pointers to the file table and inode table entries, and from the inode finds the data in the file. An installation may have several physical disk units, each containing one or more file systems. Partitioning a disk into several file system makes it easier for administrators to manage the data stored there. The kernel deals on a logical level with file systems rather than with disks, treating each one as a logical device identified by a logical device number. The conversion between a logical device (file system) addresses and physical device addresses is done by the disk driver. A file system consists of a sequence of logical blocks, each containing 512, 1024, 2048, or any convenient multiple of 512 bytes, depending on the system implementation. The size of a logical block is homogeneous within a file system but may vary between different file systems in a system configuration. Using large logical blocks increases the effective data transfer rate between disk and memory, because the kernel can transfer more data per disk operation and therefore make fewer time consuming operations. A file system has the following structure : A boot block occupies the beginning of a file system, typically the first sector, and may contain the bootstrap code that is read into the machine to boot, or initialize, the operating system. Although only one boot block is needed to boot the system, every file system has a boot block. The super block describes the state of the file system i.e., how large it is, how many files it can store, where to find free space on the file system, and other information. The inode list is a list of inodes that follows the super block in the file system. Administrators specify the size of the inode list when configuring a file system. The kernel references inodes by index into the inode list. One inode is the root inode of the file system: it is the inode by which the directory structure of the file system is accessible after execution of the mount system call. The data blocks start at the end of the inode list and contain file data and administrative data. An allocated data block can belong to one and only one file in the file system. 2.2.1.Inodes Inodes exist in a static form on disk, and the kernel reads them into an in-core inode to manipulate them. Disk inodes consist of the following fields: File owner identifier. Ownership is divided between the individual owner and a group owner and defines the set of users who have access rights to a file. The super user has access rights to all files in the system. File type. Files may be of type regular, directory, character or block special, or FIFO (pipes). File access permissions. The system protects files according to three classes: the owner and the group owner of the file, and other users; each class has access rights to read, write and execute the file, which can be set individually. Because directories can not be executed, execution permission for a directory gives the right to search the directory for a file name. File access times, giving the time the file was last modified, when it was last accessed, and when the inode was last modified. Number of links to a file, representing the number of names the file has in the directory hierarchy. Table of contents for the disk access of data in a file. Although users treat the data in file as a logical stream of bytes, the kernel saves data in discontinuous disk blocks. The inode identifies the disk blocks that contain the file’s data. File size. Data in a file is addressable by the number of bytes from the beginning of the file, starting from byte offset 0, and the file size is 1 greater than the highest byte offset of data in the file. The contents of inode change when changing the contents of the file or when changing its owner, permission, or link settings. Changing the contents of a file automatically implies a change to the inode, but changing the inode does not imply that the contents of the file change. The in-core copy of the inode contains the following fields in addition to the fields of the disk inode: The status of the in-core inode, indicating whether the inode is locked, a process is waiting for the inode to become unlocked, the in-core representation of the inode differs from the disk copy as a result of a change to the data in the inode, the in-core representation of the file differs from the disk copy as a result of a change to the file data, the file is a mount point The logical device number of the file system that contains the file. The inode number. Since inodes are stored in a linear array on disk, the kernel identifies the number of a disk inode by its position in the array. The disk inode does not need this field. Pointers to othe in-core inodes. The kernel links inodes on hash queues and on a free list in the same way that it links buffers on buffer hash queues and on the buffer free list. A reference count, indicating the number of instances of the file that are active. 2.2.2. Accessing inodes The kernel identifies particular inodes by their file system and inode number and allocates in-core inodes at the request of higher-level algorithm. The maps the device number and inode number into a hash queue and searches the queue for the inode. If it cannot find the inode, it allocates one from the free list and locks it. The kernel then prepares to read the disk copy of the newly accessed inode into the in-core copy. It already knows the inode number and logical device and computes the logical disk block that contains the inode according to how many disk inodes fit into a disk block. The kernel manipulates the inode lock and reference count independently. The lock is set during execution of a system call to prevent other processes from accessing the inode while it is in use. The kernel releases the lock at the conclusion of the system call: an inode is never locked across system calls. The kernel increments the reference count for every active reference to a file. 2.2.3. Releasing inodes When the kernel releases an inode, it decrements its in-core reference count. If the count drops to zero, the kernel writes the inode to disk if the in-core copy differs from the disk copy. They differ if the file data has changed, if the file access time has changed, or if the file owner or access permissions have changed. The kernel places the inode on the free list of inodes, effectively caching the inode in case it is needed again soon. The kernel may also release all data blocks associated with the file and free the inode if the number of links to the file is zero. 2.3. System Calls For The File Subsystem OPEN The open system call is the first step a process must take to access the data in a file. The syntax of open system call is fd = open(pathname, flags, modes) where pathname is a file name, flags indicate the type of open (such as reading or writing), and modes give the file permissions if the file is being created. The open system call returns an integer called the user file descriptor. Other file operations such as reading, writing, seeking, duplicating the file descriptor, setting file I/O parameters, determining file status, and closing the file, use the file descriptor that the open system call returns. The kernel searches the file system for the file name parameter using algorithm namei. It checks permissions for opening the file after it finds the in-core inode and allocates an entry in the file table for the open file. The file table entry contains a pointer to the inode of the open file and a field that indicates the byte offset in the file where the kernel expects the next read or write to begin. The kernel initializes the offset to 0 during the open call, meaning that the initial read or write starts at the beginning of a file by default. Each open call results in allocation of a unique entry in the user file descriptor table and in the kernel file table, but the kernel contains at most one entry per file in the in-core inode table. The first three user descriptors (0,1 & 2) are called standard input, standard output, and standard error file descriptors. READ The syntax of the read system call is number = read(fd, buffer, count) where fd is the file descriptor returned by open, buffer is the address of a data structure in the user process that will contain the read data on successful completion of the call, count is the number of bytes the user wants to read, and the number is the number of bytes actually read. WRITE The syntax for the write system call is number = write(fd, buffer, count) where fd is the file descriptor returned by open, buffer is the address of a data structure in the user process that will contain the data to be written on successful completion of the call, count is the number of bytes the user wants to write, and the number is the number of bytes actually written. LSEEK – Adjusting the position of file I/O The ordinary use of read / write system calls provides sequential access to a file, but processes can use the lseek system call to poison the I/O and allow random access to a file. The syntax for the lseek system call is position=lseek(fd, offset, reference) where fd is the file descriptor identifying the file, offset is a byte offset, and reference indicates whether offset should be considered from the beginning of the file, or from the current position of the read/write offset, or from end of the file. The return value position is the byte offset where the next read or write will start. CLOSE A process closes an open file when it no longer wants to access it. The syntax for the close system call is Close(fd) where fd is the file descriptor of the open file. The kernel does the close operation by manipulating the file descriptor and the corresponding file table and inode table entries. CREAT – File Creation The creat system call creates a new file in the system. The syntax for creat system call is fd=creat( pathname,modes); where pathname is a file name, modes give the file permissions if the file is being created. The creat system call returns an integer called the user file descriptor. If no such file previously existed, the kernel creates a new file with the specified name and permission modes. If the file already existed, the kernel truncates the file subject to suitable file access permissions. CHDIR and CHROOT – Change directory and Change root The system call chdir changes the current directory of a process. The syntax of the chdir system call is chdir(pathname) where pathname is the directory that becomes the new current directory of the process. A process usually uses the global file system root for all path names starting with “/”. The kernel contains a variable that points to the inode of the global root. Processes can change their notion of the file system root via chroot system call. This is useful if a user wants to simulate the usual file system hierarchy and run processes there. The syntax of chroot is chroot(pathname); where pathname is the directory that the kernel subsequently treats as the process’s root directory. CHOWN and CHMOD – Change owner and Change mode Changing the owner or mode (access permissions) of a file are operations on the inode, not on the file. The syntax of the calls is: chown(pathname,owner,group); chmod(pathname, mode); STAT and FSTAT The system calls stat and fstat allow processes to query the status of fiels, returning information such as file type, file owner, access permissions, file size, number of links, inode number, and file access times. The syntax for the system calls is stat(pathname, statbuffer); fstat(fd,statbuffer); where pathname is a file name, fd is a file descriptor returned by previous open call, and statbuffer is the address of a data structure in the user process that will contain the status information of the file on completion of the call. 2.4. Processes A process is the execution of a program and consists of a pattern of bytes that the CPU interprets as machine instruction, data and stack. Many process appear to execute simultaneously as the kernel schedules them for execution, and several processes may be instances of one program. A process executes by following a strict sequence of instructions that is self contained and does not jump to that of another process; it reads and writes its data and stack sections, but it can not read or write the data and stack of other processes. Processes communicate with other processes and with the rest of the world through system calls. A process on a Linux system is created by fork system call. Every process except process 0 is created when another process executes the fork system call. The process that invoked the fork system call is the parent process, and the newly created process is the child process. Every process has one parent process, but a process can have many child processes. The kernel identifies each process by its process number, called the process ID (PID). Process 0 is the special process that is created when the system boots; after forking a process (process 1), process 0 becomes the swapper process. The kernel loads an executable file into memory during an exec system call, and the loaded process consists of at least three parts, called regions : text, data and the stack. The text and data regions correspond to the text and data sections of the executable file, but the stack region is automatically created and its size is dynamically adjusted by the kernel at run time. The stack consists of logical stack frames that are pushed when calling a function and popped when returning; a special pointer called the stack pointer indicates the current stack depth. A stack frame contains the parameter to a function, its local variables and the data necessary to recover the previous stack frame, including the value of the program counter and stack pointer at the time of the System call. A process in Linux system can execute in two modes, kernel or user, it uses a separate stack for each mode. The user stack contains the arguments, local variables and other data for functions executing in user mode. When the process executes the special function, it switches mode to kernel, executes kernel code, and uses the kernel stack. The kernel stack contains the stack frames for functions executing in kernel mode. 2.5. The System Calls for controlling Processes Some of the system calls for controlling processes are fork ( create a new process), exec (overlay the image of a program onto the running process, exit (finish executing a process), wait (synchronize process execution with the exit of a previously forked process), brk (control the size of the memory allocated to a process), and signal (control process response to extra ordinary events). 2.6. Some Programs on System calls 2.6.1. WriteFile.c This program writes on to a file. #include main() { int fd; char buf[1024]; fd = creat("junk",0666); lseek(fd,2000L,2); /* 0|1|2 = bof|present pos|beyd eof */ write(fd,"hello",5); close(fd); fd = open("junk",O_RDONLY); read(fd,buf,1024); /* */ read(fd,buf,1024); /* , 0 */ ead(fd,buf,1024); } 2.6.2. ShellDemo.c /* Under Linux systems, the program that reads in the prompt and starts pograms is not really part of the operating system. It is called the shell, and it runs as a regular user program. This program uses another system call called waitpid, which a program can use to wait until a process completes its task. The waitpid system call requires three parameters, one to specific which process to wait for; another is an int* saying where to store the process's exit code; and the last parameter is for options (0 is fine here). int waitpid(int pid, int *status, int options)*/ #include #include #define CMD_LEN 120 int main(int argc, char **argv) { char cmd[CMD_LEN]; char *cmd_args[2]; int n; int child_pid; while(1) { /* read command from user */ write(1, "% ", 2); // 0|1|2 = stdin|stdout|stderr n = read(0, cmd, CMD_LEN); if(n == 0) break; /* EOF reached; exit program */ cmd[n - 1] = '\0'; /* replace '\n' with '\0' */ cmd_args[0] = cmd; cmd_args[1] = NULL; /* fork off child to execute command */ child_pid = fork(); if(child_pid == 0) { execvp(cmd, cmd_args); // process to run a different program /* If execvp returns, the command is bad. */ write(1, "Command not found\n", 19); exit(-1); } /* wait for child to exit before continuing */ waitpid(child_pid, &n, 0); } return 0; } Chapter-3 Glade 3.1 Introduction Glade is an application for creating graphical user interfaces that use the Gtk+ and GNOME libraries. Glade permits one to develop these interfaces rapidly, and can create source code in a variety of languages like C, C++, Perl, Ada etc., that will construct the interfaces. Glade can also be used in conjunction with libglade to dynamically create user interfaces from the XML description file that Glade creates. 3.2 Using Glade Glade is composed of several windows which each serve a particular purpose. The main window contains the menu, toolbar and a list of top-level windows. The palette lists the various user interface objects which one can use to build an interface. The property editor lets one manipulate the properties of widgets, such as their size, color, signal masks,etc. Typically a Glade project begins with the construction of the user interface. Using the palette, one composes and inserts widgets until one arrives at the desired interface. While doing this usually one uses the property editor to manipulate the various packing settings, dimensions, etc., of the widgets. After the interface is finished, the project is saved and the C source files that will be used to generate the user interface are built. Integration of project logic then follows. Some other things the user may do are: 1. Use libglade to build the interface 2. Use Glade to set the signal handlers for the widgets 3. Create Perl or Eiffel code instead of C The various parts of Glade are described in detail in the sec-tions that follow. 3.3. Top-Level Window List The main window displays a list of the top-level Gtk+ and GNOME windows that are defined for the current project. This includes: GtkWindow GtkDialog GtkFileSelection GtkColorSelectionDialog GtkFontSelectionDialog GtkInputDialog GnomeApp GnomeDialog GnomeMessageBox GnomeAbout 3.4. What Glade can and cannot do: Glade develops the GUI and associated code It creates empty callbacks and signal handlers to link the front end GUI with the backend of the application Glade does not develop the ‘backend’ of the application Glade is not a complete IDE, in other words it does not include a compiler, editor or debugger. It is used in conjunction with these, for example with gvim as the editor, gcc as the compiler and gdb as the debugger. 3.5. Basic Terminologies Frontend/Gui : The graphical interface that a user sees and interacts with in a windowing environment. Backend/Guts : The part of the application that actual does something, manipulates input from the user, provides output, does computation etc. This part of the application should be completely invisible to the user. Widget : One of several or many elements used to build a window. Callback/Signal Handler/Signal : The widget will emit a ‘signal’ depending upon a certain user actions. The signal handler or callback is the function that responds to that signal. 3.6. Example : Displaying and Hiding A Picture This program displays two radio buttons in a window with the labels ‘Hide Picture’ and ‘Show Picture’ and a button with label ‘Close’. It will display the picture when one clicks on ‘Show Picture’ button and hides the picture when one clicks on the hide picture button. When one clicks on close button the window is closed. callbacks.c #ifdef HAVE CONFIG H #include < config.h > #endif #include < gtk/gtk.h > #include "callbacks.h" #include "interface.h" #include "support.h" void on close clicked (GtkButton *button,gpointer user data) { gtk main quit();} void on radiobutton2 released (GtkButton *button,gpointer user data) { GtkImage *pix; pix= GTK IMAGE(lookup widget(button,"image1")); gtk_widget_hide(pix); } void on radiobutton1 released (GtkButton *button,gpointer user data) { GtkImage *pix; pix= GTK IMAGE(lookup widget(button,"image1")); gtk_widget_show(pix); } 3.7. Example – xsu program /* This program is developed by Rajalaxmi Mishra * this is a graphical version of su command*/ Here the user has to supply the username and the command then click on the ‘Ok’ button, then the user can login as that username and execute that command in a xterm terminal. #ifdef HAVE_CONFIG_H # include #endif #include #include "callbacks.h" #include "interface.h" #include "support.h" void on_button1_clicked (GtkButton *button, gpointer user_data) { GtkWidget *term; gchar *username, *password, *command; GtkWidget * en1 =lookup_widget(GTK_WIDGET(button), "entry1"); GtkWidget * en2 =lookup_widget(GTK_WIDGET(button), "entry2"); GtkWidget * en3 =lookup_widget(GTK_WIDGET(button), "entry3"); command= gtk_entry_get_text(GTK_ENTRY(en1)); username=gtk_entry_get_text(GTK_ENTRY(en2)); password = gtk_entry_get_text(GTK_ENTRY(en3)); execlp("xterm","xterm","-e","su","-c",command,"-",username,NULL); } void on_button3_clicked (GtkButton *button, gpointer user_data) { gtk_main_quit(); } 3.8. Example : xmessage This program displays a message ‘Hello’ #ifdef HAVE_CONFIG_H # include #endif #include #include "callbacks.h" #include "interface.h" #include "support.h" void on_button1_clicked(GtkButton *button, gpointer user_data) { execlp("gnome-terminal","gnome-terminal","-e","xmessage hello",NULL); } void on_button2_clicked (GtkButton *button, gpointer user_data) { gtk_main_quit(); } This the output of xmessage program 3.9. Conclusion Glade provides a handy method for rapidly creating GNOME applications. It is faster than hard-coding the programs and permits accelerated development. However, certain highly specialized and advanced Gtk features have not been provided by this front-end. In this case, hard-coding is required. Chapter 4 GTK 4.1. Introduction GTK (GIMP Toolkit) is a library for creating graphical user interfaces. It is licensed using the GPL(GNU Public License) license. Hence open software, free software, or even commercial non-free software can be developed using GTK without incurring expenses with regard to licenses or royalties. It is called the GIMP toolkit because it was originally written for developing the GIMP (GNU Image Manipulation Program), but GTK has now been used in a large number of software projects, including the GNOME (GNU Network Object Model Environment) project. GTK is built on top of GDK (GIMP Drawing Kit) that is basically a set of wrapper classes around the low-level functions for accessing the underlying windowing interfaces (Xlib in the case of the X windows system), and gdk-pixbuf, a library for client-side image manipulation. GTK is essentially an object oriented application programmer’s interface (API). Although written completely in C, it is implemented using the idea of classes and callback functions (pointers to functions). Here a simple program is given below to create and display a window. #include int main( int argc,char *argv[] ) { GtkWidget *window; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_show (window); gtk_main (); return 0;} The above program can be compiled with gcc using: gcc base.c -o base `pkg-config --cflags --libs gtk+-2.0` or gcc -Wall -g base.c -o base `pkg-config --cflags gtk+-2.0` \`pkg-config --libs gtk+-2.0` This uses the program pkg-config, which can be obtained from www.freedesktop.org. This program determines what compiler switches are needed to compile programs that use GTK. The command pkg-config --cflags gtk+-2.0 will output a list of include directories for the compiler to look in, and pkg-config --libs gtk+-2.0 will output the list of libraries for the compiler to link with and the directories to find them in. In the above example they could have been combined into a single instance, such as pkg-config --cflags --libs gtk+-2.0. The libraries that are usually linked in are: The GTK library (-lgtk), the widget library, based on GDK and forming a separate abstraction layer. The GDK library (-lgdk), the Xlib wrappers. The gdk-pixbuf library (-lgdk_pixbuf), the image manipulation library. The Pango library (-lpango) for internationalized text. The gobject library (-lgobject), containing the type system on which GTK is based. The gmodule library (-lgmodule), which is used to load run time extensions. The GLib library (-lglib), containing miscellaneous functions. GTK is built on top of GLib so it will always be required. The Xlib library (-lX11) which is used by GDK. The Xext library (-lXext). This contains code for shared memory pixmaps and other X extensions. The math library (-lm). This is used by GTK for various purposes. All programs will include gtk/gtk.h which declares the variables, functions, structures, etc. that will be used in the GTK application. The next line: gtk_init (&argc, &argv); calls the function gtk_init(gint *argc, gchar ***argv) which will be called in all GTK applications. This sets up a few things such as the default visual and color map and then proceeds to call gdk_init(gint *argc, gchar ***argv). This function initializes the library for use, sets up default signal handlers, and checks the arguments passed to the application on the command line, looking for one of the following: --gtk-module --g-fatal-warnings --gtk-debug --gtk-no-debug --gdk-debug --gdk-no-debug --display --sync --name --class It removes these from the argument list, leaving anything it does not recognize for the application to parse or ignore. This creates a set of standard arguments accepted by all GTK applications. The next two lines of code create and display a window. window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_show (window); The GTK_WINDOW_TOPLEVEL argument specifies that the window is to undergo window manager decoration and placement. Rather than create a window of 0x0 size, a window without children is set to 200x200 by default it can still be manipulated. The gtk_widget_show() function lets GTK know that setting the attributes of this widget is done and it can display it. The last line enters the GTK main processing loop. gtk_main (); gtk_main() is another call present in every GTK application. When control reaches this point, GTK will sleep waiting for X events (such as button or key presses), timeouts, or file IO notifications to occur. GTK is an event driven toolkit, which means it will sleep in gtk_main() until an event occurs and control is passed to the appropriate function. This passing of control is done using the idea of "signals". (These signals are not the same as the Linux system signals, and are not implemented using them, although the terminology is almost identical.) When an event occurs, such as the press of a mouse button, the appropriate signal will be "emitted" by the widget that was pressed. This is how GTK does most of its useful work. There are signals that all widgets inherit, such as "destroy", and there are signals that are widget specific, such as "toggled" on a toggle button. To make a button perform an action, one can set up a signal handler to catch these signals and call the appropriate function. This can be done by using the following function: gulong g_signal_connect( gpointer *object, const gchar *name, GCallback func, gpointer func_data ); where the first argument is the widget which will be emitting the signal, and the second the name of the signal that is to be catch. The third is the function that is to be called when it is caught, and the fourth, the data to be passed to this function. The function specified in the third argument is called a "callback function", and should generally be of the form void callback_func( GtkWidget *widget, gpointer callback_data ); where the first argument will be a pointer to the widget that emitted the signal, and the second a pointer to the data given as the last argument to the g_signal_connect() function as shown above. 4.2. Events In addition to the signal mechanism described above, there is a set of events that reflect the X event mechanism. Callbacks may also be attached to these events. These events are: event button_press_event button_release_event scroll_event motion_notify_event delete_event destroy_event expose_event key_press_event key_release_event enter_notify_event leave_notify_event configure_event focus_in_event focus_out_event map_event unmap_event property_notify_event selection_clear_event selection_request_event selection_notify_event proximity_in_event proximity_out_event visibility_notify_event client_event no_expose_event window_state_event GdkEvent is a C union structure whose type will depend upon which of the above events has occurred. In order to tell which event has been issued each of the possible alternatives has a type member that reflects the event being issued. The other components of the event structure will depend upon the type of the event. Possible values for the type are: GDK_NOTHING GDK_DELETE GDK_DESTROY GDK_EXPOSE GDK_MOTION_NOTIFY GDK_BUTTON_PRESS GDK_2BUTTON_PRESS GDK_3BUTTON_PRESS GDK_BUTTON_RELEASE GDK_KEY_PRESS GDK_KEY_RELEASE GDK_ENTER_NOTIFY GDK_LEAVE_NOTIFY GDK_FOCUS_CHANGE GDK_CONFIGURE GDK_MAP GDK_UNMAP GDK_PROPERTY_NOTIFY GDK_SELECTION_CLEAR GDK_SELECTION_REQUEST GDK_SELECTION_NOTIFY GDK_PROXIMITY_IN GDK_PROXIMITY_OUT GDK_DRAG_ENTER GDK_DRAG_LEAVE GDK_DRAG_MOTION GDK_DRAG_STATUS GDK_DROP_START GDK_DROP_FINISHED GDK_CLIENT_EVENT GDK_VISIBILITY_NOTIFY GDK_NO_EXPOSE GDK_SCROLL GDK_WINDOW_STATE GDK_SETTING 4.3. Data Types The gint, gchar, etc. are typedefs to int and char, respectively, that are part of the GLib system. This is done to get around that nasty dependency on the size of simple data types when doing calculations. A good example is "gint32" which will be typedef'd to a 32 bit integer for any given platform, whether it be the 64 bit alpha, or the 32 bit i386. The typedefs are very straightforward and intuitive. They are all defined in glib/glib.h (which gets included from gtk.h). 4.4. Widgets When creating an application, it is desired to put more than one widget inside a window. A gtk_container_add() call can be used to "pack" the widget into the window. When more than one widget need to be put into a window, it can be controlled where that widget is positioned using packing. 4.4.1. Theory of Packing Boxes Creating boxes does most packing. These are invisible widget containers that can pack the widgets into which come in two forms, a horizontal box, and a vertical box. When packing widgets into a horizontal box, the objects are inserted horizontally from left to right or right to left depending on the call used. In a vertical box, widgets are packed from top to bottom or vice versa. Any combination of boxes inside or beside other boxes can be used to create the desired effect. 4.4.2. Widget Overview The general steps to creating a widget in GTK are: 1.gtk_*_new() - one of various functions to create a new widget. 2.All signals and events shall be connected to the appropriate handlers. 3.The attributes of the widget shall be set. 4.The widget shall be packed into a container using the appropriate call such as gtk_container_add() or gtk_box_pack_start(). 5.gtk_widget_show() the widget. gtk_widget_show() lets GTK know that the attributes of the widget are set , and it is ready to be displayed. The children of a widget (a window is a widget too) will not be displayed until the window itself is shown using the gtk_widget_show() function. Many widgets are also containers. In the class hierarchy below, many widgets derive from the Container class. Any one of these widgets may be used with the GTK_CONTAINER macro to pass them to functions that ask for containers. 4.4.3. Widget Hierarchy Here is the class hierarchy tree used to implement widgets. (Deprecated widgets and auxiliary classes have been omitted.) GObject | GtkObject +GtkWidget | +GtkMisc | | +GtkLabel | | | `GtkAccelLabel | | +GtkArrow | | `GtkImage | +GtkContainer | | +GtkBin | | | +GtkAlignment | | | +GtkFrame | | | | `GtkAspectFrame | | | +GtkButton | | | | +GtkToggleButton | | | | | `GtkCheckButton | | | | | `GtkRadioButton | | | | `GtkOptionMenu | | | +GtkItem | | | | +GtkMenuItem | | | | +GtkCheckMenuItem | | | | | `GtkRadioMenuItem | | | | +GtkImageMenuItem | | | | +GtkSeparatorMenuItem | | | | `GtkTearoffMenuItem | | | +GtkWindow | | | | +GtkDialog | | | | | +GtkColorSelectionDialog | | | | | +GtkFileSelection | | | | | +GtkFontSelectionDialog | | | | | +GtkInputDialog | | | | | `GtkMessageDialog | | | | `GtkPlug | | | +GtkEventBox | | | +GtkHandleBox | | | +GtkScrolledWindow | | | `GtkViewport | | +GtkBox | | | +GtkButtonBox | | | | +GtkHButtonBox | | | | `GtkVButtonBox | | | +GtkVBox | | | | +GtkColorSelection | | | | +GtkFontSelection | | | | `GtkGammaCurve | | | `GtkHBox | | | +GtkCombo | | | `GtkStatusbar | | +GtkFixed | | +GtkPaned | | | +GtkHPaned | | | `GtkVPaned | | +GtkLayout | | +GtkMenuShell | | | +GtkMenuBar | | | `GtkMenu | | +GtkNotebook | | +GtkSocket | | +GtkTable | | +GtkTextView | | +GtkToolbar | | `GtkTreeView | +GtkCalendar | +GtkDrawingArea | | `GtkCurve | +GtkEditable | | +GtkEntry | | `GtkSpinButton | +GtkRuler | | +GtkHRuler | | `GtkVRuler | +GtkRange | | +GtkScale | | | +GtkHScale | | | `GtkVScale | | `GtkScrollbar | | +GtkHScrollbar | | `GtkVScrollbar | +GtkSeparator | | +GtkHSeparator | | `GtkVSeparator | +GtkInvisible | +GtkPreview | `GtkProgressBar +GtkAdjustment +GtkCellRenderer | +GtkCellRendererPixbuf | +GtkCellRendererText | +GtkCellRendererToggle +GtkItemFactory +GtkTooltips `GtkTreeViewColumn 4.5. The Button Widget 4.5.1. Normal Buttons gtk_button_new_with_label()or gtk_button_new_with_mnemonic() can be called to create a button with a label, gtk_button_new_from_stock() can be called to create a button containing the image and text from a stock item or gtk_button_new() can be called to create a blank button. 4.5.2. Toggle Buttons Toggle buttons are derived from normal buttons and are very similar, except they will always be in one of two states, alternated by a click. They may be depressed, and when clicked again, they will pop back up. When clicked again, and they will pop back down. Toggle buttons are the basis for check buttons and radio buttons, as such, many of the calls used for toggle buttons are inherited by radio and check buttons. Any of the functions given below can be called to create a new toggle button: GtkWidget *gtk_toggle_button_new( void ); GtkWidget *gtk_toggle_button_new_with_label (const gchar *label); GtkWidget *gtk_toggle_button_new_with_mnemonic ( const gchar *label ); 4.5.3. Check Buttons Check buttons inherit many properties and functions from the toggle buttons, but look a little different. Rather than being buttons with text inside them, they are small squares with the text to the right of them. These are often used for toggling options on and off in applications. The creation functions are similar to those of the normal button. GtkWidget *gtk_check_button_new( void ); GtkWidget *gtk_check_button_new_with_label ( const gchar *label ); GtkWidget *gtk_check_button_new_with_mnemonic ( const gchar *label ); The gtk_check_button_new_with_label() function creates a check button with a label beside it. 4.5.4. Radio Buttons Radio buttons are similar to check buttons except they are grouped so that only one may be selected/depressed at a time. Creating a new radio button is done with one of these function calls: GtkWidget *gtk_radio_button_new( GSList *group ); GtkWidget *gtk_radio_button_new_from_widget ( GtkRadioButton *group ); GtkWidget *gtk_radio_button_new_with_label( GSList *group, const gchar *label ); GtkWidget* gtk_radio_button_new_with_label_from_widget ( GtkRadioButton *group,const gchar *label ); GtkWidget *gtk_radio_button_new_with_mnemonic (GSList *group, const gchar *label ); GtkWidget *gtk_radio_button_new_with_mnemonic_from_widget ( GtkRadioButton *group, const gchar *label ); 4.6. Adjustments GTK has various widgets that can be visually adjusted by the user using the mouse or the keyboard, such as the range widgets. There are also a few widgets that display some adjustable portion of a larger area of data, such as the text widget and the viewport widget. Obviously, an application needs to be able to react to changes the user makes in range widgets. One way to do this would be to have each widget emit its own type of signal when its adjustment changes, and either pass the new value to the signal handler, or require it to look inside the widget's data structure in order to ascertain the value. But it may also need to connect the adjustments of several widgets together, so that adjusting one adjusts the others. The most obvious example of this is connecting a scrollbar to a panning viewport or a scrolling text area. If each widget has its own way of setting or getting the adjustment value, then the programmer may have to write their own signal handlers to translate between the output of one widget's signal and the "input" of another's adjustment setting function. GTK solves this problem using the Adjustment object, which are not a widget but a way for widgets to store and pass adjustment information in an abstract and flexible form. The most obvious use of Adjustment is to store the configuration parameters and values of range widgets, such as scrollbars and scale controls. However, since Adjustments are derived from Object, they have some special powers beyond those of normal data structures. Most importantly, they can emit signals, just like widgets, and these signals can be used not only to allow the program to react to user input on adjustable widgets, but also to propagate adjustment values transparently between adjustable widgets. 4.7. Range Widgets The category of range widgets includes the ubiquitous scrollbar widget and the less common scale widget. Though these two types of widgets are generally used for different purposes, they are quite similar in function and implementation. All range widgets share a set of common graphic elements, each of which has its own X window and receives events. They all contain a "trough" and a "slider" (what is sometimes called a "thumbwheel" in other GUI environments). Dragging the slider with the pointer moves it back and forth within the trough, while clicking in the trough advances the slider towards the location of the click, either completely, or by a designated amount, depending on which mouse button is used. All range widgets are associated with an adjustment object, from which they calculate the length of the slider and its position within the trough. When the user manipulates the slider, the range widget will change the value of the adjustment. 4.8. Scrollbar Widgets These are the standard, run-of-the-mill scrollbars. These should be used only for scrolling some other widget, such as a list, a text box, or a viewport (and it's generally easier to use the scrolled window widget in most cases). There are separate types for horizontal and vertical scrollbars. They can be created with the following functions: GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment ); GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment ); 4.9. Scale Widgets Scale widgets are used to allow the user to visually select and manipulate a value within a specific range. One might want to use a scale widget, for example, to adjust the magnification level on a zoomed preview of a picture, or to control the brightness of a color, or to specify the number of minutes of inactivity before a screensaver takes over the screen. Setting the Update Policy The "update policy" of a range widget defines at what points during user interaction it will change the value field of its Adjustment and emit the "value_changed" signal on this Adjustment. The update policies, defined in as type enum GtkUpdateType, are: GTK_UPDATE_CONTINUOUS This is the default. The "value_changed" signal is emitted continuously, i.e., whenever the slider is moved by even the tiniest amount. GTK_UPDATE_DISCONTINUOUS The "value_changed" signal is only emitted once the slider has stopped moving and the user has released the mouse button. GTK_UPDATE_DELAYED The "value_changed" signal is emitted when the user releases the mouse button, or if the slider stops moving for a short period of time. The update policy of a range widget can be set by casting it using the GTK_RANGE(widget) macro and passing it to this function: void gtk_range_set_update_policy( GtkRange *range, GtkUpdateType policy); 4.10. Miscellaneous Widgets 4.10.1. Labels Labels are used a lot in GTK, and are relatively simple. Labels emit no signals as they do not have an associated X window. If the user needs to catch signals, or do clipping, it can be placed inside a EventBox widget or a Button widget. 4.10.2. Arrows The Arrow widget draws an arrowhead, facing in a number of possible directions and having a number of possible styles. It can be very useful when placed on a button in many applications. Like the Label widget, it emits no signals. 4.10.3. The Tooltips Object These are the little text strings that pop up when the user leaves the pointer over a button or other widget for a few seconds. They are easy to use Widgets that do not receive events (widgets that do not have their own window) will not work with tooltips. The first call the user will use creates a new tooltip. It only needs to do this once for a set of tooltips as the GtkTooltips object this function returns can be used to create multiple tooltips. GtkTooltips *gtk_tooltips_new( void ); Once a new tooltip is created, and the widget the user wish to use it on, simply this call can be used to set it: void gtk_tooltips_set_tip( GtkTooltips *tooltips, GtkWidget *widget, const gchar *tip_text, const gchar *tip_private ); The first argument is the tooltip that is already created, followed by the widget the user wish to have this tooltip pop up for, and the text the user wish it to say. The last argument is a text string that can be used as an identifier when using GtkTipsQuery to implement context sensitive help. 4.10.4. Progress Bars Progress bars are used to show the status of an operation. They are pretty easy to use. GtkWidget *gtk_progress_bar_new( void ); Now the progress bar has been created. void gtk_progress_bar_set_fraction ( GtkProgressBar *pbar, gdouble fraction ); The first argument is the progress bar the user wish to operate on, and the second argument is the amount "completed", meaning the amount the progress bar has been filled from 0-100%. This is passed to the function as a real number ranging from 0 to 1. 4.10.5. Dialogs The Dialog widget is very simple, and is actually just a window with a few things pre-packed into it. The structure for a Dialog is: struct GtkDialog { GtkWindow window; GtkWidget *vbox; GtkWidget *action_area; }; So, it simply creates a window, and then packs a vbox into the top, which contains a separator and then an hbox called the "action_area". The Dialog widget can be used for pop-up messages to the user, and other similar tasks. There are two functions to create a new Dialog. GtkWidget *gtk_dialog_new( void ); GtkWidget *gtk_dialog_new_with_buttons ( const gchar *title, GtkWindow *parent, GtkDialogFlags flags, const gchar *first_button_text, ... ); 4.10.6. Rulers Ruler widgets are used to indicate the location of the mouse pointer in a given window. A window can have a vertical ruler spanning across the width and a horizontal ruler spanning down the height. A small triangular indicator on the ruler shows the exact location of the pointer relative to the ruler. A ruler must first be created. Horizontal and vertical rulers are created using GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */ GtkWidget *gtk_vruler_new( void ); /* vertical ruler */ Once a ruler is created, one can define the unit of measurement. Units of measure for rulers can be GTK_PIXELS, GTK_INCHES or GTK_CENTIMETERS. This is set using void gtk_ruler_set_metric( GtkRuler *ruler, GtkMetricType metric ); The default measure is GTK_PIXELS. gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS ); Other important characteristics of a ruler are how to mark the units of scale and where the position indicator is initially placed. These are set for a ruler using void gtk_ruler_set_range( GtkRuler *ruler, gdouble lower, gdouble upper, gdouble position, gdouble max_size ); The lower and upper arguments define the extent of the ruler, and max_size is the largest possible number that will be displayed. Position defines the initial position of the pointer indicator within the ruler. A vertical ruler can span an 800 pixel wide window thus gtk_ruler_set_range(GTK_RULER(vruler), 0, 800, 0, 800); The markings displayed on the ruler will be from 0 to 800, with a number for every 100 pixels. 4.10.7. Statusbars Statusbars are simple widgets used to display a text message. They keep a stack of the messages pushed onto them, so that popping the current message will re-display the previous text message. In order to allow different parts of an application to use the same statusbar to display messages, the statusbar widget issues Context Identifiers which are used to identify different "users". The message on top of the stack is the one displayed, no matter what context it is in. Messages are stacked in last-in-first-out order, not context identifier order. A statusbar is created with a call to: GtkWidget *gtk_statusbar_new( void ); A new Context Identifier is requested using a call to the following function with a short textual description of the context: guint gtk_statusbar_get_context_id ( GtkStatusbar *statusbar, const gchar *context_description ); There are three functions that can operate on statusbars: guint gtk_statusbar_push( GtkStatusbar *statusbar, guint context_id, const gchar *text ); void gtk_statusbar_pop( GtkStatusbar *statusbar) guint context_id ); void gtk_statusbar_remove( GtkStatusbar *statusbar, guint context_id, guint message_id ); The first, gtk_statusbar_push(), is used to add a new message to the statusbar. It returns a Message Identifier, which can be passed later to the function gtk_statusbar_remove() to remove the message with the given Message and Context Identifiers from the statusbar's stack. The function gtk_statusbar_pop() removes the message highest in the stack with the given Context Identifier. 4.10.8. Text Entries The Entry widget allows text to be typed and displayed in a single line text box. The text may be set with function calls that allow new text to replace, prepend or append the current contents of the Entry widget. Create a new Entry widget with the following function. GtkWidget *gtk_entry_new( void ); The next function alters the text, which is currently within the Entry widget. void gtk_entry_set_text( GtkEntry *entry, const gchar *text ); The function gtk_entry_set_text() sets the contents of the Entry widget, replacing the current contents. Note that the class Entry implements the Editable interface (yes, gobject supports Java-like interfaces) which contains some more functions for manipulating the contents. Using a call to the following function can retrieve the contents of the Entry. This is useful in the callback functions described below. const gchar *gtk_entry_get_text( GtkEntry *entry ); The value returned by this function is used internally, and must not be freed using either free() or g_free(). If the user doesn't want the contents of the Entry to be changed by someone typing into it, he/she can change its editable state. void gtk_editable_set_editable( GtkEditable *entry, gboolean editable ); The function above allows to toggle the editable state of the Entry widget by passing in a TRUE or FALSE value for the editable argument. 4.10.9. Spin Buttons The Spin Button widget is generally used to allow the user to select a value from a range of numeric values. It consists of a text entry box with up and down arrow buttons attached to the side. Selecting one of the buttons causes the value to "spin" up and down the range of possible values. The entry box may also be edited directly to enter a specific value. The Spin Button allows the value to have zero or a number of decimal places and to be incremented/decremented in configurable steps. The action of holding down one of the buttons optionally results in an acceleration of change in the value according to how long it is depressed. The Spin Button uses an Adjustment object to hold information about the range of values that the spin button can take. This makes for a powerful Spin Button widget. An adjustment widget is created with the following function, which illustrates the information that it holds: GtkObject *gtk_adjustment_new( gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, gdouble page_size ); These attributes of an Adjustment are used by the Spin Button in the following way: value: initial value for the Spin Button lower: lower range value upper: upper range value step_increment: value to increment/decrement when pressing mouse button 1 on a button page_increment: value to increment/decrement when pressing mouse button 2 on a button page_size: unused 4.10.10. Combo Box The combo box is another fairly simple widget that is really just a collection of other widgets. From the user's point of view, the widget consists of a text entry box and a pull down menu from which the user can select one of a set of predefined entries. Alternatively, the user can type a different option directly into the text box. The following extract from the structure that defines a Combo Box identifies several of the components: struct _GtkCombo { GtkHBox hbox; GtkWidget *entry; GtkWidget *button; GtkWidget *popup; GtkWidget *popwin; GtkWidget *list; ... }; 4.10.11. Color Selection The color selection widget is, not surprisingly, a widget for interactive selection of colors. This composite widget lets the user select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue, Saturation, Value) triples. This is done either by adjusting single values with sliders or entries, or by picking the desired color from a hue-saturation wheel/value bar. Optionally, the opacity of the color can also be set. The color selection widget currently emits only one signal, "color_changed", which is emitted whenever the current color in the widget changes, either when the user changes it or if it's set explicitly through gtk_color_selection_set_color(). 4.10.12. File Selections The file selection widget is a quick and simple way to display a File dialog box. It comes complete with Ok, Cancel, and Help buttons, a great way to cut down on programming time. To create a new file selection box use: GtkWidget *gtk_file_selection_new( const gchar *title ); 4.11. Container Widgets 4.11.1. The EventBox Some GTK widgets don't have associated X windows, so they just draw on their parents. Because of this, they cannot receive events and if they are incorrectly sized, they don't clip so the user can get messy overwriting, etc. At first glance, the EventBox widget might appear to be totally useless. It draws nothing on the screen and responds to no events. However, it does serve a function - it provides an X window for its child widget. This is important as many GTK widgets do not have an associated X window. Not having an X window saves memory and improves performance, but also has some drawbacks. A widget without an X window cannot receive events, and does not perform any clipping on its contents. Although the name EventBox emphasizes the event-handling function, the widget can also be used for clipping. (and more, see the example below). To create a new EventBox widget, use: GtkWidget *gtk_event_box_new( void ); A child widget can then be added to this EventBox: gtk_container_add(GTK_CONTAINER(event_box),child_widget); 4.11.2. The Alignment widget The alignment widget allows to place a widget within its window at a position and size relative to the size of the Alignment widget itself. For example, it can be very useful for centering a widget within the window. There are only two functions associated with the Alignment widget: GtkWidget* gtk_alignment_new( gfloat xalign, gfloat yalign, gfloat xscale, gfloat yscale ); void gtk_alignment_set( GtkAlignment *alignment, gfloat xalign, gfloat yalign, gfloat xscale, gfloat yscale ); The first function creates a new Alignment widget with the specified parameters. The second function allows the alignment parameters of an existing Alignment widget to be altered. 4.11.3. Layout Container The Layout container is similar to the Fixed container except that it implements an infinite (where infinity is less than 2^32) scrolling area. The X window system has a limitation where windows can be at most 32767 pixels wide or tall. The Layout container gets around this limitation by doing some exotic stuff using window, so that the user can have smooth scrolling even when he has many child widgets in his scrolling area. A Layout container is created using: GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment, GtkAdjustment *vadjustment ); 4.11.4. Frames Frames can be used to enclose one or a group of widgets with a box which can optionally be labelled. The position of the label and the style of the box can be altered to suit. A Frame can be created with the following function: GtkWidget *gtk_frame_new( const gchar *label ); The label is by default placed in the upper left hand corner of the frame. A value of NULL for the label argument will result in no label being displayed. The text of the label can be changed using the next function. void gtk_frame_set_label( GtkFrame *frame, const gchar *label ); The position of the label can be changed using this function: void gtk_frame_set_label_align( GtkFrame *frame, gfloat xalign, gfloat yalign ); 4.11.5. Paned Window Widgets The paned window widgets are useful when it needs to divide an area into two parts, with the relative size of the two parts controlled by the user. A groove is drawn between the two portions with a handle that the user can drag to change the ratio. The division can either be horizontal (HPaned) or vertical (VPaned). To create a new paned window, call one of: GtkWidget *gtk_hpaned_new (void); GtkWidget *gtk_vpaned_new (void); 4.11.6. Viewports It is unlikely that the user will ever need to use the Viewport widget directly. The user is much more likely to use the Scrolled Window widget which itself uses the Viewport. A viewport widget allows to place a larger widget within it such that it can be viewed a part of it at a time. It uses Adjustments to define the area that is currently in view. A Viewport is created with the function GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment, GtkAdjustment *vadjustment ); 4.11.7. Scrolled Windows Scrolled windows are used to create a scrollable area with another widget inside it. The user may insert any type of widget into a scrolled window, and it will be accessible regardless of the size by using the scrollbars. The following function is used to create a new scrolled window. GtkWidget *gtk_scrolled_window_new ( GtkAdjustment *hadjustment, GtkAdjustment *vadjustment ); 4.11.8. Button Boxes Button Boxes are a convenient way to quickly layout a group of buttons. They come in both horizontal and vertical flavours. A new Button Box can be created with one of the following calls, which create a horizontal or vertical box, respectively: GtkWidget *gtk_hbutton_box_new( void ); GtkWidget *gtk_vbutton_box_new( void ); 4.11.9. Toolbar Toolbars are usually used to group some number of widgets in order to simplify customization of their look and layout. Typically a toolbar consists of buttons with icons, labels and tooltips, but any other widget can also be put inside a toolbar. Finally, items can be arranged horizontally or vertically and buttons can be displayed with icons, labels, or both. Creating a toolbar is done with the following function: GtkWidget *gtk_toolbar_new( void ); After creating a toolbar one can append, prepend and insert items (that means simple text strings) or elements (that means any widget types) into the toolbar. To describe an item a label text is needed, a tooltip text, a private tooltip text, an icon for the button and a callback function for it. For example, to append or prepend an item, the following functions may be used: GtkWidget *gtk_toolbar_append_item ( GtkToolbar *toolbar, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data ); GtkWidget *gtk_toolbar_prepend_item ( GtkToolbar *toolbar, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data ); If the user want to use gtk_toolbar_insert_item(), the only additional parameter which must be specified is the position in which the item should be inserted, thus: GtkWidget *gtk_toolbar_insert_item ( GtkToolbar *toolbar, const char *text, const char *tooltip_text, const char *tooltip_private_text, GtkWidget *icon, GtkSignalFunc callback, gpointer user_data, gint position ); To simplify adding spaces between toolbar items, the user may use the following functions: void gtk_toolbar_append_space( GtkToolbar *toolbar ); void gtk_toolbar_prepend_space( GtkToolbar *toolbar ); void gtk_toolbar_insert_space( GtkToolbar *toolbar, gint position ); If it's required, the orientation of a toolbar and its style can be changed "on the fly" using the following functions: void gtk_toolbar_set_orientation ( GtkToolbar *toolbar, GtkOrientation orientation ); void gtk_toolbar_set_style( GtkToolbar *toolbar, GtkToolbarStyle style ); void gtk_toolbar_set_tooltips( GtkToolbar *toolbar, gint enable ); Where orientation is one of GTK_ORIENTATION_HORIZONTAL or GTK_ORIENTATION_VERTICAL. The style is used to set appearance of the toolbar items by using one of GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT, or GTK_TOOLBAR_BOTH. 4.11.10. Notebooks The NoteBook Widget is a collection of "pages" that overlap each other, each page contains different information with only one page visible at a time. This widget has become more common lately in GUI programming, and it is a good way to show blocks of similar information that warrant separation in their display. The first function call is used to create a new notebook widget. GtkWidget *gtk_notebook_new( void ); Once the notebook has been created, there are a number of functions that operate on the notebook widget. 4.12. Menu Widgets There are two ways to create menus: one-way is to create menus using the calls directly, i.e., manually the other way is to use Itemfactory. The steps to create menus manually: 1.First a menu bar is to be created. 2.This menu bar is to be packed to the window. 3.A container to the menu items is to be created. 4.The menu items are to be created. 5.The menu items are to be put in to the menu. 6.The menu is to be added to the menu bar. Item factory creates a menu out of an array of Itemfactory entries. The menu can be defined in its simplest form and menu/menu bar widgets can be created using minimum function calls. 4.13. Glib Glib is a lower –level library that provides many useful definitions and functions available for use when creating GDK and GTK applications. These include definitions for basic types and their limits, standard macros, type conversations, byte order, memory allocation, warnings and assertions, message logging, timers, string utilities, hook functions, a lexical scanner, dynamic loading of modules, and automatic string completion. A number of data structures ( and their related operations) are also defined, including memory chunks, doubly linked lists, singly linked lists, hash tables, strings (which can grow dynamically), string chunks( groups of strings), arrays (which can grow in size as elements are added), balanced binary trees, N-ary trees, quarks (a two-way association of a string and a unique integer identifier), keyed data lists( lists of data elements accessible by a string or integer id), relations and tuples (tables of data which can be indexed on any number of fields), and caches. Chapter -5 How to Write Panel Applets in Gnome 5.1. Introduction GNOME is one of the two major desktop environments in the Linux arena today. It is built upon the Gtk toolkit, in contrast to KDE, which is built upon the Qt toolkit. A very important part of the Gnome Desktop is the gnome panel, which is the usually horizontal bar found at the bottom of the desktop. It acts as a repository for menus, applets, drawers and various special objects. An applet is a Gnome application, which resides in this panel. 5.2. Hello World Given the simple standard Hello World program. #include int main(int argc, char **argv) { GtkWidget *xapplet, *xbutton; applet_widget_init("PACKAGE","VERSION",argc,argv,NULL,0,NULL); xapplet = applet_widget_new("PACKAGE"); xbutton = gtk_button_new_with_label("Hello World"); gtk_widget_show(xbutton); applet_widget_add(APPLET_WIDGET(xapplet), xbutton); gtk_widget_show(xapplet); applet_widget_gtk_main(); return EXIT_SUCCESS; } Then, it is compiled by using the command, $ gcc `gnome-config --cflags --libs applets` panel_hello.c One may get some errors regarding CORBA, if that has not been configured properly on the machine. The command gnome-config outputs a list of gnome libraries to be included in the gcc C compiler. Thus, the –libs flag specifies that the `applets' library of GNOME is to be used. After compiling the applet, it is executed using the command $./a.out. One should see the applet displaying "Hello World" in the panel. To stop the applet, ^-C (control-C) is to be pressed. Now, it is time to understand the code. The file to be included from the standard directory (ie. /usr/include is applet-widget.h, in contrast to gtk/gtk.h which must be included for non-panel applications. The first function applet_widget_init() initializes the applet widget, taking the package name, version, and command-line arguments as inputs. Here, they are specified as strings, but one can specify some values for these variables. This is the counterpart of gtk_init() for non-panel applications. Then, the applet_widget_new() function instantiates the applet. It is the counterpart of gtk_window_new() for non-panel applications. applet_widget_add() packs the applets into the applet container instead of the standard GTK container. One has to use type casting to cast xapplet instance to the correct type. It is the counterpart of gtk_container_add() for non-panel applications. applet_widget_gtk_main() is the counterpart of gtk_main() for standard GTK applets. 5.3. Display a picture in the panel #include #include // create a structure for the applet struct pic_applet_t{ GtkWidget *area; GtkWidget *pic; GtkWidget *pixmap; GdkGC *gc; }; GtkWidget *myapplet; //create an object of type clock_applet_t struct pic_applet_t mypic; //set the applet width and height static int applet_width = 41; static int applet_height = 41; //main function starts here int main (int argc, char *argv[]) { char *fname; /* initialize the applet widget */ applet_widget_init ("PACKAGE", "VERSION", argc, argv, NULL, 0, NULL); // create a new applet with label "my applet" myapplet = applet_widget_new ("my applet"); // gtk_widget_realize (myapplet); // create fixed area for clock pixmap mypic.area = gtk_fixed_new(); // set the size of the applet area gtk_widget_set_usize (mypic.area, applet_width, applet_height); // load clock pixmap fname = gnome_unconditional_pixmap_file ("apple-red.png"); mypic.pic = gnome_pixmap_new_from_file_at_size (fname, applet_width, applet_height); // free the pointer fname g_free (fname); //show the pixmap file gtk_widget_show (mypic.pic); // create a pixmap for clock mypic.pixmap = gnome_pixmap_new_from_gnome_pixmap (GNOME_PIXMAP(mypic.pic)); //fix the pixmap into the applet area gtk_fixed_put (GTK_FIXED(mypic.area), mypic.pixmap, 0, 0); //show the pixmap and applet area gtk_widget_show (mypic.pixmap); gtk_widget_show (mypic.area); mypic.gc = gdk_gc_new (myapplet->window); // show applet applet_widget_add (APPLET_WIDGET(myapplet), mypic.area); gtk_widget_show (myapplet); // applet main loop applet_widget_gtk_main (); return 0; } This is a program to display a picture as the panel applet. 5.4. Crude Digital Clock Here is the code for Crude Digital Clock #include #include #include time_t xtime; static void myf (void) { xtime = time (NULL); // time is the function defined in time.h, returns seconds since 1/1/1970 } static GtkWidget *xbutton; static int xfunction(GtkWidget *button) { char mytime[100]; myf(); sprintf(mytime,"%d", xtime); gtk_label_set_text(GTK_LABEL(GTK_BIN(xbutton)->child),mytime); return 1; } int main(int argc, char **argv) { GtkWidget *xapplet; //initialize the applet applet_widget_init("PACKAGE",”VERSION",argc,argv,NULL,0,NULL); //Creates a button with label Time xbutton = gtk_button_new_with_label("Time"); gtk_widget_show(xbutton); //Create a new applet widget xapplet = applet_widget_new("PACKAGE"); // add the button to the widget applet_widget_add(APPLET_WIDGET(xapplet), xbutton); gtk_timeout_add(1000, (GtkFunction)xfunction, xbutton); // after 1000 millisec xfunction will be attached to xbutton gtk_widget_show(xapplet); applet_widget_gtk_main(); } The output should be a number of the order of one billion, displayed in the panel. The reason for this is because time() function returns the number of seconds elapsed since Jan.1, 1970, the birthday of Unix, and the output is stored in the xtime variable. Of course, displaying the number of seconds since 1/1/1970 is not very user-friendly 5.5. Digital Clock: After the crude digital clock, it is time to move on to a more advanced application: a digital clock. The following is the source code: #include #include #include struct tm *xstime; /* defined in time.h*/ time_t xtime; /* defined in time.h */ static void myf (void) { xtime = time (NULL); // seconds since 1/1/1970 xstime = localtime (&xtime); /* converts seconds to h.m.s */ } static GtkWidget *xbutton; static int xfunction(GtkWidget *button) { int hr,mn,sc; char mytime[100]; myf(); /*get hour, minute and second from xstime*/ hr=xstime->tm_hour; mn= xstime->tm_min; sc=xstime->tm_sec; /* time i.e hour, minute and second will be put in one variable mytime*/ sprintf(mytime,"%d:%d:%d", hr,mn,sc); gtk_label_set_text(GTK_LABEL(GTK_BIN(xbutton)->child),mytime); /* mytime will be displayed as a label on the applet*/ return 1; } int main(int argc, char **argv) { GtkWidget *xapplet; //initialize the applet widget applet_widget_init("PACKAGE","VERSION",argc,argv,NULL,0,NULL); // a button called xbutton is created with label Time xbutton = gtk_button_new_with_label("Time"); gtk_widget_show(xbutton); xapplet = applet_widget_new("PACKAGE"); // the button will be added to the applet widget applet_widget_add(APPLET_WIDGET(xapplet), xbutton); gtk_timeout_add(1000, (GtkFunction)xfunction, xbutton); // afetr 1000 millisec xfunction is attached to xbutton gtk_widget_show(xapplet); applet_widget_gtk_main(); } Now, this clock displays the hours, minutes and seconds time format. Here, the function localtime is used to convert the time elapsed since 1/1/1970 into a more user-friendly format. 5.6. The Final Digital Clock: This is a more advanced digital clock. The following is the source code: #include #include #include time_t curtime; /*defined in time.h*/ struct tm *tm; /*defined in time.h*/ static void myf(void) { curtime = time (NULL); /*defined in time.h and returns seconds since 1/1/1970*/ tm = localtime (&curtime); /* defined in time.h converts seconds to h.m.s*/ } static GtkWidget *msg; static int xfunction(GtkWidget *button) { int hr,mn,sc,mday,mon,yr,wday; char mytime[200],cmon[15],day[8]; myf(); /* get hour, minute and second */ hr=tm->tm_hour; mn= tm->tm_min; sc=tm->tm_sec; mday=tm->tm_mday; mon=tm->tm_mon; yr=tm->tm_year; wday=tm->tm_wday; yr=1900+yr; /*The function returns day of the week in terms of numbers * i.e 0 – 6. To display days of the week switch case *construct is used*/ switch(wday) { case 0 : strcpy(day,"Sun"); break; case 1 : strcpy(day,"Mon"); break; case 2 : strcpy(day,"Tue"); break; case 3 : strcpy(day,"Wed"); break; case 4 : strcpy(day,"Thu"); break; case 5 : strcpy(day,"Fri"); break; case 6 : strcpy(day,"Sat"); break; } /*The function returns month in terms of numbers i.e.,0-11 To display days of the week switch case construct is used */ switch(mon) { case 0 :strcpy(cmon,"Jan"); break; case 1 :strcpy(cmon,"Feb"); break; case 2 :strcpy(cmon,"Mar"); break; case 3 :strcpy(cmon,"Apr"); break; case 4 :strcpy(cmon,"May"); break; case 5 :strcpy(cmon,"June"); break; case 6 :strcpy(cmon,"Jul"); break; case 7 :strcpy(cmon,"Aug"); break; case 8 :strcpy(cmon,"Sep"); break; case 9 :strcpy(cmon,"Oct"); break; case 10 :strcpy(cmon,"Nov"); break; case 11 :strcpy(cmon,"Dec"); break; } /* date and time will be put in one variable mytime*/ if(hr<12) sprintf(mytime,"%d:%d:%d AM \n %s %d %s %d", hr,mn,sc,day,mday,cmon,yr); else { hr=hr%12; sprintf(mytime,"%d:%d:%d PM\n %s %d %s %d", hr, mn,sc,day,mday,cmon,yr); } gtk_label_set_text(GTK_LABEL(GTK_BIN(button)->child), mytime); /* mytime will be displayed as a label on the applet*/ return 1; } int main(int argc, char **argv) { GtkWidget *applet; applet_widget_init("PACKAGE", "VERSION", argc, argv, NULL, 0, NULL); msg = gtk_button_new_with_label("Time"); gtk_widget_show(msg); applet = applet_widget_new("PACKAGE"); applet_widget_add(APPLET_WIDGET(applet), msg); gtk_timeout_add(100, (GtkFunction)xfunction, msg); gtk_widget_show(applet); applet_widget_gtk_main(); } Now, this clock should display the hours, minutes and seconds time format with day, month and year. Chapter – 6 XSU Program 6.1. About su su is abbriviated from substitute user su run a shell with substitute user and group IDs. su change the effective user id and group id to that of USER. This program is a graphical user interface to su command. 6.2. ZVT Terminal Widget The ZVT terminal Widget(Zvtterm) provides high level access to a Xterm_compliant terminal emulator which can be used for terminal emulation or as a high performance text output engine with scroll_back and selection facilities. 6.2.1. Creating a Terminal The following functions are available to create a terminal zvt_term_new :create a default widget zvt_term_new_with_size :create a widget with a specified terminal size Unless there are specified reasons not to, one should normally use zvt_term_new_with_size() to create a new terminal, otherwise one must careful of the order of perform size operations on the terminal. It would normally make sense to call zvt_term_set_size() before the widget is realized anyway. 6.2.2. Terminal Properties The terminal has a large number of properties, which can be set via object method zvt_term_set_size : set absolute terminal size. zvt_term_set_blink : enable/disable blinking cursor zvt_term_set_bell :enable/disable bell zvt_term_show_pointer : make the mouse pointer visible zvt_term_hide_pointer : make the mouse pointer invisible 6.2.3. Input to Terminal The terminal can either take input from a subprocess or from the application directory. 6.2.4. Subshell Commands zvt_term_forkpty : to fork a session in which to launch a terminal application. zvt-term_killchild : to signal the child process zvt_term_closepty : to close the master pty and let the child quit. zvt_tem_feed : feed data directly to the terminal. 6.2.5. Retrieving Data from Terminal zvt_term_get_buffer : Retrieve the raw screen or scroll back text. 6.3. The Program Code #include #include #include #include GtkWidget *xzvtterm, *xbutton, *zbutton, *xentry, *xlabel; GtkWidget *xwindow, *xtable, *xbox, *xframe; gchar *xusername; static void xf_login( GtkWidget *widget, gpointer data) /*when one clicks the login button it asks to enter the *username ,after entering the username in the textbox then *it will display the password and after giving the password *it will enter to that user*/ { xusername = gtk_entry_get_text(GTK_ENTRY(xentry)); //It will store the user entry in the variable username gtk_widget_grab_focus (xzvtterm); gtk_widget_show(xzvtterm); //it will show a new zvtterminal switch(zvt_term_forkpty(ZVT_TERM(xzvtterm), TRUE)) { case -1: perror("ERROR: unable to fork:"); exit(1); break; case 0: execlp("su","su","-",xusername,NULL); //It will execute the su command break; } g_print(xusername);//It will print the username } void xf_exit(GtkButton *button, gpointer data) /*when one clicks on the exit button it will logout from the present user*/ { zvt_term_closepty(ZVT_TERM(xzvtterm)); //It will close the zvtterminal } int main(int argc, char **argv) { gtk_init(&argc, &argv); /*This function initializes the library for use, sets up default signal handlers and checks the arguments passed to the application on the command line*/ // instantiate widgets xwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); //This will create a new Window gtk_window_set_title (GTK_WINDOW (xwindow), " My Secure Shell "); xtable = gtk_table_new(1,2,FALSE); // 2x2 table xbox = gtk_hbox_new( FALSE, 0); // create horizontal box xentry = gtk_entry_new (); xbutton = gtk_button_new_with_label(" Login "); //It will create a new button with label Login zbutton = gtk_button_new_with_label(" Exit "); //It will create a new button with label Exit xlabel = gtk_label_new ("Username : "); //It will create a new label with name username xzvtterm = zvt_term_new_with_size(80,24); zvt_term_set_blink (ZVT_TERM (xzvtterm), TRUE); xframe = gtk_frame_new (" Secure Shell "); //It will create a new frame with name Secure Shell gtk_frame_set_label_align (GTK_FRAME (xframe), 0.5, 0.0); gtk_frame_set_shadow_type(GTK_FRAME(xframe), GTK_SHADOW_ETCHED_OUT); // pack widgets gtk_box_pack_start( GTK_BOX(xbox),xlabel, TRUE, TRUE, 0); // pack buttons gtk_box_pack_start( GTK_BOX(xbox), xentry, TRUE, TRUE, 0); // pack buttons gtk_box_pack_start( GTK_BOX(xbox),xbutton, TRUE, TRUE, 0); gtk_box_pack_end( GTK_BOX(xbox), zbutton, TRUE, TRUE, 0); // into xbox //gtk_table_attach_defaults(GTK_TABLE(xtable),xbox, 0,1,0,1); // both lower quadrants gtk_table_attach( GTK_TABLE(xtable), xbox, 0,1,0,1, GTK_SHRINK,GTK_SHRINK, 10,10 ); // ULH, x1,x2,y1,y2 // URH, (table, child x1,x2,y1,y2,options, options, xpadding, ypadding) gtk_table_attach_defaults( GTK_TABLE(xtable), xzvtterm, 0,1,1,2); // both lower quadrants gtk_table_set_col_spacings( GTK_TABLE(xtable), 10 ); gtk_table_set_row_spacings( GTK_TABLE(xtable), 10 ); gtk_container_add (GTK_CONTAINER (xframe), xtable); gtk_container_add(GTK_CONTAINER (xwindow), xframe); // pack tbl into base window gtk_container_set_border_width(GTK_CONTAINER(xwindow), 20); gtk_widget_show_all (xwindow); // event handling // g_signal_connect (G_OBJECT (xbutton), "clicked", G_CALLBACK (xf_login), NULL); gtk_signal_connect (GTK_OBJECT (xbutton),"clicked", GTK_SIGNAL_FUNC (xf_login), NULL); gtk_signal_connect (GTK_OBJECT (zbutton),"clicked", GTK_SIGNAL_FUNC (xf_exit), NULL); gtk_main (); gtk_exit(0); return 0; } /* The command to compile is * *$gcc `gnome-config --cflags --libs applets zvt` mysu-0.2.c*/ /* The Command to run the application is ./a.out*/ This is the output of the program. Chapter – 7 Xwintelnet Application 7.1. About the application The telnet command is used to communicate with another host using the TELNET protocol. This program is the xwintelnet (X Windows Telnet). Here the user has to supply the IP address of the remote machine and clicks on connect button the application will connect to the machine of the specified IP address. Here a zvt terminal is displayed. The ZVT terminal Widget (Zvtterm) provides high level access to a Xterm_compliant terminal emulator which can be useed for terminal emulation or as a high performance text output engine with scroll_back and selection facilities. When one executes this application one window is displayed with a menu bar with two options: Connect, Help. There are two menu items under the connect option: Remote host and Exit. When one clicks on the Remote Host option that window shows a label as Hostname and a text entry to supply the Host IP address. There are two buttons labeled: Connect and Exit. When one clicks on the Connect button the application Telnet to the remote host with the specified IP address. When one clicks on the Exit button the application disconnects from the remote host. When one selects the Exit option from the Connect menu the application closes. There is only one menu item in the Help menu : about. When one clicks on the about option of the Help menu it displays a window inside which there is a frame showing about the application and the developers. 7.2. Program code of the application The program is given below #include #include #include #include #include #include /*Declaration*/ GtkWidget *xzvtterm, *xbutton, *zbutton, *xentry, *xlabel; GtkWidget *xwindow, *xtable, *xbox, *xframe, *mywindow; GtkWidget *vbox, *button; GtkWidget *xconnect_menu, *xhelp_menu; GtkWidget *xmenu_bar; GtkWidget *xconnect_item, *xhelp_item; GtkWidget *xremote_item,*xexit_item,*xabout_item; gchar *xhostname; /*This is the function for the main window*/ static gboolean f_delete1 (GtkWidget *widget, GtkWidget *event, gpointer data) { gtk_main_quit(); return FALSE; } /*This is the function for the help window*/ static gboolean f_delete2(GtkWidget *widget, GtkWidget *event, gpointer data) { gtk_widget_destroy(GTK_OBJECT(mywindow)); } /* This function is to be called when the user click the about option of help menu. This function will display a window, which will show some text about the application*/ static void f_help_response(void) { GtkWidget *button, *table, *frame, *label; mywindow=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(mywindow),"delete_event", GTK_SIGNAL_FUNC(f_delete2),NULL); gtk_container_set_border_width(GTK_CONTAINER(mywindow),10); table = gtk_table_new(3,6,FALSE); gtk_container_add(GTK_CONTAINER(mywindow),table); frame = gtk_frame_new("About Mytelnet"); label=gtk_label_new("This is xwintelnet (X Windows Telnet) Program\n Here one has to supply the IP address and then click on connect button\n Then it will telnet to the machine with the IP address\n This application is developed by Ms. Rajalaxmi Mishra and Miss Sarita Mohanty \n as a artial fulfilment of the requirements for M.Tech Degree in Computer Science\n School of Mathematics, Statistics and omputer Science, Utkal University, Bhubaneswar\n guided by Dr. Samar Abbas"); gtk_container_add(GTK_CONTAINER(frame),label); gtk_widget_show(label); gtk_table_attach_defaults(GTK_TABLE(table),frame,0,6,0,1); button=gtk_button_new_with_label("Close"); gtk_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(f_delete2),NULL); gtk_table_attach_defaults(GTK_TABLE(table),button,0,1,1,2); gtk_widget_show(button); gtk_widget_show(table); gtk_widget_show(frame); gtk_widget_show(mywindow); } /*This function is to be called when after supplying the IP address the user clicks on the connect button*/ static void xconnect( GtkWidget *widget, gpointer data) { gtk_widget_grab_focus (xzvtterm); xhostname = gtk_entry_get_text(GTK_ENTRY(xentry)); gtk_widget_show(xzvtterm); switch(zvt_term_forkpty(ZVT_TERM(xzvtterm), TRUE)) { case -1: perror("ERROR: unable to fork:"); exit(1); break; case 0: //This will Telnet to the specified IP address execlp("telnet","telnet",xhostname,NULL); break; } } /* This function will be called when the user clicks on the exit button*/ static xf_exit(GtkButton *button, gpointer data) { zvt_term_closepty(ZVT_TERM(xzvtterm)); zvt_term_reset(ZVT_TERM(xzvtterm), TRUE); gtk_widget_grab_focus (xentry); } /*This function is to be called when the user selects remote host option of the connect menu */ static void fconnect_response(void) { gtk_widget_show_all(xwindow); gtk_widget_grab_focus (xentry); // event handling gtk_signal_connect (GTK_OBJECT (xbutton), "clicked", GTK_SIGNAL_FUNC (xconnect), NULL); gtk_signal_connect (GTK_OBJECT (zbutton),"clicked", GTK_SIGNAL_FUNC(xf_exit), NULL); } /*The main function*/ int main(int argc,char *argv[]) { gtk_init(&argc,&argv); /*Create new window*/ xwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(xwindow),"MY TELNET"); gtk_signal_connect(GTK_OBJECT(xwindow),"delete_event",GTK_SIGNAL_FUNC(gtk_main_quit),NULL); //Menu creation xconnect_menu=gtk_menu_new(); xhelp_menu=gtk_menu_new(); xconnect_item = gtk_menu_item_new_with_label("Connect"); xhelp_item=gtk_menu_item_new_with_label("Help"); gtk_widget_show(xconnect_item); gtk_widget_show(xhelp_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(xconnect_item), xconnect_menu); gtk_menu_item_set_submenu(GTK_MENU_ITEM(xhelp_item), xhelp_menu); xremote_item=gtk_menu_item_new_with_label("Remote Host"); xexit_item=gtk_menu_item_new_with_label("Exit"); xabout_item=gtk_menu_item_new_with_label("About"); gtk_menu_shell_append(GTK_MENU_SHELL(xconnect_menu), xremote_item); gtk_menu_shell_append(GTK_MENU_SHELL(xconnect_menu), xexit_item); gtk_menu_shell_append(GTK_MENU_SHELL(xhelp_menu), xabout_item); gtk_signal_connect(GTK_OBJECT(xremote_item),"activate", GTK_SIGNAL_FUNC(fconnect_response),NULL); gtk_signal_connect(GTK_OBJECT(xexit_item),"activate", GTK_SIGNAL_FUNC(gtk_main_quit),NULL); gtk_signal_connect(GTK_OBJECT(xabout_item),"activate", GTK_SIGNAL_FUNC(f_help_response),NULL); gtk_widget_show(xremote_item); gtk_widget_show(xexit_item); gtk_widget_show(xabout_item); xmenu_bar=gtk_menu_bar_new(); gtk_widget_show(xmenu_bar); vbox = gtk_vbox_new(FALSE,0); xtable = gtk_table_new(1,2,FALSE); // 2x2 table xbox = gtk_hbox_new( FALSE, 0); // create horizontal box xentry = gtk_entry_new (); xbutton = gtk_button_new_with_label(" Connect "); zbutton = gtk_button_new_with_label(" Exit "); xlabel = gtk_label_new ("Host : "); xzvtterm = zvt_term_new_with_size(80,24); zvt_term_set_blink (ZVT_TERM (xzvtterm), TRUE); xframe = gtk_frame_new (" My Telnet "); gtk_frame_set_label_align (GTK_FRAME (xframe), 0.5, 0.0); gtk_frame_set_shadow_type (GTK_FRAME (xframe), GTK_SHADOW_ETCHED_OUT); //packing gtk_box_pack_start(GTK_BOX(xbox), xlabel, TRUE, TRUE, 0); // pack buttons gtk_box_pack_start(GTK_BOX( xbox ), xentry, TRUE, TRUE, 0); // pack buttons gtk_box_pack_start(GTK_BOX(xbox), xbutton, TRUE, TRUE, 0); // into xbox gtk_box_pack_end( GTK_BOX( xbox ), zbutton, TRUE, TRUE, 0); gtk_table_attach_defaults( GTK_TABLE(xtable), xbox, 0,1,0,1); // both upper quadrants xbox is attached to the table gtk_table_attach( GTK_TABLE(xtable), xbox, 0,1,0,1, GTK_SHRINK,GTK_SHRINK, 10,10 ); // ULH, x1,x2,y1,y2 // URH,(table, child x1,x2,y1,y2,options, options, xpadding, ypadding) gtk_table_attach_defaults( GTK_TABLE(xtable), xzvtterm, 0,1,1,2); // both lower quadrants //zvtterm is attached to the table gtk_table_set_col_spacings( GTK_TABLE(xtable), 10 ); gtk_table_set_row_spacings( GTK_TABLE(xtable), 10 ); gtk_container_add (GTK_CONTAINER (xframe), xtable); //add table to xframe gtk_widget_show(vbox); gtk_container_set_border_width(GTK_CONTAINER(xwindow), 20); //add menu to the vbox gtk_box_pack_start(GTK_BOX(vbox),xmenu_bar,FALSE,FALSE,2); //add frame to the vbox gtk_box_pack_end(GTK_BOX(vbox),xframe,TRUE,TRUE,2); gtk_container_add(GTK_CONTAINER(xwindow),vbox); // add vbox to the window gtk_menu_bar_append(GTK_MENU_BAR(xmenu_bar),xconnect_item); //The connect menu is added to the menu bar gtk_menu_bar_append(GTK_MENU_BAR(xmenu_bar),xhelp_item); // The help menu is added to the menu bar gtk_widget_show(xwindow); gtk_main(); return 0; } /* The command to compile is gcc`gnome-config --cflags --libs applets zvt` mytelnet-0.6.c*/ /* The Command to run the application is ./a.out*/ 7.3. The Output This is the output of the xwintelnet application. References 1.http://www.linux.org 2.http://www.gnome.org 3.http://www.kernel.org 4.http://www.sourceforge.net 5.http://www.gnu.org 6.http://www.gtk.org/gtk+2.0/tutorial 7.http://www.gtk.org/gtk+1.2/tutorial 8.http://www.kplug.org/glade-tutorial 9.http://www.writelinux.com/glad 10.http://www.geocities.com/ichattopadhyaya/linux/glade 11.http://www.clipx.net/ng/zcpp/ng4a6.php 12.http://www.users.csbsju.edu/~cburch/cs 13.http:://Pluto:iis.nsk.su/Russian/unix-doc 14.Peterson 2000. “The Complete Reference Red Hat Linux”, Richard Peterson, Tata McGraw-Hill Publishing Company Ltd., 7 West Patel Nagar, New Delhi - 110008 15.Vahalia 2001. “Unix Internals The new frontier”, Uresh Vahalia, Paerson Education (Singapore) Pte. Ltd., Indian Branch, 482 F.I.E, Patparganj, Delhi 110092, India. 16.Beck 2002, “Linux Kernel Programming”, M. Beck, H. Bohme, M.Dziadzka, U. Kunitz, R. Magnus, C.Schroter, D. Verworner- Paerson Education (Singapore) Pte. Ltd., Indian Branch, 482 F.I.E, Patparganj, Delhi 110092, India. 17.Bach 2002. “The design of the Unix Operating System” – Maurice J. Bach. - Paerson Education (Singapore) Pte. Ltd., Indian Branch, 482 F.I.E, Patparganj, Delhi 110092, India. 18.Wells 2000. “Guide to Linux installation and Administration” – Nicholas Wells. Vikas Publishing House Pvt. Ltd., Masjid Road , Jangpura, New Delhi –110014 19.Parker 2000. “Linux System Administrator’s Survival Guide” – Timathy Parker, Techmedia, Munish Plaza, 20 Ansari Road, Darya Ganj, New Delhi –110002.