Games-Axmud
view release on metacpan or search on metacpan
lib/Games/Axmud/Obj/Desktop.pm view on Meta::CPAN
# Copyright (C) 2011-2024 A S Lewis
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
# General Public License as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not,
# see <http://www.gnu.org/licenses/>.
#
#
# Games::Axmud::Obj::Desktop
# The main desktop object. Arranges windows on one or more workspaces, each containing one or more
# workspace grids
{ package Games::Axmud::Obj::Desktop;
use strict;
use warnings;
# use diagnostics;
use Glib qw(TRUE FALSE);
our @ISA = qw(Games::Axmud);
##################
# Constructors
sub new {
# Called by GA::Client->start
#
# Expected arguments
# (none besides $class)
#
# Return values
# 'undef' on improper arguments or if a GA::Obj::Desktop object already exists
# Blessed reference to the newly-created object on success
my ($class, $check) = @_;
# Check for improper arguments
if (! defined $class || defined $check) {
return $axmud::CLIENT->writeImproper($class . '->new', @_);
}
# Only one desktop object can exist
if ($axmud::CLIENT->desktopObj) {
return undef;
}
# Setup
my $self = {
_objName => 'desktop',
_objClass => $class,
_parentFile => undef, # No parent file object
_parentWorld => undef, # No parent file object
_privFlag => TRUE, # All IVs are private
# Widget registries
# -----------------
# The GA::Obj::WMCtrl object, based on X11::WMCtrl, which handles multiple workspaces
# (on systems that support wmctrl)
wmCtrlObj => undef,
# Registry hash of all workspace objects which still exist. Workspace objects
# (GA::Obj::Workspace) handle a single workspace on the desktop, on which 'grid'
# windows can be arranged on a 3-dimensional grid to avoid overlapping (each grid is
# handled by a workspace grid object, GA::Obj::WorkspaceGrid)
# If GA::Client->shareMainWinFlag = TRUE, all sessions share a single 'main' window,
# so each session has its own workspace grid object on every workspace. If
# GA::CLIENT->shareMainFlag = FALSE, all sessions have their own 'main' window, so
# there is only one workspace grid for each workspace, shared by all sessions
# NB The workspace object corresponding to the workspace from which Axmud was launched
# has the number 0, and cannot be deleted. Unlike GA::Client->initWorkspaceHash,
# subsequent workspaces don't have to be numbered sequentially (1, 2, 3...) but are
# still numbered in the order in which they're created
# Hash in the form
# $workspaceHash{unique_number} = blessed_reference_to_workspace_object
workspaceHash => {},
# Number of workspace objects ever created (used to give each workspace object a unique
# number)
workspaceCount => 0,
# For convenience, the 'default' workspace object (whose unique number is 0) is stored
# here
defaultWorkspaceObj => undef,
# Registry hash of workspace grid objects which still exist. Each workspace objects
# usually has one or more workspace grid objects (or none, if
# GA::Obj::Workspace->gridEnableFlag is TRUE)
# Each workspace grid object either belongs to a single session
# (GA::Client->shareMainWinFlag = TRUE), or is shared between all sessions
# (GA::CLIENT->shareMainWinFlag = FALSE)
# A workspace grid is divided up into zones. Zones can't use partial gridblocks so a
# zone size of 15x15 is possible, but not 20.5x15
# Zones can specify that only certain window types can be placed in them, or can specify
# that all window types may be placed in them.
# Hash in the form
# $gridHash{unique_number} = blessed_reference_to_workspace_grid_object
gridHash => {},
# Number of workspace grid objects ever created for this workspace (used to give every
# workspace grid object a unique number)
gridCount => 0,
# Registry hash of all 'grid' windows which still exist. 'grid' windows are any window
# specified by GA::Client->constGridWinTypeHash, specifically, windows which can be
# placed on a workspace grid (unlike temporary 'free' windows, which are never placed
# on a workspace grid)
# 'Grid' windows are handled by GA::Win::Internal or GA::Win::External objects
# Hash in the form
# $gridWinHash{unique_number} = blessed_reference_to_grid_window_object
gridWinHash => {},
# Number of 'grid' window objects ever created (used to give each 'grid' window object a
# unique number)
gridWinCount => 0,
# Registry hash of all 'free' windows which still exist (except 'dialogue' windows,
# which are not stored in any registry because they automatically close with their
# parent window; all code in this object assumes that 'free' windows exclude
# 'dialogue' windows)
# 'Free' windows are any window specified by GA::Client->constFreeWinTypeHash
# (specifically, any temporary window which is never placed on a workspace grid)
# 'Free' windows are handled by various objects inheriting from GA::Generic::FreeWin
# Hash in the form
# $freeWinHash{unique_number} = blessed_reference_to_free_window_object
freeWinHash => {},
# Number of 'free' window objects ever created (used to give each 'free' window object a
# unique number)
freeWinCount => 0,
# Registry hash of all textview objects (created by all sessions) which still exist.
# Textview objects (GA::Obj::TextView) handle a single Gtk3::Textview
# NB The code is at liberty to create its own Gtk3::TextViews, not handled by textview
# objects, if the code doesn't need the full functionality of a textview object. Those
# Gtk3::TextViews are not stored here
# Hash in the form
# $textViewHash{unique_number} = blessed_reference_to_textview_object
textViewHash => {},
# Number of textview objects ever created (used to give each textview object a unique
# number)
textViewCount => 0,
# Other IVs
# ---------
# $self->start will set this flag to FALSE if it's not possible to create workspace
# grids at all (because the desktop is too small, etc). If set to TRUE, workspace
# grids are only created when both this flag and GA::Client->activateGridFlag are
# TRUE
gridPermitFlag => TRUE,
# The number of workspaces that Axmud can potentially use is specified by
# GA::Client->initWorkspaceHash. On each workspace allowed, Axmud tests whether a
# workspace grid can be placed on it. If that test fails, Axmud takes the following
# action:
# - If it's the default (first) workspace, the workspace object's
# ->gridEnableFlag is set to FALSE. Windows are not arranged on a grid on that
# single workspace, and no more workspace objects can be created
# - For subsequent workspaces, if the test fails that workspace object is deleted,
# and windows can only be opened on previously-created workspaces
# In either case, if the test fails, this flag is set to FALSE to prevent more
# workspaces being created
newWorkspaceFlag => TRUE,
# A list of Gtk3::Gdk::Pixbufs corresponding to the icons stored in the '/icons/win'
# sub-directory for 'main' windows
mainWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'map' windows
mapWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'protocol' windows
protocolWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'fixed' windows
fixedWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'custom' windows
customWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'external' windows (the pixbufs are created, but not
# used - 'external' windows keep their own icons)
externalWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'viewer' windows
viewerWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'edit' windows
editWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'pref' windows
prefWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'wiz' windows
wizWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'dialogue' windows
dialogueWinIconList => [],
# A list of Gtk3::Gdk::Pixbufs for 'other' windows
otherWinIconList => [],
};
# Bless the object into existence
bless $self, $class;
return $self;
}
##################
# Methods
sub start {
# Called by GA::Client->start immediately after the call to $self->new
# Sets up pixbufs for all window icons, then sets up workspaces, then creates a spare 'main'
# window, which doesn't belong to any session, and which will be re-used by the first
# session that opens
lib/Games/Axmud/Obj/Desktop.pm view on Meta::CPAN
$axmud::CLIENT->set_mainWin($winObj);
}
}
return 1;
}
sub stop {
# Called by GA::Client->stop
# Closes any remaining 'internal' windows, restores 'external' windows to their original
# size/position, closes any remaining 'free' windows
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my ($workspaceCount, $gridCount, $gridWinCount, $freeWinCount, $textViewCount, $msg);
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->stop', @_);
}
# Close down workspace objects (which closes down its workspace grids and windows), youngest
# first
foreach my $workspaceObj (
sort {$b->number <=> $a->number} ($self->ivValues('workspaceHash'))
) {
if ($workspaceObj->number != 0) {
$self->del_workspace($workspaceObj);
} else {
$workspaceObj->stop();
$self->ivDelete('workspaceHash', 0);
}
}
$self->ivUndef('defaultWorkspaceObj');
# Check there are no workspaces, workspace grids, 'grid' windows, 'free' windows or
# textviews left (for error-detection purposes)
$workspaceCount = $self->ivPairs('workspaceHash');
if ($workspaceCount) {
if ($workspaceCount == 1) {
$msg = 'There was 1 un-closed workspace object';
} else {
$msg = 'There were ' . $workspaceCount . ' un-closed workspace objects';
}
$msg .= ' on desktop shutdown';
$axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
}
$gridCount = $self->ivPairs('gridHash');
if ($gridCount) {
if ($gridCount == 1) {
$msg = 'There was 1 un-closed workspace grid object';
} else {
$msg = 'There were ' . $gridCount . ' un-closed workspace grid objects';
}
$msg .= ' on desktop shutdown';
$axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
}
$gridWinCount = $self->ivPairs('gridWinHash');
if ($gridWinCount) {
if ($gridWinCount == 1) {
$msg = 'There was 1 un-closed \'grid\' window object';
} else {
$msg = 'There were ' . $gridWinCount . ' un-closed \'grid\' window objects';
}
$msg .= ' on desktop shutdown';
$axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
}
$freeWinCount = $self->ivPairs('freeWinHash');
if ($freeWinCount) {
if ($freeWinCount == 1) {
$msg = 'There was 1 un-closed \'free\' window object';
} else {
$msg = 'There were ' . $freeWinCount . ' un-closed \'free\' window objects';
}
$msg .= ' on desktop shutdown';
$axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
}
$textViewCount = $self->ivPairs('textViewHash');
if ($textViewCount) {
if ($textViewCount == 1) {
$msg = 'There was 1 un-closed textview object';
} else {
$msg = 'There were ' . $textViewCount . ' un-closed textview objects';
}
$msg .= ' on desktop shutdown';
$axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
}
return 1;
}
sub setupWorkspaces {
# Called by GA::Client->start
# The earlier call to $self->start sets up the default workspace; this function sets up
# any further workspaces specified by GA::Client->initWorkspaceHash
# Each workspace is handled by a workspace object (GA::Obj::Workspace). The workspace object
# performs certain tests on the workspace. If those tests fail, that workspace is not
# used, the workspace object is discarded, and no additional workspaces are used
# If the test failed on the default workspace created by $self->start, that workspace is
# still used, but this function uses no additional workspaces
# If $self->newWorkspaceFlag was set to FALSE by $self->start, this function uses no
# additional workspaces
#
# Expected arguments
# (none besides $self)
#
# Return values
# 'undef' on improper arguments
# 1 otherwise
my ($self, $check) = @_;
# Local variables
my @useList;
# Check for improper arguments
if (defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->setupWorkspaces', @_);
}
if ($self->wmCtrlObj && $self->gridPermitFlag && $self->newWorkspaceFlag) {
# Get a list of system workspace numbers (zero-indexed), in the order in which they
# should be used. The order depends on GA::Client->initWorkspaceDir; the returned list
# doesn't include the default workspace
@useList = $self->detectWorkspaces();
# GA::Client->specifies the workspaces that Axmud should use initially. If it specifies
# more workspaces than the 'default' one, create a new workspace object for each of
# them (but not if we've run out of available workspaces)
foreach my $index (sort {$a <=> $b} ($axmud::CLIENT->ivKeys('initWorkspaceHash'))) {
my ($workspace, $zonemap, $workspaceObj);
# The default workspace, numbered 0, already has a GA::Obj::Workspace
if ($index) {
$workspace = shift @useList;
$zonemap = $axmud::CLIENT->ivShow('initWorkspaceHash', $index);
if ($workspace) {
$self->useWorkspace($workspace, $zonemap);
lib/Games/Axmud/Obj/Desktop.pm view on Meta::CPAN
if (! $zoneObj->owner) {
# All zones with this $ownerString should have an ->owner session set, so
# give up with an error message
return $axmud::CLIENT->writeError(
'General error relinquishing zones from their owners',
$self->_objClass . '->relinquishZones',
);
}
}
}
}
# We have a list of 0, 1 or more zones that can be relinquished
foreach my $zoneObj (@list) {
$zoneObj->reset_owner();
}
return 1;
}
sub convertSpareMainWin {
# Called by GA::Session->setMainWin
# When there are no sessions, the single 'main' window is called a spare 'main' window
# When a new session starts, the spare 'main' window must be converted into a normal
# 'main' window (owned by a session, not by the GA::Client, and using a winmap that's
# not 'main_wait')
#
# Expected arguments
# $session - The calling GA::Session
# $winObj - The existing spare 'main' window object
#
# Optional arguments
# $winmap - The winmap to use. Set only if a winmap has been marked as the default
# winmap for this world; otherwise 'undef'
#
# Return values
# 'undef' on improper arguments or if the spare 'main' window can't be converted
# 1 otherwise
my ($self, $session, $winObj, $winmap, $check) = @_;
# Local variables
my ($winmapObj, $successFlag);
# Check for improper arguments
if (! defined $session || ! defined $winObj || defined $check) {
return $axmud::CLIENT->writeImproper($self->_objClass . '->convertSpareMainWin', @_);
}
# Update IVs
$winObj->set_owner($session);
$winObj->set_session($session);
# Position it on a workspace grid (if grids are activated generally)
if ($axmud::CLIENT->activateGridFlag && $self->gridPermitFlag) {
OUTER: foreach my $workspaceObj ($axmud::CLIENT->desktopObj->listWorkspaces()) {
foreach my $gridObj (
sort {$a->number <=> $b->number} ($workspaceObj->ivValues('gridHash'))
) {
if ($gridObj->repositionGridWin($winObj)) {
# 'main' window repositioned. Decide which winmap to use, if none was
# specified by the calling function
if (! $winmap) {
# Use the default winmap for the window's new zone
$winmapObj = $winObj->workspaceObj->getWinmap(
'main',
undef,
$winObj->areaObj->zoneObj,
);
$winmap = $winmapObj->name;
}
# ->repositionGridWin is also called by
# GA::Obj::WorkspaceGrid->applyZonemap, so its ->gridWinHash IV hasn't
# been modified
$gridObj->add_gridWin($winObj);
# Window IVs must also be updated
$winObj->set_workspaceGridObj($gridObj);
$winObj->set_workspaceObj($gridObj->workspaceObj);
$self->updateWidgets($self->_objClass . '->convertSpareMainWin');
# Position operation complete
$successFlag = TRUE;
last OUTER;
}
}
}
if (! $successFlag) {
# Could not position the 'main' window on any workspace grid, for some reason
return undef;
}
}
# Reset the window's winmap
if (! $winmap) {
if ($axmud::CLIENT->activateGridFlag) {
$winmap = $axmud::CLIENT->constDefaultEnabledWinmap;
} else {
$winmap = $axmud::CLIENT->constDefaultDisabledWinmap;
}
}
$winObj->resetWinmap($winmap);
return 1;
}
sub deconvertSpareMainWin {
( run in 0.590 second using v1.01-cache-2.11-cpan-f56aa216473 )