2017-09-16 03:01:49 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
Copyright 1989, 1998 The Open Group
|
|
|
|
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
the above copyright notice appear in all copies and that both that
|
|
|
|
copyright notice and this permission notice appear in supporting
|
|
|
|
documentation.
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
* */
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
*
|
|
|
|
* Icon releated routines
|
|
|
|
*
|
|
|
|
* 10-Apr-89 Tom LaStrange Initial Version.
|
|
|
|
*
|
|
|
|
**********************************************************************/
|
|
|
|
|
2019-10-07 02:28:07 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
2017-09-16 03:01:49 +00:00
|
|
|
#include "twm.h"
|
|
|
|
#include "screen.h"
|
|
|
|
#include "icons.h"
|
|
|
|
#include "gram.h"
|
|
|
|
#include "parse.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
2019-10-22 03:35:52 +00:00
|
|
|
// DEBUG
|
|
|
|
#include <iostream>
|
2019-10-07 02:28:07 +00:00
|
|
|
using namespace std;
|
2017-09-16 03:01:49 +00:00
|
|
|
|
2019-10-12 13:50:27 +00:00
|
|
|
const int icon_area_w = 70;
|
|
|
|
const int icon_pad = 8;
|
2017-09-16 03:01:49 +00:00
|
|
|
|
2019-10-07 02:28:07 +00:00
|
|
|
#define iconWidth(w) (BW2 + w->icon_w_width)
|
|
|
|
#define iconHeight(w) (BW2 + w->icon_w_height)
|
2017-09-16 03:01:49 +00:00
|
|
|
|
|
|
|
static inline int
|
|
|
|
roundUp (int v, int multiple)
|
|
|
|
{
|
|
|
|
return ((v + multiple - 1) / multiple) * multiple;
|
|
|
|
}
|
|
|
|
|
2019-10-07 02:28:07 +00:00
|
|
|
struct Span {
|
|
|
|
int p1, p2;
|
|
|
|
};
|
|
|
|
inline bool operator<(Span a, Span b)
|
|
|
|
{
|
|
|
|
return a.p1 == b.p1 && a.p2 < b.p2 || a.p1 < b.p1;
|
|
|
|
}
|
|
|
|
|
2017-09-16 03:01:49 +00:00
|
|
|
static void
|
|
|
|
PlaceIcon(TwmWindow *tmp_win, int def_x, int def_y, int *final_x, int *final_y)
|
|
|
|
{
|
2019-10-12 13:50:27 +00:00
|
|
|
// TODO: one value initialized once wouldn't cut it for multiscreen.
|
|
|
|
static int icon_area_x = 0; // icons are dropped to the right of this x.
|
|
|
|
if (icon_area_x == 0) {
|
|
|
|
icon_area_x = Scr->MyDisplayWidth - icon_area_w;
|
|
|
|
}
|
|
|
|
|
2019-10-08 03:58:20 +00:00
|
|
|
// Try to place in a gap along the right side of (current?) screen.
|
2019-10-07 02:28:07 +00:00
|
|
|
|
|
|
|
int y = 0;
|
2019-10-08 03:58:20 +00:00
|
|
|
vector<Span> occupied;
|
2019-10-22 03:35:52 +00:00
|
|
|
cerr << "tmp_win: " << tmp_win->name << '\n';
|
2019-10-08 03:58:20 +00:00
|
|
|
for (TwmWindow* pw = Scr->TwmRoot.next; pw; pw = pw->next) {
|
|
|
|
// Iconified means was it ever iconified.
|
|
|
|
if (pw->iconified) {
|
2019-10-22 03:35:52 +00:00
|
|
|
cerr << "pw, iconfified: " << pw->name << '\n';
|
2019-10-08 03:58:20 +00:00
|
|
|
Window root;
|
|
|
|
int icon_x, icon_y;
|
|
|
|
unsigned icon_w, icon_h, border_width, depth;
|
|
|
|
if (pw->icon_w
|
|
|
|
&& XGetGeometry(dpy, pw->icon_w, &root,
|
|
|
|
&icon_x, &icon_y, &icon_w, &icon_h,
|
|
|
|
&border_width, &depth)) {
|
|
|
|
if (icon_x >= icon_area_x)
|
|
|
|
occupied.push_back({icon_y, icon_y + static_cast<int>(icon_h)});
|
2019-10-07 02:28:07 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-08 03:58:20 +00:00
|
|
|
else {
|
2019-10-22 03:35:52 +00:00
|
|
|
cerr << "pw, non-iconfified: " << pw->name << '\n';
|
|
|
|
|
2019-10-08 03:58:20 +00:00
|
|
|
// A small non-iconified window sitting where an icon would? E.g. xclock.
|
|
|
|
// I assume here that non-iconified windows that look like icons won't
|
|
|
|
// ever be iconified, making this an either or decision.
|
|
|
|
if (pw->frame_x >= icon_area_x
|
|
|
|
&& pw->frame_width <= 150 && pw->frame_height <= 150) {
|
|
|
|
|
|
|
|
occupied.push_back({pw->frame_y, pw->frame_y + pw->frame_height});
|
|
|
|
}
|
2019-10-07 02:28:07 +00:00
|
|
|
}
|
2019-10-08 03:58:20 +00:00
|
|
|
}
|
2019-10-12 13:50:27 +00:00
|
|
|
const int h = tmp_win->icon_w_height ? tmp_win->icon_w_height : 64;
|
2019-10-07 02:28:07 +00:00
|
|
|
|
2019-10-22 03:35:52 +00:00
|
|
|
if (occupied.size() == 0) {
|
|
|
|
y = Scr->MyDisplayHeight - h;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sort(occupied.begin(), occupied.end());
|
|
|
|
int prev = 0;
|
|
|
|
for (auto span : occupied) {
|
|
|
|
if (span.p1 - prev >= h) {
|
|
|
|
if (span.p1 - prev >= h + 2*icon_pad)
|
|
|
|
y = prev + icon_pad;
|
|
|
|
else
|
|
|
|
y = prev;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = span.p2;
|
2017-09-16 03:01:49 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-07 02:28:07 +00:00
|
|
|
|
|
|
|
if (y) {
|
2019-10-12 13:50:27 +00:00
|
|
|
const int w = tmp_win->icon_w_width ? tmp_win->icon_w_width : 64;
|
|
|
|
const int offset = (icon_area_w - w) / 2;
|
|
|
|
if (offset > 0) {
|
|
|
|
*final_x = icon_area_x + offset;
|
|
|
|
} else
|
|
|
|
*final_x = icon_area_x + icon_pad;
|
2019-10-07 02:28:07 +00:00
|
|
|
*final_y = y;
|
2017-09-16 03:01:49 +00:00
|
|
|
} else {
|
|
|
|
*final_x = def_x;
|
|
|
|
*final_y = def_y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IconUp (TwmWindow *tmp_win)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IconDown (TwmWindow *tmp_win)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CreateIconWindow(TwmWindow *tmp_win, int def_x, int def_y)
|
|
|
|
{
|
|
|
|
unsigned long event_mask;
|
|
|
|
unsigned long valuemask; /* mask for create windows */
|
|
|
|
XSetWindowAttributes attributes; /* attributes for create windows */
|
|
|
|
Pixmap pm = None; /* tmp pixmap variable */
|
|
|
|
int final_x, final_y;
|
|
|
|
int x;
|
|
|
|
|
|
|
|
|
|
|
|
FB(tmp_win->iconc.fore, tmp_win->iconc.back);
|
|
|
|
|
|
|
|
tmp_win->forced = FALSE;
|
|
|
|
tmp_win->icon_not_ours = FALSE;
|
|
|
|
|
|
|
|
/* now go through the steps to get an icon window, if ForceIcon is
|
|
|
|
* set, then no matter what else is defined, the bitmap from the
|
|
|
|
* .twmrc file is used
|
|
|
|
*/
|
|
|
|
if (Scr->ForceIcon)
|
|
|
|
{
|
|
|
|
char *icon_name;
|
|
|
|
Pixmap bm;
|
|
|
|
|
|
|
|
icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
|
|
|
|
if (icon_name == NULL)
|
|
|
|
icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
|
2019-10-07 02:28:07 +00:00
|
|
|
&tmp_win->classh);
|
2017-09-16 03:01:49 +00:00
|
|
|
|
|
|
|
bm = None;
|
|
|
|
if (icon_name != NULL)
|
|
|
|
{
|
|
|
|
if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
|
|
|
|
{
|
|
|
|
if ((bm = GetBitmap (icon_name)) != None)
|
|
|
|
AddToList(&Scr->Icons, icon_name, (char *)bm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bm != None)
|
|
|
|
{
|
|
|
|
XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
|
|
|
|
(unsigned int *) &tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
|
|
|
|
&JunkBW, &JunkDepth);
|
|
|
|
|
|
|
|
pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
|
|
|
|
tmp_win->icon_height, Scr->d_depth);
|
|
|
|
|
|
|
|
/* the copy plane works on color ! */
|
|
|
|
XCopyPlane(dpy, bm, pm, Scr->NormalGC,
|
|
|
|
0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
|
|
|
|
|
|
|
|
tmp_win->forced = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the pixmap is still NULL, we didn't get one from the above code,
|
|
|
|
* that could mean that ForceIcon was not set, or that the window
|
|
|
|
* was not in the Icons list, now check the WM hints for an icon
|
|
|
|
*/
|
|
|
|
if (pm == None && tmp_win->wmhints &&
|
|
|
|
tmp_win->wmhints->flags & IconPixmapHint)
|
|
|
|
{
|
|
|
|
|
|
|
|
XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap,
|
|
|
|
&JunkRoot, &JunkX, &JunkY,
|
|
|
|
(unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, &JunkBW, &JunkDepth);
|
|
|
|
|
|
|
|
pm = XCreatePixmap(dpy, Scr->Root,
|
|
|
|
tmp_win->icon_width, tmp_win->icon_height,
|
|
|
|
Scr->d_depth);
|
|
|
|
|
|
|
|
XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
|
|
|
|
0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we still haven't got an icon, let's look in the Icon list
|
|
|
|
* if ForceIcon is not set
|
|
|
|
*/
|
|
|
|
if (pm == None && !Scr->ForceIcon)
|
|
|
|
{
|
|
|
|
char *icon_name;
|
|
|
|
Pixmap bm;
|
|
|
|
|
|
|
|
icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
|
|
|
|
if (icon_name == NULL)
|
|
|
|
icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
|
2019-10-07 02:28:07 +00:00
|
|
|
&tmp_win->classh);
|
2017-09-16 03:01:49 +00:00
|
|
|
|
|
|
|
bm = None;
|
|
|
|
if (icon_name != NULL)
|
|
|
|
{
|
|
|
|
if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
|
|
|
|
{
|
|
|
|
if ((bm = GetBitmap (icon_name)) != None)
|
|
|
|
AddToList(&Scr->Icons, icon_name, (char *)bm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bm != None)
|
|
|
|
{
|
|
|
|
XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
|
|
|
|
(unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
|
|
|
|
&JunkBW, &JunkDepth);
|
|
|
|
|
|
|
|
pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
|
|
|
|
tmp_win->icon_height, Scr->d_depth);
|
|
|
|
|
|
|
|
/* the copy plane works on color ! */
|
|
|
|
XCopyPlane(dpy, bm, pm, Scr->NormalGC,
|
|
|
|
0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we still don't have an icon, assign the UnknownIcon */
|
|
|
|
|
|
|
|
if (pm == None && Scr->UnknownPm != None)
|
|
|
|
{
|
|
|
|
tmp_win->icon_width = Scr->UnknownWidth;
|
|
|
|
tmp_win->icon_height = Scr->UnknownHeight;
|
|
|
|
|
|
|
|
pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
|
|
|
|
tmp_win->icon_height, Scr->d_depth);
|
|
|
|
|
|
|
|
/* the copy plane works on color ! */
|
|
|
|
XCopyPlane(dpy, Scr->UnknownPm, pm, Scr->NormalGC,
|
|
|
|
0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pm == None)
|
|
|
|
{
|
|
|
|
tmp_win->icon_height = 0;
|
|
|
|
tmp_win->icon_width = 0;
|
|
|
|
valuemask = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valuemask = CWBackPixmap;
|
|
|
|
attributes.background_pixmap = pm;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_win->icon_w_width = MyFont_TextWidth(&Scr->IconFont,
|
|
|
|
tmp_win->icon_name, strlen(tmp_win->icon_name));
|
|
|
|
|
|
|
|
tmp_win->icon_w_width += 6;
|
|
|
|
if (tmp_win->icon_w_width < tmp_win->icon_width)
|
|
|
|
{
|
|
|
|
tmp_win->icon_x = (tmp_win->icon_width - tmp_win->icon_w_width)/2;
|
|
|
|
tmp_win->icon_x += 3;
|
|
|
|
tmp_win->icon_w_width = tmp_win->icon_width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp_win->icon_x = 3;
|
|
|
|
}
|
|
|
|
tmp_win->icon_y = tmp_win->icon_height + Scr->IconFont.height;
|
|
|
|
tmp_win->icon_w_height = tmp_win->icon_height + Scr->IconFont.height + 4;
|
|
|
|
|
|
|
|
event_mask = 0;
|
|
|
|
if (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)
|
|
|
|
{
|
|
|
|
tmp_win->icon_w = tmp_win->wmhints->icon_window;
|
|
|
|
if (tmp_win->forced ||
|
|
|
|
XGetGeometry(dpy, tmp_win->icon_w, &JunkRoot, &JunkX, &JunkY,
|
|
|
|
(unsigned int *)&tmp_win->icon_w_width, (unsigned int *)&tmp_win->icon_w_height,
|
|
|
|
&JunkBW, &JunkDepth) == 0)
|
|
|
|
{
|
|
|
|
tmp_win->icon_w = None;
|
|
|
|
tmp_win->wmhints->flags &= ~IconWindowHint;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp_win->icon_not_ours = TRUE;
|
|
|
|
event_mask = EnterWindowMask | LeaveWindowMask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp_win->icon_w = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp_win->icon_w == None)
|
|
|
|
{
|
|
|
|
tmp_win->icon_w = XCreateSimpleWindow(dpy, Scr->Root,
|
|
|
|
0,0,
|
|
|
|
tmp_win->icon_w_width, tmp_win->icon_w_height,
|
2018-09-07 01:22:43 +00:00
|
|
|
BW, tmp_win->icon_border, tmp_win->iconc.back);
|
2017-09-16 03:01:49 +00:00
|
|
|
event_mask = ExposureMask;
|
|
|
|
}
|
|
|
|
|
|
|
|
XSelectInput (dpy, tmp_win->icon_w,
|
|
|
|
KeyPressMask | ButtonPressMask | ButtonReleaseMask |
|
|
|
|
event_mask);
|
|
|
|
|
|
|
|
tmp_win->icon_bm_w = None;
|
|
|
|
if (pm != None &&
|
|
|
|
(! (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)))
|
|
|
|
{
|
|
|
|
int y;
|
|
|
|
|
|
|
|
y = 0;
|
|
|
|
if (tmp_win->icon_w_width == tmp_win->icon_width)
|
|
|
|
x = 0;
|
|
|
|
else
|
|
|
|
x = (tmp_win->icon_w_width - tmp_win->icon_width)/2;
|
|
|
|
|
|
|
|
tmp_win->icon_bm_w = XCreateWindow (dpy, tmp_win->icon_w, x, y,
|
|
|
|
(unsigned int)tmp_win->icon_width,
|
|
|
|
(unsigned int)tmp_win->icon_height,
|
|
|
|
(unsigned int) 0, Scr->d_depth,
|
|
|
|
(unsigned int) CopyFromParent,
|
|
|
|
Scr->d_visual, valuemask,
|
|
|
|
&attributes);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* I need to figure out where to put the icon window now, because
|
|
|
|
* getting here means that I am going to make the icon visible
|
|
|
|
*/
|
|
|
|
if (tmp_win->wmhints &&
|
|
|
|
tmp_win->wmhints->flags & IconPositionHint)
|
|
|
|
{
|
|
|
|
final_x = tmp_win->wmhints->icon_x;
|
|
|
|
final_y = tmp_win->wmhints->icon_y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (final_x > Scr->MyDisplayWidth)
|
2018-09-07 01:22:43 +00:00
|
|
|
final_x = Scr->MyDisplayWidth - tmp_win->icon_w_width - BW2;
|
2017-09-16 03:01:49 +00:00
|
|
|
|
|
|
|
if (final_y > Scr->MyDisplayHeight)
|
|
|
|
final_y = Scr->MyDisplayHeight - tmp_win->icon_height -
|
2018-09-07 01:22:43 +00:00
|
|
|
Scr->IconFont.height - 4 - BW2;
|
2017-09-16 03:01:49 +00:00
|
|
|
|
|
|
|
XMoveWindow(dpy, tmp_win->icon_w, final_x, final_y);
|
|
|
|
tmp_win->iconified = TRUE;
|
|
|
|
|
|
|
|
XMapSubwindows(dpy, tmp_win->icon_w);
|
|
|
|
XSaveContext(dpy, tmp_win->icon_w, TwmContext, (caddr_t)tmp_win);
|
|
|
|
XSaveContext(dpy, tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
|
|
|
|
XDefineCursor(dpy, tmp_win->icon_w, Scr->IconCursor);
|
|
|
|
if (pm) XFreePixmap (dpy, pm);
|
|
|
|
return;
|
|
|
|
}
|