1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-22 14:08:06 +01:00

Add drawers to wmaker!

Drawers are horizontal docks, and they can themselves only live in the dock

To use them, right click on the dock or a docked appicon and select "Add
a drawer". Then move appicons into the drawer (drag them with the
mouse). You may change the icon of the drawer. By default, drawers
auto-expand and -collapse, and auto-raise/lower. This can be customized
in the same way as for the clip.

Set DisableDrawers to YES in G/D/WindowMaker if you do not want to see
the menu entry to add a drawer.

Just discovered this bug: the auto-attract icon functionality will not
work (to be precise, it crashes WM!) if the clip is disabled
(NoClip=YES). Will fix shortly, of course.
This commit is contained in:
Daniel Déchelotte
2013-04-12 01:42:41 +02:00
committed by Carlos R. Mafra
parent 707ce34a5e
commit e14e6b3da8
19 changed files with 1560 additions and 220 deletions

View File

@@ -199,7 +199,7 @@ void paint_app_icon(WApplication *wapp)
{
WIcon *icon;
WScreen *scr = wapp->main_window_desc->screen_ptr;
WDock *clip = scr->workspaces[scr->current_workspace]->clip;
WDock *attracting_dock;
int x = 0, y = 0;
Bool update_icon = False;
@@ -213,13 +213,17 @@ void paint_app_icon(WApplication *wapp)
if (wapp->app_icon->docked)
return;
if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
attracting_dock = scr->attracting_drawer != NULL ?
scr->attracting_drawer :
scr->workspaces[scr->current_workspace]->clip;
if (attracting_dock && attracting_dock->attract_icons &&
wDockFindFreeSlot(attracting_dock, &x, &y)) {
wapp->app_icon->attracted = 1;
if (!icon->shadowed) {
icon->shadowed = 1;
update_icon = True;
}
wDockAttachIcon(clip, wapp->app_icon, x, y, update_icon);
wDockAttachIcon(attracting_dock, wapp->app_icon, x, y, update_icon);
} else {
/* We must know if the icon is painted in the screen,
* because if painted, then PlaceIcon will return the next
@@ -238,7 +242,7 @@ void paint_app_icon(WApplication *wapp)
wapp->app_icon->next == NULL && wapp->app_icon->prev == NULL)
add_to_appicon_list(scr, wapp->app_icon);
if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
if (!attracting_dock || !wapp->app_icon->attracted || !attracting_dock->collapsed)
XMapWindow(dpy, icon->core->window);
if (wPreferences.auto_arrange_icons && !wapp->app_icon->attracted)
@@ -270,6 +274,9 @@ void removeAppIconFor(WApplication *wapp)
wAppIconPaint(wapp->app_icon);
} else if (wapp->app_icon->docked) {
wapp->app_icon->running = 0;
if (wapp->app_icon->dock->type == WM_DRAWER) {
wDrawerFillTheGap(wapp->app_icon->dock, wapp->app_icon, True);
}
wDockDetach(wapp->app_icon->dock, wapp->app_icon);
} else {
wAppIconDestroy(wapp->app_icon);
@@ -723,9 +730,12 @@ void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
{
WIcon *icon = aicon->icon;
WScreen *scr = icon->core->screen_ptr;
WDock *originalDock = aicon->dock; /* can be NULL */
WDock *lastDock = originalDock;
WDock *allDocks[2]; /* clip and dock (order to be determined at runtime) */
WDock *allDocks[scr->drawer_count + 2]; /* clip, dock and drawers (order determined at runtime) */
WDrawerChain *dc;
Bool done = False, dockable, ondock;
Bool grabbed = False;
Bool collapsed = False; /* Stores the collapsed state of lastDock, before the moving appicon entered it */
@@ -733,8 +743,6 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
int omnipresent = aicon->omnipresent; /* this must be cached */
Bool showed_all_clips = False;
WIcon *icon = aicon->icon;
WScreen *scr = icon->core->screen_ptr;
int clickButton = event->xbutton.button;
Pixmap ghost = None;
Window wins[2]; /* Managing shadow window */
@@ -773,7 +781,7 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
}
else {
ondock = False;
if (wPreferences.flags.nodock && wPreferences.flags.noclip)
if (wPreferences.flags.nodock && wPreferences.flags.noclip && wPreferences.flags.nodrawer)
dockable = 0;
else
dockable = canBeDocked(icon->owner);
@@ -781,21 +789,26 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
/* We try the various docks in that order:
* - First, the dock the appicon comes from, if any
* - Then, the drawers
* - Then, the "dock" (WM_DOCK)
* - Finally, the clip
*/
i = 0;
if (originalDock != NULL)
allDocks[ i++ ] = originalDock;
/* Testing scr->drawers is enough, no need to test wPreferences.flags.nodrawer */
for (dc = scr->drawers; dc != NULL; dc = dc->next) {
if (dc->adrawer != originalDock)
allDocks[ i++ ] = dc->adrawer;
}
if (!wPreferences.flags.nodock && scr->dock != originalDock)
allDocks[ i++ ] = scr->dock;
if (!wPreferences.flags.noclip &&
originalDock != scr->workspaces[scr->current_workspace]->clip)
allDocks[ i++ ] = scr->workspaces[scr->current_workspace]->clip;
for ( ; i < 2; i++) /* In case the clip, the dock, or both, are disabled */
for ( ; i < scr->drawer_count + 2; i++) /* In case the clip, the dock, or both, are disabled */
allDocks[ i ] = NULL;
wins[0] = icon->core->window;
wins[1] = scr->dock_shadow;
XRestackWindows(dpy, wins, 2);
@@ -856,31 +869,28 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
y = ev.xmotion.y_root - ofs_y;
wAppIconMove(aicon, x, y);
/* At a high level, this if-block is about setting theNewDock to
* the first dock that could snap the appicon at the current
* position, and the next if-block uses that and other info to
* determine whether to dock/undock.
*/
WDock *theNewDock = NULL;
for (i = 0; dockable && i < 2; i++) {
WDock *theDock = allDocks[i];
if (theDock == NULL)
break;
if (wDockSnapIcon(theDock, aicon, x, y, &ix, &iy, (theDock == originalDock))) {
theNewDock = theDock;
break;
if (!(ev.xmotion.state & MOD_MASK) || aicon->launching || aicon->lock) {
for (i = 0; dockable && i < scr->drawer_count + 2; i++) {
WDock *theDock = allDocks[i];
if (theDock == NULL)
break;
if (wDockSnapIcon(theDock, aicon, x, y, &ix, &iy, (theDock == originalDock))) {
theNewDock = theDock;
break;
}
}
if (originalDock != NULL && theNewDock == NULL &&
(aicon->launching || aicon->lock || aicon->running)) {
/* In those cases, stay in lastDock if no dock really wants us */
theNewDock = lastDock;
}
}
if (originalDock != NULL && theNewDock == NULL &&
(aicon->launching || aicon->lock || aicon->running)) {
/* In those cases, stay in lastDock if no dock really wants us */
theNewDock = lastDock;
}
if (theNewDock != NULL && !aicon->launching && !aicon->lock && ev.xmotion.state & MOD_MASK)
/* Mod is pressed: do not dock */
theNewDock = NULL;
if (lastDock != NULL && lastDock != theNewDock) {
/* Leave lastDock in the state we found it */
if (lastDock->type == WM_DRAWER) {
wDrawerFillTheGap(lastDock, aicon, (lastDock == originalDock));
}
if (collapsed) {
lastDock->collapsed = 1;
wDockHideIcons(lastDock);
@@ -918,6 +928,14 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
lastDock = theNewDock; // i.e., NULL
if (ondock) {
XUnmapWindow(dpy, scr->dock_shadow);
/*
* Leaving that weird comment for now.
* But if we see no gap, there is no need to fill one!
* We could test ondock first and the lastDock to NULL afterwards
if (lastDock_before_it_was_null->type == WM_DRAWER) {
wDrawerFillTheGap(lastDock, aicon, (lastDock == originalDock));
} */
}
ondock = 0;
}
@@ -942,6 +960,10 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
command for that appicon, and the user cancels the
wInputDialog asking for one). Make the rejection obvious by
sliding the icon to its old position */
if (lastDock->type == WM_DRAWER) {
// Also fill the gap left in the drawer
wDrawerFillTheGap(lastDock, aicon, False);
}
SlideWindow(icon->core->window, x, y, oldX, oldY);
}
}
@@ -956,14 +978,45 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
/* Possible scenario: user moved an auto-attracted appicon
from the clip to the dock, and cancelled the wInputDialog
asking for a command */
if (lastDock->type == WM_DRAWER) {
wDrawerFillTheGap(lastDock, aicon, False);
}
/* If aicon comes from a drawer, make some room to reattach it */
if (originalDock->type == WM_DRAWER) {
WAppIcon *aiconsToShift[ originalDock->icon_count ];
int j = 0;
for (i = 0; i < originalDock->max_icons; i++) {
WAppIcon *ai = originalDock->icon_array[ i ];
if (ai && ai != aicon &&
abs(ai->xindex) >= abs(aicon->xindex))
aiconsToShift[j++] = ai;
}
if (j != originalDock->icon_count - abs(aicon->xindex) - 1)
// Trust this never happens?
wwarning("Shifting j=%d appicons (instead of %d!) to reinsert aicon at index %d.",
j, originalDock->icon_count - abs(aicon->xindex) - 1, aicon->xindex);
wSlideAppicons(aiconsToShift, j, originalDock->on_right_side);
// Trust the appicon is inserted at exactly the same place, so its oldX/oldY are consistent with its "new" location?
}
SlideWindow(icon->core->window, x, y, oldX, oldY);
wDockReattachIcon(originalDock, aicon, aicon->xindex, aicon->yindex);
}
else {
if (originalDock->auto_collapse && !originalDock->collapsed) {
originalDock->collapsed = 1;
wDockHideIcons(originalDock);
}
if (originalDock->auto_raise_lower)
wDockLower(originalDock);
}
}
}
// No matter what happened above, check to lower lastDock
if (lastDock->auto_raise_lower)
wDockLower(lastDock);
// Don't see why I commented out the following 2 lines
/* if (lastDock->auto_raise_lower)
wDockLower(lastDock); */
/* If docked (or tried to dock) to a auto_collapsing dock, unset
* collapsed, so that wHandleAppIconMove doesn't collapse it
* right away (the timer will take care of it) */
@@ -983,13 +1036,23 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event)
}
}
wDockDetach(originalDock, aicon);
if (originalDock->auto_collapse && !originalDock->collapsed) {
originalDock->collapsed = 1;
wDockHideIcons(originalDock);
}
if (originalDock->auto_raise_lower)
wDockLower(originalDock);
}
}
if (collapsed) {
// Can't remember why the icon hiding is better done above than below (commented out)
// Also, lastDock is quite different from originalDock
/*
if (collapsed) {
lastDock->collapsed = 1;
wDockHideIcons(lastDock);
collapsed = 0;
}
*/
if (superfluous) {
if (ghost != None)
XFreePixmap(dpy, ghost);
@@ -1076,7 +1139,7 @@ static void create_appicon_from_dock(WWindow *wwin, WApplication *wapp, Window m
if (!wapp->app_icon && scr->dock)
wapp->app_icon = findDockIconFor(scr->dock, main_window);
/* finally check clips */
/* check clips */
if (!wapp->app_icon) {
int i;
for (i = 0; i < scr->workspace_count; i++) {
@@ -1088,6 +1151,16 @@ static void create_appicon_from_dock(WWindow *wwin, WApplication *wapp, Window m
}
}
/* Finally check drawers */
if (!wapp->app_icon) {
WDrawerChain *dc;
for (dc = scr->drawers; dc != NULL; dc = dc->next) {
wapp->app_icon = findDockIconFor(dc->adrawer, main_window);
if (wapp->app_icon)
break;
}
}
/* If created, then set some flags */
if (wapp->app_icon) {
WWindow *mainw = wapp->main_window_desc;