diff --git a/docs/develop/Makefile b/docs/develop/Makefile
new file mode 100644
index 0000000000..06fa047b79
--- /dev/null
+++ b/docs/develop/Makefile
@@ -0,0 +1,19 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+SOURCEDIR = .
+BUILDDIR = generated
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/develop/TODO b/docs/develop/TODO
new file mode 100644
index 0000000000..9c38171d7e
--- /dev/null
+++ b/docs/develop/TODO
@@ -0,0 +1,17 @@
+Documents that still need to be converted to restructuredtext (or thrown away):
+
+- kernel/vm*: it looks like these should be comments in the sourcecode?
+- kits/*: TODO, some interesting info in there but also a lot of probably obsolete things
+- media/*: some useful things, some sourcecode, and a PDF file about the echo audio driver
+
+Other things to do:
+
+- Organize the table of contents a bit. For now I just wanted to get all the existing files in,
+ in a mostly flat organization. But it makes things hard to follow.
+- Reorganize the directories. For example move midi to kits/midi. Should we follow the layout of
+ the source tree? Or the hierarchy of the table of contents?
+- There are doxyfiles for various components. Unlike the one used for API docs, they scan the cpp
+ source files and will extract some internals documentation from there. Decide what to do with that.
+- Migrate some things from the website. Start with documentation about configure and jam, for example.
+- There are TODO lists in various places in the docs, turn them into bugreports in the bugtracker
+ (including this one!)
diff --git a/docs/develop/apps/haikudepot/server.md b/docs/develop/apps/haikudepot/server.md
deleted file mode 100644
index 4a9b35c4c3..0000000000
--- a/docs/develop/apps/haikudepot/server.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# HaikuDepot and Server Interactions
-
-## Introduction
-
-This document aims to outline the general approach taken within the HaikuDepot application with regard to coordinating processes that relate to fetching and consuming data from remote systems.
-
-There are two main sources of remote data that are downloaded and consumed from network sources into the HaikuDepot desktop application;
-
-* Repository HPKR data from a Haiku mirror such as "HaikuPorts"
-* Meta-data related to packages from [HaikuDepotServer](http://depot.haiku-os.org) (HDS) such as icons, localizations, ratings and so on.
-
-## Process, ProcessNode and Coordinator
-
-A _Process_ (root class ```AbstractProcess```) is a class that takes responsibility for some aspect of pulling material down from a network source and processing it.
-
-A _ProcessNode_ is a holder for a Process, but also takes responsibility for the following;
-
-* Maintaining the relationship between the Processes. For example, if Process A needs to complete before Process B then the ProcessNode would record this fact. It does this by storing _predecessor_ and _successor_ ProcessNodes.
-* Starting the held Process in a newly spawned thread.
-* Stopping the held Process.
-
-A _Coordinator_ holds a list of ProcessNodes. It will start, stop and cancel nodes as necessary such that, in an ideal case, the various ProcessNodes are completed in the correct order.
-
-The _ProcessCoordinatorFactory_ is able to create Coordinators.
-
-## Bulk Load Processes
-
-The following diagram shows the logical dependencies of the various Processes that are involved in refreshing the HPKR data from remote repositories and then loading data from the HDS system.
-
-
-
-For example, the ```ServerRepositoryDataUpdateProcess``` must wait until the ```LocalRepositoryUpdateProcess``` has completed before it is able to be started. It is the reponsibility of the Coordinator to ensure that this sequencing is enforced. There are many instances of ```ServerPkgDataUpdateProcess``` shown because there will be one launched for each of the Repositories for which data will be downloaded; "HaikuDepot" etc...
-
-## Process / ProcessNode / Coordinator
-
-The following diagram shows the relationship and interplay between the various objects that are involved in running a larger task. Only fictional Processes are shown to keep the diagram tidy. See above for the actual Processes.
-
-
-
-Dotted lines show associations between elements and red lines show interaction or data-flow. Green arrows here demonstratively show some dependency; Process C cannot start until A and B are completed.
-
-The MainWindow owns the Coordinator for the life-span of undertaking some larger task.
-
-Each Process is coupled with a ProcessNode and then the Coordinator has a list of the ProcessNodes-s. The Processes are generally writing to the local disk system (often with compressed files) to cache data (see ```~/config/cache/HaikuDepot```) and also relay data into the ```Model``` object that maintains state for the HaikuDepot desktop application.
-
-The Processes communicate when they have finished to the Coordinator and it is at these events that the Coordinator is able to introspect the state of the Processes in order to know what to do next.
-
-The Coordinator also communicates with MainWindow. It communicates with the MainWindow in order to signal changes or progress in the overall larger task. The MainWindow also uses these events to discover when the Coordinator has completely finished.
-
-## Failure
-
-A Process may fail or be stopped. If a Process fails or is stopped then successor Processes, or those that would have run after the failed process, are stopped so that they will not run.
-
-The Coordinator will still try to complete any other Processes that could still run or are running already.
-
-Upon the Coordinator completing, the Coordinator will signal to the MainWindow client the change in state and then the MainWindow will be able to identify that the Coordinator has completed, but that something has gone wrong along the way.
-
-## Concurrency
-
-It is important to note that Processes may run concurrently. The Processes' are modelled by the Coordinator as a list rather than a tree. The dependencies are likely to form a tree or web of Processes that dictates the order of execution, but it is also quite possible to have multiple non-intersecting trees or webs such that Processes will execute independently.
diff --git a/docs/develop/apps/haikudepot/server.rst b/docs/develop/apps/haikudepot/server.rst
new file mode 100644
index 0000000000..28a0ff574e
--- /dev/null
+++ b/docs/develop/apps/haikudepot/server.rst
@@ -0,0 +1,120 @@
+HaikuDepot and Server Interactions
+==================================
+
+Introduction
+------------
+
+This document aims to outline the general approach taken within the
+HaikuDepot application with regard to coordinating processes that relate
+to fetching and consuming data from remote systems.
+
+There are two main sources of remote data that are downloaded and
+consumed from network sources into the HaikuDepot desktop application;
+
+- Repository HPKR data from a Haiku mirror such as “HaikuPorts”
+- Meta-data related to packages from
+ `HaikuDepotServer Probably the best resource for a description of the inner workings of BFS is the
-book "Practical File System Design with the Be File System" written by Dominic
-Giampaolo and published by Morgan Kaufmann Publishers. Although that book is out of
-print, it's available at the Haiku web site.
-
- If you prefer to see how it works in code, please have a look at Haiku's BFS
-implementation.
-
- If you are interested in the Haiku file system API, please refer to its documentation
-as part of the Haiku book.
-
-
-
diff --git a/docs/develop/file_systems/befs/resources.rst b/docs/develop/file_systems/befs/resources.rst
new file mode 100644
index 0000000000..e507fd1907
--- /dev/null
+++ b/docs/develop/file_systems/befs/resources.rst
@@ -0,0 +1,16 @@
+The Be File System
+================================
+
+Probably the best resource for a description of the inner workings of
+BFS is the book "Practical File System Design with the Be File System"
+written by Dominic Giampaolo and published by Morgan Kaufmann
+Publishers. Although that book is out of print, it's available at the
+`Haiku web
+site Unlike other systems, Haiku comes with its own user-friendly bootloader. The main task of
- the bootloader is to load and start the kernel. We don't have a concept of an initramfs as
- Linux does, instead our bootloader is able to find the kernel and modules in a BFS partition,
- and even extract them from packages as needed. It also provides an early boot menu that can
- be used to change settings, boot older versions of Haiku that were snapshotted by the package
- system, and write boot logs to USB mass storage.
- Haiku BIOS boot loader process is split into 3 different stages. Since the second
- stage is bound tightly to both other stages (which are independent from each other),
- it is referred to as stage 1.5, whereas the other stages are referred to as stage 1
- and 2. This architecture is used because the BIOS booting process only loads a very
- small piece of code from disk for booting, insufficient for the needs outlined above. The following will explain all stages in detail.
- The first stage is responsible for loading the real boot loader from a BFS disk. It
- will be loaded by the Master Boot Record (MBR) and executed in the x86 real mode.
- It is only used if the system will be booted directly from a BFS partition, it won't
- be used at all if it is booted from a floppy disk or CD-ROM (in this case, stage
- 1.5 is in charge immediately).
-
- It resides in the first 1024 bytes of a BFS disk which usually refers to the
- first two sectors of the partition in question. Since the BFS superblock is located
- at byte offset 512, and about 170 bytes large, this section is already reserved,
- and thus cannot be used by the loader itself.
- The loader must be able to load the real boot loader from a certain path, and
- execute it. In BeOS this boot loader would be in "/boot/beos/system/zbeos",
- in Haiku this is haiku_loader.bios_ia32 found in the haiku_loader package.
- Contains both the stage 1.5 boot loader, and the compressed stage 2 loader.
- It's not an ELF executable file; i.e. it can be directly written to a floppy
- disk which would cause the BIOS to load the first 512 bytes of that file and
- execute it.
-
- Therefore, it will start with the stage 1.5 boot loader which will be loaded
- either by the BIOS when it directly resides on the disk (for example when
- loaded from a floppy disk), or the stage 1 boot loader, although this one
- could have a different entry point than the BIOS.
-
- Will have to load the rest of haiku_loader into memory (if not already done by the
- stage 1 loader in case it has been loaded from a BFS disk), set up the global
- descriptor table, switch to x86 protected mode, uncompress stage 2, and execute it.
-
- This part is very similar to the stage 1 boot loader from NewOS.
-
- This is the most complex part of the boot loader. In short, it has to load
- any modules and devices the kernel needs to access the boot device, set up
- the system, load the kernel, and execute it.
-
- The kernel, and the modules and drivers needed are loaded from the boot
- disk - therefore the loader has to be able to access BFS disks. It also
- has to be able to load and parse the settings of these drivers (and the
- kernel) from the boot disk, some of them are already important for the
- boot loader itself (like "don't call the BIOS"). Since this stage is already
- executed in protected mode, it has to use the virtual-86 mode to call the
- BIOS and access any disk.
-
- Before loading those files from the boot disk, it should look for additional
- files located on a specific disk location after the "zbeos" file (on floppy disk
- or CD-ROM). This way, it could access disks that cannot be accessed by the
- BIOS itself.
-
- Setting up the system for the kernel also means initalizing PCI devices needed
- during the boot process before the kernel is up. It must be able to do so since
- the BIOS might not have set up those devices correctly or at all.
-
- It also must calculate a check sum for the boot device which the kernel can then
- use to identify the boot volume and partition with - there is no other reliable
- way to map BIOS disk IDs to the /dev/disk/... tree the system itself is using.
-
- After having loaded and relocated the kernel, it executes it by passing a special
- structure which tells the kernel things like the boot device check sum, which
- modules are already loaded and where they are.
-
- The stage 2 boot loader also includes user interaction. If the user presses a
- special key during the boot process (like the space key, or some others as well),
- a menu will be presented where the user can select the boot device (if several,
- the loader has to scan for options), safe mode options, VESA mode, etc.
-
- This menu may also come up if an error occured during the execution of the stage
- 2 loader.
- On Open Firmware based systems, there is no need for a stage 1.5 because the firmware
- does not give us as many constraints. Instead, the stage 2 is loaded directly by the firmware.
- This requires converting the haiku_loader executable to the appropriate executable format
- (a.out on sparc, pef on powerpc). The conversion is done using custom tools because binutils
- does not support these formats anymore. There is no notion of real and protected mode on non-x86 architectures, and the bootloader
- is able to easily call Open Firmware methods to perform most tasks (disk access, network booting,
- setting up the framebuffer) in a largely hardware-independent way. U-Boot is able to load the stage2 loader directly from an ELF file. However, it does not
- provide any other features. It is not possible for the bootloader to call into U-Boot APIs
- for disk access, displaying messages on screen etc (while possible in theory, these features
- are often disabled in U-Boot). This means haiku_loader would need to parse the FDT (describing
- the available hardware) and bundle its own drivers for using the hardware. This approach is
- not easy to set up, and it is recommended to instead use the UEFI support in U-Boot where
- possible. On EFI systems, there is no need for a stage1 loader as there is for BIOS. Instead, our stage2
- loader (haiku_loader) can be executed directly from the EFI firmware. The EFI firmware only knows how to run executables in the PE format
- (as used by Windows) because Microsoft was involved in specifying it.
- On x86_64, we can use binutils to output a PE file directly. But on other platforms, this is not
- supported by binutils. So, what we do is generate a "fake" PE header and wrap our elf file inside
- it. The bootloader then parses the embedded ELF header and relocates itself, so the other parts
- of the code can be run. After this initial loading phase, the process is very similar to the Open Firmware one. EFI
- provides us with all the tools we need to do disk access and both text mode and framebuffer
- output. This document tries to give you a short introduction into the new device
-manager, and how to write drivers for it. Haiku still supports the legacy
-device driver architecture introduced with BeOS. The new device driver architecture of Haiku is still a moving target,
-although most of its details are already specificed. The device manager functionality builds upon device_node objects.
-Every driver in the system publishes one or more of such nodes, building a
-tree of device nodes. This tree is in theory a dynamic representation of the
-current hardware devices in the system, but in practice will also contain
-implementation specific details; since every node comes with an API specific
-to that node, you'll find device nodes that only come with a number of support
-functions for a certain class of drivers. Structurally, a device_node is a set of a module, attributes,
-and resources, as well as a parent and children. At a minimum, a node must
-have a module, all other components are optional. When the system starts, there is only a root node registered. Only primary
-hardware busses register with the root node, such as PCI, and ISA on x86.
-Since the PCI bus is an intelligent bus, it knows what hardware is installed,
-and registers a child node for each device on the bus. Every driver can also publish a device in /dev for communication with
-userland applications. All drivers and devices are kernel modules. So how does it all work? When building the initial device tree, the system only
-explores a minimum of device drivers only, resulting in a tree that basically
-only shows the hardware found in the computer. Now, if the system requires disk access, it will scan the device file system
-for a driver that provides such functionality, in this case, it will look for
-drivers under "/dev/disk/". The device manager has a set of built-in rules for
-how to translate a device path into a device node, and vice versa: every node
-representing a device of an intelligent bus (such as PCI) will also contain
-device type information following the PCI definitions. In this case, the "disk"
-sub-path will translate into the PCI_mass_storage type, and hence, the
-device manager will then completely explore all device nodes of that type. It will also use that path information to only ask drivers that actually
-are in a matching module directory. In the above example of a disk driver, this
-would be either in "busses/scsi", "busses/ide", "drivers/disk", ... For untyped or generic busses, it will use the context information gained
-from the devfs query directly, and will search for drivers in that sub directory
-only. The only exception to this rule are the devfs directories "disk", "ports",
-and "bus", which will also allow to search matching drivers in "busses". While
-this is relatively limited, it is a good way to cut down the number of drivers
-to be loaded. The device manager assumes the following API from a driver module: To ensure that a module exports this API, it must end its module name
-with "driver_v1" to denote the version of the API it supports. Note that
-suspend() and resume() are currently never called, as Haiku has
-no power management implemented yet. If your driver can give the device it is attached to a nice name that can be
-presented to the user, it should add the B_DEVICE_PRETTY_NAME attribute
-to the device node.
-
- The B_DEVICE_UNIQUE_ID should be used in case the device has a unique
-ID that can be used to identify it, and also differentiate it from other devices
-of the same model and vendor. This information will be added to the file system
-attributes of all devices published by your driver, so that user applications
-can identify, say, a USB printer no matter what USB slot it is attached to, and
-assign it additional data, like paper configuration, or recognize it as the
-default printer. If your driver implements an API that is used by a support or bus module, you
-will usually use the B_DEVICE_FIXED_CHILD attribute to specify exactly
-which child device node you will be talking to. If you support several child
-nodes, you may want to have a closer look at the section explaining
-how to write a bus driver. In addition to the child nodes a driver registers itself, a driver can either
-have dynamic children or fixed children, never both. Also, fixed children are
-registered before register_child_devices() is called, while dynamic
-children are registered afterwards. A device module must export the following API: A bus driver is a driver that represents a bus where one or more arbitrary
-devices can be attached to. There are two basic types of busses: intelligent busses like PCI or USB that
-know a lot about the devices attached to it, like a generic device type, as
-well as device and vendor ID information, and simple untyped/generic busses that
-either have not all the information (like device type) or don't even know what
-and if any devices are attached. The device manager has been written in such a
-way that device exploration makes use of additional information the bus can
-provide in order to find a responsible device driver faster, and with less
-overhead. If your bus knows what type of device is attached to, and also has vendor and
-device ID information about that device, it is considered to be an intelligent
-bus. The bus driver is supposed to have one parent node representing the bus,
-and to create a child node for each device attached to the bus. The additional information you have about the devices are attached to the
-device node in the following attributes: You can use the B_DEVICE_FLAGS attribute to define how the device
-manager finds the children of the devices you exported. For this kind of bus
-drivers, you will usually only want to specify B_FIND_CHILD_ON_DEMAND
-here, which causes the driver only to be searched when the system asks for it.
- A bus can be simple in a number of ways: An example of the latter would be the Zorro bus of the Amiga - it only has
-information about the vendor and device ID, but no type information. It should
-be implemented like an intelligent bus, though, with the type information simply
-omitted. Therefore, this section is about the former case, that is, a simple bus like
-the ISA bus. Since it doesn't know anything about its children, it does not
-publish any child nodes, instead, it will just specify the
-B_FIND_MULTIPLE_CHILDREN and B_FIND_CHILD_ON_DEMAND flags for its device node.
-Since there is no additional information about this bus, the device manager
-will assume a simple bus, and will try to find drivers on demand only. The way the device manager works, it makes versioning of modules (which are
-supposed to be one of the strong points of the module system) much harder or
-even impossible. While the device manager could introduce a new API and could
-translate between a "driver_v1", and a "driver_v2" API on the fly, it's not
-yet possible for a PCI sub module to do the same thing. Proposed Solution: Add attribute B_DEVICE_ALTERNATE_VERSION
-that specifies alternate versions of the module API this device node supports.
-We would then need a request_version() or set_version() function
-(to be called from supports_device()) that allows to specify the version
-of the parent node this device node wants to talk to. This should probably be done by simply adding a simple bus driver named
-"generic" that generic drivers need to ask for. Due to the way the device tree is built, the device manager could remember
-which driver served a given device node. That way, it wouldn't need to search
-for a driver anymore, but could just pick it up. Practically, the device manager
-should cache the type (and/or vendor/device) information of a node, and assign
-one or more drivers (via module name) to this information. It should also
-remember negative outcome, that is if there is no driver supporting the
-hardware. This way, only the first boot would require an actual search for drivers, as
-subsequent boots would reuse the type-driver assignments. If a new driver is
-installed, the cached assignments would need to be updated immediately. If a
-driver has been installed outside of the running system, the device manager
-might want to create a hash per module directory to see if anything changed to
-flush the cache. Alternatively or additionally, the boot loader could have a
-menu causing the cache to be ignored. It would be nice to find a way for generic and simple busses to reduce the
-amount of searching necessary for them. One way would be to remember which
-driver supports which bus - but this information is currently only accessible
-derived from what the driver does, and is therefore not reliable or complete.
-A separately exported information would be necessary for this. Also, when looking for a generic or simple bus driver, actual directories
-could be omitted; currently, driver search is always recursive, as that's how
-the module mechanism is working. Eventually, we might want to extend the
-open_module_list_etc() call a bit more to accomplish that.
- The latter is only used for live query updates, but is obviously called by
- the former. The port/token pair identify a unique BLooper/BHandler pair, and
- it used internally to address those high-level objects from the kernel.
-
- When a file system calls the
- Each of the parameters Resources for the Be File System
-
-Haiku boot process specification
-
- Creation Date: November 23, 2002
-
-
- Version: 2.0 (Jan 22, 2021)
- Status: documenting the current state of things
- Author(s): Axel Dörfler, Adrien Destugues
- Overview
-
- Booting from BIOS
-
- Stage 1
-
- The MBR only loads the first sector of a partition into memory, so it has to load
- the superblock (and the rest of its implementation) by itself.
-
- Theoretically, it is enough to load the first few blocks from the loader, and
- let the next stage then load the whole thing (which it has to do anyway if it
- has been written on a floppy). This would be one possible optimization
- if the 850 bytes of space are filled too early, but would require that "zbeos"
- is written in one sequential block (which should be always the case anyway).
- haiku_loader.bios_ia32
- Stage 1.5
- Stage 2
- Open Firmware
-
- U-Boot
-
- EFI
-
- Introduction to Haiku's Device Driver Architecture
-
-1. The Basics
-
-2. Exploring the Device Tree
-
-3. Writing a Driver
-
-
-
-
-
- Determines wether or not the driver supports a given parent device node,
- that is the hardware device it represents (if any), and the API the node
- exports.
- The driver should register its device node here. The parent driver is
- always initialized at this point. When registering the node, the driver
- can also attach certain I/O resources (like I/O ports, or memory ranges)
- to the node -- the device manager will make sure that only one node can
- claim these resources.
- Any initialization necessary to get the driver going. For most drivers,
- this will be reduced to the creation of a private data structure that is
- going to be used for all of the following functions.
- Uninitializes resources acquired by init_driver().
- If the driver wants to register any child device nodes or to publish
- any devices, it should do so here. This function is called only during
- the initial registration process of the device node.
- Is called whenever a manual rescan is triggered.
- Enters different sleep modes.
- Resumes a device from a previous sleep mode.4. Publishing a Device
-
-To publish a device entry in the device file system under /dev, all your
-driver has to do is to call the
-
- publish_device(device_node *node, const char *path,
- const char *deviceModuleName);
-
-function the device manager module exports. The path is the path
-component that follows "/dev", for example "net/ipro1000/0". The
-deviceModuleName is the module exporting the device functionality.
-It should end with "device_v1" to show the device manager which protocol it
-supports. If the device node your device belongs to is removed, your device
-is removed automatically with it. On the other hand, you are allowed to
-unpublish the device at any point using the unpublish_device() function
-the device manager delivers for this.
-
-
-
-
- This is called when the open() is called on this device for the first
- time. You may want to create a private data structure that is passed on
- to all subsequent calls of the open() function that your device
- exports.
- Is called when the last file descriptor to the device had been closed.
- When the device node your device belongs to is going to be removed,
- you're notified about this in this function.
- Called whenever your device is opened.
-
- Free the private data structure you allocated in open().
-
-
- This is a replacement for the read(), and write() calls,
- and allows, among other things, for asynchronous I/O. This functionality
- has not yet been implemented, though (see below).
-
-
- 5. Writing a Bus Driver
-
-5.1. Writing an Intelligent Bus Driver
-
-
-
-
-
- The vendor ID - this ID has only to be valid in the namespace of your
- bus.
- The device ID.
- The device type as defined by the PCI class base information.
- The device sub type as defined by the PCI sub class information.
- The device interface type as defined by the PCI class API information.5.2. Writing a Simple Bus Driver
-
-
-
-
-The generic bus
-
-Some devices are not tied to a specific bus. This is the case for all drivers
-that do not relate to a physical device: /dev/null, /dev/zero, /dev/random,
-etc.
-
-A "generic" bus has been added, and these drivers can attach to it.
-
-6. Open Issues
-
-While most of the new device manager is fledged out, there are some areas that
-could use improvements or are problematic under certain requirements. Also, some
-parts just haven't been written yet.
-
-6.1. generic/simple busses
-
-6.2. Unpublishing
-
-6.4. Versioning
-
-6.5. Unregistering Nodes
-
-6.6. Support for generic drivers is missing
-
-6.7. Mappings, And Other Optimizations
-
-Node Monitoring
-
- Creation Date: January 16, 2003
-
- This document describes the feature of the BeOS kernel to monitor nodes. First,
- there is an explanation of what kind of functionality we have to reproduce (along
- with the higher level API), then we will present the implementation in OpenBeOS.
-
-
- Author(s): Axel Dörfler
- Requirements - Exported Functionality in BeOS
-
- From user-level, BeOS exports the following API as found in the storage/NodeMonitor.h
- header file:
-
-
- status_t watch_node(const node_ref *node,
- uint32 flags,
- BMessenger target);
-
- status_t watch_node(const node_ref *node,
- uint32 flags,
- const BHandler *handler,
- const BLooper *looper = NULL);
-
- status_t stop_watching(BMessenger target);
-
- status_t stop_watching(const BHandler *handler,
- const BLooper *looper = NULL);
-
-
- The kernel also exports two other functions to be used from file system add-ons
- that causes the kernel to send out notification messages:
-
-
- int notify_listener(int op, nspace_id nsid,
- vnode_id vnida, vnode_id vnidb,
- vnode_id vnidc, const char *name);
- int send_notification(port_id port, long token,
- ulong what, long op, nspace_id nsida,
- nspace_id nsidb, vnode_id vnida,
- vnode_id vnidb, vnode_id vnidc,
- const char *name);
-
-
- notify_listener() function, it will have
- a look if there are monitors for that node which meet the specified constraints -
- and it will call send_notification() for every single message to be send.
- vnida - vnidc has a dedicated meaning:
-
-
-
- The flags parameter in watch_node() understands the following constants:
-
- Node monitors are maintained per team - every team can have up to 4096 monitors, although - there exists a private kernel call to raise this limit (for example, Tracker is using it - intensively). -
-- The kernel is able to send the BMessages directly to the specified BLooper and BHandler; - it achieves this using the application kit's token mechanism. The message is constructed - manually in the kernel, it doesn't use any application kit services. -
-
- If you assume that every file operation could trigger a notification message to be send,
- it's clear that the node monitoring system must be optimized for sending messages. For
- every call to notify_listener(), the kernel must check if there are any
- monitors for the node that was updated.
-
- Those monitors are put into a hash table which has the device number and the vnode ID - as keys. Each of the monitors maintains a list of listeners which specify which port/token - pair should be notified for what change. Since the vnodes are created/deleted as needed - from the kernel, the node monitor is maintained independently from them; a simple pointer - from a vnode to its monitor is not possible. -
-- The main structures that are involved in providing the node monitoring functionality - look like this: -
- -
- struct monitor_listener {
- monitor_listener *next;
- monitor_listener *prev;
- list_link monitor_link;
- port_id port;
- int32 token;
- uint32 flags;
- node_monitor *monitor;
- };
-
- struct node_monitor {
- node_monitor *next;
- mount_id device;
- vnode_id node;
- struct list listeners;
- };
-
-
- - The relevant part of the I/O context structure is this: -
- -
- struct io_context {
- ...
- struct list node_monitors;
- uint32 num_monitors;
- uint32 max_monitors;
- };
-
-
-
- If you call watch_node() on a file with a flags parameter unequal to
- B_STOP_WATCHING, the following will happen in the node monitor:
-
add_node_monitor() function does a hash lookup for the
- device/vnode pair. If there is no node_monitor yet for this pair,
- a new one will be created.monitor_listener
- is created if necessary - in the latter case, the team's node monitor
- counter is incremented.
- If it's called with B_STOP_WATCHING defined, the reverse operation take effect, and
- the monitor field is used to see if this monitor don't have any listeners
- anymore, in which case it will be removed.
-
- Note the presence of the max_monitors - there is no hard limit the kernel
- exposes to userland applications; the listeners are maintained in a doubly-linked list.
-
- If a team is shut down, all listeners from its I/O context will be removed - since every - listener stores a pointer to its monitor, determining the monitors that can be removed - because of this operation is very cheap. -
-
- The notify_listener() also only does a hash lookup for the device/node
- pair it got from the file system, and sends out as many notifications as specified by
- the listeners of the monitor that belong to that node.
-
- If a node is deleted from the disk, the corresponding node_monitor and its
- listeners will be removed as well, to prevent watching a new file that accidently happen
- to have the same device/node pair (as is possible with BFS, for example).
-
- Although the aim was to create a completely compatible monitoring implementation, - there are some notable differences between the two. -
-
- BeOS reserves a certain number of slots for calls to watch_node() - each
- call to that function will use one slot, even if you call it twice for the same node.
- OpenBeOS, however, will always use one slot per node - you could call watch_node()
- several times, but you would waste only one slot.
-
- While this is an implementational detail, it also causes a change in behaviour for
- applications; in BeOS, applications will get one message for every watch_node()
- call, in OpenBeOS, you'll get only one message per node. If an application relies
- on this strange behaviour of the BeOS kernel, it will no longer work correctly.
-
- The other difference is that OpenBeOS exports its node monitoring functionality to - kernel modules as well, and provides an extra plain C API for them to use. -
- -- The current implementation directly iterates over all listeners and sends out notifications - as required synchronously in the context of the thread that triggered the notification to - be sent. -
-- If a node monitor needs to send out several messages, this could theoretically greatly - decrease file system performance. To optimize for this case, the required data of the - notification could be put into a queue and be sent by a dedicated worker thread. Since - this requires an additional copy operation and a reserved address space for this queue, - this optimization could be more expensive than the current implementation, depending - on the usage pattern of the node monitoring mechanism. -
-- With BFS, it would be possible to introduce the possibility to automatically watch all - files in a specified directory. While this would be very convenient at application level, - it comes with several disadvantages: -
-- While 1.) might be a real show stopper, 2.) is almost invalidated because of Tracker's - usage of node monitors; it consumes a monitor for every entry it displays, which might - be several thousands. Implementing this feature would not only greatly speed up maintaining - this massive need of monitors, and cut down memory usage, but also ease the implementation - at application level. -
-- Even 1.) could be solved if the kernel could query a file system if it can support - this particular feature; it could then automatically monitor all files in that directory - without adding complexity to the application using this feature. Of course, - the effort to provide this functionality is much larger then - but for applications - like Tracker, the complexity would be removed from the application without extra cost. -
-- However, none of the discussed feature extensions have been implemented for the currently - developed version R1 of OpenBeOS. -
- - diff --git a/docs/develop/kernel/fs/node_monitoring.rst b/docs/develop/kernel/fs/node_monitoring.rst new file mode 100644 index 0000000000..8e373998a7 --- /dev/null +++ b/docs/develop/kernel/fs/node_monitoring.rst @@ -0,0 +1,257 @@ +Node Monitoring +=============== + +Creation Date: January 16, 2003 +Author(s): Axel Dörfler + + +This document describes the feature of the BeOS kernel to monitor nodes. +First, there is an explanation of what kind of functionality we have to +reproduce (along with the higher level API), then we will present the +implementation in OpenBeOS. + +Requirements - Exported Functionality in BeOS +--------------------------------------------- + +From user-level, BeOS exports the following API as found in the +storage/NodeMonitor.h header file: + +:: + + status_t watch_node(const node_ref *node, + uint32 flags, + BMessenger target); + + status_t watch_node(const node_ref *node, + uint32 flags, + const BHandler *handler, + const BLooper *looper = NULL); + + status_t stop_watching(BMessenger target); + + status_t stop_watching(const BHandler *handler, + const BLooper *looper = NULL); + + +The kernel also exports two other functions to be used from file system +add-ons that causes the kernel to send out notification messages: + +:: + + int notify_listener(int op, nspace_id nsid, + vnode_id vnida, vnode_id vnidb, + vnode_id vnidc, const char *name); + int send_notification(port_id port, long token, + ulong what, long op, nspace_id nsida, + nspace_id nsidb, vnode_id vnida, + vnode_id vnidb, vnode_id vnidc, + const char *name); + + +The latter is only used for live query updates, but is obviously called +by the former. The port/token pair identify a unique BLooper/BHandler +pair, and it used internally to address those high-level objects from +the kernel. + +When a file system calls the ``notify_listener()`` function, it will +have a look if there are monitors for that node which meet the specified +constraints - and it will call ``send_notification()`` for every single +message to be send. + +Each of the parameters ``vnida - vnidc`` has a dedicated meaning: + +- **vnida:** the parent directory of the "main" node +- **vnidb:** the target parent directory for a move +- **vnidc:** the node that has triggered the notification to be send + +The flags parameter in ``watch_node()`` understands the following +constants: + +- **B_STOP_WATCHING** + watch_node() will stop to watch the specified node. +- **B_WATCH_NAME** + name changes are notified through a B_ENTRY_MOVED opcode. +- **B_WATCH_STAT** + changes to the node's stat structure are notified with a + B_STAT_CHANGED code. +- **B_WATCH_ATTR** + attribute changes will cause a B_ATTR_CHANGED to be send. +- **B_WATCH_DIRECTORY** + notifies on changes made to the specified directory, i.e. + B_ENTRY_REMOVED, B_ENTRY_CREATED +- **B_WATCH_ALL** + is a short-hand for the flags above. +- **B_WATCH_MOUNT** + causes B_DEVICE_MOUNTED and B_DEVICE_UNMOUNTED to be send. + +Node monitors are maintained per team - every team can have up to 4096 +monitors, although there exists a private kernel call to raise this +limit (for example, Tracker is using it intensively). + +The kernel is able to send the BMessages directly to the specified +BLooper and BHandler; it achieves this using the application kit's token +mechanism. The message is constructed manually in the kernel, it doesn't +use any application kit services. + +| + +Meeting the Requirements in an Optimal Way - Implementation in OpenBeOS +----------------------------------------------------------------------- + +If you assume that every file operation could trigger a notification +message to be send, it's clear that the node monitoring system must be +optimized for sending messages. For every call to ``notify_listener()``, +the kernel must check if there are any monitors for the node that was +updated. + +Those monitors are put into a hash table which has the device number and +the vnode ID as keys. Each of the monitors maintains a list of listeners +which specify which port/token pair should be notified for what change. +Since the vnodes are created/deleted as needed from the kernel, the node +monitor is maintained independently from them; a simple pointer from a +vnode to its monitor is not possible. + +The main structures that are involved in providing the node monitoring +functionality look like this: + +:: + + struct monitor_listener { + monitor_listener *next; + monitor_listener *prev; + list_link monitor_link; + port_id port; + int32 token; + uint32 flags; + node_monitor *monitor; + }; + + struct node_monitor { + node_monitor *next; + mount_id device; + vnode_id node; + struct list listeners; + }; + + +The relevant part of the I/O context structure is this: + +:: + + struct io_context { + ... + struct list node_monitors; + uint32 num_monitors; + uint32 max_monitors; + }; + + +If you call ``watch_node()`` on a file with a flags parameter unequal to +B_STOP_WATCHING, the following will happen in the node monitor: + +#. The ``add_node_monitor()`` function does a hash lookup for the + device/vnode pair. If there is no ``node_monitor`` yet for this pair, + a new one will be created. +#. The list of listeners is scanned for the provided port/token pair + (the BLooper/BHandler pointer will already be translated in + user-space), and the new flag is or'd to the old field, or a new + ``monitor_listener`` is created if necessary - in the latter case, + the team's node monitor counter is incremented. + +If it's called with B_STOP_WATCHING defined, the reverse operation take +effect, and the ``monitor`` field is used to see if this monitor don't +have any listeners anymore, in which case it will be removed. + +Note the presence of the ``max_monitors`` - there is no hard limit the +kernel exposes to userland applications; the listeners are maintained in +a doubly-linked list. + +If a team is shut down, all listeners from its I/O context will be +removed - since every listener stores a pointer to its monitor, +determining the monitors that can be removed because of this operation +is very cheap. + +The ``notify_listener()`` also only does a hash lookup for the +device/node pair it got from the file system, and sends out as many +notifications as specified by the listeners of the monitor that belong +to that node. + +If a node is deleted from the disk, the corresponding ``node_monitor`` +and its listeners will be removed as well, to prevent watching a new +file that accidently happen to have the same device/node pair (as is +possible with BFS, for example). + +| + +Differences Between Both Implementations +---------------------------------------- + +Although the aim was to create a completely compatible monitoring +implementation, there are some notable differences between the two. + +BeOS reserves a certain number of slots for calls to ``watch_node()`` - +each call to that function will use one slot, even if you call it twice +for the same node. OpenBeOS, however, will always use one slot per node +- you could call ``watch_node()`` several times, but you would waste +only one slot. + +While this is an implementational detail, it also causes a change in +behaviour for applications; in BeOS, applications will get one message +for every ``watch_node()`` call, in OpenBeOS, you'll get only one +message per node. If an application relies on this strange behaviour of +the BeOS kernel, it will no longer work correctly. + +The other difference is that OpenBeOS exports its node monitoring +functionality to kernel modules as well, and provides an extra plain C +API for them to use. + +| + +And Beyond? +----------- + +The current implementation directly iterates over all listeners and +sends out notifications as required synchronously in the context of the +thread that triggered the notification to be sent. + +If a node monitor needs to send out several messages, this could +theoretically greatly decrease file system performance. To optimize for +this case, the required data of the notification could be put into a +queue and be sent by a dedicated worker thread. Since this requires an +additional copy operation and a reserved address space for this queue, +this optimization could be more expensive than the current +implementation, depending on the usage pattern of the node monitoring +mechanism. + +With BFS, it would be possible to introduce the possibility to +automatically watch all files in a specified directory. While this would +be very convenient at application level, it comes with several +disadvantages: + +#. This feature might not be easily accomplishable for many file + systems; a file system must be able to retrieve a node by ID only - + it might not be feasible to find out about the parent directory for + many file systems. +#. Although it could potentially safe node monitors, it might cause the + kernel to send out a lot more messages to the application than it + needs. With the restriction the kernel imposes to the number of + watched nodes for a team, the application's designer might try to be + much stricter with the number of monitors his application will + consume. + +While 1.) might be a real show stopper, 2.) is almost invalidated +because of Tracker's usage of node monitors; it consumes a monitor for +every entry it displays, which might be several thousands. Implementing +this feature would not only greatly speed up maintaining this massive +need of monitors, and cut down memory usage, but also ease the +implementation at application level. + +Even 1.) could be solved if the kernel could query a file system if it +can support this particular feature; it could then automatically monitor +all files in that directory without adding complexity to the application +using this feature. Of course, the effort to provide this functionality +is much larger then - but for applications like Tracker, the complexity +would be removed from the application without extra cost. + +However, none of the discussed feature extensions have been implemented +for the currently developed version R1 of OpenBeOS. diff --git a/docs/develop/kernel/obsolete_pnp_manager b/docs/develop/kernel/obsolete_pnp_manager deleted file mode 100644 index eeb9d31c79..0000000000 --- a/docs/develop/kernel/obsolete_pnp_manager +++ /dev/null @@ -1,406 +0,0 @@ -This file contains the documentation written by Thomas Kurschel that was originally -found in the headers of his pnp_manager. -It's outdated but could be used as a basis for the real documentation. - -// former pnp_manager.h -/* - Copyright (c) 2003-04, Thomas Kurschel - - PnP manager; Takes care of registration and loading of PnP drivers - - Read pnp_driver.h first to understand the basic idea behind PnP drivers. - - To register a driver node, use register_driver. If the device got lost, - use unregister_driver (note: if the parent node is removed, your node - get removed automatically as your driver has obviously nothing to work - with anymore). To get access to a (parent) device, use load_driver/ - unload_driver. - - To let the manager find a consumer (see pnp_driver.h), you can either - specify its name directly during registration, using a - PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the - appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute. - - Searching of dynamic consumers is done as follows: - - - First, the manager searches for a Specific driver in the base - directory (see below) - - If no Specific driver is found, all Generic drivers stored under - "generic" sub-directory are informed in turn until one returns success - - Finally, _all_ Universal drivers, stored in the "universal" sub- - directory, are informed - - Specification of the base directory and of the names of Specific - drivers is done via a file name pattern given by a - PNP_DRIVER_DYNAMIC_CONSUMER attribute. - - First, all substrings of the form "%attribute_name%" are replaced by the - content of the attribute "attribute_name" as follows: - - - if the attribute contains an integer value, its content is converted to hex - (lowercase) with a fixed length according to the attribute's value range - - the content of string attributes is quoted by " and invalid characters - (i.e. /%" and all characters outside 32..126) are replaced by their - unsigned decimal value, delimited by % - - other attribute types cannot be used - - Second, the resulting name is split into chunks according to the presence - of | characters (you can escape % and | with a ^ character). These - characters are only delimiters and get removed before further processing. - The directory before the first | character is the base directory (see - above). It contains the "generic" and the "universal" subdirectories. - The names of the specific drivers are created by first taking the entire - file name, then by removing the last chunk, then by removing the last - two chunks and so on until only the first chunk is left. - - As drivers can contain multiple modules, the module name is constructed - by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file - name, seperated by a slash character (note: this only applies to dynamic - consumers; for fixed consumers, you specify the module name directly via - PNP_DRIVER_FIXED_CONSUMER). - - E.g. given a dynamic consumer pattern of - "pci/vendor=%vendor_id%|, device=%device_id%" for a device with the - attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the - PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and - (if the first one fails/doesn't exist) "pci/vendor=0123". If they both - refuse to handle the device, all drivers under "pci/generic" are tried - until one accepts the device. Finally, all drivers under "pci/universal" - are loaded, whatever happened before. - - In practise, you should try to use specific drivers as much as possible. - If detection based on device IDs is impossible (e.g. because the bus - doesn't support them at all), you can put the driver under "generic". - Generic drivers can also be used to specify wrappers that try to load old- - style drivers if no new driver can be found. Also, they can be used to - report an error or invoke an user program that tries downloading a - proper Specific driver. Universal drivers are mainly used for - informational purposes, e.g. to publish data about each found device, - or to provide raw access to all devices. - - If the device uses physical address space or I/O space or ISA DMA - channels (called I/O resources), the driver has to acquire these - resources. During hardware detection (usually via probe()), - acquire_io_resources() must be called to get exclusive access. - If no hardware could be found, they must be released via - release_io_resources(). If detection was successful, the list of - the (acquired) resources must be passed to register_device(). - Resources can either belong to one hardware detection or to a device. - If a hardware detection collides with another, it has to wait; - if it collides with a device whose driver is not loaded, the - driver loading is blocked. When detection fails, i.e. if - release_io_resources() is called, all blocked drivers can be loaded - again. If the detection fails, i.e. the resources are transferred - via register_device(), all blocked devices are unregistered and - pending load requests aborted. If a hardware detection collides - with a device whose driver is loaded, acquire_io_resources() fails - with B_BUSY. As this makes a hardware rescan impossible if the - driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN - for nodes that use I/O resources (see below). - - To search for new drivers for a given device node, use rescan(). This - marks all consumer devices as being verified and calls probe() - of all consumers drivers (see above) to let them rescan the parent - for devices. TheThe Midi Kit consists of the midi_server and two shared libraries, -libmidi2.so and libmidi.so. The latter is the "old" pre-R5 Midi Kit and has -been re-implemented using the facilities from libmidi2, which makes it fully -compatible with the new kit. This document describes the design and -implementation of the OpenBeOS midi_server and libmidi2.so.
- -The midi_server has two jobs: it keeps track of the endpoints that the -client apps have created, and it publishes endpoints for the devices from -/dev/midi. (This last task could have been done by any other app, but it was -just as convenient to make the midi_server do that.) The libmidi2.so library -also has two jobs: it assists the midi_server with the housekeeping stuff, and -it allows endpoints to send and receive MIDI events. (That's right, the -midi_server has nothing to do with the actual MIDI data.)
- -The following image shows the center of Midi Kit activity, the midi_server, -and its data structures:
- -- -
And here is the picture for libmidi2.so:
- -- -
Note that these diagrams give only a conceptual overview of who is -responsible for which bits of data. The actual implementation details of the -kit may differ.
- -The design for our implementation of the midi2 "housekeeping" protocol -roughly follows what Be did, although there are -some differences. In Be's implementation, the BMidiRosters only have -BMidiEndpoints for remote endpoints if they are registered. In our -implementation, the BMidiRosters have BMidiEndpoint objects for all -endpoints, including remote endpoints that aren't published at all. If there -are many unpublished endpoints in the system, our approach is less optimal. -However, it made the implementation of the Midi Kit much easier ;-)
Be's libmidi2.so exports the symbols "midi_debug_level" and -"midi_dispatcher_priority", both int32's. Our libmidi2 does not use either of -these. But even though these symbols are not present in the headers, some apps -may use them nonetheless. That's why our libmidi2 exports those symbols as -well.
The name of the message fields in Be's implementation of the protocol -had the "be:" prefix. Our fields have a "midi:" prefix instead. Except for the -fields in the B_MIDI_EVENT notification messages, because that would break -compatibility with existing apps.
The first time an app uses a midi2 class, the BMidiRoster::MidiRoster() -method sends an 'Mapp' message to the midi_server, and blocks (on a semaphore). -This message includes a messenger to the app's BMidiRosterLooper object. The -server adds the app to its list of registered apps. Then the server -asynchronously sends back a series of 'mNEW' message notifications for all -endpoints on the roster, and 'mCON' messages for all existing connections. The -BMidiRosterLooper creates BMidiEndpoint objects for these endpoints and adds -them to its local roster; if the app is watching, it also sends out -corresponding B_MIDI_EVENT notifications. Finally, the midi_server sends an -'mAPP' message to notify the app that it has been successfully registered. Upon -receipt, BMidiRoster::MidiRoster() unblocks and returns control to the client -code. This handshake is the only asynchronous message exchange; all the other -requests have a synchronous reply.
If the server detects an error during any of this (incorrect message -format, delivery failure, etc.) it simply ignores the request and does not try -to send anything back to the client (which is most likely impossible anyway). -If the app detects an error (server sends back meaningless info, cannot connect -to server), it pretends that everything is hunkey dorey. (The API has no way of -letting the client know that the initialization succeeded.) Next time the app -tries something, the server either still does not respond, or it ignores the -request (because this app isn't properly registered). However, if the app does -not receive the 'mAPP' message, it will not unblock, and remains frozen for all -eternity.
BMidiRoster's MidiRoster() method creates the one and only BMidiRoster -instance on the heap the first time it is called. This instance is -automatically destroyed when the app quits.
If some error occurs, then the reply message is only guaranteed to -contain the "midi:result" field with some non- zero error code. libmidi2 can -only assume that the reply contains other data on success (i.e. when -"midi:result" is B_OK).
The timeout for delivering and responding to a message is about 2 -seconds. If the client receives no reply within that time, it assumes the -request failed. If the server cannot deliver a message within 2 seconds, it -assumes the client is dead and removes it (and its endpoints) from the roster. -Of course, these assumptions may be false. If the client wasn't dead and tries -to send another request to the server, then the server will now ignore it, -since the client app is no longer registered.
Because we work with timeouts, we must be careful to avoid -misunderstandings between the midi_server and the client app. Both sides must -recognize the timeout, so they both can ignore the operation. If, however, the -server thinks that everything went okay, but the client flags an error, then -the server and the client will have two different ideas of the current state of -the roster. Of course, those situations must be avoided.
Although apps register themselves with the midi_server, there is no -corresponding "unregister" message. The only way the server recognizes that an -app and its endpoints are no longer available is when it fails to deliver a -message to that app. In that case, we remove the app and all its endpoints from -the roster. To do this, the server sends "purge endpoint" messages to itself -for all of the app's endpoints. This means we don't immediately throw the app -away, but we schedule that for some time in the future. That makes the whole -event handling mechanism much cleaner. There is no reply to the purge request. -(Actually, we do immediately throw away the app_t object, since that -doesn't really interfere with anything.) (If there are other events pending in -the queue which also cause notifications, then the server may send multiple -purge messages for the same endpoints. That's no biggie, because a purge -message will be ignored if its endpoint no longer exists.)
As mentioned above, the midi_server ignores messages that do not come -from a registered app, although it does send back an error reply. In the case -of the "purge endpoint" message, the server makes sure the message was local -(i.e. sent by the midi_server itself).
Note: BMessage's SendReply() apparently succeeds even if you kill the -app that the reply is intended for. This is rather strange, and it means that -you can't test delivery error handling for replies by killing the app. (You -can kill the app for testing the error handling on notifications, -however.)
When client code creates a new BMidiLocalProducer or BMidiLocalConsumer -endpoint, we send an 'Mnew' message to the server. Unlike Be's implementation, -the "name" field is always present, even if the name is empty. After adding the -endpoint to the roster, the server sends 'mNEW' notifications to all other -applications. Upon receipt of this notification, the BMidiRosterLoopers of -these apps create a new BMidiEndpoint for the endpoint and add it to their -internal list of endpoints. The app that made the request receives a reply with -a single "midi:result" field.
When you "new" an endpoint, its refcount is 1, even if the creation -failed. (For example, if the midi_server does not run.) When you Acquire(), the -refcount is bumped. When you Release(), it is decremented. When refcount drops -to 0, the endpoint object "deletes" itself. (So client code should never use an -endpoint after having Release()'d it, because the object may have just been -killed.) When creation succeeds, IsValid() returns true and ID() returns a -valid ID (> 0). Upon failure, IsValid() is false and ID() returns 0.
After the last Release() of a local endpoint, we send 'Mdel' to let the -midi_server know the endpoint is now deleted. We don't expect a reply back. If -something goes wrong, the endpoint is deleted regardless. We do not send -separate "unregistered" notifications, because deleting an endpoint implies -that it is removed from the roster. For the same reason, we also don't send -separate "disconnected" notifications.
The 'mDEL' notification triggers a BMidiRosterLooper to remove the -corresponding BMidiEndpoint from its internal list. This object is always a -proxy for a remote endpoint. The remote endpoint is gone, but whether we can -also delete the proxy depends on its reference count. If no one is still using -the object, its refcount is zero, and we can safely delete the object. -Otherwise, we must defer destruction until the client Release()'s the -object.
If you "delete" an endpoint, your app drops into the debugger.
If you Release() an endpoint too many times, your app could drop -into the debugger. It might also crash, because you are now using a dead -object. It depends on whether the memory that was previously occupied by your -endpoint object was overwritten in the mean time.
You are allowed to pass NULL into the constructors of BMidiLocalConsumer -and BMidiLocalProducer, in which case the endpoint's name is simply an empty -string.
An endpoint can be "invalid". In the case of a proxy this means that the -remote endpoint is unregistered or even deleted. Local endpoints can only be -invalid if something went wrong during their creation (no connection to server, -for example). You can get the attributes of invalid objects, but you cannot set -them. Any attempts to do so will return an error code.
For changing the name, latency, or properties of an endpoint, libmidi2 -sends an 'Mchg' message with the fields that should be changed, "midi:name", -"midi:latency", or "midi:properties". Registering or unregistering an endpoint -also sends such an 'Mchg' message, because we consider the "registered" state -also an attribute, in "midi:registered". The message obviously also includes -the ID of the endpoint in question. Properties are sent using a different -message, because the properties are not stored inside the -BMidiEndpoints.
After handling the 'Mchg' request, the midi_server broadcasts an 'mCHG' -notification to all the other apps. This message has the same contents as the -original request.
If the 'Mchg' message contains an invalid "midi:id" (i.e. no such -endpoint exists or it does not belong to the app that sent the request), the -midi_server returns an error code, and it does not notify the other -apps.
If you try to Register() an endpoint that is already registered, -libmidi2 does not send a message to the midi_server but simply returns B_OK. -(Be's implementation did send a message, but our libmidi2 also keeps -track whether an endpoint is registered or not.) Although registering an -endpoint more than once doesn't make much sense, it is not considered an error. -Likewise for Unregister()ing an endpoint that is not registered.
If you try to Register() or Unregister() a remote endpoint, libmidi2 -immediately returns an error code, and does not send a message to the server. -Likewise for a local endpoints that are invalid (i.e. whose IsValid() function -returns false).
BMidiRoster::Register() and Unregister() do the same thing as -BMidiEndpoint::Register() and Unregister(). If you pass NULL into these -functions, they return B_BAD_VALUE.
SetName() ignores NULL names. When you call it on a remote endpoint, -SetName() does nothing. SetName() does not send a message if the new name is -the same as the current name.
SetLatency() ignores negative values. SetLatency() does not send a -message if the new latency is the same as the current latency. (Since -SetLatency() lives in BMidiLocalConsumer, you can never use it on remote -endpoints.)
We store a copy of the endpoint properties in each BMidiEndpoint. The -properties of new endpoints are empty. GetProperties() copies this BMessage -into the client's BMessage. GetProperties() returns NULL if the message -parameter is NULL.
SetProperties() returns NULL if the message parameter is NULL. It -returns an error code if the endpoint is remote or invalid. SetProperties() -does not compare the contents of the new BMessage to the old, so it will -always send out the change request.
BMidiProducer::Connect() sends an 'Mcon' request to the midi_server. -This request contains the IDs of the producer and the consumer you want to -connect. The server sends back a reply with a result code. If it is possible to -make this connection, the server broadcasts an 'mCON' notification to all other -apps. In one of these apps the producer is local, so that app's libmidi2 calls -the BMidiLocalProducer::Connected() hook.
You are not allowed to connect the same producer and consumer more than -once. The midi_server checks for this. It also returns an error code if you try -to disconnect two endpoints that were not connected.
Disconnect() sends an 'Mdis' request to the server, which contains the -IDs of the producer and consumer that you want to disconnect. The server -replies with a result code. If the connection could be broken, it also sends an -'mDIS' notification to the other apps. libmidi2 calls the local producer's -BMidiLocalProducer::Disconnected() hook.
Connect() and Disconnect() immediately return an error code if you pass -a NULL argument, or if the producer or consumer is invalid.
When you Release() a local consumer that is connected, all apps will go -through their producers, and throw away this consumer from their connection -lists. If one of these producers is local, we call its Disconnected() hook. If -you release a local producer, this is not necessary.
When you call StartWatching(), the BMidiRosterLooper remembers the -BMessenger, and sends it B_MIDI_EVENT notifications for all registered remote -endpoints, and the current connections between them. It does not let you know -about local endpoints. When you call StartWatching() a second time with the -same BMessenger, you'll receive the whole bunch of notifications again. -StartWatching(NULL) is not allowed, and will be ignored (so it is not the same -as StopWatching()).
Within libmidi2 there are several possible race conditions, because we -are dealing with two threads: the one from BMidiRosterLooper and a thread from -the client app, most likely the BApplication's main thread. Both can access the -same data: BMidiEndpoint objects. To synchronize these threads, we lock the -BMidiRosterLooper, which is a normal BLooper. Anything happening in -BMidiRosterLooper's message handlers is safe, because BLoopers are -automatically locked when handling a message. Any other operations (which run -from a different thread) must first lock the looper if they access the list of -endpoints or certain BMidiEndpoint attributes (name, properties, etc).
What if you obtain a BMidiEndpoint object from FindEndpoint() and at the -same time the BMidiRosterLooper receives an 'mDEL' request to delete that -endpoint? FindEndpoint() locks the looper, and bumps the endpoint object before -giving it to you. Now the looper sees that the endpoint's refcount is larger -than 0, so it won't delete it (although it will remove the endpoint from its -internal list). What if you Acquire() or Release() a remote endpoint while it -is being deleted by the looper? That also won't happen, because if you have a -pointer to that endpoint, its refcount is at least 1 and the looper won't -delete it.
It is not safe to use a BMidiEndpoint and/or the BMidiRoster from more -than one client thread at a time; if you want to do that, you should -synchronize access to these objects yourself. The only exception is the Spray() -functions from BMidiLocalProducer, since most producers have a separate thread -to spray their MIDI events. This is fine, as long as that thread isn't used for -anything else, and it is the only one that does the spraying.
BMidiProducer objects keep a list of consumers they are connected to. -This list can be accessed by several threads at a time: the client's thread, -the BMidiRosterLooper thread, and possibly a separate thread that is spraying -MIDI events. We could have locked the producer using BMidiRosterLooper's lock, -but that would freeze everything else while the producer is spraying events. -Conversely, it would freeze all producers while the looper is talking to the -midi_server. To lock with a finer granularity, each BMidiProducer has its own -BLocker, which is used only to lock the list of connected consumers.
BMidiEndpoint keeps track of its local/remote state with an "isLocal" -variable, and whether it is a producer/consumer with "isConsumer". It also has -an "isRegistered" field to remember whether this endpoint is registered or not. -Why not lump all these different states together into one "flags" bitmask? The -reason is that isLocal only makes sense to this application, not to others. -Also, the values of isLocal and isConsumer never change, but isRegistered does. -It made more sense (and clearer code) to separate them out. Finally, -isRegistered does not need to be protected by a lock, even though it can be -accessed by multiple threads at a time. Reading and writing a bool is atomic, -so this can't get messed up.
- --Message: Mapp (MSG_REGISTER_APP) - BMessenger midi:messenger -Reply: - (no reply) - -Message: mAPP (MSG_APP_REGISTERED) - (no fields) - -Message: Mnew (MSG_CREATE_ENDPOINT) - bool midi:consumer - bool midi:registered - char[] midi:name - BMessage midi:properties - int32 midi:port (consumer only) - int64 midi:latency (consumer only) -Reply: - int32 midi:result - int32 midi:id - -Message: mNEW (MSG_ENPOINT_CREATED) - int32 midi:id - bool midi:consumer - bool midi:registered - char[] midi:name - BMessage midi:properties - int32 midi:port (consumer only) - int64 midi:latency (consumer only) - -Message: Mdel (MSG_DELETE_ENDPOINT) - int32 midi:id -Reply: - (no reply) - -Message: Mdie (MSG_PURGE_ENDPOINT) - int32 midi:id -Reply: - (no reply) - -Message: mDEL (MSG_ENDPOINT_DELETED) - int32 midi:id - -Message: Mchg (MSG_CHANGE_ENDPOINT) - int32 midi:id - int32 midi:registered (optional) - char[] midi:name (optional) - int64 midi:latency (optional) - BMessage midi:properties (optional) -Reply: - int32 midi:result - -Message: mCHG (MSG_ENDPOINT_CHANGED) - int32 midi:id - int32 midi:registered (optional) - char[] midi:name (optional) - int64 midi:latency (optional) - BMessage midi:properties (optional) -
MIDI events are always sent from a BMidiLocalProducer to a -BMidiLocalConsumer. Proxy endpoint objects have nothing to do with this. During -its construction, the local consumer creates a kernel port. The ID of this port -is published, so everyone knows what it is. When a producer sprays an event, it -creates a message that it sends to the ports of all connected consumers.
This means that the Midi Kit considers MIDI messages as discrete events. -Hardware drivers chop the stream of incoming MIDI data into separate events -that they send out to one or more kernel ports. Consumers never have to worry -about parsing a stream of MIDI data, just about handling a bunch of separate -events.
Each BMidiLocalConsumer has a (realtime priority) thread associated with -it that waits for data to arrive at the port. As soon as a new MIDI message -comes in, the thread examines it and feeds it to the Data() hook. The Data() -hook ignores the message if the "atomic" flag is false, or passes it on to one -of the other hook functions otherwise. Incoming messages are also ignored if -their contents are not valid; for example, if they have too few or too many -bytes for a certain type of MIDI event.
Unlike the consumer, BMidiLocalProducer has no thread of its own. As a -result, spraying MIDI events always happens in the thread of the caller. -Because the consumer port's queue is only 1 message deep, spray functions will -block if the consumer thread is already busy handling another MIDI event. (For -this reason, the Midi Kit does not support interleaving of real time messages -with lower priority messages such as sysex dumps, except at the driver -level.)
The producer does not just send MIDI event data to the consumer, it also -sends a 20-byte header describing the event. The total message looks like -this:
- -- -
- 4 bytes ID of the producer - 4 bytes ID of the consumer - 8 bytes performance time - 1 byte atomic (1 = true, 0 = false) - 3 bytes padding (0) - - x bytes MIDI event data
In the case of a sysex event, the SystemExclusive() hook is only called -if the first byte of the message is 0xF0. The sysex end marker (0xF7) is -optional; only if the last byte is 0xF7 we strip it off. This is unlike Be's -implementation, which all always strips the last byte even when it is not 0xF7. -According to the MIDI spec, 0xF7 is not really required; any non-realtime -status byte ends a sysex message.
SprayTempoChange() sends 0xFF5103tttttt, where tttttt is 60,000,000/bpm. -This feature is not really part of the MIDI spec, but an extension from the SMF -(Standard MIDI File) format. Of course, the TempoChange() hook is called in -response to this message.
The MIDI spec allows for a number of shortcuts. A Note On event with -velocity 0 is supposed to be interpreted as a Note Off, for example. The Midi -Kit does not concern itself with these shortcuts. In this case, it still calls -the NoteOn() hook with a velocity parameter of 0.
The purpose of BMidiLocalConsumer's AllNotesOff() function is not -entirely clear. All Notes Off is a so-called "channel mode message" and is -generated by doing a SprayControlChange(channel, B_ALL_NOTES_OFF, 0). BMidi has -an AllNotesOff() function that sends an All Notes Off event to all channels, -and possible Note Off events to all keys on all channels as well. I suspect -someone at Be was confused by AllNotesOff() being declared "virtual", and -thought it was a hook function. Only that would explain it being in -BMidiLocalConsumer as opposed to BMidiLocalProducer, where it would have made -sense. The disassembly for Be's libmidi2.so shows that AllNotesOff() is empty, -so to cut a long story short, our AllNotesOff() simply does nothing and is -never invoked either.
There are several types of System Common events, each of which takes a -different number of data bytes (0, 1, or 2). But SpraySystemCommon() and the -SystemCommon() hook are always given 2 data parameters. The Midi Kit simply -ignores the extra data bytes; in fact, in our implementation it doesn't even -send them. (The Be implementation always sends 2 data bytes, but that will -confuse the Midi Kit if the client does a SprayData() of a common event -instead. In our case, that will still invoke the SystemCommon() hook, because -we are not as easily fooled.)
Handling of timeouts is fairly straightforward. When reading from the -port, we specify an absolute timeout. When the port function returns with a -B_TIMED_OUT error code, we call the Timeout() hook. Then we reset the timeout -value to -1, which means that timeouts are disabled (until the client calls -SetTimeout() again). This design means that a call to SetTimeout() only takes -effect the next time we read from the port, i.e. after at least one new MIDI -event is received (or the previous timeout is triggered). Even though -BMidiLocalConsumer's timeout and timeoutData values are accessed by two -different threads, I did not bother to protect this. Both values are int32's -and reading/writing them should be an atomic operation on most processors -anyway.
Midi1 is implemented on top of midi2, which means that libmidi.so depends on libmidi2.so to do the real work. BeOS versions earlier than R5 did not include a midi_server, because midi1 itself did not need it. (A server is only really useful if data must be shared between teams, something that midi1 did not allow.)
- -Midi2 is backwards compatible with midi1: The old libmidi.so still exists so that applications using the old API will run (providing binary compatibility). The old BMidiPort object is now a wrapper that uses the new BMidiRoster to allow connections to any published MIDI producer or consumer. Published MIDI objects are presented to the old MIDI apps as if they were physical MIDI ports.
Here is a very nice picture of how BMidiPort works:

The General MIDI synthesizer is implemented in BSoftSynth. This is a private class (not usable outside the API). It is not a real BMidiEndpoint, so you will not see it appear on Patchbay. I did this for simplicity's sake, for backwards compatibility (this is how the R5 synth worked too), and because we will have to give the Midi Kit a complete makeover for R2 anyway.
The BMidiSynth and BSynth classes delegate most of the work to BSoftSynth. Not all of their methods are implemented, since some of them are very obscure. It would be a lot of work to figure out what they do, while it is likely that no applications use them anyway. However, BMidiSynth and BSynth should perform most common tasks without problems.
BSamples doesn't do anything; its functions are mostly empty. In other words, with the OpenBeOS Midi Kit you cannot push waveform data into the output of the softsynth.
For simplicity's sake, BMidiSynthFile is implemented using BMidiStore, since the latter already knows how to parse Standard MIDI Files. Duplicating that functionality elsewhere would be pointless. However, this makes the behavior of our BMidiSynthFile a little different from what the BeBook says — as long as your applications are written properly, you shouldn't notice any differences.
In the course of writing the OpenBeOS Midi Kit, I spent some time looking at -how BeOS R5's libmidi2.so and midi_server communicate. Not out of a compulsion -to clone this protocol, but to learn from it. After all, the Be engineers spent -a lot of time thinking about this already, and it would be foolish not to build -on their experience. Here is what I have found out.
- -Two kinds of communication happen: administrative tasks and MIDI events. The -housekeeping stuff is done by sending BMessages between the BMidiRoster and the -midi_server. MIDI events are sent between producers and consumers using ports, -without intervention from the server.
- -This document describes the BMessage protocol. The protocol appears to be -asynchronous, which means that when BMidiRoster sends a message to the -midi_server, it does not wait around for a reply, even though the midi_server -replies to all messages. The libmidi2 functions do block until the reply -is received, though, so client code does not have to worry about any of -this.
- -Both BMidiRoster and the midi_server can initiate messages. BMidiRoster -typically sends a message when client code calls one of the functions from a -libmidi2 class. When the midi_server sends messages, it is to keep BMidiRoster -up-to-date about changes in the roster. BMidiRoster never replies to messages -from the server. The encoding of the BMessage 'what' codes indicates their -direction. The 'Mxxx' messages are sent from libmidi2 to the midi_server. The -'mXXX' messages go the other way around: from the server to a client.
- -The players here are the midi_server, which is a normal BApplication, and -all the client apps, also BApplications. The client apps have loaded a copy of -libmidi2 into their own address space. The main class from libmidi2 is -BMidiRoster. The BMidiRoster has a BLooper that communicates with the -midi_server's BLooper.
- -The midi_server keeps a list of all endpoints in the system, even -local, nonpublished, ones. Each BMidiRoster instance keeps its own list of -remote published endpoints, and all endpoints local to this application. It -does not know about remote endpoints that are not published yet.
- -Whenever you make a change to one of your own endpoints, your BMidiRoster -notifies the midi_server. If your endpoint is published, the midi_server then -notifies all of the other BMidiRosters, so they can update their local rosters. -It does not notify your own app! (Sometimes, however, the midi_server -also notifies everyone else even if your local endpoint is not -published. The reason for this escapes me, because the other BMidiRosters have -no access to those endpoints anyway.)
- -By the way, "notification" here means the internal communications between -server and libmidi, not the B_MIDI_EVENT messages you receive when you call -BMidiRoster::StartWatching().
- -The first time it is called, this function creates the one-and-only instance -of BMidiRoster. Even if you don't explicitly call it yourself, it is used -behind-the-scenes anyway by any of the other BMidiRoster functions. -MidiRoster() constructs a BLooper and gets it running. Then it sends a -BMessenger with the looper's address to the midi_server:
- --OUT BMessage: what = Mapp (0x4d617070, or 1298231408) - entry be:msngr, type='MSNG', c=1, size=24, -- -
The server now responds with mOBJ messages for all remote -published producers and consumers. (Obviously, this list only contains -remote objects because by now you can't have created any local endpoints -yet.)
- -For a consumer this message looks like:
- --IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '') - entry be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry be:port, type='LONG', c=1, size= 4, data[0]: 0x1dab (7595, '') - entry be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0" -- -
(Oddness: why is be:latency a LONG and not a LLNG? Since latency is -expressed in microseconds using a 64-bit bigtime_t, you'd expect the -midi_server to send all 64 of those bits... In the 'Mnew' message, on the other -hand, be:latency is a LLGN.)
- -And for a producer:
- --IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x2 (2, '') - entry be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0" -- -
Note that the be:name field is not present if the endpoint has no name. That -is, if the endpoint was constructed by passing a NULL name into the -BMidiLocalConsumer() or BMidiLocalProducer() constructor.
- -Next up are notifications for all connections, even those between -endpoints that are not registered:
- --IN BMessage: what = mCON (0x6d434f4e, or 1833127758) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '') -- -
These messages are followed by an Msyn message:
- --IN BMessage: what = Msyn (0x4d73796e, or 1299413358) -- -
And finally the (asynchronous) reply:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
Only after this reply is received, MidiRoster() returns.
- -The purpose of the Msyn message is not entirely clear. (Without it, Be's -libmidi2 blocks in the MidiRoster() call.) Does it signify the end of the list -of endpoints? Why doesn't libmidi2 simply wait for the final reply?
- -BMidiRoster, on behalf of the constructor, sends the following to the -midi_server:
- --OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567) - entry be:type, type='CSTR', c=1, size=9, data[0]: "producer" - entry be:name, type='CSTR', c=1, size=21, data[0]: "MIDI Keyboard output" -- -
The be:name field is optional.
- -The reply includes the ID for the new endpoint. This means that the -midi_server assigns the IDs, and any endpoint gets an ID whether it is -published or not.
- --IN BMessage: what = (0x0, or 0) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '') - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
Unlike many other Be API classes, BMidiLocalProducer and BMidiLocalConsumer -don't have an InitCheck() method. But under certain odd circumstances (such as -the midi_server not running), creating the endpoint might fail. How does client -code check for that? Well, it turns out that upon failure, the endpoint is -assigned ID 0, so you can check for that. In that case, the endpoint's refcount -is 0 and you should not Release() it. (That is stupid, actually, because -Release() is the only way that you can destroy the object. Our implementation -should bump the endpoint to 1 even on failure!)
- -If another app creates a new endpoint, your BMidiRoster is not notified. The -remote endpoint is not published yet, so your app is not supposed to see -it.
- -This is similar to the BMidiLocalProducer constructor, although the contents -of the message differ slightly. Again, be:name is optional.
- --OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567) - entry be:type, type='CSTR', c=1, size=9, data[0]: "consumer" - entry be:latency, type='LLNG', c=1, size= 8, data[0]: 0x0 (0, '') - entry be:port, type='LONG', c=1, size= 4, data[0]: 0x4c0 (1216, '') - entry be:name, type='CSTR', c=1, size=13, data[0]: "InternalMIDI" -- -
And the reply:
- --IN BMessage: what = (0x0, or 0) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '') - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
Before it sends the message to the server, the constructor creates a new -port with the name "MidiEventPort" and a queue length (capacity) of 1.
- -Sends the same message for producers and consumers:
- --OUT BMessage: what = Mreg (0x4d726567, or 1299342695) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') -- -
The reply:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
If you try to Register() an endpoint that is already registered, libmidi2 -still sends the message. (Which could mean that BMidiRoster does not keep track -of this registered state.) The midi_server simply ignores that request, and -sends back error code 0 (B_OK). So the API does not flag this as an error.
- -If you send an invalid be:id, the midi_server returns error code -1 (General -OS Error, B_ERROR). If you try to Register() a remote endpoint, libmidi2 -immediately returns error code -1, and does not send a message to the -server.
- -If another app Register()'s a producer, your BMidiRoster receives:
- --IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '') - entry be:name, type='CSTR', c=1, size=7, data[0]: "a name" -- -
If the other app registers a consumer, your BMidiRoster -receives:
- --IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x19 (25, '') - entry be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry be:port, type='LONG', c=1, size= 4, data[0]: 0xde9 (3561, '') - entry be:name, type='CSTR', c=1, size=7, data[0]: "a name" -- -
These are the same messages you get when your BMidiRoster instance is -constructed. In both messages, the be:name field is optional again.
- -If the other app Register()'s the endpoint more than once, you still get -only one notification. So the midi_server simply ignores that second publish -request.
- -Sends the same message for producers and consumers:
- --OUT BMessage: what = Munr (0x4d756e72, or 1299541618) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') -- -
The reply:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
If you try to Unregister() and endpoint that is already unregistered, -libmidi2 still sends the message. The midi_server simply ignores that request, -and sends back error code 0 (B_OK). So the API does not flag this as an error. -If you try to Unregister() a remote endpoint, libmidi2 immediately returns -error code -1, and does not send a message to the server.
- -When another app Unregister()'s one of its own endpoints, your BMidiRoster -receives:
- --IN BMessage: what = mDEL (0x6d44454c, or 1833190732) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '') -- -
When the other app deletes that endpoint (refcount is now 0) and it is not -unregistered yet, your BMidiRoster also receives that mDEL message. Multiple -Unregisters() are ignored again by the midi_server.
- -If an app quits without properly cleaning up, i.e. it does not Unregister() -and Release() its endpoints, then the midi_server's roster contains a stale -endpoint. As soon as the midi_server recognizes this (for example, when an -application tries to connect that endpoint), it sends all BMidiRosters an mDEL -message for this endpoint. (This message is sent whenever the midi_server feels -like it, so libmidi2 can receive this message while it is still waiting for a -reply to some other message.) If the stale endpoint is still on the roster and -you (re)start your app, then you receive an mOBJ message for this endpoint -during the startup handshake. A little later you will receive the mDEL.
- -Only sends a message if the refcount of local objects (published or not) -becomes 0:
- --OUT BMessage: what = Mdel (0x4d64656c, or 1298425196) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') -- -
The corresponding reply:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
If you did not Unregister() a published endpoint before you Release()'d it, -no 'Munr' message is sent. Of course, the midi_server is smart enough to -realize that this endpoint should be wiped from the roster now. Likewise, if -this endpoint is connected to another endpoint, Release() will not send a -separate 'Mdis' message, but the server will disconnect them. (This, of -course, only happens when you Release() local objects. Releasing a proxy has no -impact on the connection with the real endpoint.)
- -When you Release() a proxy (a remote endpoint) and its refcount becomes 0, -libmidi2 does not send an 'Mdel' message to the server. After all, the object -is not deleted, just your proxy. If the remote endpoint still exists (i.e. -IsValid() returns true), the BMidiRoster actually keeps a cached copy of the -proxy object around, just in case you need it again. This means you can do -this: endp = NextEndpoint(); endp->Release(); (now refcount is 0) endp- ->Acquire(); (now refcount is 1 again). But I advice against that since it -doesn't work for all objects; local and dead remote endpoints will be -deleted when their refcount reaches zero.
- -In Be's implementation, if you Release() a local endpoint that already has a -zero refcount, libmidi still sends out the 'Mdel' message. It also drops you -into the debugger. (I think it should return an error code instead, it already -has a status_t.) However, if you Release() proxies a few times too many, your -app does not jump into the debugger. (Again, I think the return result should -be an error code here -- for OpenBeOS R1 I think we should jump into the -debugger just like with local objects). Hmm, actually, whether you end up in -the debugger depends on the contents of memory after the object is deleted, -because you perform the extra Release() on a dead object. Don't do that.
- -For local endpoints, both unpublished and published, libmidi2 sends:
- --OUT BMessage: what = Mnam (0x4d6e616d, or 1299079533) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') - entry be:name, type='CSTR', c=1, size=7, data[0]: "b name" -- -
And receives:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
You cannot rename remote endpoints. If you try, libmidi2 will simply ignore -your request. It does not send a message to the midi_server.
- -If another application renames one of its own endpoints, all other -BMidiRosters receive:
- --IN BMessage: what = mREN (0x6d52454e, or 1834108238) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x5 (5, '') - entry be:name, type='CSTR', c=1, size=7, data[0]: "b name" -- -
You receive this message even if the other app did not publish its endpoint. -This seems rather strange, because your BMidiRoster has no knowledge of this -particular endpoint yet, so what is it to do with this message? Ignore it, I -guess.
- -For any kind of endpoint (local non-published, local published, -remote) libmidi2 sends the following message to the server:
- --OUT BMessage: what = Mgpr (0x4d677072, or 1298624626) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x2b2 (690, '') - entry be:props, type='MSGG', c=1, size= 0, -- -
(Why this "get properties" request includes a BMessage is a mistery to me. -The midi_server does not appear to copy its contents into the reply, which -would have made at least some sense. The BMessage from the client is completely -overwritten with the endpoint's properties.)
- --IN BMessage: what = (0x0, or 0) - entry be:props, type='MSGG', c=1, size= 0, - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
This means that endpoint properties are stored in the server only, not -inside the BMidiEndpoints, and not by the local BMidiRosters.
- -For local endpoints, published or not, libmidi2 sends the following message -to the server:
- --OUT BMessage: what = Mspr (0x4d737072, or 1299411058) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') - entry be:props, type='MSGG', c=1, size= 0, -- -
And expects this back:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
You cannot change the properties of remote endpoints. If you try, libmidi2 -will ignore your request. It does not send a message to the midi_server, and it -returns the -1 error code (B_ERROR).
- -If another application changes the properties of one of its own endpoints, -all other BMidiRosters receive:
- --IN BMessage: what = mPRP (0x6d505250, or 1833980496) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') - entry be:properties, type='MSGG', c=1, size= 0, -- -
You receive this message even if the other app did not publish its -endpoint.
- -For local endpoints, published or not, libmidi2 sends the following message -to the server:
- --OUT BMessage: what = Mlat (0x4d6c6174, or 1298948468) - entry be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '') - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x14f (335, '') -- -
And receives:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
If another application changes the latency of one of its own consumers, all -other BMidiRosters receive:
- --IN BMessage: what = mLAT (0x6d4c4154, or 1833714004) - entry be:id, type='LONG', c=1, size= 4, data[0]: 0x15 (21, '') - entry be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '') -- -
You receive this message even if the other app did not publish its -endpoint.
- -The message:
- --OUT BMessage: what = Mcon (0x4d636f6e, or 1298362222) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x376 (886, '') -- -
The answer:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
The server sends back a B_ERROR result if you specify wrong ID's. When you -try to connect a producer and consumer that are already connected to each -other, libmidi2 still sends the 'Mcon' message to the server (even though it -could have known these endpoints are already connected). In that case, the -server responds with a B_ERROR code as well.
- -When another app makes the connection, your BMidiRoster receives:
- --IN BMessage: what = mCON (0x6d434f4e, or 1833127758) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '') -- -
Note: your BMidiRoster receives this notification even if the producer or -the consumer (or both) are not registered endpoints.
- -The message:
- --OUT BMessage: what = Mdis (0x4d646973, or 1298426227) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x309 (777, '') - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x393 (915, '') -- -
The answer:
- --IN BMessage: what = (0x0, or 0) - entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') - entry _previous_, ... -- -
The server sends back a B_ERROR result if you specify wrong ID's. When you -try to disconnect a producer and consumer that are not connected to each other, -libmidi2 still sends the 'Mdis' message to the server (even though it could -have known these endpoints are not connected). In that case, the server -responds with a B_ERROR code as well.
- -When another app breaks the connection, your BMidiRoster receives:
- --IN BMessage: what = mDIS (0x6d444953, or 1833191763) - entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') - entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '') -- -
Note: your BMidiRoster receives this notification even if the producer or -the consumer (or both) are not registered endpoints.
- -BMidiRoster::StartWatching() and StopWatching() do not send messages to the -midi_server. This means that the BMidiRoster itself, and not the midi_server, -sends the notifications to the messenger. It does this whenever it receives a -message from the midi_server.
- -The relationship between midi_server messages and B_MIDI_EVENT notifications -is as follows:
- --- --
-- message notification - mOBJ B_MIDI_REGISTERED - mDEL B_MIDI_UNREGISTERED - mCON B_MIDI_CONNECTED - mDIS B_MIDI_DISCONNECTED - mREN B_MIDI_CHANGED_NAME - mLAT B_MIDI_CHANGED_LATENCY - mPRP B_MIDI_CHANGED_PROPERTIES
For each message on the left, the watcher will receive the corresponding -notification on the right.
- -Operations that do not send messages to the midi_server:
- -BMidiEndpoint::Acquire(). This means reference counting is done locally -by BMidiRoster. Release() doesn't send a message either, unless the refcount -becomes 0 and the object is deleted. (Which suggests that it is actually the -destructor and not Release() that sends the message.)
BMidiRoster::NextEndpoint(), NextProducer(), NextConsumer(), -FindEndpoint(), FindProducer(), FindConsumer(). None of these functions send -messages to the midi_server. This means that each BMidiRoster instance keeps -its own list of available endpoints. This is why it receives 'mOBJ' messages -during the startup handshake, and whenever a new remote endpoint is registered, -and 'mDEL' messages for every endpoint that disappears. Even though the -NextXXX() functions do not return locally created objects, this "local roster" -does keep track of them, since FindXXX() do return local -endpoints.
BMidiEndpoint::Name(), ID(), IsProducer(), IsConsumer(), IsRemote(), -IsLocal() IsPersistent(). BMidiConsumer::Latency(). -BMidiLocalConsumer::GetProducerID(), SetTimeout(). These all appear to consult -BMidiRoster's local roster.
BMidiEndpoint::IsValid(). This function simply looks at BMidiRoster's -local roster to see whether the remote endpoint is still visible, i.e. not -unregistered. It does not determine whether the endpoint's application is still -alive, or "ping" the endpoint or anything fancy like that.
BMidiProducer::IsConnected(), Connections(). This means that -BMidiRoster's local roster, or maybe the BMidiProducers themselves (including -the proxies) keep track of the various connections.
BMidiLocalProducer::Connected(), Disconnected(). These methods are -invoked when any app (including your own) makes or breaks a connection on one -of your local producers. These hooks are invoked before the B_MIDI_EVENT -messages are sent to any watchers.
Quitting your app. Even though the BMidiRoster instance is deleted when -the app quits, it does not let the midi_server know that the application in -question is now gone. Any endpoints you have registered are not automatically -unregistered. This means that the midi_server is left with some stale -information. Undoubtedly, there is a mechanism in place to clean this up. The -same mechanism would be used to clean up apps that did not exit cleanly, or -that crashed.
Other stuff:
- -libmidi2.so exports an int32 symbol called "midi_debug_level". If you -set it to a non-zero value, libmidi2 will dump a lot of interesting debug info -on stdout. To do this, declare the variable in your app with "extern int32 -midi_debug_level;", and then set it to some high value later: "midi_debug_level -= 0x7FFFFFFF;" Now run your app from a Terminal and watch libmidi2 do its -thing.
libmidi2.so also exports an int32 symbol called -"midi_dispatcher_priority". This is the runtime priority of the thread that -fields MIDI events to consumers.
MPU401 kernel module. If your soundcard supports MIDI input and -output, chances are that it is powered by an MPU401 chip. Because this -interface is so popular, BeOS comes with a kernel module that makes it easy to -write drivers for the MPU401. Thanks to Greg Crain, we now have an open source -version of this kernel module.
- -The mpu401 module lives in src/add-ons/kernel/generic/mpu401.
-It supports both the v1 and (undocumented) v2 protocols, although v2 is not
-complete since we don't really know how it works. Unfortunately, almost no
-existing drivers use v1; most of the drivers provided by Be require v2.
-Currently, the module returns B_ERROR when a MIDI device is opened with
-v2.
For an example on how to use the MPU401 module in your own driver, see -the source code for the "emuxki" driver elsewhere in the source tree.
Clients without a BApplication. Sometimes the midi_server's -debug output shows an "Application -1 not registered" error message. This -means it cannot figure out which app an incoming BMessage came from. The -server ignores those messages.
- -How can this happen? libmidi2 has two ways of sending messages to the -midi_server: it either expects a reply back or not. In the first case, it is -obvious to the midi_server what the reply address of the message is. In the -second case, even though it is not necessary for the server to send a message -back, it still uses the reply address to determine which app the message came -from. For this, BMessenger uses be_app_messenger of the client app.
- -However, if the client app has no BApplication object, there is no -be_app_messenger either. Now, the midi_server cannot determine where the -message came from and will ignore it. Is this important? For example, when such -a client app Release()'s its endpoints, it sends a message to the server -without a return address. Now the server ignores that message and does not -remove the endpoint from the roster. Of course, after the client app has died, -the endpoints will be removed eventually. Does all of this matter? Not really, -because only trivial apps will have no BApplication object.
Most of the OpenBeOS source code has unit tests in the current/src/tests -directory. I looked into building CppUnit tests for the midi2 kit, but decided -that it doesn't really make much sense. Unit tests work best if you can test -something in isolation, but in the case of the midi2 kit this is very hard to -achieve. Because the classes from libmidi2.so always need to talk to the -midi_server, the tests depend on too many external factors. The available -endpoints, for example, will differ from system to system. The spray and hook -functions are difficult to test this way, too.
- -So instead of a CppUnit test suite, here is a list of manual tests that I -performed when developing the midi2 kit:
- -Required: Client app that calls BMidiRoster::MidiRoster()
- -When a client app starts, it should first receive mNEW notifications for -all endpoints in the system (even unregistered remotes), followed by mCON -notifications for all connections in the system (even those between two -unregistered local endpoints from another app).
Send invalid Mapp message (without messenger). The midi_server ignores -the request, and the client app blocks forever.
Fake a delivery error for the mNEW notifications and the mAPP reply. -(Add a snooze() in the midi_server's OnRegisterApplication(). While it is -snoozing, Ctrl-C the client app. Now the server can't deliver the message and -will unregister the application again.)
Kill the server. Start the client app. It should realize that the server -is not running, and return from MidiRoster(); it does not block -forever.
Note: The server does not protect against sending two or more Mapp -messages; it will add a new app_t object to the roster and it will also send -out the mNEW and mCON notifications again.
Verify that when the client app quits, the BMidiRoster instance is -destroyed by the BMidiRosterKiller. The BMidiRosterLooper is also destroyed, -along with any endpoint objects from its list. We don't destroy endpoints with -a refcount > 0, but print a warning message on stderr instead.
When the app quits before it has created a BMidiRoster instance, the -BMidiRosterKiller should do nothing.
Required: Client app that creates a new BMidiLocalProducer and/or -BMidiLocalConsumer
- -Send invalid Mnew message (missing fields). The server will return an -error code.
Don't send reply from midi_server. The client receives a B_NO_REPLY -error.
If something goes wrong creating a new local endpoint, you still get a -new BMidiEndpoint object (but it is not added to BMidiRosterLooper's internal -list of endpoints). Verify that its ID() function returns 0, and IsValid() -returns false. Verify that you can Release() it without crashing into the -debugger (i.e. the reference count of the new object should be 1).
Snooze in midi_server's OnCreateEndpoint() before sending reply to -client to simulate heavy processor load. Client should timeout. When done -snoozing, server fails to deliver the reply because the client is no longer -listening, and it unregisters the app.
Note: if you kill the client app with Ctrl-C before the server has sent -its reply, SendReply() still returns okay, and the midi_server adds the -endpoint, even though the corresponding app is dead. There is not much we can -do to prevent that (but it is not really a big deal).
Start the test app from two different Terminals. Verify that the new -local endpoint of app1 is added to the BMidiRosterLooper's list of endpoints, -and that its "isLocal" flag is true. Verify that when you start the second app, -it immediately receives mNEW notifications for the first app's endpoints. It -should also create BMidiEndpoint proxy objects for these endpoints with -"isLocal" set to false, and add them its own list. Vice versa for the endpoints -that app2 creates. Verify that the "registered" field in the mNEW notification -is false, because newly created endpoints are not registered yet. The -"properties" field should contain an empty message.
Start server. Start client app. The app makes new endpoints and the -server adds them to the roster. Ctrl-C the app. Start client app again. The new -client first receives mNEW notifications for the old app's endpoints. When the -new app tries to create its own endpoints, the server realizes that the old app -is dead, and sends mDEL notifications for the now-defunct endpoints.
The test app should now create 2 endpoints. Let the midi_server snooze -during the second create message, so the app times out. The server now -unregisters the app and purges its first endpoint (which was successfully -created).
The test app should now create 3 endpoints. Let the midi_server snooze -during the second create message, so the app times out. (It also times out when -sending the create request for the 3rd endpoint, because the server is still -snoozing.) Because it cannot send a reply for the 2nd create message, the -server now unregisters the app and purges its first endpoint (which was -successfully created). Then it processes the create request for the 3rd -endpoint, but ignores it because the app is now no longer registered with the -server.
Purging endpoints. The test app should now create 2 endpoints. Let the -midi_server snooze during the _fourth_ create message. Run the server. Run the -test app. Run the test app again in a second Terminal. The server times out, -and unregisters the second app. The first app should receive an mDEL -notification. Repeat, but now the test app should make 3 endpoints and the -server fails on the _sixth_ endpoint. The first app now receives 2 mDEL -notifications.
You should be allowed to pass NULL into the BMidiLocalProducer and -BMidiLocalConsumer constructor.
Let the midi_server assign random IDs to new endpoints; the -BMidiRosterLooper should sort the endpoints by their IDs when it adds them to -its internal list.
Required: client app that creates one or more endpoints and -Release()'s them
- -Verify that Acquire() increments the endpoint's refcount and Release() -decrements it. When you Release() a local endpoint so its refcount becomes -zero, the client sends an Mdel request to the server. When you Release() a -local endpoint too many times, your app jumps into the debugger.
Send an Mdel request with an invalid ID to the server. Examples of -invalid IDs: -1, 0, 1000 (or any other large number).
Start the test app from two different Terminals. Note that when one of -the apps Release()'s its endpoints, the other receives corresponding mDEL -notifications.
Snooze in midi_server's OnCreateEndpoint() before sending reply to -"create endpoint" request. The client will timeout and the server will -unregister the app. Now have the client Release() the endpoint. This sends a -"delete endpoint" request to the server, which ignores the request because the -app is no longer registered.
Override BMidiLocalProducer and BMidiLocalConsumer, and provide a public -destructor. Call "delete prod; delete cons;" from your code, instead of using -Release(). Your app should drop into the debugger.
Start the client app and let it make its endpoints. Kill the server. -Release() the endpoints. The server doesn't run, so the Mdel request never -arrives, but the BMidiEndpoint objects should be deleted regardless.
Start the test app from two different Terminals, and let them make their -endpoints. Quit the apps (using the Deskbar's "Quit Application" menu item). -Verify that both clean up and exit correctly. App1 removes its own endpoint -from the BMidiRosterLooper's list of endpoints and sends an 'mDEL' message to -the server, which passes it on to app2. In response, app2 removes the proxy -object from its own list and deletes it. Again, vice versa for the endpoint -from app2.
Start both apps again and wait until they have notified each other about -the endpoints. Ctrl-C app1, and restart it. Verify that app1 receives the -'mNEW' messages and creates proxies for these remote endpoints. Both apps -should receive an 'mDEL' message for app1's old endpoint (because the -midi_server realizes it no longer exists and purges it), and remove it from -their lists accordingly.
Required: Client app that creates an endpoint and calls Register(), -Unregister(), SetName(), and SetLatency()
- -Send an Mchg request with an invalid ID to the server.
Register() a local endpoint that is already registered. This does not -send a message to the server and always returns B_OK. Likewise for -Unregister()ing a local endpoint that is not registered.
Register() or Unregister() a remote endpoint, or an invalid local -endpoint. That should immediately return an error code.
Verify that BMidiRoster::Register() does the same thing as -BMidiEndpoint::Register(). Also for BMidiRoster::Unregister() and -BMidiEndpoint::Unregister().
If you pass NULL into BMidiRoster::Register() or Unregister(), the -functions immediately return with an error code.
SetName() should ignore NULL names. When you call it on a remote -endpoint, SetName() should do nothing. SetName() does not send a message if the -new name is the same as the current name.
SetLatency() should ignore negative values. SetLatency() does not send a -message if the new latency is the same as the current latency. (Since -SetLatency() lives in BMidiLocalConsumer, you can never use it on remote -endpoints.)
Kill the server after making the new endpoint, and call Register(). The -client app should return an error code. Also for Unregister(), SetName(), -SetLatency(), and SetProperties().
Snooze in the midi_server's OnChangeEndpoint() before sending the reply -to the client. Both sides will flag an error. No mCHG notifications will be -sent. The server unregisters the app and purges its endpoints.
Verify that other apps will receive mCHG notifications when the test app -successfully calls Register(), Unregister(), SetName(), and SetLatency(), and -that they modify the corresponding BMidiEndpoint objects accordingly. Since -clients are never notified when they change their own endpoints, they should -ignore the notifications that concern local endpoints. Latency changes should -be ignored if the endpoint is not a consumer.
Send an Mchg request with only the "midi:id" field, so no "midi:name", -"midi:registered", "midi:latency", or "midi:properties". The server will still -notify the other apps, although they will obviously ignore the notification, -because it doesn't contain any useful data.
The Mchg request is overloaded to change several attributes. Verify that -changing one of these attributes, such as the latency, does not overwrite/wipe -out the others.
Start app1. Wait until it has created and registered its endpoint. Start -app2. During the initial handshake, app2 should receive an 'mNEW' message for -app1's endpoint. Verify that the "refistered" field in this message is already -true, and that this is passed on correctly to the new BMidiEndpoint proxy -object.
GetProperties() should return NULL if the message parameter is -NULL.
The properties of new endpoints are empty. Create a new endpoint and -call GetProperties(). The BMessage that you receive should contain no -fields.
SetProperties() should return NULL if the message parameter is NULL. It -should return an error code if the endpoint is remote or invalid. It should -work fine on local endpoints, registered or not. SetProperties() does not -compare the contents of the new BMessage to the old, so it will always send out -the change request.
If you Unregister() an endpoint that is connected, the connection should -not be broken.
Required: Client app that creates several endpoints, and registers -some of them (not all), and uses the BMidiRoster::FindEndpoint() etc functions -to examine the roster.
- -Verify that FindEndpoint() returns NULL if you pass it:
- -Verify that FindEndpoint() returns a valid BMidiEndpoint object if you pass -it:
- -Verify that FindConsumer() works just like FindEndpoint(), but that it -also returns NULL if the endpoint with the specified ID is not a consumer. -Likewise for FindProducer().
Verify that NextEndpoint() returns NULL if you pass it NULL. It also -returns NULL if no more endpoints exist. Otherwise, it returns a BMidiEndpoint -object, bumps the endpoint's reference count, and sets the "id" parameter to -the ID of the endpoint. NextEndpoint() should never return local endpoints -(registered or not), nor unregistered remote endpoints. Verify that negative -"id" values also work.
Verify that you can safely call the Find and Next functions without -having somehow initialized the BMidiRoster first (by making a new endpoint, for -example). The functions themselves should call MidiRoster() and do the -handshake with the server.
The Find and Next functions should bump the reference count of the -BMidiEndpoint object that they return. However, they should not (inadvertently) -modify the refcounts of any other endpoint objects.
Get a BMidiEndpoint proxy for a remote published endpoint. Release(). -Now it should not be removed from the endpoint list or even be deleted, even -though its reference count dropped to zero.
Start app1. Start app2. App2 gets a BMidiEndpoint proxy for a remote -endpoint from app1. Ctrl-C app1. Start app1 again. Now app2 receives an mDEL -message for app1's old endpoint. Verify that the endpoint is removed from the -endpoint list, but not deleted because its reference count isn't zero. If app2 -now Release()s the endpoint, the BMidiEndpoint object should be deleted. Try -again, but now Release() the endpoint before you Ctrl-C; now it should be -deleted and removed from the list when you start app1 again.
Required: Client app that creates a producer and consumer endpoint, -optionally registers them, consults the roster for remote endpoints, and makes -various kinds of connections.
- -Test the following for BMidiProducer::Connect():
- -Test the following for BMidiProducer::Disconnect():
- -Make a connection on a local producer. Release() the producer. The other -app should only receive an mDEL notification. Likewise if you have a connection -with a local consumer and you Release() that. However, now all apps should -throw away this consumer from the connection lists, invoking the Disconnected() -hook of local producers. The same thing happens if you Ctrl-C the app and -restart it. (Now the old endpoints are purged.)
BMidiProducer::IsConnected() should return false if you pass NULL or an -invalid consumer.
BMidiProducer::Connections() should return a new BList every time you -call it. The objects in this list are the BMidiConsumers that are connected to -this producer; verify that their reference counts are bumped for every call to -Connections().
Required: Client app that creates local consumer and producer -endpoints, and calls Register(), Unregister(), SetName(), SetLatency(), and -SetProperties(). It should also make and break connections.
- -When you call StartWatching(), you should receive B_MIDI_EVENT -notifications for all remote registered endpoints and the connections between -them. You will get no notifications for local endpoints, or for any connections -that involve unregistered endpoints. The BMidiRosterLooper should make a copy -of the BMessenger, so when the client destroys the original messenger, you will -still receive notifications. Verify that calling StartWatching() with the same -BMessenger twice in a row will also send the initial set of notifications -twice. StartWatching(NULL) should be ignored and does not remove the current -messenger.
Run the client app from two different Terminals. Verify that you receive -properly formatted B_MIDI_EVENT notifications when the other app changes the -attributes of its registered endpoints with the various Set() functions. -You should also receive notifications if the app Register()s or Unregister()s -its endpoints. That app that makes these changes does not receive the -notifications.
Run the client app from two different Terminals. Verify that you receive -properly formatted B_MIDI_EVENT notifications when the apps make and break -connections. Every app receives these connection notifications, whether the -endpoints are published or not. The app that makes and breaks the connections -does not receive any notifications.
StopWatching() should delete BMidiRosterLooper's BMessenger copy, if -any. Verify that you no longer receive B_MIDI_EVENT notifications for remote -endpoints after you have called StopWatching().
If the client is watching, and the BMidiRosterLooper receives an mDEL -notification for a registered remote endpoint, it should also send an -"unregistered" B_MIDI_EVENT to let the client know that this endpoint is no -longer available. If the endpoint was connected to anything, you'll also -receive "disconnected" B_MIDI_EVENTs.
If you get a "registered" event, and you do FindEndpoint() for that id, -you'll get its BMidiEndpoint object. If you get an "unregistered" event, then -FindEndpoint() returns NULL. So the events are send after the roster is -modified.
Required: Several client apps that create and register consumer -endpoints that override the various MIDI event hook functions, as well as -producer endpoints that spray MIDI events. Also useful is a tool that lets you -make connections between all these endpoints (PatchBay), and a tool that lets -you monitor the MIDI events (MidiMonitor).
- -BMidiLocalProducer's spray functions should only try to send something -if there is one or more connected consumer. If the spray functions cannot -deliver their events, they simply ignore that consumer until the next spray. -(No connections are broken or anything.)
All spray functions except SprayData() should set the atomic flag to -true, even SpraySystemExclusive().
When you send a sysex message using SpraySystemExclusive(), it should -add 0xF0 in front of your data and 0xF7 at the back. When you call SprayData() -instead, no bytes are added to the MIDI event data.
Verify that all events arrive correctly and that the latency is minimal, -even when the load is heavy (i.e. many events are being sprayed to many -different consumers).
Verify that the BMidiLocalConsumer destructor properly destroys the -corresponding port and event thread before it returns.
BMidiLocalConsumer should ignore messages that are too small, addressed -to another consumer, or otherwise invalid.
BMidiLocalConsumer's Data() hook should ignore all non-atomic events. -The rest of the events, provided they contain the correct number of bytes for -that kind of event, are passed on to the other hooks.
Hook a producer up to a consumer and call all SprayXXX() functions with -a variety of arguments to make sure the correct hooks are being called with the -correct values. Call SprayData() and SpraySystemExclusive() with NULL data -and/or length 0.
Call GetProducerID() from one of BMidiLocalConsumer's hooks to verify -that this indeed returns the ID of the producer that sprayed the -event.
To test timeouts, first call SetTimeout(system_time() + 2000000), spray -an event to the consumer, and wait 2 seconds. The consumer's Timeout() hook -should now be called. Try again, but now spray multiple events to the consumer. -The Timeout() hook should still be called after 2 seconds, measured from the -moment the timeout was set. Replace the call to SetTimeout() with -SetTimeout(0). After spraying the first event, you should immediately get the -Timeout() signal, because the target time was set in the past. Verify that -calling SetTimeout() only takes effect after at least one new event has been -received.
Kill the server. Now run a client app. It should recognize that the -server isn't running, and return error codes on all operations. Also kill the -server while the test app is running. From then on, the client app will return -error codes on all operations. Also bring it back up again while the test app -is still running. Now the client app's request messages will be delivered to -the server again, but the server will ignore them, because our app did not -register with this new instance of the server.
Start the midi_server and several client apps. Use PatchBay to make and -break a whole bunch of connections. Quit PatchBay. Start it again. Now the same -connections should show up. Run similar tests with MidiKeyboard. Also install -VirtualMidi (and run the old midi_server for the time being) to get a whole -bunch of fake MIDI devices.
Regression bug: After you quit one client app, another app fails -to send request to the midi_server.
- -Required: Client app that creates a new endpoint and registers it. In -the app's destructor, it unregisters and releases the endpoint.
- -How to reproduce: Run the app from two different Terminals. Ctrl-C -app1. Start app1 again. From the Deskbar quit both apps at the same time (that -is possible because app1 and app2 both have the same signature). When it tries -to send the Unregister() request to the midi_server, app2 gives the error -"Cannot send msg to server". The error code is "Bad Port ID", which means that -the reply port is dead. The Mdel message from Release() is sent without any -problems, however, because that expects no reply back. This is not the only way -to reproduce the problem, but it seems to be the most reliable one.
- -The reason this happens is because you kill app1. When app2 sends a -synchronous request to the midi_server, the server re-used that same message to -notify the other apps. (Because it already contained all the necessary fields.) -But app1 is dead, the notification fails, and this (probably) wipes out the -reply address in the message. I changed the midi_server to create new BMessages -for the notifications, and was no longer able to reproduce the -problem.
May 14, 2004
- -Softsynth. We need a General MIDI softsynth. We can either write it ourselves or port an existing one. I was thinking about FluidSynth (formerly IIWU Synth) since it is very good and supports SoundFonts, but I had trouble writing a BeOS audio driver for it. FluidSynth is also GPL, but that is not a major problem. Must be implemented in the BSoftSynth class from libmidi.so
- -Test libmidi.so The BMidiSynth, BMidiSynthFile, BSamples, and BSynth classes have been implemented and briefly tested. They seemed to work fine, even with the R5 MidiPlayer app. However, the only proper way to test them is with sound output, and for that we need the softsynth.
- -Communicating with device drivers. The midi_server already has a pretty good parser that turns an incoming stream of bytes into MIDI messages. It uses read() to read a single byte at a time. However, the midi_driver.h file lists a number of ioctl() opcodes that we are currently not using. Should we? In addition, do we really need to spawn a new thread for each device? The R5 midi_server doesn't appear to do this. An optional feature is to implement "running status" for MIDI OUT ports (i.e. when writing to the device driver). This would be pretty simple to add.
- -BMidiStore is slow. Importing a Standard MIDI File of a few hundred kilobytes takes too long for my taste. The one from R5 is at least twice as fast. It is important to speed this up since BMidiStore is used by BMidiSynthFile to play MIDI files. We don't want games to slow down too much.
- -MPU401 kernel module. Greg Crain did a great job of writing this module. Unfortunately, we only know how the v1 interface works; v2 is not documented. What's worse, most Be R5 drivers use v2. Currently, the module returns B_ERROR when a device is opened with v2. Is this going to be a problem for us? It depends on whether we will be able to use the closed-source Be drivers with our own kernel — if not, then we can simply ignore v2.
- -BSynth::GetAudio() This function fills up a user-provided buffer with recent sample data. Mostly used to display scopes and other visual trickery. Whether we will support this or not depends on the capabilities of the softsynth back-end.
- -Watching /dev/midi for changes. Whenever a new device appears in /dev/midi, the midi_server must create and publish a new MidiProducer and MidiConsumer for that device. When a device disappears, its endpoints must be removed again. Philippe Houdoin suggested we use the device_watcher for this, but R5 doesn't appear to do it that way. Either it uses node monitoring or doesn't do this at all. Our midi_server already has a DeviceWatcher class, but it only examines the entries from /dev/midi when the server starts, not while the server is running.
- -BMidiSynthFile::Fade() Right now this simply calls Stop(). We could set a flag in BMidiStore (which handles our playback), which would then slowly reduce the volume and abort the loop after a few seconds. But we need to have the softsynth in order to tune this properly.
- -Must be_synth be deleted when the app quits? I have not found a word about this, nor a way to test what happens in R5. For example, the BMidiSynth constructor creates a BSynth object (if none already existed), but we cannot destroy be_synth from the BMidiSynth destructor because it may still be used in other places in the code (BSynth is not refcounted). We could add the following code to libmidi.so to clean up properly, but I don't know if it is really necessary:
- -namespace BPrivate
-{
- static struct BSynthKiller
- {
- ~BSynthKiller()
- {
- delete be_synth;
- }
- }
- synth_killer;
-}
-
-midiparser kernel module. midi_driver.h (from the Sonic Vibes driver sample code) contains the definition of a "midiparser" kernel module. This is a very simple module that makes it easy to recognize where MIDI messages begin and end, but apparently doesn't tell you what they mean. In R5, this module lives in /boot/beos/system/add-ons/kernel/media. Does anyone use this module? Is it necessary for us to provide it? Personally, I'd say foggeddaboutit.
- - - diff --git a/docs/develop/midi/todo.rst b/docs/develop/midi/todo.rst new file mode 100644 index 0000000000..e7632f3339 --- /dev/null +++ b/docs/develop/midi/todo.rst @@ -0,0 +1,70 @@ +Midi Kit TO DO List +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Communicating with device drivers.** The midi_server already has a +pretty good parser that turns an incoming stream of bytes into MIDI +messages. It uses read() to read a single byte at a time. However, the +midi_driver.h file lists a number of ioctl() opcodes that we are +currently not using. Should we? In addition, do we really need to spawn +a new thread for each device? The R5 midi_server doesn't appear to do +this. An optional feature is to implement "running status" for MIDI OUT +ports (i.e. when writing to the device driver). This would be pretty +simple to add. + +**BMidiStore is slow.** Importing a Standard MIDI File of a few hundred +kilobytes takes too long for my taste. The one from R5 is at least twice +as fast. It is important to speed this up since BMidiStore is used by +BMidiSynthFile to play MIDI files. We don't want games to slow down too +much. + +**MPU401 kernel module.** Greg Crain did a great job of writing this +module. Unfortunately, we only know how the v1 interface works; v2 is +not documented. What's worse, most Be R5 drivers use v2. Currently, the +module returns B_ERROR when a device is opened with v2. Is this going to +be a problem for us? It depends on whether we will be able to use the +closed-source Be drivers with our own kernel — if not, then we can +simply ignore v2. + +**Watching /dev/midi for changes.** Whenever a new device appears in +/dev/midi, the midi_server must create and publish a new MidiProducer +and MidiConsumer for that device. When a device disappears, its +endpoints must be removed again. Philippe Houdoin suggested we use the +device_watcher for this, but R5 doesn't appear to do it that way. Either +it uses node monitoring or doesn't do this at all. Our midi_server +already has a DeviceWatcher class, but it only examines the entries from +/dev/midi when the server starts, not while the server is running. + +**BMidiSynthFile::Fade()** Right now this simply calls Stop(). We could +set a flag in BMidiStore (which handles our playback), which would then +slowly reduce the volume and abort the loop after a few seconds. But we +need to have the softsynth in order to tune this properly. + +**Must be_synth be deleted when the app quits?** I have not found a word +about this, nor a way to test what happens in R5. For example, the +BMidiSynth constructor creates a BSynth object (if none already +existed), but we cannot destroy be_synth from the BMidiSynth destructor +because it may still be used in other places in the code (BSynth is not +refcounted). We could add the following code to libmidi.so to clean up +properly, but I don't know if it is really necessary: + + :: + + namespace BPrivate + { + static struct BSynthKiller + { + ~BSynthKiller() + { + delete be_synth; + } + } + synth_killer; + } + +**midiparser kernel module.** midi_driver.h (from the Sonic Vibes driver +sample code) contains the definition of a "midiparser" kernel module. +This is a very simple module that makes it easy to recognize where MIDI +messages begin and end, but apparently doesn't tell you what they mean. +In R5, this module lives in /boot/beos/system/add-ons/kernel/media. Does +anyone use this module? Is it necessary for us to provide it? +Personally, I'd say foggeddaboutit. diff --git a/docs/develop/net/HowTo-Synchronize_with_NetBSD.md b/docs/develop/net/HowTo-Synchronize_with_NetBSD.md deleted file mode 100644 index b452663ba2..0000000000 --- a/docs/develop/net/HowTo-Synchronize_with_NetBSD.md +++ /dev/null @@ -1,30 +0,0 @@ -How to Merge Patches from NetBSD Trunk -============================================ -Using the NetBSD CVS is a pain, so instead, the preferred thing to do is to use -[the official Git mirror](https://github.com/NetBSD/src). The code here is -in the tree at a few places:`inet` is at `lib/libc/inet`, irs is scattered -across the tree, and `resolv` is at `lib/libc/resolv`. - -The preferable way to merge is to take the last commit merged from IIJ's mirror -(can be found in the merging commit in Haiku, if the merger has done their work -properly) and check all commits since then to see if they apply or not (some -apply to documentation we don't have, etc.) Cherry-pick the ones that do, and -download them as git-format-patch patches (by adding `.patch` onto the end of the -commit URL). - -To convert the patches to have the correct paths to the resolv/inet/etc. code, use -`sed`: -``` -sed s%lib/libc/resolv%src/kits/network/netresolv/resolv%g -i *.patch -``` -(You'll need to use similar commands for the `inet` and `irs` code.) - -Then apply the patches using `git apply --reject file.patch`. Git will spew a lot of -errors about files in the patch that aren't in the tree, and then it will warn that -some hunks are being rejected. Review the rejected hunks **VERY CAREFULLY**, as -some code in Haiku's NetResolv is not in NetBSD's and vice versa, and so some patches -may not apply cleanly because of that. You might have to resort to merging those -hunks by hand, if they apply at all to Haiku's code. - -Commit the changes all at once, but list all the commits merged from NetBSD -in the commit message (see previous merges for the style to follow). diff --git a/docs/develop/net/HowTo-Synchronize_with_NetBSD.rst b/docs/develop/net/HowTo-Synchronize_with_NetBSD.rst new file mode 100644 index 0000000000..1f016fd5e1 --- /dev/null +++ b/docs/develop/net/HowTo-Synchronize_with_NetBSD.rst @@ -0,0 +1,36 @@ +How to Merge Patches from NetBSD Trunk +====================================== + +Using the NetBSD CVS is a pain, so instead, the preferred thing to do is +to use `the official Git mirror- The Haiku Network Stack is a modular and layered networking stack, very - similar to what you may know as BONE. -
-- The entry point when talking to the stack is through a dedicated device - driver that publish itself in /dev/net. The userland library libnetwork.so - (which combines libsocket.so, and libbind.so) directly talks to this - driver, mostly via ioctl()1. -
- The driver either creates sockets, or passes on every command to the socket - module2. Depending on the address family and - type of the sockets, the lower layers will be loaded and connected. - -- For example, with a TCP/IP socket, the stack could look like this: -
| Socket | |
| TCP | -Protocols |
-
| IPv4 | |
| Datalink | |
| ARP | -Datalink Protocols |
-
| Ethernet framing | |
| Ethernet device | (physical layer) |
- When sending data through a socket, a net_buffer is created in the socket module, and passed - on to the lower levels where each protocol processes it, before passing it on to the next - protocol in the chain. The last protocol in the chain is always a domain protocol - it will - directly forward the buffers to the datalink module. When the buffer reaches the datalink - level, an accompanied net_route object will determine for which interface (which determines - the datalink protocols in the chain) the buffer is destined. The route has to be specified - by the upper protocols before the buffer gets into the datalink level - if a buffer comes - in without a valid route, it is discarded. -
-- The protocol modules are loaded and unloaded as needed. The stack itself stays loaded - as long as there are interfaces defined - as soon as the last interface is removed, - the stack gets unloaded (which is, of course, not yet implemented). -
-- Every supported address family gets its own domain. A domain comprises such a family, - a net_protocol module that handles this domain, and a list of interfaces and routes. - It also gets a name: for example, the IPv4 module registers the "internet" domain - (AF_INET). -
-- The domain protocol module is responsible for managing the domain; it has to register - it when it's loaded, and it has to unregister it when it is unloaded by the networking - stack. -
-- An interface makes an underlying net_device accessible by the stack. When creating - a new interface, you have to specify a domain, and a device to be used. The stack - will then look through the registered datalink protocols, and builds a chain of - them for that interface. -
-- The interface usually gets a network address, and a route that directs buffers to - be sent to it. If there is no route to an interface, it will never be used for - outgoing data, but may well receive data from other hosts. -
-
- An interface can be "up" (when IFF_UP is set in its flags
- member) in which case it accepts data - when that flag is not set, it will discard
- all data it gets. The interface also specifies the maximum buffer size that can be
- sent over this interface (the mtu member, a.k.a. maximum transmission
- unit).
-
- Interfaces are configured via ioctl()s (SIOCAIFADDR, ...). You can use the command - line tool "ifconfig" to do this for you. -
-- A networking device is used to actually send and receive the buffers. It either points - to an actual hardware device (in case of ethernet), or to a virtual device (in case of - loopback). Every device has a unique name that identifies it. When creating a device, - the name also decides which net_device module will be chosen; for example, everything - that starts with "loop" will end up in the loopback device, while the ethernet device - accepts names that start with "/dev/net/". -
-
- A device can be shared by many interfaces at the same time. The device to be used by
- an interface is specified at the time an interface is created.
- It also has an mtu member that determines the upper limit of an interface's
- mtu as well.
-
- A buffer holds exactly one packet, and has a source as well as a destination address. - The addresses may be changed in every layer the buffer passes through. For example, - the datalink protocols usually use sockaddr_dl structures with family AF_DLI, while - the upper levels may use sockaddr_in structures with family AF_INET. Every protocol - only supports a small number of address types, and it's the requirement of the upper - protocols to prepare the address for use in the lower protocols (and that's also a - reason why it wouldn't work to arbitrarily stack protocols onto each other). -
-- The net_buffer module can be used to access the data within the buffer, append new - data to the buffer, or remove chunks of data from it. Internally, the buffer consists - of usually fixed size (2048 byte) buffers that can be shared or connected as needed. -
-- The socket is only of interest for the net_protocol modules, as it stores options - that may have an effect on the protocol's performance. It's the direct counterpart - to a socket file descriptor in userland, but it has only little logic bound to it. -
-- When a socket is created, the networking stack creates a chain of net_protocol - modules for the socket that will then do the real work. When the socket is closed, - the net_protocol chain is freed, and the modules are eventually unloaded (if they - are no longer in use). -
-- The protocols are bound to a specific socket, process the outgoing buffers as needed - (ie. add or remove headers, compute checksums, ...), and pass it on to the next - protocol. The last protocol in the chain is always a domain protocol that will forward - the calls to the datalink module directly, if needed. -
-- A domain protocol is a net_protocol that registered a domain, ie. IPv4. Other than usual - protocols, domain protocols have some special requirements: -
- Similar to the need to perform send_data() outside of the socket context, all protocols - that can receive data need to handle incoming data without the socket context: incoming - data is always handled outside of the socket context, as the actual target socket - is unknown during processing. -
-- Only the top-most protocol will be able to forward the packet to the target socket(s). - To receive incoming data, a protocol must register itself as receiving protocol with - the networking stack. The domain protocol is usually registered automatically by a - net_datalink_protocol module that knows about both ends (for example, the ARP - module is both IPv4 and ethernet specific, and therefore registers the AF_INET - domain to receive ethernet packets of type IP). -
-- The datalink protocols are bound to a specific net_interface, and therefore to a - specific net_device as well. Outgoing data is processed so that it can be sent - via the net_device. For example, the ARP protocol will replace sockaddr_in structures - in the buffer with sockaddr_dl structures describing the ethernet MAC address of - the source and destination hosts, the ethernet_frame protocol will add the usual - ethernet header, etc. -
-- The last protocol in the chain is also a special device interface bridge protocol, - that redirects the calls to the underlying net_device. -
-
- Incoming data is handled differently again; when you want to receive data directly
- coming from a device, you can either register a deframing function for it, or a
- handler that will be called depending on what data type the deframing module reported.
- For example, the ethernet_frame module registers an ethernet deframing function, while
- the ARP module registers a handler for ethernet ARP packets with the device. When the
- deframing function reports a ETHER_TYPE_ARP packet, the ARP receiving
- function will be called.
-
- A route determines the target interface of an outgoing packet. A route is always - owned by a specific domain, and the route is chosen by comparing the networking - address of the outgoing buffer with the mask and address of the route. -
-- A protocol will usually not use the routes directly, but use a net_route_info - object (see below), that will make sure that the route is updated automatically - whenever the routing table is changed. -
-
- A routing helper for protocol usage: it stores the target address as well as the
- route to be used, and has to be registered with the networking stack via
- register_route_info().
-
- Then, the stack will automatically update the route as needed, whenever the - routing table of the domain changes; it will always matches the address specified - there. When the routing is no longer needed, you must unregister the net_route_info - again. -
-AppServer class
-
-
The AppServer class sits at the top of the hierarchy, starting and stopping services, monitoring for messages, and so forth.
-
-
-
-Member Functions
-
|
- AppServer(void) - |
-
- ~AppServer(void) - |
-
|
- static int32 Poller(void *data) - |
-
- static int32 Picasso(void *data) - |
-
|
- thread_id Run(void) - |
-
- void MainLoop(void) - |
-
|
- bool LoadDecorator(const char *path) - |
-
- void DispatchMessage(int32 code, int8 *buffer) - |
-
|
- void Broadcast(int32 code) - |
-
- void HandleKeyMessage(int32 code, int8 *buffer) - |
-
-
-Global Functions
-Decorator * instantiate_decorator(Layer *owner, uint32 wflags, uint32 wlook)
-
-
AppServer(void)
-
-1) Create the message and input ports
2) Create any necessary semaphores for regulating the 3 main threads
-3) Initialize all member variables
-4) Allocate the application BList
-5) Read in and process all configuration data
-6) Initialize the desktop
-7) Spawn the Picasso and Poller threads
-
-
-~AppServer(void)
-1) Shut down the desktop
2) Empty and delete the application list
-3) Wait for Picasso and Poller to exit
-4) Free any allocated heap space
-
-
-void MainLoop(void)
-MainLoop is one large loop used to monitor the main message port in the app_server thread. This is a standard port-monitoring loop code:
-1) Call port_buffer_size - which will block if the port is empty
2) Allocate a buffer on the heap if the port buffer size is greater than 0
-3) Read the port
-4) Pass specified messages to DispatchMessage() for processing, spitting out an error message to stderr if the message's code is unrecognized
-5) Return from DispatchMessage() and free the message buffer if one was allocated
-6) If the message code matches the B_QUIT_REQUESTED definition and the quit_server flag is true, fall out of the infinite message-monitoring loop
-
-
-void DispatchMessage(int32 code, int8 *buffer)
-DispatchMessage implements all the code necessary to respond to a given message sent to the app_server on its main port. This allows for clearer and more manageable code.
-CREATE_APP:
-Sent by a new BApplication object via synchronous PortLink messaging. Set up the corresponding ServerApp and reply to the BApplication with the new port to which it will send future communications with the App Server.
-Attached Data:
-
|
- port_id reply_port - |
-
- port to which the server is to reply in response to the current message - |
-
|
- port_id app_port - |
-
- message port for the requesting BApplication - |
-
|
- int16 sig_length - |
-
- length of the following application signature - |
-
|
- const char *signature - |
-
- Signature of the requesting BApplication - |
-
-
-1) Get all attached data
2) Acquire the application list lock
-3) Allocate a ServerApp object and add it to the list
-4) Release application list lock
-5) Acquire active application pointer lock
-6) Update active application pointer
-7) Release active application lock
-8) Send the message SET_SERVER_PORT (with the ServerApp's receiver port attached) to the reply port
-9) Run() the new ServerApp instance
-
-
-DELETE_APP:
-Sent by a ServerApp when told to quit either by its BApplication or the Server itself (during shutdown). It is identified by the unique ID assigned to its thread.
-Attached Data:
-
|
- thread_id app_thread - |
-
- Thread id of the ServerApp sending this message - |
-
-
-1) Get app's thread_id
2) Acquire application list lock
-3) Iterate through the application list, searching for the ServerApp object with the sent thread_id
-4) Remove the object from the list and delete it
-5) Acquire active application lock
-6) Check to see if the application is active
-7) If application is/was active, set it to the previous application in the list or NULL if there are no other active applications
-8) Release application list lock
-9) Release active application lock
-
-
-GET_SCREEN_MODE:
-Received from the OpenBeOS Input Server when requesting the current screen settings via synchronous PortLink messaging. This is a temporary solution which will be deprecated as soon as the BScreen class is complete.
-
Attached Data:
-
-
|
- port_id reply_port - |
-
- port to which the server is to reply in response to the current message - |
-
-
-1) Get height, width, and color depth from the global graphics driver object
2) Attach via PortLink and reply to sender
-
-B_QUIT_REQUESTED:
-Encountered only under testing situations where the Server is told to quit.
-Attached Data: None
-1) Set quit_server flag to true
2) Call Broadcast(QUIT_APP)
-
-
-SET_DECORATOR:
-Received from just about anything when a new window decorator is chosen
-
Attached Data:
-
-
|
- const char *path - |
-
- Path to the proposed new decorator - |
-
-
-1) Get the path from the buffer
2) Call LoadDecorator()
-
-
-void Run(void)
-Run() exists mostly for consistency with other regular applications.
-1) Call MainLoop()
-
-bool LoadDecorator(const char *path)
-Allows for a simple way to change the current window decorator systemwide simply by specifying the path to the desired Decorator addon.
-1) Load the passed string as the path to an addon.
2) Load all necessary symbols for the decorator
-3) Return false if things didn't go so well
-4) Call Broadcast(UPDATE_DECORATOR)
-5) Return true
-
-static int32 Picasso(void *data)
-Picasso is a function, despite its name, dedicated to ensuring that the server deallocates resources to a dead application. It consists of a while(!quit_server) loop as follows:
-1) Acquire the appliction list lock
2) Iterate through the list, calling each ServerApp object's PingTarget() method.
-3) If PingTarget returns false, remove the ServerApp from the list and delete it.
-4) Release the appliction list lock
-5) snooze for 3 seconds
-
-static int32 Poller(void *data)
-Poller is the main workhorse of the AppServer class, polling the Server's input port constantly for any messages from the Input Server and calling the appropriate handlers. Like Picasso, it, too, is mostly a while(!quit_server) loop.
-
1) Call port_buffer_size_etc() with a timeout of 3 seconds.
-2) Check to see if the port_buffer_size_etc() timed out and do a continue to next iteration if it did.
-3) Allocate a buffer on the heap if the port buffer size is greater than 0
-4) Read the port
-5) Pass specified messages to DispatchMessage() for processing, spitting out an error message to stderr if the message's code is unrecognized
-6) Return from DispatchMessage() and free the message buffer if one was allocated
-
-
-
Decorator * instantiate_decorator(Layer *owner, uint32 wflags, uint32 wlook)
-
-instantiate_decorator returns a new instance of the decorator currently in use. The caller is responsible for the memory allocated for the returned object.
-1) Acquire the decorator lock
2) If create_decorator is NULL, create a new instance of the default decorator
-3) If create_decorator is non-NULL, create a new decorator instance by calling AppServer::create_decorator().
-4) Release the decorator lock
-5) Return the newly allocated instance
-
-void Broadcast(int32 code)
-Broadcast() provides the AppServer class with an easy way to send a quick message to all ServerApps. Primarily, this is called when a font or decorator has changed, or when the server is shutting down. It is not intended to do anything except send a quick message which requires no extra data, such as for some upadate signalling.
-
1) Acquire application list lock
-2) Create a PortLink instance and set its message code to the passed parameter.
-3) Iterate through the application list, targeting the PortLink instance to each ServerApp's message port and calling Flush().
-4) Release application list lock
-
-void HandleKeyMessage(int32 code, int8 *buffer)
-
Called from DispatchMessage to filter out App Server events and otherwise send keystrokes to the active application.
-
-B_KEY_DOWN:
-Sent when the user presses (or holds down) a key that's been mapped to a character.
-Attached Data:
-
|
- int64 when - |
-
- event time in seconds since 1/1/70 - |
-
|
- int32 rawcode - |
-
- code for the physical key pressed - |
-
|
- int32 repeat_count - |
-
- number of times a key has been repeated - |
-
|
- int32 modifiers - |
-
- flags signifying the states of the modifier keys - |
-
|
- int32 state_count - |
-
- number of bytes to follow containing the state of all keys - |
-
|
- int8 *states - |
-
- array of the state of all keys at the time of the event - |
-
|
- int8 utf8data[3] - |
-
- UTF-8 data generated - |
-
|
- int8 charcount - |
-
- number of bytes to follow containing the string generated (usually 1) - |
-
|
- const char *string - |
-
- null-terminated string generated by the keystroke - |
-
|
- int32 raw_char - |
-
- modifier-independent ASCII code for the character - |
-
-
-1) Get all attached data
2) If the command modifier is down, check for Left Ctrl+Left Alt+Left Shift+F12 and reset the workspace to 640 x 480 x 256 @ 60Hz and return if true
-3) If the command modifier is down, check for Alt+F1 through Alt+F12 and set workspace and return if true
-4) If the control modifier is true, check for B_CONTROL_KEY+Tab and, if true, find and send to the Deskbar.
-4) Acquire the active application lock
-5) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_KEY_DOWN, attach the buffer en masse, and send it to the BApplication.
-6) Release the active application lock
-
-
B_KEY_UP:
-
-
Sent when the user releases a key that's been mapped to a character.
-
-Attached Data:
-
|
- int64 when - |
-
- event time in seconds since 1/1/70 - |
-
|
- int32 rawcode - |
-
- code for the physical key pressed - |
-
|
- int32 modifiers - |
-
- flags signifying the states of the modifier keys - |
-
|
- int32 state_count - |
-
- number of bytes to follow containing the state of all keys - |
-
|
- int8 *states - |
-
- array of the state of all keys at the time of the event - |
-
|
- int8 utf8data[3] - |
-
- UTF-8 data generated - |
-
|
- int8 charcount - |
-
- number of bytes to follow containing the string generated (usually 1) - |
-
|
- const char *string - |
-
- null-terminated string generated by the keystroke - |
-
|
- int32 raw_char - |
-
- modifier-independent ASCII code for the character - |
-
-
-1) Get all attached data
2) Acquire the active application lock
-3) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_KEY_UP, attach the buffer en masse, and send it to the BApplication.
-4) Release the active application lock
-
-B_UNMAPPED_KEY_DOWN:
-
Sent when the user presses a key that has not been mapped to a character.
-
-Attached Data:
-
|
- int64 when - |
-
- event time in seconds since 1/1/70 - |
-
|
- int32 rawcode - |
-
- code for the physical key pressed - |
-
|
- int32 modifiers - |
-
- flags signifying the states of the modifier keys - |
-
|
- int8 state_count - |
-
- number of bytes to follow containing the state of all keys - |
-
|
- int8 *states - |
-
- array of the state of all keys at the time of the event - |
-
-
-1) Acquire the active application lock
2) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_UNMAPPED_KEY_DOWN, attach the buffer en masse, and send it to the BApplication.
-3) Release the active application lock
-
-B_UNMAPPED_KEY_UP:
-
Sent when the user presses a key that has not been mapped to a character.
-
-Attached Data:
-
|
- int64 when - |
-
- event time in seconds since 1/1/70 - |
-
|
- int32 rawcode - |
-
- code for the physical key pressed - |
-
|
- int32 modifiers - |
-
- flags signifying the states of the modifier keys - |
-
|
- int8 state_count - |
-
- number of bytes to follow containing the state of all keys - |
-
|
- int8 *states - |
-
- array of the state of all keys at the time of the event - |
-
-
-1) Acquire the active application lock
2) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_UNMAPPED_KEY_UP, attach the buffer en masse, and send it to the BApplication.
-3) Release the active application lock
-
-
B_MODIFIERS_CHANGED:
-
-
Sent when the user presses or releases one of the modifier keys
-
-Attached Data:
-
|
- int64 when - |
-
- event time in seconds since 1/1/70 - |
-
|
- int32 modifiers - |
-
- flags signifying the states of the modifier keys - |
-
|
- int32 old_modifiers - |
-
- former states of the modifier keys - |
-
|
- int8 state_count - |
-
- number of bytes to follow containing the state of all keys - |
-
|
- int8 *states - |
-
- array of the state of all keys at the time of the event - |
-
-
-1) Acquire the active application lock
2) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_MODIFIERS_CHANGED, attach the buffer en masse, and send it to the BApplication.
-3) Release the active application lock
-BitmapManager class
-
-
The BitmapManager object handles all ServerBitmap allocation and deallocation. The rest of the server uses CreateBitmap and DeleteBitmap instead of new and delete. It utilizes the outside pool manager BGET.
-
-
-
-Member Functions
-
|
- BitmapManager(void) - |
-
- ~BitmapManager(void) - |
-
|
- ServerBitmap *CreateBitmap(BRect bounds, color_space space, int32 flags, int32 bytes_per_row=-1, screen_id screen=B_MAIN_SCREEN_ID) - |
-
- void DeleteBitmap(ServerBitmap *bitmap) - |
-
-
-Global Functions
-extern "C" void set_area_buffer_management(void);
void * expand_area_storage(long size)
-void contract_area_storage(void *buffer)
-
-
BitmapManager(void)
-
-1) Create the bitmap list
2) Create the bitmap area
-3) Allocate the access semaphore
-4) Call set_buffer_area_management
-5) Set up the buffer pool via bpool
-
-~BitmapManager(void)
-1) Iterate over each item in the bitmap list, removing each item, calling brel() on its buffer, and deleting it.
2) Delete the bitmap list
-3) Delete the bitmap area
-4) Free the access semaphore
-
-ServerBitmap *CreateBitmap(BRect bounds, color_space space, int32 flags, int32 bytes_per_row=-1, screen_id screen=B_MAIN_SCREEN_ID)
-CreateBitmap is called by outside objects to allocate a ServerBitmap object. If a problem occurs, it returns NULL.
-1) Acquire the access semaphore
2) Verify parameters and if any are invalid, spew an error to stderr and return NULL
-3) Allocate a new ServerBitmap
-4) Allocate a buffer for the bitmap via bget() with the bitmap's theoretical buffer length
-5) If NULL, delete the bitmap and return NULL
-6) Set the bitmap's area and buffer to the appropriate values (area_for buffer and buffer)
-7) Add the bitmap to the bitmap list
-8) Release the access semaphore
-9) Return the bitmap
-
-void DeleteBitmap(ServerBitmap *bitmap)
-Frees a ServerBitmap allocated by CreateBitmap()
-1) Acquire the access semaphore
2) Find the bitmap in the list
-3) Remove the bitmap from the list or release the semaphore and return if not found
-4) call brel() on the bitmap's buffer if it is non-NULL
-5) delete the bitmap
-6) Release the access semaphore
-
-extern "C" void set_area_buffer_management(void)
-C function defined externally to point the BGET manager to our homegrown area allocation and deallocation functions.
-void * expand_area_storage(long size)
-"Internal" global function accessed only by set_area_buffer_management and BGET to handle the task of adding more area space to make room for more bitmaps.
-1) If size is less than B_PAGE_SIZE, set the area size to B_PAGE_SIZE
2) If size % B_PAGE_SIZE, set area size to (size/B_PAGE_SIZE)+1)*B_PAGE_SIZE, otherwise setting it to the given size
-3) Call create_area with the area size.
-4) If it couldn't allocate an area, write a panic message to stderr and return NULL, otherwise, return the pointer to the area.
-
-void contract_area_storage(void *buffer)
-"Internal" global function accessed only by set_area_buffer_management and BGET to remove the area which was previously used for the bitmap pool
-1) Call area_for on the buffer
2) If the area_id is not B_ERROR, call delete_area on its area_id.
-ColorSet class
-
-
The ColorSet class provides an easy manner to manage system attribute colors, such as window tabs, panel background colors, etc. Each member is an RGBColor. The attributes are list below and are publicly accessible.
-
-
panel_background
-panel_text
-document_background
-document_text
-control_background
-control_text
-control_border
-control_highlight
-tooltip_background
-tooltip_text
-menu_background
-menu_selected_background
-menu_text
-menu_selected_text
-menu_separator_high
-menu_separator_low
-menu_triggers
-window_tab
-window_tab_text
-inactive_window_tab
-inactive_window_tab_text
-keyboard_navigation
-desktop
-
-
-
-Member Functions
-
|
- ColorSet(void) - |
-
- ColorSet(const ColorSet &cs) - |
-
|
- ColorSet & operator=(const ColorSet &cs) - |
-
- void SetColors(const ColorSet &cs) - |
-
|
- void PrintToStream(void) - |
- - - | -
-
-
-
-ColorSet(void)
-Does nothing.
-
-ColorSet(const ColorSet &cs)
ColorSet & operator=(const ColorSet &cs)
-
-Calls SetColors on the passed ColorSet object
-
-void SetColors(const ColorSet &cs)
-Copies all data members of the passed color set to those of the current one
-
-void PrintToStream(void)
-Prints the name of each attribute color and then calls the color's PrintToStream member.
ColorUtils
-
-
These functions are used for general purpose color-related tasks.
-
-
-
Global Functions
-
-void SetRGBColor32(rgb_color *col, uint8 r, uint8 g, uint8 b, uint8 a=255)
void SetRGBAColor32(rgb_color *col, uint16 color16)
-void SetRGBColor16(uint16 *col, uint8 r, uint8 g, uint8 b)
-void SetRGBAColor15(uint16 *col, uint8 r, uint8 g, uint8 b, bool opaque=true)
-
-uint8 FindClosestColor(rgb_color *palette,rgb_color col)
uint16 FindClosestColor16(rgb_color col)
-uint16 FindClosestColor15(rgb_color col)
-
-rgb_color MakeBlendColor(rgb_color col, rgb_color col2, float position)
-
void SetRGBColor32(rgb_color *col, uint8 r, uint8 g, uint8 b, uint8 a=255)
-
-Simply assigns the passed parameters to the internal members of the passed color
-
-void SetRGBAColor32(rgb_color *col, uint16 color16)
-Maps a 16-bit color to a 32-bit one.
-gggbbbbb arrrrrgg
1) Extract component values using the following calculations:
-
- red16 = (uint8[1] & 124) >> 2
- green16 = ((uint8[0] & 224) >> 5) | ((uint8[1] & 3) << 3)
- blue16 = uint8[0] & 31
2) Use cross-multiplication to map each 16-bit color component from 0-31 space to 0-255 space, i.e. red32 = (red16 / 31) * 255
-3) Assign mapped values to the rgb_color passed to the function
-
-
-void SetRGBColor16(uint16 *col, uint8 r, uint8 g, uint8 b)
-Used for easy assignment of opaque (B_RGB16) 16-bit colors.
-1) Clip parameters via a bitwise AND with 31 (var &=31)
2) Create a uint8 * to the passed color
-3) Assign as follows and return:
-a) uint8[0] = ( (g & 7) << 5) | (b & 31)
-b) uint8[1] = ( (r & 31) << 3) | ( (g & 56) >> 3)
-
-
-void SetRGBAColor15(uint16 *col, uint8 r, uint8 g, uint8 b, bool opaque=true)
-Used for easy assignment of alpha-aware (B_RGBA16) 16-bit colors.
-1) Clip parameters via a bitwise AND with 31 (var &=31)
2) Create a uint8 * to the passed color
-3) Assign as follows and return:
-a) uint8[0] = ( (g & 7) << 5) | (b & 31)
-b) uint8[1] = ( (r & 31) << 2) | ( (g & 24) >> 3) | (a) ? 128 : 0
-
-
-uint8 FindClosestColor(rgb_color *palette,rgb_color col)
-Finds the color which most closely resembles the given one in the given palette.
-1) Set the saved delta value to 765 (maximum difference)
2) Loop through all the colors in the palette. For each color,
-a) calculate the delta value for each color component and add them together
-b) compare the new combined delta with the saved one
-c) if the delta is 0, immediately return the current index
-d) if the new one is smaller, save it and also the palette index
-
-
-uint16 FindClosestColor16(rgb_color col)
-Returns a 16-bit approximation of the given 32-bit color. Alpha values are ignored.
1) Create an opaque, 16-bit approximation of col using the following calculations:
-r16=(31*col.red)/255
-g16=(31*col.green)/255
-b16=(31*col.blue)/255
-2) Assign it to a uint16 using the same code as in SetRGBColor16() and return it.
-
-
-uint16 FindClosestColor15(rgb_color col)
-This functions almost exactly like the 16-bit version, but this also takes into account the alpha transparency bit and works in the color space B_RGBA15. Follow the same algorithm as FindClosestColor16(), but assign the return value using SetRGBColor15.
-
-rgb_color MakeBlendColor(rgb_color col, rgb_color col2, float position)
-MakeBlendColor calculates a color that is somewhere between start color col and end color col2, based on position, where 0<= position <= 1. If position is out of these bounds, a color of {0,0,0,0} is returned. If position is 0, the start color is returned. If position is 1, col2 is returned. Otherwise, the color is calculated thus:
-1) calculate delta values for each channel, i.e. int16 delta_r=col.red-col2.red
2) Based on these delta values, calculate the blend values for each channel, i.e. blend_color.red=uint8(col1.red - (delta_r * position) )
-CursorManager class
-
-
The CursorManager class handles token creation, calling the cursor-related graphics driver functions, and freeing heap memory for all ServerCursor instances.
-
-
-
-Member Functions
-
|
- CursorManager(void) - |
-
- ~CursorManager(void) - |
-
|
- int32 AddCursor(ServerCursor *c) - |
-
- void DeleteCursor(int32 token) - |
-
|
- void RemoveAppCursors(ServerApp *a) - |
-
- void ShowCursor(void) - |
-
|
- void HideCursor(void) - |
-
- void ObscureCursor(void) - |
-
|
- void SetCursor(int32 token) - |
-
- ServerCursor *GetCursor(cursor_which which) - |
-
|
- void SetCursor(cursor_which which) - |
-
- void ChangeCursor(cursor_which which, -int32 token) - |
-
|
- cursor_which GetCursorWhich(void) - |
- - - | -
-
-Enumerated Types:
-cursor_which {
CURSOR_DEFAULT
-CURSOR_TEXT
-CURSOR_MOVE
-CURSOR_DRAG
-CURSOR_RESIZE
-CURSOR_RESIZE_NW
-CURSOR_RESIZE_SE
-CURSOR_RESIZE_NS
-CURSOR_RESIZE_EW
-CURSOR_OTHER
-}
-
-
-
CursorManager(void)
-
-
-1) Create the cursor list empty
2) Set the token index to 0
-3) Allocate the default system cursor and pass it to AddCursor
-4) Initialize the member pointer for the graphics driver
-5) Create the cursorlock semaphore
-6) Call SetDefaultCursor
-
-
-~CursorManager(void)
-1) Empty and delete the cursor list
2) Delete the cursorlock semaphore
-
-
-int32 AddCursor(ServerCursor *sc)
-AddCursor() is used to register the cursor in question with the manager, allowing for the user application to have the identifying token, if necessary. The cursor becomes the property of the manager. If a user application deletes a BCursor, its ServerApp will call DeleteCursor().
-1) Acquire cursor lock
2) Add *sc to the cursor list
-3) Set sc->token to the current token index value
-4) Increment the token index
-5) Assign sc->token to temporary variable
-6) Release cursor lock
-7) Return the saved token value
-
-
-void DeleteCursor(int32 ctoken)
-1) Acquire cursor lock
2) Iterate through the cursor list, looking for ctoken
-3) If any ServerCursor->token equals ctoken, remove and delete it
-4) Release cursor lock
-
-
-void RemoveAppCursors(ServerApp *app)
-1) Acquire cursor lock
2) Iterate through the cursor list, checking each cursor's ServerApp pointer
-3) If any have a ServerApp pointer which matches the passed pointer, remove and delete them
-4) Release cursor lock
-
-
-void ShowCursor(void)
void HideCursor(void)
-void ObscureCursor(void)
-
-Simple pass-through functions which call the graphics driver's functions. Note that acquiring the cursor lock will be necessary for all three calls.
-
-void SetCursor(int32 token)
void SetCursor(cursor_which cursor)
-
-These set the current cursor for the graphics driver to the passed cursor, either one previously added via AddCursor or a system cursor.
-1) Acquire cursor lock
-Token version:
2) Find the cursor in the cursor list and call the graphics driver if non-NULL
-3) Iterate through list of system cursor tokens and see if there's a match. If so, set the internal cursor_which to the match.
-
-cursor_which version:
2) determine which cursor to use via a switch statement and call the graphics driver with the internal pointer for the appropriate cursor
-3) set the internal cursor_which to the one passed to the function
-
-4) Release cursor lock
-
-ServerCursor *GetCursor(cursor_which which)
-GetCursor is intended for use in figuring out what cursor is in use for a particular system cursor.
-1) Acquire cursor lock
2) use a switch statement to figure which cursor to return and assign a temporary pointer its value
-3) Release cursor lock
-4) Return the temporary pointer
-
-
-void ChangeCursor(cursor_which which, int32 token)
-Calling ChangeCursor will allow a user to change a system cursor's appearance. Note that in calling this, the cursor changes ownership and belongs to the system. Thus, the BCursor destructor will not ultimately cause the cursor to be deleted.
-1) Acquire cursor lock
2) Call FindCursor and, if NULL, release the cursor lock and return
-3) Look up the pointer for the system cursor in question and check to see if it is active. If active, then set the local active flag to true. Set the system cursor pointer to the one looked up.
-4) If active flag is true, call SetCursor()
-5) Release cursor lock
-
-
-cursor_which GetCursorWhich(void)
-Returns the current cursor_which attribute which describes the currently active cursor. If the active cursor is not a system cursor, it will return CURSOR_OTHER.
-1) Acquire cursor lock
2) Create a local cursor_which and assign it the value of the CursorManager's cursor_which
-3) Release cursor lock
-4) Return the local copy
-DebugUtils
-
-
These functions are used to make print-based debugging easier.
-
-
-
Global Functions
-
-BString TranslateStatusToBString(status_t value)
BString TranslateColorSpaceToBString(color_space value)
-BString TranslateMessageCodeToBString(int32 value)
-
-
-
BString TranslateStatusToBString(status_t value)
-BString TranslateColorSpaceToBString(color_space value)
-BString TranslateMessageCodeToBString(int32 value)
-
-const char * TranslateStatusToString(status_t value)
const char * TranslateColorSpaceToString(color_space value)
-const char * TranslateMessageCodeToString(int32 value)
-
-All of these functions are essentially big switch() statements which assign an appropriate string for the passed parameter and return the assigned string. This way the string can be printed or otherwise easily used.
Decorator class
-
-
Decorators provide the actual drawing for a window's looks.
-
-
-
-Member Functions
-
|
- Decorator(BRect int32 wlook, int32 wfeel, int32 wflags) - |
-
- ~Decorator(void) - |
-
|
- void SetColors(color_set colors) - |
-
- void SetDriver(DisplayDriver *driver) - |
-
|
- void SetClose(bool is_down) - |
-
- void SetMinimize(bool is_down) - |
-
|
- void SetZoom(bool is_down) - |
-
- void SetFlags(int32 wflags) - |
-
|
- void SetFeel(int32 wfeel) - |
-
- void SetLook(int32 wlook) - |
-
|
- bool GetClose(void) - |
-
- bool GetMinimize(void) - |
-
|
- bool GetZoom(void) - |
-
- int32 GetLook(void) - |
-
|
- int32 GetFeel(void) - |
-
- int32 GetFlags(void) - |
-
|
- void SetTitle(const char *string) - |
-
- void SetFont(SFont *sf) - |
-
|
- int32 _ClipTitle(float width) - |
-
- void SetFocus(bool is_active) - |
-
|
- bool GetFocus(void) - |
-
- int32 _TitleWidth(void) - |
-
-
-
-Virtual Functions
-
|
- void MoveBy(float x, float y) - |
-
- void MoveBy(BPoint pt) - |
-
|
- void ResizeBy(float x, float y) - |
-
- void ResizeBy(BPoint pt) - |
-
|
- void Draw(BRect r) - |
-
- void Draw(void) - |
-
|
- void DrawClose(void) - |
-
- void DrawFrame(void) - |
-
|
- void DrawMinimize(void) - |
-
- void DrawTab(void) - |
-
|
- void DrawTitle(void) - |
-
- void DrawZoom(void) - |
-
|
- void _DrawClose(BRect r) - |
-
- void _DrawFrame(BRect r) - |
-
|
- void _DrawMinimize(BRect r) - |
-
- void _DrawTab(BRect r) - |
-
|
- void _DrawTitle(BRect r) - |
-
- void _DrawZoom(BRect r) - |
-
|
- SRegion GetFootprint(void) - |
-
- click_type Clicked(BPoint pt, int32 buttons, int32 modifiers) - |
-
|
- void _SetFocus(void) - |
-
- BRect SlideTab(float dx, float dy=0) - |
-
-
-_ Indicates a protected member function
-Exported C Functions
-Decorator *create_decorator(BRect frame, int32 wlook, int32 wfeel, int32 wflags)
float get_decorator_version(void)
-
-
-Enumerated Types
-click_type {
CLICK_NONE
-CLICK_ZOOM
-CLICK_CLOSE
-CLICK_MINIMIZE
-CLICK_TAB
-CLICK_MOVE
-CLICK_MOVETOBACK
-CLICK_MOVETOFRONT
-CLICK_RESIZE
-CLICK_RESIZE_L
-CLICK_RESIZE_T
-CLICK_RESIZE_R
-CLICK_RESIZE_B
-CLICK_RESIZE_LT
-CLICK_RESIZE_RT
-CLICK_RESIZE_LB
-CLICK_RESIZE_RB
-}
-
-
Decorator(BRect int32 wlook, int32 wfeel, int32 wflags)
-
-Sets up internal variables common to all decorators.
-1) Assign parameters to respective data members
-
-~Decorator(void)
-Empty.
-void SetColors(color_set colors)
void SetDriver(DisplayDriver *driver)
-void SetClose(bool is_down)
-void SetMinimize(bool is_down)
-void SetZoom(bool is_down)
-void SetFlags(int32 wflags)
-void SetFeel(int32 wfeel)
-void SetLook(int32 wlook)
-bool GetClose(void)
-bool GetMinimize(void)
-bool GetZoom(void)
-int32 GetLook(void)
-int32 GetFeel(void)
-int32 GetFlags(void)
-void SetTitle(const char *string)
-void SetFont(SFont *sf)
-
-These functions work with the internal members common to all Decorators - assigning them and returning them. Additionally, SetTitle() and SetFont() set the clip_font flag to true.
-int32 _ClipTitle(float width)
-ClipTitle calculates how much of the title, in characters, can be displayed in the given width.
-1) Call StringWidth() on the title.
2) If the string's width is less thanwidth, return the string's character count
-3) while the character count to display is > 0
-a) calculate the string's width
-b) if the string's width is less than width, return the character count
-c) decrement the character count
-4) If the loop completes itself without returning a value, it can't fit, so return 0.
-
-
-void SetFocus(bool is_active)
-This is for handling color states when a window receives or loses the focus.
-1) Set focus flag to whatever is_active is.
2) call hook function _SetFocus()
-
-
-bool GetFocus(void)
-Returns the focus state held by the decorator
-1) Return the focus flag
-
-int32 _TitleWidth(void)
-Returns the character count of the title or 0 if it is NULL.
-
-Virtual Functions
-Most of these functions have a default behavior which can be overridden, but are implemented to handle the more common implementations.
-void MoveBy(float x, float y)
void MoveBy(BPoint pt)
-
-Move all member rectangles of Decorator by the specified amount.
-
-void ResizeBy(float x, float y)
void ResizeBy(BPoint pt)
-
-Resize the client frame, window frame, and the tab frame (width only) by the specified amount. Button rectangles - close, minimize, and zoom - are not modified.
-
-void Draw(BRect r)
void Draw(void)
-
-Main drawing call which checks the intersection of the rectangle passed to it and draws all items which intersect it. Draw(void) simply performs drawing calls to draw the entire decorator's footprint area.
-1) Check for intersection with BRect which encompasses the decorator's footprint and return if no intersection.
2) Call _DrawFrame(intersection)
-3) Call _DrawTab(intersection)
-
-
-void DrawClose(void)
protected: void _DrawClose(BRect r)
-void DrawMinimize(void)
-protected: void _DrawMinimize(BRect r)
-void DrawZoom(void)
-protected: void _DrawZoom(BRect r)
-
-Each of these is designed to utilize their respective button rectangles. The public (void) versions simply call the internal protected ones with the button rectangle. These protected versions are, by default, empty. The rectangle passed to them is the invalid area to be drawn, which is not necessarily the entire button's rectangle.
-
-void DrawFrame(void)
protected: void _DrawFrame(BRect r)
-
-Draws the frame, if any. The public version amounts to _DrawFrame(framerect). The protected version is expected to not cover up the client frame when drawing. Any drawing within the clientrect member will end up being drawn over by the window's child views.
-
-void DrawTab(void)
protected: void _DrawTab(BRect r)
-
-Draws the window's tab, if any. DrawTab() amounts to _DrawTab(tabrect). If window titles are displayed, the _DrawTitle call is expected to be made here. Button-drawing calls, assuming that a window's buttons are in the tab, should be made here, as well.
-
-void DrawTitle(void)
protected: void _DrawTitle(BRect r)
-
-These cause the window's title to be drawn. DrawTitle() amounts to _DrawTitle(titlerect).
-
-void _SetFocus(void)
-This hook function is primarily used to change colors used when a window changes focus states and is called immediately after the state is changed. If, for example, a decorator does not use OpenBeOS' GUI color set, it would change its drawing colors to reflect the change in focus.
-
-SRegion GetFootprint(void)
-This returns the "footprint" of the decorator, i.e. the area which is occupied by the window which is is the border surrounding the main client rectangle. It is possible to have oddly-shaped window borders, like ellipses and circles, but the resulting performance hit would reduce the said decorator to a novelty and not something useable. All versions are to construct an SRegion which the border occupies. This footprint is permitted to include the client rectangle area, but this area must not be actually drawn upon by the decorator itself. The default version returns the frame which encompasses all other rectangles - the "frame" member which belongs to its window border.
-
-click_type Clicked(BPoint pt, int32 buttons, int32 modifiers)
-Clicked() performs hit testing for the decorator, given input conditions. This function is required by ALL subclasses expecting to do more than display itself. The return type will cause the server to take the appropriate actions, such as close the window, get ready to move it, etc.
-
-BRect SlideTab(float dx, dy=0)
-SlideTab is implemented only for those decorators which allow the user to somehow slide the tab (if there is one) along the window. Currently, only the horizontal direction is supported. It returns the rectangle of the invalid region which needs redrawn as a result of the slide.
-extern "C" Decorator *create_decorator(BRect frame, int32 wlook, int32 wfeel, int32 wflags)
-Required export function which simply allocates an instance of the decorator and returns it.
-extern "C" float get_decorator_version(void)
-This should, for now, return 1.00.
-
Desktop module
-
-
There are no globally accessible objects in this section of code, but many function definitions to work with workspaces, screen attributes, and other such things. These functions work with the private desktop classes Screen and Workspace.
-
-
-
Global Functions
-
-void InitDesktop(void)
void ShutdownDesktop(void)
-
-void AddWorkspace(int32 index=-1)
void DeleteWorkspace(int32 index)
-int32 CountWorkspaces(void)
-void SetWorkspaceCount(int32 count)
-int32 CurrentWorkspace(screen_id screen=B_MAIN_SCREEN_ID)
-void SetWorkspace(int32 workspace, screen_id screen=B_MAIN_SCREEN_ID)
-
-void SetScreen(screen_id id)
int32 CountScreens(void)
-screen_id ActiveScreen(void)
-DisplayDriver *GetGfxDriver(screen_id screen=B_MAIN_SCREEN_ID)
-status_t SetSpace(int32 index, int32 res, bool stick=true, screen_id screen=B_MAIN_SCREEN_ID)
-
-void AddWindowToDesktop(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID)
void RemoveWindowFromDesktop(ServerWindow *win)
-ServerWindow *GetActiveWindow(void)
-void SetActiveWindow(ServerWindow *win)
-Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE, screen_id s
-screen=B_MAIN_SCREEN_ID)
-
-void set_drag_message(int32 size, int8 *flattened)
int8* get_drag_message(int32 *size)
-void empty_drag_ message(void)
-
-Namespaces
-desktop_private {
int8 *dragmessage
-int32 dragmessagesize
-sem_id draglock
-}
-
-
void InitDesktop(void)
-
-Sets up all the stuff necessary for the system's desktop.
-1) Create a graphics module list by looping through allocation and initialization of display modules until failure is returned. If app_server exists, just create a ViewDriver module
2) Create and populate Screen list, pointing each Screen instance to its Driver instance
-3) Create layer and workspace locks
-4) Set screen 0 to active
-5) Create the desktop_private::draglock semaphore
-
-
-void ShutdownDesktop(void)
-Undoes everything done in InitDesktop().
-1) Delete all locks
2) Delete all screens in the list
-3) Delete the desktop_private::draglock semaphore
-4) If desktop_private::dragmessage is non-NULL, delete it.
-
-
-void AddWorkspace(int32 index=-1)
void DeleteWorkspace(int32 index)
-int32 CountWorkspaces(void)
-void SetWorkspaceCount(int32 count)
-int32 CurrentWorkspace(screen_id screen=B_MAIN_SCREEN_ID)
-void SetWorkspace(int32 workspace, screen_id screen=B_MAIN_SCREEN_ID)
-
-Each of these calls the appropriate method in the Screen class. Add and Delete workspace functions operate on all screens.
-
-void SetScreen(screen_id id)
int32 CountScreens(void)
-screen_id ActiveScreen(void)
-DisplayDriver *GetGfxDriver(screen_id screen=B_MAIN_SCREEN_ID)
-status_t SetSpace(int32 index, int32 res, bool stick=true, screen_id screen=B_MAIN_SCREEN_ID)
-
-Each of these calls operate on the objects in the Screen list, calling methods as appropriate.
-
-void AddWindowToDesktop(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID)
void RemoveWindowFromDesktop(ServerWindow *win)
-ServerWindow *GetActiveWindow(void)
-void SetActiveWindow(ServerWindow *win)
-Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID)
-
-These operate on the layer structure in the active Screen object, calling methods as appropriate.
-
-void set_drag_message(int32 size, int8 *flattened)
-This assigns a BMessage in its flattened state to the internal storage. Only one message can be stored at a time. Once an assignment is made, another cannot be made until the current one is emptied. If additional calls are made while there is a drag message assigned, the new assignment will not be made. Note that this merely passes a pointer around. No copies are made and the caller is responsible for freeing any allocated objects from the heap.
-1) Acquire the draglock
2) release the lock and return if winborder_private::dragmessage is non-NULL
-3) Assign parameters to the private variables
-4) Release the draglock
-
-
-int8* get_drag_message(int32 *size)
-Retrieve the current drag message in use. This function will fail if a NULL pointer is passed to it. Note that this does not free the current drag message from use. The size of the flattened message is stored in the size parameter. Note that if there is no message in use, it will return NULL and set size to 0.
-1) return NULL if size pointer is NULL
2) acquire the draglock
-3) set value of size parameter to winborder_private::dragmessagesize
-4) assign a temporary pointer the value of desktop_private::dragmessage
-5) release the draglock
-6) return the temporary pointer
-
-
-void empty_drag_ message(void)
-This empties the current drag message from use and allows for other messages to be assigned.
-1) acquire draglock
2) assign 0 to desktop_private::dragmessagesize and set desktop_private::dragmessage to NULL
-3) release draglock
-Screen class
-Workspace class
-RootLayer class
-
-The Screen class handles all infrastructure needed for each monitor/video card pair. The Workspace class holds data and supplies the infrastructure for drawing the screen.
-
-Member Functions
-
|
- Screen(DisplayDriver *gfxmodule, uint8 workspaces) - |
-
- ~Screen(void) - |
-
|
- void AddWorkspace(int32 index=-1) - |
-
- void DeleteWorkspace(int32 index) - |
-
|
- int32 CountWorkspaces(void) - |
-
- void SetWorkspaceCount(int32 count) - |
-
|
- int32 CurrentWorkspace(void) - |
-
- void SetWorkspace(int32 workspace) - |
-
|
- void Activate(bool active=true) - |
-
- DisplayDriver *GetDriver(void) - |
-
|
- status_t SetSpace(int32 index, int32 res, bool stick=true) - |
-
- void AddWindow(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE) - |
-
|
- void RemoveWindow(ServerWindow *win) - |
-
- ServerWindow *ActiveWindow(void) - |
-
|
- void SetActiveWindow(ServerWindow *win) - |
-
- Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE) - |
-
|
- bool IsInitialized(void) - |
-
- Workspace *GetActiveWorkspace(void) - |
-
-
-
-
-Screen(DisplayDriver *gfxmodule, uint8 workspaces)
-1) Set driver pointer to gfxmodule
2) If driver pointer is non-NULL and driver->Initialize() is true, set initialized flag to true
-3) If initialized, get the appropriate display driver info and save it internally
-4) Create and populate workspace list
-5) Clear all workspaces
-
-~Screen(void)
-1) Remove all workspaces from the list and delete them
2) Delete the workspace list
-
-
-void AddWorkspace(int32 index=-1)
-Adds a workspace to the screen object, setting its settings to the default, and adding it to the list in the specified index or the end of the list if the index is -1
-1) Create a workspace object
2) Add it to the workspace list - to the end if the index is -1, and to the particular index if not
-
-
-void DeleteWorkspace(int32 index)
-Deletes the workspace at the specified index.
-1) Remove the item at the specified index and if non-NULL, delete it.
-
-int32 CountWorkspaces(void)
-Returns the number of workspaces kept by the particular Screen objects
-1) Return the workspace list's CountItems() value
-
-void SetWorkspaceCount(int32 count)
-Sets the number of workspaces available to count. If count is less than the number of current workspaces, the last workspaces are deleted first. Workspaces are added to the end of the list. If a delete workspace should include the active workspace, then the workspace with the index count-1 is activated. There must be at least one workspace.
-1) if count equals the workspace list's CountItems value, return
2) If count is less than 1, set count to 1. If greater than 32, set to 32.
-3) If active workspace index is greater than count-1, call SetWorkspace(count-1)
-4) If count is greater than the workspace list's CountItems value, call AddWorkspace the appropriate number of times.
-5) If count is less than the workspace list's CountItems, call RemoveWorkspace the appropriate number of times
-
-
-int32 CurrentWorkspace(void)
-Returns the active workspace index
-
-void SetWorkspace(int32 workspace)
void Activate(bool active=true)
-DisplayDriver *GetDriver(void)
-status_t SetSpace(int32 index, int32 res, bool stick=true)
-void AddWindow(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE)
-void RemoveWindow(ServerWindow *win)
-ServerWindow *ActiveWindow(void)
-void SetActiveWindow(ServerWindow *win)
-Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE)
-bool IsInitialized(void)
-Workspace *GetActiveWorkspace(void)
-
-
Workspace class members
-
-
|
- Workspace(graphics_card_info *gcinfo, frame_buffer_info *fbinfo) - |
-
- ~Workspace(void) - |
-
|
- void SetBGColor(const RGBColor &c) - |
-
- RGBColor BGColor(void) - |
-
|
- RootLayer *GetRoot(void) - |
-
- void SetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo) - |
-
|
- void GetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo) - |
- - - | -
-
-
-Workspace(void)
-1) Set background color to RGB(51,102,160)
2) Copy frame_buffer_info and graphics_card_info structure values
-3) Create a RootLayer object using the values from the two structures
-
-
-~Workspace(void)
-1) Call the RootLayer object's PruneTree method and delete it
-
-void SetBGColor(const RGBColor &c)
-Sets the particular color for the workspace. Note that this does not refresh the display.
-1) Set the internal background RGBColor object to the color parameter
-
-RGBColor BGColor(void)
-Returns the internal background color
-
-RootLayer *GetRoot(void)
-Returns the pointer to the RootLayer object
-
-void SetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)
-Changes the graphics data and resizes the RootLayer accordingly.
-1) Copy the two structures to the internal one
2) Resize the RootLayer
-3) If the RootLayer was resized larger, Invalidate the new areas
-
-
-void GetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)
-Copies the two data structures into the parameters passed.
-
RootLayer class members
-
-
|
- RootLayer(BRect frame, const char *name) - |
-
- ~RootLayer(void) - |
-
|
- void RequestDraw(const BRect &r) - |
-
- void MoveBy(float x, float y) - |
-
|
- void MoveBy(BPoint pt) - |
-
- void SetDriver(DisplayDriver *d) - |
-
|
- void RebuildRegions(bool recursive=false) - |
- - - | -
-
-RootLayer(BRect frame, const char *name)
-1) passes B_FOLLOW_NONE to Layer constructor
2) set level to 0
-3) set the background color to the color for the workspace set in the system preferences
-
-
-~RootLayer(void)
-Does nothing.
-
-void RequestDraw(const BRect &r)
-Requests that the layer be drawn on screen. The rectangle passed is in the layer's own coordinates.
-1) call the display driver's FillRect on the rectangle, filling with the layer's background color
2) recurse through each child and call its RequestDraw() function if it intersects the child's frame
-
-
-void MoveBy(BPoint pt)
void MoveBy(float x, float y)
-
-Made empty so that the root layer cannot be moved
-
-void SetDriver(DisplayDriver *d)
-Assigns a particular display driver object to the root layer if non-NULL.
-
-void RebuildRegions(bool recursive=false)
-Rebuilds the visible and invalid layers based on the layer hierarchy. Used to update the regions after a call to remove or add a child layer is made or when a layer is hidden or shown.
-1) get the frame
2) set full and visible regions to frame
-3) iterate through each child and exclude its full region from the visible region if the child is visible.
-DisplayDriver class
-
-
The DisplayDriver class is not a useful class unto itself. It is to provide a consistent interface for the rest of the app_server to whatever rendering context it is utilizing, whether it be a remote screen, a ServerBitmap, installed graphics hardware, or whatever. Documentation below will describe the role of each function.
--
Member Functions
-
-
|
- DisplayDriver(void) - |
-
- ~DisplayDriver(void) - |
-
|
- bool Initialize(void) - |
-
- void Shutdown(void) - |
-
|
- void DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest) - |
-
- void DrawChar(char c, BPoint pt) - |
-
|
- void DrawString(const char *string, int32 length, BPoint pt, escapement_delta *delta=NULL) - |
-
- void Stroke/FillBezier(BPoint *pts, layerdata *d, int8 *pat) - |
-
|
- void Stroke/FillEllipse(BRect r, layerdata *d, int8 *pattern) - |
-
- void Stroke/FillArc(BRect r, float angle, float span, layerdata *d, int8 *pattern) - |
-
|
- void StrokeLine(BPoint start, BPoint end, layerdata *d, int8 *pattern) - |
-
- void StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern, bool is_closed=true) - |
-
|
- void FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern) - |
-
- void Stroke/FillRect(BRect r, layerdata *d, int8 *pattern) - |
-
|
- void Stroke/FillRoundRect(BRect r, float xrad, float yrad, layerdata *d, int8 *pattern) - |
-
- void Stroke/FillShape(SShape *sh, layerdata *d, int8 *pattern) - |
-
|
- void Stroke/FillTriangle(BPoints *pts, BRect r, layerdata *d, int8 *pattern) - |
-
- void StrokeLineArray(BPoint *pts, int32 numlines, rgb_color *colors, layerdata *d) - |
-
|
- void DrawPicture(SPicture *pic, BPoint pt) - |
-
- void CopyBits(BRect src, BRect dest) - |
-
|
- void InvertRect(BRect r) - |
-
- uint8 GetDepth(void) - |
-
|
- uint16 GetHeight(void) - |
-
- uint16 GetWidth(void) - |
-
|
- screen_mode GetMode(void) - |
-
- void SetMode(screen_mode mode) - |
-
|
- bool DumpToFile(const char *path) - |
-
- void ShowCursor(void) - |
-
|
- void HideCursor(void) - |
-
- void ObscureCursor(void) - |
-
|
- bool IsCursorHidden(void) - |
-
- void SetCursor(ServerCursor *csr) - |
-
|
- virtual float StringWidth(const char *string, int32 length, LayerData *d) - |
-
- virtual float StringHeight(const char *string, int32 length, LayerData *d) - |
-
-
-Protected Functions
-
|
- void Lock(void) - |
-
- void Unlock(void) - |
-
|
- void SetDepth(void) - |
-
- void SetHeight(void) - |
-
|
- void SetWidth(void) - |
-
- void SetMode(void) - |
-
|
- void SetCursorHidden(void) - |
-
- void SetCursorObscured(void) - |
-
-
-
DisplayDriver(void)
-~DisplayDriver(void)
-bool Initialize(void)
-void Shutdown(void)
-
-These four are for general start and stop procedures. The constructor and destructor concern themselves with the internal members common to all drivers, such as the current cursor and the access semaphore. Subclasses will probably end up using these to handle memory allocation-related issues, but likely not much else. Initialize() and Shutdown() are for general setup internal to the module. Note that if Initialize() returns false, the server will not use the module, call Shutdown(), and then delete it as accordingly.
-void CopyBits(BRect src, BRect dest)
void InvertRect(BRect r)
-void DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest, render_mode mode)
-void DrawPicture(SPicture *pic, BPoint pt)
-void DrawChar(char c, BPoint pt)
-void DrawString(const char *string, int32 length, BPoint pt, escapement_delta *delta=NULL)
-
-void StrokeArc(BRect r, float angle, float span, layerdata *d, int8 *pattern)
void FillArc(BRect r, float angle, float span, layerdata *d, int8 *pattern)
-void StrokeBezier(BPoint *pts, layerdata *d, int8 *pat)
-void FillBezier(BPoint *pts, layerdata *d, int8 *pat)
-void StrokeEllipse(BRect r, layerdata *d, int8 *pattern)
-void FillEllipse(BRect r, layerdata *d, int8 *pattern)
-void StrokeLine(BPoint start, BPoint end, layerdata *d, int8 *pattern)
-void StrokeLineArray(BPoint *pts, int32 numlines, rgb_color *colors, layerdata *d)
-void StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern, bool is_closed=true)
-void FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern)
-void StrokeRect(BRect r, layerdata *d, int8 *pattern)
-void FillRect(BRect r, layerdata *d, int8 *pattern)
-void StrokeRoundRect(BRect r, float xrad, float yrad, layerdata *d, int8 *pattern)
-void FillRoundRect(BRect r, float xrad, float yrad, layerdata *d, int8 *pattern)
-void StrokeShape(SShape *sh, layerdata *d, int8 *pattern)
-void FillShape(SShape *sh, layerdata *d, int8 *pattern)
-void StrokeTriangle(BPoints *pts, BRect r, layerdata *d, int8 *pattern)
-void FillTriangle(BPoints *pts, BRect r, layerdata *d, int8 *pattern)
-void ShowCursor(void)
-void HideCursor(void)
-void ObscureCursor(void)
-bool IsCursorHidden(void)
-void SetCursor(ServerCursor *csr)
-float StringWidth(const char *string, int32 length, LayerData *d)
-float StringHeight(const char *string, int32 length, LayerData *d)
-
-These drawing functions are the meat and potatoes of the graphics module. Defining any or all of them is completely optional. However, the default versions of these functions will do nothing. Thus, implementing them is likely a good idea, even if not required.
-
-uint8 GetDepth(void)
uint16 GetHeight(void)
-uint16 GetWidth(void)
-screen_mode GetMode(void)
-void SetMode(screen_mode mode)
-
-These five functions are called internally in order to get information about the current state of the buffer in the module. GetDepth should return 8, 16, or 32, in any event because the server handles RGB color spaces of these depths only.
-bool DumpToFile(const char *path)
-DumpToFile is completely optional, providing a hook which allows screenshots to be taken. The default version does nothing but return false. If a screenshot is successful, return true.
-
-void Lock(void)
void Unlock(void)
-
-These two functions provide a locking scheme for the driver in order to easily make it thread safe. Note that it is not publicly callable.
-
-void SetDepthInternal(uint8 d)
void SetHeightInternal(uint16 h)
-void SetWidthInternal(uint16 w)
-void SetModeInternal(int32 m)
-
-These four functions set the internal state variables for height, width, etc. If the driver reimplements the public members SetDepth(), etc, be sure to call the respective internal call so that calls to GetDepth(), etc. return the proper values.
-
-void SetCursorHidden(bool state)
void SetCursorObscured(bool state)
-bool IsCursorObscured(void)
-
-These calls handle internal state tracking so that subclasses don't have to.
FontFamily class
-
-FontFamily objects are used to tie together all related font styles.
-
Member Functions
-
-
|
- FontFamily(const char *name) - |
-
- ~FontFamily(void) - |
-
|
- const char *GetName(void) - |
-
- void AddStyle(const char *path, FT_Face face) - |
-
|
- void RemoveStyle(const char *style) - |
-
- FontStyle *GetStyle(const char *stylename) - |
-
|
- const char *GetStyle(int32 index) - |
-
- int32 CountStyles(void) - |
-
|
- bool HasStyle(const char *style) - |
- - - | -
-
-
-
FontFamily(const char *name)
-
-1) Create and set internal name to the one passed to the constructor
2) Create the styles list
-
-
-~FontFamily(void)
-1) delete the internal name
2) empty and delete the internal style list
-
-
-const char *GetName(void)
-Returns the internal family name
-
-void AddStyle(const char *path, FT_Face face)
-Adds the style to the family.
-1) Create the FontStyle object and add it to the style list.
-
-void RemoveStyle(const char *style)
-Removes the style from the FontFamily object.
-1) Call GetStyle on the given pointer
2) If non-NULL, delete the object
-3) If the style list is now empty, ask the FontServer to remove it from the family list
-
-
-FontStyle *GetStyle(const char *style)
-Looks up a FontStyle object based on its style name. Returns NULL if not found.
-1) Iterate through the style list
a) compare style to each FontStyle object's GetName method and return the object if they are the same
-2) If all items have been checked and nothing has been returned, return NULL
-
-
-const char *GetStyle(int32 index)
-Returns the name of the style at index
-1) Get the FontStyle item at index obtained via the style list's ItemAt call
-
-int32 CountStyles(void)
-Returns the number of items in the style list and, thus, the number of styles in the family
-
-bool HasStyle(const char *stylename)
-Returns true if the family has a style with the name stylename
-1) Call GetStyle on the style name and return false if NULL, true if not.
-
FontServer class
-
-
The FontServer provides the base functionality for providing font support for the rest of the system and insulates the rest of the server from having to deal too much with FreeType.
-
-
Member Functions
-
-
|
- FontServer(void) - |
-
- ~FontServer(void) - |
-
|
- void Lock(void) - |
-
- void Unlock(void) - |
-
|
- void SaveList(void) - |
-
- status_t ScanDirectory(const char *path) - |
-
|
- FontStyle *GetFont(font_family family, font_style face) - |
-
- FontInstance *GetInstance(font_family family, font_style face, int16 size, int16 rotation, int16 shear) - |
-
|
- int32 CountFamiles(void) - |
-
- status_t IsInitialized(void) - |
-
|
- int32 CountStyles(font_family family) - |
-
- FontStyle *GetStyle(font_family family, font_style style) - |
-
|
- void RemoveFamily(const char *family) - |
-
- FontFamily *_FindFamily(const char *name) - |
-
|
- ServerFont *GetSystemPlain(void) - |
-
- ServerFont *GetSystemBold(void) - |
-
|
- ServerFont *GetSystemFixed(void) - |
-
- bool SetSystemPlain(const char *family, const char *style, float size) - |
-
|
- void RemoveUnusedFamilies(void) - |
-
- bool FontsNeedUpdated(void) - |
-
-
-
FontServer(void)
-
-1) Create access semaphore
2) Call FT_Init_FreeType()
-3) If no error initializing the FreeType library, set init flag to true
-
-
-~FontServer(void)
-1) Call FT_Done_FreeType()
-
-void Lock(void)
void Unlock(void)
-
-These functions simply acquire and release the internal access semaphore.
-
-void SaveList(void)
-Saves the list of all scanned and valid font families and styles to disk
-1) create a BMessage for storing font family data (hereafter, the font message)
2) create a BMessage for storing a list of font family messages (hereafter, the list message)
-3) create a boolean tuned flag and a boolean fixed flag
-4) Iterate through all families
-A) for each family, get its name and add its name to the font message as "name"
-B) iterate through the families styles
-a) get the style's name, and if valid, add it to the font message as "styles"
-b) if IsTuned and IsScalable, set the tuned flag to true
-c) if IsFixedWidth, set the fixed flag to true
-C) if the tuned flag is set, add a boolean true to the font message as "tuned"
-D) if the fixed flag is set, add a boolean true to the font message as "fixed"
-E) add the font message to the list message as "family"
-F) empty the font message
-5) Create a BFile from the path definition SERVER_FONT_LIST for Read/Write, creating the file if nonexistent and erasing any existing one
-6) Flatten the list message to the created BFile object
-7) Set the needs_update flag to false
-
-
-status_t ScanDirectory(const char *path)
-ScanDirectory is where the brunt of the work of the FontServer is done - scans the directory of all fonts which can be loaded.
-1) Make a BDirectory object pointer at the path parameter. If the init code is not B_OK, return it.
2) Enter a while() loop, iterating through each entry in the given directory, executing as follows:
-a) Ensure that the entry is not '.' or '..'
-b) Call FT_New_Face on the entry's full path
-c) If a valid FT_Face is returned, iterate through to see if there are any supported character mappings in the current entry.
-d) If there are no supported character mappings, dump the supported mappings to debug output, call FT_Done_Face(), and continue to the next entry
-e) See if the entry's family has been added to the family list. If it hasn't, create one and add it.
-f) Check to see if the font's style has been added to its family. If so, call FT_Done_Face, and continue to the next entry
-g) If the style has not been added, create a new SFont for that family and face, increment the font count, and continue to the next entry.
-3) set the needs_update flag to true
-4) Return B_OK
-
-Supported character mappings are Windows and Apple Unicode, Windows symbol, and Apple Roman character mappings, in order of preference from first to last.
-
-FontStyle *GetFont(font_family family, font_style face)
-Returns an FontStyle object for the specified family and style or NULL if not found.
-1) Call _FindFamily() for the given family
2) If non-NULL, call its FindStyle() method
-3) Return the result
-
-
-FontInstance *GetInstance(font_family family, font_style face, int16 size, int16 rotation, int16 shear)
-Returns a usable instance of a specified font object with specified properties.
-1) Duplicates and performs the code found in GetFont
2) Assuming that the FontStyle object is non-NULL, it calls its GetInstance method and returns the result.
-
-
-int32 CountFamilies(void)
-Returns the number of valid font families available to the system.
-1) Return the number of items in the family list
-
-status_t IsInitialized(void)
-Returns the initialization status variable
-
-int32 CountStyles(font_family family)
-Returns the number of styles available for a given font family.
-1) Call _FindFamily() to get the appropriate font family
2) If non-NULL, call its return the result of its CountStyles method
-
-
-FontStyle *GetStyle(font_family family, font_style style)
-Gets the FontStyle object of the family, style, and flags.
-1) Call _FindFamily() to get the appropriate font family
2) If non-NULL, call the family's GetStyle method on the font_style parameter and return the result
-3) If family is NULL, return NULL
-
-
-void RemoveFamily(const char *family)
-Removes a font family from the family list
-1) Look up font family in the family list via _FindFamily()
2) If it exists, delete it
-
-
-protected:
-FontFamily *_FindFamily(const char *name)
-Looks up a FontFamily object based on its family name. Returns NULL if not found.
-1) Call the family list's find() method.
2) Return the appropriate FontFamily object or NULL if not found.
-
-
-ServerFont *GetSystemPlain(void)
ServerFont *GetSystemBold(void)
-ServerFont *GetSystemFixed(void)
-
-These return a copy of a pointer to the system-wide ServerFont objects which represent the appropriate system font settings. It is the responsibility of the caller to delete the object returned. NULL is returned if no setting has been set for a particular system font.
-bool SetSystemPlain(const char *family, const char *style, float size)
bool SetSystemBold(const char *family, const char *style, float size)
-bool SetSystemFixed(const char *family, const char *style, float size)
-
-The system fonts settings may be set via these calls by specifying the family, style, and size. They return true if everything worked out ok and false if not. Settings are not changed if false is returned.
-1) Call _FindFamily on the family parameter. if NULL, return false
2) Call the family's GetStyle member. if NULL, return false
-3) if the appropriate system font pointer is non-NULL, delete it
-4) call the style's Instantiate member with the size parameter
-
-
-void RemoveUnusedFamilies(void)
-The purpose of this function is to allow for a complete rescan of the fonts in the appropriate directories.
-1) Iterate through the family list
A) Get a family
-B) if it has no dependents, remove it from the list and delete it
-2) Set the needs_update flag to true
-
-
-bool FontsNeedUpdated(void)
-Returns the value of the needs_update flag
FontStyle class : public SharedObject
-
-
FontStyle objects represent a font's look, such as bold, italics, etc.
-
-
-
Type Definitions
-
-typedef struct CachedFaceRec_
{
-BString file_path;
-uint32 face_index;
-} CachedFaceRec, *CachedFace;
-
-A record used in FreeType caching.
-
-Member Functions
-
|
- FontStyle(const char *filepath, FT_Face face) - |
-
- ~FontStyle(void) - |
-
|
- ServerFont *Instantiate(float size, float rotation=0.0, float shear=90.0) - |
-
- bool IsFixedWidth(void) - |
-
|
- bool IsScalable(void) - |
-
- bool HasKerning(void) - |
-
|
- bool HasTuned(void) - |
-
- uint16 GlyphCount(void) - |
-
|
- uint16 CharMapCount(void) - |
-
- const char *Style(void) - |
-
|
- FontFamily *Family(void) - |
-
- FT_Face GetFace(void) - |
-
|
- const char *GetPath(void) - |
-
- int16 ConvertToUni code(uint16 c) - |
-
-
-
-
FontStyle(const char *filepath, FT_Face face)
-
-1) set name from face
2) create a CachedFaceRec object and generate the handle as being the memory address converted to an integer. Assign the path from the parameter.
-3) set the path from the parameter
-4) set family to NULL
-5) create the instance list
-6) check to see if face object has ready-made strikes and set IsTuned flags as appropriate
-7) set fixed-width, kerning, and scalable flags as appropriate, based on face data
-8) get and assign glyph and charmap count
-9) set bounds to an invalid rectangle
-
-
-~FontStyle(void)
-1) delete all pointer objects
2) empty instance list, delete all attached instances, and delete the list
-
-
-ServerFont *Instantiate(float size, float rotation=0.0, float shear=90.0)
-Retrieves a specific instance of the font style, based on the size, rotation, and shear values
-1) create a new ServerFont object
2) add the new object to the instance list and return it
-
-
-bool IsFixedWidth(void)
bool IsScalable(void)
-bool HasKerning(void)
-bool HasTuned(void)
-uint16 GlyphCount(void)
-uint16 CharMapCount(void)
-const char *GetPath(void)
-FT_Face GetFace(void)
-
-These merely return the appropriate flags/values which are assigned values in the constructor.
-
-const char *Style(void)
-Returns the string value for the particular style.
-
-FontFamily *Family(void)
-Returns the pointer to the FontStyle object's family. Do NOT delete this pointer.
-
-int16 ConvertToUnicode(uint16 c)
-Converts a character code to a UTF-8 string
-1) Look up the face from the cache manager
2) Call FT_Get_Char_Index for the particular character code and return the value
-Layer class
-
-
The Layer class is responsible for working with invalid regions and serves as the shadow class for BViews.
-
-
-
|
- Layer(BRect frame, const char *name, int32 resize, int32 flags, ServerWindow *win) - |
-
- ~Layer(void) - |
-
|
- void AddChild(Layer *child, Layer *before=NULL, bool rebuild=true) - |
-
- RemoveChild(Layer *child, bool rebuild=true) - |
-
|
- void RemoveSelf(bool rebuild=true) - |
-
- void Invalidate(BRect r) - |
-
|
- void Invalidate(BRegion *region) - |
-
- BRect Frame(void) - |
-
|
- BRect Bounds(void) - |
-
- void MoveBy(BPoint pt) - |
-
|
- void MoveBy(float x, float y) - |
-
- void ResizeBy(BPoint pt) - |
-
|
- void ResizeBy(float x, float y) - |
-
- int32 CountChildren(void) - |
-
|
- bool IsDirty(void) - |
-
- BRect ConvertToTop(const BRect &r) - |
-
|
- BRegion ConvertToTop(const BRegion &r) - |
-
- BRect ConvertFromTop(const BRect &r) - |
-
|
- BRegion ConvertFromTop(const BRegion &r) - |
-
- BRect ConvertToParent(const BRect &r) - |
-
|
- BRegion ConvertToParent(const BRegion &r) - |
-
- BRect ConvertFromParent(const BRect &r) - |
-
|
- BRegion ConvertFromParent(const BRegion &r) - |
-
- void RebuildRegions(bool recursive=false) - |
-
|
- void MakeTopChild(void) - |
-
- void MakeBottomChild(void) - |
-
|
- void RequestDraw(const BRect &r) - |
-
- Layer *FindLayer(int32 token) - |
-
|
- Layer *GetChildAt(BPoint pt, bool recursive=false) - |
-
- PortLink *GetLink(void) - |
-
-
-Global Functions
-If there are any global functions associated with the class, they are listed here.
-
-
Layer(BRect frame, const char *name, int32 resize, int32 flags, ServerWindow *win)
-
-1) acquire a new layer token
2) validate (and fix, if necessary) parameters and assign to member objects
-3) initalize relation pointers to NULL
-4) set level to -1
-5) set invalid region to NULL
-6) set full and visible regions to bounds
-7) set child count to 0
-8) get ServerWindow's window port and create a PortLink pointed at it
-
-
-~Layer(void)
-1) if parent is non-NULL, call RemoveSelf()
2) if topchild is non-NULL, iterate through children and delete them.
-3) delete invalid, full, and visible regions if non-NULL
-4) delete the internal PortLink
-
-
-void AddChild(Layer *child, Layer *before=NULL, bool rebuild=true)
-Function which corresponds to BView::AddChild
-1) if child->parent is non-NULL, spew an error to stderr and return
2) set child->parent to this
-
- if before == NULL:
A) if topchild is non-NULL, set child->uppersibling to child
-B) set child->lowersibling to topchild
-C) if topchild is NULL, set bottomchild to child
-D) set topchild to child
-
-if before != NULL:
A) if before->upper is non-NULL, set child->upper to before->upper
-B) set before->upper to child
-C) set child->lower to before
-D) if child->upper is non-NULL, set child->upper->lower to child
-E) increment child's level
-3) increment the child count
-4) if rebuild flag is true, call RebuildRegions
-
-
-RemoveChild(Layer *child, bool rebuild=true)
-Function which corresponds to BView::RemoveChild
-1) if child's parent != this, spew an error to stderr and return
2) set child's parent to NULL
-3) set child's level to -1
-4) if top child matches child, set top child to child's lower sibling
-5) if bottom child matches child, set bottom child to child's upper sibilng
-6) if child->uppersibling is non-NULL, set its lowersibling to the child's lowersibling
-7) if child->lowersibling is non-NULL, set its uppersibling to the child's uppersibling
-8) decrement child count
-9) call RebuildRegions
-
-
-void RemoveSelf(bool rebuild=true)
-Function which corresponds to BView::RemoveSelf
-1) if parent is NULL, spew an error to stderr and return
2) call parent->RemoveChild(this)
-
-
-void Invalidate(BRect r)
void Invalidate(BRegion *region)
-
-Marks the area passed to the function as needing to be redrawn
-1) if parent is NULL, return
2) if the passed area intersects the layer's frame, add it to the invalid region, creating a new invalid object if necessary.
-3) Iterate through all child layers, calling child->Invalidate() on the area converted from the parent
-
-
-BRect Frame(void)
BRect Bounds(void)
-
-Frame() returns the layer's frame in its parent coordinates. Bounds() returns the frame offset to (0,0).
-
-void MoveBy(BPoint pt)
void MoveBy(float x, float y)
-
-Moves the layer in its parent's coordinate space by the specified amount
-1) offset the frame by the specified amount
2) if parent is non-NULL, call parent->RebuildRegions()
-
-
-void ResizeBy(BPoint pt)
void ResizeBy(float x, float y)
-
-Resizes the layer by the specified amount and all children as appropriate.
-1) resize the frame by the specified amount
2) iterate through all children, checking the resize flags to see whether each should be resized and calling child->ResizeBy() by the appropriate amount if it is necessary.
-
-
-int32 CountChildren(void)
-Returns the number of children owned directly by the layer - grandchildren not included and some assembly required. Instructions are written in Yiddish.
-
-bool IsDirty(void)
-Returns true if the layer needs redrawn (if invalid region is non-NULL).
-
-BRect ConvertToTop(const BRect &r)
BRegion ConvertToTop(const BRegion &r)
-
-Converts the given data to the coordinates of the root layer in the layer tree.
-1) if parent is non-NULL, return the data.
2) if parent is NULL, call this: return (parent->ConvertToTop( data_offset_by_frame.left_top ) )
-
-
-BRect ConvertFromTop(const BRect &r)
BRegion ConvertFromTop(const BRegion &r)
-
-Converts the given data from the coordinates of the root layer in the layer tree.
-1) if parent is non-NULL, return the layer's frame
2) if parent is NULL, call this: return (parent->ConvertFromTop( data_offset_by_frame.left_and_top * -1 ) )
-
-
-BRect ConvertToParent(const BRect &r)
BRegion ConvertToParent(const BRegion &r)
-
-Converts the given data to the coordinates of the parent layer
-1) return the data offset by the layer's frame's top left point, i.e. frame.LeftTop()
-
-BRect ConvertFromParent(const BRect &r)
BRegion ConvertFromParent(const BRegion &r)
-
-Converts the given data from the coordinates of the parent layer
-1) operates exactly like ConvertToParent, except that the offset values are multiplied by -1
-
-void RebuildRegions(bool recursive=false)
-Rebuilds the visible and invalid layers based on the layer hierarchy. Used to update the regions after a call to remove or add a child layer is made or when a layer is hidden or shown.
-1) get the frame
2) set full and visible regions to frame
-3) iterate through each child and exclude its full region from the visible region if the child is visible.
-4) iterate through each lowersibling and exclude its full region from the visible region if the it is visible and it intersects the layer's frame.
-
-
-void MakeTopChild(void)
-Makes the layer the top child owned by its parent. Note that the top child is "behind" other children on the screen.
-1) if parent is NULL, spew an error to stderr and return
2) if parent's top child equals this, return without doing anything
-3) if lowersibling and uppersibling are both NULL, return without doing anything
-4) save pointer to parent layer to a temporary variable
-5) call RemoveSelf and then the former parent's AddChild
-
-
-void MakeBottomChild(void)
-Makes the layer the bottom child owned by its parent. Note that the top child is "in front of" other children on the screen.
-1) if parent is NULL, spew an error to stderr and return
2) if parent's bottom child equals this, return without doing anything
-3) if lowersibling and uppersibling are both NULL, return without doing anything
-4) save pointer to parent layer to a temporary variable
-5) call RemoveSelf() with rebuild set to false
-6) call former parent's AddChild (rebuild is false), setting the before parameter to the former parent's bottomchild
-7) save lowersibling to a temporary variable
-8) call lowersibling->RemoveSelf() with no rebuild
-9) call the parent's AddChild() with the before set to this and rebuild set to true
-
-
-void RequestDraw(const BRect &r)
-Requests that the layer be drawn on screen. The rectangle passed is in the layer's own coordinates.
-1) if invalid is NULL, return
2) set the PortLink opcode to B_DRAW
-3) create a BMessage(B_DRAW) and attach all invalid rectangles to it
-4) attach the view token to the message
-4) flatten the message to a buffer, attach it to the PortLink, and Flush() it.
-5) recurse through each child and call its RequestDraw() function if it intersects the child's frame
-
-
-Layer *FindLayer(int32 token)
-Finds a child layer given an identifying token
-1) iterate through children and check tokens. Return a match if found.
2) iterate through children, calling its FindLayer function, return any non-NULL results
-3) return NULL - we got this far, so there is no match
-
-
-Layer *GetChildAt(BPoint pt, bool recursive=false)
-Gets the child at a given point. if recursive is true, all layers under the current one in the tree are searched. if the point is contained by the current layer's frame and no child is found, this function returns the current layer. if the point is outside the current layer's frame, it returns NULL
-1) if frame does not contain the point, return NULL
-
if recursive is true:
-A) start at the *bottom* child and iterate upward.
-B) if the child has children, call the child's GetChildAt with the point converted to the child's coordinate space, returning any non-NULL results
-C) if the child is hidden, continue to the next iteration
-D) if the child's frame contains the point, return the child
-E) if none of the children contain the point, return this
-
-if recursive is false:
A) start at the *bottom* child and iterate upward.
-B) if the child is hidden, continue to the next iteration
-C) if the child's frame contains the point, return the child
-D) if none of the children contain the point, return this
-
-
-PortLink *GetLink(void)
-Returns the layer's internal PortLink object so a message can be sent to the Layer's window.
PatternHandler class
-
-
PatternHandler provides an easy way to integrate pattern support into classes which require it, such as the DisplayDriver class.
-
-
-
-Member Functions
-
|
- PatternHandler(void) - |
-
- ~PatternHandler(void) - |
-
|
- void SetTarget(int8 *pattern) - |
-
- void SetColors(RGBColor c1, RGBColor c2) - |
-
|
- RGBColor GetColor(BPoint pt) - |
-
- RGBColor GetColor(float x, float y) - |
-
|
- bool GetValue(float x, float y) - |
-
- bool GetValue(BPoint pt) - |
-
-
-Enumerated Types
-pattern_enum
{
-uint64 type64
-uint8 type8 [8]
-}
-
-
PatternHandler()
-
-1) Initialize internal RGBColor variables to black and white, respectively.
2) Set internal pattern to B_SOLID_HIGH (all 1's)
-
-
-~PatternHandler()
-Empty
-
-void SetTarget(int8 *pattern)
-Updates the pattern handler's pattern. It copies the pattern passed to it, so it does NOT take responsibility for freeing any memory.
-1) cast the passed pointer in such a way to copy it as a uint64 to the pattern_enum.type64 member
-void SetColors(RGBColor c1, RGBColor c2)
-Sets the internal high and low colors for the pattern handler. These will be the colors returned when GetColor() is called.
-1) Assign c1 to high color and c2 to low color
-
-RGBColor GetColor(BPoint pt)
-RGBColor GetColor (float x, float y)
-bool GetValue(BPoint pt)
-bool GetValue (float x, float y)
-GetColor returns the color in the pattern at the specified location. GetValue returns true for the high color and false for the low color.
-1) xpos = x % 8, ypos = y % 8
-2) value = pointer [ ypos ] & ( 1 << (7 - xpos) )
3) GetValue: return (value==0)?false:true
-GetColor: return (value==0)?lowcolor:highcolor
-RGBColor class
-
-
RGBColor objects provide a simplified interface to colors for the app_server, especially the DisplayDriver class
-
-
-
-Member Functions
-
|
- RGBColor(uint8 r, uint8 g, uint8 b, uint8 a=255) - |
-
- RGBColor(rgb_color col) - |
-
|
- RGBColor(uint16 color16) - |
-
- RGBColor(uint8 color8) - |
-
|
- RGBColor(const RGBColor &color) - |
-
- RGBColor(void) - |
-
|
- void PrintToStream(void) - |
-
- uint8 GetColor8(void) - |
-
|
- uint16 GetColor16(void) - |
-
- rgb_color GetColor32(void) - |
-
|
- void SetColor(uint8 r, uint8 g, uint8 b, uint8 a=255) - |
-
- void SetColor(uint16 color16) - |
-
|
- void SetColor(uint8 color 8) - |
-
- void SetColor(rgb_color color) - |
-
|
- void SetColor(const RGBColor &col) - |
-
- Operators: =,==,!= - |
-
|
- RGBColor MakeBlendColor( RGBColor c, float position) - |
- - - | -
-
-
RGBColor(uint8 r, uint8 g, uint8 b, uint8 a=255)
-RGBColor(rgb_color col)
-RGBColor(uint16 color16)
-RGBColor(uint8 color8)
-RGBColor(const RGBColor &color)
-RGBColor(void)
-
-1) In all cases, extract the color data by calling SetColor. Void version sets to (0,0,0,0)
-
-void PrintToStream(void)
-Prints the color values of the color32 member via printf()
-uint8 GetColor8(void)
uint16 GetColor16(void)
-rgb_color GetColor32(void)
-
-These are for obtaining space-specific versions of the color assigned to the object.
-1) In all cases, return the internal color storage members
-
-void SetColor(const RGBColor &color)
-Copy all internal members to the current object.
-
-void SetColor(uint8 r, uint8 g, uint8 b, uint8 a=255)
void SetColor(rgb_color col)
-
-1) Assign parameters to internal rgb_color
2) call SetRGBAColor15()
-3) call SystemPalette::FindClosestColor()
-
-
-void SetColor(uint16 color16)
-1) Assign parameter to internal uint16
2) call SetRGBAColor32()
-3) call SystemPalette::FindClosestColor()
-
-
-void SetColor(uint8 color8)
-1) Assign parameter to internal uint8
2) Get the 32-bit value from the palette and assign it to the internal rgb_color
-3) call SetRGBAColor16()
-
-
-RGBColor & operator=(const RGBColor &from)
-Copy all data members over and return the value of this (return *this;)
-bool operator==(const RGBColor &from)
-Compare rgb_colors and if all members are equal, return true. Otherwise, return false.
-bool operator!=(const RGBColor &from)
-Compare rgb_colors and if all are equal, return false. Otherwise, return true.
-RGBColor MakeBlendColor(RGBColor c, float position)
-Returns a color which is (position * 100) of the way from the current color to the one passed to it. This would be an easy way to generate color gradients, for example, but with more control.
-1) Clip position to the range 0<=position<=1
2) For each color component,
-a) calculate the delta (delta=int16(c.component-thiscolor.component))
-b) calculate the modifier (mod=thiscolor.component+(delta * position))
-c) clip modifier to the range 0 <= modifier <= 255
-d) assign modifier to the component (thiscolor.component=int8(mod))
-3) return a new RGBColor constructed around the new color
-
-
ServerApp class
-
-
ServerApps are the server-side counterpart to BApplications. They monitor for messages for the BApplication, create BWindows and BBitmaps, and provide a channel for the app_server to send messages to a user application without having a window.
-
-
-
Member Functions
-
-
|
- ServerApp(port_id sendport, port_id rcvport, const char *signature, thread_id thread_bapp) - |
-
- ~ServerApp(void) - |
-
|
- bool Run(void) - |
-
- static int32 MonitorApp(void *data) - |
-
|
- void Lock(void) - |
-
- void Unlock(void) - |
-
|
- bool IsLocked(void) - |
-
- void WindowBroadcast(int32 code) - |
-
|
- bool IsActive(void) - |
-
- bool PingTarget(void) - |
-
|
- void DispatchMessage(int32 code, int8 *buffer) - |
- - - | -
-
-Global Functions
-
-
ServerApp(port_id sendport, port_id rcvport, const char *sig, thread_id thread_bapp)
-
-1) Create the window list as empty
2) Save sendport, rcvport, sig, and thread_bapp to the respective ServerApp members
-3) Set quit_app flag to false
-4) Create the window list lock
-
-
-~ServerApp(void)
-1) Empty and delete window list and accompanying windows
2) Wait for the monitoring thread to exit
-3) Call CursorManager::RemoveAppCursors(this)
-4) Delete the window list lock
-5) If monitoring thread still active, kill it (in case app is deleted without a quit message)
-
-
-bool Run(void)
-Run() simply makes a ServerApp start monitoring for messages from its BApplication, telling it to quit if there is a problem.
-1) Spawn the monitoring thread (which utilizes MonitorApp())
-2) If any error, tell the BApplication to quit, spit an error to stderr, and return false
3) Resume the monitoring thread
-4) Return true
-
-
-static int32 MonitorApp(void *data)
-Thread function for monitoring for messages from the ServerApp's BApplication.
-1) Call port_buffer_size - which will block if the port is empty
2) Allocate a buffer on the heap if the port buffer size is greater than 0
-3) Read the port
-4) Pass specified messages to DispatchMessage() for processing, spitting out an error message to stderr if the message's code is unrecognized
-5) Return from DispatchMessage() and free the message buffer if one was allocated
-6) If the message code matches the B_QUIT_REQUESTED definition and the quit_app flag is true, fall out of the infinite message-monitoring loop. Otherwise continue to next iteration
-7) Send a DELETE_APP message to the server's main message to force deleting of the ServerApp instance and exit
-
-
-
-bool IsActive(void)
-Used for determining whether the application is the active one. Simply returns the isactive flag.
-
-void PingTarget(void)
-PingTarget() is called only from the Picasso thread of the app_server in order to determine whether its respective BApplication still exists. BApplications have been known to crash from time to time without the common courtesy of notifying the server of its intentions. ;D
-1) Call get_thread_info() with the app's thread_id
2) if it returns anything but B_OK, return false. Otherwise, return true.
-
-
-void DispatchMessage(int32 code, int8 *buffer)
-DispatchMessage implements all the code necessary to respond to a given message sent to the ServerApp on its receiving message port. This allows for clearer and more manageable code.
-CREATE_WINDOW:
-Sent by a new BWindow object via synchronous PortLink messaging. Set up the corresponding ServerWindow and reply to the BWindow with the new port to which it will send future communications with the App Server.
-Attached Data:
-
|
- port_id reply_port - |
-
- port to which the server is to reply in response to the current message - |
-
|
- BRect wframe - |
-
- frame of the requesting BWindow - |
-
|
- uint32 wflags - |
-
- flag data of the requesting BWindow - |
-
|
- port_id win_port - |
-
- receiver port of the requesting BWindow - |
-
|
- uint32 workspaces - |
-
- workspaces on which the BWindow is to appear - |
-
|
- const char *title - |
-
- title of the requesting BWindow - |
-
-
-1) Get all attached data
2) Acquire the window list lock
-3) Allocate a ServerWindow object and add it to the list
-4) Release window list lock
-5) Send the message SET_SERVER_PORT (with the ServerWindow's receiver port attached to the reply port
-
-
-DELETE_APP:
-Sent by a ServerWindow when told to quit. It is identified by the unique ID assigned to its thread.
-Attached Data:
-
|
- thread_id win_thread - |
-
- Thread id of the ServerWindow sending this message - |
-
-
-1) Get window's thread_id
2) Acquire window list lock
-3) Iterate through the window list, searching for the ServerWindow object with the sent thread_id
-4) Remove the object from the list and delete it
-5) Release window list lock
-
-
-SET_CURSOR_DATA:
-Received from the ServerApp's BApplication when SetCursor(const void *) is called.
-
Attached Data:
-
-
|
- int8 cursor[68] - |
-
- Cursor data in the format as defined in the BeBook - |
-
-
-1) Create a ServerCursor from the attached cursor data
2) Add the new ServerCursor to the CursorManager and then call CursorManager::SetCursor
--
-SET_CURSOR_BCURSOR:
-
-Received from the ServerApp's BApplication when SetCursor(BCursor *, bool) is called.
-
Attached Data:
-
-
|
- int32 token - |
-
- Token identifier of cursor in the BCursor class - |
-
-
-1) Get the attached token and call CursorManager::SetCursor(token)
-
-B_QUIT_REQUESTED:
-Received from the BApplication when quits, so set the quit flag and ask the server to delete the object
-Attached Data: None
-1) Set quit_app flag to true
-
-UPDATE_DECORATOR:
-Received from the poller thread when the window decorator for the system has changed.
-Attached Data: None
-1) Call WindowBroadcast(UPDATE_DECORATOR)
-
-void WindowBroadcast(int32 code)
-Similar to AppServer::Broadcast(), this sends a message to all ServerWindows which belong to the ServerApp.
-1) Acquire window list lock
2) Create a PortLink instance and set its message code to the passed parameter.
-3) Iterate through the window list, targeting the PortLink instance to each ServerWindow's message port and calling Flush().
-4) Release window list lock
-
-
-void Lock(void)
void Unlock(void)
-bool IsLocked(void)
-
-These functions are used to regulate access to the ServerApp's data members. Lock() acquires the internal semaphore, Unlock() releases it, and IsLocked returns true only if the semaphore's value is positive.
ServerBitmap class
-
-
ServerBitmaps are the server side counterpart to BBitmap. Note that they are not allocated like other objects - the BitmapManager handles all allocation and deletion tasks.
-
-
-
-Member Functions
-
|
- ServerBitmap(BRect r, color_space cspace, int32 flags, int32 bytesperrow=-1, screen_id screen=B_MAIN_SCREEN_ID) - |
-
- void _HandleSpace(color_space cs, int32 bytesperline=-1) - |
-
|
- ~ServerBitmap(void) - |
-
- int32 BytesPerRow(void) - |
-
|
- uint8 *Bits(void) - |
-
- area_id Area(void) - |
-
|
- uint32 BitsLength(void) - |
-
- BRect Bounds(void) - |
-
-
-Global Functions
-If there are any global functions associated with the class, they are listed here.
-
-
ServerBitmap(BRect r, color_space cspace, int32 flags, int32 bytesperrow=-1, screen_id screen=B_MAIN_SCREEN_ID)
-
-1) Call _HandleSpace()
2) Call _HandleFlags()
-3) Initialize remaining data members to parameters or safe values
-
-
-~ServerBitmap(void)
-Empty
-
-uint8 *Bits(void)
-Returns the bitmap's buffer member
-
-area_id Area(void)
-Returns the bitmap's buffer member.
-
-uint32 BitsLength(void)
-Returns bytes_per_row * height
-
-BRect Bounds(void)
-returns BRect(width-1,height-1)
-
-int32 BytesPerRow(void)
-returns the bitmap's bytes_per_row member
-
-void _HandleSpace(color_space cs, int32 bytesperline=-1)
-Large function which essentially consists of a switch() of the available color spaces and assigns the bits per pixel and bytes per line values based on the color space. If bytesperline is -1, the default is used, otherwise it uses the specified value.
SharedObjectf class
-
-The FontStyle class represents the particular style in a font family, such as Bold, Roman, etc. and provides information on an individual font, such as whether it has a fixed width, whether it is scalable etc. It also houses all instances of the individual style.
-
Member Functions
-
-
|
- SharedObject(void) - |
-
- virtual SharedObject(void) - |
-
|
- virtual void AddDependent(void) - |
-
- virtual void RemoveDependent(void) - |
-
|
- virtual bool HasDependents(void) - |
- - - | -
-
-
SharedObject(void)
-
-1) Sets dependent count to 0
-
-virtual ~SharedObject(void)
-1) Does nothing
-
-virtual void AddDependent(void)
-1) Increments dependent count
-
-virtual void RemoveDependent(void)
-1) Decrements dependent count if greater than 0
-
-virtual bool HasDependents(void)
-1) if dependent count > 0, return true. Otherwise, return false.
SystemPalette class
-
-
This object does all the handling for system attribute colors and system palette management.
-
-
-
-Member Functions
-
|
- SystemPalette(void) - |
-
- ~SystemPalette(void) - |
-
|
- void SetPalette(uint8 index, RGBColor col) - |
-
- void SetPalette(uint8 index, rgb_color col) - |
-
|
- RGBColor GetPalette(uint8 index) - |
-
- void SetGUIColor(color_which which, RGBColor col) - |
-
|
- RGBColor GetGUIColor(color_which which) - |
-
- color_set GetGUIColors(void) - |
-
|
- void SetGUIColors(color_set cset) - |
-
- void _GenerateSystemPalette(rgb_color *palette) - |
-
|
- void _SetDefaultGUIColors(void) - |
- - - | -
-
-_ Denotes a protected function
-Structures
-color_set {
rgb_color panel_background
-rgb_color panel_text
-rgb_color document_background
-rgb_color document_text
-rgb_color control_background
-rgb_color control_text
-rgb_color control_border
-rgb_color control_highlight
-rgb_color tooltip_background
-rgb_color tooltip_text
-rgb_color menu_background
-rgb_color menu_selected_background
-rgb_color menu_text
-rgb_color menu_selected_text
-rgb_color menu_separator
-rgb_color menu_triggers
-}
-
-
SystemPalette(void)
-
-1) Allocate the rgb_color[256] palette on the heap and call _GenerateSystemPalette()
2) Initialize attribute variables to the defaults
-
-
-~SystemPalette(void)
-1) Free the palette array
-
-void SetPalette(uint8 index, RGBColor col)
void SetPalette(uint8 index, rgb_color col)
-
-Sets the said index to the passed color value.
-
-RGBColor GetPalette(uint8 index)
-Returns the color at said index in the palette.
-
-void SetGUIColor(color_which which, RGBColor col)
RGBColor GetGUIColor(color_which which)
-color_set GetGUIColors(void)
-void SetGUIColors(color_set cset)
-
-These tweak or return the system attribute colors, one at a time or all at once.
-
-protected: void _GenerateSystemPalette(rgb_color *palette)
-Sets the passed palette to the BeOS R5 system colors, which follows.
Grays:
-0,0,0 -> 248,248,248 by increments of 8
-Blues:
-0,0,255
-0,0,229
-0,0,204
-0,0,179
-0,0,154
-0,0,129
-0,0,105
-0,0,80
-0,0,55
-0,0,30
-Reds: as per blues, but red values are 1 less
-Greens: as per blues, but green values are 1 less
-0,152,51
-255,255,255
-
-The following sets use [255, 203, 152, 102, 51, 0] for the blue values, keeping the other colors the same:
-203,255, [value]
152,255, [value]
-102,255, [value]
-51,255, [value]
-255,152, [value]
-
-0,102,255
0,102,203
-
-203,203, [value]
152,255, [value]
-102,255, [value]
-51,255, [value]
-255,102, [value]
-
-0,102,152
0,102,102
-
-203,152, [value]
152,152, [value]
-102,152, [value]
-51,152, [value]
-
-230,134,0
-255,51, [value excepting 255]
-0,102,51
0,102,0
-
-203,102, [value]
152,102, [value]
-102,102, [value]
-51,102, [value]
-255,0, [value excepting 0]
-
-255,175,19
0,51,255
-0,51,203
-
-203,51, [value]
152,51, [value]
-102,51, [value]
-51,51, [value]
-
-255,203,102 -> 255,203,255, stepping in the [value] increments
-0,51, [value, starting at 152]
203,0, [value, excepting 0]
-
-255,227,70
-152,0, [value]
102,0, [value]
-51,0, [value]
-
-255,203,51
255,203,0
-
-255,255, [values in reverse]
-
-protected: void _SetDefaultGUIColors(void)
-Sets the internal color_set to the defaults, which is the following:
-panel_background: 216,216, 216
panel_text: 0,0,0
-document_background: 255,255,255
-document_text: 0,0,0
-control_background: 216,216,216
-control_text: 0,0,0
-control_border: 0,0,0
-control_highlight: 0,0,255
-tooltip_background:
-tooltip_text: 0,0,0
-menu_background: 216,216,216
-menu_selected_background: 160,160,160
-menu_text: 0,0,0
-menu_selected_text: 0,0,0
-menu_separator_high: 241,241,241
-menu_separator_low: 186,186,186
-menu_triggers: 0,0,0
-TokenHandler class
-
-This is a simple way to provide tokens for various reasons.
-
-Member Functions
-
|
- TokenHandler(void) - |
-
- ~TokenHandler(void) - |
-
|
- int32 GetToken(void) - |
-
- void Reset(void) - |
-
|
- void ExcludeValue(int32 value) - |
-
- void ResetExcludes(void) - |
-
|
- bool IsExclude(int32 value) - |
- - - | -
| - - | -- - | -
-
-
TokenHandler(void)
-
-1) Initialize the index to -1
2) create the access semaphore
-3) create the exclude list with no items
-
-
-~TokenHandler(void)
-1) delete the access lock
2) call ResetExcludes and delete the exclude list
-
-
-int32 GetToken(void)
-Returns a unique token which is not equal to any excluded values
-1) create a local variable to return the new token
2) acquire the access semaphore
-3) Increment the internal index
-4) while IsExclude(index) is true, increment the index
-5) assign it to the local variable
-6) release the access semaphore
-7) return the local variable
-
-
-void Reset(void)
-1) acquire the access semaphore
2) set the internal index to -1
-3) release the access semaphore
-
-
-void ExcludeValue(int32 value)
-1) acquire the access semaphore
2) if IsExclude(value) is false, add it to the exclude list
-3) release the access semaphore
-
-
-void ResetExcludes(void)
-1) acquire the access semaphore
2) Iterate through the exclude list, removing and deleting each item
-3) release the access semaphore
-
-
-bool IsExclude(int32 value)
-1) create a boolean match flag and set it to false
2) acquire the access semaphore
-3) iterate through the exclude list and see if the value matches any in the list
-4) If there is a match, set the match flag to true and exit the loop
-5) release the access semaphore
-6) return the match flag
-WinBorder class : public Layer
-
-
WinBorder objects provide window management functionality and ensure that the border for each window is drawn.
-
-
-
-Member Functions
-
|
- WinBorder(BRect r, const char *name, int32 resize, int32 flags, ServerWindow *win) - |
-
- ~WinBorder(void) - |
-
|
- void RequestDraw(void) - |
-
- void MoveBy(BPoint pt) - |
-
|
- void MoveBy(float x, float y) - |
-
- void ResizeBy(BPoint pt) - |
-
|
- void ResizeBy(float x, float y) - |
-
- void MouseDown(int8 *buffer) - |
-
|
- void MouseUp(int8 *buffer) - |
-
- void MouseMoved(int8 *buffer) - |
-
|
- void UpdateDecorator(void) - |
-
- void UpdateColors(void) - |
-
|
- void UpdateFont(void) - |
-
- void UpdateScreen(void) - |
-
|
- void RebuildRegions(bool recursive=true) - |
-
- void Activate(bool state) - |
-
-
-Global Functions
-bool is_moving_window(void)
void set_is_moving_window(bool state)
-bool is_resizing_window(void)
-void set_is_resizing_window(bool state)
-void set_active_winborder(WinBorder *win)
-WinBorder * get_active_winborder(void)
-
-Namespaces
-winborder_private {
bool is_moving_a_window
-bool is_resizing_a_window
-WinBorder *active_winborder
-}
-
-
WinBorder(BRect r, const char *name, int32 resize, int32 flags, ServerWindow *win)
-
-1) Pass parameters to Layer constructor
2) Instantiate a decorator
-3) Initialize visible and full regions via Decorator::GetFootprint()
-
-
-~WinBorder(void)
-1) Delete decorator instance
-
-void RequestDraw(void)
-Reimplements Layer::RequestDraw() because it has no corresponding BView
-1) if IsDirty()==false, return
2) Iterate through each BRect in the invalid region and call Decorator::Draw(BRect) for each invalid rectangle
-3) Perform recursive child calls as in Layer::RequestDraw()
-
-
-void MoveBy(BPoint pt)
void MoveBy(float x, float y)
-
-Moves the WinBorder's position on screen - reimplements Layer::MoveBy()
-1) Call the decorator's MoveBy()
2) Call Layer::MoveBy()
-
-
-void ResizeBy(BPoint pt)
void ResizeBy(float x, float y)
-
-Resizes the WinBorder - reimplements Layer::MoveBy()
-1) Call the decorator's ResizeBy()
2) Call Layer::ResizeBy()
-
-
-void MouseDown(int8 *buffer)
-Figures out what to do with B_MOUSE_DOWN messages sent to the window's border.
-1) Extract data from the buffer
2) Call the decorator's Clicked() function
-3) Feed return value to a switch() function (table below)
-4) Call the ServerWindow's Activate() function
-
-
|
- CLICK_MOVETOBACK - |
-
- call MoveToBack() - |
-
|
- CLICK_MOVETOFRONT - |
-
- call MoveToFront() - |
-
|
- CLICK_CLOSE - |
-
- 1) call SetCloseButton(true) -2) call decorator->DrawClose - |
-
|
- CLICK_ZOOM - |
-
- 1) call SetZoomButton(true) -2) call decorator->DrawZoom - |
-
|
- CLICK_MINIMIZE - |
-
- 1) call SetMinimizeButton(true) -2) call decorator->DrawMinimize - |
-
|
- CLICK_DRAG - |
-
- 1) call MoveToFront() -2) call set_is_win_moving(true) -3) Save the mouse position - |
-
|
- CLICK_RESIZE - |
-
- 1) call MoveToFront() -2) call set_is_win_resizing(true) - |
-
|
- CLICK_NONE - |
-
- do nothing - |
-
|
- default: - |
-
- Spew an error to stderr and return - |
-
-
-
-void MouseUp(int8 *buffer)
-Figures out what to do with B_MOUSE_UP messages sent to the window's border.
-1) Extract data from the buffer
2) Call the decorator's Clicked() function
-3) Feed return value to a switch() function (table below)
-4) if is_resizing_window, call set_is_resizing_window(false)
-5) if is_moving_window, call set_is_moving_window(false)
- -|
- CLICK_MOVETOBACK - |
-
- call MoveToBack() - |
-
|
- CLICK_MOVETOFRONT - |
-
- call MoveToFront() - |
-
|
- CLICK_CLOSE - |
-
- 1) call SetCloseButton(false) -2) call decorator->DrawClose -3) send B_QUIT_REQUESTED to the target BWindow - |
-
|
- CLICK_ZOOM - |
-
- 1) call SetZoomButton(false) -2) call decorator->DrawZoom -3) send B_ZOOM to the target BWindow - |
-
|
- CLICK_MINIMIZE - |
-
- 1) call SetMinimizeButton(false) -2) call decorator->DrawMinimize -3) send B_MINIMIZE to the target BWindow - |
-
|
- CLICK_DRAG - |
-
- call set_is_win_moving(false) - |
-
|
- CLICK_RESIZE - |
-
- call set_is_win_resizing(false) - |
-
|
- CLICK_NONE - |
-
- do nothing - |
-
|
- default: - |
-
- Spew an error to stderr - |
-
-
-
-void MouseMoved(int8 *buffer)
-Figures out what to do with B_MOUSE_MOVED messages sent to the window's border.
-1) Extract data from the buffer
2) Call the decorator's Clicked() function
-3) If not CLICK_CLOSE and decorator->GetClose is true, call SetClose(false) and DrawClose()
-4) If not CLICK_ZOOM and decorator->GetZoom is true, call SetZoom(false) and DrawZoom()
-5) If not CLICK_MINIMIZE and decorator->GetMinimize is true, call SetMinimize(false) and DrawMinimize()
-6) if CLICK_RESIZE or its variants, call CursorManager::SetCursor() with the appropriate system cursor.
-7) if is_moving_window() is true, calculate the amount the mouse has moved and call decorator->MoveBy() followed by Layer::MoveBy()
-8) if is_resizing_window() is true, calculate the amount the mouse has moved and call decorator->ResizeBy() followed by Layer::ResizeBy()
-
-
-void UpdateDecorator(void)
-Hook function called by the WinBorder's ServerWindow when the decorator used is changed.
-1) Delete the current decorator
2) Call instantiate_decorator
-3) Get the new decorator's footprint region and assign it to the full and visible regions
-4) Call RebuildRegions and then RequestDraw
-
-
-void UpdateColors(void)
-Hook function called by the WinBorder's ServerWindow when system colors change
-1) Call the decorator's SetColors(), passing the SystemPalette's GetGUIColors() value
-
-void UpdateFont(void)
-Hook function called by the WinBorder's ServerWindow when system fonts change
-TODO: implementation details
-
-void UpdateScreen(void)
-Hook function called by the WinBorder's ServerWindow when screen attributes change
-1) Call the decorator's UpdateScreen and then RequestDraw
-
-void RebuildRegions(bool recursive=true)
-Reimplementation of Layer::RebuildRegions which changes it such that lower siblings are clipped to the footprint instead of the frame.
-
-void Activate(bool state)
-This function is never directly called except from within set_active_winborder. It exists to force redraw and set the internal state information to the proper values for when a window receives or loses focus.
-1) call the decorator's SetFocus(state)
2) set the internal is_active flag to state
-3) iterate through each rectangle in the visible region and call the decorator's Draw on it.
-
-
-bool is_moving_window(void)
void set_is_moving_window(bool state)
-
-These two functions set and return the variable winborder_private::is_moving_a_window.
-
-bool is_resizing_window(void)
void set_is_resizing_window(bool state)
-
-These two functions set and return the variable winborder_private::is_resizing_a_window.
-
-void set_active_winborder(WinBorder *win)
WinBorder * get_active_winborder(void)
-
-These two functions set and return the variable winborder_private::active_winborder
App Server Interface Specification v0.3
-
-Purpose:
The app_server provides services to the OpenBeOS by managing processes, filtering and dispatching input from the Input Server to the appropriate applications, and managing all graphics-related tasks.
-
-Tasks:
The tasks performed by the app_server are grouped in relation to its purpose.
-
-Receives and redirects (dispatches) messages from the input server
-Responds to messages from apps
Receives and consolidates requests from BView, BWindow, BBitmap, and others to draw stuff (draw bitmap, etc)
-Utilizes ports to communicate with child processes
-Handles drag & drop messaging
-Manages the system clipboard
-
-Loads and Kills processes
Detects absence of Input Server and restarts when not running
-Aids in system shutdown
-
-Dynamically loads accelerant portion of graphics driver
Creates a connection with BBitmaps requiring a child view
-Draws the blue desktop screen
-Provides workspace support
-Provides functionality to the BeAPI for drawing primitives, such as rectangles, ellipses, and beziers
-Provides a means for BViews to draw on BBitmaps
-Manages window behavior with respect to redraw (move to front, minimize, etc)
-Returns a frame buffer to direct-access classes
-Caches fonts for screen and printer use
-Draws text and provides other font API support for the BeAPI classes
-
-Table of Contents
-Graphics:
I. Desktop Initialization
-II. Window management
-A. ServerApp
-B. ServerWindow
-C. Layer
-D. WindowBorder
-E. Decorator
-III. Screen updates
-IV. Cursor management
-V. Display Drivers
-Process Management:
-I. BApplication execution
-II. Non-BApplication execution
-III. Killing/Exiting applications
-IV. System Shutdown
-Input Processing:
-I. Input Server messages
-II. Mouse
-III. Keyboard
-Messaging:
-I. Inter-Application messaging
-II. Drag-and-drop
-III. Methods
-
-
-
-
-Graphics:
I. Desktop Initialization
-II. Window management
-III. Screen updates
-IV. Cursor management
-
-I. Desktop Initialization
-The graphics hardware is abstracted from the rest of the app_server. When started, the server creates the desktop, which is little more than a collection of workspaces. The desktop actually creates a DisplayDriver and then calls the driver's method Inititialize() before calling a few high-level routines for setup. Below is the process by which the HWDriver class, which is used to access the primary graphics card in the system, followed by the steps taken to set up the desktop.
-Load Accelerant
The app_server looks in three paths when scanning for an accelerant:
-/fd/beos/system/add-ons/app_server
-/boot/home/config/add-ons/app_server
-/boot/beos/system/add-ons/app_server
-
- When the app_server searches a path, it simply prints to the debug stream on the serial port a message akin "Attempting to load accelerant so-and-so" when loading the accelerant. Following this, it is loads the accelerant via load_add_on(), obtains the hook function control_graphics_card is via get_image_symbol, and control_graphics_card(OPEN_GRAPHICS_CARD) is called. If this returns an error, the image is unloaded after a control_graphics_card(CLOSE_GRAPHICS_CARD) is called and the server spits out a message like "So-and-so is not an acceptable driver" to the serial port. Assuming that the OPEN call succeeds, the app_server serial prints "Using so-and-so as accelerant." Hook functions are then acquired through control_graphics_card(B_GET_GRAPHICS_CARD_HOOKS). At this point, it is a good idea to have a palette generated for 8-bit mode (just in case we're going to use it), so the server generates the system palette. The palette on the graphics card is then set through many calls to control_graphics_card(B_SET_INDEXED_COLOR).
-Set up workspaces
Workspace preferences are read in from disk. If they exist, they are used; otherwise the default of 3 workspace, each with the settings 640x480x256@59.9Hz, is used. Each workspace is initialized to the proper information (preferences or default). Additionally, all settings are checked and possibly "clipped" by information gained through the driver class. With the desktop having been given the proper settings, the default workspace, 0, is activated.
-
-Display
Provided that everything has gone well so far, the screen is filled to the user-set workspace color or RGB(51,102,160) Also, the global clipboard is created, which is nothing more than a BClipboard object. The Input Server will notify the app_server of its existence, at which point the cursor will be set to B_HAND_CURSOR and shown on the screen.
-
-II. Window management
-Window management is a complicated issue, requiring the cooperation of a number of different types of elements. Each BApplication, BWindow, and BView has a counterpart in the app_server which has a role to play. These objects are Decorators, ServerApps, ServerWindows, Layers, and WindowBorders.
-A. ServerApps
-ServerApp objects are created when a BApplication notifies the app_server of its presence. In acknowledging the BApplication's existence, the server creates a ServerApp which will handle future server-app communications and notifies the BApplication of the port to which it must send future messages.
-ServerApps are each an independent thread which has a function similar to that of a BLooper, but with additional tasks. When a BWindow is created, it spawns a ServerWindow object to handle the new window. The same applies to when a window is destroyed. Cursor commands and all other BApplication functions which require server interaction are also handled. B_QUIT_REQUESTED messages are received and passed along to the main thread in order for the ServerApp object to be destroyed. The server's Picasso thread also utilizes ServerApp::PingTarget in order to determine whether the counterpart BApplication is still alive and running.
-B. ServerWindows
-ServerWindow objects' purpose is to take care of the needs of BWindows. This includes all calls which require a trip to the server, such as BView graphics calls and sending messages to invoke hook functions within a window.
-C. Layers
-Layers are shadowed BViews and are used to handle much BView functionality and also determine invalid screen regions. Hierarchal functions, such as AddChild, are mirrored. Invalid regions are tracked and generate Draw requests which are sent to the application for a specific BView to update its part of the screen.
-D. WindowBorders
-WindowBorders are a special kind of Layer with no BView counterpart, designed to handle window management issues, such as click tests, resize and move events, and ensuring that its decorator updates the screen appropriately.
-F. Decorators
-Decorators are addons which are intended to do one thing: draw the window frame. The Decorator API and development information is described in the Decorator Development Reference. They are essentially the means by which WindowBorders draw to the screen.
-G. How It All Works
-The app_server is one large, complex beast because of all the tasks it performs. It also utilizes the various objects to accomplish them. Input messages are received from the Input Server and all messages not specific to the server (such as Ctrl-Alt-Shift-Backspace) are passed to the active application, if any. Mouse clicks are passed to the ServerWindow class for hit testing. These hit tests can result in window tabs and buttons being clicked, or mouse click messages being passed to a specific view in a window.
-These input messages which are passed to a running application will sometimes cause things to happen inside it, such as button presses, window closings/openings, etc. which will cause messages to be sent to the server. These messages are sent either from a BWindow to a ServerWindow or a BApplication to a ServerApp. When such messages are sent, then the corresponding app_server object performs an appropriate action.
-III. Screen Updates
-Screen updates are done entirely through the BView class or some subclass thereof, hereafter referred to as a view. A view's drawing commands will cause its window to store draw command messages in a message packet. At some point Flush() will be called and the command packet will be sent to the window's ServerWindow object inside the server.
-The ServerWindow will receive the packet, check to ensure that its size is correct, and begin retrieving each command from the packet and dispatching it, taking the appropriate actions. Actual drawing commands, such as StrokeRect, will involve the ServerWindow object calling the appropriate command in the graphics module for the Layer corresponding to the view which sent the command.
-IV. Cursor Management
-The app_server handles all messiness to do with the cursor. The cursor commands which are members of the BApplication class will send a message to its ServerApp, which will then call the DisplayDriver's appropriate function. The DisplayDriver used will actually handle the drawing of the cursor and whether or not to do so at any given time.
-OpenBeOS R1 will also include the advent of an extension of the API: SetCursor(BBitmap *), which will accept a BBitmap of color space RGB(A)32, RGBA16, CMAP8, GRAY8, or GRAY1. Thus, color cursors and cursors which are not 16x16 are now supported.
-V. Display Drivers
-Unlike the BeOS R5 app_server, OpenBeOS' server will have a special feature: a modular graphics driver access class. The class is not actually the graphics driver, but, rather, a generalized interface which is implemented to interact with various destinations for graphics output. This allows the server to draw to a BWindow/BView combination, a BDirectWindow, or the actual frame buffer of a particular graphics card. All that the rest of the server needs to do is call whichever graphics function that is needed.
-Process Management:
I. BApplication execution
-II. Non-BApplication execution
-III. Killing/Exiting applications
-IV. System Shutdown
-
-I. BApplication execution
-Applications will come in two types: those which communicate with the app_server and take advantage of its services, and those which do not. To access the app_server, an application must be derived from BApplication.
-When a BApplication (referred to hereafter as a BApp) is executed, the app constructor creates its BLooper message port with the name AppLooperPort. This port's id, by means of BLooper, registers its port_id with the app_server so that the two can communicate with each other most easily.
-When the app_server receives notification that an app has been created, the server creates an AppMonitor (with accompanying thread) in its own team to handle messages sent to it and sends a reply with the port_id of the AppMonitor, to which all future messages are sent. These AppMonitor objects are stored in a global BList created for the storage of such things.
-II. non-BApplication execution
-Other applications do not communicate with the app_server. These applications have no access to app services and do not generally pass BMessages. This includes, but is not limited to, UNIX apps. The app_server ignores such applications except when asked to kill them.
-While, technically, these are not limited to being non-GUI applications, in practice these applications are command-line-only, for the application would be required to (1) render the app_server unable to access video hardware and (2) reinvent existing graphics code to load and use accelerants and draw onto the video buffer. This is extremely bad style and programming practice, not to mention more work than it is worth except in one case: the OpenBeOS app_server can coexist with the BeOS R5 app_server with some degree of peace because it can utilize extra video cards which the BeOS app_server does not use.
-III. Killing/Exiting Applications
-While the input server handles the Team Monitor window, the app_server actually takes care of shutting down teams, peacefully or not. Exiting an app is done simply by sending a B_QUIT_REQUESTED message to particular app. Killing an app is done via kill_team, but all the messy details are handled by the kernel itself through this call. When the user requests a team die via the Team Monitor, the Input Server sends a message to the app_server to kill the team, attaching the team_id. The app_server responds by happily nuking the respective team and notifies the registrar of its forcible removal from the roster.
-IV. System Shutdown
-Although the server maintains an internal list of running GUI applications, when a request to shut down the system is received by the app_server, it will pass the request on to the registrar, which will, in turn, increment its way through the app roster and request each app quit. When each quit request is sent, a timer is started and after timeout, the registrar will ask the server to kill the particular team and continue iterating through the application list.
-Input Processing:
I. Input Server messages
-II. Mouse
-III. Keyboard
-
-I. Input Server messages
-The Input Server collects information about keyboard and mouse events and forwards them to the app_server via messages. They are sent to port specifically for such messages, and the port is monitored by a thread whose task is to monitor, process, and dispatch them to the appropriate recipients. The Input Server is a regular BApplication, and unlike other applications, it requests a port to which it can send input messages.
-II. Mouse
-Mouse events consist of button changes, mouse movements, and the mouse wheel. The message will consist of the time of the event and attachments appropriate for each message listed below:
-B_MOUSE_DOWN
when
-location of the cursor
-button number
-modifiers
-clicks
-B_MOUSE_UP
-time
-buttons' status // not implemented for R5 but included for future expansion
-location of the cursor
-modifiers
-B_MOUSE_MOVED
-time
-location of the cursor
-buttons' status
-B_MOUSE_WHEEL_CHANGED
-time
-location of the cursor
-transit - in or out
-x delta
-y delta
-
-III. Keyboard
-Keyboard events consist of notification when a key is pressed or released. Any keypress or release will evoke a message, regardless of whether or not the key is mapped. The message will consist of the appropriate code and attachments listed below:
-B_KEY_DOWN
time
-key code
-repeat count
-modifiers
-states
-UTF-8 code
-string generated
-modifier-independent ASCII code
-B_KEY_UP
-time
-key code
-modifiers
-states
-UTF-8 code
-string generated
-modifier-independent ASCII code
-B_UNMAPPED_KEY_DOWN
-time
-key code
-modifiers
-states
-B_UNMAPPED_KEY_UP
-time
-key code
-modifiers
-states
-B_MODIFIERS_CHANGED // sent when a modifier key changes
-time
-modifier states
-previous modifier states
-states
-
-Nearly all keypresses received by the app_server are passed onto the appropriate application. Control-Tab, when held, is sent to the Deskbar for app switching. Command+F?? is intercepted and a workspace is switched. Left Control + Alt + Delete is not even intercepted by the app_server. The Input Server receives it and shows the Team Monitor window.
-Messaging:
I. Inter-Application messaging
-II. Drag-and-drop
-III. Methods
-
-I. Inter-Application Messaging
-The details of messaging are depicted under Process Management::BApplication.
-II. Drag-and-drop
-III. Methods
-Messaging with the app_server is not done using BMessages because of the overhead required to send them costs time and speed. Instead, ports are utilized indirectly by means of the PortLink class, which simply makes attaching data to a port message easier, but requires very little overhead.
-
-
|
An Introduction to the Input Server
-One of the many upcoming changes in the BeOS is in the world -of input devices and events. The Input Server, slated to -debut in R4, is a server that deals with all things "input." -Specifically, it serves three functions: manages input -devices such as keyboards and mice; hosts a stream of events -that those devices generate; and dispatches those events -that make it through the stream. - - -
-Managing Input Devices - - -
The Input Server is a pretty dumb piece of software. (Cue to
-Alex: roll your eyes and say, "What do you expect Hiroshi,
-you wrote it.") On its own, the server doesn't know how a
-keyboard or a mouse works; it relies on BInputServerDevice
-add-ons to tell it.
-
-
-
BInputServerDevice is a base class from which all input
-device add-ons must derive. It provides the basic framework
-of virtual hook functions and non-virtual member functions
-that the Input Server uses to communicate with an add-on,
-and that the add-on can use to talk back to the server. To
-give a sneak peak of the API, some of the virtuals include
-InitCheck(), Start(), Stop(), and Control(). The common
-sequence of the life of an input device is this:
-
-
BInputServerDevice-derived object.
-
-
-InitCheck() on the object. The
- object determines whether it is capable of doing its job
- -- that is, generating input events.
-
-
-/dev. If the object is happy, it registers with
- the Input Server any input device(s) it finds, and
- returns B_NO_ERROR. An error return causes the Input
- Server to promptly destruct the object and unload the
- add-on.
-
-
-Start(). The
- system automatically starts keyboards and mice at boot
- time. Any other type of device (an "undefined" input
- device that the system doesn't have any special knowledge
- about) can be started by an application using new API in
- the Interface Kit.
-
-
-Control()-ed at any time. Think of Control()
- as the ioctl() equivalent in input device parlance.
- Examples of system-defined control messages include
- keymap changes and mouse speed changes.
--Generating Input Events - - -
Once a BInputServerDevice-derived object's input device is
-up and running, its primary task is to generate input
-events. These events are expressed as BMessages. For
-example, a keyboard input device will most likely generate
-B_KEY_DOWN and B_KEY_UP messages. Similarly, a mouse input
-device will probably generate B_MOUSE_UP, B_MOUSE_DOWN, and
-B_MOUSE_MOVED events.
-
-
-
There is nothing that prevents an input device from putting
-arbitrary data in any of the BMessages it generates. So, for
-example, a tablet may generate the aforementioned mouse
-events with extra data such as pressure and proximity. Any
-information packed into the BMessages is delivered
-unmolested by the input server.
-
-
-
When an event is ready to be shipped off, an input device
-enqueues it into the Input Server's event stream. Some
-BHandler (most likely a BView) down the line eventually
-receives the event by way of the usual hook functions such
-as KeyDown(), MouseDown(), and MouseMoved().
-
-
-
-The Input Event Stream - - -
The Input Server's event stream is open for inspection and
-alteration by anyone in the system. This is achieved through
-another set of add-ons called BInputServerFilter. Like
-BInputServerDevice, BInputServerFilter is a base class for input filter add-ons to the Input Server.
-
-
-
An input filter add-on is privy to all the events that pass
-through the Input Server's event stream. A filter may
-inspect, alter, generate, or completely drop input events.
-It's similar in some ways to the Interface Kit's
-BMessageFilter, but much more low-level. A
-BInputServerFilter sees all events that exist in the system;
-BMessageFilters are associated with a specific BLooper and
-thus see only the events targeted to its BLooper. Also,
-filters in the Input Server can generate additional events
-in place of, or in addition to, the original input event
-that it was invoked with.
-
-
-
-Conclusion - - -
With the introduction of loadable input device objects, the -Input Server enables the BeOS to be used with a wide variety -of input devices (and more than one of them at once too). -And with the advent of input filters, the Input Server opens -the door to a new class of tricks, hacks, and (gulp) pranks -for the creative developer. It's going to be fun. - - -
-
-
-
diff --git a/docs/develop/servers/input/objdump-inputserver b/docs/develop/servers/input/objdump-inputserver
deleted file mode 100644
index 06ffc764ab..0000000000
--- a/docs/develop/servers/input/objdump-inputserver
+++ /dev/null
@@ -1,104 +0,0 @@
-00000000 l df *ABS* 00000000 InputServer.cpp
-00000000 l df *ABS* 00000000 InputServerDevice.cpp
-00000000 l df *ABS* 00000000 InputServerFilter.cpp
-00000000 l df *ABS* 00000000 InputServerMethod.cpp
-000245c0 g O .bss 0000000c InputServer type_info node
-000164cc g F .text 0000002f BInputServerDevice::StartMonitoringDevice(char const *)
-000245ec g O .bss 0000000c BInputServerMethod type_info node
-0001fce0 w O .data 00000058 BInputServerDevice virtual table
-00016584 g F .text 00000009 BInputServerDevice::Stop(char const *, void *)
-00016550 g F .text 00000026 BInputServerDevice::RegisterDevices(input_device_ref **)
-00012e64 g F .text 00000207 InputServer::QuitRequested(void)
-00024580 g O .bss 00000020 InputServer::fMouseState
-00016720 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod2(void)
-000151bc g F .text 0000010f InputServer::HandleGetSetMouseAcceleration(BMessage *, BMessage *)
-0001620c g F .text 000000df InputServer::EnqueueMethodMessage(BMessage *)
-00014f9c g F .text 0000010f InputServer::HandleGetSetMouseType(BMessage *, BMessage *)
-00016008 g F .text 0000001d InputServer::EventLoopRunning(void)
-00015b1c g F .text 0000003e InputServer::UnlockMethodQueue(void)
-0001612c g F .text 000000cf InputServer::StartStopDevices(char const *, input_device_type, bool)
-000157f8 g F .text 00000323 InputServer::EventLoop(void *)
-00018834 g F .text 00000157 MethodReplicant::SendToInputServer(BMessage *)
-0001b000 g O .rodata 00000022 kInputServerSignature
-00015690 g F .text 00000165 InputServer::HandleSetMethod(BMessage *)
-00016578 g F .text 00000009 BInputServerDevice::Control(char const *, void *, unsigned long, BMessage *)
-00024620 g O .bss 00000008 BInputServerFilter type_info node
-000166b0 g F .text 0000002f BInputServerFilter::~BInputServerFilter(void)
-00014c3c g F .text 0000010f InputServer::HandleGetSetKeyRepeatDelay(BMessage *, BMessage *)
-00013ce0 g F .text 000001ea InputServer::MethodizeEvents(BList *, bool)
-0001cd35 g O .data 00000001 InputServer::sEventLoopRunning
-00015bec g F .text 00000053 InputServer::HandleGetKeyInfo(BMessage *, BMessage *)
-00015b5c g F .text 00000048 InputServer::LockMethodQueue(void)
-00016834 g F .text 0000002d BInputServerMethod::~BInputServerMethod(void)
-00016494 g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice1(void)
-0001631c g F .text 00000026 InputServer::ReadyToRun(void)
-0001fd40 w O .data 00000040 BInputServerFilter virtual table
-00015d8c g F .text 00000077 InputServer::SetNextMethod(bool)
-0001306c g F .text 000002f2 InputServer::InitKeyboardMouseStates(void)
-00013360 g F .text 000000ff InputServer::InitMethods(void)
-00019ddc w F .text 00000045 InputServer::~InputServer(void)
-0001662c g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter1(void)
-0001649c g F .text 0000002f BInputServerDevice::StopMonitoringDevice(char const *)
-0001fb60 w O .data 00000180 InputServer virtual table
-00015ba4 g F .text 00000045 InputServer::HandleGetModifiers(BMessage *, BMessage *)
-000148e0 g F .text 000001ef InputServer::HandleSetModifierKey(BMessage *, BMessage *)
-000165a8 g F .text 00000009 BInputServerDevice::InitCheck(void)
-00013794 g F .text 00000549 InputServer::SanitizeEvents(BList *)
-00016710 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod4(void)
-000166e0 g F .text 00000023 BInputServerFilter::BInputServerFilter(void)
-000167ac g F .text 00000027 BInputServerMethod::SetIcon(unsigned char const *)
-00014800 g F .text 000000dd InputServer::HandleSetKeyboardLocks(BMessage *, BMessage *)
-00019d98 w F .text 00000041 InputServer type_info function
-000165b4 g F .text 0000002f BInputServerDevice::~BInputServerDevice(void)
-00016528 g F .text 00000026 BInputServerDevice::UnregisterDevices(input_device_ref **)
-000165e4 g F .text 0000002d BInputServerDevice::BInputServerDevice(void)
-00014e5c g F .text 0000013f InputServer::HandleGetSetMouseMap(BMessage *, BMessage *)
-000135e8 g F .text 000001ab InputServer::DoMouseAcceleration(long *, long *)
-00015ec4 g F .text 0000004e InputServer::SetMousePos(long *, long *, long, long)
-00015c88 g F .text 00000103 InputServer::SetActiveMethod(_BMethodAddOn_ *)
-00019ed8 w F .text 00000041 BInputServerMethod type_info function
-0001277c g F .text 000006e5 InputServer::MessageReceived(BMessage *)
-000162ec g F .text 0000002e InputServer::EnqueueDeviceMessage(BMessage *)
-000167d4 g F .text 00000027 BInputServerMethod::SetName(char const *)
-00016624 g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter2(void)
-00016028 g F .text 0000001d InputServer::SafeMode(void)
-00016590 g F .text 00000009 BInputServerDevice::Start(char const *, void *)
-00016484 g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice3(void)
-00016614 g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter4(void)
-00016728 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod1(void)
-0001648c g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice2(void)
-0001cd34 g O .data 00000001 InputServer::sSafeMode
-00016698 g F .text 0000000c BInputServerFilter::Filter(BMessage *, BList *)
-000144d0 g F .text 0000032e InputServer::DispatchEvents(BList *)
-000140dc g F .text 000003f4 InputServer::CacheEvents(BList *)
-000124f0 g F .text 0000028b InputServer::InputServer(void)
-0001647c g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice4(void)
-00016828 g F .text 00000009 BInputServerMethod::MethodActivated(bool)
-00016344 g F .text 00000079 InputServer::ArgvReceived(long, char **)
-000150ac g F .text 0000010f InputServer::HandleGetSetMouseSpeed(BMessage *, BMessage *)
-00013460 g F .text 00000186 InputServer::GetNextEvents(BList *)
-000153dc g F .text 00000155 InputServer::HandleSetMousePosition(BMessage *, BMessage *)
-0001661c g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter3(void)
-00019e68 w F .text 00000035 BInputServerDevice type_info function
-00016864 g F .text 00000097 BInputServerMethod::BInputServerMethod(char const *, unsigned char const *)
-000164fc g F .text 00000029 BInputServerDevice::EnqueueMessage(BMessage *)
-00015fc8 g F .text 0000003f InputServer::InitFilters(void)
-000166a4 g F .text 00000009 BInputServerFilter::InitCheck(void)
-000167fc g F .text 00000029 BInputServerMethod::EnqueueMessage(BMessage *)
-00013ecc g F .text 0000020d InputServer::FilterEvents(BList *)
-000161fc g F .text 00000010 InputServer::MethodReplicant(void) const
-00015c40 g F .text 00000046 InputServer::HandleGetKeyboardID(BMessage *, BMessage *)
-000152cc g F .text 0000010f InputServer::HandleGetSetClickSpeed(BMessage *, BMessage *)
-0001659c g F .text 00000009 BInputServerDevice::SystemShuttingDown(void)
-0001fd80 w O .data 00000068 BInputServerMethod virtual table
-00024728 g O .bss 00000008 BInputServerDevice type_info node
-00016730 g F .text 0000007c BInputServerMethod::SetMenu(BMenu const *, BMessenger)
-00016048 g F .text 000000e3 InputServer::ControlDevices(char const *, input_device_type, unsigned long, BMessage *)
-00015534 g F .text 0000015b InputServer::HandleFocusUnfocusIMAwareView(BMessage *, BMessage *)
-00019ea0 w F .text 00000035 BInputServerFilter type_info function
-00016718 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod3(void)
-00015f14 g F .text 000000b4 InputServer::SetMousePos(long *, long *, BPoint)
-00014d4c g F .text 0000010f InputServer::HandleGetSetKeyRepeatRate(BMessage *, BMessage *)
-00014ad0 g F .text 0000016c InputServer::HandleGetSetKeyMap(BMessage *, BMessage *)
-00015e04 g F .text 000000bf InputServer::SetMousePos(long *, long *, float, float)
-00016634 g F .text 00000061 BInputServerFilter::GetScreenRegion(BRegion *) const
diff --git a/docs/develop/servers/registrar/Protocols b/docs/develop/servers/registrar/Protocols
deleted file mode 100644
index 4360e6b9b8..0000000000
--- a/docs/develop/servers/registrar/Protocols
+++ /dev/null
@@ -1,1028 +0,0 @@
-Protocols
-=========
-
-Standard Replies
-----------------
-
-standard success reply message
-
-reply: B_REG_SUCCESS
- [ SEO Count - Keyword Ranking Tool - Frequently Asked Questions eBay Hacks - Frequently Asked Questions Free SOAP Resources, freeprogrammingresources.com FAQ: SEO Search Engine Optimization Frequently Asked Questions Among Other Things Google API Cocoa framework FAQ: Very Frequently Asked Questions (with answers) v1.29 comp.lang.prolog Frequently Asked Questions Chat11.com: SEM - Paid Inclusion Doesn't Seem To Be Helping Data Transformation Services for SQL Server 2005: Frequently Asked ... Programming Articles on webservices.xml.com Google launches its Deskbar API Java FAQ - Frequently Asked Questions Frequently Asked Questions - comp.lang.java.gui Search engine articles, tools, links and resources hey Google - don't auto-update my toolbar! hey Google - don't auto-update my toolbar! Michel Olagnon's Fortran 90 List Frequently Asked Questions - Confluence Frequently Asked Questions - Confluence Bookmarks for bradg@videotron.ca Resources for Java server-side developers: CLDC - Bluetooth API ... Vivsimo // Frequently Asked Questions DataPower: Technical Resources Search Results | MySmartChannels Macromedia -UltraDevTechNotes:UltraDev Technical FAQ (Frequently ... Mensniche.com Forum - Main Forum Bookshare.org - Book Information Bookshare.org - Books by Author Java Programming FAQs and Tutorials: Learning Java Keyword density research report - Best Practices Search Engine ... Recommended Reading List / Answers to Frequently Asked Questions XMLhub.com Web Directory: Computers: Programming: Languages ... Forum FAQ - GameDev.Net Discussion Forums NDIS Frequently Asked Questions Managing CruiseControl With JMX - Confluence FWE - National Headquarters - Job Search - View Job The Star Online Directory - FAQs, Help, and Tutorials eMarketing Resources @ Spherica Building XML Web Services with .NET: Hands-On - Course FAQ
-
-
Web Images GroupsNew! News Froogle more » Advanced Search
Preferences Web Results 1 - 50 of about 12,800 English pages over the past 3 months for google api help "frequently asked" -plop. (0.40 seconds) Sponsored Links Google Help
Better Understand Your Results &
Learn Fun Facts Too. Get More Info!
www.GoogleStore.comSee your message here... ... a custom Java client library, documentation on how to use the ... You can find it at
-http://api.google.com/GoogleSearch.wsdl ... need to get started is in googleapi.jar ...
-
www.google.com/apis/api_faq.html - 29k - Frequently Asked Questions. ... that Google only indexes the www version to help increase
-Page ... Since the Google API provides results for UTF-8 Encoding we are able ...
-
www.seocount.com/faq.php - 16k - ... If you need help getting started with eBay, you'd ... is concerned with programming and
-the eBay API; that leaves ... 5.36934319 10 41 Joules, as reported by Google ...
-
www.ebayhacks.com/exec/show/book_faq - 8k - 5 Dec 2004 - ... The Google API is used as an example. ... Tutorials, Links FAQs. ... This page explains how
-to get started editing the home page of your Manila site using SOAP to make ...
-
www.freeprogrammingresources.com/soap.html - ... come from the Top25Web.com server, and it is using the Google API which was recently
-made available by Google. ... Post a message in our forums for more help! ...
-
www.top25web.com/faq.html - 15k - ... to be using the Google API for something ... NetBSD/dreamcast NetBSD/dreamcast: How to
-use NetBSD/dreamcast NetBSD/dreamcast Frequently Asked Questions The ...
-
interalia.org/archives/2003/ 03/24/google-api-cocoa-framework - 48k - ... www.googleguide.com/searchLeader.html; Google's Online Help: Google Help Central -
-www.google.com/help/; ... Google Web API - www.google.com/apis/ API stands ...
-
www.googleguide.com/links.html - 12k - 6 Dec 2004 - ... some of the questions that are most frequently asked in comp ... Google search:
-<URL:http://groups.google.com/groups ... URLs contain information on how to reinstate ...
-
www.codecomments.com/Clipper/message320018.html - 23k - ... For details on how to join or send in contributions, check ... readers who would be glad
-to help people making a ... Yes, there are: Google Groups has archives of news ...
-
www.codecomments.com/Prolog/message321541.html - 42k -
[ More results from www.codecomments.com ]... Frequently Asked Questions. ... Since the API is entirely modular, we are looking for
-people who can help fix bugs or add enhancements to the project. ...
-
open.echomine.org/cowiki/20.html - 36k - ... Google, ... I Thought Paid Inclusion Would Help, So Why Are My Pages Not Ranked Better? ...
-Our Tutorial About How To Increase Visitors To Your Website. ...
-
www.chat11.com/ SEM_-_Paid_Inclusion_Doesn't_Seem_To_Be_Helping - 17k - ... Tuesday, November 23, 2004. .: Home Articles/Tutorials SQL_Server : Data Transformation
-Services for SQL Server 2005: Frequently Asked Design Questions. ...
-
www.wwwcoder.com/main/parentid/ 191/site/3373/68/default.aspx - 47k - ... month's XML Endpoints column, Rich Salz explains how to process SOAP ... Google's Gaffe.
-By Paul Prescod Paul Prescod explains why moving its API to use ...
-
webservices.xml.com/programming/ - 38k - 5 Dec 2004 - ... This is a nice site found using Google: ... Borland Delphi and HH. Free code examples
-show you how to program the HTML Help API via Borland Delphi. ...
-
www.helpware.net/FAR/far_faq.htm - 101k - 5 Dec 2004 - ... Frequently Asked Questions, Getting Started with Radio UserLand, Tips, and Tutorials. ...
-Using the Google API with Radio and Frontier - How to make requests ...
-
ruminations.weblogger.com/ - 27k - 5 Dec 2004 - ... a big difference in your rankings and our most popular ** How To ** section The ... Deskbar
-API can be found here: http://deskbar.google.com/help/api/index.html ...
-
news-01.rankforsales.com/news-bf/889-seo-nov-22-04.html - 18k - 6 Dec 2004 - ... Search google. ... The JAI API is the subject of discussion in this Sun sponsored mailing ...
-Java FAQ is written and maintained by Andrew Thompson, with help from the ...
-
www.physci.org/codes/javafaq.jsp - 53k - ... first document has requested a notice that he is not a help desk for ... 7.10 Java 3D
-API. ... see news:comp.lang.java.3d http://groups.google.com/groups?group=comp.lang ...
-
www.physci.org/guifaq.jsp - 44k - ... Asked Questions (FAQ) An old Frequently Asked Questions list ... sample source code which
-illustrates how to use the ... SOAP library to call the Google API from PHP. ...
-
www.googleduel.com/about.php - 12k - ... Search Engine Help by Highrankings Search Engine Features Chart ... top Guide to frames
-usage How to Optimize a ... Enumeration Google Count - uses Google API Go Rank ...
-
www.bearcanyonseo.com/tips_links.html - 29k - ... Most Frequently Asked Questions On using OpenOffice.org software in ... printing with
-the binaries, the help system, licensing ... API FAQ Questions and answers on the ...
-
www.openoffice.org/faq.html - 10k - Google Toolbar, Desktop Search, and API Topics. ... Google, there is absolutely no need
-for this. ... Asked Questions section of the toolbar help: http://toolbar.google ...
-
www.webmasterworld.com/forum80/457-9-10.htm - Google Toolbar, Desktop Search, and API Topics. ... then the very first link is to the
-toolbar help page. ... If Google is willing to support use of the toolbar without ...
-
www.webmasterworld.com/forum80/457-10-10.htm -
[ More results from www.webmasterworld.com ]... programs and Microsoft Windows Open Database Connectivity (ODBC) API. ... 3.7 - Other
-places for Help on Fortran 90. ... ftp.cs.unm.edu; Free Software; How to get Fortran ...
-
www.kcl.ac.uk/kis/support/cc/fortran/engfaq.html - 56k - ... exporting, searchable attachments, a comprehensive remote API, easy installation ...
-starting up to tell it how to use its ... If you need help with a particular server ...
-
confluence.atlassian.com/ display/DOC/Frequently+Asked+Questions - 35k - 5 Dec 2004 - ... I figured-out how to add an inline image. ... page hierachies, page subscription, online
-help, WebDAV file storage, a more comprehensive remote API... ...
-
confluence.atlassian.com/display/DOC/ Frequently+Asked+Questions?focusedCommentId=11067 - 72k -
[ More results from confluence.atlassian.com ]... The Mother of All Search Engines Google SEARCH.COM ... J2EE API Java(TM) SE Platform
-Documentation Servlets ... Franck Allimant - Accueil (Win JDK Help Files) Getting ...
-
pages.videotron.com/gbradet/home_bm.htm - 30k - ... Applications by Qusay H. Mahmoud This two-part series of articles will show you
-how to use J2ME ... Home > J2ME Technologies > CLDC - Bluetooth API (JSR-82). Google, ...
-
www.java201.com/resources/browse/126-all.html - 13k - ... just a small sampling of who we can help: Researchers; Support ... well we work on top
-of the Google Appliance ... delivered as aC software library with an API; they run ...
-
vivisimo.com/html/faq - 31k - ... Headers DataPower chief security architect Rich Salz explains how to process SOAP ...
-of WSDL, with particular reference to the new Google web services API. ...
-
www.datapower.com/xmldev/tech_resources.html - 19k - 5 Dec 2004 - ... Search Google, ... MySmartChannels I agree that actually trying out the different SQL
-functions on a computer will help with the ... Is there an API to MySmartChannels? ...
-
myst-technology.com/mysmartchannels/ public/search?q=mysmartchannels&scheme=standalone - 101k - ... Printable instructions on how to create objects and server behaviors using UltraDev's
-JavaScript API are available ... Search powered by Powered by Google.
-
www.macromedia.com/support/ ultradev/ts/documents/ultradev_faq.htm - 28k - ... SG Forum - Great Resource; need help; PPC Results; 404 Traffic; www.volume ... Meta Tags
-Optimization; Pre-Sell; Google PageRank, & How to Get It; Nice Google API tool ...
-
mensniche.com/forum/archive/index.php/f-2.html - 15k - ... new Google API, including how to build and modify scripts that can become custom
-business applications based on Google. Google Hacks contains 100 tips, tricks ...
-
www.bookshare.org/web/SingleTitle. html?submittitleid=19778 - 18k - ... advanced search interface and the new Google API, including how ... Google Hacks contains
-100 tips, tricks and scripts ... tips, tricks, and tools to help serious Mac ...
-
www.bookshare.org/web/ BooksByAuthor.html?author_id=10726 - 29k - ... PHP Implementation of the Google Web API System 26 ... Promotion Google ranking tips
-Google's AdWords Advertising Program How to Advertise Responsibly ...
-
www.page87.net/links/ - 70k - ... Its an AppleScript which calls the Google API and gets the top result for your
-query. ... Frequently Asked Questions. ... Help define the site. =-). ...
-
www.iwalt.com/weblog/2002/04/ - 39k - ... Search the Web: Google. ... Tutorials, online courses and more, to help you pass your
-Java certification ... Learning how to generate high-quality printouts of components ...
-
www.apl.jhu.edu/~hall/java/FAQs-and-Tutorials.html - 21k - ... everything come from the Google API? Did Google have to approve this? If so,
-do you have any tips on getting API applications approved? ...
-
www.ihelpyouservices.com/forums/ showthread.php?s=&threadid=13023 - 63k - ... Guide Clark Connect Help Downloadable User Guides Webconfig API (For those ... relay
-host(I can't send email) Help, I can ... Also, don't forget to google Note: All the ...
-
www.clarkconnect.org/forums/showflat. php?Cat=&Board=howtos&Number=40192 - 31k - ... Microsoft: Visual FoxPro v3.0+ - Technical support forums and mutual help system
-for ... Usenet microsoft.public.fox.vfp.lck-api - news: - Google Groups; Usenet ...
-
www.xmlhub.com/dir/index/Computers/ Programming/Languages/Visual_FoxPro/ - 18k - ... If you're looking for API specific tutorials, here are some of the most common to
-help get you ... could easily answer yourself with a quick Google search or a ...
-
www.gamedev.net/community/ forums/showfaq.asp?forum_id=31 - 32k - 5 Dec 2004 - ... The Microsoft DDK help file and DDK samples, as well as ... On the other hand, the
-user-mode WMI API is fairly ... useful information is to perform a Google Search on ...
-
www.ndis.com/faq/QA10290101.htm - 35k - ... It is ridiculously easy to enable controling CC using the JMX (Java Mananagement
-eXtensions) api. Here's what you get : ... How to enable the JMX server. ...
-
confluence.public.thoughtworks.org/ display/CC/Managing+CruiseControl+With+JMX - 26k - 6 Dec 2004 - ... Gone Wild General RSS Stuff Hardware Help HijackThis Logs ... And why has the Google
-API stagnated for 2.5 years ... So what should Google, MSNbot and Yahoo search (to ...
-
chris.pirillo.com/blog/cmd=post_comment/ article_id=119543/parent_id=165843 - 57k - ... Northwest-Software Engineering GOOGLE - C++, Win32 API, and Linux Kernel Engineering
-Opportunities POSTED: 9/30/2004 JOB TITLE: Software Engineer Google is ...
-
www.fwe.org/p/p.asp?mlid=354&jid=1018 - 43k - ... be able to find packages using Google. ... EWH32.api , printme.api and search.api from
-plug_ins_disabled ... can convert the bookmarks with the help from BookmarkPriest ...
-
www.mozilla.org/support/firefox/faq - 35k - 5 Dec 2004 - ... Active Server Pages, and the Internet Server API. ... public.inetserver.iis.activeserverpages
-- news: - Google Groups. Help build the largest human-edited directory ...
-
directory.thestar.com.my/cat.asp?/Computers/ Programming/Internet/ASP/FAQs,_Help,_and_Tutorials/ - 15k - ... Rank Checker SEO Count Advanced API Rank Checker ... Google AdWords Keyword Suggestion
-Tool Additional eTools Spider ... Index: Simple formula to help determine the ...
-
www.spheri.ca/resources.html - 18k - 5 Dec 2004 - ... Web services currently available include the Google API, Microsofts ... You learn how
-to use the .NET System.Xml class ... Does this course help me prepare for the ...
-
www.learningtree.com/courses/508qa.htm - 29k -
Search within results | Language Tools | Search Tips | Dissatisfied? Help us improveGoogle Home - Advertising Programs - Business Solutions - About Google
©2004 Google