Add button_press_event() callback into LXPanelPluginInit struct.
[lxde/lxpanel.git] / src / plugins / wincmd.c
CommitLineData
239cb032 1/**
a99ee9e1
JH
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
a52c2257
HJYP
19#include <stdlib.h>
20
21#include <gdk-pixbuf/gdk-pixbuf.h>
e7cb732b 22#include <glib/gi18n.h>
a52c2257
HJYP
23
24#include "panel.h"
25#include "misc.h"
b31cb1d2 26#include "private.h"
a52c2257
HJYP
27#include "dbg.h"
28
2918994e 29/* Commands that can be issued. */
30typedef enum {
31 WC_NONE,
32 WC_ICONIFY,
33 WC_SHADE
34} WindowCommand;
35
36/* Private context for window command plugin. */
a52c2257 37typedef struct {
2918994e 38 char * image; /* Main icon */
39 WindowCommand button_1_command; /* Command for mouse button 1 */
40 WindowCommand button_2_command; /* Command for mouse button 2 */
ea20096e 41 gboolean toggle_preference; /* User preference: toggle iconify/shade and map */
42 gboolean toggle_state; /* State of toggle */
2918994e 43} WinCmdPlugin;
44
a52c2257
HJYP
45static pair wincmd_pair [] = {
46 { WC_NONE, "none" },
47 { WC_ICONIFY, "iconify" },
48 { WC_SHADE, "shade" },
49 { 0, NULL },
50};
51
6e76a9e2 52static void wincmd_adjust_toggle_state(WinCmdPlugin * wc);
ea20096e 53static void wincmd_execute(WinCmdPlugin * wc, WindowCommand command);
2918994e 54static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, Plugin * plugin);
55static int wincmd_constructor(Plugin * p, char ** fp);
56static void wincmd_destructor(Plugin * p);
aff07791 57static void wincmd_apply_configuration(Plugin * p);
ea20096e 58static void wincmd_configure(Plugin * p, GtkWindow * parent);
2918994e 59static void wincmd_save_configuration(Plugin * p, FILE * fp);
8f9e6256 60static void wincmd_panel_configuration_changed(Plugin * p);
61
6e76a9e2
MJ
62/* Adjust the toggle state after a window command. */
63static void wincmd_adjust_toggle_state(WinCmdPlugin * wc)
64{
65 /* Ensure that if the user changes the preference from "unconditional" to "toggle", we do a raise on the next click. */
66 if (wc->toggle_preference)
67 wc->toggle_state = ! wc->toggle_state;
68 else wc->toggle_state = TRUE;
69}
70
2918994e 71/* Execute a window command. */
ea20096e 72static void wincmd_execute(WinCmdPlugin * wc, WindowCommand command)
a52c2257 73{
2918994e 74 /* Get the list of all windows. */
75 int client_count;
76 Window * client_list = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CLIENT_LIST, XA_WINDOW, &client_count);
77 if (client_list != NULL)
78 {
79 /* Loop over all windows. */
80 guint current_desktop = get_net_current_desktop();
81 int i;
82 for (i = 0; i < client_count; i++)
83 {
84 /* Get the desktop and window type properties. */
85 NetWMWindowType nwwt;
86 guint task_desktop = get_net_wm_desktop(client_list[i]);
87 get_net_wm_window_type(client_list[i], &nwwt);
88
89 /* If the task is visible on the current desktop and it is an ordinary window,
90 * execute the requested Iconify or Shade change. */
18ecfe2a 91 if (((task_desktop == -1) || (task_desktop == current_desktop))
2918994e 92 && (( ! nwwt.dock) && ( ! nwwt.desktop) && ( ! nwwt.splash)))
93 {
94 switch (command)
95 {
18ecfe2a 96 case WC_NONE:
97 break;
98
2918994e 99 case WC_ICONIFY:
6e76a9e2 100 if (( ! wc->toggle_preference) || ( ! wc->toggle_state))
ea20096e 101 XIconifyWindow(GDK_DISPLAY(), client_list[i], DefaultScreen(GDK_DISPLAY()));
102 else
103 XMapWindow (GDK_DISPLAY(), client_list[i]);
18ecfe2a 104 break;
2918994e 105
106 case WC_SHADE:
107 Xclimsg(client_list[i], a_NET_WM_STATE,
6e76a9e2 108 ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? a_NET_WM_STATE_ADD : a_NET_WM_STATE_REMOVE),
2918994e 109 a_NET_WM_STATE_SHADED, 0, 0, 0);
110 break;
111 }
112 }
a52c2257 113 }
2918994e 114 XFree(client_list);
ea20096e 115
6e76a9e2
MJ
116 /* Adjust toggle state. */
117 wincmd_adjust_toggle_state(wc);
a52c2257 118 }
a52c2257
HJYP
119}
120
2918994e 121/* Handler for "clicked" signal on main widget. */
122static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, Plugin * plugin)
a52c2257 123{
ea20096e 124 WinCmdPlugin * wc = (WinCmdPlugin *) plugin->priv;
125
9dd114c4 126 /* Standard right-click handling. */
127 if (plugin_button_press_event(widget, event, plugin))
128 return TRUE;
7414a73f 129
2918994e 130 /* Left-click to iconify. */
131 if (event->button == 1)
53b37ef2
HJYP
132 {
133 GdkScreen* screen = gtk_widget_get_screen(widget);
134 static GdkAtom atom = 0;
135 if( G_UNLIKELY(0 == atom) )
136 atom = gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE);
137
6e76a9e2
MJ
138 /* If window manager supports _NET_SHOWING_DESKTOP, use it.
139 * Otherwise, fall back to iconifying windows individually. */
140 if (gdk_x11_screen_supports_net_wm_hint(screen, atom))
53b37ef2 141 {
6e76a9e2
MJ
142 int showing_desktop = ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? 1 : 0);
143 Xclimsg(DefaultRootWindow(GDK_DISPLAY()), a_NET_SHOWING_DESKTOP, showing_desktop, 0, 0, 0, 0);
144 wincmd_adjust_toggle_state(wc);
53b37ef2
HJYP
145 }
146 else
53b37ef2 147 wincmd_execute(wc, WC_ICONIFY);
53b37ef2 148 }
a52c2257 149
2918994e 150 /* Middle-click to shade. */
151 else if (event->button == 2)
ea20096e 152 wincmd_execute(wc, WC_SHADE);
a52c2257 153
2918994e 154 return TRUE;
a52c2257
HJYP
155}
156
2918994e 157/* Plugin constructor. */
158static int wincmd_constructor(Plugin * p, char ** fp)
159{
160 /* Allocate plugin context and set into Plugin private data pointer. */
161 WinCmdPlugin * wc = g_new0(WinCmdPlugin, 1);
162 p->priv = wc;
a52c2257 163
2918994e 164 /* Initialize to defaults. */
165 wc->button_1_command = WC_ICONIFY;
166 wc->button_2_command = WC_SHADE;
a52c2257 167
2918994e 168 /* Load parameters from the configuration file. */
a52c2257 169 line s;
a52c2257 170 s.len = 256;
2918994e 171 if(fp != NULL)
db449f6e 172 {
2918994e 173 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END)
174 {
175 if (s.type == LINE_NONE)
176 {
177 ERR("wincmd: illegal token %s\n", s.str);
178 return 0;
db449f6e 179 }
2918994e 180 if (s.type == LINE_VAR)
181 {
182 if (g_ascii_strcasecmp(s.t[0], "Button1") == 0)
183 wc->button_1_command = str2num(wincmd_pair, s.t[1], WC_ICONIFY);
184 else if (g_ascii_strcasecmp(s.t[0], "Button2") == 0)
185 wc->button_2_command = str2num(wincmd_pair, s.t[1], WC_SHADE);
186 else if (g_ascii_strcasecmp(s.t[0], "image") == 0)
187 wc->image = expand_tilda(g_strdup(s.t[1]));
ea20096e 188 else if (g_ascii_strcasecmp(s.t[0], "Toggle") == 0)
189 wc->toggle_preference = str2num(bool_pair, s.t[1], 0);
2918994e 190 else
191 ERR("wincmd: unknown var %s\n", s.t[0]);
192 }
193 else
194 {
195 ERR("wincmd: illegal in this context %s\n", s.str);
196 return 0;
a52c2257 197 }
a52c2257
HJYP
198 }
199 }
5297da29 200
2918994e 201 /* Default the image if unspecified. */
202 if (wc->image == NULL)
203 wc->image = g_strdup("window-manager");
fcf6205e 204
2918994e 205 /* Allocate top level widget and set into Plugin widget pointer. */
8f9e6256 206 p->pwid = fb_button_new_from_file(wc->image, p->panel->icon_size, p->panel->icon_size, PANEL_ICON_HIGHLIGHT, TRUE);
2918994e 207 gtk_container_set_border_width(GTK_CONTAINER(p->pwid), 0);
8e05828e 208 g_signal_connect(G_OBJECT(p->pwid), "button-press-event", G_CALLBACK(wincmd_button_clicked), (gpointer) p);
2918994e 209 gtk_widget_set_tooltip_text(p->pwid, _("Left click to iconify all windows. Middle click to shade them."));
4542c20d 210
2918994e 211 /* Show the widget and return. */
212 gtk_widget_show(p->pwid);
9dd114c4 213 return 1;
a52c2257
HJYP
214}
215
2918994e 216/* Plugin destructor. */
217static void wincmd_destructor(Plugin * p)
9c97f69e 218{
8f9e6256 219 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
2918994e 220 g_free(wc->image);
221 g_free(wc);
9c97f69e
HJYP
222}
223
ea20096e 224/* Callback when the configuration dialog has recorded a configuration change. */
225static void wincmd_apply_configuration(Plugin * p)
226{
ea20096e 227}
228
229/* Callback when the configuration dialog is to be shown. */
230static void wincmd_configure(Plugin * p, GtkWindow * parent)
231{
232 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
233 GtkWidget * dlg = create_generic_config_dlg(
234 _(p->class->name),
235 GTK_WIDGET(parent),
236 (GSourceFunc) wincmd_apply_configuration, (gpointer) p,
237 _("Alternately iconify/shade and raise"), &wc->toggle_preference, CONF_TYPE_BOOL,
238 NULL);
239 gtk_window_present(GTK_WINDOW(dlg));
240}
241
242
2918994e 243/* Save the configuration to the configuration file. */
244static void wincmd_save_configuration(Plugin * p, FILE * fp)
245{
246 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
247 lxpanel_put_str(fp, "image", wc->image);
248 lxpanel_put_str(fp, "Button1", num2str(wincmd_pair, wc->button_1_command, NULL));
249 lxpanel_put_str(fp, "Button2", num2str(wincmd_pair, wc->button_2_command, NULL));
ea20096e 250 lxpanel_put_bool(fp, "Toggle", wc->toggle_preference);
2918994e 251}
a52c2257 252
8f9e6256 253/* Callback when panel configuration changes. */
254static void wincmd_panel_configuration_changed(Plugin * p)
255{
256 WinCmdPlugin * wc = (WinCmdPlugin *) p->priv;
730e3f7b 257 fb_button_set_from_file(p->pwid, wc->image, p->panel->icon_size, p->panel->icon_size, TRUE);
8f9e6256 258}
259
2918994e 260/* Plugin descriptor. */
22242ed4 261PluginClass wincmd_plugin_class = {
2918994e 262
263 PLUGINCLASS_VERSIONING,
a52c2257 264
3c3e9c9e
HG
265 .type = "wincmd",
266 .name = N_("Minimize All Windows"),
267 .version = "1.0",
268 .description = N_("Sends commands to all desktop windows.\nSupported commands are 1) iconify and 2) shade"),
269
270 .constructor = wincmd_constructor,
271 .destructor = wincmd_destructor,
272 .config = wincmd_configure,
273 .save = wincmd_save_configuration,
274 .panel_configuration_changed = wincmd_panel_configuration_changed
ea20096e 275
a52c2257 276};