1
/*****************************************************************************
2
* Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com> *
3
* Copyright 2013 - 2014 Yichao Yu <yyc1992@gmail.com> *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU Lesser General Public License as *
7
* published by the Free Software Foundation; either version 2.1 of the *
8
* License, or (at your option) version 3, or any later version accepted *
9
* by the membership of KDE e.V. (or its successor approved by the *
10
* membership of KDE e.V.), which shall act as a proxy defined in *
11
* Section 6 of version 3 of the license. *
13
* This program is distributed in the hope that it will be useful, *
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16
* Lesser General Public License for more details. *
18
* You should have received a copy of the GNU Lesser General Public *
19
* License along with this library. If not, *
20
* see <http://www.gnu.org/licenses/>. *
21
*****************************************************************************/
23
#include <qtcurve-utils/x11qtc.h>
24
#include <qtcurve-utils/x11wrap.h>
25
#include <qtcurve-utils/gtkprops.h>
26
#include <qtcurve-utils/log.h>
27
#include <qtcurve-cairo/utils.h>
29
#include <gdk/gdkkeysyms.h>
31
#include <common/common.h>
32
#include <common/config_file.h>
33
#include "qt_settings.h"
39
static GtkWidget *qtcCurrentActiveWindow = NULL;
49
static GHashTable *qtcWindowTable = NULL;
52
qtcWindowLookupHash(void *hash, gboolean create)
57
qtcWindowTable = g_hash_table_new(g_direct_hash, g_direct_equal);
59
rv = (QtCWindow*)g_hash_table_lookup(qtcWindowTable, hash);
62
rv = qtcNew(QtCWindow);
63
rv->width = rv->height = rv->timer = 0;
66
g_hash_table_insert(qtcWindowTable, hash, rv);
67
rv = g_hash_table_lookup(qtcWindowTable, hash);
73
qtcWindowRemoveFromHash(void *hash)
76
QtCWindow *tv = qtcWindowLookupHash(hash, false);
79
g_source_remove(tv->timer);
80
g_object_unref(G_OBJECT(tv->widget));
82
g_hash_table_remove(qtcWindowTable, hash);
88
qtcWindowCleanup(GtkWidget *widget)
91
QTC_DEF_WIDGET_PROPS(props, widget);
92
if (!(qtcIsFlatBgnd(opts.bgndAppearance)) ||
93
opts.bgndImage.type != IMG_NONE) {
94
qtcWindowRemoveFromHash(widget);
95
qtcDisconnectFromProp(props, windowConfigure);
97
qtcDisconnectFromProp(props, windowDestroy);
98
qtcDisconnectFromProp(props, windowStyleSet);
99
if ((opts.menubarHiding & HIDE_KEYBOARD) ||
100
(opts.statusbarHiding & HIDE_KEYBOARD))
101
qtcDisconnectFromProp(props, windowKeyRelease);
102
if ((opts.menubarHiding & HIDE_KWIN) ||
103
(opts.statusbarHiding & HIDE_KWIN))
104
qtcDisconnectFromProp(props, windowMap);
105
if (opts.shadeMenubarOnlyWhenActive || BLEND_TITLEBAR ||
106
opts.menubarHiding || opts.statusbarHiding)
107
qtcDisconnectFromProp(props, windowClientEvent);
108
qtcWidgetProps(props)->windowHacked = false;
113
qtcWindowStyleSet(GtkWidget *widget, GtkStyle *prev_style, void *data)
115
QTC_UNUSED(prev_style);
117
qtcWindowCleanup(widget);
121
static gboolean qtcWindowToggleMenuBar(GtkWidget *widget);
122
static gboolean qtcWindowToggleStatusBar(GtkWidget *widget);
125
qtcWindowClientEvent(GtkWidget *widget, GdkEventClient *event, void *data)
128
if (gdk_x11_atom_to_xatom(event->message_type) ==
129
qtc_x11_qtc_active_window) {
130
if (event->data.l[0]) {
131
qtcCurrentActiveWindow = widget;
132
} else if (qtcCurrentActiveWindow == widget) {
133
qtcCurrentActiveWindow = 0L;
135
gtk_widget_queue_draw(widget);
136
} else if (gdk_x11_atom_to_xatom(event->message_type) ==
137
qtc_x11_qtc_titlebar_size) {
138
qtcGetWindowBorderSize(true);
139
GtkWidget *menubar = qtcWindowGetMenuBar(widget, 0);
142
gtk_widget_queue_draw(menubar);
144
} else if (gdk_x11_atom_to_xatom(event->message_type) ==
145
qtc_x11_qtc_toggle_menubar) {
146
if (opts.menubarHiding & HIDE_KWIN && qtcWindowToggleMenuBar(widget)) {
147
gtk_widget_queue_draw(widget);
149
} else if (gdk_x11_atom_to_xatom(event->message_type) ==
150
qtc_x11_qtc_toggle_statusbar) {
151
if (opts.statusbarHiding & HIDE_KWIN &&
152
qtcWindowToggleStatusBar(widget)) {
153
gtk_widget_queue_draw(widget);
160
qtcWindowDestroy(GtkWidget *widget, GdkEvent *event, void *data)
164
qtcWindowCleanup(widget);
169
qtcWindowIsActive(GtkWidget *widget)
171
return widget && (gtk_window_is_active(GTK_WINDOW(widget)) ||
172
qtcCurrentActiveWindow == widget);
176
qtcWindowSizeRequest(GtkWidget *widget)
178
if (widget && (!(qtcIsFlatBgnd(opts.bgndAppearance)) ||
179
IMG_NONE != opts.bgndImage.type)) {
180
QtcRect alloc = qtcWidgetGetAllocation(widget);
181
QtcRect rect = {0, 0, 0, 0};
182
if (qtcIsFlat(opts.bgndAppearance) &&
183
IMG_NONE != opts.bgndImage.type) {
184
EPixPos pos = (IMG_FILE == opts.bgndImage.type ?
185
opts.bgndImage.pos : PP_TR);
186
if (opts.bgndImage.type == IMG_FILE) {
187
qtcLoadBgndImage(&opts.bgndImage);
191
rect.width = opts.bgndImage.width + 1;
192
rect.height = opts.bgndImage.height + 1;
196
rect.width = alloc.width;
197
rect.height = (opts.bgndImage.type == IMG_FILE ?
198
opts.bgndImage.height :
199
RINGS_HEIGHT(opts.bgndImage.type)) + 1;
203
rect.width = opts.bgndImage.width + 1;
204
rect.height = alloc.height;
210
rect.width = alloc.width;
211
rect.height = alloc.height;
214
if (alloc.width < rect.width) {
215
rect.width = alloc.width;
217
if (alloc.height < rect.height) {
218
rect.height = alloc.height;
221
rect.width = alloc.width, rect.height = alloc.height;
223
gdk_window_invalidate_rect(gtk_widget_get_window(widget),
224
(GdkRectangle*)&rect, false);
230
qtcWindowDelayedUpdate(void *user_data)
232
QtCWindow *window = (QtCWindow*)user_data;
235
if (window->locked) {
236
window->locked = false;
239
g_source_remove(window->timer);
241
// otherwise, trigger update
243
qtcWindowSizeRequest(window->widget);
245
g_object_unref(G_OBJECT(window->widget));
253
qtcWindowConfigure(GtkWidget *widget, GdkEventConfigure *event, void *data)
256
QtCWindow *window = (QtCWindow*)data;
258
if (window && (event->width != window->width ||
259
event->height != window->height)) {
260
window->width = event->width;
261
window->height = event->height;
263
// schedule delayed timeOut
264
if (!window->timer) {
265
g_object_ref(G_OBJECT(window->widget));
267
g_timeout_add(50, qtcWindowDelayedUpdate, window);
268
window->locked = false;
270
window->locked = true;
277
canGetChildren(GtkWidget *widget)
279
return (GTK_APP_GHB != qtSettings.app ||
280
0 != strcmp(g_type_name(G_OBJECT_TYPE(widget)), "GhbCompositor") ||
281
gtk_widget_get_realized(widget));
285
qtcWindowGetMenuBar(GtkWidget *parent, int level)
287
if (level < 3 && GTK_IS_CONTAINER(parent) && canGetChildren(parent)
288
/* && gtk_widget_get_realized(parent)*/) {
289
GtkWidget *rv = NULL;
290
GList *children = gtk_container_get_children(GTK_CONTAINER(parent));
291
for (GList *child = children;child && !rv;child = child->next) {
292
GtkWidget *boxChild = (GtkWidget*)child->data;
294
if (GTK_IS_MENU_BAR(boxChild)) {
295
rv = GTK_WIDGET(boxChild);
296
} else if (GTK_IS_CONTAINER(boxChild)) {
297
rv=qtcWindowGetMenuBar(GTK_WIDGET(boxChild), level + 1);
302
g_list_free(children);
310
qtcWindowGetStatusBar(GtkWidget *parent, int level)
312
if (level < 3 && GTK_IS_CONTAINER(parent) && canGetChildren(parent)
313
/* && gtk_widget_get_realized(parent)*/) {
314
GtkWidget *rv = NULL;
315
GList *children = gtk_container_get_children(GTK_CONTAINER(parent));
316
for(GList *child = children;child && !rv;child = child->next) {
317
GtkWidget *boxChild = (GtkWidget*)child->data;
319
if (GTK_IS_STATUSBAR(boxChild)) {
320
rv=GTK_WIDGET(boxChild);
321
} else if (GTK_IS_CONTAINER(boxChild)) {
322
rv=qtcWindowGetStatusBar(GTK_WIDGET(boxChild), level + 1);
326
g_list_free(children);
334
qtcWindowMenuBarDBus(GtkWidget *widget, int size)
336
GtkWindow *topLevel = GTK_WINDOW(gtk_widget_get_toplevel(widget));
337
unsigned int xid = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(topLevel)));
340
//sprintf(cmd, "qdbus org.kde.kwin /QtCurve menuBarSize %u %d", xid, size);
341
sprintf(cmd, "dbus-send --type=method_call --session --dest=org.kde.kwin /QtCurve org.kde.QtCurve.menuBarSize uint32:%u int32:%d",
347
char *args[]={"qdbus", "org.kde.kwin", "/QtCurve", "menuBarSize", xidS, sizeS, NULL};
349
sprintf(xidS, "%u", xid);
350
sprintf(sizeS, "%d", size);
351
g_spawn_async("/tmp", args, NULL, (GSpawnFlags)0, NULL, NULL, NULL, NULL);
356
qtcWindowStatusBarDBus(GtkWidget *widget, gboolean state)
358
GtkWindow *topLevel = GTK_WINDOW(gtk_widget_get_toplevel(widget));
359
unsigned int xid = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(topLevel)));
362
//sprintf(cmd, "qdbus org.kde.kwin /QtCurve statusBarState %u %s", xid, state ? "true" : "false");
363
sprintf(cmd, "dbus-send --type=method_call --session --dest=org.kde.kwin /QtCurve org.kde.QtCurve.statusBarState uint32:%u boolean:%s",
364
xid, state ? "true" : "false");
369
char *args[]={"qdbus", "org.kde.kwin", "/QtCurve", "statusBarState", xidS, stateS, NULL};
371
sprintf(xidS, "%u", xid);
372
sprintf(stateS, "%s", state ? "true" : "false");
373
g_spawn_async("/tmp", args, NULL, (GSpawnFlags)0, NULL, NULL, NULL, NULL);
378
qtcWindowToggleMenuBar(GtkWidget *widget)
380
GtkWidget *menuBar = qtcWindowGetMenuBar(widget, 0);
384
qtcSetMenuBarHidden(qtSettings.appName, gtk_widget_get_visible(menuBar));
385
if (gtk_widget_get_visible(menuBar)) {
386
gtk_widget_hide(menuBar);
388
size = qtcWidgetGetAllocation(menuBar).height;
389
gtk_widget_show(menuBar);
392
qtcMenuEmitSize(menuBar, size);
393
qtcWindowMenuBarDBus(widget, size);
400
qtcWindowSetStatusBarProp(GtkWidget *w)
402
QTC_DEF_WIDGET_PROPS(props, w);
403
if (w && !qtcWidgetProps(props)->statusBarSet) {
404
GtkWindow *topLevel = GTK_WINDOW(gtk_widget_get_toplevel(w));
406
GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(topLevel)));
408
qtcWidgetProps(props)->statusBarSet = true;
409
qtcX11SetStatusBar(wid);
416
qtcWindowToggleStatusBar(GtkWidget *widget)
418
GtkWidget *statusBar = qtcWindowGetStatusBar(widget, 0);
421
bool state = gtk_widget_get_visible(statusBar);
422
qtcSetStatusBarHidden(qtSettings.appName, state);
424
gtk_widget_hide(statusBar);
426
gtk_widget_show(statusBar);
428
qtcWindowStatusBarDBus(widget, state);
435
qtcWindowSetProperties(GtkWidget *w, unsigned short opacity)
437
GtkWindow *topLevel = GTK_WINDOW(gtk_widget_get_toplevel(w));
438
unsigned long prop = (qtcIsFlatBgnd(opts.bgndAppearance) ?
439
(IMG_NONE != opts.bgndImage.type ?
440
APPEARANCE_RAISED : APPEARANCE_FLAT) :
441
opts.bgndAppearance) & 0xFF;
442
//GtkRcStyle *rcStyle=gtk_widget_get_modifier_style(w);
443
GdkColor *bgnd = /* rcStyle ? &rcStyle->bg[GTK_STATE_NORMAL] : */
444
&qtcPalette.background[ORIGINAL_SHADE];
446
GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(topLevel)));
448
if (opacity != 100) {
449
qtcX11SetOpacity(wid, opacity);
451
prop |= (((toQtColor(bgnd->red) & 0xFF) << 24) |
452
((toQtColor(bgnd->green) & 0xFF) << 16) |
453
((toQtColor(bgnd->blue) & 0xFF) << 8));
454
qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, wid, qtc_x11_qtc_bgnd,
455
XCB_ATOM_CARDINAL, 32, 1, &prop);
460
qtcWindowKeyRelease(GtkWidget *widget, GdkEventKey *event, void *user_data)
462
QTC_UNUSED(user_data);
463
// Ensure only ctrl/alt/shift/capsLock are pressed...
464
if (GDK_CONTROL_MASK & event->state && GDK_MOD1_MASK & event->state &&
465
!event->is_modifier && 0 == (event->state & 0xFF00)) {
466
bool toggled = false;
467
if (opts.menubarHiding & HIDE_KEYBOARD &&
468
(GDK_KEY_m == event->keyval || GDK_KEY_M == event->keyval)) {
469
toggled = qtcWindowToggleMenuBar(widget);
471
if (opts.statusbarHiding & HIDE_KEYBOARD &&
472
(GDK_KEY_s == event->keyval || GDK_KEY_S == event->keyval)) {
473
toggled = qtcWindowToggleStatusBar(widget);
476
gtk_widget_queue_draw(widget);
483
qtcWindowMap(GtkWidget *widget, GdkEventKey *event, void *user_data)
486
QTC_UNUSED(user_data);
487
QTC_DEF_WIDGET_PROPS(props, widget);
488
qtcWindowSetProperties(widget, qtcWidgetProps(props)->windowOpacity);
490
if (opts.menubarHiding & HIDE_KWIN) {
491
GtkWidget *menuBar = qtcWindowGetMenuBar(widget, 0);
494
int size = (gtk_widget_get_visible(menuBar) ?
495
qtcWidgetGetAllocation(menuBar).height : 0);
497
qtcMenuEmitSize(menuBar, size);
498
qtcWindowMenuBarDBus(widget, size);
502
if(opts.statusbarHiding&HIDE_KWIN)
504
GtkWidget *statusBar=qtcWindowGetStatusBar(widget, 0);
507
qtcWindowStatusBarDBus(widget, !gtk_widget_get_visible(statusBar));
513
qtcWindowSetup(GtkWidget *widget, int opacity)
515
QTC_DEF_WIDGET_PROPS(props, widget);
516
if (widget && !qtcWidgetProps(props)->windowHacked) {
517
qtcWidgetProps(props)->windowHacked = true;
518
if (!qtcIsFlatBgnd(opts.bgndAppearance) ||
519
opts.bgndImage.type != IMG_NONE) {
520
QtCWindow *window = qtcWindowLookupHash(widget, true);
522
QtcRect alloc = qtcWidgetGetAllocation(widget);
523
qtcConnectToProp(props, windowConfigure, "configure-event",
524
qtcWindowConfigure, window);
525
window->width = alloc.width;
526
window->height = alloc.height;
527
window->widget = widget;
530
qtcConnectToProp(props, windowDestroy, "destroy-event",
531
qtcWindowDestroy, NULL);
532
qtcConnectToProp(props, windowStyleSet, "style-set",
533
qtcWindowStyleSet, NULL);
534
if ((opts.menubarHiding & HIDE_KEYBOARD) ||
535
(opts.statusbarHiding & HIDE_KEYBOARD)) {
536
qtcConnectToProp(props, windowKeyRelease, "key-release-event",
537
qtcWindowKeyRelease, NULL);
539
qtcWidgetProps(props)->windowOpacity = (unsigned short)opacity;
540
qtcWindowSetProperties(widget, (unsigned short)opacity);
542
if ((opts.menubarHiding & HIDE_KWIN) ||
543
(opts.statusbarHiding & HIDE_KWIN) || 100 != opacity)
544
qtcConnectToProp(props, windowMap, "map-event", qtcWindowMap, NULL);
545
if (opts.shadeMenubarOnlyWhenActive || BLEND_TITLEBAR ||
546
opts.menubarHiding || opts.statusbarHiding)
547
qtcConnectToProp(props, windowClientEvent, "client-event",
548
qtcWindowClientEvent, NULL);