Games-Axmud

 view release on metacpan or  search on metacpan

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

            #   specified by GA::Client instead
            controlsLeftSize            => undef,
            controlsRightSize           => undef,
            controlsTopSize             => undef,
            controlsBottomSize          => undef,

            # Registry hash of workspace grid objects that have been created on this workspace (a
            #   subset of GA::Obj::Desktop->gridHash). Hash in the form
            #   $gridHash{number} = blessed_reference_to_workspace_grid_object
            gridHash                    => {},
            # In some cases workspace grids are not enabled on this workspace, in which case this
            #   flag is set by $self->start
            #       TRUE    - workspace grids are enabled on this workspace (the default setting)
            #       FALSE   - workspace grids are disabled on this workspace (and this is the only
            #                   workspace used by Axmud - see comments in GA::Obj::Desktop->new).
            #                   Axmud doesn't change the position of any windows, which are left
            #                   where the system's window manager puts them. Window controls are
            #                   compulsory
            gridEnableFlag              => TRUE,
            # The name of the default zonemap to use for this workspace (which initially depends on
            #   GA::Client->initWorkspaceHash). Set only while $self->gridEnableFlag remains set
            #   to TRUE
            defaultZonemap              => undef,
        };

        # Bless the object into existence
        bless $self, $class;

        return $self;
    }

    ##################
    # Methods

    sub start {

        # Called by GA::Obj::Desktop->start for the default (first) workspace and by
        #   GA::Obj::Desktop->useWorkspace thereafter
        # Finds the actual size of the available workspace available to Axmud (the total workspace,
        #   minus any panels/taskbars), if possible. If not possible, artificially sets the size
        #   of the available workspace according to various IVs
        #
        # Expected arguments
        #   $zonemap    - The default zonemap to use for this workspace
        #
        # Return values
        #   'undef' on improper arguments
        #   1 otherwise

        my ($self, $zonemap, $check) = @_;

        # Local variables
        my ($screen, $msg);

        # Check for improper arguments
        if (! defined $zonemap || defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->start', @_);
        }

        if (! $axmud::CLIENT->desktopObj->gridPermitFlag) {

            # Workspace grids are disabled in general
            $self->ivPoke('gridEnableFlag', FALSE);

        } else {

            # Test whether the workspace is too small
            # NB Due to technical limitations, we assume that the values returned by this test
            #   apply to all workspaces, on systems where multiple workspaces are available
            $screen = Gtk3::Gdk::Screen::get_default();
            $self->ivPoke('currentWidth', $screen->get_width());
            $self->ivPoke('currentHeight', $screen->get_height());

            if (
                $self->currentWidth < $axmud::CLIENT->constWorkspaceMinWidth
                || $self->currentHeight < $axmud::CLIENT->constWorkspaceMinHeight
            ) {
                # Test failed
                $self->ivPoke('gridEnableFlag', FALSE);

                $axmud::CLIENT->writeWarning(
                    'Workspace ' . $self->number . ' smaller than minimum - disabling workspace'
                    . ' grids',
                    $self->_objClass . '->start',
                );
            }
        }

        if ($self->gridEnableFlag && $self->currentWidth && $self->currentHeight) {

            # Set the default zonemap for this workspace
            $self->ivPoke('defaultZonemap', $zonemap);

            # Test whether the workspace is too big and, if so, reduce the size of the available
            #   workspace used by workspace grids
            if (
                $self->currentWidth > $axmud::CLIENT->constWorkspaceMaxWidth
                && $self->currentHeight > $axmud::CLIENT->constWorkspaceMaxHeight
            ) {
                $self->ivPoke('currentWidth', $axmud::CLIENT->constWorkspaceMaxWidth);
                $self->ivPoke('currentHeight', $axmud::CLIENT->constWorkspaceMaxHeight);
                $msg = 'Desktop width and height';

            } elsif ($self->currentWidth > $axmud::CLIENT->constWorkspaceMaxWidth) {

                $self->ivPoke('currentWidth', $axmud::CLIENT->constWorkspaceMaxWidth);
                $msg = 'Desktop width';

            } elsif ($self->currentHeight > $axmud::CLIENT->constWorkspaceMaxHeight) {

                $self->ivPoke('currentHeight', $axmud::CLIENT->constWorkspaceMaxHeight);
                $msg = 'Desktop height';
            }

            if ($msg) {

                $axmud::CLIENT->writeWarning(
                    $msg . ' exceeds maximum, reducing desktop size to '
                        . $self->currentWidth . 'x' . $self->currentHeight,
                    $self->_objClass . '->setup',
                );
            }

            # Find the size of panels (taskbars), if possible
            $self->findPanelSize();
        }

        # Find the size of the window controls on this workspace, by creating two test windows in
        #   opposite corners and checking their actual size and position with what was expected
        $self->findWinControlSize();

        # If workspace grids are enabled, set up workspace grids for each existing session (but
        #   don't set up any workspace grids if there are no sessions running yet; each new session
        #   creates its own workspace grids)
        if ($axmud::CLIENT->sessionHash) {

            if (! $axmud::CLIENT->shareMainWinFlag) {

                # Create a shared workspace grid
                $self->addWorkspaceGrid();

            } else {

                # Create a workspace grid for each existing session
                foreach my $session ($axmud::CLIENT->listSessions()) {

                    $self->addWorkspaceGrid($session);
                }
            }
        }

        # Operation complete
        return 1;
    }

    sub stop {

        # Called by GA::Obj::Desktop->del_workspace and (for the default workspace) by
        #   GA::Obj::Desktop->stop
        # Shuts down any workspace grid objects for this workspace (which closes its windows)
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Return values
        #   'undef' on improper arguments
        #   1 otherwise

        my ($self, $check) = @_;

        # Local variables
        my ($count, $msg);

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->stop', @_);
        }

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

            } else {
                $msg = 'There were ' . $count;
            }

            $msg .= ' un-closed workspace grids when the parent workspace closed';

            $axmud::CLIENT->writeWarning($msg, $self->_objClass . '->stop');
        }

        # In certain (rare) circumstances (such as when Axmud starts in blind mode, and the user
        #   manually closes the dialogue window created by GA::Client->connectBlind), the spare
        #   'main' window will still exist. If it does, close it now to prevent an error
        if (
            $axmud::CLIENT->mainWin
            && $axmud::CLIENT->mainWin->owner eq $axmud::CLIENT
            && $axmud::CLIENT->mainWin->workspaceObj eq $self
        ) {
            $axmud::CLIENT->mainWin->winDestroy();
        }

        return 1;
    }

    # General functions

    sub addWorkspaceGrid {

        # Called by $self->start or GA::Session->setMainWin
        # Adds a workspace grid object to this workspace, and sets it up (if allowed)
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Optional arguments
        #   $session    - (GA::Client->shareMainWinFlag = TRUE) The GA::Session object which
        #                   controls this workspace grid
        #               - (GA::Client->shareMainWinFlag = FALSE) 'undef' (the grid is shared between
        #                   all sessions)
        #   $zonemap    - The zonemap to use to set up the workspace grid object. If 'undef',
        #                   $self->defaultZonemap is used
        #
        # Return values
        #   'undef' on improper arguments, if workspace grids can't be created in general or if
        #       the operation fails
        #   Otherwise returns workspace grid object added

        my ($self, $session, $zonemap, $check) = @_;

        # Local variables
        my ($gridObj, $result);

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->addWorkspaceGrid', @_);
        }

        if (
            # Workspace grids are disactivated generally (at the user's request)
            ! $axmud::CLIENT->activateGridFlag
            # Axmud cannot create workspace grids, because the desktop is too small, etc
            || ! $axmud::CLIENT->desktopObj->gridPermitFlag
            # # Workspace grids are disabled on this workspace
            || ! $self->gridEnableFlag
        ) {
            # Workspace grids are disabled on this workspace
            return undef;
        }

        # Add the workspace grid object
        $gridObj = $axmud::CLIENT->desktopObj->add_grid($self, $session);
        if (! $gridObj) {

            # Operation failed
            return undef;

        } else {

            # Also update our own IV
            $self->ivAdd('gridHash', $gridObj->number, $gridObj);
        }

        # Set up the new workspace grid object
        if ($zonemap) {
            $result = $gridObj->start($zonemap);
        } else {
            $result = $gridObj->start($self->defaultZonemap);
        }

        if (! $result) {

            # Setup failed; discard this workspace grid
            $axmud::CLIENT->desktopObj->del_grid($gridObj);
            $self->ivDelete('gridHash', $gridObj->number);

            return undef;

        } else {

            return $gridObj;
        }
    }

    sub removeWorkspaceGrid {

        # Called by $self->stop, ->disableWorkspaceGrids and
        #   GA::Obj::Desktop->removeSessionWorkspaceGrids
        # Removes a workspace grid object from this workspace (which closes all its windows), and
        #   informs GA::Obj::Desktop
        #
        # Expected arguments
        #   $gridObj    - The GA::Obj::WorkspaceGrid to remove
        #
        # Optional arguments
        #   $session    - If defined, that session's 'main' window is disengaged (removed from its
        #                   workspace grid, but not destroyed)
        #
        # Return values
        #   'undef' on improper arguments or if the operation fails
        #   1 otherwise

        my ($self, $gridObj, $session, $check) = @_;

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->removeWorkspaceGrid', @_);
        }

        # Shut down the workspace grid object
        if (! $axmud::CLIENT->desktopObj->del_grid($gridObj, $session)) {

            return undef;

        } else {

            # Update our own IVs
            $self->ivDelete('gridHash', $gridObj->number);

            return 1;
        }
    }

    sub enableWorkspaceGrids {

        # Called by GA::Obj::Desktop->activateWorkspaceGrids and GA::Cmd::ActivateGrid->do
        # Enables workspace grids on this workspace. Creates workspace grids for every session (or a
        #   single workspace grid, if sessions don't share a 'main' window), places existing
        #   windows on the correct grid and updates IVs
        # If grids are already enabled on this workspace, does nothing
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Optional arguments
        #   $zonemap    - If specified, the name of the zonemap (matches a key in
        #                   GA::Client->zonemapHash) to be used as the default zonemap on this
        #                   workspace (and which is applied to every new workspace grid)
        #
        # Return values
        #   'undef' on improper arguments
        #   1 otherwise

        my ($self, $zonemap, $check) = @_;

        # Local variables
        my (
            $zonemapObj,
            @gridList, @winList,
        );

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->enableWorkspaceGrids', @_);
        }

        if (! $self->gridEnableFlag) {

            # Update IVs
            $self->ivPoke('gridEnableFlag', TRUE);

            # If a zonemap was specified, it's the default zonemap for this workspace
            if (defined $zonemap && $axmud::CLIENT->ivExists('zonemapHash', $zonemap)) {

                $self->ivPoke('defaultZonemap', $zonemap);
            }

            # Get a sorted list of 'grid' window objects
            @winList = sort {$a->number <=> $b->number}
                        ($axmud::CLIENT->desktopObj->ivValues('gridWinHash'));

            # Create workspace grids
            if ($axmud::CLIENT->shareMainWinFlag) {

                # Create a grid for every session
                foreach my $session ($axmud::CLIENT->listSessions()) {

                    my $gridObj = $self->addWorkspaceGrid($session, $zonemap);
                    if ($gridObj) {

                        push (@gridList, $gridObj);

                        # All 'grid' windows on this workspace controlled by the session should be
                        #   placed onto this grid. Start by updating the workspace object's IV
                        foreach my $winObj (@winList) {

                            if (
                                $winObj->workspaceObj eq $self
                                && $winObj->session
                                && $winObj->session eq $session
                            ) {
                                $gridObj->add_gridWin($winObj);
                            }
                        }
                    }
                }

            } else {

                # Create a single grid shared by all sessions
                my $gridObj = $self->addWorkspaceGrid(undef, $zonemap);
                if ($gridObj) {

                    push (@gridList, $gridObj);

                    # All 'grid' windows on this workspace controlled by the session should be
                    #   placed onto this grid. Start by updating the workspace object's IV
                    foreach my $winObj (@winList) {

                        if ($winObj->workspaceObj eq $self) {

                            $gridObj->add_gridWin($winObj);
                        }
                    }
                }
            }

            # Get the default zonemap object for this workspace
            $zonemapObj = $axmud::CLIENT->ivShow('zonemapHash', $self->defaultZonemap);

            # For any workspace grid object assigned a window, we can use the normal reset code to
            #   have the windows places on the grid, as if they had been opened there
            foreach my $gridObj (@gridList) {

                if ($gridObj->gridWinHash) {

                    $gridObj->applyZonemap($zonemapObj);
                }
            }
        }

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

            if (defined $axmud::CLIENT->customPanelBottomSize) {
                $self->ivPoke('panelBottomSize', $axmud::CLIENT->customPanelBottomSize);
            } else {
                $self->ivPoke('panelBottomSize', $bottom);
            }

            # Return the results of the test (not the size of the available workspace)
            return ($left, $right, $top, $bottom);
        }
    }

    sub testPanelSize {

        # Called by $self->findPanelSize
        # Creates a maximised test window and returns its position and size
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Optional arguments
        #   $timeout    - A timeout, in seconds. If not defined, a default timeout is used
        #
        # Return values
        #   An empty list on improper arguments or if the test fails
        #   Otherwise returns the detected sizes of panels/taskbars detected, a list in the form
        #       (left, right, top, bottom)

        my ($self, $timeout, $check) = @_;

        # Local variables
        my (
            $testWinName, $initSize, $startTime, $checkTime, $regionX, $regionY, $regionWidth,
            $regionHeight,
            @emptyList,
        );

        # Check for improper arguments
        if (defined $check) {

            $axmud::CLIENT->writeImproper($self->_objClass . '->testPanelSize', @_);
            return @emptyList;
        }

        # Prepare the test window's title bar
        $testWinName = $axmud::SCRIPT . ' panel test';
        # The test window's size can be measured once it is no longer its original size
        $initSize = 100;
        # If no timeout was specified, use the default one
        if (! defined $timeout) {

            $timeout = 1;
        }

        # Create a test window with maximum opacity, so the user doesn't see it
        my $testWin = Gtk3::Window->new('toplevel');
        $testWin->set_title($testWinName);
        $testWin->set_border_width(0);
        $testWin->set_size_request($initSize, $initSize);
        $testWin->set_decorated(FALSE);
        $testWin->set_opacity(0);
        $testWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});
        $testWin->set_skip_taskbar_hint(TRUE);
        $testWin->set_skip_pager_hint(TRUE);
        $testWin->show_all();

        # If using X11::WMCtrl, we can move the test window to the correct workspace (if not, there
        #   is only one workspace in use, anyway)
        if ($axmud::CLIENT->desktopObj->wmCtrlObj) {

            $axmud::CLIENT->desktopObj->wmCtrlObj->move_to($testWinName, $self->systemNum);
        }

        $testWin->maximize();
        $testWin->show_all();

        # Initialise the timeout (a time in seconds)
        $startTime = $axmud::CLIENT->getTime();

        # The window will not become maximised immediately, so we keep looking on a loop until it
        #   does on until the timeout expires
        do {

            $axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->testWinControls');
            ($regionX, $regionY, $regionWidth, $regionHeight)
                = $self->getWinGeometry($testWin->get_window());

            $checkTime = $axmud::CLIENT->getTime();

        } until (
            ($regionWidth != $initSize && $regionHeight != $initSize)
            || $checkTime > ($startTime + $timeout)
        );

        $testWin->destroy();

        if ($regionWidth == $initSize || $regionHeight == $initSize) {

            # Test failed
            return @emptyList;

        } else {

            # Test successful
            return ($regionX, $regionY, $regionWidth, $regionHeight);
        }
    }

    sub findWinControlSize {

        # Called by $self->start or GA::Cmd::TestWindowControls->do
        # Tries to find the sizes of window controls, the edges around windows added by desktop's
        #   window manager. (It's extremely unlikely that different workspaces will use different
        #   window controls, but Axmud checks windows controls on every workspace it uses anyway)
        # Create two test windows in opposite corners of the workspace and compare their actual size
        #   and position with what was expected
        # If the test succeeds, sets $self->controlsLeftSize, etc. (If
        #   GA::Client->customControlsLeftSize (etc) are set, those values take precedence over
        #   the test values)
        # If the test fails and $self->controlsLeftSize (etc) have never been set for this
        #   workspace, sets them using GA::Client->customControlsLeftSize or
        #   ->constControlsLeftSize (etc)
        #
        # Expected arguments
        #   (none besides $self)
        #
        # Return values
        #   An empty list on improper arguments or if either test fails
        #   Otherwise returns the detected sizes of window controls (which might not match the
        #       values stored in $self->controlsLeftSize, etc), a list in the form
        #       (left, right, top, bottom)

        my ($self, $check) = @_;

        # Local variables
        my (
            $left, $right, $top, $bottom,
            @emptyList,
        );

        # Check for improper arguments
        if (defined $check) {

            $axmud::CLIENT->writeImproper($self->_objClass . '->findWinControlSize', @_);
            return @emptyList;
        }

        # Try to detect window controls sizes. Create first test window near the top-left corner of
        #   this workspace
        ($left, $top) = $self->testWinControls(FALSE);
        # Create second test window near the bottom-right corner
        ($right, $bottom) = $self->testWinControls(TRUE);

        # If the test succeeded, perform some sanity checking (just in case)
        if (
            defined $left
            && defined $right
            && (
                $left < 0 || $left > 200
                || $top < 0 || $top > 200
                || $right < 0 || $right > 200
                || $bottom < 0 || $bottom > 200
            )
        ) {
            # Sanity check fails, therefore the test fails
            $left = undef;
        }

        # Respond to the test
        if (! defined $left || ! defined $right) {

            # Test failed

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

                if (defined $axmud::CLIENT->customControlsBottomSize) {
                    $self->ivPoke('controlsBottomSize', $axmud::CLIENT->customControlsBottomSize);
                } else {
                    $self->ivPoke('controlsBottomSize', $axmud::CLIENT->constControlsBottomSize);
                }
            }

            return @emptyList;

        } else {

            # Test successful

            # DEBUG v2.0
            # MS Windows adds extra pixels to the window width and height (for unknown reasons);
            #   compensate for that, if required
            if ($^O eq 'MSWin32' && $axmud::CLIENT->mswinWinPosnTweakFlag) {

                # N.B. The $top value is OK
                $left = 0;
                $right = 0;
                $bottom = 0;
            }

            # Store the detected sizes unless GA::Client->customControlsLeftSize (etc) are set, as
            #   those values take precedence
            if (defined $axmud::CLIENT->customControlsLeftSize) {
                $self->ivPoke('controlsLeftSize', $axmud::CLIENT->customControlsLeftSize);
            } else {
                $self->ivPoke('controlsLeftSize', $left);
            }

            if (defined $axmud::CLIENT->customControlsRightSize) {
                $self->ivPoke('controlsRightSize', $axmud::CLIENT->customControlsRightSize);
            } else {
                $self->ivPoke('controlsRightSize', $right);
            }

            if (defined $axmud::CLIENT->customControlsTopSize) {
                $self->ivPoke('controlsTopSize', $axmud::CLIENT->customControlsTopSize);
            } else {
                $self->ivPoke('controlsTopSize', $top);
            }

            if (defined $axmud::CLIENT->customControlsBottomSize) {
                $self->ivPoke('controlsBottomSize', $axmud::CLIENT->customControlsBottomSize);
            } else {
                $self->ivPoke('controlsBottomSize', $bottom);
            }

            # Return the results of the test (not the stored controls sizes)
            return ($left, $right, $top, $bottom);
        }
    }

    sub testWinControls {

        # Called by $self->findWinControlSize
        # Creates a test window in one of two opposite corners of this workspace and, by testing its
        #   actual coordinates against its expected coordinates, finds out the size of two of the
        #   window controls used by the current desktop theme
        #
        # Expected arguments
        #   $gravityFlag        - FALSE to use top-left corner, TRUE to use bottom-right corner
        #
        # Return values
        #   Returns an empty list on improper arguments or if the window's position on the desktop
        #       can't be found
        #   Otherwise returns a list in the form
        #       ($gravityFlag = FALSE) - The list (size_of_left_control, size_of_top_control)
        #       ($gravityFlag = TRUE) - The list (size_of_bottom_control, size_of_right_control)

        my ($self, $gravityFlag, $check) = @_;

        # Local variables
        my (
            $testWinName, $testWinSize, $testWinDistance, $checkTime, $matchFlag, $regionX,
            $regionY, $regionWidth, $regionHeight, $clientX, $clientY,
            @emptyList, @nameList,
        );

        # Check for improper arguments
        if (! defined $gravityFlag || defined $check) {

            $axmud::CLIENT->writeImproper($self->_objClass . '->testWinControls', @_);
            return @emptyList;
        }

        # This test requires that window panels have been set in an earlier call to
        #   $self->findPanelSize; if they haven't, then this test fails
        if (
            ! defined $self->panelLeftSize
            || ! defined $self->panelRightSize
            || ! defined $self->panelTopSize
            || ! defined $self->panelBottomSize
        ) {
            return @emptyList;
        }

        # Prepare the test window's title bar
        if (! $gravityFlag) {
            $testWinName = $axmud::SCRIPT . '_test_1';
        } else {
            $testWinName = $axmud::SCRIPT . '_test_2';
        }

        # Prepare the width and height of the test window in pixels
        $testWinSize = 100;
        # Set the distance from the corner in pixels
        $testWinDistance = 100;

        # Create the test window
        my $testWin = Gtk3::Window->new('toplevel');
        $testWin->set_title($testWinName);
        $testWin->set_border_width(0);
        $testWin->set_size_request($testWinSize, $testWinSize);
        $testWin->set_decorated(TRUE);
        $testWin->set_opacity(0);
        $testWin->set_skip_taskbar_hint(TRUE);
        $testWin->set_skip_pager_hint(TRUE);

        if (! $gravityFlag) {

            # Position the test window near the top-left corner
            $testWin->move(
                ($self->panelLeftSize + $testWinDistance),
                ($self->panelTopSize + $testWinDistance),
            );

        } else {

            # Position the test window near the bottom-right corner
            $testWin->move(
                ($self->currentWidth - $self->panelRightSize - $testWinDistance - $testWinSize),
                ($self->currentHeight - $self->panelBottomSize - $testWinDistance - $testWinSize),
            );
        }

        # Set the window's gravity
        if (! $gravityFlag) {
            $testWin->set_gravity('GDK_GRAVITY_NORTH_WEST');
        } else {
            $testWin->set_gravity('GDK_GRAVITY_SOUTH_EAST');
        }

        # Use standard 'dialogue' window icons
        $testWin->set_icon_list($axmud::CLIENT->desktopObj->{dialogueWinIconList});

        # Make the window visible, briefly
        $testWin->show_all();
        $axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->testWinControls');

        # If using X11::WMCtrl, we can move the test window to the correct workspace (if not, there
        #   is only one workspace in use, anyway)
        if ($axmud::CLIENT->desktopObj->wmCtrlObj) {

            # Very rarely, the call to X11::WMCtrl->get_windows() produces an unexplainable error.
            #   This nudge seems to prevent it from happening
            $axmud::CLIENT->desktopObj->wmCtrlObj->get_window_manager();

            # In some cases, X11::WMCtrl doesn't know about the test window (despite the call to
            #   ->updateWidgets just above). Wait for up to a second and, if X11::WMCtrl still
            #   hasn't spotted the new window, regard the test as a failure
            $checkTime = $axmud::CLIENT->getTime() + 1;
            do {

                OUTER: foreach my $hashRef ($axmud::CLIENT->desktopObj->wmCtrlObj->get_windows()) {

                    if ($$hashRef{'title'} eq $testWinName) {

                        $matchFlag = TRUE;
                        last OUTER;
                    }
                }

            } until ($matchFlag || $axmud::CLIENT->getTime() > $checkTime);

            if (! $matchFlag) {

                # Test failed
                return @emptyList;

            } else {

                # Can move the window to its workspace without triggering an error (providing we do
                #   a quick ->updateWidgets first)
                $axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->testWinControls');
                $axmud::CLIENT->desktopObj->wmCtrlObj->move_to($testWinName, $self->systemNum);
            }
        }

        # Get the window's actual position on the desktop
        ($regionX, $regionY, $regionWidth, $regionHeight, $clientX, $clientY)
            = $self->getWinGeometry($testWin->get_window());

        # Destroy the test window, now that we have all the data we want
        $testWin->destroy();

        # Return the window controls sizes as a list
        if (! $gravityFlag) {

            # Return size of the left and top window controls
            return (
                ($clientX - ($self->panelLeftSize + $testWinDistance)),
                ($clientY - ($self->panelTopSize + $testWinDistance)),
            )

        } else {

            # Return size of the right and bottom window controls
            return (
                (
                    $self->currentWidth - $self->panelRightSize - $testWinDistance - $testWinSize
                    - $clientX
                ),
                (
                    $self->currentHeight - $self->panelBottomSize - $testWinDistance - $testWinSize
                    - $clientY
                ),
            )
        }
    }

    sub getWinGeometry {

        # Can be called by any function, e.g. by $self->testWinControls
        # Gets the actual size and position of a Gdk::Window
        #
        # Expected arguments
        #   $gdkWin     - The Gdk::Window to use
        #
        # Return values
        #   An empty list on improper arguments or if the test fails
        #   Otherwise a list in groups of 4, showing the size and position of the window region (the
        #       window's visible size and position), and then the size and position of the window's
        #       client area (i.e. not taking into account the window's title bar):
        #       (
        #           $regionX, $regionY, $regionWidth, $regionHeight,
        #           $clientX, $clientY, $clientWidth, $clientHeight,
        #       )

        my ($self, $gdkWin, $check) = @_;

        # Local variables
        my (
            $regionX, $regionY, $clientX, $clientY, $clientWidth, $clientHeight,
            @emptyList,
        );

        # Check for improper arguments
        if (! defined $gdkWin || defined $check) {

            $axmud::CLIENT->writeImproper($self->_objClass . '->getWinGeometry', @_);
            return @emptyList;
        }

        # Make sure all drawing operations are complete
        $axmud::CLIENT->desktopObj->updateWidgets($self->_objClass . '->getWinGeometry');

        # Get the position of the visible window
        ($regionX, $regionY) = $gdkWin->get_root_origin();
        # Get the position of the window's client area
        ($clientX, $clientY) = $gdkWin->get_origin();
        # Get the size of the window's client area; the size of the window region can be calculated
        #   by adding the ttitle bar
        $clientWidth = $gdkWin->get_width();
        $clientHeight = $gdkWin->get_height();

        # Return the results
        return (
            $regionX,
            $regionY,
            $clientWidth + ($clientX - $regionX),
            $clientHeight + ($clientY - $regionY),
            $clientX,
            $clientY,
            $clientWidth,
            $clientHeight,
        );
    }

    sub matchWinList {

        # Called GA::GrabWindowCmd->do or any other code
        # Compares a list of patterns - e.g. ('Notepad', 'Firefox') - against a list of windows on
        #   this workspace. Returns a list of internal IDs for the matching windows
        # The patterns are treated as regexes (so 'Notepad' and '^Note' are both acceptable). The
        #   pattern match is case-insensitive
        #
        # NB This function does nothing if X11::WMCtrl is not available
        #
        # Expected arguments
        #   $number         - The number of windows to match. 1 - return only the first matching
        #                       window; 7 - return only the first 7 matching windows, 0 - return all
        #                       matching windows
        #
        # Optional arguments
        #   @patternList    - A list of patterns matching one or more window titles. If an empty
        #                       list, no matching occurs
        #
        # Return values
        #   An empty list on improper arguments
        #   Otherwise returns a list (which may be an empty list) in groups of 2 for each matching
        #       window, in the form
        #           (window_title, window_internal_id)

        my ($self, $number, @patternList) = @_;

        # Local variables
        my (
            $count,
            @emptyList, @returnList,
        );

        # Check for improper arguments
        if (! defined $number) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->matchWinList', @_);
        }

        # Can't do anything without X11::WMCtrl
        if (! $axmud::CLIENT->desktopObj->wmCtrlObj) {

            return @emptyList;
        }

        # Cycle through the list of windows on all workspaces, ignoring any windows that aren't on
        #   this workspace
        $count = 0;
        OUTER: foreach my $hashRef ($axmud::CLIENT->desktopObj->wmCtrlObj->get_windows()) {

            my $title;

            if ($$hashRef{'workspace'} == $self->systemNum) {

                # X11::WMCtrl handles a string containing both the window's title and the hostname
                #   of the X client drawing the window; however, when that hostname is 'N/A',
                #   X11::WMCtrl is unable to remove it, so we'll have to do that ourselves
                $title = $$hashRef{'title'};
                $title =~ s/^\sN\/A\s//;

                INNER: foreach my $pattern (@patternList) {

                    if ($title =~ m/$pattern/i) {

                        # A matching window was found
                        push (@returnList, $title, $$hashRef{'id'});
                        $count++;

                        # Do we have enough matching windows now?
                        if ($number > 0 && $count >= $number) {

                            # We have enough matching windows
                            return @returnList;

                        } else {

                            # Look for the next matching window
                            next OUTER;
                        }
                    }
                }
            }
        }

        # Operation complete
        return @returnList;
    }

    sub moveResizeWin {

        # Can be called by any function (but not used by $self->testWinControls, which calls
        #   Gtk3::Window->move and ->resize directly)
        # Moves a window to a specific position on the workspace and resizes it
        # Calls to this function should usually be followed by a call to
        #   GA::Obj::Zone->restackWin() and/or GA::Generic::Win->restoreFocus
        #
        # Expected arguments
        #   $winObj     - The window object (anything inheriting from GA::Generic::Win) whose
        #                   window should be moved and/or resized
        #
        # Optional arguments
        #   $xPosPixels, $yPosPixels
        #               - The new position of the window (both set to 'undef' if the position isn't
        #                   to be changed)
        #   $widthPixels, $heightPixels
        #               - The new size of the window (both set to 'undef' if the size isn't to be
        #                   changed)
        #
        # Notes
        #   The following combinations of arguments lists are acceptable:
        #       ($winObj, $xPosPixels, $yPosPixels, $widthPixels, $heightPixels)
        #       ($winObj, $xPosPixels, $yPosPixels, undef, undef)
        #       ($winObj, undef, undef, $widthPixels, $heightPixels)
        #       ($winObj, undef, undef, undef, undef)
        #   Any other combination, for example the following one, will cause an error
        #       ($winObj, $xPosPixels, $yPosPixels, undef, $heightPixels)
        #
        # Return values
        #   'undef' on improper arguments or if the window can't be moved (because a non-external
        #       window object doesn't have its ->winWidget set)
        #   1 otherwise

        my ($self, $winObj, $xPosPixels, $yPosPixels, $widthPixels, $heightPixels, $check) = @_;

        # Local variables
        my $title;

        # Check for improper arguments
        if (
            ! defined $winObj
            || (defined $xPosPixels && ! defined $yPosPixels)
            || (! defined $xPosPixels && defined $yPosPixels)
            || (defined $widthPixels && ! defined $heightPixels)
            || (! defined $widthPixels && defined $heightPixels)
            || defined $check
        ) {
            return $axmud::CLIENT->writeImproper($self->_objClass . '->moveResizeWin', @_);
        }

        if ($winObj->winType ne 'external') {

            # Move the window to the correct workspace, if possible
            if ($axmud::CLIENT->desktopObj->wmCtrlObj) {

                # Give the window a unique name, so WMCtrl can find it
                my $title = $winObj->winWidget->get_title();
                $winObj->winWidget->set_title($axmud::SCRIPT . int(rand(1_000_000_000)));

                # Move the window
                $axmud::CLIENT->desktopObj->wmCtrlObj->move_to(
                    $winObj->winWidget->get_title(),
                    $self->systemNum,
                );

                # Restore the original title
                $winObj->winWidget->set_title($title);
            }

            # Resize the window, if that was specified
            if (defined $widthPixels) {

                $winObj->winWidget->resize($widthPixels, $heightPixels);
            }

            # Move the window, if that was specified
            # $winObj->winWidget is occasionally set to 'undef' just before this line. It's a very
            #   difficult error to reproduce, so I'm not sure what the cause is
            if ($winObj->winWidget && defined $xPosPixels) {

                # DEBUG v2.0
                # MS Windows adds extra pixels to the X position (for unknown reasons); compensate
                #   for that, if required
                if ($^O eq 'MSWin32' && $axmud::CLIENT->mswinWinPosnTweakFlag) {

                    $xPosPixels -= 7;
                }

                $winObj->winWidget->move($xPosPixels, $yPosPixels);
            }

        } else {

            # X11::WMCtrl expects -1 values, rather than undef
            if (! defined $xPosPixels) {

                $xPosPixels = -1;
                $yPosPixels = -1;
            }

            if (! defined $widthPixels) {

                $widthPixels = -1;
                $heightPixels = -1;
            }

            # Move the window to the correct workspace
            $axmud::CLIENT->desktopObj->wmCtrlObj->wmctrl(
                '-r',
                $winObj->internalID,
                '-t',
                $self->systemNum,
                '-i',
            );

            # Set the window's size and position
            $axmud::CLIENT->desktopObj->wmCtrlObj->wmctrl(
                '-r',
                $winObj->internalID,
                "-e 0,$xPosPixels,$yPosPixels,$widthPixels,$heightPixels",
                '-i',
            );
        }

        # Operation complete
        return 1;
    }

    # Window creation

    sub createGridWin {

        # Can be called by anything
        #
        # Creates a 'grid' window object. 'external' windows use GA::Win::External objects; other
        #   kinds of 'grid' window use GA::Win::Internal. (This function isn't used to create 'free'
        #   windows; call GA::Generic::Win->createFreeWin for that)
        # If the window itself doesn't exist, creates it using the specified size and coordinates,
        #   in the specified layer, on the workspace $self->systemNum
        # If the window already exists, resizes and moves it using the specified size and
        #   coordinates
        # If workspace grids are available and the window's specified position is occupied by
        #   another window, moves the specified window to another position in the zone, if possible
        # If workspace grids aren't available, ignores the specified coordinates (if supplied), and
        #   lets the desktop's window manager decide where to put the window
        #
        # NB If the calling function wants the window to appear on a particular workspace only, it
        #   can call this function directly
        # If the calling function wants the window to appear on the first available workspace, it
        #   can call GA::Obj::Desktop->listWorkspaces to get an ordered list of workspaces, with
        #   the preferred workspace (if specified) first in the list. The calling function can then
        #   call this function for each workspace on the list until a new window object is actually
        #   created
        #
        # NB 'main' windows should only be created by code in GA::Client or GA::Session.
        #   'protocol' and 'external' windows should only be created by code in GA::Session
        # If you write your own plugins, don't use them to create your own 'main', 'protocol' or
        #   'external' windows. You can create as many 'map', 'fixed' or 'custom' windows as you
        #   like, though
        #
        # Expected arguments
        #   $winType        - The window type; one of the 'grid' window types specified by
        #                       GA::Client->constGridWinTypeHash
        #   $winName        - A name for the window:
        #                       $winType    $winName
        #                       --------    --------
        #                       main        main
        #                       map         map
        #                       protocol    Any string chosen by the protocol code (default value is
        #                                       'protocol')
        #                       fixed       Any string chosen by the controlling code (default value
        #                                       is 'fixed')
        #                       custom      Any string chosen by the controlling code. For task
        #                                       windows, the name of the task (e.g. 'status_task',
        #                                       for other windows, default value is 'custom'
        #                       external    The 'external' window's name (e.g. 'Notepad')
        #
        # Optional arguments
        #   $winTitle       - The text to use in the window's title bar. If 'undef', a default
        #                       window title is used
        #   $winmapName     - The name of the GA::Obj::Winmap object that specifies the
        #                       Gtk3::Window's layout when it is first created. If 'undef', a
        #                       default winmap is used. Ignored for 'map', 'fixed' and 'external'
        #                       windows which should have no winmap
        #   $packageName    - 'main', 'protocol' and 'custom' windows are created via a call to
        #                       GA::Win::Internal->new(). 'external' windows are created via a
        #                       call to GA::Win::External->new(). However, the calling function
        #                       can specify its own $packageName, if required. It's expected that
        #                       the package should inherit from GA::Win::Internal or
        #                       GA::Win::External
        #                   - 'map' windows are created via a call to GA::Win::Map->new(). If the
        #                       calling function specifies its own $packageName, it's expected that
        #                       the package either inherits from GA::Win::Map, or provides a
        #                       similar range of functions for other parts of the Axmud code to call
        #                   - $packageName must be specified when creating a 'fixed' window. If not,
        #                       an error is produced
        #   $winWidget      - The Gtk3::Window, if it already exists and it is known (otherwise
        #                       set to 'undef')
        #   $internalID     - For 'external' windows, the window internal ID, provided by
        #                       X11::WMCtrl ('undef' for other types of window)
        #   $owner          - The owner, if known. Can be any blessed reference, typically it's an
        #                       GA::Session or a task (inheriting from GA::Generic::Task). The owner
        #                       must have a ->del_winObj function, which is called when this window
        #                       closes
        #   $session        - The owner's session. If $owner is a GA::Session, that session. If

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

            $layer,
            $xPosPixels,
            $yPosPixels,
        );

        if (! defined $layer) {

            # Zone is full
            return undef;
        }

        # Create a GA::Obj::Area within the zone (which handles the new window, and is the same
        #   size as it)
        $areaObj = $zoneObj->addArea(
            $layer,
            $xPosBlocks,
            $yPosBlocks,
            $widthBlocks,
            $heightBlocks,
            $xPosPixels,
            $yPosPixels,
            $widthPixels,
            $heightPixels,
            $session,
        );

        if (! $areaObj) {

            # Checks failed
            return undef;
        }

        # Convert a winmap name to a winmap object. If no winmap was specified, use a default one
        $winmapObj = $self->getWinmap($winType, $winmapName, $zoneObj);
        # We need to specify a winmap name or 'undef' in the call to ->new
        if ($winmapObj) {
            $winmapName = $winmapObj->name;
        } else {
            $winmapName = undef;
        }

        # Create a new window object
        if (! defined $packageName) {

            if ($winType eq 'external') {

                $packageName = 'Games::Axmud::Win::External';

            } elsif ($winType eq 'map') {

                $packageName = 'Games::Axmud::Win::Map';

            } else {

                # $winType is 'main', 'protocol', 'custom'
                $packageName = 'Games::Axmud::Win::Internal';
            }
        }

        $winObj = $packageName->new(
            $axmud::CLIENT->desktopObj->gridWinCount,
            $winType,
            $winName,
            $self,
            $owner,
            $session,
            $workspaceGridObj,
            $areaObj,
            $winmapName,
        );

        # (The check for ->winType makes sure that plugins don't create, for example, a 'free'
        #   window and then try to add it via a call to GA::Client->createGridWin)
        if (! $winObj || $winObj->winCategory ne 'grid' || $winObj->winType ne $winType) {

            # Something or other failed. Update the zone
            $zoneObj->removeArea($areaObj);

            return undef;
        }

        # Update the GA::Obj::Desktop object's registry of all 'grid' windows
        $axmud::CLIENT->desktopObj->add_gridWin($winObj);
        # Tell the workspace grid object and area object they have received a new window
        $workspaceGridObj->add_gridWin($winObj);
        $areaObj->set_win($winObj);

        # Move the window to its correct workspace, size and position
        if ($winType ne 'external') {

            # Create a new Gtk3::Window widget at the specified size and position (but don't make
            #   it visible yet)
            if (! $winObj->winSetup($winTitle, $beforeListRef)) {

                # Something or other failed. Update the zone
                $zoneObj->removeArea($areaObj);

                return undef;
            }

            # Make the window actually visible, if it's not already visible
            if (! $winObj->enabledFlag) {

                $winObj->winEnable($afterListRef);
            }

            # Move the window to its correct workspace, size and position
            $self->moveResizeWin(
                $winObj,
                $xPosPixels,
                $yPosPixels,
                $widthPixels,
                $heightPixels,
            );

#            # For 'grid' windows, $winObj->winEnable created the window in a minimised state so it
#            #   didn't appear to jump around on the desktop. Unminimise it now
#            $winObj->unminimise();

            # Update the GA::Client's hash of stored window positions (if required)
            if ($winObj->winWidget) {

                $axmud::CLIENT->add_storeGridPosn(
                    $winObj,
                    $winObj->winWidget->get_position(),
                    $winObj->winWidget->get_size(),
                );
            }

        } else {

            # Update the 'external' window object's IVs
            if (! $winObj->winSetup($internalID)) {

                # Something or other failed. Update the zone
                $zoneObj->removeArea($areaObj);

                return undef;
            }

            $self->moveResizeWin(
                $winObj,
                ($xPosPixels - $self->controlsLeftSize),
                ($yPosPixels - $self->controlsTopSize),
                $widthPixels,
                $heightPixels,
            );

            # Make the window actually visible, if it's not already visible
            if (! $winObj->enabledFlag) {

                $winObj->winEnable($afterListRef);
            }

            # If this 'external' window has already been grabbed to the workspace grid with
            #   ';grabwindow' and then removed from it with ';banishwindow', it will be minimised.
            #   In any case, if the window is minimised, it should be unminimised before being
            #   restacked
            $winObj->unminimise();
        }

        # The workspace grid's new current layer is the layer in which this window will be
        #   placed (so that it's visible to the user immediately)
        $workspaceGridObj->set_currentLayer($layer);

        # Make sure all windows on the workspace grid are stacked correctly, so that windows in
        #   lower layers are beneath windows in higher layers (but windows in a layer higher than
        #   the workspace grid's current layer are minimised)
        $zoneObj->restackWin();

        # GA::Obj::Zone->adjustSingleWin is called above to fill in small gaps in the zone. Now,
        #   if the zone is wide enough (and its orientation is 'horizontal') or high enough (and its
        #   orientation is 'vertical') for only one area of the zone's default size, then consider
        #   expanding all of the areas in the zone to fill gaps that are bigger than a gridblock
        #   or two, but still not big enough to hold another area
        # If it would be better to reduce all the area sizes in order to make room for another
        #   area, some time in the future, do that instead. Leave enough room for an area of the

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

                $widthPixels = $axmud::CLIENT->customGridWinWidth;
                $heightPixels = $axmud::CLIENT->customGridWinHeight;
            }
        }

        # Convert a winmap name to a winmap object. If no winmap was specified, use a default one
        $winmapObj = $self->getWinmap($winType, $winmapName);
        if (! defined $winmapObj) {

            # No winmap name specified, or winmap doesn't exist, so use a default winmap
            if ($winType eq 'main') {

                if ($self->gridEnableFlag && $axmud::CLIENT->activateGridFlag) {

                    $winmapObj = $axmud::CLIENT->ivShow(
                        'winmapHash',
                        $axmud::CLIENT->defaultEnabledWinmap,
                    );

                } else {

                    $winmapObj = $axmud::CLIENT->ivShow(
                        'winmapHash',
                        $axmud::CLIENT->defaultDisabledWinmap,
                    );
                }

            } elsif ($winType ne 'external') {

                $winmapObj
                    = $axmud::CLIENT->ivShow('winmapHash', $axmud::CLIENT->defaultInternalWinmap);
            }
        }

        # We need to specify a winmap name or 'undef' in the call to ->new
        if ($winmapObj) {
            $winmapName = $winmapObj->name;
        } else {
            $winmapName = undef;
        }

        # Create a new window object
        if (! defined $packageName) {

            if ($winType eq 'external') {

                $packageName = 'Games::Axmud::Win::External';

            } elsif ($winType eq 'map') {

                $packageName = 'Games::Axmud::Win::Map';

            } else {

                # $winType is 'main', 'protocol', 'custom'
                $packageName = 'Games::Axmud::Win::Internal';
            }
        }

        $winObj = $packageName->new(
            $axmud::CLIENT->desktopObj->gridWinCount,
            $winType,
            $winName,
            $self,
            $owner,
            $session,
            undef,
            undef,
            $winmapName,
        );

        # (The check for ->winType makes sure that plugins don't create, for example, a 'free'
        #   window and then try to add it via a call to GA::Client->createGridWin)
        if (! $winObj || $winObj->winCategory ne 'grid' || $winObj->winType ne $winType) {

            # Something or other failed
            return undef;
        }

        # Update the GA::Obj::Desktop object's registry of all 'grid' windows
        $axmud::CLIENT->desktopObj->add_gridWin($winObj);

        # Move the window to its correct workspace, size and position
        if ($winType ne 'external') {

            # Create a new Gtk3::Window widget (but don't make it visible yet)
            if (! $winObj->winSetup($winTitle, $beforeListRef)) {

                # Something or other failed
                return undef;
            }

            # If a size and/or position were specified, move the window
            if (
                (defined $xPosPixels && defined $yPosPixels)
                || (defined $widthPixels && defined $heightPixels)
            ) {
                $self->moveResizeWin(
                    $winObj,
                    $xPosPixels,
                    $yPosPixels,
                    $widthPixels,
                    $heightPixels,
                );
            }

            # Make the window actually visible, if it's not already visible
            if (! $winObj->enabledFlag) {

                $winObj->winEnable($afterListRef);
            }

            # Update the GA::Client's hash of stored window positions (if required)
            if ($winObj->winWidget) {

                $axmud::CLIENT->add_storeGridPosn(
                    $winObj,
                    $winObj->winWidget->get_position(),
                    $winObj->winWidget->get_size(),
                );
            }

        } else {

            # Update the 'external' window object's IVs
            if (! $winObj->winSetup($internalID)) {

                # Something or other failed
                return undef;
            }

            # If a size and/or position were specified, move the window
            if (
                (defined $xPosPixels && defined $yPosPixels)
                || (defined $widthPixels && defined $heightPixels)
            ) {
                $self->moveResizeWin(
                    $winObj,
                    ($xPosPixels - $self->controlsLeftSize),
                    ($yPosPixels - $self->controlsTopSize),
                    $widthPixels,
                    $heightPixels,
                );
            }

            # Make the window actually visible, if it's not already visible
            if (! $winObj->enabledFlag) {

                $winObj->winEnable($afterListRef);
            }

            # If this 'external' window has already been grabbed to the workspace grid with
            #   ';grabwindow' and then removed from it with ';banishwindow', it will be minimised.
            #   In any case, if the window is minimised, it should be unminimised before being
            #   restacked
            $axmud::CLIENT->desktopObj->wmCtrlObj->unminimize($internalID);
        }

        # Windows created via this function always have the focus (unlike those created by calls to
        #   $self->createGridWin, in which the 'main' windows is always given focus)
        $winObj->restoreFocus();

        # Return the blessed reference of the new window object to show success
        return $winObj;
    }

    sub chooseZone {

        # Called by $self->createGridWin, when that function is asked to create a window in an
        #   unspecified zone
        # Also called by GA::Session->setMainWin when there are no sessions, to move the spare
        #   'main' window into the first available zone
        #
        # Decides which zone in the specified workspace grid to place the window. If it's not
        #   possible to place the window in any of them, returns 'undef'
        #
        # Expected arguments
        #   $workspaceGridObj
        #                   - The GA::Obj::WorkspaceGrid object which will receive the new window
        #   $winType        - The window type; one of the 'grid' window types specified by
        #                       GA::Client->constGridWinTypeHash
        #   $winName        - The window name
        #                       $winType    $winName
        #                       --------    --------
        #                       main        main
        #                       map         map
        #                       protocol    Any string chosen by the protocol code (default value is
        #                                       'protocol')
        #                       fixed       Any string chosen by the controlling code (default value
        #                                       is 'fixed')
        #                       custom      Any string chosen by the controlling code. For task
        #                                       windows, the name of the task (e.g. 'status_task',
        #                                       for other windows, default value is 'custom'
        #                       external    The 'external' window's name (e.g. 'Notepad')
        #
        # Optional arguments
        #   $winWidget      - The Gtk3::Window, if it already exists and it is known (otherwise set
        #                       to 'undef')
        #   $internalID     - For 'external' windows, the window internal ID, provided by
        #                       X11::WMCtrl ('undef' for other types of window)
        #   $owner          - The owner, if known. Can be any blessed reference, typically it's an
        #                       GA::Session or a task (inheriting from GA::Generic::Task)
        #   $session        - The owner's session. If $owner is a GA::Session, that session. If
        #                       it's something else (like a task), the task's session. If $owner is
        #                       'undef', so is $session
        #
        # Return values
        #   'undef' on improper arguments or if no zone is available for this window
        #   Otherwise, returns the chosen GA::Obj::Zone

        my (
            $self, $workspaceGridObj, $winType, $winName, $winWidget, $internalID, $owner, $session,
            $check,
        ) = @_;

        # Local variables

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN

        # Also called by GA::Obj::WorkspaceGrid->applyZonemap
        #
        # Expected arguments
        #   $winType    - The window type; one of the 'grid' window types specified by
        #                   GA::Client->constGridWinTypeHash
        #   $workspaceGridObj
        #               - The GA::Obj::WorkspaceGrid object which will receive the new window
        #   $zoneObj    - Blessed reference to the GA::Obj::Zone object, handling the zone in which
        #                   the window will be placed
        #
        # Optional arguments
        #   $zoneSpecifiedFlag
        #               - Set to TRUE if the function that called $self->createGridWin specified a
        #                   zone to use, otherwise set to FALSE. Set to 'undef' when called by
        #                   any other function
        #   $widthPixels, $heightPixels
        #               - The size of the window specified by the function that called
        #                   $self->createGridWin. Both set to 'undef' if no size was specified
        #
        # Return values
        #   An empty list on improper arguments
        #   Otherwise, returns the list ($widthPixels, $heightPixels)

        my (
            $self, $winType, $workspaceGridObj, $zoneObj, $zoneSpecifiedFlag, $widthPixels,
            $heightPixels, $check,
        ) = @_;

        # Local variables
        my (
            $blockSize,
            @emptyList,
        );

        # Check for improper arguments
        if (
            ! defined $winType || ! defined $workspaceGridObj || ! defined $zoneObj
            || defined $check
        ) {
            $axmud::CLIENT->writeImproper($self->_objClass . '->chooseWinSize', @_);
            return @emptyList;
        }

        # Import the standard gridblock size (in pixels) for convenience
        $blockSize = $axmud::CLIENT->gridBlockSize;

        # On the original call to $self->createGridWin, if a zone number wasn't specified and one
        #   (but not both) of $widthPixels / $heightPixels weren't specified, use default values for
        #   the width and height
        # Exception: if this window is a 'main' window and it's the first window ever created,
        #   assume that the Axmud is still setting up. If there is more than one zone, set the
        #   'main' window to fill the zone. If there is only one zone, use the default 'main' window
        #   size
        if (
            ! $zoneSpecifiedFlag
            && (
                (defined $widthPixels && ! defined $heightPixels)
                || (defined $heightPixels && ! defined $widthPixels)
            )
        ) {
            if ($winType eq 'main' && ! $axmud::CLIENT->desktopObj->gridWinHash) {

                # It's the 'main' window, which is almost always in zone 1
                if ($workspaceGridObj->zoneCount == 1) {

                    $widthPixels = $axmud::CLIENT->customMainWinWidth;
                    $heightPixels = $axmud::CLIENT->customMainWinHeight;

                } else {

                    $widthPixels = ($zoneObj->widthBlocks * $blockSize);
                    $heightPixels = ($zoneObj->heightBlocks * $blockSize);
                }

            } else {

                if (! defined $widthPixels) {

                    $widthPixels = $axmud::CLIENT->customGridWinWidth;

                } elsif (! defined $heightPixels) {

                    $heightPixels = $axmud::CLIENT->customGridWinHeight;
                }
            }

        # In a positioning free-for-all (zonemap 'single'), let a 'main' window use its own default
        #   size
        } elsif ($winType eq 'main' && $workspaceGridObj->zonemap eq 'single') {

            $widthPixels = $axmud::CLIENT->customMainWinWidth;
            $heightPixels = $axmud::CLIENT->customMainWinHeight;

        # Most of the time, use the zone's default width and height if those defaults are specified.
        #   Take into account any adjustment to the zone's default width and height that
        #   $zoneObj->adjustMultipleWin might have made
        # If the zone's default values aren't specified, use the global default values
        } else {

            if (! defined $widthPixels) {

                if ($zoneObj->defaultAreaWidth) {

                    $widthPixels
                        = ($zoneObj->defaultAreaWidth + $zoneObj->widthAdjustBlocks) * $blockSize;

                } else {

                    $widthPixels = $axmud::CLIENT->customGridWinWidth;
                }
            }

            if (! defined $heightPixels) {

                if ($zoneObj->defaultAreaHeight) {

                    $heightPixels
                        = ($zoneObj->defaultAreaHeight + $zoneObj->heightAdjustBlocks) * $blockSize;

                } else {

lib/Games/Axmud/Obj/Workspace.pm  view on Meta::CPAN


        # If $layer wasn't specified, use the default layer provisionally
        if (! defined $layer) {

            $layer = $workspaceGridObj->defaultLayer;

        # Otherwise, check that the specified layer is valid (and use the default one if
        #   not)
        } elsif (! $axmud::CLIENT->intCheck($layer, 0, ($workspaceGridObj->maxLayers - 1))) {

            $complainant->writeWarning(
                'The specified layer #' . $layer . ' is not valid, using the default layer #'
                . $workspaceGridObj->defaultLayer,
                $self->_objClass . '->chooseWinPosn',
            );

            $layer = $workspaceGridObj->defaultLayer;
        }

        # Place the window at some position within the zone (hopefully at the provisional one, on
        #   the default layer)
        ($successFlag, $layer, $xPosBlocks, $yPosBlocks)
            = $zoneObj->placeWin($layer, $xPosBlocks, $yPosBlocks, $widthBlocks, $heightBlocks);

        if (! $successFlag) {

            # There is no room for the window in this zone
            $complainant->writeError(
                'Couldn\'t find room for the \'' . $winType . '\' window anywhere in zone #'
                . $zoneObj->number,
                $self->_objClass . '->chooseWinPosn',
            );

            return @emptyList;
        }

        # If the window position on the grid puts it rather close to the edge (or edges) of the
        #   zone, and if the gaps between the window and the zone's edge are empty, adjust the size
        #   of the window to fill the gap (this prevents small areas of the zone from always being
        #   empty: makes the workspace look nice). If the maximum allowable gap size is 0, don't
        #   fill gaps at all
        if ($axmud::CLIENT->gridGapMaxSize) {

            ($xPosBlocks, $yPosBlocks, $widthBlocks, $heightBlocks)
                = $zoneObj->adjustSingleWin(
                    $layer,
                    $xPosBlocks,
                    $yPosBlocks,
                    $widthBlocks,
                    $heightBlocks,
            );
        }

        # Now that we have the window's final size and position in the zone, reset the variables
        #   that show the window's size and position, in pixels, on the workspace
        ($xPosPixels, $yPosPixels) = $zoneObj->getInternalGridPosn($xPosBlocks, $yPosBlocks);

        $widthPixels = $widthBlocks * $axmud::CLIENT->gridBlockSize;
        $heightPixels = $heightBlocks * $axmud::CLIENT->gridBlockSize;

        # If the desktop theme uses window controls, we have to take them into account, changing the
        #   size of the window accordingly
        ($xPosPixels, $yPosPixels, $widthPixels, $heightPixels)
            = $workspaceGridObj->fineTuneWinSize(
                $winType,
                $xPosPixels,
                $yPosPixels,
                $widthPixels,
                $heightPixels
        );

        return (
            $layer, $xPosBlocks, $yPosBlocks, $widthBlocks, $heightBlocks, $xPosPixels, $yPosPixels,
            $widthPixels, $heightPixels,
        );
    }

    sub getWinmap {

        # Called by $self->createGridWin or $self->createSimpleGridWin
        # If a winmap name was specified as an argument to those functions, selects the
        #   corresponding winmap object (if it exists)
        # Otherwise selects a default winmap object, or 'undef' for 'map', 'fixed' and 'external'
        #   windows (which don't use winmaps)
        # 'main' windows must contain at least one winzone which creates a pane object
        #   (GA::Table::Pane). For 'main' windows, if the selected winmap doesn't contain a pane
        #   object, a standard winmap is used instead
        #
        # Expected arguments
        #   $winType        - The window type; one of the 'grid' window types specified by
        #                       GA::Client->constGridWinTypeHash
        #
        # Optional arguments
        #   $winmapName     - The winmap name specified as an argument in the calls to
        #                       $self->createGridWin or $self->createSimpleGridWin (may be 'undef')
        #   $zoneObj        - When called by $self->createGridWin, the GA::Obj::Zone into which the
        #                       window will be moved. When called by $self->createSimpleGridWin,
        #                       'undef'
        #
        # Return values
        #   'undef' on improper arguments or if no winmap object is created
        #   Otherwise, returns a winmap object (GA::Obj::Winmap)

        my ($self, $winType, $winmapName, $zoneObj, $check) = @_;

        # Local variables
        my ($winmapObj, $flag);

        # Check for improper arguments
        if (defined $check) {

            return $axmud::CLIENT->writeImproper($self->_objClass . '->getWinmap', @_);
        }

        # Convert a winmap name to a winmap object. If no winmap was specified, use a default one
        if (! defined $winType || defined $winmapName) {

            $winmapObj = $axmud::CLIENT->ivShow('winmapHash', $winmapName);
        }

        if (! $winmapObj) {



( run in 0.950 second using v1.01-cache-2.11-cpan-f56aa216473 )