mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-25 16:02:33 +01:00
There is little point caching a pixmap for an app that isn't in the dock. This patch creates a function wAppIconSave that saves only if the app icon is docked, and adds calls to that function in all the places where an appicon can transition from undocked to docked. It also "adds" a function wApplicationSaveIconPathFor that saves an icon path to the configuration plist; the function already existed, it was just static before. Signed-off-by: Brad Jorsch <anomie@users.sourceforge.net>
724 lines
19 KiB
C
724 lines
19 KiB
C
/* appicon.c- icon for applications (not mini-window)
|
|
*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1997-2003 Alfredo K. Kojima
|
|
* Copyright (c) 1998-2003 Dan Pascu
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "WindowMaker.h"
|
|
#include "window.h"
|
|
#include "icon.h"
|
|
#include "application.h"
|
|
#include "appicon.h"
|
|
#include "actions.h"
|
|
#include "stacking.h"
|
|
#include "dock.h"
|
|
#include "funcs.h"
|
|
#include "defaults.h"
|
|
#include "workspace.h"
|
|
#include "superfluous.h"
|
|
#include "menu.h"
|
|
#include "framewin.h"
|
|
#include "dialog.h"
|
|
#include "client.h"
|
|
#ifdef XDND
|
|
#include "xdnd.h"
|
|
#endif
|
|
|
|
/*
|
|
* icon_file for the dock is got from the preferences file by
|
|
* using the classname/instancename
|
|
*/
|
|
|
|
/**** Global variables ****/
|
|
extern Cursor wCursor[WCUR_LAST];
|
|
extern WPreferences wPreferences;
|
|
|
|
#define MOD_MASK wPreferences.modifier_mask
|
|
|
|
void appIconMouseDown(WObjDescriptor * desc, XEvent * event);
|
|
static void iconDblClick(WObjDescriptor * desc, XEvent * event);
|
|
static void iconExpose(WObjDescriptor * desc, XEvent * event);
|
|
|
|
WAppIcon *wAppIconCreateForDock(WScreen * scr, char *command, char *wm_instance, char *wm_class, int tile)
|
|
{
|
|
WAppIcon *dicon;
|
|
char *path;
|
|
|
|
dicon = wmalloc(sizeof(WAppIcon));
|
|
wretain(dicon);
|
|
memset(dicon, 0, sizeof(WAppIcon));
|
|
dicon->yindex = -1;
|
|
dicon->xindex = -1;
|
|
|
|
dicon->prev = NULL;
|
|
dicon->next = scr->app_icon_list;
|
|
if (scr->app_icon_list) {
|
|
scr->app_icon_list->prev = dicon;
|
|
}
|
|
scr->app_icon_list = dicon;
|
|
|
|
if (command) {
|
|
dicon->command = wstrdup(command);
|
|
}
|
|
if (wm_class)
|
|
dicon->wm_class = wstrdup(wm_class);
|
|
if (wm_instance)
|
|
dicon->wm_instance = wstrdup(wm_instance);
|
|
|
|
path = wDefaultGetIconFile(scr, wm_instance, wm_class, True);
|
|
if (!path && command) {
|
|
wApplicationExtractDirPackIcon(scr, command, wm_instance, wm_class);
|
|
|
|
path = wDefaultGetIconFile(scr, wm_instance, wm_class, False);
|
|
}
|
|
|
|
if (path)
|
|
path = FindImage(wPreferences.icon_path, path);
|
|
|
|
dicon->icon = wIconCreateWithIconFile(scr, path, tile);
|
|
if (path)
|
|
wfree(path);
|
|
#ifdef XDND
|
|
wXDNDMakeAwareness(dicon->icon->core->window);
|
|
#endif
|
|
|
|
/* will be overriden by dock */
|
|
dicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
|
|
dicon->icon->core->descriptor.handle_expose = iconExpose;
|
|
dicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
|
|
dicon->icon->core->descriptor.parent = dicon;
|
|
AddToStackList(dicon->icon->core);
|
|
|
|
return dicon;
|
|
}
|
|
|
|
WAppIcon *wAppIconCreate(WWindow * leader_win)
|
|
{
|
|
WAppIcon *aicon;
|
|
WScreen *scr = leader_win->screen_ptr;
|
|
|
|
aicon = wmalloc(sizeof(WAppIcon));
|
|
wretain(aicon);
|
|
memset(aicon, 0, sizeof(WAppIcon));
|
|
|
|
aicon->yindex = -1;
|
|
aicon->xindex = -1;
|
|
|
|
aicon->prev = NULL;
|
|
aicon->next = scr->app_icon_list;
|
|
if (scr->app_icon_list) {
|
|
scr->app_icon_list->prev = aicon;
|
|
}
|
|
scr->app_icon_list = aicon;
|
|
|
|
if (leader_win->wm_class)
|
|
aicon->wm_class = wstrdup(leader_win->wm_class);
|
|
if (leader_win->wm_instance)
|
|
aicon->wm_instance = wstrdup(leader_win->wm_instance);
|
|
|
|
aicon->icon = wIconCreate(leader_win);
|
|
#ifdef XDND
|
|
wXDNDMakeAwareness(aicon->icon->core->window);
|
|
#endif
|
|
|
|
/* will be overriden if docked */
|
|
aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
|
|
aicon->icon->core->descriptor.handle_expose = iconExpose;
|
|
aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
|
|
aicon->icon->core->descriptor.parent = aicon;
|
|
AddToStackList(aicon->icon->core);
|
|
aicon->icon->show_title = 0;
|
|
wIconUpdate(aicon->icon);
|
|
|
|
return aicon;
|
|
}
|
|
|
|
void wAppIconDestroy(WAppIcon * aicon)
|
|
{
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
|
|
RemoveFromStackList(aicon->icon->core);
|
|
wIconDestroy(aicon->icon);
|
|
if (aicon->command)
|
|
wfree(aicon->command);
|
|
#ifdef XDND
|
|
if (aicon->dnd_command)
|
|
wfree(aicon->dnd_command);
|
|
#endif
|
|
if (aicon->wm_instance)
|
|
wfree(aicon->wm_instance);
|
|
if (aicon->wm_class)
|
|
wfree(aicon->wm_class);
|
|
|
|
if (aicon == scr->app_icon_list) {
|
|
if (aicon->next)
|
|
aicon->next->prev = NULL;
|
|
scr->app_icon_list = aicon->next;
|
|
} else {
|
|
if (aicon->next)
|
|
aicon->next->prev = aicon->prev;
|
|
if (aicon->prev)
|
|
aicon->prev->next = aicon->next;
|
|
}
|
|
|
|
aicon->destroyed = 1;
|
|
wrelease(aicon);
|
|
}
|
|
|
|
static void drawCorner(WIcon * icon)
|
|
{
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
XPoint points[3];
|
|
|
|
points[0].x = 1;
|
|
points[0].y = 1;
|
|
points[1].x = 12;
|
|
points[1].y = 1;
|
|
points[2].x = 1;
|
|
points[2].y = 12;
|
|
XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
|
|
points, 3, Convex, CoordModeOrigin);
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 0, 12);
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 12, 0);
|
|
/* drawing the second line gives a weird concave look. -Dan */
|
|
#if 0
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 1, 1, 1, 11);
|
|
XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 1, 1, 11, 1);
|
|
#endif
|
|
}
|
|
|
|
void wAppIconMove(WAppIcon * aicon, int x, int y)
|
|
{
|
|
XMoveWindow(dpy, aicon->icon->core->window, x, y);
|
|
aicon->x_pos = x;
|
|
aicon->y_pos = y;
|
|
}
|
|
|
|
#ifdef WS_INDICATOR
|
|
static void updateDockNumbers(WScreen * scr)
|
|
{
|
|
int length;
|
|
char *ws_numbers;
|
|
WAppIcon *dicon = scr->dock->icon_array[0];
|
|
|
|
ws_numbers = wmalloc(20);
|
|
snprintf(ws_numbers, 20, "%i [ %i ]", scr->current_workspace + 1, ((scr->current_workspace / 10) + 1));
|
|
length = strlen(ws_numbers);
|
|
|
|
XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, WMFontHeight(scr->icon_title_font) + 1, False);
|
|
|
|
WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->black,
|
|
scr->icon_title_font, 4, 3, ws_numbers, length);
|
|
|
|
WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->white,
|
|
scr->icon_title_font, 3, 2, ws_numbers, length);
|
|
|
|
wfree(ws_numbers);
|
|
}
|
|
#endif /* WS_INDICATOR */
|
|
|
|
void wAppIconPaint(WAppIcon * aicon)
|
|
{
|
|
WApplication *wapp;
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
|
|
if (aicon->icon->owner)
|
|
wapp = wApplicationOf(aicon->icon->owner->main_window);
|
|
else
|
|
wapp = NULL;
|
|
|
|
wIconPaint(aicon->icon);
|
|
|
|
# ifdef WS_INDICATOR
|
|
if (aicon->docked && scr->dock && scr->dock == aicon->dock && aicon->yindex == 0)
|
|
updateDockNumbers(scr);
|
|
# endif
|
|
if (scr->dock_dots && aicon->docked && !aicon->running && aicon->command != NULL) {
|
|
XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
|
|
XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
|
|
XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
|
|
scr->copy_gc, 0, 0, scr->dock_dots->width, scr->dock_dots->height, 0, 0);
|
|
}
|
|
#ifdef HIDDENDOT
|
|
if (wapp && wapp->flags.hidden) {
|
|
XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
|
|
XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
|
|
XCopyArea(dpy, scr->dock_dots->image,
|
|
aicon->icon->core->window, scr->copy_gc, 0, 0, 7, scr->dock_dots->height, 0, 0);
|
|
}
|
|
#endif /* HIDDENDOT */
|
|
|
|
if (aicon->omnipresent)
|
|
drawCorner(aicon->icon);
|
|
|
|
XSetClipMask(dpy, scr->copy_gc, None);
|
|
if (aicon->launching) {
|
|
XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
|
|
0, 0, wPreferences.icon_size, wPreferences.icon_size);
|
|
}
|
|
}
|
|
|
|
Bool wAppIconSave(WAppIcon *aicon)
|
|
{
|
|
char *path;
|
|
|
|
if (!aicon->docked || aicon->attracted) return True;
|
|
|
|
path = wIconStore(aicon->icon);
|
|
if (!path)
|
|
return False;
|
|
|
|
wApplicationSaveIconPathFor(path, aicon->wm_instance, aicon->wm_class);
|
|
|
|
wfree(path);
|
|
return True;
|
|
}
|
|
|
|
#define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
|
|
|
|
static void hideCallback(WMenu * menu, WMenuEntry * entry)
|
|
{
|
|
WApplication *wapp = (WApplication *) entry->clientdata;
|
|
|
|
if (wapp->flags.hidden) {
|
|
wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
|
|
wUnhideApplication(wapp, False, False);
|
|
} else {
|
|
wHideApplication(wapp);
|
|
}
|
|
}
|
|
|
|
static void unhideHereCallback(WMenu * menu, WMenuEntry * entry)
|
|
{
|
|
WApplication *wapp = (WApplication *) entry->clientdata;
|
|
|
|
wUnhideApplication(wapp, False, True);
|
|
}
|
|
|
|
static void setIconCallback(WMenu * menu, WMenuEntry * entry)
|
|
{
|
|
WAppIcon *icon = ((WApplication *) entry->clientdata)->app_icon;
|
|
char *file = NULL;
|
|
WScreen *scr;
|
|
int result;
|
|
|
|
assert(icon != NULL);
|
|
|
|
if (icon->editing)
|
|
return;
|
|
icon->editing = 1;
|
|
scr = icon->icon->core->screen_ptr;
|
|
|
|
wretain(icon);
|
|
|
|
result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
|
|
|
|
if (result && !icon->destroyed) {
|
|
if (file && *file == 0) {
|
|
wfree(file);
|
|
file = NULL;
|
|
}
|
|
if (!wIconChangeImageFile(icon->icon, file)) {
|
|
wMessageDialog(scr, _("Error"),
|
|
_("Could not open specified icon file"), _("OK"), NULL, NULL);
|
|
} else {
|
|
wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
|
|
wAppIconPaint(icon);
|
|
}
|
|
if (file)
|
|
wfree(file);
|
|
}
|
|
icon->editing = 0;
|
|
wrelease(icon);
|
|
}
|
|
|
|
static void killCallback(WMenu * menu, WMenuEntry * entry)
|
|
{
|
|
WApplication *wapp = (WApplication *) entry->clientdata;
|
|
WFakeGroupLeader *fPtr;
|
|
char *buffer;
|
|
char *shortname;
|
|
char *basename(const char *shortname);
|
|
|
|
if (!WCHECK_STATE(WSTATE_NORMAL))
|
|
return;
|
|
|
|
WCHANGE_STATE(WSTATE_MODAL);
|
|
|
|
assert(entry->clientdata != NULL);
|
|
|
|
shortname = basename(wapp->app_icon->wm_instance);
|
|
|
|
buffer = wstrconcat(wapp->app_icon ? shortname : NULL,
|
|
_(" will be forcibly closed.\n"
|
|
"Any unsaved changes will be lost.\n" "Please confirm."));
|
|
|
|
fPtr = wapp->main_window_desc->fake_group;
|
|
|
|
wretain(wapp->main_window_desc);
|
|
if (wPreferences.dont_confirm_kill
|
|
|| wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
|
|
buffer, _("Yes"), _("No"), NULL) == WAPRDefault) {
|
|
if (fPtr != NULL) {
|
|
WWindow *wwin, *twin;
|
|
|
|
wwin = wapp->main_window_desc->screen_ptr->focused_window;
|
|
while (wwin) {
|
|
twin = wwin->prev;
|
|
if (wwin->fake_group == fPtr) {
|
|
wClientKill(wwin);
|
|
}
|
|
wwin = twin;
|
|
}
|
|
} else if (!wapp->main_window_desc->flags.destroyed) {
|
|
wClientKill(wapp->main_window_desc);
|
|
}
|
|
}
|
|
wrelease(wapp->main_window_desc);
|
|
|
|
wfree(buffer);
|
|
|
|
WCHANGE_STATE(WSTATE_NORMAL);
|
|
}
|
|
|
|
static WMenu *createApplicationMenu(WScreen * scr)
|
|
{
|
|
WMenu *menu;
|
|
|
|
menu = wMenuCreate(scr, NULL, False);
|
|
wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
|
|
wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
|
|
wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
|
|
wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
|
|
|
|
return menu;
|
|
}
|
|
|
|
static void openApplicationMenu(WApplication * wapp, int x, int y)
|
|
{
|
|
WMenu *menu;
|
|
WScreen *scr = wapp->main_window_desc->screen_ptr;
|
|
int i;
|
|
|
|
if (!scr->icon_menu) {
|
|
scr->icon_menu = createApplicationMenu(scr);
|
|
wfree(scr->icon_menu->entries[1]->text);
|
|
}
|
|
|
|
menu = scr->icon_menu;
|
|
|
|
if (wapp->flags.hidden) {
|
|
menu->entries[1]->text = _("Unhide");
|
|
} else {
|
|
menu->entries[1]->text = _("Hide");
|
|
}
|
|
|
|
menu->flags.realized = 0;
|
|
wMenuRealize(menu);
|
|
|
|
x -= menu->frame->core->width / 2;
|
|
if (x + menu->frame->core->width > scr->scr_width)
|
|
x = scr->scr_width - menu->frame->core->width;
|
|
if (x < 0)
|
|
x = 0;
|
|
|
|
/* set client data */
|
|
for (i = 0; i < menu->entry_no; i++) {
|
|
menu->entries[i]->clientdata = wapp;
|
|
}
|
|
wMenuMapAt(menu, x, y, False);
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
static void iconExpose(WObjDescriptor * desc, XEvent * event)
|
|
{
|
|
wAppIconPaint(desc->parent);
|
|
}
|
|
|
|
static void iconDblClick(WObjDescriptor * desc, XEvent * event)
|
|
{
|
|
WAppIcon *aicon = desc->parent;
|
|
WApplication *wapp;
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
int unhideHere;
|
|
|
|
assert(aicon->icon->owner != NULL);
|
|
|
|
wapp = wApplicationOf(aicon->icon->owner->main_window);
|
|
unhideHere = (event->xbutton.state & ShiftMask);
|
|
|
|
/* go to the last workspace that the user worked on the app */
|
|
if (!unhideHere && wapp->last_workspace != scr->current_workspace)
|
|
wWorkspaceChange(scr, wapp->last_workspace);
|
|
|
|
wUnhideApplication(wapp, event->xbutton.button == Button2, unhideHere);
|
|
|
|
if (event->xbutton.state & MOD_MASK) {
|
|
wHideOtherApplications(aicon->icon->owner);
|
|
}
|
|
}
|
|
|
|
void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
|
|
{
|
|
WAppIcon *aicon = desc->parent;
|
|
WIcon *icon = aicon->icon;
|
|
XEvent ev;
|
|
int x = aicon->x_pos, y = aicon->y_pos;
|
|
int dx = event->xbutton.x, dy = event->xbutton.y;
|
|
int grabbed = 0;
|
|
int done = 0;
|
|
int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
WWorkspace *workspace = scr->workspaces[scr->current_workspace];
|
|
int shad_x = 0, shad_y = 0, docking = 0, dockable, collapsed = 0;
|
|
int ix, iy;
|
|
int clickButton = event->xbutton.button;
|
|
Pixmap ghost = None;
|
|
Window wins[2];
|
|
Bool movingSingle = False;
|
|
int oldX = x;
|
|
int oldY = y;
|
|
Bool hasMoved = False;
|
|
|
|
if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
|
|
return;
|
|
|
|
if (IsDoubleClick(scr, event)) {
|
|
iconDblClick(desc, event);
|
|
return;
|
|
}
|
|
|
|
if (event->xbutton.button == Button3) {
|
|
WObjDescriptor *desc;
|
|
WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
|
|
|
|
if (!wapp)
|
|
return;
|
|
|
|
if (event->xbutton.send_event &&
|
|
XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
|
|
| ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
|
|
GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
|
|
wwarning("pointer grab failed for appicon menu");
|
|
return;
|
|
}
|
|
|
|
openApplicationMenu(wapp, event->xbutton.x_root, event->xbutton.y_root);
|
|
|
|
/* allow drag select of menu */
|
|
desc = &scr->icon_menu->menu->descriptor;
|
|
event->xbutton.send_event = True;
|
|
(*desc->handle_mousedown) (desc, event);
|
|
return;
|
|
}
|
|
|
|
if (event->xbutton.state & MOD_MASK)
|
|
wLowerFrame(icon->core);
|
|
else
|
|
wRaiseFrame(icon->core);
|
|
|
|
if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
|
|
| ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
|
|
GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
|
|
wwarning("pointer grab failed for appicon move");
|
|
}
|
|
|
|
if (wPreferences.flags.nodock && wPreferences.flags.noclip)
|
|
dockable = 0;
|
|
else
|
|
dockable = canBeDocked(icon->owner);
|
|
|
|
wins[0] = icon->core->window;
|
|
wins[1] = scr->dock_shadow;
|
|
XRestackWindows(dpy, wins, 2);
|
|
if (superfluous) {
|
|
if (icon->pixmap != None)
|
|
ghost = MakeGhostIcon(scr, icon->pixmap);
|
|
else
|
|
ghost = MakeGhostIcon(scr, icon->core->window);
|
|
XSetWindowBackgroundPixmap(dpy, scr->dock_shadow, ghost);
|
|
XClearWindow(dpy, scr->dock_shadow);
|
|
}
|
|
|
|
while (!done) {
|
|
WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
|
|
| ButtonMotionMask | ExposureMask | EnterWindowMask, &ev);
|
|
switch (ev.type) {
|
|
case Expose:
|
|
WMHandleEvent(&ev);
|
|
break;
|
|
|
|
case EnterNotify:
|
|
/* It means the cursor moved so fast that it entered
|
|
* something else (if moving slowly, it would have
|
|
* stayed in the appIcon that is being moved. Ignore
|
|
* such "spurious" EnterNotifiy's */
|
|
break;
|
|
|
|
case MotionNotify:
|
|
hasMoved = True;
|
|
if (!grabbed) {
|
|
if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD
|
|
|| abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) {
|
|
XChangeActivePointerGrab(dpy, ButtonMotionMask
|
|
| ButtonReleaseMask | ButtonPressMask,
|
|
wCursor[WCUR_MOVE], CurrentTime);
|
|
grabbed = 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
x = ev.xmotion.x_root - dx;
|
|
y = ev.xmotion.y_root - dy;
|
|
|
|
if (movingSingle) {
|
|
XMoveWindow(dpy, icon->core->window, x, y);
|
|
} else {
|
|
wAppIconMove(aicon, x, y);
|
|
}
|
|
|
|
if (dockable) {
|
|
if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y, &ix, &iy, False)) {
|
|
shad_x = scr->dock->x_pos + ix * wPreferences.icon_size;
|
|
shad_y = scr->dock->y_pos + iy * wPreferences.icon_size;
|
|
|
|
if (scr->last_dock != scr->dock && collapsed) {
|
|
scr->last_dock->collapsed = 1;
|
|
wDockHideIcons(scr->last_dock);
|
|
collapsed = 0;
|
|
}
|
|
if (!collapsed && (collapsed = scr->dock->collapsed)) {
|
|
scr->dock->collapsed = 0;
|
|
wDockShowIcons(scr->dock);
|
|
}
|
|
|
|
if (scr->dock->auto_raise_lower)
|
|
wDockRaise(scr->dock);
|
|
|
|
scr->last_dock = scr->dock;
|
|
|
|
XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
|
|
if (!docking) {
|
|
XMapWindow(dpy, scr->dock_shadow);
|
|
}
|
|
docking = 1;
|
|
} else if (workspace->clip &&
|
|
wDockSnapIcon(workspace->clip, aicon, x, y, &ix, &iy, False)) {
|
|
shad_x = workspace->clip->x_pos + ix * wPreferences.icon_size;
|
|
shad_y = workspace->clip->y_pos + iy * wPreferences.icon_size;
|
|
|
|
if (scr->last_dock != workspace->clip && collapsed) {
|
|
scr->last_dock->collapsed = 1;
|
|
wDockHideIcons(scr->last_dock);
|
|
collapsed = 0;
|
|
}
|
|
if (!collapsed && (collapsed = workspace->clip->collapsed)) {
|
|
workspace->clip->collapsed = 0;
|
|
wDockShowIcons(workspace->clip);
|
|
}
|
|
|
|
if (workspace->clip->auto_raise_lower)
|
|
wDockRaise(workspace->clip);
|
|
|
|
scr->last_dock = workspace->clip;
|
|
|
|
XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
|
|
if (!docking) {
|
|
XMapWindow(dpy, scr->dock_shadow);
|
|
}
|
|
docking = 1;
|
|
} else if (docking) {
|
|
XUnmapWindow(dpy, scr->dock_shadow);
|
|
docking = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case ButtonPress:
|
|
break;
|
|
|
|
case ButtonRelease:
|
|
if (ev.xbutton.button != clickButton)
|
|
break;
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
if (docking) {
|
|
Bool docked;
|
|
|
|
/* icon is trying to be docked */
|
|
SlideWindow(icon->core->window, x, y, shad_x, shad_y);
|
|
XUnmapWindow(dpy, scr->dock_shadow);
|
|
docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
|
|
if (scr->last_dock->auto_collapse) {
|
|
collapsed = 0;
|
|
}
|
|
if (workspace->clip &&
|
|
workspace->clip != scr->last_dock && workspace->clip->auto_raise_lower)
|
|
wDockLower(workspace->clip);
|
|
|
|
if (!docked) {
|
|
/* If icon could not be docked, slide it back to the old
|
|
* position */
|
|
SlideWindow(icon->core->window, x, y, oldX, oldY);
|
|
}
|
|
} else {
|
|
if (movingSingle) {
|
|
/* move back to its place */
|
|
SlideWindow(icon->core->window, x, y, oldX, oldY);
|
|
wAppIconMove(aicon, oldX, oldY);
|
|
} else {
|
|
XMoveWindow(dpy, icon->core->window, x, y);
|
|
aicon->x_pos = x;
|
|
aicon->y_pos = y;
|
|
}
|
|
if (workspace->clip && workspace->clip->auto_raise_lower)
|
|
wDockLower(workspace->clip);
|
|
}
|
|
if (collapsed) {
|
|
scr->last_dock->collapsed = 1;
|
|
wDockHideIcons(scr->last_dock);
|
|
collapsed = 0;
|
|
}
|
|
if (superfluous) {
|
|
if (ghost != None)
|
|
XFreePixmap(dpy, ghost);
|
|
XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
|
|
}
|
|
|
|
if (wPreferences.auto_arrange_icons)
|
|
wArrangeIcons(scr, True);
|
|
|
|
if (wPreferences.single_click && !hasMoved)
|
|
iconDblClick(desc, event);
|
|
|
|
done = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|